package es.usj.svit.simuhaff.approach.simulation import java.awt.* import java.io.File import java.util.* import javax.swing.* import javax.swing.border.EmptyBorder import javax.swing.border.LineBorder import javax.swing.event.MenuEvent import javax.swing.event.MenuListener import javax.imageio.ImageIO import kotlin.math.roundToInt import es.usj.svit.util.IO import es.usj.svit.graphics.HullComponent class UI(private val content: MutableList, private val props: Map) : JFrame() { lateinit var body: Container val btnSubmit by lazy { JButton("Submit") } init { title = "SimuHaFF" setSize(1200, 700) setLocationRelativeTo(null) createLayout() //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()) isResizable = true isVisible = true defaultCloseOperation = EXIT_ON_CLOSE } fun collectScores(): List { val humanScores = mutableListOf() val divs: List = body.components.filterIsInstance().takeIf { it.size == body.components.size } ?: return listOf() for (div in divs) { val slider: JSlider = div.components.last() as JSlider humanScores.add(slider.value) } return humanScores } private fun createLayout() { createHeader() createBody() createFooter() createLegend() } private fun createHeader() { val modelSimulation = props["modelName"].toString() val head = JPanel() head.layout = BorderLayout() val modelButton = JButton("Open model") modelButton.addActionListener { if (!Desktop.isDesktopSupported()) { println("Desktop is not supported") return@addActionListener } val desktop = Desktop.getDesktop() val modelFile = File(IO.getResourcePath(modelSimulation)) if (modelFile.exists()) desktop.open(modelFile) } head.add(modelButton, BorderLayout.LINE_START) val modelLabel = JLabel( "Model simulation: ${modelSimulation.substring(0, modelSimulation.length - 4)}", SwingConstants.CENTER ) modelLabel.border = EmptyBorder(8, 0, 8, 0) head.add(modelLabel, BorderLayout.CENTER) val hintLabel = JLabel("(7 = MAX bug candidate score)", SwingConstants.CENTER) hintLabel.border = EmptyBorder(8, 0, 8, 32) head.add(hintLabel, BorderLayout.LINE_END) contentPane.add(head, BorderLayout.PAGE_START) } private fun createBody() { body = Container() body.layout = BoxLayout(body, BoxLayout.Y_AXIS) for ((index, modelFragment) in obtainModelFragments().withIndex()) { val div = JPanel() div.border = LineBorder(Color.BLACK, 1) div.layout = GridBagLayout() val constraints = GridBagConstraints() constraints.fill = GridBagConstraints.BOTH constraints.gridy = 0 constraints.weighty = 1.0 val individualLabel = JLabel("Candidate
Solution ${index + 1}", JLabel.CENTER) individualLabel.border = EmptyBorder(0, 0, 0, 8) constraints.gridx = 0 constraints.weightx = 1.0 div.add(individualLabel, constraints) val traceArea = HullComponent() for (mf in modelFragment) { traceArea.add(position = mf.first, steps = mf.second) } constraints.gridx = 1 constraints.weightx = 6.0 div.add(traceArea, constraints) val scoreLabel = JLabel("4", JLabel.CENTER) scoreLabel.border = EmptyBorder(0, 0, 0, 8) constraints.gridx = 3 constraints.weightx = 1.0 div.add(scoreLabel, constraints) val scoreSlider = JSlider(1, 7, 4) scoreSlider.addChangeListener { scoreLabel.text = scoreSlider.value.toString() } constraints.gridx = 2 constraints.weightx = 2.0 div.add(scoreSlider, constraints) body.add(div) } if (body.components.isEmpty()) { body.add( JLabel( "No candidate model fragments have been found as a likely bug source. " + "Please continue running simulations." ) ) } contentPane.add(JScrollPane(body), BorderLayout.CENTER) } private fun createFooter() { val footer = JPanel() val userIteration = JLabel("${props["userIteration"]}") footer.add(userIteration) val progressBar = JProgressBar(0, 100) progressBar.preferredSize = Dimension(700, 20) progressBar.value = props["progress"] as Int progressBar.isStringPainted = true footer.add(progressBar) val userIterations = JLabel("${props["userIterations"]}") footer.add(userIterations) footer.add(btnSubmit) contentPane.add(footer, BorderLayout.PAGE_END) } private fun createLegend() { val menuBar = JMenuBar() jMenuBar = menuBar val menu = JMenu("Legend") menu.addMenuListener(object : MenuListener { override fun menuSelected(e: MenuEvent?) { val modal = JDialog() modal.setLocation( this@UI.location.x + this@UI.size.width / 4, this@UI.location.y + this@UI.size.height / 4 ) val legend = JPanel() legend.layout = BoxLayout(legend, BoxLayout.Y_AXIS) val image = JLabel() val icon = ImageIcon( ImageIO.read(File(IO.getResourcePath("legend.png"))).getScaledInstance(787, 487, Image.SCALE_SMOOTH) ) image.icon = icon legend.add(image) val caption = JLabel( "
The hulls shown as candidate solutions are those that are potential bug sources, i.e., those that the expert must look
" + "at both the hull itself (where the more red means more likely, and the less and more blue means less likely, but also likely)
" + "as well as other associated elements such as weapons, weak points, ..., declared in that hull.
", JLabel.CENTER ) val outsideBorder = EmptyBorder(0, 8, 16, 8) val insideBorder = BorderFactory.createCompoundBorder(BorderFactory.createRaisedBevelBorder(), EmptyBorder(4, 4, 4, 4)) caption.border = BorderFactory.createCompoundBorder(outsideBorder, insideBorder) legend.add(caption) modal.contentPane.add(legend) modal.pack() modal.title = "Legend" modal.isResizable = false modal.isVisible = true modal.defaultCloseOperation = DISPOSE_ON_CLOSE } override fun menuDeselected(e: MenuEvent?) {} override fun menuCanceled(e: MenuEvent?) {} }) menuBar.add(menu) } private fun obtainModelFragments(): List>> { val traces = List(10) { Array(64) { 0 } } val thresholds = MutableList(traces.size) { 0 } val modelFragments = List(traces.size) { mutableListOf>() } for ((i, c) in content.withIndex()) { for (e in (c as IndividualBossConfig).trace.distinct()) { traces[i][e] = Collections.frequency(c.trace, e) } //val median = median(traces[i].toList()) //thresholds[i] = if (median > 30) median else -1 //val (mode, _) = traces[i].toList().groupingBy { it }.eachCount().maxByOrNull { it.value }!! //thresholds[i] = mode val mean = traces[i].average().roundToInt() thresholds[i] = mean } for (i in traces.indices) { val similarTraces = traces.flatMap { it.toList() }.groupingBy { it }.eachCount().filterValues { it > 1 }.keys val distinctTraces = traces[i].distinct() for (x in distinctTraces.indices) { if (!similarTraces.contains(distinctTraces[x]) && distinctTraces[x] > thresholds[i]) { modelFragments[i].add(Pair(x + 1, distinctTraces[x])) } } // In case no probable bug source model fragments have been found, // the restriction is lowered to include some. if (modelFragments[i].isEmpty()) { val xs = mutableListOf() repeat((1..7).random()) { xs.add(distinctTraces.indices.random()) } for (x in xs.sorted()) { modelFragments[i].add(Pair(x + 1, distinctTraces[x])) } } } return modelFragments } }