class ChannelSelector(QWidget):
    channelSelected = Signal(str)
    channelDeselected = Signal(str)

    def __init__(self):
        QWidget.__init__(self)
        self.setLayout(QGridLayout())

        self.control_group = QButtonGroup()
        self.control_group.setExclusive(False)
        self.control_group.idToggled.connect(self.notifyChannel)
        self.ids_to_channels = {}  # {id: channel_name (str)}
        self.checkboxes = {}  # {channel_name: QCheckBox}

        self.next_id = 0

        # TODO(jacob): 4 columns is mostly an arbitrary choice; 5 seemed
        # too crowded, 3 seemed too empty. Ideally we'd change this
        # dynamically based on the column width.
        self.num_cols = 4

    def add_checkbox(self, channel_name):
        if channel_name in self.checkboxes:
            warnings.warn('attempted to add a duplicate checkbox to the DAQ channel selector')
            return
        checkbox = QCheckBox(channel_name)
        self.checkboxes[channel_name] = checkbox

        num_widgets = len(self.checkboxes)
        row = (num_widgets - 1) // self.num_cols
        col = (num_widgets - 1) % self.num_cols
        self.layout().addWidget(checkbox, row, col)

        self.control_group.addButton(checkbox, self.next_id)
        self.ids_to_channels[self.next_id] = channel_name
        self.next_id += 1

    def clear_checkboxes(self):
        for checkbox in self.checkboxes.values():
            self.control_group.removeButton(checkbox)
            self.layout().removeWidget(checkbox)
            checkbox.deleteLater()
        self.checkboxes = {}
        self.ids_to_channels = {}

    @Slot(top.PlumbingEngine)
    def updateNodeList(self, plumb):
        self.clear_checkboxes()
        for node in plumb.nodes(data=False):
            self.add_checkbox(node)

    @Slot(int)
    def notifyChannel(self, checkbox_id, is_checked):
        channel = self.ids_to_channels[checkbox_id]
        if is_checked:
            self.channelSelected.emit(channel)
        else:
            self.channelDeselected.emit(channel)
示例#2
0
class ParameterTagToolBar(QToolBar):
    """A toolbar to add items using drag and drop actions."""

    tag_button_toggled = Signal("QVariant", "bool")
    manage_tags_action_triggered = Signal("bool")
    tag_actions_added = Signal("QVariant", "QVariant")

    def __init__(self, parent, db_mngr, *db_maps):
        """

        Args:
            parent (DataStoreForm): tree or graph view form
            db_mngr (SpineDBManager): the DB manager for interacting with the db
            db_maps (iter): DiffDatabaseMapping instances
        """
        super().__init__("Parameter Tag Toolbar", parent=parent)
        self.db_mngr = db_mngr
        self.db_maps = db_maps
        label = QLabel("Parameter tag")
        self.addWidget(label)
        self.tag_button_group = QButtonGroup(self)
        self.tag_button_group.setExclusive(False)
        self.actions = []
        self.db_map_ids = []
        empty = QWidget()
        empty.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.empty_action = self.addWidget(empty)
        button = QPushButton("Manage tags...")
        self.addWidget(button)
        # noinspection PyUnresolvedReferences
        # pylint: disable=unnecessary-lambda
        button.clicked.connect(lambda checked: self.manage_tags_action_triggered.emit(checked))
        self.setStyleSheet(PARAMETER_TAG_TOOLBAR_SS)
        self.setObjectName("ParameterTagToolbar")
        self.tag_actions_added.connect(self._add_db_map_tag_actions)

    def init_toolbar(self):
        for button in self.tag_button_group.buttons():
            self.tag_button_group.removeButton(button)
        for action in self.actions:
            self.removeAction(action)
        action = QAction("untagged")
        self.insertAction(self.empty_action, action)
        action.setCheckable(True)
        button = self.widgetForAction(action)
        self.tag_button_group.addButton(button, id=0)
        self.actions = [action]
        self.db_map_ids = [[(db_map, 0) for db_map in self.db_maps]]
        tag_data = {}
        for db_map in self.db_maps:
            for parameter_tag in self.db_mngr.get_items(db_map, "parameter tag"):
                tag_data.setdefault(parameter_tag["tag"], {})[db_map] = parameter_tag["id"]
        for tag, db_map_data in tag_data.items():
            action = QAction(tag)
            self.insertAction(self.empty_action, action)
            action.setCheckable(True)
            button = self.widgetForAction(action)
            self.tag_button_group.addButton(button, id=len(self.db_map_ids))
            self.actions.append(action)
            self.db_map_ids.append(list(db_map_data.items()))
        self.tag_button_group.buttonToggled["int", "bool"].connect(
            lambda i, checked: self.tag_button_toggled.emit(self.db_map_ids[i], checked)
        )

    def receive_parameter_tags_added(self, db_map_data):
        for db_map, parameter_tags in db_map_data.items():
            self.tag_actions_added.emit(db_map, parameter_tags)

    @Slot("QVariant", "QVariant")
    def _add_db_map_tag_actions(self, db_map, parameter_tags):
        action_texts = [a.text() for a in self.actions]
        for parameter_tag in parameter_tags:
            if parameter_tag["tag"] in action_texts:
                # Already a tag named after that, add db_map id information
                i = action_texts.index(parameter_tag["tag"])
                self.db_map_ids[i].append((db_map, parameter_tag["id"]))
            else:
                action = QAction(parameter_tag["tag"])
                self.insertAction(self.empty_action, action)
                action.setCheckable(True)
                button = self.widgetForAction(action)
                self.tag_button_group.addButton(button, id=len(self.db_map_ids))
                self.actions.append(action)
                self.db_map_ids.append([(db_map, parameter_tag["id"])])
                action_texts.append(action.text())

    def receive_parameter_tags_removed(self, db_map_data):
        for db_map, parameter_tags in db_map_data.items():
            parameter_tag_ids = {x["id"] for x in parameter_tags}
            self._remove_db_map_tag_actions(db_map, parameter_tag_ids)

    def _remove_db_map_tag_actions(self, db_map, parameter_tag_ids):
        for tag_id in parameter_tag_ids:
            i = next(k for k, x in enumerate(self.db_map_ids) if (db_map, tag_id) in x)
            self.db_map_ids[i].remove((db_map, tag_id))
            if not self.db_map_ids[i]:
                self.db_map_ids.pop(i)
                self.removeAction(self.actions.pop(i))

    def receive_parameter_tags_updated(self, db_map_data):
        for db_map, parameter_tags in db_map_data.items():
            self._update_db_map_tag_actions(db_map, parameter_tags)

    def _update_db_map_tag_actions(self, db_map, parameter_tags):
        for parameter_tag in parameter_tags:
            i = next(k for k, x in enumerate(self.db_map_ids) if (db_map, parameter_tag["id"]) in x)
            action = self.actions[i]
            action.setText(parameter_tag["tag"])