1 /*******************************************************************************
2  *  Copyright (c) 2005, 2008 IBM Corporation and others.
3  *
4  *  This program and the accompanying materials
5  *  are made available under the terms of the Eclipse Public License 2.0
6  *  which accompanies this distribution, and is available at
7  *  https://www.eclipse.org/legal/epl-2.0/
8  *
9  *  SPDX-License-Identifier: EPL-2.0
10  *
11  *  Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.pde.internal.ui.wizards.product;
15 
16 import org.eclipse.jface.text.*;
17 import org.eclipse.pde.internal.core.text.IDocumentAttributeNode;
18 import org.eclipse.pde.internal.core.text.IDocumentElementNode;
19 import org.eclipse.pde.internal.core.util.PDEXMLHelper;
20 import org.eclipse.text.edits.*;
21 
22 public class TextEditUtilities {
23 
getInsertOperation(IDocumentElementNode node, IDocument doc)24 	public static TextEdit getInsertOperation(IDocumentElementNode node, IDocument doc) {
25 		node = getHighestNodeToBeWritten(node, doc);
26 		if (node.getParentNode() == null)
27 			return new InsertEdit(0, node.write(true));
28 
29 		if (node.getOffset() > -1) {
30 			// this is an element that was of the form <element/>
31 			// it now needs to be broken up into <element><new/></element>
32 			return new ReplaceEdit(node.getOffset(), node.getLength(), node.write(false));
33 		}
34 		// try to insert after last sibling that has an offset
35 		TextEdit op = insertAfterSibling(node, doc);
36 
37 		// insert as first child of its parent if op is null
38 		return (op != null) ? op : insertAsFirstChild(node, doc);
39 	}
40 
addAttributeOperation(IDocumentAttributeNode attr, String newValue, IDocument doc)41 	public static TextEdit addAttributeOperation(IDocumentAttributeNode attr, String newValue, IDocument doc) {
42 		int offset = attr.getValueOffset();
43 		if (offset > -1)
44 			return new ReplaceEdit(offset, attr.getValueLength(), PDEXMLHelper.getWritableString(newValue));
45 
46 		IDocumentElementNode node = attr.getEnclosingElement();
47 		if (node.getOffset() > -1) {
48 			int len = getNextPosition(doc, node.getOffset(), '>');
49 			return new ReplaceEdit(node.getOffset(), len + 1, node.writeShallow(shouldTerminateElement(doc, node.getOffset() + len)));
50 		}
51 		return getInsertOperation(node, doc);
52 	}
53 
shouldTerminateElement(IDocument doc, int offset)54 	private static boolean shouldTerminateElement(IDocument doc, int offset) {
55 		try {
56 			return doc.get(offset - 1, 1).toCharArray()[0] == '/';
57 		} catch (BadLocationException e) {
58 		}
59 		return false;
60 	}
61 
getHighestNodeToBeWritten(IDocumentElementNode node, IDocument doc)62 	private static IDocumentElementNode getHighestNodeToBeWritten(IDocumentElementNode node, IDocument doc) {
63 		IDocumentElementNode parent = node.getParentNode();
64 		if (parent == null)
65 			return node;
66 		if (parent.getOffset() > -1) {
67 			try {
68 				String endChars = doc.get(parent.getOffset() + parent.getLength() - 2, 2);
69 				return ("/>".equals(endChars)) ? parent : node; //$NON-NLS-1$
70 			} catch (BadLocationException e) {
71 				return node;
72 			}
73 
74 		}
75 		return getHighestNodeToBeWritten(parent, doc);
76 	}
77 
insertAfterSibling(IDocumentElementNode node, IDocument doc)78 	private static InsertEdit insertAfterSibling(IDocumentElementNode node, IDocument doc) {
79 		IDocumentElementNode sibling = node.getPreviousSibling();
80 		for (;;) {
81 			if (sibling == null)
82 				break;
83 			if (sibling.getOffset() > -1) {
84 				node.setLineIndent(sibling.getLineIndent());
85 				String sep = TextUtilities.getDefaultLineDelimiter(doc);
86 				return new InsertEdit(sibling.getOffset() + sibling.getLength(), sep + node.write(true));
87 			}
88 			sibling = sibling.getPreviousSibling();
89 		}
90 		return null;
91 	}
92 
insertAsFirstChild(IDocumentElementNode node, IDocument doc)93 	private static InsertEdit insertAsFirstChild(IDocumentElementNode node, IDocument doc) {
94 		int offset = node.getParentNode().getOffset();
95 		int length = getNextPosition(doc, offset, '>');
96 		node.setLineIndent(node.getParentNode().getLineIndent() + 3);
97 		String sep = TextUtilities.getDefaultLineDelimiter(doc);
98 		return new InsertEdit(offset + length + 1, sep + node.write(true));
99 	}
100 
getNextPosition(IDocument doc, int offset, char ch)101 	private static int getNextPosition(IDocument doc, int offset, char ch) {
102 		int i = 0;
103 		try {
104 			for (i = 0; i + offset < doc.getLength(); i++) {
105 				if (ch == doc.get(offset + i, 1).toCharArray()[0])
106 					break;
107 			}
108 		} catch (BadLocationException e) {
109 		}
110 		return i;
111 	}
112 
113 }
114