swingui: class list toggable between class hierarchy and package hierarchy

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1148 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 25 years ago
parent 74acab5ec7
commit 15e5e76033
  1. 2
      jode/TODO
  2. 1
      jode/configure.in
  3. 270
      jode/jode/swingui/HierarchyTreeModel.java.in
  4. 93
      jode/jode/swingui/Main.java.in
  5. 1
      jode/jode/swingui/Makefile.am
  6. 43
      jode/jode/swingui/PackagesTreeModel.java.in

@ -21,7 +21,7 @@ DeObfuscator:
User Interface:
- make a nice user interface:
- list classnames: toggable between class hierarchie/package hierarchie.
~ list classnames: toggable between class hierarchie/package hierarchie.
- list fields/method of selected class.
- show decompilation of selected method.
- show usage of method/fields.

@ -202,6 +202,7 @@ jode/obfuscator/UniqueRenamer.java
jode/obfuscator/WildCard.java
jode/swingui/Main.java
jode/swingui/PackagesTreeModel.java
jode/swingui/HierarchyTreeModel.java
jode/type/Type.java
jode/util/SimpleSet.java
jode/util/SimpleMap.java

@ -0,0 +1,270 @@
/* HierarchyTreeModel Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.swingui;
import jode.Decompiler;
import jode.bytecode.ClassInfo;
import @JAVAX_SWING@.JProgressBar;
import @JAVAX_SWING@.tree.TreeModel;
import @JAVAX_SWING@.tree.TreePath;
import @JAVAX_SWING@.event.TreeModelListener;
import @JAVAX_SWING@.event.TreeModelEvent;
import @COLLECTIONEXTRA@.Comparable;
import @COLLECTIONS@.TreeSet;
import @COLLECTIONS@.Collection;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.HashMap;
import @COLLECTIONS@.Set;
import @COLLECTIONS@.HashSet;
import java.util.Enumeration;
import java.util.NoSuchElementException;
public class HierarchyTreeModel implements TreeModel, Runnable {
static final int MAX_PACKAGE_LEVEL = 10;
TreeElement root = new TreeElement("");
Set listeners = new HashSet();
JProgressBar progressBar;
Main main;
class TreeElement implements Comparable {
String fullName;
TreeSet childs;
boolean inClassPath = false;
public TreeElement(String fqn) {
this.fullName = fqn;
childs = new TreeSet();
}
public String getFullName() {
return fullName;
}
public void addChild(TreeElement child) {
childs.add(child);
}
public Collection getChilds() {
return childs;
}
public String toString() {
return fullName;
}
public int compareTo(Object o) {
TreeElement other = (TreeElement) o;
return fullName.compareTo(other.fullName);
}
public boolean equals(Object o) {
return (o instanceof TreeElement)
&& fullName.equals(((TreeElement)o).fullName);
}
public int hashCode() {
return fullName.hashCode();
}
}
private TreeElement handleClass(HashMap classes, ClassInfo clazz) {
if (clazz == null)
return root;
TreeElement elem = (TreeElement) classes.get(clazz);
if (elem != null)
return elem;
elem = new TreeElement(clazz.getName());
classes.put(clazz, elem);
if (!clazz.isInterface()) {
ClassInfo superClazz = clazz.getSuperclass();
handleClass(classes, superClazz).addChild(elem);
}
ClassInfo[] ifaces = clazz.getInterfaces();
for (int i=0; i < ifaces.length; i++)
handleClass(classes, ifaces[i]).addChild(elem);
if (ifaces.length == 0 && clazz.isInterface())
root.addChild(elem);
return elem;
}
public int readPackage(int depth, HashMap classes, String packageName,
int count) {
if (depth++ >= MAX_PACKAGE_LEVEL)
return count;
String prefix = packageName.length() == 0 ? "" : packageName + ".";
Enumeration enum =
ClassInfo.getClassesAndPackages(packageName);
while (enum.hasMoreElements()) {
//insert sorted and remove double elements;
String name = (String)enum.nextElement();
String fqn = prefix + name;
if (ClassInfo.isPackage(fqn)) {
count = readPackage(depth, classes, fqn, count);
} else {
TreeElement elem = handleClass(classes,
ClassInfo.forName(fqn));
if (progressBar != null)
progressBar.setValue(++count);
elem.inClassPath = true;
}
}
return count;
}
public int countClasses(int depth, String packageName) {
if (depth++ >= MAX_PACKAGE_LEVEL)
return 0;
int number = 0;
String prefix = packageName.length() == 0 ? "" : packageName + ".";
Enumeration enum =
ClassInfo.getClassesAndPackages(packageName);
while (enum.hasMoreElements()) {
//insert sorted and remove double elements;
String name = (String)enum.nextElement();
String fqn = prefix + name;
if (ClassInfo.isPackage(fqn)) {
number += countClasses(depth, fqn);
} else {
number++;
}
}
return number;
}
public HierarchyTreeModel(Main main) {
this.main = main;
this.progressBar = null;
rebuild();
}
public HierarchyTreeModel(Main main, JProgressBar progressBar) {
this.main = main;
this.progressBar = progressBar;
rebuild();
}
public void rebuild() {
Thread t = new Thread(this);
t.setPriority(Thread.MIN_PRIORITY);
t.start();
}
public void run() {
if (progressBar != null) {
progressBar.setMinimum(0);
progressBar.setMaximum(countClasses(0, ""));
}
readPackage(0, new HashMap(), "", 0);
TreeModelListener[] ls;
synchronized (listeners) {
ls = (TreeModelListener[])
listeners.toArray(new TreeModelListener[listeners.size()]);
}
TreeModelEvent ev = new TreeModelEvent(this, new Object[] { root });
for (int i=0; i< ls.length; i++)
ls[i].treeStructureChanged(ev);
main.reselect();
}
public void addTreeModelListener(TreeModelListener l) {
listeners.add(l);
}
public void removeTreeModelListener(TreeModelListener l) {
listeners.remove(l);
}
public void valueForPathChanged(TreePath path, Object newValue) {
// we don't allow values
}
public Object getChild(Object parent, int index) {
Iterator iter = ((TreeElement) parent).getChilds().iterator();
for (int i=0; i< index; i++)
iter.next();
return iter.next();
}
public int getChildCount(Object parent) {
return ((TreeElement) parent).getChilds().size();
}
public int getIndexOfChild(Object parent, Object child) {
Iterator iter = ((TreeElement) parent).getChilds().iterator();
int i=0;
while (iter.next() != child)
i++;
return i;
}
public Object getRoot() {
return root;
}
public boolean isLeaf(Object node) {
return ((TreeElement) node).getChilds().isEmpty();
}
public boolean isValidClass(Object node) {
return ((TreeElement) node).inClassPath;
}
public String getFullName(Object node) {
return ((TreeElement) node).getFullName();
}
public TreePath getPath(String fullName) {
if (fullName == null || fullName.length() == 0)
return new TreePath(root);
int length = 2;
ClassInfo ci = ClassInfo.forName(fullName);
while (ci.getSuperclass() != null) {
length++;
ci = ci.getSuperclass();
}
TreeElement[] path = new TreeElement[length];
path[0] = root;
int nr = 0;
next_component:
while (nr < length-1) {
ci = ClassInfo.forName(fullName);
for (int i=2; i < length - nr; i++)
ci = ci.getSuperclass();
Iterator iter = path[nr].getChilds().iterator();
while (iter.hasNext()) {
TreeElement te = (TreeElement) iter.next();
if (te.getFullName().equals(ci.getName())) {
path[++nr] = te;
continue next_component;
}
}
return null;
}
return new TreePath(path);
}
}

@ -35,11 +35,17 @@ public class Main
implements ActionListener, Runnable, TreeSelectionListener {
JFrame frame;
JTree classTree;
PackagesTreeModel classModel;
JPanel statusLine;
PackagesTreeModel packModel;
HierarchyTreeModel hierModel;
JTextArea sourcecodeArea, errorArea;
Thread decompileThread;
String currentClassPath, lastClassName;
JProgressBar progressBar;
boolean hierarchyTree;
public Main(String classpath) {
setClasspath(classpath);
frame = new JFrame(GlobalOptions.copyright);
@ -59,9 +65,12 @@ public class Main
}
public void fillContentPane(Container contentPane) {
statusLine = new JPanel();
hierarchyTree = false;
packModel = new PackagesTreeModel(this);
hierModel = null;
Font monospaced = new Font("monospaced", Font.PLAIN, 12);
classModel = new PackagesTreeModel();
classTree = new JTree(classModel);
classTree = new JTree(packModel);
classTree.setRootVisible(false);
DefaultTreeSelectionModel selModel = new DefaultTreeSelectionModel();
selModel.setSelectionMode(selModel.SINGLE_TREE_SELECTION);
@ -79,12 +88,17 @@ public class Main
spText, spError);
JSplitPane allPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
spClassTree, rightPane);
contentPane.add(allPane);
contentPane.setLayout(new BorderLayout());
contentPane.add(allPane, BorderLayout.CENTER);
contentPane.add(statusLine, BorderLayout.SOUTH);
progressBar = new JProgressBar();
statusLine.add(progressBar);
rightPane.setDividerLocation(300);
rightPane.setDividerSize(4);
allPane.setDividerLocation(200);
allPane.setDividerSize(4);
GlobalOptions.err = new PrintWriter(new AreaWriter(errorArea), true);
GlobalOptions.err = new PrintWriter
(new BufferedWriter(new AreaWriter(errorArea)), true);
}
public synchronized void valueChanged(TreeSelectionEvent e) {
@ -94,8 +108,14 @@ public class Main
if (path == null)
return;
Object node = path.getLastPathComponent();
if (node != null && classModel.isLeaf(node)) {
lastClassName = classModel.getFullName(node);
if (node != null) {
if (hierarchyTree && hierModel.isValidClass(node))
lastClassName = hierModel.getFullName(node);
else if (!hierarchyTree && packModel.isValidClass(node))
lastClassName = packModel.getFullName(node);
else
return;
decompileThread = new Thread(this);
decompileThread.setPriority(Thread.MIN_PRIORITY);
sourcecodeArea.setText("Please wait, while decompiling...\n");
@ -226,6 +246,28 @@ public class Main
menu.add(item);
bar.add(menu);
menu = new JMenu("Options");
final JCheckBoxMenuItem hierItem
= new JCheckBoxMenuItem("Class hierarchy", hierarchyTree);
hierItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
hierarchyTree = hierItem.isSelected();
if (hierarchyTree && hierModel == null) {
hierModel = new HierarchyTreeModel(Main.this, progressBar);
reselect();
}
classTree.setModel(hierarchyTree
? (TreeModel) hierModel : packModel);
if (lastClassName != null) {
TreePath lastPath = (hierarchyTree
? hierModel.getPath(lastClassName)
: packModel.getPath(lastClassName));
classTree.setSelectionPath(lastPath);
classTree.scrollPathToVisible(lastPath);
}
}
});
menu.add(hierItem);
menu.add(new JSeparator());
item = new JMenuItem("Set classpath...");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
@ -256,9 +298,42 @@ public class Main
classpath = ".";
currentClassPath = classpath;
ClassInfo.setClassPath(classpath);
if (classModel != null) {
if (classTree != null)
classTree.clearSelection();
classModel.rebuild();
if (packModel != null)
packModel.rebuild();
if (hierModel != null && hierarchyTree) {
hierModel.rebuild();
} else {
hierModel = null;
}
}
public void treeNodesChanged(TreeModelEvent e) {
reselect();
}
public void treeNodesInserted(TreeModelEvent e) {
reselect();
}
public void treeNodesRemoved(TreeModelEvent e) {
reselect();
}
public void treeStructureChanged(TreeModelEvent e) {
reselect();
}
public void reselect() {
if (lastClassName != null) {
TreePath lastPath = (hierarchyTree
? hierModel.getPath(lastClassName)
: packModel.getPath(lastClassName));
if (lastPath != null) {
classTree.setSelectionPath(lastPath);
classTree.scrollPathToVisible(lastPath);
}
}
}

@ -11,6 +11,7 @@ BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB)
MY_JAVA_FILES = \
Main.java \
HierarchyTreeModel.java \
PackagesTreeModel.java
noinst_DATA = $(MY_JAVA_FILES:.java=.class)

@ -40,6 +40,7 @@ import java.util.NoSuchElementException;
public class PackagesTreeModel implements TreeModel {
Map cachedChildrens = new HashMap();
Main main;
class TreeElement implements Comparable {
String fullName;
@ -89,6 +90,10 @@ public class PackagesTreeModel implements TreeModel {
TreeElement root = new TreeElement("", "", false);
Set listeners = new HashSet();
public PackagesTreeModel(Main main) {
this.main = main;
}
public void rebuild() {
cachedChildrens.clear();
TreeModelListener[] ls;
@ -99,6 +104,8 @@ public class PackagesTreeModel implements TreeModel {
TreeModelEvent ev = new TreeModelEvent(this, new Object[] { root });
for (int i=0; i< ls.length; i++)
ls[i].treeStructureChanged(ev);
main.reselect();
}
public TreeElement[] getChildrens(TreeElement parent) {
@ -158,7 +165,41 @@ public class PackagesTreeModel implements TreeModel {
}
public boolean isLeaf(Object node) {
return ((TreeElement)node).isLeaf();
return ((TreeElement) node).isLeaf();
}
public boolean isValidClass(Object node) {
return ((TreeElement) node).isLeaf();
}
public TreePath getPath(String fullName) {
if (fullName == null || fullName.length() == 0)
return new TreePath(root);
int pos = -1;
int length = 2;
while ((pos = fullName.indexOf('.', pos+1)) != -1)
length++;
TreeElement[] path = new TreeElement[length];
path[0] = root;
int i = 0;
pos = -1;
next_component:
while (pos < fullName.length()) {
int start = pos+1;
pos = fullName.indexOf('.', start);
if (pos == -1)
pos = fullName.length();
String component = fullName.substring(start, pos);
TreeElement[] childs = getChildrens(path[i]);
for (int j=0; j< childs.length; j++) {
if (childs[j].getName().equals(component)) {
path[++i] = childs[j];
continue next_component;
}
}
return null;
}
return new TreePath(path);
}
public String getFullName(Object node) {

Loading…
Cancel
Save