blob: cf52d0fbcd9bf53aad7de15c6e02c71747891f17 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 CEA LIST.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Ansgar Radermacher - ansgar.radermacher@cea.fr CEA LIST - initial API and implementation
*
*******************************************************************************/
package org.eclipse.papyrus.designer.languages.java.jdt.texteditor;
import org.eclipse.papyrus.designer.languages.common.extensionpoints.GenerationConstants;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Package;
/**
* Collection of utility operations that are used by the CDT editor.
*/
public class Utils {
public static final String nsSep = "::"; //$NON-NLS-1$
/**
* Decrease the indentation of a text block. This function is used during synchronization, since
* the code within an opaque behavior is not indented, whereas the code of an operation within a
* file is indented with a tab.
*/
public static String decreaseIndent(char[] contents, int start, int end) {
return decreaseIndent(contents, start, end, 4);
}
/**
* Decrease the indentation of a text block. This function is used during synchronization, since
* the code within an opaque behavior is not indented, whereas the code of an operation within a
* file is indented with a tab.
*/
public static String decreaseIndent(char[] contents, int start, int end, int indentation) {
String newBlock = ""; //$NON-NLS-1$
boolean newLine = true;
int consume = 0;
for (int i = start; i < end; i++) {
char c = contents[i];
// consume either a tab or 4 spaces;
if (newLine && (c == '\t')) {
consume = 1;
}
else if (newLine && (c == ' ')) {
consume = indentation;
}
else if (consume == 0 || c != ' ') {
newBlock += c;
consume = 0;
} else if (c == ' ') {
consume--;
} else {
consume = 0;
}
if ((c == '\n') || (c == '\r')) {
newLine = true;
} else {
newLine = false;
}
}
return newBlock;
}
/**
* Get an element via its qualified name. Will find elements from the root
* model and elements in imported models. Also supports target model in
* which imports have been copied (while keeping the top-level name)
*
* @param root
* @param qualifiedName
* @return the named element (or null, if not found)
*/
public static NamedElement getQualifiedElement(Package root,
String qualifiedName) {
NamedElement namedElement = null;
int index = qualifiedName.indexOf(nsSep);
if (index != -1) {
// first try using a path without top element (since
// getQualifiedElement is typically used for
// imported elements)
String remainder = qualifiedName.substring(index + 2);
namedElement = getQualifiedElement(root, remainder, qualifiedName);
}
if (namedElement == null) {
// try with complete name as path name, but assume that the element
// has been copied into the model,
// i.e. qualifiedName is prefixed by model name
namedElement = getQualifiedElement(root, qualifiedName,
root.getName() + nsSep + qualifiedName);
}
return namedElement;
}
/**
* Retrieve an element via its qualified name within a package The segments
* of the package may be non unique due to imports
*
* @return the found element, if it exists
*/
public static NamedElement getQualifiedElement(Package root,
String remainingPath, String qualifiedName) {
if (root == null) {
return null;
}
if (!remainingPath.contains(nsSep)) {
for (NamedElement candidate : root.getMembers()) {
String name = candidate.getName();
if ((name != null) && name.equals(remainingPath)) {
if (candidate.getQualifiedName().equals(qualifiedName)) {
return candidate;
}
}
}
} else {
String segment = remainingPath.split(nsSep)[0];
String remainder = remainingPath.substring(segment.length() + 2);
for (Element element : root.getMembers()) {
if (element instanceof Package) {
if (((NamedElement) element).getName().equals(segment)) {
NamedElement foundElement = getQualifiedElement(
(Package) element, remainder, qualifiedName);
// return, if not found
if (foundElement != null) {
return foundElement;
}
}
}
}
}
return null;
}
/**
* return the top-level owner of an element. This function returns the same
* value as getModel, if the top-level element is a model. While this is the
* case for models, model libraries have a top-level package (not a model).
* In this case, getTop returns the top-level package whereas getModel would
* return null.
*
* @param element
* @return the top-level owning package
*/
public static Package getTop(Element element) {
while (element != null) {
Element owner = element.getOwner();
if (owner == null) {
if (element instanceof Package) {
return (Package) element;
}
}
element = owner;
}
return null;
}
/**
* Remove generated code from a body (everything between the GENERATED_START flag
*
* @param bodyStr
* @return the code without the start and end tags
*/
public static String removeGenerated(String bodyStr) {
for (;;) {
int startPos = bodyStr.indexOf(GenerationConstants.GENERATED_START);
if (startPos == -1) {
break;
}
// search line break of previous line (if any)
while ((startPos > 0) && bodyStr.charAt(startPos) != '\r' && bodyStr.charAt(startPos) != '\n') {
startPos--;
}
int endPos = bodyStr.indexOf(GenerationConstants.GENERATED_END, startPos);
if (endPos == -1) {
break;
}
endPos += GenerationConstants.GENERATED_END.length();
// stop at first non white-space character after comment.
while ((endPos < bodyStr.length()) && Character.isWhitespace(bodyStr.charAt(endPos))) {
endPos++;
}
bodyStr = bodyStr.substring(0, startPos) + bodyStr.substring(endPos);
}
return bodyStr;
}
}