Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added inspection to debug net state #94

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion src/main/java/dk/aau/cs/model/CPN/ColorType.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class ColorType implements Iterable<Color> {
public static final ColorType COLORTYPE_DOT = new ColorType("dot") {{addColor("dot");}};
private final Vector<Color> colors = new Vector<>();
private final String id;
private final String name;
private String name;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undo this change


public ColorType(String name) { this(name, name); } //id is unused. Solution for now.

Expand Down
8 changes: 4 additions & 4 deletions src/main/java/net/tapaal/gui/debug/Debug.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import javax.swing.KeyStroke

fun noOp() {}
object DEBUG {

@JvmStatic fun buildMenuDEBUG(): JMenu {

val debugMenu = JMenu("DEBUG")
Expand All @@ -28,6 +27,10 @@ object DEBUG {
override fun actionPerformed(e: ActionEvent) = throw RuntimeException("Casted Exception from DEBUG")
})

add(object : GuiAction("Inspect net", "Inspect net", KeyStroke.getKeyStroke('I'.code, Toolkit.getDefaultToolkit().menuShortcutKeyMask + InputEvent.SHIFT_MASK)) {
override fun actionPerformed(e: ActionEvent) = InspectSpy().show()
})

add(object : AbstractAction("Show undo/redo stack") {
override fun actionPerformed(e: ActionEvent) = UndoRedoSpy().show()
})
Expand All @@ -48,13 +51,10 @@ object DEBUG {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Debug: Save/Load Error","Failure to save/load, please check stack-trace on console.", JOptionPane.ERROR_MESSAGE)
}


}
})
}

return debugMenu
}

}
226 changes: 226 additions & 0 deletions src/main/java/net/tapaal/gui/debug/InspectSpy.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
package net.tapaal.gui.debug

import dk.aau.cs.model.CPN.ProductType
import net.tapaal.gui.petrinet.TAPNLens
import pipe.gui.TAPAALGUI
import java.awt.event.ActionEvent
import java.lang.reflect.Field
import java.util.*
import javax.swing.*
import javax.swing.JTree.DynamicUtilTreeNode
import javax.swing.tree.DefaultMutableTreeNode
import javax.swing.tree.DefaultTreeModel
import kotlin.reflect.KClass


/*
Usage:
// fun t(): Iterable<DefaultMutableTreeNode> =
// listOf(
// LazyDefaultMutableTreeNode('a'),
// LazyDefaultMutableTreeNode("t", ::t)
// )
// val lazy = LazyDefaultMutableTreeNode("test", ::t)
// treeRoot.add(lazy)
*/
class LazyDefaultMutableTreeNode(value: Any?, val genFun: (() -> Iterable<DefaultMutableTreeNode>)? = null) :
DynamicUtilTreeNode(value, null) {
private var constructed = false; // Delay running loadChildren until fully constructed

init {
if (genFun != null) {
allowsChildren = true;
}
constructed = true;
}

override fun loadChildren() {
if (constructed) {
loadedChildren = true
genFun?.invoke()?.forEach { this.add(it) }
println("generated")
}

}
}

