Refactoring ClassFileTreeNodeFactoryProvider

This commit is contained in:
emmanue1 2015-06-02 19:25:24 +02:00
parent 1a5b82a03b
commit f7c4eab301
2 changed files with 423 additions and 386 deletions

View File

@ -0,0 +1,416 @@
/*
* Copyright (c) 2008-2015 Emmanuel Dupuy
* This program is made available under the terms of the GPLv3 License.
*/
package jd.gui.service.treenode
import groovy.transform.CompileStatic
import jd.gui.api.API
import jd.gui.api.feature.PageCreator
import jd.gui.api.feature.TreeNodeExpandable
import jd.gui.api.feature.UriGettable
import jd.gui.api.model.Container
import jd.gui.api.model.Type
import jd.gui.view.data.TreeNodeBean
import javax.swing.*
import javax.swing.tree.DefaultMutableTreeNode
abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeFactoryProvider {
static class BaseTreeNode extends DefaultMutableTreeNode implements UriGettable, PageCreator {
Container.Entry entry
PageFactory pageFactory;
URI uri
BaseTreeNode(Container.Entry entry, String fragment, Object userObject, PageFactory pageFactory) {
super(userObject)
this.entry = entry
this.pageFactory = pageFactory
if (fragment) {
def uri = entry.uri
this.uri = new URI(uri.scheme, uri.host, uri.path, fragment)
} else {
this.uri = entry.uri
}
}
// --- UriGettable --- //
URI getUri() { uri }
// --- PageCreator --- //
public <T extends JComponent & UriGettable> T createPage(API api) {
// Lazy 'tip' initialization
def file = new File(entry.container.root.uri)
def tip = "<html>Location: $file.path"
entry.inputStream.withStream { is ->
is.skip(4) // Skip magic number
int minorVersion = readUnsignedShort(is)
int majorVersion = readUnsignedShort(is)
if (majorVersion >= 49) {
tip += "<br>Java compiler version: ${majorVersion - (49-5)} ($majorVersion.$minorVersion)"
} else if (majorVersion >= 45) {
tip += "<br>Java compiler version: 1.${majorVersion - (45-1)} ($majorVersion.$minorVersion)"
}
}
tip += "</html>"
userObject.tip = tip
return pageFactory.make(api, entry)
}
/**
* @see java.io.DataInputStream#readUnsignedShort()
*/
@CompileStatic
int readUnsignedShort(InputStream is) throws IOException {
int ch1 = is.read()
int ch2 = is.read()
if ((ch1 | ch2) < 0)
throw new EOFException()
return (ch1 << 8) + (ch2 << 0)
}
}
static class FileTreeNode extends BaseTreeNode implements TreeNodeExpandable {
boolean initialized
FileTreeNode(Container.Entry entry, Object userObject, PageFactory pageFactory) {
this(entry, null, userObject, pageFactory)
}
FileTreeNode(Container.Entry entry, String fragment, Object userObject, PageFactory pageFactory) {
super(entry, fragment, userObject, pageFactory)
initialized = false
// Add dummy node
add(new DefaultMutableTreeNode())
}
// --- TreeNodeExpandable --- //
void populateTreeNode(API api) {
if (!initialized) {
removeAllChildren()
// Create type node
def type = api.getTypeFactory(entry).make(api, entry, null)
if (type) {
add(new TypeTreeNode(entry, type, new TreeNodeBean(label: type.displayTypeName, icon: type.icon), pageFactory))
}
initialized = true
}
}
}
static class TypeTreeNode extends BaseTreeNode implements TreeNodeExpandable {
boolean initialized
Type type
TypeTreeNode(Container.Entry entry, Type type, Object userObject, PageFactory pageFactory) {
super(entry, type.name, userObject, pageFactory)
this.initialized = false
this.type = type
// Add dummy node
add(new DefaultMutableTreeNode())
}
// --- TreeNodeExpandable --- //
void populateTreeNode(API api) {
if (!initialized) {
removeAllChildren()
def sb = new StringBuffer()
def typeAccess = type.flags
def typeName = type.name
def constructorName = type.displayInnerTypeName ?: type.displayTypeName
def isInnerClass = (type.displayInnerTypeName != null)
// Create inner types
type.innerTypes.sort { t1, t2 ->
t1.name.compareTo(t2.name)
}.each {
add(new TypeTreeNode(entry, it, new TreeNodeBean(label: it.displayInnerTypeName, icon: it.icon), pageFactory))
}
// Create fields
type.fields.collect {
sb.setLength(0)
sb.append(it.name).append(' : ')
writeSignature(sb, it.descriptor, it.descriptor.length(), 0, false)
def label = sb.toString()
def fragment = typeName + '-' + it.name + '-' + it.descriptor
return new FieldOrMethodBean(fragment:fragment, label:label, icon:it.icon)
}.sort { f1, f2 ->
f1.label.compareTo(f2.label)
}.each {
add(new FieldOrMethodTreeNode(entry, it.fragment, new TreeNodeBean(label: it.label, icon: it.icon), pageFactory))
}
// Create methods
type.methods.collect {
sb.setLength(0)
writeMethodSignature(sb, typeAccess, it.flags, isInnerClass, constructorName, it.name, it.descriptor)
def label = sb.toString()
def fragment = typeName + '-' + it.name + '-' + it.descriptor
return new FieldOrMethodBean(fragment:fragment, label:label, icon:it.icon)
}.sort { m1, m2 ->
m1.label.compareTo(m2.label)
}.each {
add(new FieldOrMethodTreeNode(entry, it.fragment, new TreeNodeBean(label: it.label, icon: it.icon), pageFactory))
}
initialized = true
}
}
int writeSignature(StringBuffer sb, String descriptor, int length, int index, boolean varargsFlag) {
while (true) {
// Print array : '[[?' ou '[L[?;'
int dimensionLength = 0
if (descriptor.charAt(index) == '[') {
dimensionLength++;
while (++index < length) {
if ((descriptor.charAt(index) == 'L') && (index+1 < length) && (descriptor.charAt(index+1) == '[')) {
index++
length--
dimensionLength++;
} else if (descriptor.charAt(index) == '[') {
dimensionLength++
} else {
break
}
}
}
switch(descriptor.charAt(index)) {
case 'B':
sb.append('byte')
index++
break
case 'C':
sb.append('char')
index++
break
case 'D':
sb.append('double')
index++
break
case 'F':
sb.append('float')
index++
break
case 'I':
sb.append('int')
index++
break
case 'J':
sb.append('long')
index++
break
case 'L': case '.':
int beginIndex = ++index
char c = '.'
// Search ; or de <
while (index < length) {
c = descriptor.charAt(index)
if ((c == ';') || (c == '<'))
break
index++
}
String internalClassName = descriptor.substring(beginIndex, index)
int lastPackageSeparatorIndex = internalClassName.lastIndexOf('/')
if (lastPackageSeparatorIndex >= 0) {
// Cut package name
internalClassName = internalClassName.substring(lastPackageSeparatorIndex + 1)
}
sb.append(internalClassName.replace('$', '.'))
if (c == '<') {
sb.append('<')
index = writeSignature(sb, descriptor, length, index+1, false)
while (descriptor.charAt(index) != '>') {
sb.append(', ')
index = writeSignature(sb, descriptor, length, index, false)
}
sb.append('>')
// pass '>'
index++
}
// pass ';'
if (descriptor.charAt(index) == ';')
index++
break
case 'S':
sb.append('short')
index++
break
case 'T':
int beginIndex = ++index
index = descriptor.substring(beginIndex, length).indexOf(';')
sb.append(descriptor.substring(beginIndex, index))
index++
break;
case 'V':
sb.append('void')
index++
break
case 'Z':
sb.append('boolean')
index++
break
case '-':
sb.append('? ').append('super').append(' ')
index = writeSignature(sb, descriptor, length, index+1, false)
break;
case '+':
sb.append('? ').append('extends').append(' ')
index = writeSignature(sb, descriptor, length, index+1, false)
break;
case '*':
sb.append('?')
index++
break
case 'X': case 'Y':
sb.append('int')
index++
break
default:
throw new RuntimeException('SignatureWriter.WriteSignature: invalid signature "' + descriptor + '"')
}
if (varargsFlag)
{
if (dimensionLength > 0)
{
while (--dimensionLength > 0)
sb.append('[]')
sb.append('...')
}
}
else
{
while (dimensionLength-- > 0)
sb.append('[]')
}
if ((index >= length) || (descriptor.charAt(index) != '.'))
break
sb.append('.')
}
return index
}
void writeMethodSignature(
StringBuffer sb, int typeAccess, int methodAccess, boolean isInnerClass,
String constructorName, String methodName, String descriptor) {
if (methodName.equals('<clinit>')) {
sb.append('{...}')
} else {
boolean isAConstructor = methodName.equals('<init>')
if (isAConstructor) {
sb.append(constructorName)
} else {
sb.append(methodName)
}
// Skip generics
int length = descriptor.length()
int index = 0
while ((index < length) && (descriptor.charAt(index) != '('))
index++
if (descriptor.charAt(index) != '(') {
throw RuntimeException('Signature format exception: "' + descriptor + '"');
}
sb.append('(')
// pass '('
index++
if (descriptor.charAt(index) != ')') {
if (isAConstructor && isInnerClass && ((typeAccess & Type.FLAG_STATIC) == 0)) {
// Skip first parameter
int lengthBackup = sb.length()
index = writeSignature(sb, descriptor, length, index, false)
sb.setLength(lengthBackup)
}
if (descriptor.charAt(index) != ')') {
int varargsParameterIndex
if ((methodAccess & Type.FLAG_VARARGS) == 0) {
varargsParameterIndex = Integer.MAX_VALUE
} else {
// Count parameters
int indexBackup = index
int lengthBackup = sb.length()
varargsParameterIndex = -1
while (descriptor.charAt(index) != ')') {
index = writeSignature(sb, descriptor, length, index, false)
varargsParameterIndex++
}
index = indexBackup
sb.setLength(lengthBackup)
}
// Write parameters
index = writeSignature(sb, descriptor, length, index, false)
int parameterIndex = 1
while (descriptor.charAt(index) != ')') {
sb.append(', ')
index = writeSignature(sb, descriptor, length, index, (parameterIndex == varargsParameterIndex))
parameterIndex++
}
}
}
if (isAConstructor) {
sb.append(')')
} else {
sb.append(') : ')
writeSignature(sb, descriptor, length, ++index, false)
}
}
}
}
static class FieldOrMethodTreeNode extends BaseTreeNode {
FieldOrMethodTreeNode(Container.Entry entry, String fragment, Object userObject, PageFactory pageFactory) {
super(entry, fragment, userObject, pageFactory)
}
}
static class FieldOrMethodBean {
String fragment, label
Icon icon
}
interface PageFactory {
public <T extends JComponent & UriGettable> T make(API api, Container.Entry entry);
}
}

