/*******************************************************************************
* Copyright (c) 2007-2013 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.model.ui.views.palette;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Properties;
import org.eclipse.core.resources.IFile;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.xml.core.internal.document.CommentImpl;
import org.eclipse.wst.xml.core.internal.document.DocumentTypeImpl;
import org.eclipse.wst.xml.core.internal.document.ElementImpl;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.jboss.tools.common.model.ServiceDialog;
import org.jboss.tools.common.model.XModelObjectConstants;
import org.jboss.tools.common.model.options.PreferenceModelUtilities;
import org.jboss.tools.common.model.ui.ModelUIPlugin;
import org.jboss.tools.common.model.ui.editors.dnd.IElementGenerator;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
/**
* @author Victor Rubezhny
*/
abstract public class PaletteInsertHelper {
public static final String PROPERTY_SELECTION_PROVIDER = "selectionProvider"; //$NON-NLS-1$
public static final String PROPERTY_START_TEXT = XModelObjectConstants.START_TEXT;
public static final String PROPERTY_END_TEXT = XModelObjectConstants.END_TEXT;
public static final String PROPERTY_REFORMAT_BODY = XModelObjectConstants.REFORMAT;
public static final String PROPERTY_TAG_NAME = "tag name"; //$NON-NLS-1$
public static final String PROPERTY_NEW_LINE = "new line"; //$NON-NLS-1$
public PaletteInsertHelper() {}
protected void insertIntoEditor(ITextEditor editor, Properties p, IPositionCorrector corrector) {
if(editor == null) return;
if(!isEditable(editor)) {
ServiceDialog d = PreferenceModelUtilities.getPreferenceModel().getService();
String name = editor.getEditorInput().getName();
String mes = "Source " + name + " is read-only";
if(editor != null && isEditable(editor.getEditorInput())) {
mes = "Please activate Source tab.";
}
d.showDialog("Warning", mes, new String[]{"OK"}, null, ServiceDialog.WARNING);
return;
}
IDocument doc = editor.getDocumentProvider().getDocument(editor.getEditorInput());
ISelectionProvider selProvider = editor.getSelectionProvider();
p.put(PROPERTY_SELECTION_PROVIDER, selProvider);
insertIntoEditorInternal(doc, p, corrector);
}
public ITextSelection correctSelection(IDocument document, ITextSelection selection, IPositionCorrector corrector){
int start = selection.getOffset();
int end = start + selection.getLength();
IStructuredModel model = null;
try{
model = StructuredModelManager.getModelManager().getExistingModelForRead((IStructuredDocument)document);
IDOMDocument xmlDocument = (model instanceof IDOMModel) ? ((IDOMModel) model).getDocument() : null;
if(xmlDocument != null){
if(corrector != null) {
selection = corrector.correctSelection(xmlDocument, selection);
start = selection.getOffset();
end = start + selection.getLength();
}
return basicCorrectSelection(model, start, end);
}
}finally{
if (model != null) model.releaseFromRead();
}
return new TextSelection(document, start, end-start);
}
protected void insertIntoEditorInternal(IDocument doc, Properties p, IPositionCorrector corrector) {
String startText = p.getProperty(PROPERTY_START_TEXT);
String endText = p.getProperty(PROPERTY_END_TEXT);
String newline = p.getProperty(PROPERTY_NEW_LINE);
boolean reformat = "yes".equals(p.getProperty(PROPERTY_REFORMAT_BODY)); //$NON-NLS-1$
ISelectionProvider selProvider = (ISelectionProvider)p.get(PROPERTY_SELECTION_PROVIDER);
if (doc == null || selProvider == null) return;
ITextSelection selection = (ITextSelection)selProvider.getSelection();
selection = correctSelection(doc, selection, corrector);
int offset = selection.getOffset();
int length = selection.getLength();
if (startText == null) startText = ""; //$NON-NLS-1$
else startText = prepare(prepare(startText, "\\n", getLineDelimiter(doc)), "\\t", "\t"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (endText == null) endText = ""; //$NON-NLS-1$
else endText = prepare(prepare(endText, "\\n", getLineDelimiter(doc)), "\\t", "\t"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
int start = offset;
int end = offset + length;
String body = "";
try {
int firstLine = doc.getLineOfOffset(start);
int firstLineStart = doc.getLineOffset(firstLine);
String firstLineBeginning = start == firstLineStart ?
"" : doc.get(firstLineStart, start - firstLineStart).trim();
if (firstLineBeginning.isEmpty()) {
start = firstLine == 0 ?
firstLineStart :
doc.getLineOffset(firstLine - 1) + doc.getLineLength(firstLine - 1) -
getLineDelimiter(doc, firstLine - 1).length();
}
if(start < 0){
start = 0;
}else if(start > doc.getLength()){
start = doc.getLength();
}
int lastLine = doc.getLineOfOffset(end);
int lastLineEnd = doc.getLineOffset(lastLine) + doc.getLineLength(lastLine) -
getLineDelimiter(doc, lastLine).length();
String lastLineEnding = end == lastLineEnd ? "" : doc.get(end, lastLineEnd - end).trim();
if (lastLineEnding.isEmpty()) {
end = lastLineEnd;
}
if(end < 0){
end = 0;
}else if(end > doc.getLength()){
end = doc.getLength();
}
//Changed due to new WTP version 1.5 R 2006.06.28 get selected text from document.
body = end == start? "" : doc.get(start, end - start); //$NON-NLS-1$
} catch (BadLocationException e1) {
ModelUIPlugin.getDefault().logError(e1);
}
String text = reformat ? formatText (doc, start, end - start, body, selection, startText, endText, newline) : (startText + body + endText);
int pos = text.indexOf("|"); //$NON-NLS-1$
if (pos >= 0) {
text = text.substring(0, pos) + text.substring(pos + 1);
} else {
pos = text.length();
}
if(start >=0 && end <= doc.getLength() && (end - start) >= 0 && !text.isEmpty()){
try {
doc.replace(start, end - start, text);
} catch (BadLocationException ex) {
ModelUIPlugin.getDefault().logError(ex);
}
ITextSelection sel = new TextSelection(start + pos, 0);
selProvider.setSelection(sel);
}
}
static boolean isEditable(ITextEditor editor) {
if(editor == null) return false;
return editor.isEditable();
}
protected boolean isEditable(IEditorInput input) {
if(input instanceof IFileEditorInput) {
IFile f = ((IFileEditorInput)input).getFile();
return f != null && !f.isReadOnly();
}
return true;
}
protected void modify(ISourceViewer v, Properties p, String[] texts) {
//override
}
protected void insertIntoEditor(final ISourceViewer v, Properties p, IPositionCorrector corrector) {
String startText = p.getProperty(PROPERTY_START_TEXT);
String endText = p.getProperty(PROPERTY_END_TEXT);
ISelectionProvider selProvider
= (ISelectionProvider)p.get(PROPERTY_SELECTION_PROVIDER);
if(selProvider == null) {
p.put(PROPERTY_SELECTION_PROVIDER, v.getSelectionProvider());
}
IDocument d = v.getDocument();
String[] texts = new String[] {startText, endText};
//do any auxiliary job here
modify(v, p, texts);
startText = texts[0];
endText = texts[1];
if(startText != null) {
p.setProperty(PROPERTY_START_TEXT, startText);
}
if(endText != null) {
p.setProperty(PROPERTY_END_TEXT, endText);
}
IEditorPart activeEditor = ModelUIPlugin.getDefault().getWorkbench()
.getActiveWorkbenchWindow().getActivePage().getActiveEditor();
insertIntoEditorInternal(d, p, corrector);
// Leave as is
if(v instanceof IIgnoreSelection) {
((IIgnoreSelection)v).setIgnore(true);
}
if (activeEditor != null) {
activeEditor.getSite().getPage().activate(activeEditor);
}
// Set Ignore false, to prevent focus losing.
if(v instanceof IIgnoreSelection) {
((IIgnoreSelection)v).setIgnore(false);
}
}
protected ITextSelection basicCorrectSelection(IStructuredModel model, int start, int end){
IDOMDocument xmlDocument = (model instanceof IDOMModel) ? ((IDOMModel) model).getDocument() : null;
if(xmlDocument != null){
if(start == end){
IndexedRegion region = model.getIndexedRegion(start);
if (region instanceof ElementImpl) {
ElementImpl element = (ElementImpl) region;
int startOffset = element.getStartOffset();
int startEndOffset = element.getStartEndOffset();
int endStartOffset = element.getEndStartOffset();
int endOffset = element.getEndOffset();
if(start >= startOffset && start <= startEndOffset){
if(start-startOffset < startEndOffset-start){
start = end = startOffset;
}else{
start = end = startEndOffset;
}
}else if(start >= endStartOffset && start <= endOffset){
if(start-endStartOffset < endOffset-start){
start = end = endStartOffset;
}else{
start = end = endOffset;
}
}
}else if(region instanceof DocumentTypeImpl){
DocumentTypeImpl element = (DocumentTypeImpl) region;
int startOffset = element.getStartOffset();
int endOffset = element.getEndOffset();
if(start >= startOffset && start <= endOffset){
if(start-startOffset < endOffset-start){
start = end = startOffset;
}else{
start = end = endOffset;
}
}else if(start >= endOffset && start <= endOffset){
if(start-endOffset < endOffset-start){
start = end = endOffset;
}else{
start = end = endOffset;
}
}
} else if(region instanceof CommentImpl) {
int startOffset = region.getStartOffset();
int endOffset = region.getEndOffset();
if(start >= startOffset && start <= endOffset) {
if(start-startOffset < endOffset-start){
start = end = startOffset;
}else{
start = end = endOffset;
}
}
}
}else{
IndexedRegion startRegion = model.getIndexedRegion(start);
IndexedRegion endRegion = model.getIndexedRegion(end);
if(startRegion != null && endRegion != null){
IndexedRegion commonRegion = findCommonRegion(startRegion, endRegion, start, end);
if(commonRegion != null){
if(commonRegion instanceof ElementImpl){
ElementImpl root = (ElementImpl) commonRegion;
ElementImpl firstElement = findElement(root, start, end);
if(firstElement != null){
ElementImpl lastElement = firstElement;
Node lastNode = firstElement;
while(lastNode.getNextSibling() != null){
lastNode = lastNode.getNextSibling();
if(lastNode instanceof ElementImpl){
ElementImpl element = (ElementImpl)lastNode;
if((element.getStartEndOffset() != element.getEndOffset() && element.getStartEndOffset() > start && element.getEndStartOffset() < end) ||
(element.getStartEndOffset() == element.getEndOffset() && element.getStartOffset() >= start && element.getEndOffset() <= end)){
lastElement = (ElementImpl)lastNode;
}else{
break;
}
}
}
if(firstElement != null){
start = firstElement.getStartOffset();
if(lastElement != null){
end = lastElement.getEndOffset();
}else{
end = firstElement.getEndOffset();
}
}
}else{
// first element -null
start = end = findMinimalDistance(startRegion, endRegion, start, end);
}
}
}else{
// common region -null
start = end = findMinimalDistance(startRegion, endRegion, start, end);
}
}
}
}
return new TextSelection(model.getStructuredDocument(), start, end-start);
}
private int findMinimalDistance(IndexedRegion startRegion, IndexedRegion endRegion, int start, int end){
int middle = start + (end-start)/2;
ElementImpl startElement = null;
if(startRegion instanceof Text){
startElement = (ElementImpl)((Text)startRegion).getParentNode();
}else if(startRegion instanceof ElementImpl){
startElement = (ElementImpl)startRegion;
}
ElementImpl endElement = null;
if(endRegion instanceof Text){
endElement = (ElementImpl)((Text)endRegion).getParentNode();
}else if(endRegion instanceof ElementImpl){
endElement = (ElementImpl)endRegion;
}
int[] offsets=new int[]{
startElement.getStartOffset(),
startElement.getStartEndOffset(),
startElement.getEndStartOffset(),
startElement.getEndOffset(),
endElement.getStartOffset(),
endElement.getStartEndOffset(),
endElement.getEndStartOffset(),
endElement.getEndOffset()
};
int[] distances=new int[8];
for(int i = 0; i < 8; i++){
distances[i] = Math.abs(offsets[i]-middle);
}
int minDistance = distances[0];
int offset = offsets[0];
for(int index = 0; index < distances.length; index++){
if(distances[index] < minDistance){
minDistance = distances[index];
offset = offsets[index];
}
}
return offset;
}
private ElementImpl findElement(ElementImpl root, int start, int end){
if((root.getStartEndOffset() != root.getEndOffset() && root.getStartEndOffset() > start && root.getEndStartOffset() < end) ||
(root.getStartEndOffset() == root.getEndOffset() && root.getStartOffset() >= start && root.getEndOffset() <= end)){
return root;
}else{
NodeList list = root.getChildNodes();
for(int index = 0; index < list.getLength(); index++){
Node child = list.item(index);
if(child instanceof ElementImpl){
ElementImpl result = findElement((ElementImpl)child, start, end);
if(result != null){
return result;
}
}
}
}
return null;
}
private IndexedRegion findCommonRegion(IndexedRegion startRegion, IndexedRegion endRegion, int start, int end){
if(startRegion.getStartOffset() == endRegion.getStartOffset()){
return startRegion;
}
IndexedRegion startElement = null;
if(startRegion instanceof Text){
startElement = (IndexedRegion)((Text)startRegion).getParentNode();
}else if(startRegion instanceof ElementImpl){
startElement = startRegion;
}
IndexedRegion endElement = null;
if(endRegion instanceof Text){
endElement = (IndexedRegion)((Text)endRegion).getParentNode();
}else if(endRegion instanceof ElementImpl){
endElement = endRegion;
}
// startElement loop
while(startElement != null){
// endElement loop
IndexedRegion elem = endElement;
while(elem != null){
if(startElement.getStartOffset() == elem.getStartOffset()){
return (IndexedRegion)startElement;
}
elem = (IndexedRegion)((Node)elem).getParentNode();
}
startElement = (IndexedRegion)((Node)startElement).getParentNode();
}
return null;
}
protected static String prepare (String text, String pattern, String replacer) {
String res = text;
int index;
while ((index = res.indexOf(pattern)) != -1) {
res = res.substring(0, index) + replacer + res.substring(index + pattern.length());
}
return res;
}
protected static String createIndent(String line, boolean increase, String lineDelimiter) {
String indentString = getIndentOfLine(line, lineDelimiter);
int tabWidth = IElementGenerator.NodeWriter.getTabWidth();
int displayedWidth = calculateDisplayedWidth(indentString, tabWidth);
if (increase)
displayedWidth += tabWidth;
return createIndent(displayedWidth);
}
protected static String createIndent(int displayedWidth) {
StringBuilder indent = new StringBuilder();
int tabWidth = IElementGenerator.NodeWriter.getTabWidth();
boolean useSpaces = IElementGenerator.NodeWriter.useSpaces();
if (useSpaces) {
while (indent.length() < displayedWidth) {
indent = indent.append(' ');
}
} else {
int width = 0;
while (width < displayedWidth) {
indent = indent.append(width + tabWidth <= displayedWidth ? '\t' : ' ');
width += width + tabWidth <= displayedWidth ? tabWidth : 1;
}
}
return indent.toString();
}
protected static String createIndent(IDocument doc, boolean increase, int offset) {
String lineDelimiter = getLineDelimiter(doc);
String lineText = "";
try {
int line = doc.getLineOfOffset(offset);
while (line >= 0) {
int lineOffset = doc.getLineOffset(line);
int lineLength = doc.getLineLength(line);
String text = lineLength == 0 ? "" : doc.get(lineOffset, lineLength);
if (text.trim().length() > 0) {
lineText = text;
break;
}
line--;
}
} catch (BadLocationException e) {
ModelUIPlugin.getPluginLog().logError(e);
}
return createIndent(lineText, increase, lineDelimiter);
}
protected static boolean shouldIncreaseIndent(StringBuilder buffer, int offset) {
return shouldIncreaseIndent(new Document(buffer.toString()), offset);
}
protected static boolean shouldIncreaseIndent(IDocument doc, int offset) {
try {
List<String> closingTags = new ArrayList<String>();
// Find first non-empty line to calculate indents
int line = doc.getLineOfOffset(offset);
String text = "";
while (line >= 0) {
int lineOffset = doc.getLineOffset(line);
int lineLength = doc.getLineLength(line);
lineLength = offset < lineOffset + lineLength ? offset - lineOffset : lineLength;
if (lineLength > 0) {
String lineText = doc.get(lineOffset, lineLength);
if (!lineText.trim().isEmpty()) {
text = lineText;
break;
}
}
line--;
}
int index = text.length();
while (index >= 0) {
index = text.lastIndexOf('<', index - 1);
if (index == -1) return false;
boolean closingTag = (index + 1 >= text.length() || '/' == text.charAt(index + 1));
int tagEnd = text.indexOf('>', index);
boolean selfClosingTag = (tagEnd == -1 || '/' == text.charAt(tagEnd - 1) || ('-' == text.charAt(tagEnd - 1) && '-' == text.charAt(tagEnd - 2)));
StringBuilder sb = new StringBuilder();
for (int i = index + 1; i < tagEnd; i++) {
char ch = text.charAt(i);
if (ch == '/') continue;
if (!Character.isJavaIdentifierStart(ch))
break;
sb.append(ch);
}
String tagName = sb.toString();
if ("br".equalsIgnoreCase(tagName) || "hr".equals(tagName))
continue;
if (closingTag) {
closingTags.add(tagName);
}
if (!closingTag && !selfClosingTag) {
int closingTagIndex = closingTags.indexOf(tagName);
if (closingTagIndex == -1)
return true; // No according closing tag found - so, the tag isn't closed
else
closingTags.remove(closingTagIndex);
}
}
} catch (BadLocationException e) {
ModelUIPlugin.getPluginLog().logError(e);
}
return false;
}
protected static int calMinIndentWidth(String text, String lineDelimiter) {
if (text == null)
return 0;
LineIterator textLines = new LineIterator(text);
int minIndentWidth = -1;
while (textLines.hasNext()) {
String line = (String)textLines.next();
int lineIndent = calculateDisplayedWidth(getIndentOfLine(line, lineDelimiter), IElementGenerator.NodeWriter.getTabWidth());
if (minIndentWidth == -1 || minIndentWidth > lineIndent)
minIndentWidth = lineIndent;
}
return minIndentWidth;
}
protected static String formatText(IDocument d, int offset, int length, String body, ITextSelection selection, String startText, String endText, String newline) {
String lineDelimiter = getLineDelimiter(d);
startText = trimNewLines(startText);
endText = trimNewLines(endText);
body = body == null ? "" : body;
int minStartTextIndentWidth = calMinIndentWidth(startText, lineDelimiter);
int minEndTextIndentWidth = calMinIndentWidth(endText, lineDelimiter);
int minBodyIndentWidth = calMinIndentWidth(body, lineDelimiter);
int tabWidth = IElementGenerator.NodeWriter.getTabWidth();
boolean indentBody = (startText.trim().length() > 0 && endText.trim().length() > 0);
boolean increaseIndent = shouldIncreaseIndent(d, offset);
String firstLineIndent = createIndent(d, increaseIndent, offset);
int bodyIndentWidth = calculateDisplayedWidth(firstLineIndent, tabWidth) +
(indentBody ? tabWidth : 0);
int selectedLineIndentWidth = calculateDisplayedWidth(
createIndent(d, false, selection.getOffset()), tabWidth);
String bodyPrefix = "";
String bodySuffix = "";
try {
bodyPrefix = selection.getOffset() == offset ? "" : d.get(offset, selection.getOffset() - offset);
bodySuffix = offset + length == selection.getOffset() + selection.getLength() ?
"" : d.get(selection.getOffset() + selection.getLength(),
offset + length - selection.getOffset() - selection.getLength());
} catch (BadLocationException e) {
ModelUIPlugin.getPluginLog().logError(e);
}
StringBuilder buffer = new StringBuilder();
boolean notFirstOrLast = false;
try {
int line = d.getLineOfOffset(offset);
int lineOffset = d.getLineOffset(line);
int lineLength = d.getLineLength(line);
notFirstOrLast = !d.get(lineOffset, offset-lineOffset).trim().isEmpty() && !d.get(offset, lineOffset+lineLength-offset).trim().isEmpty();
} catch (BadLocationException ex) {
ModelUIPlugin.getPluginLog().logError(ex);
}
boolean inlineFormatting =
startText.indexOf('\n') == -1 &&
endText.indexOf('\n') == -1 &&
((selection.getLength() != 0 && selection.getText().indexOf('\n') == -1) || notFirstOrLast);
if (inlineFormatting) {
String insertLine = bodyPrefix + bodySuffix;
String prefix = "";
String indent = "";
if (bodyPrefix.lastIndexOf('\n') != -1) {
if (insertLine.trim().isEmpty()) {
prefix = bodyPrefix.substring(0, bodyPrefix.lastIndexOf('\n') + 1);
} else {
prefix = bodyPrefix.substring(bodyPrefix.lastIndexOf('\n') + 1);
}
indent = firstLineIndent;
}
buffer.append(prefix)
.append(createIndent(calculateDisplayedWidth(indent, tabWidth)))
.append(startText.trim())
.append(selection.getText())
.append(endText.trim());
} else {
boolean appendLastDelimiter = true;
try {
int line = d.getLineOfOffset(offset + length);
int lineOffset = d.getLineOffset(line);
int lineLength = d.getLineLength(line) - (offset + length - lineOffset);
String lastLine = lineLength == 0 ? "" : d.get(offset + length, lineLength);
appendLastDelimiter = !lastLine.trim().isEmpty();
} catch (BadLocationException ex) {
ModelUIPlugin.getPluginLog().logError(ex);
}
int firstLineIndentWidth = calculateDisplayedWidth(firstLineIndent, tabWidth);
int indentWidth = 0;
if (!startText.trim().isEmpty()) {
LineIterator textLines = new LineIterator(startText);
while (textLines.hasNext()) {
String line = (String)textLines.next();
indentWidth = firstLineIndentWidth + calculateDisplayedWidth(getIndentOfLine(line, lineDelimiter), tabWidth) - minStartTextIndentWidth;
buffer = buffer.append(lineDelimiter);
buffer = buffer.append(createIndent(indentWidth));
buffer = buffer.append(line.trim());
}
}
if (!selection.getText().trim().isEmpty()) {
bodyIndentWidth = indentWidth + (shouldIncreaseIndent(buffer, buffer.length()) ?
tabWidth : 0);
LineIterator textLines = new LineIterator(selection.getText());
while (textLines.hasNext()) {
String line = (String)textLines.next();
indentWidth = bodyIndentWidth + calculateDisplayedWidth(getIndentOfLine(line, lineDelimiter), tabWidth) - minBodyIndentWidth;
buffer = buffer.append(lineDelimiter);
buffer = buffer.append(createIndent(indentWidth));
buffer = buffer.append(line.trim());
}
} else {
if ((startText.indexOf('|') == -1) &&
(endText.indexOf('|') == -1))
buffer.append('|');
}
if (!endText.trim().isEmpty()) {
LineIterator textLines = new LineIterator(endText);
while (textLines.hasNext()) {
String line = (String)textLines.next();
indentWidth = firstLineIndentWidth + calculateDisplayedWidth(getIndentOfLine(line, lineDelimiter), tabWidth) - minEndTextIndentWidth;
indentWidth = firstLineIndentWidth + calculateDisplayedWidth(getIndentOfLine(line, lineDelimiter), tabWidth) - minStartTextIndentWidth;
buffer = buffer.append(lineDelimiter);
buffer = buffer.append(createIndent(indentWidth));
buffer = buffer.append(line.trim());
}
}
if (appendLastDelimiter && !inlineFormatting) {
String ending = "";
int selectionEnd = selection.getOffset() + selection.getLength();
try {
int endLine = d.getLineOfOffset(selectionEnd);
int selectionLineEnd = d.getLineOffset(endLine) + d.getLineLength(endLine);
ending = selectionEnd == selectionLineEnd ?
"" : d.get(selectionEnd, selectionLineEnd - selectionEnd).trim();
} catch (BadLocationException e) {
ModelUIPlugin.getPluginLog().logError(e);
}
indentWidth = selectedLineIndentWidth;
buffer = buffer.append(lineDelimiter);
buffer = buffer.append(createIndent(indentWidth));
}
}
return buffer.toString();
}
protected static String trimNewLines(String text) {
if (text == null) return "";
char[] data = text.toCharArray();
int start = 0;
while (start < data.length) {
if ('\n' != data[start] && '\r' != data[start])
break;
start++;
}
int end = data.length;
while (end > 0) {
if ('\n' != data[end - 1] && '\r' != data[end - 1])
break;
end--;
}
return new String(Arrays.copyOfRange(data, start, end));
}
/**
* Returns the displayed width of a string, taking in account the displayed tab width.
* The result can be compared against the print margin.
*/
protected static int calculateDisplayedWidth(String string, int tabWidth) {
int column= 0;
for (int i= 0; i < string.length(); i++)
if ('\t' == string.charAt(i))
column += tabWidth - (column % tabWidth);
else
column++;
return column;
}
protected static String getLineDelimiter(IDocument document, int line) throws BadLocationException {
String delim = document.getLineDelimiter(line);
return delim == null ? "" : delim;
}
public static String getLineDelimiter(IDocument document) {
try {
if (document.getNumberOfLines() > 1)
return document.getLineDelimiter(0);
} catch (BadLocationException e) {
ModelUIPlugin.getPluginLog().logError(e);
}
return System.getProperty("line.separator"); //$NON-NLS-1$
}
protected static String getIndentOfLine(String line, String lineDelimiter) {
int i= 0;
for (; i < line.length(); i++) {
if (!Character.isWhitespace(line.charAt(i)))
break;
if (lineDelimiter != null && lineDelimiter.indexOf(line.charAt(i)) != -1)
break;
}
return line.substring(0, i);
}
protected static final class LineIterator implements Iterator {
/** The document to iterator over. */
private final IDocument fDocument;
/** The line index. */
private int fLineIndex;
/**
* Creates a line iterator.
*/
public LineIterator(String string) {
fDocument= new Document(string);
}
/**
* @see java.util.Iterator#hasNext()
*/
public boolean hasNext() {
return fLineIndex != fDocument.getNumberOfLines();
}
/*
* @see java.util.Iterator#next()
*/
public Object next() {
try {
IRegion region= fDocument.getLineInformation(fLineIndex++);
return fDocument.get(region.getOffset(), region.getLength());
} catch (BadLocationException e) {
ModelUIPlugin.getPluginLog().logError(e);
throw new NoSuchElementException();
}
}
/*
* @see java.util.Iterator#remove()
*/
public void remove() {
throw new UnsupportedOperationException();
}
}
}