Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 80 additions & 11 deletions src/main/java/groovy/inspect/Inspector.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import groovy.lang.MetaClass;
import groovy.lang.MetaMethod;
import groovy.lang.PropertyValue;
import groovy.lang.Tuple2;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
import org.codehaus.groovy.runtime.InvokerHelper;

Expand Down Expand Up @@ -131,6 +132,25 @@ public Object[] getMethods() {
return result;
}

/**
* Get info about usual Java instance and class Methods as well as Constructors.
*/
public Tuple2[] getMethodsWithInfo() {
Method[] methods = getClassUnderInspection().getMethods();
Constructor[] ctors = getClassUnderInspection().getConstructors();
Tuple2[] result = new Tuple2[methods.length + ctors.length];
int resultIndex = 0;
for (; resultIndex < methods.length; resultIndex++) {
Method method = methods[resultIndex];
result[resultIndex] = Tuple2.tuple(method, methodInfo(method));
}
for (int i = 0; i < ctors.length; i++, resultIndex++) {
Constructor ctor = ctors[i];
result[resultIndex] = Tuple2.tuple(ctor, methodInfo(ctor));
}
return result;
}

/**
* Get info about instance and class Methods that are dynamically added through Groovy.
*
Expand All @@ -148,6 +168,21 @@ public Object[] getMetaMethods() {
return result;
}

/**
* Get info about instance and class Methods that are dynamically added through Groovy.
*/
public Tuple2[] getMetaMethodsWithInfo() {
MetaClass metaClass = InvokerHelper.getMetaClass(objectUnderInspection);
List<MetaMethod> metaMethods = metaClass.getMetaMethods();
Tuple2[] result = new Tuple2[metaMethods.size()];
int i = 0;
for (Iterator<MetaMethod> iter = metaMethods.iterator(); iter.hasNext(); i++) {
MetaMethod metaMethod = (MetaMethod) iter.next();
result[i] = Tuple2.tuple(metaMethod, methodInfo(metaMethod));
}
return result;
}