View File

@ -5,20 +5,16 @@
package jd.gui.service.treenode
import groovy.transform.CompileStatic
import jd.gui.api.API
import jd.gui.api.feature.PageCreator
import jd.gui.api.feature.TreeNodeExpandable
import jd.gui.api.feature.UriGettable
import jd.gui.api.model.Container
import jd.gui.api.model.Type
import jd.gui.view.component.ClassFilePage
import jd.gui.view.data.TreeNodeBean
import javax.swing.*
import javax.swing.tree.DefaultMutableTreeNode
class ClassFileTreeNodeFactoryProvider extends AbstractTreeNodeFactoryProvider {
class ClassFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryProvider {
static final ImageIcon CLASS_FILE_ICON = new ImageIcon(ClassFileTreeNodeFactoryProvider.class.classLoader.getResource('images/classf_obj.png'))
static {
@ -36,388 +32,13 @@ class ClassFileTreeNodeFactoryProvider extends AbstractTreeNodeFactoryProvider {
public <T extends DefaultMutableTreeNode & UriGettable> T make(API api, Container.Entry entry) {
int lastSlashIndex = entry.path.lastIndexOf('/')
def name = entry.path.substring(lastSlashIndex+1)
return new ClassFileTreeNode(entry, new TreeNodeBean(label:name, icon:CLASS_FILE_ICON))
}
static abstract class AbstractTreeNode extends DefaultMutableTreeNode implements UriGettable, PageCreator {
Container.Entry entry
URI uri
AbstractTreeNode(Container.Entry entry, String fragment, Object userObject) {
super(userObject)
this.entry = entry
if (fragment) {
def uri = entry.uri
this.uri = new URI(uri.scheme, uri.host, uri.path, fragment)
} else {
this.uri = entry.uri
}
}
URI getUri() { uri }
public <T extends JComponent & UriGettable> T createPage(API api) {
// Lazy 'tip' initialization
def file = new File(entry.container.root.uri)
def tip = "<html>Location: $file.path"
entry.inputStream.withStream { is ->
is.skip(4) // Skip magic number
int minorVersion = readUnsignedShort(is)
int majorVersion = readUnsignedShort(is)
if (majorVersion >= 49) {
tip += "<br>Java compiler version: ${majorVersion - (49-5)} ($majorVersion.$minorVersion)"
} else if (majorVersion >= 45) {
tip += "<br>Java compiler version: 1.${majorVersion - (45-1)} ($majorVersion.$minorVersion)"
return new FileTreeNode(
entry,
new TreeNodeBean(label:name, icon:CLASS_FILE_ICON),
new AbstractTypeFileTreeNodeFactoryProvider.PageFactory() {
public <T extends JComponent & UriGettable> T make(API a, Container.Entry e) { new ClassFilePage(a, e) }
}
}
tip += "</html>"
userObject.tip = tip
return new ClassFilePage(api, entry)
}
/**
* @see java.io.DataInputStream#readUnsignedShort()
*/
@CompileStatic
int readUnsignedShort(InputStream is) throws IOException {
int ch1 = is.read()
int ch2 = is.read()
if ((ch1 | ch2) < 0)
throw new EOFException()
return (ch1 << 8) + (ch2 << 0)
}
}
static class ClassFileTreeNode extends AbstractTreeNode implements TreeNodeExpandable {
boolean initialized
ClassFileTreeNode(Container.Entry entry, Object userObject) {
this(entry, null, userObject)
}
ClassFileTreeNode(Container.Entry entry, String fragment, Object userObject) {
super(entry, fragment, userObject)
initialized = false
// Add dummy node
add(new DefaultMutableTreeNode())
}
void populateTreeNode(API api) {
if (!initialized) {
removeAllChildren()
// Create type node
def type = api.getTypeFactory(entry).make(api, entry, null)
add(new TypeTreeNode(entry, type, new TreeNodeBean(label: type.displayTypeName, icon: type.icon)))
initialized = true
}
}
}
static class TypeTreeNode extends AbstractTreeNode implements TreeNodeExpandable {
boolean initialized
Type type
TypeTreeNode(Container.Entry entry, Type type, Object userObject) {
super(entry, type.name, userObject)
this.initialized = false
this.type = type
// Add dummy node
add(new DefaultMutableTreeNode())
}
void populateTreeNode(API api) {
if (!initialized) {
removeAllChildren()
def sb = new StringBuffer()
def typeAccess = type.flags
def typeName = type.name
def constructorName = type.displayInnerTypeName ?: type.displayTypeName
def isInnerClass = (type.displayInnerTypeName != null)
// Create inner types
type.innerTypes.sort { t1, t2 ->
t1.name.compareTo(t2.name)
}.each {
add(new TypeTreeNode(entry, it, new TreeNodeBean(label: it.displayInnerTypeName, icon: it.icon)))
}
// Create fields
type.fields.collect {
sb.setLength(0)
sb.append(it.name).append(' : ')
writeSignature(sb, it.descriptor, it.descriptor.length(), 0, false)
def label = sb.toString()
def fragment = typeName + '-' + it.name + '-' + it.descriptor
return new FieldOrMethodBean(fragment:fragment, label:label, icon:it.icon)
}.sort { f1, f2 ->
f1.label.compareTo(f2.label)
}.each {
add(new FieldOrMethodTreeNode(entry, it.fragment, new TreeNodeBean(label: it.label, icon: it.icon)))
}
// Create methods
type.methods.collect {
sb.setLength(0)
writeMethodSignature(sb, typeAccess, it.flags, isInnerClass, constructorName, it.name, it.descriptor)
def label = sb.toString()
def fragment = typeName + '-' + it.name + '-' + it.descriptor
return new FieldOrMethodBean(fragment:fragment, label:label, icon:it.icon)
}.sort { m1, m2 ->
m1.label.compareTo(m2.label)
}.each {
add(new FieldOrMethodTreeNode(entry, it.fragment, new TreeNodeBean(label: it.label, icon: it.icon)))
}
initialized = true
}
}
int writeSignature(StringBuffer sb, String descriptor, int length, int index, boolean varargsFlag) {
while (true) {
// Print array : '[[?' ou '[L[?;'
int dimensionLength = 0
if (descriptor.charAt(index) == '[') {
dimensionLength++;
while (++index < length) {
if ((descriptor.charAt(index) == 'L') && (index+1 < length) && (descriptor.charAt(index+1) == '[')) {
index++
length--
dimensionLength++;
} else if (descriptor.charAt(index) == '[') {
dimensionLength++
} else {
break
}
}
}
switch(descriptor.charAt(index)) {
case 'B':
sb.append('byte')
index++
break
case 'C':
sb.append('char')
index++
break
case 'D':
sb.append('double')
index++
break
case 'F':
sb.append('float')
index++
break
case 'I':
sb.append('int')
index++
break
case 'J':
sb.append('long')
index++
break
case 'L': case '.':
int beginIndex = ++index
char c = '.'
// Search ; or de <
while (index < length) {
c = descriptor.charAt(index)
if ((c == ';') || (c == '<'))
break
index++
}
String internalClassName = descriptor.substring(beginIndex, index)
int lastPackageSeparatorIndex = internalClassName.lastIndexOf('/')
if (lastPackageSeparatorIndex >= 0) {
// Cut package name
internalClassName = internalClassName.substring(lastPackageSeparatorIndex + 1)
}
sb.append(internalClassName.replace('$', '.'))
if (c == '<') {
sb.append('<')
index = writeSignature(sb, descriptor, length, index+1, false)
while (descriptor.charAt(index) != '>') {
sb.append(', ')
index = writeSignature(sb, descriptor, length, index, false)
}
sb.append('>')
// pass '>'
index++
}
// pass ';'
if (descriptor.charAt(index) == ';')
index++
break
case 'S':
sb.append('short')
index++
break
case 'T':
int beginIndex = ++index
index = descriptor.substring(beginIndex, length).indexOf(';')
sb.append(descriptor.substring(beginIndex, index))
index++
break;
case 'V':
sb.append('void')
index++
break
case 'Z':
sb.append('boolean')
index++
break
case '-':
sb.append('? ').append('super').append(' ')
index = writeSignature(sb, descriptor, length, index+1, false)
break;
case '+':
sb.append('? ').append('extends').append(' ')
index = writeSignature(sb, descriptor, length, index+1, false)
break;
case '*':
sb.append('?')
index++
break
case 'X': case 'Y':
sb.append('int')
index++
break
default:
throw new RuntimeException('SignatureWriter.WriteSignature: invalid signature "' + descriptor + '"')
}
if (varargsFlag)
{
if (dimensionLength > 0)
{
while (--dimensionLength > 0)
sb.append('[]')
sb.append('...')
}
}
else
{
while (dimensionLength-- > 0)
sb.append('[]')
}
if ((index >= length) || (descriptor.charAt(index) != '.'))
break
sb.append('.')
}
return index
}
void writeMethodSignature(
StringBuffer sb, int typeAccess, int methodAccess, boolean isInnerClass,
String constructorName, String methodName, String descriptor) {
if (methodName.equals('<clinit>')) {
sb.append('{...}')
} else {
boolean isAConstructor = methodName.equals('<init>')
if (isAConstructor) {
sb.append(constructorName)
} else {
sb.append(methodName)
}
// Skip generics
int length = descriptor.length()
int index = 0
while ((index < length) && (descriptor.charAt(index) != '('))
index++
if (descriptor.charAt(index) != '(') {
throw RuntimeException('Signature format exception: "' + descriptor + '"');
}
sb.append('(')
// pass '('
index++
if (descriptor.charAt(index) != ')') {
if (isAConstructor && isInnerClass && ((typeAccess & Type.FLAG_STATIC) == 0)) {
// Skip first parameter
int lengthBackup = sb.length()
index = writeSignature(sb, descriptor, length, index, false)
sb.setLength(lengthBackup)
}
if (descriptor.charAt(index) != ')') {
int varargsParameterIndex
if ((methodAccess & Type.FLAG_VARARGS) == 0) {
varargsParameterIndex = Integer.MAX_VALUE
} else {
// Count parameters
int indexBackup = index
int lengthBackup = sb.length()
varargsParameterIndex = -1
while (descriptor.charAt(index) != ')') {
index = writeSignature(sb, descriptor, length, index, false)
varargsParameterIndex++
}
index = indexBackup
sb.setLength(lengthBackup)
}
// Write parameters
index = writeSignature(sb, descriptor, length, index, false)
int parameterIndex = 1
while (descriptor.charAt(index) != ')') {
sb.append(', ')
index = writeSignature(sb, descriptor, length, index, (parameterIndex == varargsParameterIndex))
parameterIndex++
}
}
}
if (isAConstructor) {
sb.append(')')
} else {
sb.append(') : ')
writeSignature(sb, descriptor, length, ++index, false)
}
}
}
}
static class FieldOrMethodTreeNode extends AbstractTreeNode {
FieldOrMethodTreeNode(Container.Entry entry, String fragment, Object userObject) {
super(entry, fragment, userObject)
}
}
static class FieldOrMethodBean {
String fragment, label
Icon icon
)
}
}