<commit_before>package tornadofx

import javafx.application.Platform
import javafx.beans.property.DoubleProperty
import javafx.beans.property.Property
import javafx.beans.property.SimpleObjectProperty
import javafx.beans.property.StringProperty
import javafx.event.EventHandler
import javafx.geometry.Bounds
import javafx.geometry.Insets
import javafx.geometry.Pos
import javafx.scene.Node
import javafx.scene.Parent
import javafx.scene.Scene
import javafx.scene.canvas.Canvas
import javafx.scene.control.*
import javafx.scene.input.MouseEvent
import javafx.scene.layout.*
import javafx.scene.paint.Color
import javafx.scene.shape.Shape
import javafx.stage.Modality
import javafx.util.StringConverter
import javafx.util.converter.DoubleStringConverter

@Suppress("UNCHECKED_CAST")
class LayoutDebugger : Fragment() {
    override val root = BorderPane()

    lateinit var currentScene: Scene
    val hoveredNode = SimpleObjectProperty<Node>()
    val selectedNode = SimpleObjectProperty<Node>()
    var nodeTree: TreeView<Node> by singleAssign()
    val propertyContainer = ScrollPane()
    val stackpane = StackPane()
    val overlay = Canvas()
    val gc = overlay.graphicsContext2D

    init {
        overlay.isMouseTransparent = true
        stackpane += overlay
        gc.fill = c("#99bbbb", 0.4)

        with(root) {
            setPrefSize(800.0, 600.0)

            center = splitpane {
                setDividerPosition(0, 0.3)
                treeview<Node> {
                    nodeTree = this
                }
                this += propertyContainer.apply {
                    padding = Insets(10.0)
                }
            }
        }

        hookListeners()
    }

    private fun hookListeners() {
        nodeTree.selectionModel.selectedItemProperty().addListener { observableValue, oldItem, newItem ->
            if (newItem != null)
                setSelectedNode(newItem.value)
        }

        // Position overlay over hovered node
        hoveredNode.addListener { observableValue, oldNode, newNode ->
            if (oldNode != newNode && newNode != null)
                positionOverlayOver(newNode)
            else if (newNode == null && oldNode != null)
                clearOverlay()
        }
    }

    private fun positionOverlayOver(node: Node) {
        val p = node.localToScene(node.boundsInLocal)
        clearOverlay()
        gc.fillRect(p.minX, p.minY, p.width, p.height)
    }

    private fun clearOverlay() {
        gc.clearRect(0.0, 0.0, overlay.width, overlay.height)
    }

    val hoverHandler = EventHandler<MouseEvent> { event ->
        val newHover = event.target
        if (newHover is Node && hoveredNode.value != newHover)
            hoveredNode.value = newHover
    }

    val sceneExitedHandler = EventHandler<MouseEvent> { event ->
        hoveredNode.value = null
    }

    val clickHandler = EventHandler<MouseEvent> { event ->
        val clickedTarget = event.target
        if (clickedTarget is Node) setSelectedNode(clickedTarget)
        event.consume()
    }

    private fun setSelectedNode(node: Node) {
        selectedNode.value = node
        val treeItem = selectedNode.value.properties["tornadofx.layoutdebugger.treeitem"] as TreeItem<Node>?
        if (treeItem != null) nodeTree.selectionModel.select(treeItem)
        propertyContainer.content = NodePropertyView(node)
    }

