/******************************************************************************* * 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(); } } }