<commit_before>
import pulse
from pulse.vendor.Qt import QtCore, QtWidgets
from .core import PulseWindow
from .core import BlueprintUIModel


__all__ = [
    'ActionButtonsWidget',
    'ActionTreeWidget',
    'ActionTreeWindow',
]



class ActionTreeWidget(QtWidgets.QWidget):
    """
    A tree view that displays all BuildActions in a Blueprint.
    Items can be selected, and the shared selection model
    can then be used to display info about selected BuildActions
    in other UI.
    """

    def __init__(self, parent=None):
        super(ActionTreeWidget, self).__init__(parent=parent)

        # get shared models
        self.blueprintModel = BlueprintUIModel.getDefaultModel()
        self.model = self.blueprintModel.buildItemTreeModel
        self.selectionModel = self.blueprintModel.buildItemSelectionModel

        self.setupUi(self)

        # connect signals
        self.model.modelReset.connect(self.onModelReset)

    def showEvent(self, event):
        super(ActionTreeWidget, self).showEvent(event)
        self.blueprintModel.addSubscriber(self)

    def hideEvent(self, event):
        super(ActionTreeWidget, self).hideEvent(event)
        self.blueprintModel.removeSubscriber(self)

    def eventFilter(self, widget, event):
        if widget is self.treeView:
            if event.type() == QtCore.QEvent.KeyPress:
                key = event.key()
                if key == QtCore.Qt.Key_Delete:
                    self.deleteSelectedItems()
                    return True
        return QtWidgets.QWidget.eventFilter(self, widget, event)

    def setupUi(self, parent):
        layout = QtWidgets.QVBoxLayout(parent)

        self.treeView = QtWidgets.QTreeView(parent)
        self.treeView.setHeaderHidden(True)
        self.treeView.setDragEnabled(True)
        self.treeView.setDragDropMode(QtWidgets.QAbstractItemView.DragDropMode.DragDrop)
        self.treeView.setDefaultDropAction(QtCore.Qt.DropAction.MoveAction)
        self.treeView.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection)
        self.treeView.setIndentation(14)
        self.treeView.installEventFilter(self)
        self.treeView.setModel(self.model)
        self.treeView.setSelectionModel(self.selectionModel)
        self.treeView.expandAll()
        layout.addWidget(self.treeView)

    def onModelReset(self):
        self.treeView.expandAll()

    def deleteSelectedItems(self):
        wasChanged = False
        while True:
            indexes = self.selectionModel.selectedIndexes()
            if not indexes:
                break
            if not self.model.removeRow(indexes[0].row(), indexes[0].parent()):
                break
            wasChanged = True
        if wasChanged:
            self.blueprintModel.save()