/**
* Get info about usual Java public fields incl. constants.
*
Expand Down Expand Up @@ -195,18 +230,35 @@ protected String[] fieldInfo(Field field) {
}

protected String[] fieldInfo(PropertyValue pv) {
String[] result = new String[MEMBER_VALUE_IDX + 1];
result[MEMBER_ORIGIN_IDX] = GROOVY;
result[MEMBER_MODIFIER_IDX] = "public";
result[MEMBER_DECLARER_IDX] = NOT_APPLICABLE;
result[MEMBER_TYPE_IDX] = shortName(pv.getType());
result[MEMBER_NAME_IDX] = pv.getName();
return fieldWithInfo(pv).getV2();
}

public Object[] getPropertiesWithInfo() {
List<PropertyValue> props = DefaultGroovyMethods.getMetaPropertyValues(objectUnderInspection);
Object[] result = new Object[props.size()];
int i = 0;
for (Iterator<PropertyValue> iter = props.iterator(); iter.hasNext(); i++) {
result[i] = fieldWithInfo(iter.next());
}
return result;
}

protected Tuple2<Object, String[]> fieldWithInfo(PropertyValue pv) {
String[] info = new String[MEMBER_VALUE_IDX + 1];
info[MEMBER_ORIGIN_IDX] = GROOVY;
info[MEMBER_MODIFIER_IDX] = "public";
info[MEMBER_DECLARER_IDX] = NOT_APPLICABLE;
info[MEMBER_TYPE_IDX] = shortName(pv.getType());
info[MEMBER_NAME_IDX] = pv.getName();
Object field = null;
try {
result[MEMBER_VALUE_IDX] = InvokerHelper.inspect(pv.getValue());
field = pv.getValue();
info[MEMBER_VALUE_IDX] = InvokerHelper.inspect(field);
} catch (Exception e) {
result[MEMBER_VALUE_IDX] = NOT_APPLICABLE;
info[MEMBER_VALUE_IDX] = NOT_APPLICABLE;
}
return withoutNulls(result);
info = withoutNulls(info);
return new Tuple2<>(field, info);
}

protected Class getClassUnderInspection() {
Expand Down Expand Up @@ -305,13 +357,18 @@ static void print(final PrintStream out, Object[] memberInfo) {
}

public static Collection sort(List<Object> memberInfo) {
memberInfo.sort(new MemberComparator());
return sort(memberInfo, new MemberComparator());
}

public static Collection sort(List<Object> memberInfo, Comparator<Object> comparator) {
memberInfo.sort(comparator);
return memberInfo;
}

public static class MemberComparator implements Comparator<Object>, Serializable {
private static final long serialVersionUID = -7691851726606749541L;

@Override
public int compare(Object a, Object b) {
String[] aStr = (String[]) a;
String[] bStr = (String[]) b;
Expand All @@ -329,4 +386,16 @@ public int compare(Object a, Object b) {
return result;
}
}
}

public static class MemberComparatorWithValue implements Comparator<Object>, Serializable {
private static final long serialVersionUID = 294298614093394525L;
private static final MemberComparator delegate = new MemberComparator();

@Override
public int compare(Object a, Object b) {
Tuple2<Object, String[]> aTuple = (Tuple2<Object, String[]>) a;
Tuple2<Object, String[]> bTuple = (Tuple2<Object, String[]>) b;
return delegate.compare(aTuple.getV2(), bTuple.getV2());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ import java.awt.BorderLayout
import java.awt.Cursor
import java.awt.Font
import java.awt.event.KeyEvent
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import java.util.prefs.Preferences
import java.util.regex.Pattern

Expand All @@ -58,10 +60,10 @@ import static java.awt.GridBagConstraints.NORTHWEST
import static java.awt.GridBagConstraints.WEST

/**
* This object is a GUI for looking at the AST that Groovy generates.
* This object is a GUI for looking at the AST that Groovy generates.
*
* Usage: java groovy.console.ui.AstBrowser [filename]
* where [filename] is an existing Groovy script.
* where [filename] is an existing Groovy script.
*/
class AstBrowser {

Expand Down Expand Up @@ -361,6 +363,50 @@ class AstBrowser {
return sw.toString()
}

def mouseListener(int valueCol, Closure pathClosure) {
def outer = this
new MouseAdapter() {
void mouseClicked(MouseEvent e) {
def table = e.source
if (e.clickCount == 2) {
launch(table, valueCol, pathClosure)
}
}

void mouseReleased(MouseEvent e) {
def table = e.source
int r = table.rowAtPoint(e.point)
if (r >= 0 && r < table.rowCount) {
table.setRowSelectionInterval(r, r)
} else {
table.clearSelection()
}

if (table.selectedRow < 0) return
if (e.isPopupTrigger()) {
def popup = swing.popupMenu {
menuItem(action(
name: 'Copy',
closure: outer.&copyAction.curry(table, e),
mnemonic: 'C',
accelerator: shortcut('C'),
smallIcon: imageIcon(resource: 'icons/page_copy.png', class: this),
shortDescription: 'Copy'
))
menuItem(action(
name: 'Browse',
enabled: table.model.getValueAt(table.selectedRow, valueCol) != null,
closure: outer.&launchAction.curry(table, valueCol, pathClosure),
smallIcon: imageIcon(resource: 'icons/page_white_go.png', class: this),
shortDescription: 'Browse'
))
}
popup.show(e.component, e.x, e.y)
}
}
}
}

private void showSource(view, String source, boolean showOnlyMethodCode, boolean isMethodNameAndMethodDescriptorAvailable, getPatternStr) {
swing.doLater {
view.textEditor.text = source
Expand Down Expand Up @@ -637,7 +683,7 @@ class TreeNodeWithProperties extends DefaultMutableTreeNode {
}

/**
* This interface is used to create tree nodes of various types
* This interface is used to create tree nodes of various types
*/
@CompileStatic
interface AstBrowserNodeMaker<T> {
Expand All @@ -647,7 +693,7 @@ interface AstBrowserNodeMaker<T> {
}

/**
* Creates tree nodes for swing UI
* Creates tree nodes for swing UI
*/
@CompileStatic
class SwingTreeNodeMaker implements AstBrowserNodeMaker<DefaultMutableTreeNode> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package groovy.console.ui

import javax.swing.JTable
import java.awt.event.MouseEvent

class CellValueToolTipJTable extends JTable {
public String getToolTipText(MouseEvent me) {
int viewRowIndex = rowAtPoint(me.point)
int viewColumnIndex = columnAtPoint(me.point)

def value = getValueAt(viewRowIndex, viewColumnIndex)

return (value != null ? String.valueOf(value) : null)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ smartHighlighterAction = action(
aboutAction = action(
name: 'About',
closure: controller.&showAbout,
smallIcon: imageIcon(resource: 'icons/information.png', class: this),
mnemonic: 'A'
)

Expand Down
Loading