blob: ac259e3bd02268b9baff3f907483679a1b14bb7e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.refactoring.java.ui;
import java.awt.Color;
import java.awt.Component;
import java.io.CharConversionException;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.text.AttributeSet;
import javax.swing.text.StyleConstants;
import org.netbeans.api.editor.mimelookup.MimeLookup;
import org.netbeans.api.editor.mimelookup.MimePath;
import org.netbeans.api.editor.settings.FontColorSettings;
import org.netbeans.api.java.lexer.JavaTokenId;
import org.netbeans.api.java.source.ui.ScanDialog;
import org.netbeans.api.lexer.Token;
import org.netbeans.api.lexer.TokenHierarchy;
import org.netbeans.api.lexer.TokenSequence;
import org.netbeans.modules.parsing.api.ParserManager;
import org.netbeans.modules.refactoring.java.api.MemberInfo;
import org.netbeans.swing.plaf.LFCustoms;
import org.openide.util.Lookup;
import org.openide.xml.XMLUtil;
/**
* Class containing various utility methods and inner classes useful when
* creating refactoring UI.
*
* @author Martin Matula, Jan Becicka
*/
public final class UIUtilities {
// XXX: Remove "test_" when #211651 is fixed
private static final String TEST_JAVA_MIME_TYPE = "test_text/x-java"; // NOI18N
/**
* Element.Kind values allowed to be used when calling ElementHandle.create
*
* @see javax.lang.model.element.ElementKind
* @see org.netbeans.api.java.source.ElementHandle
*/
public static EnumSet allowedElementKinds = EnumSet.of(ElementKind.PACKAGE, ElementKind.CLASS, ElementKind.INTERFACE, ElementKind.ENUM, ElementKind.ANNOTATION_TYPE, ElementKind.METHOD, ElementKind.CONSTRUCTOR, ElementKind.INSTANCE_INIT, ElementKind.STATIC_INIT, ElementKind.FIELD, ElementKind.ENUM_CONSTANT, ElementKind.TYPE_PARAMETER);
// not to be instantiated
private UIUtilities() {
}
/**
* Returns the same string as passed in or " " if the passed string was an
* empty string. This method is used as a workaround for issue #58302.
*
* @param name Original table column name.
* @return "Fixed" column name.
*/
public static String getColumnName(String name) {
return name == null || name.length() == 0 ? " " : name; // NOI18N
}
/**
* Initializes preferred (and eventually maximum) width of a table column
* based on the size of its header and the estimated longest value.
*
* @param table Table to adjust the column width for.
* @param index Index of the column.
* @param longValue Estimated long value for the column.
* @param padding Number of pixes for padding.
*/
public static void initColumnWidth(JTable table, int index, Object longValue, int padding) {
TableColumn column = table.getColumnModel().getColumn(index);
// get preferred size of the header
TableCellRenderer headerRenderer = column.getHeaderRenderer();
if (headerRenderer == null) {
headerRenderer = table.getTableHeader().getDefaultRenderer();
}
Component comp = headerRenderer.getTableCellRendererComponent(
table, column.getHeaderValue(), false, false, 0, 0);
int width = comp.getPreferredSize().width;
// get preferred size of the long value (remeber max of the pref. size for header and long value)
comp = table.getDefaultRenderer(table.getModel().getColumnClass(index)).getTableCellRendererComponent(
table, longValue, false, false, 0, index);
width = Math.max(width, comp.getPreferredSize().width) + 2 * padding;
// set preferred width of the column
column.setPreferredWidth(width);
// if the column contains boolean values, the preferred width
// should also be its max width
if (longValue instanceof Boolean) {
column.setMaxWidth(width);
}
}
/**
* Table cell renderer that renders Java elements (instances of NamedElement
* and its subtypes). When rendering the elements it displays element's icon
* (if available) and display text.
*/
public static class JavaElementTableCellRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, extractText(value), isSelected, hasFocus, row, column);
if (value instanceof MemberInfo) {
Icon i = ((MemberInfo) value).getIcon();
setIcon(i);
} else {
setIcon(null);
}
return this;
}
/**
* Can be overriden to return alter the standard display text returned
* for elements.
*
* @param value Cell value.
* @return Display text.
*/
protected String extractText(Object value) {
if (value == null) {
return null;
}
if (value instanceof MemberInfo) {
return ((MemberInfo) value).getHtmlText();
} else {
return value.toString();
}
}
}
/**
* Table cell renderer that renders Java elements (instances of NamedElement
* and its subtypes). When rendering the elements it displays element's icon
* (if available) and display text.
*/
public static class JavaElementListCellRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, extractText(value), index, isSelected, cellHasFocus);
if (value instanceof MemberInfo) {
Icon i = ((MemberInfo) value).getIcon();
setIcon(i);
}
return this;
}
/**
* Can be overriden to return alter the standard display text returned
* for elements.
*
* @param value Cell value.
* @return Display text.
*/
protected String extractText(Object value) {
if (value instanceof MemberInfo) {
return ((MemberInfo) value).getHtmlText();
} else {
return value.toString();
}
}
}
/**
* Table cell renderer for boolean values (a little more advanced that the
* standard one). Enables hiding the combo box in case the value is
* <code>null</code> rather than
* <code>Boolean.TRUE</code> or
* <code>Boolean.FALSE</code> or in case of read-only cells to give a better
* visual feedback that the cells cannot be edited.
*/
public static class BooleanTableCellRenderer implements TableCellRenderer {
private final TableCellRenderer checkbox;
private final TableCellRenderer label;
public BooleanTableCellRenderer(JTable jt) {
this(jt.getDefaultRenderer(String.class), jt.getDefaultRenderer(Boolean.class));
}
private BooleanTableCellRenderer(TableCellRenderer label, TableCellRenderer checkbox) {
this.checkbox = checkbox;
this.label = label;
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
TableCellRenderer rend = value == null || !table.getModel().isCellEditable(row, column)
? label : checkbox;
// reset value in case the cell is not editable
value = value != null && rend == label ? null : value;
Component comp = rend.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
return comp;
}
}
public static String getHtml(String text) {
StringBuilder buf = new StringBuilder();
TokenHierarchy tokenH = TokenHierarchy.create(text, JavaTokenId.language());
Lookup lookup = MimeLookup.getLookup(MimePath.get(TEST_JAVA_MIME_TYPE));
FontColorSettings settings = lookup.lookup(FontColorSettings.class);
TokenSequence tok = tokenH.tokenSequence();
while (tok.moveNext()) {
Token<JavaTokenId> token = (Token) tok.token();
String category = token.id().primaryCategory();
if (category == null) {
category = "whitespace"; //NOI18N
}
AttributeSet set = settings.getTokenFontColors(category);
buf.append(color(htmlize(token.text().toString()), set));
}
return buf.toString();
}
private static String color(String string, AttributeSet set) {
if (set == null) {
return string;
}
if (string.trim().length() == 0) {
return string.replace(" ", "&nbsp;").replace("\n", "<br>"); //NOI18N
}
StringBuffer buf = new StringBuffer(string);
if (StyleConstants.isBold(set)) {
buf.insert(0, "<b>"); //NOI18N
buf.append("</b>"); //NOI18N
}
if (StyleConstants.isItalic(set)) {
buf.insert(0, "<i>"); //NOI18N
buf.append("</i>"); //NOI18N
}
if (StyleConstants.isStrikeThrough(set)) {
buf.insert(0, "<s>"); // NOI18N
buf.append("</s>"); // NOI18N
}
buf.insert(0, "<font color=" + getHTMLColor(LFCustoms.getForeground(set)) + ">"); //NOI18N
buf.append("</font>"); //NOI18N
return buf.toString();
}
private static String getHTMLColor(Color c) {
String colorR = "0" + Integer.toHexString(c.getRed()); //NOI18N
colorR = colorR.substring(colorR.length() - 2);
String colorG = "0" + Integer.toHexString(c.getGreen()); //NOI18N
colorG = colorG.substring(colorG.length() - 2);
String colorB = "0" + Integer.toHexString(c.getBlue()); //NOI18N
colorB = colorB.substring(colorB.length() - 2);
String html_color = "#" + colorR + colorG + colorB; //NOI18N
return html_color;
}
public static String htmlize(String input) {
String temp = input.replace("<", "&lt;"); // NOI18N
temp = temp.replace(">", "&gt;"); // NOI18N
return temp;
}
static String format(Element element) {
return format(element, false, false);
}
static String format(Element element, boolean forSignature, boolean FQNs) {
StringBuilder stringBuilder = new StringBuilder();
format(element, stringBuilder, forSignature, FQNs);
return stringBuilder.toString();
}
static void format(Element element, StringBuilder stringBuilder, boolean forSignature, boolean FQNs) {
if (element == null) {
return;
}
boolean first = true;
Set<Modifier> modifiers = element.getModifiers();
switch (element.getKind()) {
case PACKAGE:
PackageElement packageElement = (PackageElement) element;
if (forSignature) {
stringBuilder.append("package "); // NOI18N
}
stringBuilder.append(packageElement.getQualifiedName());
break;
case CLASS:
case INTERFACE:
case ENUM:
case ANNOTATION_TYPE:
if (forSignature) {
stringBuilder.append(toString(modifiers));
if (modifiers.size() > 0) {
if (stringBuilder.length() > 0) {
stringBuilder.append(" ");
}
}
}
if (forSignature) {
switch (element.getKind()) {
case CLASS:
stringBuilder.append("class "); // NOI18N
break;
case INTERFACE:
stringBuilder.append("interface "); // NOI18N
break;
case ENUM:
stringBuilder.append("enum "); // NOI18N
break;
case ANNOTATION_TYPE:
stringBuilder.append("@interface "); // NOI18N
break;
}
}
TypeElement typeElement = (TypeElement) element;
stringBuilder.append(FQNs
? typeElement.getQualifiedName().toString()
: typeElement.getSimpleName().toString());
formatTypeParameters(typeElement.getTypeParameters(), stringBuilder, FQNs);
break;
case CONSTRUCTOR:
if (forSignature) {
stringBuilder.append(toString(modifiers));
if (modifiers.size() > 0) {
if (stringBuilder.length() > 0) {
stringBuilder.append(" ");
}
}
}
ExecutableElement constructorElement = (ExecutableElement) element;
stringBuilder.append(constructorElement.getEnclosingElement()
.getSimpleName().toString());
stringBuilder.append("(");
formatVariableElements(constructorElement.getParameters(),
constructorElement.isVarArgs(), stringBuilder, FQNs);
stringBuilder.append(")");
List<? extends TypeMirror> thrownTypesMirrors = constructorElement.getThrownTypes();
if (!thrownTypesMirrors.isEmpty()) {
stringBuilder.append(" throws "); // NOI18N
formatTypeMirrors(thrownTypesMirrors, stringBuilder, FQNs);
}
break;
case METHOD:
ExecutableElement methodElement = (ExecutableElement) element;
TypeMirror returnTypeMirror = methodElement.getReturnType();
List<?extends TypeParameterElement> typeParameters = methodElement.getTypeParameters();
if (forSignature) {
stringBuilder.append(toString(modifiers));
if (modifiers.size() > 0) {
if (stringBuilder.length() > 0) {
stringBuilder.append(" ");
}
}
if ((typeParameters != null) && (typeParameters.size() > 0)) {
formatTypeParameters(typeParameters, stringBuilder, FQNs);
if (stringBuilder.length() > 0) {
stringBuilder.append(" ");
}
}
formatTypeMirror(returnTypeMirror, stringBuilder, FQNs);
}
if (stringBuilder.length() > 0) {
stringBuilder.append(" ");
}
stringBuilder.append(methodElement.getSimpleName().toString());
stringBuilder.append("(");
formatVariableElements(methodElement.getParameters(),
methodElement.isVarArgs(), stringBuilder, FQNs);
stringBuilder.append(")");
List<? extends TypeMirror> thrownTypesMirrorsByMethod = methodElement.getThrownTypes();
if (!thrownTypesMirrorsByMethod.isEmpty()) {
stringBuilder.append(" throws "); // NOI18N
formatTypeMirrors(thrownTypesMirrorsByMethod, stringBuilder, FQNs);
}
if (forSignature) {
AnnotationValue annotationValue = methodElement.getDefaultValue();
if (annotationValue != null) {
Object annotationValueValue = annotationValue.getValue();
if (annotationValueValue != null) {
stringBuilder.append(" default "); // NOI18N
if (annotationValueValue instanceof String) {
stringBuilder.append("\"");
} else if (annotationValueValue instanceof Character) {
stringBuilder.append("\'");
}
stringBuilder.append(String.valueOf(annotationValueValue));
if (annotationValueValue instanceof String) {
stringBuilder.append("\"");
} else if (annotationValueValue instanceof Character) {
stringBuilder.append("\'");
}
}
}
} else {
stringBuilder.append(":");
formatTypeMirror(returnTypeMirror, stringBuilder, FQNs);
if ((typeParameters != null) && (typeParameters.size() > 0)) {
stringBuilder.append(":");
formatTypeParameters(typeParameters, stringBuilder, FQNs);
}
}
break;
case TYPE_PARAMETER:
TypeParameterElement typeParameterElement = (TypeParameterElement) element;
stringBuilder.append(typeParameterElement.getSimpleName());
List<?extends TypeMirror> bounds = null;
try {
bounds = typeParameterElement.getBounds();
if ((bounds != null) && (bounds.size() > 0)) {
if(!(bounds.size() == 1 && "java.lang.Object".equals( bounds.get(0).toString()))) { // NOI18N
stringBuilder.append(" extends "); // NOI18N
first = true;
for (TypeMirror typeMirror : bounds) {
if (first) {
first = false;
} else {
stringBuilder.append(" & "); // NOI18N
}
formatTypeMirror(typeMirror, stringBuilder, FQNs);
}
}
}
} catch (NullPointerException npe) {
// Bug?
}
break;
case FIELD:
VariableElement fieldElement = (VariableElement) element;
if (forSignature) {
stringBuilder.append(toString(modifiers));
if (stringBuilder.length() > 0) {
stringBuilder.append(" ");
}
formatTypeMirror(fieldElement.asType(), stringBuilder, FQNs);
}
if (stringBuilder.length() > 0) {
stringBuilder.append(" ");
}
stringBuilder.append(fieldElement.getSimpleName().toString());
if (forSignature) {
Object fieldValue = fieldElement.getConstantValue();
if (fieldValue != null) {
stringBuilder.append(" = ");
if (fieldValue instanceof String) {
stringBuilder.append("\"");
} else if (fieldValue instanceof Character) {
stringBuilder.append("\'");
}
stringBuilder.append(String.valueOf(fieldValue));
if (fieldValue instanceof String) {
stringBuilder.append("\"");
} else if (fieldValue instanceof Character) {
stringBuilder.append("\'");
}
}
} else {
stringBuilder.append(":");
formatTypeMirror(fieldElement.asType(), stringBuilder, FQNs);
}
break;
case ENUM_CONSTANT:
stringBuilder.append(element.toString());
break;
case PARAMETER:
case LOCAL_VARIABLE:
VariableElement variableElement = (VariableElement) element;
formatTypeMirror(variableElement.asType(), stringBuilder, FQNs);
stringBuilder.append(" ");
stringBuilder.append(element.getSimpleName().toString());
break;
}
}
static void formatTypeMirror(TypeMirror typeMirror,
StringBuilder stringBuilder, boolean FQNs) {
if (typeMirror == null) {
return;
}
boolean first = true;
switch (typeMirror.getKind()) {
case BOOLEAN:
case BYTE:
case CHAR:
case DOUBLE:
case FLOAT:
case INT:
case LONG:
case NONE:
case NULL:
case SHORT:
case VOID:
stringBuilder.append(typeMirror);
break;
case TYPEVAR:
TypeVariable typeVariable = (TypeVariable)typeMirror;
stringBuilder.append(typeVariable.asElement().getSimpleName().toString());
break;
case WILDCARD:
WildcardType wildcardType = (WildcardType)typeMirror;
stringBuilder.append("?");
if ( wildcardType.getExtendsBound() != null ) {
stringBuilder.append(" extends "); // NOI18N
formatTypeMirror(wildcardType.getExtendsBound(), stringBuilder, FQNs);
}
if ( wildcardType.getSuperBound() != null ) {
stringBuilder.append(" super "); // NOI18N
formatTypeMirror(wildcardType.getSuperBound(), stringBuilder, FQNs);
}
break;
case DECLARED:
DeclaredType declaredType = (DeclaredType) typeMirror;
Element element = declaredType.asElement();
if (element instanceof TypeElement) {
stringBuilder.append(
FQNs ?
((TypeElement)element).getQualifiedName().toString() :
element.getSimpleName().toString());
} else {
stringBuilder.append(element.getSimpleName().toString());
}
List<? extends TypeMirror> typeArgs = declaredType.getTypeArguments();
if ( !typeArgs.isEmpty() ) {
stringBuilder.append("<");
formatTypeMirrors(typeArgs, stringBuilder, FQNs);
stringBuilder.append(">");
}
break;
case ARRAY:
int dims = 0;
while (typeMirror.getKind() == TypeKind.ARRAY) {
dims++;
typeMirror = ((ArrayType) typeMirror).getComponentType();
}
formatTypeMirror(typeMirror, stringBuilder, FQNs);
for (int i = 0; i < dims; i++) {
stringBuilder.append("[]");
}
break;
}
}
static void formatTypeParameters(
List<? extends TypeParameterElement> typeParameters,
StringBuilder stringBuilder, boolean FQNs) {
if ((typeParameters == null) || (typeParameters.size() == 0)) {
return;
}
boolean first = true;
if (typeParameters.size() > 0) {
stringBuilder.append("<");
first = true;
for (TypeParameterElement typeParameterElement : typeParameters) {
if (first) {
first = false;
} else {
stringBuilder.append(", ");
}
format(typeParameterElement, stringBuilder, false, FQNs);
}
stringBuilder.append(">");
}
}
static void formatVariableElements(
List<? extends VariableElement> variableElements, boolean varArgs,
StringBuilder stringBuilder, boolean FQNs) {
if ((variableElements == null) || (variableElements.size() == 0)) {
return;
}
boolean first = true;
for (VariableElement variableElement : variableElements) {
if (first) {
first = false;
} else {
stringBuilder.append(", ");
}
format(variableElement, stringBuilder, false, FQNs);
}
if (varArgs) {
stringBuilder.append("...");
}
}
static void formatTypeMirrors(List<?extends TypeMirror> thrownTypeMirros,
StringBuilder stringBuilder, boolean FQNs) {
if ((thrownTypeMirros == null) || (thrownTypeMirros.size() == 0)) {
return;
}
boolean first = true;
for (TypeMirror typeMirror : thrownTypeMirros) {
if (first) {
first = false;
} else {
stringBuilder.append(", ");
}
formatTypeMirror(typeMirror, stringBuilder, FQNs);
}
}
static int getIntModifiers(Set<Modifier> modifiers) {
int intModifiers = 0;
if (modifiers.contains(Modifier.ABSTRACT)) {
intModifiers |= java.lang.reflect.Modifier.ABSTRACT;
}
if (modifiers.contains(Modifier.FINAL)) {
intModifiers |= java.lang.reflect.Modifier.FINAL;
}
if (modifiers.contains(Modifier.NATIVE)) {
intModifiers |= java.lang.reflect.Modifier.NATIVE;
}
if (modifiers.contains(Modifier.PRIVATE)) {
intModifiers |= java.lang.reflect.Modifier.PRIVATE;
}
if (modifiers.contains(Modifier.PROTECTED)) {
intModifiers |= java.lang.reflect.Modifier.PROTECTED;
}
if (modifiers.contains(Modifier.PUBLIC)) {
intModifiers |= java.lang.reflect.Modifier.PUBLIC;
}
if (modifiers.contains(Modifier.STATIC)) {
intModifiers |= java.lang.reflect.Modifier.STATIC;
}
if (modifiers.contains(Modifier.STRICTFP)) {
intModifiers |= java.lang.reflect.Modifier.STRICT;
}
if (modifiers.contains(Modifier.SYNCHRONIZED)) {
intModifiers |= java.lang.reflect.Modifier.SYNCHRONIZED;
}
if (modifiers.contains(Modifier.TRANSIENT)) {
intModifiers |= java.lang.reflect.Modifier.TRANSIENT;
}
if (modifiers.contains(Modifier.VOLATILE)) {
intModifiers |= java.lang.reflect.Modifier.VOLATILE;
}
return intModifiers;
}
static String toString(Set<Modifier> modifiers) {
return java.lang.reflect.Modifier.toString(getIntModifiers(modifiers));
}
static Set<Modifier> getModifiers(int intModifiers) {
EnumSet<Modifier> modifiers = EnumSet.noneOf(Modifier.class);
if ((intModifiers & java.lang.reflect.Modifier.ABSTRACT) != 0) {
modifiers.add(Modifier.ABSTRACT);
}
if ((intModifiers & java.lang.reflect.Modifier.FINAL) != 0) {
modifiers.add(Modifier.FINAL);
}
if ((intModifiers & java.lang.reflect.Modifier.NATIVE) != 0) {
modifiers.add(Modifier.NATIVE);
}
if ((intModifiers & java.lang.reflect.Modifier.PRIVATE) != 0) {
modifiers.add(Modifier.PRIVATE);
}
if ((intModifiers & java.lang.reflect.Modifier.PROTECTED) != 0) {
modifiers.add(Modifier.PROTECTED);
}
if ((intModifiers & java.lang.reflect.Modifier.PUBLIC) != 0) {
modifiers.add(Modifier.PUBLIC);
}
if ((intModifiers & java.lang.reflect.Modifier.STATIC) != 0) {
modifiers.add(Modifier.STATIC);
}
if ((intModifiers & java.lang.reflect.Modifier.STRICT) != 0) {
modifiers.add(Modifier.STRICTFP);
}
if ((intModifiers & java.lang.reflect.Modifier.SYNCHRONIZED) != 0) {
modifiers.add(Modifier.SYNCHRONIZED);
}
if ((intModifiers & java.lang.reflect.Modifier.TRANSIENT) != 0) {
modifiers.add(Modifier.TRANSIENT);
}
if ((intModifiers & java.lang.reflect.Modifier.VOLATILE) != 0) {
modifiers.add(Modifier.VOLATILE);
}
return modifiers;
}
static String getClassName(String className) {
return getClassName(className, false);
}
static String getClassName(String className, boolean FQNs) {
// Handle generic type names i.e. strip off parameters
int firstLessThan = className.indexOf('<');
if (firstLessThan != -1) {
className = className.substring(0, firstLessThan);
}
if (!FQNs) {
int lastDot = className.lastIndexOf('.');
if (lastDot != -1) {
className = className.substring(lastDot + 1);
}
}
return className;
}
static String getClassNameSansPackage(String className) {
// Handle generic type names i.e. strip off parameters
int firstLessThan = className.indexOf('<');
if (firstLessThan != -1) {
className = className.substring(0, firstLessThan);
}
int lastDot = className.lastIndexOf('.');
if (lastDot != -1) {
className = className.substring(lastDot + 1);
}
return className;
}
// Tree movement
static void firstRow(JTree tree) {
int rowCount = tree.getRowCount();
if (rowCount > 0) {
tree.setSelectionRow(0);
scrollTreeToSelectedRow(tree);
}
}
static void previousRow(JTree tree) {
int rowCount = tree.getRowCount();
if (rowCount > 0) {
int selectedRow = tree.getSelectionModel().getMinSelectionRow();
if (selectedRow == -1) {
selectedRow = (rowCount -1);
} else {
selectedRow--;
if (selectedRow < 0) {
selectedRow = (rowCount -1);
}
}
tree.setSelectionRow(selectedRow);
scrollTreeToSelectedRow(tree);
}
}
static void nextRow(JTree tree) {
int rowCount = tree.getRowCount();
if (rowCount > 0) {
int selectedRow = tree.getSelectionModel().getMinSelectionRow();
if (selectedRow == -1) {
selectedRow = 0;
tree.setSelectionRow(selectedRow);
} else {
selectedRow++;
}
tree.setSelectionRow(selectedRow % rowCount);
scrollTreeToSelectedRow(tree);
}
}
static void lastRow(JTree tree) {
int rowCount = tree.getRowCount();
if (rowCount > 0) {
tree.setSelectionRow(rowCount - 1);
scrollTreeToSelectedRow(tree);
}
}
static void scrollTreeToSelectedRow(final JTree tree) {
final int selectedRow = tree.getLeadSelectionRow();
if (selectedRow >=0) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
tree.scrollRectToVisible(tree.getRowBounds(selectedRow));
}
}
);
}
}
static String escape(String s) {
if (s != null) {
try {
return XMLUtil.toAttributeValue(s);
} catch (CharConversionException ex) {
}
}
return null;
}
private static final String TYPE_COLOR = "#707070";
private static final String INHERITED_COLOR = "#7D694A";
/**
* Creates HTML display name of the Executable element
*/
public static String createHeader(ExecutableElement e, boolean isDeprecated, boolean isInherited, boolean html, boolean isBold) {
StringBuilder sb = new StringBuilder();
if (html) {
if (isDeprecated) {
sb.append("<s>"); // NOI18N
} else if (isBold) {
sb.append("<b>"); // NOI18N
}
if (isInherited) {
sb.append("<font color=" + INHERITED_COLOR + ">"); // NOI18N
}
}
Name name = e.getKind() == ElementKind.CONSTRUCTOR ? e.getEnclosingElement().getSimpleName() : e.getSimpleName();
sb.append(UIUtilities.escape(name.toString()));
if (html) {
if (isDeprecated) {
sb.append("</s>"); // NOI18N
}
}
sb.append("("); // NOI18N
List<? extends VariableElement> params = e.getParameters();
for (Iterator<? extends VariableElement> it = params.iterator(); it.hasNext();) {
VariableElement param = it.next();
if (html) {
sb.append("<font color=" + TYPE_COLOR + ">"); // NOI18N
}
final boolean vararg = !it.hasNext() && e.isVarArgs();
sb.append(printArg(param.asType(), vararg, html));
if (html) {
sb.append("</font>"); // NOI18N
}
sb.append(" "); // NOI18N
sb.append(UIUtilities.escape(param.getSimpleName().toString()));
if (it.hasNext()) {
sb.append(", "); // NOI18N
}
}
sb.append(")"); // NOI18N
if (html) {
if (!isDeprecated && isBold) {
sb.append("</b>"); // NOI18N
}
}
if (e.getKind() != ElementKind.CONSTRUCTOR) {
TypeMirror rt = e.getReturnType();
if (rt.getKind() != TypeKind.VOID) {
sb.append(" : "); // NOI18N
if (html) {
sb.append("<font color=" + TYPE_COLOR + ">"); // NOI18N
}
sb.append(print(e.getReturnType(), html));
if (html) {
sb.append("</font>"); // NOI18N
}
}
}
return sb.toString();
}
public static String createHeader(VariableElement e, boolean isDeprecated, boolean isInherited, boolean html, boolean isBold) {
StringBuilder sb = new StringBuilder();
if (html) {
if (isDeprecated) {
sb.append("<s>"); // NOI18N
} else if (isBold) {
sb.append("<b>"); // NOI18N
}
if (isInherited) {
sb.append("<font color=" + INHERITED_COLOR + ">"); // NOI18N
}
}
sb.append(UIUtilities.escape(e.getSimpleName().toString()));
if (html) {
if (isDeprecated) {
sb.append("</s>"); // NOI18N
} else if (isBold) {
sb.append("</b>"); // NOI18N
}
}
if (e.getKind() != ElementKind.ENUM_CONSTANT) {
sb.append(" : "); // NOI18N
if (html) {
sb.append("<font color=" + TYPE_COLOR + ">"); // NOI18N
}
sb.append(print(e.asType(), html));
if (html) {
sb.append("</font>"); // NOI18N
}
}
return sb.toString();
}
public static String createHeader(TypeParameterElement e, boolean isDeprecated, boolean isInherited, boolean html, boolean isBold) {
StringBuilder sb = new StringBuilder();
if (html) {
if (isDeprecated) {
sb.append("<s>"); // NOI18N
} else if (isBold) {
sb.append("<b>"); // NOI18N
}
if (isInherited) {
sb.append("<font color=" + INHERITED_COLOR + ">"); // NOI18N
}
}
sb.append(UIUtilities.escape(e.getSimpleName().toString()));
if (html) {
if (isDeprecated) {
sb.append("</s>"); // NOI18N
} else if (isBold) {
sb.append("</b>"); // NOI18N
}
}
if (e.getKind() != ElementKind.ENUM_CONSTANT) {
sb.append(" : "); // NOI18N
if (html) {
sb.append("<font color=" + TYPE_COLOR + ">"); // NOI18N
}
sb.append(print(e.asType(), html));
if (html) {
sb.append("</font>"); // NOI18N
}
}
return sb.toString();
}
public static String createHeader(PackageElement e, boolean isDeprecated, boolean isInherited, boolean html, boolean isBold) {
StringBuilder sb = new StringBuilder();
if (html) {
if (isDeprecated) {
sb.append("<s>"); // NOI18N
} else if (isBold) {
sb.append("<b>"); // NOI18N
}
if (isInherited) {
sb.append("<font color=" + INHERITED_COLOR + ">"); // NOI18N
}
}
sb.append(UIUtilities.escape(e.getSimpleName().toString()));
if (html) {
if (isDeprecated) {
sb.append("</s>"); // NOI18N
} else if (isBold) {
sb.append("</b>"); // NOI18N
}
}
if (e.getKind() != ElementKind.ENUM_CONSTANT) {
sb.append(" : "); // NOI18N
if (html) {
sb.append("<font color=" + TYPE_COLOR + ">"); // NOI18N
}
sb.append(print(e.asType(), html));
if (html) {
sb.append("</font>"); // NOI18N
}
}
return sb.toString();
}
public static String createHeader(TypeElement e, boolean isDeprecated, boolean isInherited, boolean html, boolean isBold) {
StringBuilder sb = new StringBuilder();
if (html) {
if (isDeprecated) {
sb.append("<s>"); // NOI18N
} else if (isBold) {
sb.append("<b>"); // NOI18N
}
if (isInherited) {
sb.append("<font color=" + INHERITED_COLOR + ">"); // NOI18N
}
}
sb.append(UIUtilities.escape(e.getSimpleName().toString()));
if(html) {
if (isDeprecated) {
sb.append("</s>"); // NOI18N
}
}
List<? extends TypeParameterElement> typeParams = e.getTypeParameters();
if (typeParams != null && !typeParams.isEmpty()) {
sb.append(html ? "&lt;" : "<"); // NOI18N
for (Iterator<? extends TypeParameterElement> it = typeParams.iterator(); it.hasNext();) {
TypeParameterElement tp = it.next();
sb.append(UIUtilities.escape(tp.getSimpleName().toString()));
List<? extends TypeMirror> bounds = null;
try {
bounds = tp.getBounds();
} catch (NullPointerException npe) {
// Ignore
}
if (bounds != null && !bounds.isEmpty()) {
sb.append(printBounds(bounds, html));
}
if (it.hasNext()) {
sb.append(", "); // NOI18N
}
}
sb.append(html ? "&gt;" : ">"); // NOI18N
}
if (html && !isDeprecated && isBold) {
sb.append("<b>"); // NOI18N
}
// Add superclass and implemented interfaces
TypeMirror sc = e.getSuperclass();
String scName = print(sc, html);
if (sc == null
|| e.getKind() == ElementKind.ENUM
|| e.getKind() == ElementKind.ANNOTATION_TYPE
|| "java.lang.Object".equals(sc.toString()) || // NOI18N
"<none>".equals(sc.toString())) { // NOI18N
scName = null;
}
List<? extends TypeMirror> ifaces = e.getInterfaces();
if ((scName != null || !ifaces.isEmpty())
&& e.getKind() != ElementKind.ANNOTATION_TYPE) {
sb.append(" :: "); // NOI18N
if (scName != null) {
if (html) {
sb.append("<font color=" + TYPE_COLOR + ">"); // NOI18N
}
sb.append(scName);
if (html) {
sb.append("</font>"); // NOI18N
}
}
if (!ifaces.isEmpty()) {
if (scName != null) {
sb.append(" : "); // NOI18N
}
for (Iterator<? extends TypeMirror> it = ifaces.iterator(); it.hasNext();) {
TypeMirror typeMirror = it.next();
if (html) {
sb.append("<font color=" + TYPE_COLOR + ">"); // NOI18N
}
sb.append(print(typeMirror, html));
if (html) {
sb.append("</font>"); // NOI18N
}
if (it.hasNext()) {
sb.append(", "); // NOI18N
}
}
}
}
return sb.toString();
}
public static boolean runWhenScanFinished (final Runnable runnable, final String actionName) {
return ScanDialog.runWhenScanFinished(
() -> {
if (ParserManager.isParsing()) {
SwingUtilities.invokeLater(runnable);
} else {
runnable.run();
}
},
actionName);
}
private static String printBounds(List<? extends TypeMirror> bounds, boolean html) {
if (bounds.size() == 1 && "java.lang.Object".equals(bounds.get(0).toString())) {
return "";
}
StringBuilder sb = new StringBuilder();
sb.append(" extends "); // NOI18N
for (Iterator<? extends TypeMirror> it = bounds.iterator(); it.hasNext();) {
TypeMirror bound = it.next();
sb.append(print(bound, html));
if (it.hasNext()) {
sb.append(" & "); // NOI18N
}
}
return sb.toString();
}
private static String printArg(final TypeMirror tm, final boolean varArg, boolean html) {
if (varArg) {
if (tm.getKind() == TypeKind.ARRAY) {
final ArrayType at = (ArrayType) tm;
final StringBuilder sb = new StringBuilder(print(at.getComponentType(), html));
sb.append("..."); //NOI18N
return sb.toString();
} else {
assert false : "Expected array: " + tm.toString() + " ( " + tm.getKind() + " )"; //NOI18N
}
}
return print(tm, html);
}
private static String print(TypeMirror tm, boolean html) {
StringBuilder sb;
switch (tm.getKind()) {
case DECLARED:
DeclaredType dt = (DeclaredType) tm;
sb = new StringBuilder(dt.asElement().getSimpleName().toString());
List<? extends TypeMirror> typeArgs = dt.getTypeArguments();
if (!typeArgs.isEmpty()) {
sb.append(html ? "&lt;" : "<"); // NOI18N
for (Iterator<? extends TypeMirror> it = typeArgs.iterator(); it.hasNext();) {
TypeMirror ta = it.next();
sb.append(print(ta, html));
if (it.hasNext()) {
sb.append(", ");
}
}
sb.append(html ? "&gt;" : ">"); // NOI18N
}
return sb.toString();
case TYPEVAR:
TypeVariable tv = (TypeVariable) tm;
sb = new StringBuilder(tv.asElement().getSimpleName().toString());
return sb.toString();
case ARRAY:
ArrayType at = (ArrayType) tm;
sb = new StringBuilder(print(at.getComponentType(), html));
sb.append("[]");
return sb.toString();
case WILDCARD:
WildcardType wt = (WildcardType) tm;
sb = new StringBuilder("?");
if (wt.getExtendsBound() != null) {
sb.append(" extends "); // NOI18N
sb.append(print(wt.getExtendsBound(), html));
}
if (wt.getSuperBound() != null) {
sb.append(" super "); // NOI18N
sb.append(print(wt.getSuperBound(), html));
}
return sb.toString();
default:
return UIUtilities.escape(tm.toString());
}
}
}