class ActionButtonsWidget(QtWidgets.QWidget):
    """
    Provides UI for creating any BuildAction. One button is created
    for each BuildAction, and they are grouped by category. Also
    includes a search field for filtering the list of actions.
    """

    def __init__(self, parent=None):
        super(ActionButtonsWidget, self).__init__(parent=parent)

        self.blueprintModel = BlueprintUIModel.getDefaultModel()
        self.model = self.blueprintModel.buildItemTreeModel
        self.selectionModel = self.blueprintModel.buildItemSelectionModel
        self.setupUi(self)

    def setupUi(self, parent):
        """ Build the UI """
        layout = QtWidgets.QVBoxLayout(parent)

        grpBtn = QtWidgets.QPushButton(parent)
        grpBtn.setText("New Group")
        grpBtn.clicked.connect(self.createBuildGroup)
        layout.addWidget(grpBtn)

        searchField = QtWidgets.QLineEdit(parent)
        searchField.setPlaceholderText("Search")
        layout.addWidget(searchField)

        tabScrollWidget = QtWidgets.QWidget(parent)
        tabScroll = QtWidgets.QScrollArea(parent)
        tabScroll.setFrameShape(QtWidgets.QScrollArea.NoFrame)
        tabScroll.setWidgetResizable(True)
        tabScroll.setWidget(tabScrollWidget)

        self.setupContentUi(tabScrollWidget)

        layout.addWidget(tabScroll)

    def setupContentUi(self, parent):
        """ Build the action buttons UI """
        layout = QtWidgets.QVBoxLayout(parent)

        # make button for each action
        registeredActions = pulse.getRegisteredActions().values()
        categories = list(set([ac.config.get('category', 'Default') for ac in registeredActions]))
        categoryLayouts = {}

        # create category layouts
        for i, cat in enumerate(sorted(categories)):
            # add category layout
            catLay = QtWidgets.QVBoxLayout(parent)
            catLay.setSpacing(4)
            layout.addLayout(catLay)
            categoryLayouts[cat] = catLay
            # add label
            label = self.createLabel(parent, cat)
            catLay.addWidget(label)

        for actionClass in registeredActions:
            cat = actionClass.config.get('category', 'Default')
            color = self.getActionColor(actionClass)
            btn = QtWidgets.QPushButton(parent)
            btn.setText(actionClass.config['displayName'])
            btn.setStyleSheet('background-color:rgba({0}, {1}, {2}, 30)'.format(*color))
            btn.setMinimumHeight(22)
            cmd = lambda x=actionClass.getTypeName(): self.createBuildAction(x)
            btn.clicked.connect(cmd)
            categoryLayouts[cat].addWidget(btn)

        spacer = QtWidgets.QSpacerItem(0, 0,
            QtWidgets.QSizePolicy.Minimum,
            QtWidgets.QSizePolicy.Expanding)
        layout.addItem(spacer)

    def createLabel(self, parent, text):
        label = QtWidgets.QLabel(parent)
        label.setText(text)
        label.setMinimumHeight(20)
        label.setContentsMargins(10, 2, 2, 2)
        label.setStyleSheet('background-color: rgba(0, 0, 0, 40); border-radius: 2px')
        return label

    def getActionColor(self, actionClass):
        color = actionClass.config.get('color', [1, 1, 1])
        if color:
            return [int(c * 255) for c in color]
        else:
            return [255, 255, 255]

    def onActionClicked(self, typeName):
        self.clicked.emit(typeName)

    def createBuildGroup(self):
        if self.blueprintModel.isReadOnly():
            return

        grpIndexes = self.selectionModel.getSelectedGroups()
        for grpIndex in grpIndexes:
            grp = pulse.BuildItem('MyGroup')
            self.model.insertBuildItems(0, [grp], grpIndex)
        self.blueprintModel.save()

    def createBuildAction(self, typeName):
        if self.blueprintModel.isReadOnly():
            return

        grpIndexes = self.selectionModel.getSelectedGroups()
        ac = pulse.getActionClass(typeName)
        newIndexes = []
        for grpIndex in grpIndexes:
            action = ac()
            if self.model.insertBuildItems(0, [action], grpIndex):
                newIndexes.append(self.model.index(0, 0, grpIndex))
        # select new items
        self.selectionModel.clearSelection()
        for index in newIndexes:
            self.selectionModel.select(index, QtCore.QItemSelectionModel.Select)
        self.blueprintModel.save()




class ActionTreeWindow(PulseWindow):
    """
    A standalone window that contains an ActionTreeWidget
    and an ActionButtonsWidget.
    """

    OBJECT_NAME = 'pulseActionTreeWindow'

    def __init__(self, parent=None):
        super(ActionTreeWindow, self).__init__(parent=parent)

        self.setWindowTitle('Pulse Action Tree')

        widget = QtWidgets.QWidget(self)
        self.setCentralWidget(widget)
<commit_msg>prevents making new build items when nothing is selected<commit_after>
import pulse
from pulse.vendor.Qt import QtCore, QtWidgets
from .core import PulseWindow
from .core import BlueprintUIModel