    override fun onDock() {
        // Prevent the debugger from being reloaded
        Platform.runLater {
            modalStage!!.scene.properties["javafx.layoutdebugger"] = this
        }

        with(currentScene) {
            title = "Layout Debugger [%s]".format(this)
            // Prevent the scene from being reloaded while the debugger is running
            properties["javafx.layoutdebugger"] = this@LayoutDebugger
            addEventFilter(MouseEvent.MOUSE_EXITED, sceneExitedHandler)
            addEventFilter(MouseEvent.MOUSE_MOVED, hoverHandler)
            addEventFilter(MouseEvent.MOUSE_CLICKED, clickHandler)
        }

        // Overlay has same size as scene
        overlay.widthProperty().unbind()
        overlay.widthProperty().bind(currentScene.widthProperty())
        overlay.heightProperty().bind(currentScene.heightProperty())

        // Stackpane becomes the new scene root and contains the currentScene.root and our overlay
        stackpane.scene?.root = null
        val newSceneRoot = currentScene.root
        currentScene.root = stackpane
        stackpane += newSceneRoot
        overlay.toFront()<commit_msg>Fixed duplicate ondock in LayoutDebugger<commit_after>package tornadofx

import javafx.application.Platform
import javafx.beans.property.DoubleProperty
import javafx.beans.property.Property
import javafx.beans.property.SimpleObjectProperty
import javafx.beans.property.StringProperty
import javafx.event.EventHandler
import javafx.geometry.Bounds
import javafx.geometry.Insets
import javafx.geometry.Pos
import javafx.scene.Node
import javafx.scene.Parent
import javafx.scene.Scene
import javafx.scene.canvas.Canvas
import javafx.scene.control.*
import javafx.scene.input.MouseEvent
import javafx.scene.layout.*
import javafx.scene.paint.Color
import javafx.scene.shape.Shape
import javafx.stage.Modality
import javafx.util.StringConverter
import javafx.util.converter.DoubleStringConverter

@Suppress("UNCHECKED_CAST")
class LayoutDebugger : Fragment() {
    override val root = BorderPane()

    lateinit var currentScene: Scene
    val hoveredNode = SimpleObjectProperty<Node>()
    val selectedNode = SimpleObjectProperty<Node>()
    var nodeTree: TreeView<Node> by singleAssign()
    val propertyContainer = ScrollPane()
    val stackpane = StackPane()
    val overlay = Canvas()
    val gc = overlay.graphicsContext2D

    init {
        overlay.isMouseTransparent = true
        stackpane += overlay
        gc.fill = c("#99bbbb", 0.4)

        with(root) {
            setPrefSize(800.0, 600.0)

            center = splitpane {
                setDividerPosition(0, 0.3)
                treeview<Node> {
                    nodeTree = this
                }
                this += propertyContainer.apply {
                    padding = Insets(10.0)
                }
            }
        }

        hookListeners()
    }

    private fun hookListeners() {
        nodeTree.selectionModel.selectedItemProperty().addListener { observableValue, oldItem, newItem ->
            if (newItem != null)
                setSelectedNode(newItem.value)
        }

        // Position overlay over hovered node
        hoveredNode.addListener { observableValue, oldNode, newNode ->
            if (oldNode != newNode && newNode != null)
                positionOverlayOver(newNode)
            else if (newNode == null && oldNode != null)
                clearOverlay()
        }
    }

    private fun positionOverlayOver(node: Node) {
        val p = node.localToScene(node.boundsInLocal)
        clearOverlay()
        gc.fillRect(p.minX, p.minY, p.width, p.height)
    }

    private fun clearOverlay() {
        gc.clearRect(0.0, 0.0, overlay.width, overlay.height)
    }

    val hoverHandler = EventHandler<MouseEvent> { event ->
        val newHover = event.target
        if (newHover is Node && hoveredNode.value != newHover)
            hoveredNode.value = newHover
    }

    val sceneExitedHandler = EventHandler<MouseEvent> { event ->
        hoveredNode.value = null
    }

    val clickHandler = EventHandler<MouseEvent> { event ->
        val clickedTarget = event.target
        if (clickedTarget is Node) setSelectedNode(clickedTarget)
        event.consume()
    }

    private fun setSelectedNode(node: Node) {
        selectedNode.value = node
        val treeItem = selectedNode.value.properties["tornadofx.layoutdebugger.treeitem"] as TreeItem<Node>?
        if (treeItem != null) nodeTree.selectionModel.select(treeItem)
        propertyContainer.content = NodePropertyView(node)
    }

    override fun onDock() {
        // Avoid duplicate ondock, since we redock inside this function
        if (currentScene.root == stackpane) return

        // Prevent the debugger from being reloaded
        Platform.runLater {
            modalStage!!.scene.properties["javafx.layoutdebugger"] = this
        }

        with(currentScene) {
            title = "Layout Debugger [%s]".format(this)
            // Prevent the scene from being reloaded while the debugger is running
            properties["javafx.layoutdebugger"] = this@LayoutDebugger
            addEventFilter(MouseEvent.MOUSE_EXITED, sceneExitedHandler)
            addEventFilter(MouseEvent.MOUSE_MOVED, hoverHandler)
            addEventFilter(MouseEvent.MOUSE_CLICKED, clickHandler)
        }

        // Overlay has same size as scene
        overlay.widthProperty().unbind()
        overlay.widthProperty().bind(currentScene.widthProperty())
        overlay.heightProperty().bind(currentScene.heightProperty())

        // Stackpane becomes the new scene root and contains the currentScene.root and our overlay
        //stackpane.scene?.root = null
        val newSceneRoot = currentScene.root
        currentScene.root = stackpane
        stackpane += newSceneRoot
        overlay.toFront()
{'fraction_non_alphanumeric': 0.08772120290956466, 'fraction_numerical': 0.004994028878514819, 'mean_word_length': 2.570542635658915, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2222528', 'n_tokens_mistral': 2574, 'n_tokens_neox': 2479, 'n_words': 562}