class InspectSpy : JFrame() {

private val reloadBtn = JButton(object : AbstractAction("Reload") {
override fun actionPerformed(e: ActionEvent?) {
reload()
}
})

private val treeRoot = DefaultMutableTreeNode("root")
private val tree = JTree(treeRoot)

private fun reload() {
val m = tree.model as DefaultTreeModel
treeRoot.removeAllChildren()

generateGlobal()

m.reload()
tree.expandRow(1)
}

private fun <T : Any> T.getPrivateField(
field: String,
): Any? {
var ref: Field? = null;

var clz: Class<*>? = this.javaClass
while (clz != null || clz != Any::class.java) {
try {
ref = clz?.getDeclaredField(field)
break
} catch (e: NoSuchFieldException) {
clz = clz?.superclass
}
}
if (ref == null) throw Exception("Field not found " + field)

ref.isAccessible = true
return ref.get(this)
}

private fun handleFieldWithRender(render: Render, obj: Any?, node: DefaultMutableTreeNode) {
when (render) {
is ToStringRender -> {
val str = if (render.field != null) {
"${render.displayName}: ${render.render(obj?.getPrivateField(render.field))}"
} else {
render.render(obj)
}
node.add(DefaultMutableTreeNode(str))
}

is ListModelRender -> {
val top = DefaultMutableTreeNode(render.displayName)
val lm = (obj!!.getPrivateField(render.field)) as AbstractListModel<*>
lm.forEach { lm ->
render.render.forEach {
handleFieldWithRender(it, lm, top)
}

}
node.add(top)
}

is VectorRender -> {
val top = DefaultMutableTreeNode(render.displayName)
val lm = (obj!!.getPrivateField(render.field)) as Vector<*>
lm.forEach {
handleFieldWithRender(render.render, it, top)
}
node.add(top)
}

is RenderField -> {
val o = if (render.field != null) {
obj?.getPrivateField(render.field)
} else {
obj
}
if (render.typeFilter.isInstance(obj)) {
render.fields.forEach {
handleFieldWithRender(it, o, node)
}
}
}

is ObjectRender -> {
if (render.typeFilter.isInstance(obj)) {
val top = DefaultMutableTreeNode(render.displayName ?: obj)
render.fields.forEach {
handleFieldWithRender(it, obj, top)
}
node.add(top)
}
}

is HashMapRender -> {
val top = DefaultMutableTreeNode(render.displayName)
val o = if (render.field != null) {
obj?.getPrivateField(render.field)
} else {
obj
}
val map = o as HashMap<*, *>
map.forEach { e ->
handleFieldWithRender(render.render, e, top)
}
node.add(top)
}
}
}

private fun generateGlobal() {
val render =
ObjectRender(
ToStringRender("lens", render = {
it as TAPNLens;
"Timed: ${it.isTimed}, Game: ${it.isGame}, Color: ${it.isColored}"
}, displayName = "Lense"),
RenderField(
field = "constantsPanel",
fields = arrayOf(
ListModelRender("variablesListModel", ToStringRender(), displayName = "Variables"),
ListModelRender("constantsListModel", ToStringRender(), displayName = "Constants"),
ListModelRender(
"colorTypesListModel",
ObjectRender(
ToStringRender("id"),
ToStringRender("name"),
VectorRender("colors"),
RenderField(
ToStringRender("name"),
VectorRender("constituents"),
HashMapRender("colorCache"),
typeFilter = ProductType::class,
),
),
displayName = "Color Types"
),
)
),
RenderField(
field = "queries",
fields = arrayOf(ListModelRender("listModel", ToStringRender(), displayName = "Queries"))
),
displayName = "Global"
)

handleFieldWithRender(render, TAPAALGUI.getCurrentTab(), treeRoot)
}

init {
contentPane.layout = BoxLayout(contentPane, BoxLayout.Y_AXIS)
setSize(600, 900)
contentPane.add(reloadBtn)

contentPane.add(JScrollPane(tree))

reload()
}
}

private fun <E> AbstractListModel<E>.forEach(function: (e: E) -> Unit) {
for (i in 0 until this.size) {
function(this.getElementAt(i))
}
}

sealed class Render()
class ToStringRender(
val field: String? = null,
val displayName: String? = field,
val render: ((Any?) -> String) = { a: Any? -> a?.toString() ?: "null" }
) : Render()

class RenderField(vararg val fields: Render, val field: String? = null, val typeFilter: KClass<*> = Any::class) : Render()
class ObjectRender(vararg val fields: Render, val displayName: String? = null, val typeFilter: KClass<*> = Any::class) : Render()
class VectorRender(val field: String, val render: Render = ToStringRender(), val displayName: String? = field) : Render()
class ListModelRender(val field: String, vararg val render: Render, val displayName: String? = field) : Render()
class HashMapRender(val field: String? = null, val render: Render = ToStringRender(), val displayName: String? = field) : Render()