<commit_before>package circlet.plugins.pipelines.ui

import circlet.pipelines.config.api.*
import circlet.plugins.pipelines.services.*
import circlet.plugins.pipelines.viewmodel.*
import circlet.runtime.*
import com.intellij.execution.*
import com.intellij.icons.*
import com.intellij.ide.*
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.project.*
import com.intellij.openapi.ui.*
import com.intellij.ui.*
import com.intellij.ui.treeStructure.*
import kotlinx.coroutines.*
import runtime.async.*
import runtime.reactive.*
import javax.swing.*
import javax.swing.tree.*

class CircletScriptsViewFactory {
    fun createView(lifetime: Lifetime, project: Project, viewModel: ScriptWindowViewModel) : JComponent {
        return createModelTreeView(lifetime, project, viewModel)
    }

    private fun createModelTreeView(lifetime: Lifetime, project: Project, viewModel: ScriptWindowViewModel) : JComponent {
        val tree = Tree()
        tree.selectionModel.selectionMode = TreeSelectionModel.SINGLE_TREE_SELECTION
        val root = tree.model.root as DefaultMutableTreeNode
        tree.selectionModel.addTreeSelectionListener {
            val selectedNode = it.path.lastPathComponent
            viewModel.selectedNode.value = if (selectedNode is CircletModelTreeNode) selectedNode else null

        }
        resetNodes(root, viewModel.script.value)
        expandTree(tree)
        tree.isRootVisible = false

        val refreshLifetimes = SequentialLifetimes(lifetime)
        val scriptModelBuilder = ScriptModelBuilder()
        val refreshAction = object : DumbAwareActionButton(IdeBundle.message("action.refresh"), AllIcons.Actions.Refresh) {
            override fun actionPerformed(e: AnActionEvent) {
                if (viewModel.modelBuildIsRunning.value) {
                    return
                }
                viewModel.modelBuildIsRunning.value = true
                val lt = refreshLifetimes.next()
                GlobalScope.launch {
                    val logBuildData = LogData("")
                    viewModel.logBuildData.value = logBuildData
                    val model = scriptModelBuilder.build(lt, project, logBuildData)
                    viewModel.script.value = model

                }.invokeOnCompletion {
                    launch(lt, ApplicationUiDispatch.coroutineContext) {
                        val model = viewModel.script.value
                        resetNodes(root, model)
                        tree.updateUI()
                        viewModel.modelBuildIsRunning.value = false
                    }
                }
            }
        }

        val runAction = object : DumbAwareActionButton(ExecutionBundle.message("run.configurable.display.name"), AllIcons.RunConfigurations.TestState.Run) {
            override fun actionPerformed(e: AnActionEvent) {
                if (viewModel.modelBuildIsRunning.value) {
                    return
                }
                Messages.showInfoMessage("run task", "circlet")
            }
        }

        fun updateActionsIsEnabledStates() {
            val smthIsRunning = viewModel.modelBuildIsRunning.value || viewModel.taskIsRunning.value
            val isSelectedNodeRunnable = viewModel.selectedNode.value?.isRunnable ?: false
            refreshAction.isEnabled = !smthIsRunning
            runAction.isEnabled = !smthIsRunning && isSelectedNodeRunnable
        }

        viewModel.apply {
            selectedNode.forEach(lifetime) {
                updateActionsIsEnabledStates()
            }
            modelBuildIsRunning.forEach(lifetime) {
                updateActionsIsEnabledStates()
            }
            taskIsRunning.forEach(lifetime) {
                updateActionsIsEnabledStates()
            }
        }

        return ToolbarDecorator
            .createDecorator(tree)
            .addExtraAction(refreshAction)
            .addExtraAction(runAction)
            .createPanel()
    }

    private fun expandTree(tree: JTree) {
        var oldRowCount = 0
        do {
            val rowCount = tree.rowCount
            if (rowCount == oldRowCount) break
            oldRowCount = rowCount
            for (i in 0 until rowCount) {
                tree.expandRow(i)
            }
        } while (true)
    }

    private fun resetNodes(root: DefaultMutableTreeNode, model: ScriptViewModel?) {<commit_msg>[idea plugin] [automation] add expandAll + collapseAll actions to toolbar<commit_after>package circlet.plugins.pipelines.ui

import circlet.pipelines.config.api.*
import circlet.plugins.pipelines.services.*
import circlet.plugins.pipelines.viewmodel.*
import circlet.runtime.*
import com.intellij.execution.*
import com.intellij.icons.*
import com.intellij.ide.*
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.project.*
import com.intellij.openapi.ui.*
import com.intellij.ui.*
import com.intellij.ui.treeStructure.*
import com.intellij.util.ui.tree.*
import kotlinx.coroutines.*
import runtime.async.*
import runtime.reactive.*
import javax.swing.*
import javax.swing.tree.*

class CircletScriptsViewFactory {
    fun createView(lifetime: Lifetime, project: Project, viewModel: ScriptWindowViewModel) : JComponent {
        return createModelTreeView(lifetime, project, viewModel)
    }

    private fun createModelTreeView(lifetime: Lifetime, project: Project, viewModel: ScriptWindowViewModel) : JComponent {
        val tree = Tree()
        tree.selectionModel.selectionMode = TreeSelectionModel.SINGLE_TREE_SELECTION
        val root = tree.model.root as DefaultMutableTreeNode
        tree.selectionModel.addTreeSelectionListener {
            val selectedNode = it.path.lastPathComponent
            viewModel.selectedNode.value = if (selectedNode is CircletModelTreeNode) selectedNode else null

        }
        resetNodes(root, viewModel.script.value)
        TreeUtil.expandAll(tree)
        tree.isRootVisible = false

        val refreshLifetimes = SequentialLifetimes(lifetime)
        val scriptModelBuilder = ScriptModelBuilder()
        val refreshAction = object : DumbAwareActionButton(IdeBundle.message("action.refresh"), AllIcons.Actions.Refresh) {
            override fun actionPerformed(e: AnActionEvent) {
                if (viewModel.modelBuildIsRunning.value) {
                    return
                }
                viewModel.modelBuildIsRunning.value = true
                val lt = refreshLifetimes.next()
                GlobalScope.launch {
                    val logBuildData = LogData("")
                    viewModel.logBuildData.value = logBuildData
                    val model = scriptModelBuilder.build(lt, project, logBuildData)
                    viewModel.script.value = model

                }.invokeOnCompletion {
                    launch(lt, ApplicationUiDispatch.coroutineContext) {
                        val model = viewModel.script.value
                        resetNodes(root, model)
                        tree.updateUI()
                        viewModel.modelBuildIsRunning.value = false
                    }
                }
            }
        }

        val runAction = object : DumbAwareActionButton(ExecutionBundle.message("run.configurable.display.name"), AllIcons.RunConfigurations.TestState.Run) {
            override fun actionPerformed(e: AnActionEvent) {
                if (viewModel.modelBuildIsRunning.value) {
                    return
                }
                Messages.showInfoMessage("run task", "circlet")
            }
        }

        val expandAllAction = object : DumbAwareActionButton(IdeBundle.message("action.expand.all"), AllIcons.Actions.Expandall) {
            override fun actionPerformed(e: AnActionEvent) {
                if (viewModel.modelBuildIsRunning.value) {
                    return
                }

                TreeUtil.expandAll(tree)
            }
        }

        val colapseAllAction = object : DumbAwareActionButton(IdeBundle.message("action.collapse.all"), AllIcons.Actions.Collapseall) {
            override fun actionPerformed(e: AnActionEvent) {
                if (viewModel.modelBuildIsRunning.value) {
                    return
                }

                TreeUtil.collapseAll(tree, 0)
            }
        }

        fun updateActionsIsEnabledStates() {
            val smthIsRunning = viewModel.modelBuildIsRunning.value || viewModel.taskIsRunning.value
            val isSelectedNodeRunnable = viewModel.selectedNode.value?.isRunnable ?: false
            refreshAction.isEnabled = !smthIsRunning
            runAction.isEnabled = !smthIsRunning && isSelectedNodeRunnable
        }

        viewModel.apply {
            selectedNode.forEach(lifetime) {
                updateActionsIsEnabledStates()
            }
            modelBuildIsRunning.forEach(lifetime) {
                updateActionsIsEnabledStates()
            }
            taskIsRunning.forEach(lifetime) {
                updateActionsIsEnabledStates()
            }
        }

        return ToolbarDecorator
            .createDecorator(tree)
            .addExtraAction(refreshAction)
            .addExtraAction(runAction)
            .addExtraAction(expandAllAction)
            .addExtraAction(colapseAllAction)
            .createPanel()
    }

    private fun resetNodes(root: DefaultMutableTreeNode, model: ScriptViewModel?) {
{'fraction_non_alphanumeric': 0.07878464818763327, 'fraction_numerical': 0.0003198294243070363, 'mean_word_length': 2.137458193979933, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '423594', 'n_tokens_mistral': 2463, 'n_tokens_neox': 2330, 'n_words': 429}