__all__ = [
    'ActionButtonsWidget',
    'ActionTreeWidget',
    'ActionTreeWindow',
]



class ActionTreeWidget(QtWidgets.QWidget):
    """
    A tree view that displays all BuildActions in a Blueprint.
    Items can be selected, and the shared selection model
    can then be used to display info about selected BuildActions
    in other UI.
    """

    def __init__(self, parent=None):
        super(ActionTreeWidget, self).__init__(parent=parent)

        # get shared models
        self.blueprintModel = BlueprintUIModel.getDefaultModel()
        self.model = self.blueprintModel.buildItemTreeModel
        self.selectionModel = self.blueprintModel.buildItemSelectionModel

        self.setupUi(self)

        # connect signals
        self.model.modelReset.connect(self.onModelReset)

    def showEvent(self, event):
        super(ActionTreeWidget, self).showEvent(event)
        self.blueprintModel.addSubscriber(self)

    def hideEvent(self, event):
        super(ActionTreeWidget, self).hideEvent(event)
        self.blueprintModel.removeSubscriber(self)

    def eventFilter(self, widget, event):
        if widget is self.treeView:
            if event.type() == QtCore.QEvent.KeyPress:
                key = event.key()
                if key == QtCore.Qt.Key_Delete:
                    self.deleteSelectedItems()
                    return True
        return QtWidgets.QWidget.eventFilter(self, widget, event)

    def setupUi(self, parent):
        layout = QtWidgets.QVBoxLayout(parent)

        self.treeView = QtWidgets.QTreeView(parent)
        self.treeView.setHeaderHidden(True)
        self.treeView.setDragEnabled(True)
        self.treeView.setDragDropMode(QtWidgets.QAbstractItemView.DragDropMode.DragDrop)
        self.treeView.setDefaultDropAction(QtCore.Qt.DropAction.MoveAction)
        self.treeView.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection)
        self.treeView.setIndentation(14)
        self.treeView.installEventFilter(self)
        self.treeView.setModel(self.model)
        self.treeView.setSelectionModel(self.selectionModel)
        self.treeView.expandAll()
        layout.addWidget(self.treeView)

    def onModelReset(self):
        self.treeView.expandAll()

    def deleteSelectedItems(self):
        wasChanged = False
        while True:
            indexes = self.selectionModel.selectedIndexes()
            if not indexes:
                break
            if not self.model.removeRow(indexes[0].row(), indexes[0].parent()):
                break
            wasChanged = True
        if wasChanged:
            self.blueprintModel.save()




class ActionButtonsWidget(QtWidgets.QWidget):
    """
    Provides UI for creating any BuildAction. One button is created
    for each BuildAction, and they are grouped by category. Also
    includes a search field for filtering the list of actions.
    """

    def __init__(self, parent=None):
        super(ActionButtonsWidget, self).__init__(parent=parent)

        self.blueprintModel = BlueprintUIModel.getDefaultModel()
        self.model = self.blueprintModel.buildItemTreeModel
        self.selectionModel = self.blueprintModel.buildItemSelectionModel
        self.setupUi(self)

    def setupUi(self, parent):
        """ Build the UI """
        layout = QtWidgets.QVBoxLayout(parent)

        grpBtn = QtWidgets.QPushButton(parent)
        grpBtn.setText("New Group")
        grpBtn.clicked.connect(self.createBuildGroup)
        layout.addWidget(grpBtn)

        searchField = QtWidgets.QLineEdit(parent)
        searchField.setPlaceholderText("Search")
        layout.addWidget(searchField)

        tabScrollWidget = QtWidgets.QWidget(parent)
        tabScroll = QtWidgets.QScrollArea(parent)
        tabScroll.setFrameShape(QtWidgets.QScrollArea.NoFrame)
        tabScroll.setWidgetResizable(True)
        tabScroll.setWidget(tabScrollWidget)

        self.setupContentUi(tabScrollWidget)

        layout.addWidget(tabScroll)

    def setupContentUi(self, parent):
        """ Build the action buttons UI """
        layout = QtWidgets.QVBoxLayout(parent)

        # make button for each action
        registeredActions = pulse.getRegisteredActions().values()
        categories = list(set([ac.config.get('category', 'Default') for ac in registeredActions]))
        categoryLayouts = {}

        # create category layouts
        for i, cat in enumerate(sorted(categories)):
            # add category layout
            catLay = QtWidgets.QVBoxLayout(parent)
            catLay.setSpacing(4)
            layout.addLayout(catLay)
            categoryLayouts[cat] = catLay
            # add label
            label = self.createLabel(parent, cat)
            catLay.addWidget(label)

        for actionClass in registeredActions:
            cat = actionClass.config.get('category', 'Default')
            color = self.getActionColor(actionClass)
            btn = QtWidgets.QPushButton(parent)
            btn.setText(actionClass.config['displayName'])
            btn.setStyleSheet('background-color:rgba({0}, {1}, {2}, 30)'.format(*color))
            btn.setMinimumHeight(22)
            cmd = lambda x=actionClass.getTypeName(): self.createBuildAction(x)
            btn.clicked.connect(cmd)
            categoryLayouts[cat].addWidget(btn)

        spacer = QtWidgets.QSpacerItem(0, 0,
            QtWidgets.QSizePolicy.Minimum,
            QtWidgets.QSizePolicy.Expanding)
        layout.addItem(spacer)

    def createLabel(self, parent, text):
        label = QtWidgets.QLabel(parent)
        label.setText(text)
        label.setMinimumHeight(20)
        label.setContentsMargins(10, 2, 2, 2)
        label.setStyleSheet('background-color: rgba(0, 0, 0, 40); border-radius: 2px')
        return label

    def getActionColor(self, actionClass):
        color = actionClass.config.get('color', [1, 1, 1])
        if color:
            return [int(c * 255) for c in color]
        else:
            return [255, 255, 255]

    def onActionClicked(self, typeName):
        self.clicked.emit(typeName)

    def createBuildGroup(self):
        if self.blueprintModel.isReadOnly():
            return

        grpIndexes = self.selectionModel.getSelectedGroups()
        if not grpIndexes:
            return

        for grpIndex in grpIndexes:
            grp = pulse.BuildItem('MyGroup')
            self.model.insertBuildItems(0, [grp], grpIndex)
        self.blueprintModel.save()

    def createBuildAction(self, typeName):
        if self.blueprintModel.isReadOnly():
            return

        grpIndexes = self.selectionModel.getSelectedGroups()
        if not grpIndexes:
            return

        ac = pulse.getActionClass(typeName)
        newIndexes = []
        for grpIndex in grpIndexes:
            action = ac()
            if self.model.insertBuildItems(0, [action], grpIndex):
                newIndexes.append(self.model.index(0, 0, grpIndex))
        # select new items
        self.selectionModel.clearSelection()
        for index in newIndexes:
            self.selectionModel.select(index, QtCore.QItemSelectionModel.Select)
        self.blueprintModel.save()




class ActionTreeWindow(PulseWindow):
    """
    A standalone window that contains an ActionTreeWidget
    and an ActionButtonsWidget.
    """

    OBJECT_NAME = 'pulseActionTreeWindow'

    def __init__(self, parent=None):
        super(ActionTreeWindow, self).__init__(parent=parent)

        self.setWindowTitle('Pulse Action Tree')

        widget = QtWidgets.QWidget(self)
        self.setCentralWidget(widget)

{'fraction_non_alphanumeric': 0.09152961060911395, 'fraction_numerical': 0.005980627965936423, 'mean_word_length': 2.591874854074247, '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': '4659185', 'n_tokens_mistral': 4432, 'n_tokens_neox': 4259, 'n_words': 860}