diff --git a/.gitignore b/.gitignore
index 613ec67bd..598439978 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,4 +65,7 @@ hs_err_pid*.log
/libsrc/cmykjpeg/nbproject/private/
/libsrc/Plugins/nbproject/private/
/libsrc/Plugins/build/
-/libsrc/Plugins/dist/
\ No newline at end of file
+/libsrc/Plugins/dist/
+/libsrc/treetable/nbproject/private/
+/libsrc/treetable/build/
+/libsrc/treetable/dist/
\ No newline at end of file
diff --git a/lib/flashdebugger.jar b/lib/flashdebugger.jar
index 8b7a7a60c..6f2c726d5 100644
Binary files a/lib/flashdebugger.jar and b/lib/flashdebugger.jar differ
diff --git a/lib/treetable.jar b/lib/treetable.jar
new file mode 100644
index 000000000..610bf18d4
Binary files /dev/null and b/lib/treetable.jar differ
diff --git a/libsrc/cmykjpeg/nbproject/build-impl.xml b/libsrc/cmykjpeg/nbproject/build-impl.xml
index 4044e3e5a..ed218bcac 100644
--- a/libsrc/cmykjpeg/nbproject/build-impl.xml
+++ b/libsrc/cmykjpeg/nbproject/build-impl.xml
@@ -191,7 +191,12 @@ is divided into following sections:
-
+
+
+
+
+
+
@@ -217,6 +222,7 @@ is divided into following sections:
+
@@ -693,7 +699,7 @@ is divided into following sections:
-
+
@@ -768,7 +774,7 @@ is divided into following sections:
-
+
@@ -795,7 +801,7 @@ is divided into following sections:
-
+
diff --git a/libsrc/cmykjpeg/nbproject/genfiles.properties b/libsrc/cmykjpeg/nbproject/genfiles.properties
index 605d6401d..1b65a7437 100644
--- a/libsrc/cmykjpeg/nbproject/genfiles.properties
+++ b/libsrc/cmykjpeg/nbproject/genfiles.properties
@@ -4,5 +4,5 @@ build.xml.stylesheet.CRC32=8064a381@1.75.2.48
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=73f9688e
-nbproject/build-impl.xml.script.CRC32=de1179e8
-nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48
+nbproject/build-impl.xml.script.CRC32=ce0b030d
+nbproject/build-impl.xml.stylesheet.CRC32=05530350@1.79.1.48
diff --git a/libsrc/jpproxy/nbproject/build-impl.xml b/libsrc/jpproxy/nbproject/build-impl.xml
index fa9ad0fbe..ec2302d65 100644
--- a/libsrc/jpproxy/nbproject/build-impl.xml
+++ b/libsrc/jpproxy/nbproject/build-impl.xml
@@ -189,7 +189,12 @@ is divided into following sections:
-
+
+
+
+
+
+
@@ -215,6 +220,7 @@ is divided into following sections:
+
@@ -680,7 +686,7 @@ is divided into following sections:
-
+
@@ -755,7 +761,7 @@ is divided into following sections:
-
+
@@ -782,7 +788,7 @@ is divided into following sections:
-
+
diff --git a/libsrc/jpproxy/nbproject/genfiles.properties b/libsrc/jpproxy/nbproject/genfiles.properties
index 9e4b5fd3d..c37be34a0 100644
--- a/libsrc/jpproxy/nbproject/genfiles.properties
+++ b/libsrc/jpproxy/nbproject/genfiles.properties
@@ -4,5 +4,5 @@ nbbuild.xml.stylesheet.CRC32=8064a381@1.74.2.48
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=0a5363c8
-nbproject/build-impl.xml.script.CRC32=13f57099
-nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.74.2.48
+nbproject/build-impl.xml.script.CRC32=6f75ce45
+nbproject/build-impl.xml.stylesheet.CRC32=05530350@1.79.1.48
diff --git a/libsrc/treetable/build.xml b/libsrc/treetable/build.xml
new file mode 100644
index 000000000..8a974bcd8
--- /dev/null
+++ b/libsrc/treetable/build.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+ Builds, tests, and runs the project treetable.
+
+
+
diff --git a/libsrc/treetable/manifest.mf b/libsrc/treetable/manifest.mf
new file mode 100644
index 000000000..328e8e5bc
--- /dev/null
+++ b/libsrc/treetable/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/libsrc/treetable/nbproject/build-impl.xml b/libsrc/treetable/nbproject/build-impl.xml
new file mode 100644
index 000000000..a53c99b03
--- /dev/null
+++ b/libsrc/treetable/nbproject/build-impl.xml
@@ -0,0 +1,1419 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set src.dir
+ Must set test.src.dir
+ Must set build.dir
+ Must set dist.dir
+ Must set build.classes.dir
+ Must set dist.javadoc.dir
+ Must set build.test.classes.dir
+ Must set build.test.results.dir
+ Must set build.classes.excludes
+ Must set dist.jar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No tests executed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set JVM to use for profiling in profiler.info.jvm
+ Must set profiler agent JVM arguments in profiler.info.jvmargs.agent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ To run this application from the command line without Ant, try:
+
+ java -jar "${dist.jar.resolved}"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set debug.class
+
+
+
+
+ Must select one file in the IDE or set debug.class
+
+
+
+
+ Must set fix.includes
+
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set profile.class
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+
+ Must select some files in the IDE or set test.includes
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Some tests failed; see details above.
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set test.includes
+
+
+
+ Some tests failed; see details above.
+
+
+
+ Must select some files in the IDE or set test.class
+ Must select some method in the IDE or set test.method
+
+
+
+ Some tests failed; see details above.
+
+
+
+
+ Must select one file in the IDE or set test.class
+
+
+
+ Must select one file in the IDE or set test.class
+ Must select some method in the IDE or set test.method
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libsrc/treetable/nbproject/genfiles.properties b/libsrc/treetable/nbproject/genfiles.properties
new file mode 100644
index 000000000..d931ac2ee
--- /dev/null
+++ b/libsrc/treetable/nbproject/genfiles.properties
@@ -0,0 +1,8 @@
+build.xml.data.CRC32=3ded4556
+build.xml.script.CRC32=4673fb60
+build.xml.stylesheet.CRC32=8064a381@1.75.2.48
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=3ded4556
+nbproject/build-impl.xml.script.CRC32=646636b1
+nbproject/build-impl.xml.stylesheet.CRC32=05530350@1.79.1.48
diff --git a/libsrc/treetable/nbproject/project.properties b/libsrc/treetable/nbproject/project.properties
new file mode 100644
index 000000000..93930aa33
--- /dev/null
+++ b/libsrc/treetable/nbproject/project.properties
@@ -0,0 +1,73 @@
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.processor.options=
+annotation.processing.processors.list=
+annotation.processing.run.all.processors=true
+annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+ ${run.classpath}
+debug.test.classpath=\
+ ${run.test.classpath}
+# Files in build.classes.dir which should be excluded from distribution jar
+dist.archive.excludes=
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/treetable.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+excludes=
+includes=**
+jar.compress=false
+javac.classpath=
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.processorpath=\
+ ${javac.classpath}
+javac.source=1.8
+javac.target=1.8
+javac.test.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+javac.test.processorpath=\
+ ${javac.test.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+main.class=de.hameister.treetable.TreeTableMain
+manifest.file=manifest.mf
+meta.inf.dir=${src.dir}/META-INF
+mkdist.disabled=false
+platform.active=default_platform
+run.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project.
+# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
+# To set system properties for unit tests define test-sys-prop.name=value:
+run.jvmargs=
+run.test.classpath=\
+ ${javac.test.classpath}:\
+ ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=src
+test.src.dir=test
diff --git a/libsrc/treetable/nbproject/project.xml b/libsrc/treetable/nbproject/project.xml
new file mode 100644
index 000000000..69f12b7e3
--- /dev/null
+++ b/libsrc/treetable/nbproject/project.xml
@@ -0,0 +1,15 @@
+
+
+ org.netbeans.modules.java.j2seproject
+
+
+ treetable
+
+
+
+
+
+
+
+
+
diff --git a/libsrc/treetable/src/de/hameister/treetable/MyAbstractTreeTableModel.java b/libsrc/treetable/src/de/hameister/treetable/MyAbstractTreeTableModel.java
new file mode 100644
index 000000000..ba1c398d1
--- /dev/null
+++ b/libsrc/treetable/src/de/hameister/treetable/MyAbstractTreeTableModel.java
@@ -0,0 +1,91 @@
+package de.hameister.treetable;
+
+import javax.swing.event.EventListenerList;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreePath;
+
+public abstract class MyAbstractTreeTableModel implements MyTreeTableModel {
+
+ protected Object root;
+ protected EventListenerList listenerList = new EventListenerList();
+
+ private static final int CHANGED = 0;
+ private static final int INSERTED = 1;
+ private static final int REMOVED = 2;
+ private static final int STRUCTURE_CHANGED = 3;
+
+ public MyAbstractTreeTableModel(Object root) {
+ this.root = root;
+ }
+
+ public Object getRoot() {
+ return root;
+ }
+
+ public boolean isLeaf(Object node) {
+ return getChildCount(node) == 0;
+ }
+
+ public void valueForPathChanged(TreePath path, Object newValue) {
+ }
+
+ /**
+ * Die Methode wird normalerweise nicht aufgerufen.
+ */
+ public int getIndexOfChild(Object parent, Object child) {
+ return 0;
+ }
+
+ public void addTreeModelListener(TreeModelListener l) {
+ listenerList.add(TreeModelListener.class, l);
+ }
+
+ public void removeTreeModelListener(TreeModelListener l) {
+ listenerList.remove(TreeModelListener.class, l);
+ }
+
+ private void fireTreeNode(int changeType, Object source, Object[] path, int[] childIndices, Object[] children) {
+ Object[] listeners = listenerList.getListenerList();
+ TreeModelEvent e = new TreeModelEvent(source, path, childIndices, children);
+ for (int i = listeners.length - 2; i >= 0; i -= 2) {
+ if (listeners[i] == TreeModelListener.class) {
+
+ switch (changeType) {
+ case CHANGED:
+ ((TreeModelListener) listeners[i + 1]).treeNodesChanged(e);
+ break;
+ case INSERTED:
+ ((TreeModelListener) listeners[i + 1]).treeNodesInserted(e);
+ break;
+ case REMOVED:
+ ((TreeModelListener) listeners[i + 1]).treeNodesRemoved(e);
+ break;
+ case STRUCTURE_CHANGED:
+ ((TreeModelListener) listeners[i + 1]).treeStructureChanged(e);
+ break;
+ default:
+ break;
+ }
+
+ }
+ }
+ }
+
+ protected void fireTreeNodesChanged(Object source, Object[] path, int[] childIndices, Object[] children) {
+ fireTreeNode(CHANGED, source, path, childIndices, children);
+ }
+
+ protected void fireTreeNodesInserted(Object source, Object[] path, int[] childIndices, Object[] children) {
+ fireTreeNode(INSERTED, source, path, childIndices, children);
+ }
+
+ protected void fireTreeNodesRemoved(Object source, Object[] path, int[] childIndices, Object[] children) {
+ fireTreeNode(REMOVED, source, path, childIndices, children);
+ }
+
+ protected void fireTreeStructureChanged(Object source, Object[] path, int[] childIndices, Object[] children) {
+ fireTreeNode(STRUCTURE_CHANGED, source, path, childIndices, children);
+ }
+
+}
diff --git a/libsrc/treetable/src/de/hameister/treetable/MyDataModel.java b/libsrc/treetable/src/de/hameister/treetable/MyDataModel.java
new file mode 100644
index 000000000..49ba6079b
--- /dev/null
+++ b/libsrc/treetable/src/de/hameister/treetable/MyDataModel.java
@@ -0,0 +1,64 @@
+package de.hameister.treetable;
+
+
+
+import java.util.Date;
+
+public class MyDataModel extends MyAbstractTreeTableModel {
+
+ // Spalten Name.
+
+ static protected String[] columnNames = {"Knotentext", "String", "Datum", "Integer"};
+
+ // Spalten Typen.
+ static protected Class>[] columnTypes = {MyTreeTableModel.class, String.class, Date.class, Integer.class};
+
+ public MyDataModel(MyDataNode rootNode) {
+ super(rootNode);
+ root = rootNode;
+ }
+
+ public Object getChild(Object parent, int index) {
+ return ((MyDataNode) parent).getChildren().get(index);
+ }
+
+ public int getChildCount(Object parent) {
+ return ((MyDataNode) parent).getChildren().size();
+ }
+
+ public int getColumnCount() {
+ return columnNames.length;
+ }
+
+ public String getColumnName(int column) {
+ return columnNames[column];
+ }
+
+ public Class> getColumnClass(int column) {
+ return columnTypes[column];
+ }
+
+ public Object getValueAt(Object node, int column) {
+ switch (column) {
+ case 0:
+ return ((MyDataNode) node).getName();
+ case 1:
+ return ((MyDataNode) node).getCapital();
+ case 2:
+ return ((MyDataNode) node).getDeclared();
+ case 3:
+ return ((MyDataNode) node).getArea();
+ default:
+ break;
+ }
+ return null;
+ }
+
+ public boolean isCellEditable(Object node, int column) {
+ return true; // Important to activate TreeExpandListener
+ }
+
+ public void setValueAt(Object aValue, Object node, int column) {
+ }
+
+}
diff --git a/libsrc/treetable/src/de/hameister/treetable/MyDataNode.java b/libsrc/treetable/src/de/hameister/treetable/MyDataNode.java
new file mode 100644
index 000000000..6c6c43ff0
--- /dev/null
+++ b/libsrc/treetable/src/de/hameister/treetable/MyDataNode.java
@@ -0,0 +1,56 @@
+package de.hameister.treetable;
+
+
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+public class MyDataNode {
+
+ private String name;
+ private String capital;
+ private Date declared;
+ private Integer area;
+
+ private List children;
+
+ public MyDataNode(String name, String capital, Date declared, Integer area, List children) {
+ this.name = name;
+ this.capital = capital;
+ this.declared = declared;
+ this.area = area;
+ this.children = children;
+
+ if (this.children == null) {
+ this.children = Collections.emptyList();
+ }
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getCapital() {
+ return capital;
+ }
+
+ public Date getDeclared() {
+ return declared;
+ }
+
+ public Integer getArea() {
+ return area;
+ }
+
+ public List getChildren() {
+ return children;
+ }
+
+ /**
+ * Knotentext vom JTree.
+ */
+ public String toString() {
+ return name;
+ }
+}
diff --git a/libsrc/treetable/src/de/hameister/treetable/MyTreeTable.java b/libsrc/treetable/src/de/hameister/treetable/MyTreeTable.java
new file mode 100644
index 000000000..2da462026
--- /dev/null
+++ b/libsrc/treetable/src/de/hameister/treetable/MyTreeTable.java
@@ -0,0 +1,51 @@
+package de.hameister.treetable;
+
+import java.awt.Dimension;
+
+import javax.swing.JTable;
+import javax.swing.plaf.basic.BasicTableUI;
+
+public class MyTreeTable extends JTable {
+
+ private MyTreeTableCellRenderer tree;
+ private MyTreeTableModel treeTableModel;
+
+ public MyTreeTableCellRenderer getTree() {
+ return tree;
+ }
+
+ public MyTreeTableModel getTreeTableModel() {
+ return treeTableModel;
+ }
+
+ public void setTreeModel(MyTreeTableModel treeTableModel) {
+ // JTree erstellen.
+ this.treeTableModel = treeTableModel;
+ tree = new MyTreeTableCellRenderer(this, treeTableModel);
+
+ // Modell setzen.
+ super.setModel(new MyTreeTableModelAdapter(treeTableModel, tree));
+
+ // Gleichzeitiges Selektieren fuer Tree und Table.
+ MyTreeTableSelectionModel selectionModel = new MyTreeTableSelectionModel();
+ tree.setSelectionModel(selectionModel); //For the tree
+ setSelectionModel(selectionModel.getListSelectionModel()); //For the table
+
+ // Renderer fuer den Tree.
+ setDefaultRenderer(MyTreeTableModel.class, tree);
+ // Editor fuer die TreeTable
+ setDefaultEditor(MyTreeTableModel.class, new MyTreeTableCellEditor(tree, this));
+
+ // Kein Grid anzeigen.
+ setShowGrid(false);
+
+ // Keine Abstaende.
+ setIntercellSpacing(new Dimension(0, 0));
+ }
+
+ public MyTreeTable(MyTreeTableModel treeTableModel) {
+ super();
+ setUI(new BasicTableUI());
+ setTreeModel(treeTableModel);
+ }
+}
diff --git a/libsrc/treetable/src/de/hameister/treetable/MyTreeTableCellEditor.java b/libsrc/treetable/src/de/hameister/treetable/MyTreeTableCellEditor.java
new file mode 100644
index 000000000..859862d89
--- /dev/null
+++ b/libsrc/treetable/src/de/hameister/treetable/MyTreeTableCellEditor.java
@@ -0,0 +1,44 @@
+package de.hameister.treetable;
+
+
+
+import java.awt.Component;
+import java.awt.event.MouseEvent;
+import java.util.EventObject;
+
+import javax.swing.AbstractCellEditor;
+import javax.swing.JTable;
+import javax.swing.JTree;
+import javax.swing.table.TableCellEditor;
+
+public class MyTreeTableCellEditor extends AbstractCellEditor implements TableCellEditor {
+
+ private JTree tree;
+ private JTable table;
+
+ public MyTreeTableCellEditor(JTree tree, JTable table) {
+ this.tree = tree;
+ this.table = table;
+ }
+
+ public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int r, int c) {
+ return tree;
+ }
+
+ public boolean isCellEditable(EventObject e) {
+ if (e instanceof MouseEvent) {
+ int colunm1 = 0;
+ MouseEvent me = (MouseEvent) e;
+ int doubleClick = 2;
+ MouseEvent newME = new MouseEvent(tree, me.getID(), me.getWhen(), me.getModifiers(), me.getX() - table.getCellRect(0, colunm1, true).x, me.getY(), doubleClick, me.isPopupTrigger());
+ tree.dispatchEvent(newME);
+ }
+ return false;
+ }
+
+ @Override
+ public Object getCellEditorValue() {
+ return null;
+ }
+
+}
diff --git a/libsrc/treetable/src/de/hameister/treetable/MyTreeTableCellRenderer.java b/libsrc/treetable/src/de/hameister/treetable/MyTreeTableCellRenderer.java
new file mode 100644
index 000000000..30fb20abe
--- /dev/null
+++ b/libsrc/treetable/src/de/hameister/treetable/MyTreeTableCellRenderer.java
@@ -0,0 +1,75 @@
+package de.hameister.treetable;
+
+import java.awt.Component;
+import java.awt.Graphics;
+
+import javax.swing.JTable;
+import javax.swing.JTree;
+import javax.swing.plaf.basic.BasicTableUI;
+import javax.swing.plaf.basic.BasicTreeUI;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.tree.TreeModel;
+
+public class MyTreeTableCellRenderer extends JTree implements TableCellRenderer {
+
+ /**
+ * Die letzte Zeile, die gerendert wurde.
+ */
+ protected int visibleRow;
+
+ private MyTreeTable treeTable;
+
+ public MyTreeTableCellRenderer(MyTreeTable treeTable, TreeModel model) {
+ super(model);
+ setUI(new BasicTreeUI());
+
+ this.treeTable = treeTable;
+
+ // Setzen der Zeilenhoehe fuer die JTable
+ // Muss explizit aufgerufen werden, weil treeTable noch
+ // null ist, wenn super(model) setRowHeight aufruft!
+ setRowHeight(getRowHeight());
+ }
+
+ /**
+ * Tree und Table muessen die gleiche Hoehe haben.
+ */
+ public void setRowHeight(int rowHeight) {
+ if (rowHeight > 0) {
+ super.setRowHeight(rowHeight);
+ if (treeTable != null && treeTable.getRowHeight() != rowHeight) {
+ treeTable.setRowHeight(getRowHeight());
+ }
+ }
+ }
+
+ /**
+ * Tree muss die gleiche Hoehe haben wie Table.
+ */
+ public void setBounds(int x, int y, int w, int h) {
+ super.setBounds(x, 0, w, treeTable.getHeight());
+ }
+
+ /**
+ * Sorgt fuer die Einrueckung der Ordner.
+ */
+ public void paint(Graphics g) {
+ g.translate(0, -visibleRow * getRowHeight());
+
+ super.paint(g);
+ }
+
+ /**
+ * Liefert den Renderer mit der passenden Hintergrundfarbe zurueck.
+ */
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+ if (isSelected) {
+ setBackground(table.getSelectionBackground());
+ } else {
+ setBackground(table.getBackground());
+ }
+
+ visibleRow = row;
+ return this;
+ }
+}
diff --git a/libsrc/treetable/src/de/hameister/treetable/MyTreeTableModel.java b/libsrc/treetable/src/de/hameister/treetable/MyTreeTableModel.java
new file mode 100644
index 000000000..0d24776bc
--- /dev/null
+++ b/libsrc/treetable/src/de/hameister/treetable/MyTreeTableModel.java
@@ -0,0 +1,58 @@
+package de.hameister.treetable;
+
+
+
+import javax.swing.tree.TreeModel;
+
+public interface MyTreeTableModel extends TreeModel {
+
+ /**
+ * Returns the number of available columns.
+ *
+ * @return Number of Columns
+ */
+ public int getColumnCount();
+
+ /**
+ * Returns the column name.
+ *
+ * @param column Column number
+ * @return Column name
+ */
+ public String getColumnName(int column);
+
+ /**
+ * Returns the type (class) of a column.
+ *
+ * @param column Column number
+ * @return Class
+ */
+ public Class> getColumnClass(int column);
+
+ /**
+ * Returns the value of a node in a column.
+ *
+ * @param node Node
+ * @param column Column number
+ * @return Value of the node in the column
+ */
+ public Object getValueAt(Object node, int column);
+
+ /**
+ * Check if a cell of a node in one column is editable.
+ *
+ * @param node Node
+ * @param column Column number
+ * @return true/false
+ */
+ public boolean isCellEditable(Object node, int column);
+
+ /**
+ * Sets a value for a node in one column.
+ *
+ * @param aValue New value
+ * @param node Node
+ * @param column Column number
+ */
+ public void setValueAt(Object aValue, Object node, int column);
+}
diff --git a/libsrc/treetable/src/de/hameister/treetable/MyTreeTableModelAdapter.java b/libsrc/treetable/src/de/hameister/treetable/MyTreeTableModelAdapter.java
new file mode 100644
index 000000000..90c906aff
--- /dev/null
+++ b/libsrc/treetable/src/de/hameister/treetable/MyTreeTableModelAdapter.java
@@ -0,0 +1,63 @@
+package de.hameister.treetable;
+
+import java.awt.Rectangle;
+
+import javax.swing.JTree;
+import javax.swing.event.TreeExpansionEvent;
+import javax.swing.event.TreeExpansionListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.tree.TreePath;
+
+public class MyTreeTableModelAdapter extends AbstractTableModel {
+
+ JTree tree;
+ MyTreeTableModel treeTableModel;
+
+ public MyTreeTableModelAdapter(MyTreeTableModel treeTableModel, JTree tree) {
+ this.tree = tree;
+ this.treeTableModel = treeTableModel;
+
+ tree.addTreeExpansionListener(new TreeExpansionListener() {
+ public void treeExpanded(TreeExpansionEvent event) {
+ fireTableDataChanged();
+ }
+
+ public void treeCollapsed(TreeExpansionEvent event) {
+ fireTableDataChanged();
+ }
+ });
+ }
+
+ public int getColumnCount() {
+ return treeTableModel.getColumnCount();
+ }
+
+ public String getColumnName(int column) {
+ return treeTableModel.getColumnName(column);
+ }
+
+ public Class> getColumnClass(int column) {
+ return treeTableModel.getColumnClass(column);
+ }
+
+ public int getRowCount() {
+ return tree.getRowCount();
+ }
+
+ protected Object nodeForRow(int row) {
+ TreePath treePath = tree.getPathForRow(row);
+ return treePath.getLastPathComponent();
+ }
+
+ public Object getValueAt(int row, int column) {
+ return treeTableModel.getValueAt(nodeForRow(row), column);
+ }
+
+ public boolean isCellEditable(int row, int column) {
+ return treeTableModel.isCellEditable(nodeForRow(row), column);
+ }
+
+ public void setValueAt(Object value, int row, int column) {
+ treeTableModel.setValueAt(value, nodeForRow(row), column);
+ }
+}
diff --git a/libsrc/treetable/src/de/hameister/treetable/MyTreeTableSelectionModel.java b/libsrc/treetable/src/de/hameister/treetable/MyTreeTableSelectionModel.java
new file mode 100644
index 000000000..c15bbe052
--- /dev/null
+++ b/libsrc/treetable/src/de/hameister/treetable/MyTreeTableSelectionModel.java
@@ -0,0 +1,26 @@
+package de.hameister.treetable;
+
+
+
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.tree.DefaultTreeSelectionModel;
+
+public class MyTreeTableSelectionModel extends DefaultTreeSelectionModel {
+
+ public MyTreeTableSelectionModel() {
+ super();
+
+ getListSelectionModel().addListSelectionListener(new ListSelectionListener() {
+ @Override
+ public void valueChanged(ListSelectionEvent e) {
+
+ }
+ });
+ }
+
+ ListSelectionModel getListSelectionModel() {
+ return listSelectionModel;
+ }
+}
diff --git a/libsrc/treetable/src/de/hameister/treetable/TreeTableMain.java b/libsrc/treetable/src/de/hameister/treetable/TreeTableMain.java
new file mode 100644
index 000000000..fa9947af2
--- /dev/null
+++ b/libsrc/treetable/src/de/hameister/treetable/TreeTableMain.java
@@ -0,0 +1,84 @@
+package de.hameister.treetable;
+
+import java.awt.Container;
+import java.awt.GridLayout;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.swing.JFrame;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+
+public class TreeTableMain extends JFrame {
+
+ public TreeTableMain() {
+ super("Tree Table Demo");
+
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+ setLayout(new GridLayout(0, 1));
+ MyAbstractTreeTableModel treeTableModel = new MyDataModel(createDataStructure());
+
+ MyTreeTable myTreeTable = new MyTreeTable(treeTableModel);
+
+ Container cPane = getContentPane();
+
+ cPane.add(new JScrollPane(myTreeTable));
+
+ setSize(1000, 800);
+ setLocationRelativeTo(null);
+
+ }
+
+ private static MyDataNode createDataStructure() {
+ List children1 = new ArrayList();
+ children1.add(new MyDataNode("N12", "C12", new Date(), Integer.valueOf(50), null));
+ children1.add(new MyDataNode("N13", "C13", new Date(), Integer.valueOf(60), null));
+ children1.add(new MyDataNode("N14", "C14", new Date(), Integer.valueOf(70), null));
+ children1.add(new MyDataNode("N15", "C15", new Date(), Integer.valueOf(80), null));
+
+ List children2 = new ArrayList();
+ children2.add(new MyDataNode("N12", "C12", new Date(), Integer.valueOf(10), null));
+ children2.add(new MyDataNode("N13", "C13", new Date(), Integer.valueOf(20), children1));
+ children2.add(new MyDataNode("N14", "C14", new Date(), Integer.valueOf(30), null));
+ children2.add(new MyDataNode("N15", "C15", new Date(), Integer.valueOf(40), null));
+
+ List rootNodes = new ArrayList();
+ rootNodes.add(new MyDataNode("N1", "C1", new Date(), Integer.valueOf(10), children2));
+ rootNodes.add(new MyDataNode("N2", "C2", new Date(), Integer.valueOf(10), children1));
+ rootNodes.add(new MyDataNode("N3", "C3", new Date(), Integer.valueOf(10), children2));
+ rootNodes.add(new MyDataNode("N4", "C4", new Date(), Integer.valueOf(10), children1));
+ rootNodes.add(new MyDataNode("N5", "C5", new Date(), Integer.valueOf(10), children1));
+ rootNodes.add(new MyDataNode("N6", "C6", new Date(), Integer.valueOf(10), children1));
+ rootNodes.add(new MyDataNode("N7", "C7", new Date(), Integer.valueOf(10), children1));
+ rootNodes.add(new MyDataNode("N8", "C8", new Date(), Integer.valueOf(10), children1));
+ rootNodes.add(new MyDataNode("N9", "C9", new Date(), Integer.valueOf(10), children1));
+ rootNodes.add(new MyDataNode("N10", "C10", new Date(), Integer.valueOf(10), children1));
+ rootNodes.add(new MyDataNode("N11", "C11", new Date(), Integer.valueOf(10), children1));
+ rootNodes.add(new MyDataNode("N12", "C7", new Date(), Integer.valueOf(10), children1));
+ rootNodes.add(new MyDataNode("N13", "C8", new Date(), Integer.valueOf(10), children1));
+ rootNodes.add(new MyDataNode("N14", "C9", new Date(), Integer.valueOf(10), children1));
+ rootNodes.add(new MyDataNode("N15", "C10", new Date(), Integer.valueOf(10), children1));
+ rootNodes.add(new MyDataNode("N16", "C11", new Date(), Integer.valueOf(10), children1));
+ MyDataNode root = new MyDataNode("R1", "R1", new Date(), Integer.valueOf(10), rootNodes);
+
+ return root;
+ }
+
+ public static void main(final String[] args) {
+ Runnable gui = new Runnable() {
+
+ public void run() {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ new TreeTableMain().setVisible(true);
+ }
+ };
+ SwingUtilities.invokeLater(gui);
+ }
+}
diff --git a/nbproject/project.xml b/nbproject/project.xml
index 286b09cc5..cfa9340f0 100644
--- a/nbproject/project.xml
+++ b/nbproject/project.xml
@@ -308,7 +308,7 @@
src
- lib/LZMA.jar;lib/jna-3.5.1.jar;lib/jpproxy.jar;lib/trident-6.2.jar;lib/substance-flamingo-6.2.jar;lib/flamingo-6.2.jar;lib/substance-6.2.jar;lib/jl1.0.1.jar;lib/nellymoser.jar;lib/gif.jar;lib/avi.jar;lib/ttf.jar;lib/jpacker.jar;lib/sfntly.jar;lib/gnujpdf.jar;libsrc/ffdec_lib/src;lib/tablelayout.jar;lib/jsyntaxpane-0.9.5.jar;lib/JavactiveX.jar;lib/flashdebugger.jar
+ lib/LZMA.jar;lib/jna-3.5.1.jar;lib/jpproxy.jar;lib/trident-6.2.jar;lib/substance-flamingo-6.2.jar;lib/flamingo-6.2.jar;lib/substance-6.2.jar;lib/jl1.0.1.jar;lib/nellymoser.jar;lib/gif.jar;lib/avi.jar;lib/ttf.jar;lib/jpacker.jar;lib/sfntly.jar;lib/gnujpdf.jar;libsrc/ffdec_lib/src;lib/tablelayout.jar;lib/jsyntaxpane-0.9.5.jar;lib/JavactiveX.jar;lib/flashdebugger.jar;lib/treetable.jar
build
javadoc
reports
diff --git a/src/com/jpexs/decompiler/flash/gui/DebugPanel.java b/src/com/jpexs/decompiler/flash/gui/DebugPanel.java
index 5df50caed..f90e6cd2f 100644
--- a/src/com/jpexs/decompiler/flash/gui/DebugPanel.java
+++ b/src/com/jpexs/decompiler/flash/gui/DebugPanel.java
@@ -21,6 +21,11 @@ import com.jpexs.debugger.flash.messages.in.InBreakAtExt;
import com.jpexs.debugger.flash.messages.in.InFrame;
import com.jpexs.decompiler.flash.gui.DebuggerHandler.BreakListener;
import com.jpexs.decompiler.flash.gui.abc.ABCPanel;
+import de.hameister.treetable.MyAbstractTreeTableModel;
+import de.hameister.treetable.MyTreeTable;
+import de.hameister.treetable.MyTreeTableModel;
+import de.hameister.treetable.MyTreeTableModelAdapter;
+import de.hameister.treetable.MyTreeTableSelectionModel;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
@@ -43,7 +48,15 @@ import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.plaf.basic.BasicTableUI;
+import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.table.DefaultTableModel;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
/**
*
@@ -51,11 +64,11 @@ import javax.swing.table.DefaultTableModel;
*/
public class DebugPanel extends JPanel {
- private JTable debugRegistersTable;
+ private MyTreeTable debugRegistersTable;
- private JTable debugLocalsTable;
+ private MyTreeTable debugLocalsTable; //JTable debugLocalsTable;
- private JTable debugScopeTable;
+ private MyTreeTable debugScopeTable;
private JTable callStackTable;
@@ -88,10 +101,34 @@ public class DebugPanel extends JPanel {
private SelectedTab selectedTab = null;
+ private void safeSetTreeModel(MyTreeTable tt, MyTreeTableModel tmodel) {
+ List> expanded = View.getExpandedNodes(tt.getTree());
+
+ int selRows[] = tt.getSelectedRows();
+
+ TreePath selPaths[] = new TreePath[selRows.length];
+ for (int i = 0; i < selRows.length; i++) {
+ selPaths[i] = tt.getTree().getPathForRow(selRows[i]);
+ }
+ tt.setTreeModel(tmodel);
+ //tt.getTree().setRootVisible(false);
+
+ View.expandTreeNodes(tt.getTree(), expanded);
+ for (int i = 0; i < selRows.length; i++) {
+ selRows[i] = tt.getTree().getRowForPath(selPaths[i]);
+ if (i == 0) {
+ tt.setRowSelectionInterval(selRows[i], selRows[i]);
+ } else {
+ tt.addRowSelectionInterval(selRows[i], selRows[i]);
+ }
+ }
+
+ }
+
public DebugPanel() {
super(new BorderLayout());
- debugRegistersTable = new JTable(new ABCPanel.VariablesTableModel(new ArrayList<>(), new ArrayList<>()));
- debugLocalsTable = new JTable(new ABCPanel.VariablesTableModel(new ArrayList<>(), new ArrayList<>()));
+ debugRegistersTable = new MyTreeTable(new ABCPanel.VariablesTableModel(debugRegistersTable, new ArrayList<>(), new ArrayList<>()));
+ debugLocalsTable = new MyTreeTable(new ABCPanel.VariablesTableModel(debugLocalsTable, new ArrayList<>(), new ArrayList<>()));
//Add watch feature, commented out. I tried it, but without success. I can't add watch in Flash Pro or FDB either. :-(
/*
@@ -161,7 +198,7 @@ public class DebugPanel extends JPanel {
debugScopeTable.addMouseListener(watchHandler);
*/
- debugScopeTable = new JTable(new ABCPanel.VariablesTableModel(new ArrayList<>(), new ArrayList<>()));
+ debugScopeTable = new MyTreeTable(new ABCPanel.VariablesTableModel(debugScopeTable, new ArrayList<>(), new ArrayList<>()));
callStackTable = new JTable();
stackTable = new JTable();
@@ -271,21 +308,56 @@ public class DebugPanel extends JPanel {
for (int i = 0; i < f.registers.size(); i++) {
regVarIds.add(0L);
}
- debugRegistersTable.setModel(new ABCPanel.VariablesTableModel(f.registers, regVarIds));
+ safeSetTreeModel(debugRegistersTable, new ABCPanel.VariablesTableModel(debugRegistersTable, f.registers, regVarIds));
List locals = new ArrayList<>();
locals.addAll(f.arguments);
locals.addAll(f.variables);
List localIds = new ArrayList<>();
- localIds.addAll(f.argumentIds);
- localIds.addAll(f.variableIds);
+ localIds.addAll(f.argumentFrameIds);
+ localIds.addAll(f.frameIds);
- debugLocalsTable.setModel(new ABCPanel.VariablesTableModel(locals, localIds));
- debugScopeTable.setModel(new ABCPanel.VariablesTableModel(f.scopeChain, f.scopeChainIds));
+ safeSetTreeModel(debugLocalsTable, new ABCPanel.VariablesTableModel(debugLocalsTable, locals, localIds));
+ safeSetTreeModel(debugScopeTable, new ABCPanel.VariablesTableModel(debugScopeTable, f.scopeChain, f.scopeChainFrameIds));
+
+ /*TableModelListener refreshListener = new TableModelListener() {
+ @Override
+ public void tableChanged(TableModelEvent e) {
+ Main.getDebugHandler().refreshFrame();
+ refresh();
+ }
+ };*/
+ TreeModelListener refreshListener = new TreeModelListener() {
+ @Override
+ public void treeNodesChanged(TreeModelEvent e) {
+ Main.getDebugHandler().refreshFrame();
+ refresh();
+ }
+
+ @Override
+ public void treeNodesInserted(TreeModelEvent e) {
+ Main.getDebugHandler().refreshFrame();
+ refresh();
+ }
+
+ @Override
+ public void treeNodesRemoved(TreeModelEvent e) {
+ Main.getDebugHandler().refreshFrame();
+ refresh();
+ }
+
+ @Override
+ public void treeStructureChanged(TreeModelEvent e) {
+ Main.getDebugHandler().refreshFrame();
+ refresh();
+ }
+ };
+ debugLocalsTable.getTreeTableModel().addTreeModelListener(refreshListener);
+ debugScopeTable.getTreeTableModel().addTreeModelListener(refreshListener);
} else {
- debugRegistersTable.setModel(new DefaultTableModel());
- debugLocalsTable.setModel(new DefaultTableModel());
- debugScopeTable.setModel(new DefaultTableModel());
+ debugRegistersTable.setTreeModel(new ABCPanel.VariablesTableModel(debugRegistersTable, new ArrayList<>(), new ArrayList<>()));
+ debugLocalsTable.setTreeModel(new ABCPanel.VariablesTableModel(debugLocalsTable, new ArrayList<>(), new ArrayList<>()));
+ debugScopeTable.setTreeModel(new ABCPanel.VariablesTableModel(debugScopeTable, new ArrayList<>(), new ArrayList<>()));
}
InBreakAtExt info = Main.getDebugHandler().getBreakInfo();
if (info != null) {
@@ -325,13 +397,13 @@ public class DebugPanel extends JPanel {
varTabs.removeAll();
tabTypes.clear();
JPanel pa;
- if (debugRegistersTable.getRowCount() > 0) {
+ if (debugRegistersTable.getRowCount() > 1 /*root*/) {
tabTypes.add(SelectedTab.REGISTERS);
pa = new JPanel(new BorderLayout());
pa.add(new JScrollPane(debugRegistersTable), BorderLayout.CENTER);
varTabs.addTab(AppStrings.translate("variables.header.registers"), pa);
}
- if (debugLocalsTable.getRowCount() > 0) {
+ if (debugLocalsTable.getRowCount() > 1 /*root*/) {
tabTypes.add(SelectedTab.LOCALS);
pa = new JPanel(new BorderLayout());
@@ -339,7 +411,7 @@ public class DebugPanel extends JPanel {
varTabs.addTab(AppStrings.translate("variables.header.locals"), pa);
}
- if (debugScopeTable.getRowCount() > 0) {
+ if (debugScopeTable.getRowCount() > 1 /*root*/) {
tabTypes.add(SelectedTab.SCOPECHAIN);
pa = new JPanel(new BorderLayout());
diff --git a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java
index c951dd3ce..5869e2ecb 100644
--- a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java
+++ b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java
@@ -22,6 +22,7 @@ import com.jpexs.debugger.flash.Debugger;
import com.jpexs.debugger.flash.DebuggerCommands;
import com.jpexs.debugger.flash.DebuggerConnection;
import com.jpexs.debugger.flash.Variable;
+import com.jpexs.debugger.flash.VariableType;
import com.jpexs.debugger.flash.messages.in.InAskBreakpoints;
import com.jpexs.debugger.flash.messages.in.InBreakAt;
import com.jpexs.debugger.flash.messages.in.InBreakAtExt;
@@ -108,6 +109,40 @@ public class DebuggerHandler implements DebugConnectionListener {
return breakScriptName;
}
+ public InGetVariable getVariable(long parentId, String varName, boolean children) {
+ try {
+ return commands.getVariable(parentId, varName, true, children);
+ } catch (IOException ex) {
+ return null;
+ }
+ }
+
+ public void setVariable(long parentId, String varName, int valueType, Object value) {
+ try {
+ String svalue = "";
+ switch (valueType) {
+ case VariableType.STRING:
+ svalue = "" + value;
+ break;
+ case VariableType.NUMBER:
+ svalue = "" + value;
+ break;
+ case VariableType.BOOLEAN:
+ svalue = ((Boolean) value) ? "true" : "false";
+ break;
+ case VariableType.UNDEFINED:
+ svalue = "undefined";
+ break;
+ case VariableType.NULL:
+ svalue = "undefined";
+ break;
+ }
+ commands.setVariable(parentId, varName, valueType, svalue);
+ } catch (IOException ex) {
+ //ignore
+ }
+ }
+
public synchronized void removeBreakPoint(String scriptName, int line) {
if (isBreakpointInvalid(scriptName, line)) {
invalidBreakPointMap.get(scriptName).remove(line);
@@ -332,6 +367,17 @@ public class DebuggerHandler implements DebugConnectionListener {
clisteners.remove(l);
}
+ public synchronized void refreshFrame() {
+ if (!paused) {
+ return;
+ }
+ try {
+ frame = commands.getFrame(0);
+ } catch (IOException ex) {
+ //ignore
+ }
+ }
+
public synchronized InFrame getFrame() {
if (!paused) {
return null;
diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java
index 3809ce7ee..fcd4818fc 100644
--- a/src/com/jpexs/decompiler/flash/gui/Main.java
+++ b/src/com/jpexs/decompiler/flash/gui/Main.java
@@ -519,6 +519,10 @@ public class Main {
loadFromMemoryFrame.setVisible(true);
}
+ public static void setVariable(long parentId, String varName, int valueType, Object value) {
+ getDebugHandler().setVariable(parentId, varName, valueType, value);
+ }
+
public static void setSubLimiter(boolean value) {
if (value) {
AVM2Code.toSourceLimit = Configuration.sublimiter.get();
@@ -1394,7 +1398,9 @@ public class Main {
@Override
public void disconnected() {
- Main.mainFrame.getPanel().refreshBreakPoints();
+ if (Main.mainFrame != null && Main.mainFrame.getPanel() != null) {
+ Main.mainFrame.getPanel().refreshBreakPoints();
+ }
}
});
flashDebugger.addConnectionListener(debugHandler);
diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java
index 4433e28d7..57f6c2a79 100644
--- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java
+++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java
@@ -17,6 +17,9 @@
package com.jpexs.decompiler.flash.gui.abc;
import com.jpexs.debugger.flash.Variable;
+import com.jpexs.debugger.flash.VariableType;
+import com.jpexs.debugger.flash.messages.in.InFrame;
+import com.jpexs.debugger.flash.messages.in.InGetVariable;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.ClassPath;
@@ -38,6 +41,13 @@ import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
import com.jpexs.decompiler.flash.abc.usages.MultinameUsage;
import com.jpexs.decompiler.flash.abc.usages.TraitMultinameUsage;
+import com.jpexs.decompiler.flash.action.parser.ActionParseException;
+import com.jpexs.decompiler.flash.action.parser.pcode.ASMParsedSymbol;
+import com.jpexs.decompiler.flash.action.parser.pcode.ASMParser;
+import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer;
+import com.jpexs.decompiler.flash.action.parser.script.ActionScriptLexer;
+import com.jpexs.decompiler.flash.action.parser.script.ParsedSymbol;
+import com.jpexs.decompiler.flash.action.parser.script.SymbolType;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.gui.AppDialog;
import com.jpexs.decompiler.flash.gui.AppStrings;
@@ -66,6 +76,9 @@ import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.helpers.CancellableWorker;
+import com.jpexs.helpers.Helper;
+import de.hameister.treetable.MyTreeTable;
+import de.hameister.treetable.MyTreeTableModel;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.FlowLayout;
@@ -82,8 +95,13 @@ import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
@@ -101,7 +119,11 @@ import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;
+import javax.swing.event.EventListenerList;
+import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.text.Highlighter;
@@ -263,30 +285,167 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener tableListeners = new ArrayList<>();
+ public List path = new ArrayList<>();
- private List vars;
- private List varIds;
+ public Long parentId;
+ public int level;
- public List getVarIds() {
- return varIds;
- }
+ public Variable thisVar;
+ public Variable thisTrait;
+ public long thisTraitId;
- public List getVars() {
- return new ArrayList<>(vars);
- }
+ private List childs;
+ private List childTraits;
- public VariablesTableModel(List vars, List varIds) {
- this.vars = vars;
- this.varIds = varIds;
+ @Override
+ public int hashCode() {
+ int hash = 3;
+ hash = 53 * hash + Objects.hashCode(this.parentId);
+ hash = 53 * hash + (this.thisVar == null ? 0 : Objects.hashCode(this.thisVar.name));
+ return hash;
}
@Override
- public int getRowCount() {
- return vars.size();
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final VariableNode other = (VariableNode) obj;
+ if (!Objects.equals(this.parentId, other.parentId)) {
+ return false;
+ }
+ if (this.thisVar == null && other.thisVar == null) {
+ return true;
+ }
+ if (this.thisVar == null) {
+ return false;
+ }
+ if (other.thisVar == null) {
+ return false;
+ }
+ return Objects.equals(this.thisVar.name, other.thisVar.name);
+ }
+
+ public boolean loaded = false;
+
+ private static boolean isTraits(Variable v) {
+ return (v.vType == VariableType.UNKNOWN && "traits".equals(v.typeName));
+ }
+
+ @Override
+ public String toString() {
+ if (level == 0) {
+ return "root"; //TODO: localize?
+ }
+ return thisVar.name;
+ }
+
+ private void refresh() {
+ if (path.size() > 1) {
+ path.get(path.size() - 2).reloadChildren();
+ } else {
+ //Main.getDebugHandler().refreshFrame();
+ //InFrame fr = Main.getDebugHandler().getFrame();
+ }
+ }
+
+ private void reloadChildren() {
+ InGetVariable igv = Main.getDebugHandler().getVariable(parentId, thisVar.name, true);
+ childs = new ArrayList<>();
+ childTraits = new ArrayList<>();
+
+ Variable curTrait = null;
+
+ for (int i = 0; i < igv.childs.size(); i++) {
+ if (!isTraits(igv.childs.get(i))) {
+ childs.add(igv.childs.get(i));
+ childTraits.add(curTrait);
+ } else {
+ curTrait = igv.childs.get(i);
+ }
+ }
+ }
+
+ private void ensureLoaded() {
+ if (!loaded) {
+ reloadChildren();
+ loaded = true;
+ }
+ }
+
+ public VariableNode getChildAt(int index) {
+ ensureLoaded();
+ Long parId = 0L;
+ if (thisVar != null && thisVar.vType == VariableType.OBJECT) {
+ parId = (Long) thisVar.value;
+ }
+ VariableNode vn = new VariableNode(level + 1, childs.get(index), parId, childTraits.get(index));
+ vn.path.addAll(path);
+ vn.path.add(vn);
+ return vn;
+ }
+
+ public int getChildCount() {
+ ensureLoaded();
+ return childs.size();
+ }
+
+ public VariableNode(int level, Variable thisVar, Long parentId, Variable thisTrait) {
+ this.parentId = parentId;
+ this.thisVar = thisVar;
+ this.level = level;
+ this.thisTrait = thisTrait;
+ }
+
+ public VariableNode(int level, Variable thisVar, Long parentId, Variable thisTrait, Long thisTraitId, List vars, List varTraits) {
+ this.parentId = parentId;
+
+ this.thisVar = thisVar;
+
+ this.level = level;
+ this.childs = vars;
+
+ this.thisTrait = thisTrait;
+
+ this.childTraits = varTraits;
+ this.path.add(this);
+
+ loaded = true;
+ }
+
+ }
+
+ public static class VariablesTableModel implements MyTreeTableModel {
+
+ List tableListeners = new ArrayList<>();
+
+ VariableNode root;
+ private Map> nodeCache = new HashMap<>();
+
+ protected EventListenerList listenerList = new EventListenerList();
+
+ private static final int CHANGED = 0;
+ private static final int INSERTED = 1;
+ private static final int REMOVED = 2;
+ private static final int STRUCTURE_CHANGED = 3;
+
+ private MyTreeTable ttable;
+
+ public VariablesTableModel(MyTreeTable ttable, List vars, List parentIds) {
+ this.ttable = ttable;
+ List varTraits = new ArrayList<>();
+ for (int i = 0; i < vars.size(); i++) {
+ varTraits.add(null);
+ }
+ root = new VariableNode(0, null, 0L, null, 0L, vars, varTraits);
}
@Override
@@ -310,17 +469,21 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener getColumnClass(int columnIndex) {
+ if (columnIndex == 0) {
+ return MyTreeTableModel.class;
+ }
return String.class;
}
@Override
- public boolean isCellEditable(int rowIndex, int columnIndex) {
- return false; //columnIndex == 2; //TODO: edit variables
- }
-
- @Override
- public Object getValueAt(int rowIndex, int columnIndex) {
- Variable v = vars.get(rowIndex);
+ public Object getValueAt(Object node, int columnIndex) {
+ if (node == root) {
+ if (columnIndex == 0) {
+ return "root";
+ }
+ return "";
+ }
+ Variable v = ((VariableNode) node).thisVar;
switch (columnIndex) {
case 0:
@@ -335,24 +498,157 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener= 0; i -= 2) {
+ if (listeners[i] == TreeModelListener.class) {
+
+ switch (changeType) {
+ case CHANGED:
+ ((TreeModelListener) listeners[i + 1]).treeNodesChanged(e);
+ break;
+ case INSERTED:
+ ((TreeModelListener) listeners[i + 1]).treeNodesInserted(e);
+ break;
+ case REMOVED:
+ ((TreeModelListener) listeners[i + 1]).treeNodesRemoved(e);
+ break;
+ case STRUCTURE_CHANGED:
+ ((TreeModelListener) listeners[i + 1]).treeStructureChanged(e);
+ break;
+ default:
+ break;
+ }
+
+ }
+ }
}
}
@@ -650,6 +946,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener(null));
if (dpos > -1) {
decompiledTextArea.setCaretPosition(dpos);
+
}
}
@@ -872,8 +1169,10 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener