Exemplo n.º 1
0
    def add_supplier_list_to_combo(self, combo: QComboBox):
        # clear QComboBox
        combo.clear()
        combo.clearEditText()

        if self.parent.sheets is None:
            combo.setEnabled(False)
            return

        if self.db is None:
            self.flag_db = False
            combo.setEnabled(False)
            return

        # DB Query and update QConboBox
        sql = "SELECT name_supplier_short FROM supplier;"
        out = self.db.get(sql)
        for supplier in out:
            combo.addItem(supplier[0])

        name = self.get_supplier_name()
        index = combo.findText(name)
        if index >= 0:
            combo.setCurrentIndex(index)
            combo.setEnabled(False)
        else:
            combo.setEnabled(True)
Exemplo n.º 2
0
    def generateDataTypesField(dataType=None):
        """
		@rtype: QComboBox
		"""
        dataTypes = QComboBox()
        dataTypes.addItems(
            ['TINYINT', 'SMALLINT', 'MEDIUMINT', 'INT', 'BIGINT', 'BIT'])
        dataTypes.insertSeparator(dataTypes.count())
        dataTypes.addItems(['FLOAT', 'DOUBLE', 'DECIMAL'])
        dataTypes.insertSeparator(dataTypes.count())
        dataTypes.addItems(
            ['CHAR', 'VARCHAR', 'TINYTEXT', 'TEXT', 'MEDIUMTEXT', 'LONGTEXT'])
        dataTypes.insertSeparator(dataTypes.count())
        dataTypes.addItems([
            'BINARY', 'VARBINARY', 'TINYBLOB', 'BLOB', 'MEDIUMBLOB', 'LONGBLOB'
        ])
        dataTypes.insertSeparator(dataTypes.count())
        dataTypes.addItems(['DATE', 'TIME', 'YEAR', 'DATETIME', 'TIMESTAMP'])
        dataTypes.insertSeparator(dataTypes.count())
        dataTypes.addItems([
            'POINT', 'LINESTRING', 'POLYGON', 'GEOMETRY', 'MULTIPOINT',
            'MULTILINESTRING', 'MULTIPOLYGON', 'GEOMETRYCOLLECTION'
        ])
        dataTypes.insertSeparator(dataTypes.count())
        dataTypes.addItems(['ENUM', 'SET'])

        if dataType is not None:
            dataTypes.setCurrentIndex(dataTypes.findText(dataType.upper()))

        return dataTypes
Exemplo n.º 3
0
def comboBoxSelectItemByText(combobox: QtWidgets.QComboBox, value, block=False):
    index = combobox.findText(value)
    if index >= 0:
        if block:
            block_state = combobox.blockSignals(True)
        combobox.setCurrentIndex(index)
        if block:
            combobox.blockSignals(block_state)
class DatatypeSelector(QGroupBox):
    def __init__(self,
                 title: str,
                 datatype_to_widget,
                 parent: "QWidget" = None):
        super().__init__(title, parent)

        # Maps a datatype with its respective widget. The widget is optional
        self._datatype_to_widget = datatype_to_widget

        self._datatype_combobox = QComboBox()

        self._stacked_widgets = QStackedWidget()

        for (i, (name, datatype_factory)) in enumerate(
                DataTypeContainer.providers.items()):
            datatype_instance = datatype_factory()
            self._datatype_combobox.addItem(name, datatype_instance)

            if datatype_factory in self._datatype_to_widget:
                self._stacked_widgets.insertWidget(
                    i, self._datatype_to_widget[datatype_factory](
                        datatype_instance))

        self._main_layout = QVBoxLayout()
        self._main_layout.addWidget(self._datatype_combobox)
        self._main_layout.addWidget(self._stacked_widgets)

        self.setLayout(self._main_layout)

        self._datatype_combobox.currentIndexChanged[int].connect(
            self._change_active_widget)

    @property
    def selected_datatype(self):
        return self._datatype_combobox.currentData()

    def change_current_datatype(self, new_datatype_dict: dict):
        index = self._datatype_combobox.findText(new_datatype_dict["class"])

        if index != -1:
            self._datatype_combobox.setCurrentIndex(index)
            self._datatype_combobox.currentData().from_dict(new_datatype_dict)
            self._stacked_widgets.currentWidget().reload()

    def _change_active_widget(self, index):
        self._stacked_widgets.setCurrentIndex(index)

        # Hide the `stacked_widgets` when the current datatype doesn't needs to display
        # a widget
        if self._stacked_widgets.currentIndex() != index:
            self._stacked_widgets.setVisible(False)
        else:
            self._stacked_widgets.setVisible(True)

    def to_dict(self):
        return self.selected_datatype.to_dict()
Exemplo n.º 5
0
    def initUI(self):
        mainLayout = QGridLayout(self)
        mainLayout.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        # mainLayout.setColumnStretch(0,0)
        mainLayout.setColumnStretch(1,1)
        mainLayout.setColumnStretch(2,1)
        # mainLayout.setColumnStretch(3,1)
        self.setLayout(mainLayout)

        line = 0
        title = QLabel('Change Current Namespace to:')
        title.setAlignment(Qt.AlignLeft)
        mainLayout.addWidget(title, line, 0, 1, 3)

        line += 1
        for each in self.namespace:
            dyName = QLabel(each)
            dyCombo = QComboBox()
            dyCombo.setLineEdit(QLineEdit())
            for valName in self.validNamespace:
                dyCombo.addItem(valName,self.validNamespace.index(valName))
            dyCombo.setCurrentIndex(dyCombo.findText(each,Qt.MatchExactly))
            mainLayout.addWidget(dyName, line, 0, 1, 1)
            mainLayout.addWidget(dyCombo, line, 1, 1, 2)
            self.model[each] = dyCombo
            line += 1

        line += 1
        okBtn = QPushButton("OK")
        okBtn.clicked.connect(self.accept)
        cancelBtn = QPushButton("Cancel")
        cancelBtn.clicked.connect(self.reject)

        mainLayout.addWidget(okBtn, line, 1, 1, 1)
        mainLayout.addWidget(cancelBtn, line, 2, 1, 1)
        self.setWindowTitle("Choose Namespace")
        self.setWindowFlags(Qt.WindowStaysOnTopHint)
Exemplo n.º 6
0
class AdvancedTab(QWidget):
    def __init__(self, parent_dialog, parent):
        """Initialize the advanced tab
        """

        super(AdvancedTab, self).__init__(parent)

        self.prefs = parent_dialog.prefs
        self.parent = parent

        # Log Details
        log_label = QLabel("Log Detail Level:")
        self.log_edit = QComboBox(self)
        self.log_edit.addItems(['INFO', 'DEBUG', 'WARNING'])
        self.log_edit.setCurrentIndex(self.log_edit.findText(self.prefs['log_level']))
        self.log_edit.currentIndexChanged.connect(self.log_level)
        self.log_edit.setMaximumWidth(100)

        # Clear IDD cache
        self.clear_idd_button = QPushButton("Clear IDD Cache")
        self.clear_idd_button.setMaximumWidth(200)
        self.clear_idd_button.clicked.connect(self.clear_idd_cache)
        clear_text = QLabel("This will delete the pre-processed IDD files and force "
                                  "IDF+ to reprocess them the next time they are required. "
                                  "This should happen automatically when necessary, but if "
                                  "there are problems after updating to a new version of "
                                  "IDF+, it can sometimes help to force it here.")
        clear_text.setWordWrap(True)
        clear_text.setMaximumWidth(450)
        clear_text.setMinimumHeight(40)

        # Clear IDD cache group box code
        self.clear_idd_group_box = QGroupBox("Clear Pre-processed IDD Cache:")
        clear_group_box = QVBoxLayout()
        clear_group_box.addWidget(clear_text)
        clear_group_box.addSpacing(10)
        clear_group_box.addWidget(self.clear_idd_button)
        clear_group_box.addStretch(1)
        self.clear_idd_group_box.setLayout(clear_group_box)

        # Open dirs code
        self.open_settings_button = QPushButton("Open Settings Directory")
        self.open_settings_button.setMaximumWidth(175)
        self.open_settings_button.clicked.connect(lambda: self.parent.show_in_folder(config.CONFIG_FILE_PATH))
        self.open_log_button = QPushButton("Open Log Directory")
        self.open_log_button.setMaximumWidth(175)
        self.open_log_button.clicked.connect(lambda: self.parent.show_in_folder(config.LOG_DIR))
        self.open_data_button = QPushButton("Open Data Directory")
        self.open_data_button.setMaximumWidth(175)
        self.open_data_button.clicked.connect(lambda: self.parent.show_in_folder(config.DATA_DIR))

        # Default IDF file version code
        idd_label = QLabel("Default IDF File Version:")
        idd_label.setToolTip('Default version to use if none is detected.')
        self.idd_edit = QComboBox(self)
        self.idd_edit.addItems(config.idd_versions())
        self.idd_edit.setMaximumWidth(100)
        self.idd_edit.setCurrentIndex(self.idd_edit.findText(self.prefs['default_idd_version']))
        self.idd_edit.currentIndexChanged.connect(self.update_idd_version)

        # Main layout code
        main_layout = QVBoxLayout()
        main_layout.addWidget(idd_label)
        main_layout.addWidget(self.idd_edit)
        main_layout.addSpacing(10)
        main_layout.addWidget(log_label)
        main_layout.addWidget(self.log_edit)
        main_layout.addSpacing(10)
        main_layout.addWidget(self.clear_idd_group_box)
        main_layout.addStretch(1)
        main_layout.addWidget(self.open_settings_button)
        main_layout.addWidget(self.open_log_button)
        main_layout.addWidget(self.open_data_button)
        self.setLayout(main_layout)

    def log_level(self):
        self.prefs['log_level'] = self.log_edit.currentText()

    def clear_idd_cache(self):
        self.prefs['clear_idd_cache'] = True

    def update_idd_version(self):
        self.prefs['default_idd_version'] = self.idd_edit.currentText()
Exemplo n.º 7
0
class Parameters(QWidget):
    onChangeBGColor = Signal(QColor)
    onChangeFontColor = Signal(QColor)
    onChangeFontSize = Signal(int)
    onChangeText = Signal(str)
    onChangeShape = Signal(str)

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

        # self.setMinimumHeight(1)
        self.setFixedHeight(35)
        self.setMinimumWidth(1)

        # ------------- Main Layout --------------
        main_layout = QHBoxLayout(self)
        main_layout.setContentsMargins(5, 5, 5, 5)
        main_layout.setSpacing(5)
        main_layout.setAlignment(Qt.AlignTop)
        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

        # ------- Row 1 -------
        # ----------------------------------------
        allLayout = QHBoxLayout()
        allLayout.setContentsMargins(0, 0, 0, 0)
        allLayout.setSpacing(3)
        allLayout.setAlignment(Qt.AlignTop | Qt.AlignLeft)

        # Color
        colorLabel = QLabel(u"Color:")
        colorLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.color_btn = QPushColorButton(columns=0,
                                          rows=6,
                                          palette=COLOR_PALETTE)
        self.color_btn.colorSelected.connect(self.change_bg_color)

        # Size
        sizeLabel = QLabel(u"Size:")
        sizeLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.size_combo = QComboBox()
        for i in range(1, 100):
            self.size_combo.addItem(str(i), i)
        self.size_combo.activated.connect(self.change_font_size)

        # Shape
        shapeLabel = QLabel(u"Shape:")
        shapeLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.shape_combo = QComboBox()
        self.shape_combo.addItem(QIconSVG('square'), PickShape.SQUARE,
                                 PickShape.SQUARE)
        self.shape_combo.addItem(QIconSVG('circle'), PickShape.CIRCLE,
                                 PickShape.CIRCLE)
        self.shape_combo.addItem(QIconSVG('triangle'), PickShape.TRIANGLE,
                                 PickShape.TRIANGLE)
        self.shape_combo.addItem(QIconSVG('plus'), PickShape.PLUS,
                                 PickShape.PLUS)
        self.shape_combo.activated.connect(self.change_shape)

        # Name
        nameLabel = QLabel(u"Label:")
        nameLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)

        self.nameIn = QLineEdit()
        self.nameIn.textEdited.connect(self.change_name)
        self.textColor_btn = QPushColorButton(columns=1,
                                              rows=0,
                                              palette=BW_PALETTE)
        self.textColor_btn.colorSelected.connect(self.change_font_color)

        # Add widget to Layout
        allLayout.addWidget(colorLabel)
        allLayout.addWidget(self.color_btn)
        allLayout.addWidget(sizeLabel)
        allLayout.addWidget(self.size_combo)
        allLayout.addWidget(shapeLabel)
        allLayout.addWidget(self.shape_combo)
        allLayout.addWidget(nameLabel)
        allLayout.addWidget(self.nameIn)
        allLayout.addWidget(self.textColor_btn)

        main_layout.addLayout(allLayout)

    def change_name(self):
        '''
        Sending Signal from "onChangeText" to change the text
        '''
        self.onChangeText.emit(self.nameIn.text())

    def change_bg_color(self, color=QColor):
        '''
        Sending Signal from "onChangeBGColor" to change the
        background color.

        Parameters
        ----------
        color: (QColor)
            QColor value to send over.
        '''
        self.onChangeBGColor.emit(color)

    def change_font_color(self, color=QColor):
        '''
        Sending Signal from "onChangeFontColor" to change the
        font color.

        Parameters
        ----------
        color: (QColor)
            QColor value to send over.
        '''
        self.onChangeFontColor.emit(color)

    def change_font_size(self, value):
        '''
        Sending Signal from "onChangeFontSize" to change the
        font size.
        '''
        self.onChangeFontSize.emit(value + 1)

    def change_shape(self):
        '''
        Sending Signal from "onChangeShape" to change the
        shape of node.
        '''
        self.onChangeShape.emit(self.shape_combo.currentText())

    def update_param(self,
                     text=str,
                     fontSize=int,
                     fontColor=QColor,
                     bgColor=QColor,
                     shapeName=str()):
        '''
        Update the UI parameters.

        Parameters
        ----------
        text: (str)
            Name of the node.
        fontSize: (int)
            Size of the font.
        fontColor: (QColor)
            Color of the font.
        bgColor: (QColor)
            Color of the background.
        '''
        self.color_btn.CurrentColor = bgColor
        self.textColor_btn.CurrentColor = fontColor
        self.size_combo.setCurrentIndex(self.size_combo.findText(
            str(fontSize)))
        self.nameIn.setText(text)
        if shapeName:
            self.shape_combo.setCurrentIndex(
                self.shape_combo.findText(shapeName))
            self.shape_combo.setEnabled(True)
        else:
            self.shape_combo.setEnabled(False)
            self.shape_combo.setCurrentIndex(-1)

    def get_name(self):
        return self.nameIn.text()

    def set_name(self, value=str()):
        self.nameIn.setText(value)

    Name = property(get_name, set_name)
Exemplo n.º 8
0
class TallyDock(PlotterDock):

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

        self.setAllowedAreas(QtCore.Qt.RightDockWidgetArea)

        # Dock maps for tally information
        self.tally_map = {}
        self.filter_map = {}
        self.score_map = {}
        self.nuclide_map = {}

        # Tally selector
        self.tallySelectorLayout = QFormLayout()
        self.tallySelector = QComboBox(self)
        self.tallySelector.currentTextChanged[str].connect(
            self.main_window.editSelectedTally)
        self.tallySelectorLayout.addRow(self.tallySelector)
        self.tallySelectorLayout.setLabelAlignment(QtCore.Qt.AlignLeft)
        self.tallySelectorLayout.setFieldGrowthPolicy(
            QFormLayout.AllNonFixedFieldsGrow)

        # Add selector to its own box
        self.tallyGroupBox = QGroupBox('Selected Tally')
        self.tallyGroupBox.setLayout(self.tallySelectorLayout)

        # Create submit button
        self.applyButton = QPushButton("Apply Changes")
        self.applyButton.setMinimumHeight(self.font_metric.height() * 1.6)
        self.applyButton.clicked.connect(self.main_window.applyChanges)

        # Color options section
        self.tallyColorForm = ColorForm(self.model, self.main_window, 'tally')
        self.scoresGroupBox = Expander(title="Scores:")
        self.scoresListWidget = QListWidget()
        self.nuclidesListWidget = QListWidget()

        # Main layout
        self.dockLayout = QVBoxLayout()
        self.dockLayout.addWidget(QLabel("Tallies"))
        self.dockLayout.addWidget(HorizontalLine())
        self.dockLayout.addWidget(self.tallyGroupBox)
        self.dockLayout.addStretch()
        self.dockLayout.addWidget(HorizontalLine())
        self.dockLayout.addWidget(self.tallyColorForm)
        self.dockLayout.addWidget(HorizontalLine())
        self.dockLayout.addWidget(self.applyButton)

        # Create widget for dock and apply main layout
        self.scroll = QScrollArea()
        self.scroll.setWidgetResizable(True)
        self.widget = QWidget()
        self.widget.setLayout(self.dockLayout)
        self.scroll.setWidget(self.widget)
        self.setWidget(self.scroll)

    def _createFilterTree(self, spatial_filters):
        av = self.model.activeView
        tally = self.model.statepoint.tallies[av.selectedTally]
        filters = tally.filters

        # create a tree for the filters
        self.treeLayout = QVBoxLayout()
        self.filterTree = QTreeWidget()
        self.treeLayout.addWidget(self.filterTree)
        self.treeExpander = Expander("Filters:", layout=self.treeLayout)
        self.treeExpander.expand()  # start with filters expanded

        header = QTreeWidgetItem(["Filters"])
        self.filterTree.setHeaderItem(header)
        self.filterTree.setItemHidden(header, True)
        self.filterTree.setColumnCount(1)
        self.filterTree.itemChanged.connect(self.updateFilters)

        self.filter_map = {}
        self.bin_map = {}

        for tally_filter in filters:
            filter_label = str(type(tally_filter)).split(".")[-1][:-2]
            filter_item = QTreeWidgetItem(self.filterTree, (filter_label,))
            self.filter_map[tally_filter] = filter_item

            # make checkable
            if not spatial_filters:
                filter_item.setFlags(QtCore.Qt.ItemIsUserCheckable)
                filter_item.setToolTip(0, "Only tallies with spatial filters are viewable.")
            else:
                filter_item.setFlags(filter_item.flags() | QtCore.Qt.ItemIsTristate | QtCore.Qt.ItemIsUserCheckable)
            filter_item.setCheckState(0, QtCore.Qt.Unchecked)

            # all mesh bins are selected by default and not shown in the dock
            if isinstance(tally_filter, openmc.MeshFilter):
                filter_item.setCheckState(0, QtCore.Qt.Checked)
                filter_item.setFlags(QtCore.Qt.ItemIsUserCheckable)
                filter_item.setToolTip(0, "All Mesh bins are selected automatically")
                continue

            def _bin_sort_val(bin):
                if isinstance(bin, Iterable) and all([isinstance(val, float) for val in bin]):
                    return np.sum(bin)
                else:
                    return bin

            for bin in sorted(tally_filter.bins, key=_bin_sort_val):
                item = QTreeWidgetItem(filter_item, [str(bin),])
                if not spatial_filters:
                    item.setFlags(QtCore.Qt.ItemIsUserCheckable)
                    item.setToolTip(0, "Only tallies with spatial filters are viewable.")
                else:
                    item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
                item.setCheckState(0, QtCore.Qt.Unchecked)

                bin = bin if not isinstance(bin, Iterable) else tuple(bin)
                self.bin_map[tally_filter, bin] = item

            # start with all filters selected if spatial filters are present
            if spatial_filters:
                filter_item.setCheckState(0, QtCore.Qt.Checked)

    def selectFromModel(self):
        cv = self.model.currentView
        self.selectedTally(cv.selectedTally)

    def selectTally(self, tally_label=None):
        # using active view to populate tally options live
        av = self.model.activeView

        # reset form layout
        for i in reversed(range(self.tallySelectorLayout.count())):
            self.tallySelectorLayout.itemAt(i).widget().setParent(None)

        # always re-add the tally selector to the layout
        self.tallySelectorLayout.addRow(self.tallySelector)
        self.tallySelectorLayout.addRow(HorizontalLine())

        if tally_label is None or tally_label == "None" or tally_label == "":
            av.selectedTally = None
            self.score_map = None
            self.nuclide_map = None
            self.filter_map = None
            av.tallyValue = "Mean"
        else:
            # get the tally
            tally = self.model.statepoint.tallies[av.selectedTally]

            # populate filters
            filter_types = {type(f) for f in tally.filters}
            spatial_filters = bool(filter_types.intersection(_SPATIAL_FILTERS))

            if not spatial_filters:
                self.filter_description = QLabel("(No Spatial Filters)")
                self.tallySelectorLayout.addRow(self.filter_description)

            self._createFilterTree(spatial_filters)

            self.tallySelectorLayout.addRow(self.treeExpander)
            self.tallySelectorLayout.addRow(HorizontalLine())

            # value selection
            self.tallySelectorLayout.addRow(QLabel("Value:"))
            self.valueBox = QComboBox(self)
            self.values = tuple(_TALLY_VALUES.keys())
            for value in self.values:
                self.valueBox.addItem(value)
            self.tallySelectorLayout.addRow(self.valueBox)
            self.valueBox.currentTextChanged[str].connect(
                self.main_window.editTallyValue)
            self.updateTallyValue()

            if not spatial_filters:
                self.valueBox.setEnabled(False)
                self.valueBox.setToolTip("Only tallies with spatial filters are viewable.")

            # scores
            self.score_map = {}
            self.scoresListWidget.itemClicked.connect(
                self.main_window.updateScores)
            self.score_map.clear()
            self.scoresListWidget.clear()

            sorted_scores = sorted(tally.scores)
            # always put total first if present
            if 'total' in sorted_scores:
                idx = sorted_scores.index('total')
                sorted_scores.insert(0, sorted_scores.pop(idx))

            for score in sorted_scores:
                ql = QListWidgetItem()
                ql.setText(score.capitalize())
                ql.setCheckState(QtCore.Qt.Unchecked)
                if not spatial_filters:
                    ql.setFlags(QtCore.Qt.ItemIsUserCheckable)
                else:
                    ql.setFlags(ql.flags() | QtCore.Qt.ItemIsUserCheckable)
                    ql.setFlags(ql.flags() & ~QtCore.Qt.ItemIsSelectable)
                self.score_map[score] = ql
                self.scoresListWidget.addItem(ql)

            # select the first score item by default
            for item in self.score_map.values():
                item.setCheckState(QtCore.Qt.Checked)
                break
            self.updateScores()

            self.scoresGroupBoxLayout = QVBoxLayout()
            self.scoresGroupBoxLayout.addWidget(self.scoresListWidget)
            self.scoresGroupBox = Expander("Scores:", layout=self.scoresGroupBoxLayout)
            self.tallySelectorLayout.addRow(self.scoresGroupBox)

            # nuclides
            self.nuclide_map = {}
            self.nuclidesListWidget.itemClicked.connect(self.main_window.updateNuclides)
            self.nuclide_map.clear()
            self.nuclidesListWidget.clear()

            sorted_nuclides = sorted(tally.nuclides)
            # always put total at the top
            if 'total' in sorted_nuclides:
                idx = sorted_nuclides.index('total')
                sorted_nuclides.insert(0, sorted_nuclides.pop(idx))

            for nuclide in sorted_nuclides:
                ql = QListWidgetItem()
                ql.setText(nuclide.capitalize())
                ql.setCheckState(QtCore.Qt.Unchecked)
                if not spatial_filters:
                    ql.setFlags(QtCore.Qt.ItemIsUserCheckable)
                else:
                    ql.setFlags(ql.flags() | QtCore.Qt.ItemIsUserCheckable)
                    ql.setFlags(ql.flags() & ~QtCore.Qt.ItemIsSelectable)
                self.nuclide_map[nuclide] = ql
                self.nuclidesListWidget.addItem(ql)

            # select the first nuclide item by default
            for item in self.nuclide_map.values():
                item.setCheckState(QtCore.Qt.Checked)
                break
            self.updateNuclides()

            self.nuclidesGroupBoxLayout = QVBoxLayout()
            self.nuclidesGroupBoxLayout.addWidget(self.nuclidesListWidget)
            self.nuclidesGroupBox = Expander("Nuclides:", layout=self.nuclidesGroupBoxLayout)
            self.tallySelectorLayout.addRow(self.nuclidesGroupBox)

    def updateMinMax(self):
        self.tallyColorForm.updateMinMax()

    def updateTallyValue(self):
        cv = self.model.currentView
        idx = self.valueBox.findText(cv.tallyValue)
        self.valueBox.setCurrentIndex(idx)

    def updateSelectedTally(self):
        cv = self.model.currentView
        idx = 0
        if cv.selectedTally:
            idx = self.tallySelector.findData(cv.selectedTally)
        self.tallySelector.setCurrentIndex(idx)

    def updateFilters(self):
        applied_filters = defaultdict(tuple)
        for f, f_item in self.filter_map.items():
            if type(f) == openmc.MeshFilter:
                continue

            filter_checked = f_item.checkState(0)
            if filter_checked != QtCore.Qt.Unchecked:
                selected_bins = []
                for idx, b in enumerate(f.bins):
                    b = b if not isinstance(b, Iterable) else tuple(b)
                    bin_checked = self.bin_map[(f, b)].checkState(0)
                    if bin_checked == QtCore.Qt.Checked:
                        selected_bins.append(idx)
                applied_filters[f] = tuple(selected_bins)

            self.model.appliedFilters = applied_filters

    def updateScores(self):
        applied_scores = []
        for score, score_box in self.score_map.items():
            if score_box.checkState() == QtCore.Qt.CheckState.Checked:
                applied_scores.append(score)
        self.model.appliedScores = tuple(applied_scores)

        if not applied_scores:
            # if no scores are selected, enable all scores again
            for score, score_box in self.score_map.items():
                sunits = _SCORE_UNITS.get(score, _REACTION_UNITS)
                empty_item = QListWidgetItem()
                score_box.setFlags(empty_item.flags() | QtCore.Qt.ItemIsUserCheckable)
                score_box.setFlags(empty_item.flags() & ~QtCore.Qt.ItemIsSelectable)
        elif 'total' in applied_scores:
            self.model.appliedScores = ('total',)
            # if total is selected, disable all other scores
            for score, score_box in self.score_map.items():
                if score != 'total':
                    score_box.setFlags(QtCore.Qt.ItemIsUserCheckable)
                    score_box.setToolTip("De-select 'total' to enable other scores")
        else:
            # get units of applied scores
            selected_units = _SCORE_UNITS.get(applied_scores[0], _REACTION_UNITS)
            # disable scores with incompatible units
            for score, score_box in self.score_map.items():
                sunits = _SCORE_UNITS.get(score, _REACTION_UNITS)
                if sunits != selected_units:
                    score_box.setFlags(QtCore.Qt.ItemIsUserCheckable)
                    score_box.setToolTip("Score is incompatible with currently selected scores")
                else:
                    score_box.setFlags(score_box.flags() | QtCore.Qt.ItemIsUserCheckable)
                    score_box.setFlags(score_box.flags() & ~QtCore.Qt.ItemIsSelectable)

    def updateNuclides(self):
        applied_nuclides = []
        for nuclide, nuclide_box in self.nuclide_map.items():
            if nuclide_box.checkState() == QtCore.Qt.CheckState.Checked:
                applied_nuclides.append(nuclide)
        self.model.appliedNuclides = tuple(applied_nuclides)

        if 'total' in applied_nuclides:
            self.model.appliedNuclides = ['total',]
            for nuclide, nuclide_box in self.nuclide_map.items():
                if nuclide != 'total':
                    nuclide_box.setFlags(QtCore.Qt.ItemIsUserCheckable)
                    nuclide_box.setToolTip("De-select 'total' to enable other nuclides")
        elif not applied_nuclides:
            # if no nuclides are selected, enable all nuclides again
            for nuclide, nuclide_box in self.nuclide_map.items():
                empty_item = QListWidgetItem()
                nuclide_box.setFlags(empty_item.flags() | QtCore.Qt.ItemIsUserCheckable)
                nuclide_box.setFlags(empty_item.flags() & ~QtCore.Qt.ItemIsSelectable)

    def update(self):

        # update the color form
        self.tallyColorForm.update()

        if self.model.statepoint:
            self.tallySelector.clear()
            self.tallySelector.setEnabled(True)
            self.tallySelector.addItem("None")
            for idx, tally in enumerate(self.model.statepoint.tallies.values()):
                if tally.name == "":
                    self.tallySelector.addItem('Tally {}'.format(tally.id), userData=tally.id)
                else:
                    self.tallySelector.addItem('Tally {} "{}"'.format(tally.id, tally.name), userData=tally.id)
                self.tally_map[idx] = tally
            self.updateSelectedTally()
            self.updateMinMax()
        else:
            self.tallySelector.clear()
            self.tallySelector.setDisabled(True)
Exemplo n.º 9
0
class ColorForm(QWidget):
    """
    Class for handling a field with a colormap, alpha, and visibility

    Attributes
    ----------

    model : PlotModel
        The model instance used when updating information on the form.
    colormapBox : QComboBox
        Holds the string of the matplotlib colorbar being used
    visibilityBox : QCheckBox
        Indicator for whether or not the field should be visible
    alphaBox : QDoubleSpinBox
        Holds the alpha value for the displayed field data
    colormapBox : QComboBox
        Selector for colormap
    dataIndicatorCheckBox : QCheckBox
        Inidcates whether or not the data indicator will appear on the colorbar
    userMinMaxBox : QCheckBox
        Indicates whether or not the user defined values in the min and max
        will be used to set the bounds of the colorbar.
    maxBox : ScientificDoubleSpinBox
        Max value of the colorbar. If the userMinMaxBox is checked, this will be
        the user's input. If the userMinMaxBox is not checked, this box will
        hold the max value of the visible data.
    minBox : ScientificDoubleSpinBox
        Min value of the colorbar. If the userMinMaxBox is checked, this will be
        the user's input. If the userMinMaxBox is not checked, this box will
        hold the max value of the visible data.
    scaleBox : QCheckBox
        Indicates whether or not the data is displayed on a log or linear
        scale
    maskZeroBox : QCheckBox
        Indicates whether or not values equal to zero are displayed
    clipDataBox : QCheckBox
        Indicates whether or not values outside the min/max are displayed
    contoursBox :  QCheckBox
        Inidicates whether or not data is displayed as contours
    contourLevelsLine : QLineEdit
        Controls the contours of the data. If this line contains a single
        integer, that number of levels is used to display the data. If a
        comma-separated set of values is entered, those values will be used as
        levels in the contour plot.
    """
    def __init__(self, model, main_window, field, colormaps=None):
        super().__init__()

        self.model = model
        self.main_window = main_window
        self.field = field

        self.layout = QFormLayout()

        # Visibility check box
        self.visibilityBox = QCheckBox()
        visible_connector = partial(main_window.toggleTallyVisibility)
        self.visibilityBox.stateChanged.connect(visible_connector)

        # Alpha value
        self.alphaBox = QDoubleSpinBox()
        self.alphaBox.setDecimals(2)
        self.alphaBox.setRange(0, 1)
        self.alphaBox.setSingleStep(0.05)
        alpha_connector = partial(main_window.editTallyAlpha)
        self.alphaBox.valueChanged.connect(alpha_connector)

        # Color map selector
        self.colormapBox = QComboBox()
        if colormaps is None:
            colormaps = sorted(m for m in mcolormaps.datad if not m.endswith("_r"))
        for colormap in colormaps:
            self.colormapBox.addItem(colormap)
        cmap_connector = partial(main_window.editTallyDataColormap)
        self.colormapBox.currentTextChanged[str].connect(cmap_connector)

        # Data indicator line check box
        self.dataIndicatorCheckBox = QCheckBox()
        data_indicator_connector = partial(main_window.toggleTallyDataIndicator)
        self.dataIndicatorCheckBox.stateChanged.connect(data_indicator_connector)

        # User specified min/max check box
        self.userMinMaxBox = QCheckBox()
        minmax_connector = partial(main_window.toggleTallyDataUserMinMax)
        self.userMinMaxBox.stateChanged.connect(minmax_connector)

        # Data min spin box
        self.minBox = ScientificDoubleSpinBox()
        self.minBox.setMinimum(0.0)
        min_connector = partial(main_window.editTallyDataMin)
        self.minBox.valueChanged.connect(min_connector)

        # Data max spin box
        self.maxBox = ScientificDoubleSpinBox()
        self.maxBox.setMinimum(0.0)
        max_connector = partial(main_window.editTallyDataMax)
        self.maxBox.valueChanged.connect(max_connector)

        # Linear/Log scaling check box
        self.scaleBox = QCheckBox()
        scale_connector = partial(main_window.toggleTallyLogScale)
        self.scaleBox.stateChanged.connect(scale_connector)

        # Masking of zero values check box
        self.maskZeroBox = QCheckBox()
        zero_connector = partial(main_window.toggleTallyMaskZero)
        self.maskZeroBox.stateChanged.connect(zero_connector)

        # Clip data to min/max check box
        self.clipDataBox = QCheckBox()
        clip_connector = partial(main_window.toggleTallyDataClip)
        self.clipDataBox.stateChanged.connect(clip_connector)

        # Display data as contour plot check box
        self.contoursBox = QCheckBox()
        self.contoursBox.stateChanged.connect(main_window.toggleTallyContours)
        self.contourLevelsLine = QLineEdit()
        self.contourLevelsLine.textChanged.connect(
            main_window.editTallyContourLevels)

        # Organize widgets on layout
        self.layout.addRow("Visible:", self.visibilityBox)
        self.layout.addRow("Alpha: ", self.alphaBox)
        self.layout.addRow("Colormap: ", self.colormapBox)
        self.layout.addRow("Data Indicator: ", self.dataIndicatorCheckBox)
        self.layout.addRow("Custom Min/Max: ", self.userMinMaxBox)
        self.layout.addRow("Min: ", self.minBox)
        self.layout.addRow("Max: ", self.maxBox)
        self.layout.addRow("Log Scale: ", self.scaleBox)
        self.layout.addRow("Clip Data: ", self.clipDataBox)
        self.layout.addRow("Mask Zeros: ", self.maskZeroBox)
        self.layout.addRow("Contours: ", self.contoursBox)
        self.layout.addRow("Contour Levels:", self.contourLevelsLine)
        self.setLayout(self.layout)

    def updateTallyContours(self):
        cv = self.model.currentView
        self.contoursBox.setChecked(cv.tallyContours)
        self.contourLevelsLine.setText(cv.tallyContourLevels)

    def updateDataIndicator(self):
        cv = self.model.currentView
        self.dataIndicatorCheckBox.setChecked(cv.tallyDataIndicator)

    def setMinMaxEnabled(self, enable):
        enable = bool(enable)
        self.minBox.setEnabled(enable)
        self.maxBox.setEnabled(enable)

    def updateMinMax(self):
        cv = self.model.currentView
        self.minBox.setValue(cv.tallyDataMin)
        self.maxBox.setValue(cv.tallyDataMax)
        self.setMinMaxEnabled(cv.tallyDataUserMinMax)

    def updateTallyVisibility(self):
        cv = self.model.currentView
        self.visibilityBox.setChecked(cv.tallyDataVisible)

    def updateMaskZeros(self):
        cv = self.model.currentView
        self.maskZeroBox.setChecked(cv.tallyMaskZeroValues)

    def updateDataClip(self):
        cv = self.model.currentView
        self.clipDataBox.setChecked(cv.clipTallyData)

    def update(self):
        cv = self.model.currentView

        # set colormap value in selector
        cmap = cv.tallyDataColormap
        idx = self.colormapBox.findText(cmap, QtCore.Qt.MatchFixedString)
        self.colormapBox.setCurrentIndex(idx)

        self.alphaBox.setValue(cv.tallyDataAlpha)
        self.visibilityBox.setChecked(cv.tallyDataVisible)
        self.userMinMaxBox.setChecked(cv.tallyDataUserMinMax)
        self.scaleBox.setChecked(cv.tallyDataLogScale)

        self.updateMinMax()
        self.updateMaskZeros()
        self.updateDataClip()
        self.updateDataIndicator()
        self.updateTallyContours()
Exemplo n.º 10
0
class FontsTab(QWidget):
    def __init__(self, parent_dialog, parent):
        """Initialize the fonts tab
        """

        super(FontsTab, self).__init__(parent_dialog)

        self.prefs = parent_dialog.prefs
        self.parent = parent

        # Base application font code
        app = QApplication.instance()
        self.font_base = app.font()
        font_label_base = QLabel("Base Application Font:")
        self.font_combo_base = QFontComboBox()
        self.font_combo_base.setMaximumWidth(175)
        self.font_combo_base.setCurrentFont(self.font_base.family())
        self.font_combo_base.currentFontChanged.connect(self.update)
        self.font_size_combo_base = QComboBox()
        points_base = self.font_points(self.font_base)
        self.font_size_combo_base.addItems(points_base)
        self.font_size_combo_base.setMaximumWidth(50)
        self.font_size_combo_base.setCurrentIndex(self.font_size_combo_base.findText(str(self.font_base.pointSize())))
        self.font_size_combo_base.currentIndexChanged.connect(self.update)
        base_layout = QHBoxLayout()
        base_layout.addWidget(font_label_base)
        base_layout.addWidget(self.font_combo_base)
        base_layout.addWidget(self.font_size_combo_base)

        # Class Tree font code
        self.font_classTree = self.parent.classTree.font()
        font_label_classTree = QLabel("Class Tree Font:")
        self.font_combo_classTree = QFontComboBox()
        self.font_combo_classTree.setMaximumWidth(175)
        self.font_combo_classTree.setCurrentFont(self.font_classTree.family())
        self.font_combo_classTree.currentFontChanged.connect(self.update)
        self.font_size_combo_classTree = QComboBox()
        points_classTree = self.font_points(self.font_classTree)
        self.font_size_combo_classTree.addItems(points_classTree)
        self.font_size_combo_classTree.setMaximumWidth(50)
        self.font_size_combo_classTree.setCurrentIndex(self.font_size_combo_classTree.findText(str(self.font_classTree.pointSize())))
        self.font_size_combo_classTree.currentIndexChanged.connect(self.update)
        classTree_layout = QHBoxLayout()
        classTree_layout.addWidget(font_label_classTree)
        classTree_layout.addWidget(self.font_combo_classTree)
        classTree_layout.addWidget(self.font_size_combo_classTree)

        # Class Table font code
        self.font_classTable = self.parent.classTable.font()
        font_label_classTable = QLabel("Class Table Font:")
        self.font_combo_classTable = QFontComboBox()
        self.font_combo_classTable.setMaximumWidth(175)
        self.font_combo_classTable.setCurrentFont(self.font_classTable.family())
        self.font_combo_classTable.currentFontChanged.connect(self.update)
        self.font_size_combo_classTable = QComboBox()
        points_classTable = self.font_points(self.font_classTable)
        self.font_size_combo_classTable.addItems(points_classTable)
        self.font_size_combo_classTable.setMaximumWidth(50)
        self.font_size_combo_classTable.setCurrentIndex(self.font_size_combo_classTable.findText(str(self.font_classTable.pointSize())))
        self.font_size_combo_classTable.currentIndexChanged.connect(self.update)
        classTable_layout = QHBoxLayout()
        classTable_layout.addWidget(font_label_classTable)
        classTable_layout.addWidget(self.font_combo_classTable)
        classTable_layout.addWidget(self.font_size_combo_classTable)

        # Comments view font code
        self.font_comments = self.parent.commentView.font()
        font_label_comments = QLabel("Comments Font:")
        self.font_combo_comments = QFontComboBox()
        self.font_combo_comments.setMaximumWidth(175)
        self.font_combo_comments.setCurrentFont(self.font_comments.family())
        self.font_combo_comments.currentFontChanged.connect(self.update)
        self.font_size_combo_comments = QComboBox()
        points_comments = self.font_points(self.font_comments)
        self.font_size_combo_comments.addItems(points_comments)
        self.font_size_combo_comments.setMaximumWidth(50)
        self.font_size_combo_comments.setCurrentIndex(self.font_size_combo_comments.findText(str(self.font_comments.pointSize())))
        self.font_size_combo_comments.currentIndexChanged.connect(self.update)
        comments_layout = QHBoxLayout()
        comments_layout.addWidget(font_label_comments)
        comments_layout.addWidget(self.font_combo_comments)
        comments_layout.addWidget(self.font_size_combo_comments)

        # Main layout code
        mainLayout = QVBoxLayout()
        mainLayout.addLayout(base_layout)
        mainLayout.addSpacing(10)
        mainLayout.addLayout(classTree_layout)
        mainLayout.addSpacing(10)
        mainLayout.addLayout(classTable_layout)
        mainLayout.addSpacing(10)
        mainLayout.addLayout(comments_layout)
        mainLayout.addStretch(1)
        self.setLayout(mainLayout)

    def update(self):
        self.font_base.setFamily(self.font_combo_base.currentFont().family())
        self.font_base.setPointSize(int(self.font_size_combo_base.currentText()))
        self.font_classTree.setFamily(self.font_combo_classTree.currentFont().family())
        self.font_classTree.setPointSize(int(self.font_size_combo_classTree.currentText()))
        self.font_classTable.setFamily(self.font_combo_classTable.currentFont().family())
        self.font_classTable.setPointSize(int(self.font_size_combo_classTable.currentText()))
        self.font_comments.setFamily(self.font_combo_comments.currentFont().family())
        self.font_comments.setPointSize(int(self.font_size_combo_comments.currentText()))
        self.prefs['base_font'] = self.font_base.toString()
        self.prefs['class_tree_font'] = self.font_classTree.toString()
        self.prefs['class_table_font'] = self.font_classTable.toString()
        self.prefs['comments_font'] = self.font_comments.toString()
        # self.prefs['log_font'] = self.font_base.toString()
        # self.prefs['ref_font'] = self.font_base.toString()
        # self.prefs['info_font'] = self.font_base.toString()
        # self.prefs['undo_font'] = self.font_base.toString()

    def font_points(self, font):
        points = [str(p) for p in QFontDatabase().pointSizes(font.family())]
        if not points:
            points = [str(p) for p in QFontDatabase().standardSizes()]
        return points
Exemplo n.º 11
0
class TabDisplays(QTabWidget):
    def __init__(self, parent=None):
        super(TabDisplays, self).__init__(parent)

        # Initialize logging
        logging_conf_file = os.path.join(os.path.dirname(__file__),
                                         'cfg/aecgviewer_aecg_logging.conf')
        logging.config.fileConfig(logging_conf_file)
        self.logger = logging.getLogger(__name__)

        self.studyindex_info = aecg.tools.indexer.StudyInfo()

        self.validator = QWidget()

        self.studyinfo = QWidget()

        self.statistics = QWidget()

        self.waveforms = QWidget()

        self.waveforms.setAccessibleName("Waveforms")

        self.scatterplot = QWidget()

        self.histogram = QWidget()

        self.trends = QWidget()

        self.xmlviewer = QWidget()
        self.xml_display = QTextEdit(self.xmlviewer)

        self.options = QWidget()

        self.aecg_display_area = QScrollArea()
        self.cbECGLayout = QComboBox()
        self.aecg_display = EcgDisplayWidget(self.aecg_display_area)
        self.aecg_display_area.setWidget(self.aecg_display)

        self.addTab(self.validator, "Study information")
        self.addTab(self.waveforms, "Waveforms")
        self.addTab(self.xmlviewer, "XML")
        self.addTab(self.options, "Options")

        self.setup_validator()
        self.setup_waveforms()
        self.setup_xmlviewer()
        self.setup_options()

        size = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        size.setHeightForWidth(False)
        self.setSizePolicy(size)

        # Initialized a threpool with 2 threads 1 for the GUI, 1 for long
        # tasks, so GUI remains responsive
        self.threadpool = QThreadPool()
        self.threadpool.setMaxThreadCount(2)
        self.validator_worker = None
        self.indexing_timer = QElapsedTimer()

    def setup_validator(self):
        self.directory_indexer = None  # aecg.indexing.DirectoryIndexer()
        self.validator_layout_container = QWidget()
        self.validator_layout = QFormLayout()
        self.validator_form_layout = QFormLayout(
            self.validator_layout_container)
        self.validator_grid_layout = QGridLayout()
        self.study_info_file = QLineEdit()
        self.study_info_file.setToolTip("Study index file")
        self.study_info_description = QLineEdit()
        self.study_info_description.setToolTip("Description")
        self.app_type = QLineEdit()
        self.app_type.setToolTip("Application type (e.g., NDA, IND, BLA, IDE)")
        self.app_num = QLineEdit()
        self.app_num.setToolTip("Six-digit application number")
        self.app_num.setValidator(QIntValidator(self.app_num))
        self.study_id = QLineEdit()
        self.study_id.setToolTip("Study identifier")
        self.study_sponsor = QLineEdit()
        self.study_sponsor.setToolTip("Sponsor of the study")

        self.study_annotation_aecg_cb = QComboBox()
        self.study_annotation_aecg_cb.addItems(
            ["Rhythm", "Derived beat", "Holter-rhythm", "Holter-derived"])
        self.study_annotation_aecg_cb.setToolTip(
            "Waveforms used to perform the ECG measurements (i.e., "
            "annotations)\n"
            "\tRhythm: annotations in a rhythm strip or discrete ECG "
            "extraction (e.g., 10-s strips)\n"
            "\tDerived beat: annotations in a representative beat derived "
            "from a rhythm strip\n"
            "\tHolter-rhythm: annotations in a the analysis window of a "
            "continuous recording\n"
            "\tHolter-derived: annotations in a representative beat derived "
            "from analysis window of a continuous recording\n")
        self.study_annotation_lead_cb = QComboBox()
        self.ui_leads = ["GLOBAL"] + aecg.STD_LEADS[0:12] +\
            [aecg.KNOWN_NON_STD_LEADS[1]] + aecg.STD_LEADS[12:15] + ["Other"]
        self.study_annotation_lead_cb.addItems(self.ui_leads)
        self.study_annotation_lead_cb.setToolTip(
            "Primary analysis lead annotated per protocol. There could be "
            "annotations in other leads also, but only the primary lead should"
            " be selected here.\n"
            "Select global if all leads were used at the "
            "same time (e.g., superimposed on screen).\n"
            "Select other if the primary lead used is not in the list.")

        self.study_numsubjects = QLineEdit()
        self.study_numsubjects.setToolTip(
            "Number of subjects with ECGs in the study")
        self.study_numsubjects.setValidator(
            QIntValidator(self.study_numsubjects))

        self.study_aecgpersubject = QLineEdit()
        self.study_aecgpersubject.setToolTip(
            "Number of scheduled ECGs (or analysis windows) per subject as "
            "specified in the study protocol.\n"
            "Enter average number of ECGs "
            "per subject if the protocol does not specify a fixed number of "
            "ECGs per subject.")
        self.study_aecgpersubject.setValidator(
            QIntValidator(self.study_aecgpersubject))

        self.study_numaecg = QLineEdit()
        self.study_numaecg.setToolTip(
            "Total number of aECG XML files in the study")
        self.study_numaecg.setValidator(QIntValidator(self.study_numaecg))

        self.study_annotation_numbeats = QLineEdit()
        self.study_annotation_numbeats.setToolTip(
            "Minimum number of beats annotated in each ECG or analysis window"
            ".\nEnter 1 if annotations were done in the derived beat.")
        self.study_annotation_numbeats.setValidator(
            QIntValidator(self.study_annotation_numbeats))

        self.aecg_numsubjects = QLineEdit()
        self.aecg_numsubjects.setToolTip(
            "Number of subjects found across the provided aECG XML files")
        self.aecg_numsubjects.setReadOnly(True)

        self.aecg_aecgpersubject = QLineEdit()
        self.aecg_aecgpersubject.setToolTip(
            "Average number of ECGs per subject found across the provided "
            "aECG XML files")
        self.aecg_aecgpersubject.setReadOnly(True)

        self.aecg_numaecg = QLineEdit()
        self.aecg_numaecg.setToolTip(
            "Number of aECG XML files found in the study aECG directory")
        self.aecg_numaecg.setReadOnly(True)

        self.subjects_less_aecgs = QLineEdit()
        self.subjects_less_aecgs.setToolTip(
            "Percentage of subjects with less aECGs than specified per "
            "protocol")
        self.subjects_less_aecgs.setReadOnly(True)

        self.subjects_more_aecgs = QLineEdit()
        self.subjects_more_aecgs.setToolTip(
            "Percentage of subjects with more aECGs than specified per "
            "protocol")
        self.subjects_more_aecgs.setReadOnly(True)

        self.aecgs_no_annotations = QLineEdit()
        self.aecgs_no_annotations.setToolTip(
            "Percentage of aECGs with no annotations")
        self.aecgs_no_annotations.setReadOnly(True)

        self.aecgs_less_qt_in_primary_lead = QLineEdit()
        self.aecgs_less_qt_in_primary_lead.setToolTip(
            "Percentage of aECGs with less QT intervals in the primary lead "
            "than specified per protocol")
        self.aecgs_less_qt_in_primary_lead.setReadOnly(True)

        self.aecgs_less_qts = QLineEdit()
        self.aecgs_less_qts.setToolTip(
            "Percentage of aECGs with less QT intervals than specified per "
            "protocol")
        self.aecgs_less_qts.setReadOnly(True)

        self.aecgs_annotations_multiple_leads = QLineEdit()
        self.aecgs_annotations_multiple_leads.setToolTip(
            "Percentage of aECGs with QT annotations in multiple leads")
        self.aecgs_annotations_multiple_leads.setReadOnly(True)

        self.aecgs_annotations_no_primary_lead = QLineEdit()
        self.aecgs_annotations_no_primary_lead.setToolTip(
            "Percentage of aECGs with QT annotations not in the primary lead")
        self.aecgs_annotations_no_primary_lead.setReadOnly(True)

        self.aecgs_with_errors = QLineEdit()
        self.aecgs_with_errors.setToolTip("Number of aECG files with errors")
        self.aecgs_with_errors.setReadOnly(True)

        self.aecgs_potentially_digitized = QLineEdit()
        self.aecgs_potentially_digitized.setToolTip(
            "Number of aECG files potentially digitized (i.e., with more than "
            "5% of samples missing)")
        self.aecgs_potentially_digitized.setReadOnly(True)

        self.study_dir = QLineEdit()
        self.study_dir.setToolTip("Directory containing the aECG files")
        self.study_dir_button = QPushButton("...")
        self.study_dir_button.clicked.connect(self.select_study_dir)
        self.study_dir_button.setToolTip("Open select directory dialog")

        self.validator_form_layout.addRow("Application Type", self.app_type)
        self.validator_form_layout.addRow("Application Number", self.app_num)
        self.validator_form_layout.addRow("Study name/ID", self.study_id)
        self.validator_form_layout.addRow("Sponsor", self.study_sponsor)
        self.validator_form_layout.addRow("Study description",
                                          self.study_info_description)

        self.validator_form_layout.addRow("Annotations in",
                                          self.study_annotation_aecg_cb)
        self.validator_form_layout.addRow("Annotations primary lead",
                                          self.study_annotation_lead_cb)

        self.validator_grid_layout.addWidget(QLabel(""), 0, 0)
        self.validator_grid_layout.addWidget(
            QLabel("Per study protocol or report"), 0, 1)
        self.validator_grid_layout.addWidget(QLabel("Found in aECG files"), 0,
                                             2)

        self.validator_grid_layout.addWidget(QLabel("Number of subjects"), 1,
                                             0)
        self.validator_grid_layout.addWidget(self.study_numsubjects, 1, 1)
        self.validator_grid_layout.addWidget(self.aecg_numsubjects, 1, 2)

        self.validator_grid_layout.addWidget(
            QLabel("Number of aECG per subject"), 2, 0)
        self.validator_grid_layout.addWidget(self.study_aecgpersubject, 2, 1)
        self.validator_grid_layout.addWidget(self.aecg_aecgpersubject, 2, 2)

        self.validator_grid_layout.addWidget(QLabel("Total number of aECG"), 3,
                                             0)
        self.validator_grid_layout.addWidget(self.study_numaecg, 3, 1)
        self.validator_grid_layout.addWidget(self.aecg_numaecg, 3, 2)

        self.validator_grid_layout.addWidget(
            QLabel("Number of beats per aECG"), 4, 0)
        self.validator_grid_layout.addWidget(self.study_annotation_numbeats, 4,
                                             1)

        self.validator_grid_layout.addWidget(
            QLabel("Subjects with fewer ECGs"), 5, 1)
        self.validator_grid_layout.addWidget(self.subjects_less_aecgs, 5, 2)
        self.validator_grid_layout.addWidget(QLabel("Subjects with more ECGs"),
                                             6, 1)
        self.validator_grid_layout.addWidget(self.subjects_more_aecgs, 6, 2)
        self.validator_grid_layout.addWidget(
            QLabel("aECGs without annotations"), 7, 1)
        self.validator_grid_layout.addWidget(self.aecgs_no_annotations, 7, 2)
        self.validator_grid_layout.addWidget(
            QLabel("aECGs without expected number of QTs in primary lead"), 8,
            1)
        self.validator_grid_layout.addWidget(
            self.aecgs_less_qt_in_primary_lead, 8, 2)
        self.validator_grid_layout.addWidget(
            QLabel("aECGs without expected number of QTs"), 9, 1)
        self.validator_grid_layout.addWidget(self.aecgs_less_qts, 9, 2)

        self.validator_grid_layout.addWidget(
            QLabel("aECGs annotated in multiple leads"), 10, 1)
        self.validator_grid_layout.addWidget(
            self.aecgs_annotations_multiple_leads, 10, 2)
        self.validator_grid_layout.addWidget(
            QLabel("aECGs with annotations not in primary lead"), 11, 1)
        self.validator_grid_layout.addWidget(
            self.aecgs_annotations_no_primary_lead, 11, 2)
        self.validator_grid_layout.addWidget(QLabel("aECGs with errors"), 12,
                                             1)
        self.validator_grid_layout.addWidget(self.aecgs_with_errors, 12, 2)

        self.validator_grid_layout.addWidget(
            QLabel("Potentially digitized aECGs"), 13, 1)
        self.validator_grid_layout.addWidget(self.aecgs_potentially_digitized,
                                             13, 2)

        self.validator_form_layout.addRow(self.validator_grid_layout)

        tmp = QHBoxLayout()
        tmp.addWidget(self.study_dir)
        tmp.addWidget(self.study_dir_button)
        self.validator_form_layout.addRow("Study aECGs directory", tmp)

        self.validator_form_layout.addRow("Study index file",
                                          self.study_info_file)

        self.validator_layout.addWidget(self.validator_layout_container)
        self.validator_effective_dirs = QLabel("")
        self.validator_effective_dirs.setWordWrap(True)
        self.validator_layout.addWidget(self.validator_effective_dirs)

        self.val_button = QPushButton("Generate/update study index")
        self.val_button.clicked.connect(self.importstudy_dialog)
        self.validator_layout.addWidget(self.val_button)
        self.cancel_val_button = QPushButton("Cancel study index generation")
        self.cancel_val_button.clicked.connect(self.cancel_validator)
        self.cancel_val_button.setEnabled(False)
        self.validator_layout.addWidget(self.cancel_val_button)
        self.validator_pl = QLabel("")
        self.validator_layout.addWidget(self.validator_pl)
        self.validator_pb = QProgressBar()
        self.validator_layout.addWidget(self.validator_pb)
        self.validator.setLayout(self.validator_layout)
        self.stop_indexing = False

        self.lastindexing_starttime = None

        self.update_validator_effective_dirs()

    def effective_aecgs_dir(self, navwidget, silent=False):
        aecgs_effective_dir = self.study_dir.text()
        if navwidget.project_loaded != '':
            # Path specified in the GUI
            potential_aecgs_dirs = [self.study_dir.text()]
            # StudyDir path from current working directory
            potential_aecgs_dirs += [self.studyindex_info.StudyDir]
            # StudyDir path from directory where the index is located
            potential_aecgs_dirs += [
                os.path.join(os.path.dirname(navwidget.project_loaded),
                             self.studyindex_info.StudyDir)
            ]
            # StudyDir replaced with the directory where the index is located
            potential_aecgs_dirs += [os.path.dirname(navwidget.project_loaded)]
            dir_found = False
            # Get xml and zip filenames from first element in the index
            aecg_xml_file = navwidget.data_index["AECGXML"][0]
            zipfile = ""
            if aecg_xml_file != "":
                zipfile = navwidget.data_index["ZIPFILE"][0]
            for p in potential_aecgs_dirs:
                testfn = os.path.join(p, aecg_xml_file)
                if zipfile != "":
                    testfn = os.path.join(p, zipfile)
                if os.path.isfile(testfn):
                    dir_found = True
                    aecgs_effective_dir = p
                    break
            if not silent:
                if not dir_found:
                    QMessageBox.warning(
                        self, f"Study aECGs directory not found",
                        f"The following paths were checked:"
                        f"{[','.join(p) for p in potential_aecgs_dirs]} and "
                        f"none of them is valid")
                elif p != self.study_dir.text():
                    QMessageBox.warning(
                        self, f"Study aECGs directory not found",
                        f"The path specified in the study aECGs directory is "
                        f"not valid and {p} is being used instead. Check and "
                        f"update the path in Study aECGs directory textbox if "
                        f"the suggested path is not the adequate path")
        return aecgs_effective_dir

    def update_validator_effective_dirs(self):
        msg = f"Working directory: {os.getcwd()}"
        if self.parent() is not None:
            if isinstance(self.parent(), QSplitter):
                navwidget = self.parent().parent()
            else:  # Tabs widget has not been allocated the QSplitter yet
                navwidget = self.parent()
            project_loaded = navwidget.project_loaded
            if project_loaded != '':
                msg = f"{msg}\nLoaded project index: "\
                      f"{navwidget.project_loaded}"
                effective_aecgs_path = self.effective_aecgs_dir(navwidget)
                msg = f"{msg}\nEffective study aECGs directory: "\
                      f"{effective_aecgs_path}"
            else:
                msg = f"{msg}\nLoaded project index: None"
        else:
            msg = f"{msg}\nLoaded project index: None"
        self.validator_effective_dirs.setText(msg)

    def load_study_info(self, fileName):
        self.study_info_file.setText(fileName)
        try:
            study_info = pd.read_excel(fileName, sheet_name="Info")
            self.studyindex_info = aecg.tools.indexer.StudyInfo()
            self.studyindex_info.__dict__.update(
                study_info.set_index("Property").transpose().reset_index(
                    drop=True).to_dict('index')[0])
            sponsor = ""
            description = ""
            if self.studyindex_info.Sponsor is not None and\
                    isinstance(self.studyindex_info.Sponsor, str):
                sponsor = self.studyindex_info.Sponsor
            if self.studyindex_info.Description is not None and\
                    isinstance(self.studyindex_info.Description, str):
                description = self.studyindex_info.Description
            self.study_sponsor.setText(sponsor)
            self.study_info_description.setText(description)
            self.app_type.setText(self.studyindex_info.AppType)
            self.app_num.setText(f"{int(self.studyindex_info.AppNum):06d}")
            self.study_id.setText(self.studyindex_info.StudyID)
            self.study_numsubjects.setText(str(self.studyindex_info.NumSubj))
            self.study_aecgpersubject.setText(
                str(self.studyindex_info.NECGSubj))
            self.study_numaecg.setText(str(self.studyindex_info.TotalECGs))

            anns_in = self.studyindex_info.AnMethod.upper()
            idx = 0
            if anns_in == "RHYTHM":
                idx = 0
            elif anns_in == "DERIVED":
                idx = 1
            elif anns_in == "HOLTER_RHYTHM":
                idx = 2
            elif anns_in == "HOLTER_MEDIAN_BEAT":
                idx = 3
            else:
                idx = int(anns_in) - 1
            self.study_annotation_aecg_cb.setCurrentIndex(idx)

            the_lead = self.studyindex_info.AnLead
            idx = self.study_annotation_lead_cb.findText(str(the_lead))
            if idx == -1:
                idx = self.study_annotation_lead_cb.findText("MDC_ECG_LEAD_" +
                                                             str(the_lead))
            if idx == -1:
                idx = int(the_lead)
            self.study_annotation_lead_cb.setCurrentIndex(idx)

            self.study_annotation_numbeats.setText(
                str(self.studyindex_info.AnNbeats))
            if self.studyindex_info.StudyDir == "":
                self.studyindex_info.StudyDir = os.path.dirname(fileName)
            self.study_dir.setText(self.studyindex_info.StudyDir)

            self.update_validator_effective_dirs()
            self.setCurrentWidget(self.validator)

        except Exception as ex:
            QMessageBox.critical(
                self, "Import study error",
                "Error reading the study information file: '" + fileName + "'")

    def setup_waveforms(self):
        wflayout = QVBoxLayout()

        # ECG plot layout selection box
        self.cbECGLayout.addItems(
            ['12-lead stacked', '3x4 + lead II rhythm', 'Superimposed'])
        self.cbECGLayout.currentIndexChanged.connect(
            self.ecgplotlayout_changed)

        # Zoom buttons
        blayout = QHBoxLayout()

        pb_zoomin = QPushButton()
        pb_zoomin.setText("Zoom +")
        pb_zoomin.clicked.connect(self.zoom_in)

        pb_zoomreset = QPushButton()
        pb_zoomreset.setText("Zoom 1:1")
        pb_zoomreset.clicked.connect(self.zoom_reset)

        pb_zoomout = QPushButton()
        pb_zoomout.setText("Zoom -")
        pb_zoomout.clicked.connect(self.zoom_out)

        blayout.addWidget(self.cbECGLayout)
        blayout.addWidget(pb_zoomout)
        blayout.addWidget(pb_zoomreset)
        blayout.addWidget(pb_zoomin)

        wflayout.addLayout(blayout)

        # Add QScrollArea to main layout of waveforms tab
        self.aecg_display_area.setWidgetResizable(False)
        wflayout.addWidget(self.aecg_display_area)
        self.waveforms.setLayout(wflayout)
        size = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        size.setHeightForWidth(False)
        self.aecg_display_area.setSizePolicy(size)
        self.waveforms.setSizePolicy(size)

    def setup_xmlviewer(self):
        wf_layout = QHBoxLayout()
        wf_layout.addWidget(self.xml_display)
        self.xmlviewer.setLayout(wf_layout)

    def setup_options(self):
        self.options_layout = QFormLayout()
        self.aecg_schema_filename = QLineEdit(aecg.get_aecg_schema_location())
        self.options_layout.addRow("aECG XML schema path",
                                   self.aecg_schema_filename)

        self.save_index_every_n_aecgs = QSpinBox()
        self.save_index_every_n_aecgs.setMinimum(0)
        self.save_index_every_n_aecgs.setMaximum(50000)
        self.save_index_every_n_aecgs.setValue(0)
        self.save_index_every_n_aecgs.setSingleStep(100)
        self.save_index_every_n_aecgs.setSuffix(" aECGs")
        self.save_index_every_n_aecgs.setToolTip(
            "Set o 0 to save the study index file only after its generation "
            "is completed.\nOtherwise, the file is saved everytime the "
            " specified number of ECGs have been appended to the index.")
        self.options_layout.addRow("Save index every ",
                                   self.save_index_every_n_aecgs)

        self.save_all_intervals_cb = QCheckBox("")
        self.save_all_intervals_cb.setChecked(False)
        self.options_layout.addRow("Save individual beat intervals",
                                   self.save_all_intervals_cb)

        self.parallel_processing_cb = QCheckBox("")
        self.parallel_processing_cb.setChecked(True)
        self.options_layout.addRow("Parallel processing of files",
                                   self.parallel_processing_cb)

        self.options.setLayout(self.options_layout)

    def zoom_in(self):
        self.aecg_display.apply_zoom(self.aecg_display.zoom_factor + 0.1)

    def zoom_out(self):
        self.aecg_display.apply_zoom(self.aecg_display.zoom_factor - 0.1)

    def zoom_reset(self):
        self.aecg_display.apply_zoom(1.0)

    def ecgplotlayout_changed(self, i):
        self.aecg_display.update_aecg_plot(
            ecg_layout=aecg.utils.ECG_plot_layout(i + 1))

    def update_search_progress(self, i, n):
        self.validator_pl.setText(
            f"Searching aECGs in directory ({n} XML files found)")

    def update_progress(self, i, n):
        j = i
        m = n
        if i <= 1:
            j = 1
            if self.validator_pb.value() > 0:
                j = self.validator_pb.value() + 1
            m = self.validator_pb.maximum()
        running_time = self.indexing_timer.elapsed() * 1e-3  # in seconds
        time_per_item = running_time / j
        # reamining = seconds per item so far * total pending items to process
        remaining_time = time_per_item * (m - j)
        eta = datetime.datetime.now() +\
            datetime.timedelta(seconds=round(remaining_time, 0))
        self.validator_pl.setText(
            f"Validating aECG {j}/{m} | "
            f"Execution time: "
            f"{str(datetime.timedelta(0,seconds=round(running_time)))} | "
            f"{round(1/time_per_item,2)} aECGs per second | "
            f"ETA: {eta.isoformat(timespec='seconds')}")
        self.validator_pb.setValue(j)
        if self.save_index_every_n_aecgs.value() > 0 and\
                len(self.directory_indexer.studyindex) % \
                self.save_index_every_n_aecgs.value() == 0:
            self.save_validator_results(
                pd.concat(self.directory_indexer.studyindex,
                          ignore_index=True))

    def save_validator_results(self, res):
        if res.shape[0] > 0:
            self.studyindex_info = aecg.tools.indexer.StudyInfo()
            self.studyindex_info.StudyDir = self.study_dir.text()
            self.studyindex_info.IndexFile = self.study_info_file.text()
            self.studyindex_info.Sponsor = self.study_sponsor.text()
            self.studyindex_info.Description =\
                self.study_info_description.text()
            self.studyindex_info.Date = self.lastindexing_starttime.isoformat()
            self.studyindex_info.End_date = datetime.datetime.now().isoformat()
            self.studyindex_info.Version = aecg.__version__
            self.studyindex_info.AppType = self.app_type.text()
            self.studyindex_info.AppNum = f"{int(self.app_num.text()):06d}"
            self.studyindex_info.StudyID = self.study_id.text()
            self.studyindex_info.NumSubj = int(self.study_numsubjects.text())
            self.studyindex_info.NECGSubj = int(
                self.study_aecgpersubject.text())
            self.studyindex_info.TotalECGs = int(self.study_numaecg.text())
            anmethod = aecg.tools.indexer.AnnotationMethod(
                self.study_annotation_aecg_cb.currentIndex())
            self.studyindex_info.AnMethod = anmethod.name
            self.studyindex_info.AnLead =\
                self.study_annotation_lead_cb.currentText()
            self.studyindex_info.AnNbeats = int(
                self.study_annotation_numbeats.text())

            # Calculate stats
            study_stats = aecg.tools.indexer.StudyStats(
                self.studyindex_info, res)

            # Save to file
            aecg.tools.indexer.save_study_index(self.studyindex_info, res,
                                                study_stats)

    validator_data_ready = Signal()

    def save_validator_results_and_load_index(self, res):
        self.save_validator_results(res)
        self.validator_data_ready.emit()

    def indexer_validator_results(self, res):
        self.studyindex_df = pd.concat([self.studyindex_df, res],
                                       ignore_index=True)

    def subindex_thread_complete(self):
        return

    def index_directory_thread_complete(self):
        tmp = self.validator_pl.text().replace("ETA:", "Completed: ").replace(
            "Validating", "Validated")
        self.validator_pl.setText(tmp)
        self.val_button.setEnabled(True)
        self.cancel_val_button.setEnabled(False)
        self.validator_layout_container.setEnabled(True)

    def index_directory(self, progress_callback):
        self.lastindexing_starttime = datetime.datetime.now()
        self.indexing_timer.start()

        studyindex_df = []
        n_cores = os.cpu_count()
        aecg_schema = None
        if self.aecg_schema_filename.text() != "":
            aecg_schema = self.aecg_schema_filename.text()
        if self.parallel_processing_cb.isChecked():
            studyindex_df = self.directory_indexer.index_directory(
                self.save_all_intervals_cb.isChecked(), aecg_schema, n_cores,
                progress_callback)
        else:
            studyindex_df = self.directory_indexer.index_directory(
                self.save_all_intervals_cb.isChecked(), aecg_schema, 1,
                progress_callback)

        return studyindex_df

    def importstudy_dialog(self):
        dirName = os.path.normpath(self.study_dir.text())
        if dirName != "":
            if os.path.exists(dirName):
                self.directory_indexer = aecg.indexing.DirectoryIndexer()
                self.directory_indexer.set_aecg_dir(
                    dirName, self.update_search_progress)
                self.validator_pb.setMaximum(self.directory_indexer.num_files)
                self.validator_pb.reset()
                self.stop_indexing = False
                self.validator_layout_container.setEnabled(False)
                self.val_button.setEnabled(False)
                self.cancel_val_button.setEnabled(True)
                self.validator_worker = Worker(self.index_directory)
                self.validator_worker.signals.result.connect(
                    self.save_validator_results_and_load_index)
                self.validator_worker.signals.finished.connect(
                    self.index_directory_thread_complete)
                self.validator_worker.signals.progress.connect(
                    self.update_progress)

                # Execute
                self.threadpool.start(self.validator_worker)
            else:
                QMessageBox.critical(
                    self, "Directory not found",
                    f"Specified study directory not found:\n{dirName}")
        else:
            QMessageBox.critical(self, "Import study error",
                                 "Study directory cannot be empty")

    def cancel_validator(self):
        self.cancel_val_button.setEnabled(False)
        self.stop_indexing = True
        self.directory_indexer.cancel_indexing = True
        self.threadpool.waitForDone(3000)
        self.val_button.setEnabled(True)

    def select_study_dir(self):
        cd = self.study_dir.text()
        if cd == "":
            cd = "."
        dir = QFileDialog.getExistingDirectory(
            self, "Open Directory", cd,
            QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)
        if dir != "":
            self.study_dir.setText(dir)
Exemplo n.º 12
0
class AppearanceTab(QWidget):
    def __init__(self, parent):
        """Initialize the appearance tab
        """

        super(AppearanceTab, self).__init__(parent)

        self.prefs = parent.prefs

        # Default column width code
        col_width_label = QLabel("Default Column Width:")
        self.col_width_edit = QLineEdit(str(self.prefs['default_column_width']))
        self.col_width_edit.setMinimumWidth(40)
        self.col_width_edit.setMaximumWidth(100)
        validator = QIntValidator(10, 200, self)
        self.col_width_edit.setValidator(validator)

        # Visual style code
        style_label = QLabel("Visual Style of Application:")
        self.style_edit = QComboBox(self)
        self.style_edit.addItems(list(QStyleFactory.keys()))
        self.style_edit.setMaximumWidth(200)
        self.style_edit.setCurrentIndex(self.style_edit.findText(self.prefs['style']))

        # Units display code
        units_header_label = QLabel("Units Display:")
        self.header_units_check = QCheckBox('Show Units in Table Headers', self)
        checked_header = Qt.Checked if self.prefs['show_units_in_headers'] == 1 else Qt.Unchecked
        self.header_units_check.setCheckState(checked_header)
        self.cells_units_check = QCheckBox('Show Units in Table Cells', self)
        checked_cells = Qt.Checked if self.prefs['show_units_in_cells'] == 1 else Qt.Unchecked
        self.cells_units_check.setCheckState(checked_cells)

        # Handling of file options code
        default_handling_text = QLabel("Select how options saved directly within an IDF "
                                             "file are treated. See \"Save Options\" tab "
                                             "for the options in question.")
        default_handling_text.setWordWrap(True)
        default_handling_text.setMaximumWidth(450)
        self.button_force = QRadioButton("Force Session Options:", self)
        force_text = QLabel("Options from the current session will be used for all "
                                  "files, ignoring any options saved in the IDF file.")
        force_text.setWordWrap(True)
        force_text.setMaximumWidth(450)
        force_text.setMinimumHeight(30)
        force_text.setIndent(25)
        self.button_obey = QRadioButton("Obey IDF Options if Present:", self)
        obey_text = QLabel("Obey options saved in the IDF file. If none are "
                                 "present, use the current session's options.")
        obey_text.setWordWrap(True)
        obey_text.setMaximumWidth(450)
        obey_text.setMinimumHeight(30)
        obey_text.setIndent(25)

        # Handling of file options group box
        self.behaviour_group_box = QGroupBox("Handling of File-based Options")
        self.behaviour_group_box.setMinimumHeight(220)
        self.behaviour_group_box.setMinimumWidth(450)
        behaviour_box = QVBoxLayout()
        behaviour_box.addWidget(default_handling_text)
        behaviour_box.addWidget(self.button_force)
        behaviour_box.addWidget(force_text)
        behaviour_box.addSpacing(5)
        behaviour_box.addWidget(self.button_obey)
        behaviour_box.addWidget(obey_text)
        behaviour_box.addStretch(1)
        self.behaviour_group_box.setLayout(behaviour_box)

        self.behaviour_button_group = QButtonGroup(self)
        self.behaviour_button_group.addButton(self.button_force)
        self.behaviour_button_group.addButton(self.button_obey)
        self.behaviour_button_group.setId(self.button_force, 0)
        self.behaviour_button_group.setId(self.button_obey, 1)
        self.behaviour_button_group.button(self.prefs['obey_idf_options']).setChecked(True)

        # Main layout code
        mainLayout = QVBoxLayout()
        mainLayout.addWidget(col_width_label)
        mainLayout.addWidget(self.col_width_edit)
        mainLayout.addSpacing(10)
        mainLayout.addWidget(style_label)
        mainLayout.addWidget(self.style_edit)
        mainLayout.addSpacing(10)
        mainLayout.addWidget(self.behaviour_group_box)
        mainLayout.addSpacing(10)
        mainLayout.addWidget(units_header_label)
        mainLayout.addWidget(self.header_units_check)
        mainLayout.addWidget(self.cells_units_check)
        mainLayout.addStretch(1)
        self.setLayout(mainLayout)

        # Update settings
        self.behaviour_button_group.buttonClicked.connect(self.update)
        self.col_width_edit.textChanged.connect(self.update)
        self.style_edit.currentIndexChanged.connect(self.update)
        self.header_units_check.stateChanged.connect(self.update)
        self.cells_units_check.stateChanged.connect(self.update)

    def update(self):
        self.prefs['default_column_width'] = self.col_width_edit.text()
        self.prefs['style'] = self.style_edit.currentText()
        self.prefs['obey_idf_options'] = self.behaviour_button_group.checkedId()
        self.prefs['show_units_in_headers'] = 1 if self.header_units_check.checkState() else 0
        self.prefs['show_units_in_cells'] = 1 if self.cells_units_check.checkState() else 0
Exemplo n.º 13
0
class CamView(AbstractView):
    def __init__(self,
                 name: str = "CAM_NONE",
                 log_handlers: [StreamHandler] = None):
        self._logger = getLogger(__name__)
        if log_handlers:
            for h in log_handlers:
                self._logger.addHandler(h)
        self._logger.debug("Initializing")
        super().__init__(name)
        """ Min size for cam window """
        self._subwindow_height = 222
        self._subwindow_width = 518

        self._initialization_bar_frame = EasyFrame()
        self._initialization_bar_frame.setMouseTracking(True)
        self._initialization_bar_frame.setMaximumHeight(70)
        self._initialization_bar_layout = QVBoxLayout(
            self._initialization_bar_frame)

        self._initialization_bar_label = QLabel(self._initialization_bar_frame)
        self._initialization_bar_label.setMouseTracking(True)
        self._initialization_bar = QProgressBar(self._initialization_bar_frame)
        self._initialization_bar.setMouseTracking(True)
        self._initialization_bar.setMaximumHeight(15)
        self._initialization_bar.setTextVisible(True)
        self._initialization_bar.setAlignment(Qt.AlignHCenter)

        self._initialization_bar_layout.addWidget(
            self._initialization_bar_label)
        self._initialization_bar_layout.addWidget(self._initialization_bar)

        self._cam_settings_frame = EasyFrame()
        self._cam_settings_layout = QGridLayout(self._cam_settings_frame)

        self._resolution_selector_label = QLabel(self._cam_settings_frame)
        self._resolution_selector_label.setAlignment(Qt.AlignLeft)

        self._resolution_selector = QComboBox(self._cam_settings_frame)
        self._resolution_selector.setMaximumHeight(22)

        self._cam_settings_layout.addWidget(self._resolution_selector_label, 0,
                                            0)
        self._cam_settings_layout.addWidget(self._resolution_selector, 0, 1)

        self._fps_selector_label = QLabel(self._cam_settings_frame)
        self._fps_selector_label.setAlignment(Qt.AlignLeft)

        self._fps_selector = QComboBox(self._cam_settings_frame)
        self._fps_selector.setMaximumHeight(22)

        self._cam_settings_layout.addWidget(self._fps_selector_label, 1, 0)
        self._cam_settings_layout.addWidget(self._fps_selector, 1, 1)

        self._show_feed_checkbox_label = QLabel(self._cam_settings_frame)
        self._show_feed_checkbox_label.setAlignment(Qt.AlignLeft)

        self._show_feed_checkbox = QCheckBox()
        self._show_feed_checkbox.setChecked(True)
        self._show_feed_checkbox.setLayoutDirection(Qt.RightToLeft)

        self._cam_settings_layout.addWidget(self._show_feed_checkbox_label, 2,
                                            0)
        self._cam_settings_layout.addWidget(self._show_feed_checkbox, 2, 1)

        self._use_cam_checkbox_label = QLabel(self._cam_settings_frame)
        self._use_cam_checkbox_label.setAlignment(Qt.AlignLeft)

        self._use_cam_checkbox = QCheckBox()
        self._use_cam_checkbox.setChecked(True)
        self._use_cam_checkbox.setLayoutDirection(Qt.RightToLeft)

        self._cam_settings_layout.addWidget(self._use_cam_checkbox_label, 3, 0)
        self._cam_settings_layout.addWidget(self._use_cam_checkbox, 3, 1)

        self._use_overlay_checkbox_label = QLabel(self._cam_settings_frame)
        self._use_overlay_checkbox_label.setAlignment(Qt.AlignLeft)

        self._use_overlay_checkbox = QCheckBox()
        self._use_overlay_checkbox.setChecked(True)
        self._use_overlay_checkbox.setLayoutDirection(Qt.RightToLeft)

        self._cam_settings_layout.addWidget(self._use_overlay_checkbox_label,
                                            4, 0)
        self._cam_settings_layout.addWidget(self._use_overlay_checkbox, 4, 1)

        self._image_display_frame = EasyFrame()
        self._image_display_layout = QVBoxLayout(self._image_display_frame)

        self._image_display_label = QLabel(self._image_display_frame)
        self._image_display_label.setAlignment(Qt.AlignHCenter)
        self._image_display = QLabel(self._image_display_frame)
        self._image_display.setAlignment(Qt.AlignCenter)
        self._image_display.setMouseTracking(True)
        self._image_display_layout.addWidget(self._image_display_label)
        self._image_display_layout.addWidget(self._image_display)

        spacer = QSpacerItem(1, 1, vData=QSizePolicy.Expanding)

        self._dev_sets_frame = EasyFrame()
        self._dev_sets_layout = QVBoxLayout(self._dev_sets_frame)

        self.config_button = ClickAnimationButton()
        self.config_button.clicked.connect(self._config_button_handler)

        self.layout().addWidget(self.config_button, 0, 0,
                                Qt.AlignTop | Qt.AlignRight)
        self.config_button.setFixedSize(30, 25)
        self.config_button.setStyleSheet(
            "background-color: rgba(200, 200, 200, 50%)")

        self._dev_sets_layout.addWidget(self._cam_settings_frame)
        self._dev_sets_layout.addItem(spacer)
        self.layout().addWidget(self._image_display, 0, 0)
        self.layout().addWidget(self._initialization_bar_frame, 0, 0)

        self._config_items = [
            self._resolution_selector,
            self._fps_selector,
            self._use_cam_checkbox,
            self._show_feed_checkbox,
            self._use_overlay_checkbox,
        ]

        config_win_w = 350
        config_win_h = len(self._config_items) * 30

        self.config_button.raise_()

        self._config_win = ConfigPopUp()
        self._config_win.setLayout(self._dev_sets_layout)
        self._config_win.setFixedSize(config_win_w, config_win_h)

        self._rec_label = QLabel()
        self._rec_label.setStyleSheet(
            "background-color: rgba(0, 0, 0, 0%); color: red; font: 20px")
        self._rec_label.hide()

        self.layout().addWidget(self._rec_label, 0, 0,
                                Qt.AlignBottom | Qt.AlignRight)

        self.layout().setMargin(0)

        self._window_changing = False
        self._showing_images = False
        self._hidden = False
        w = 320
        self._aspect_ratio = 9 / 16
        self.resize(w, self.heightForWidth(w))
        self._strings = dict()
        self._lang_enum = LangEnum.ENG
        self.setMinimumSize(self._subwindow_width, self._subwindow_height)
        self.old_size = QSize(self.width(), self.height())

        self._logger.debug("Initialized")

    def set_show_feed_button_handler(self, func) -> None:
        """
        Add handler for show camera selector.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._show_feed_checkbox.toggled.connect(func)
        self._logger.debug("done")

    def set_resolution_selector_handler(self, func) -> None:
        """
        Add handler for resolution selector.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._resolution_selector.activated.connect(func)
        self._logger.debug("done")

    def set_fps_selector_handler(self, func) -> None:
        """
        Add handler for resolution selector.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._fps_selector.activated.connect(func)
        self._logger.debug("done")

    def set_use_cam_button_handler(self, func) -> None:
        """
        Add handler for use camera selector.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._use_cam_checkbox.toggled.connect(func)
        self._logger.debug("done")

    def set_use_overlay_button_handler(self, func) -> None:
        """
        Add handler for use camera selector.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._use_overlay_checkbox.toggled.connect(func)
        self._logger.debug("done")

    def _config_button_handler(self) -> None:
        """
        Show config pop up.
        :return None:
        """
        self._logger.debug("running")
        self.config_button.setStyleSheet(
            "background-color: rgba(200, 200, 200, 50%)")
        self._config_win.exec_()
        self._logger.debug("done")

    @property
    def language(self) -> LangEnum:
        """
        :return: The current lang enum being used.
        """
        return self._lang_enum

    @language.setter
    def language(self, lang: LangEnum) -> None:
        """
        Set the language for this view object.
        :param lang: The language to use.
        :return None:
        """
        self._logger.debug("running")
        self._lang_enum = lang
        self._strings = strings[lang]
        self._set_texts()
        self._set_tooltips()
        self._logger.debug("done")

    @property
    def resolution_list(self) -> list:
        """
        Get list of resolutions.
        :return list: The list of resolutions.
        """
        ret = list()
        return ret

    @resolution_list.setter
    def resolution_list(self, res_list: list) -> None:
        """
        Set list of resolutions available to res_list.
        :param res_list: The list of available resolutions.
        :return None:
        """
        self._logger.debug("running")
        self._resolution_selector.clear()
        for item in res_list:
            self._resolution_selector.addItem(str(item))
        self._logger.debug("done")

    @property
    def resolution(self) -> str:
        """
        Get the current resolution selection.
        :return str: The current resolution.
        """
        return self._resolution_selector.currentText()

    @resolution.setter
    def resolution(self, res: str) -> None:
        """
        Set the current resolution selection.
        :param res: The resolution to set to.
        :return None:
        """
        self._resolution_selector.setCurrentIndex(
            self._resolution_selector.findText(res))

    @property
    def fps_list(self) -> list:
        """
        Get list of fps options.
        :return list: The list of fps options.
        """
        ret = list()
        return ret

    @fps_list.setter
    def fps_list(self, fps_list: list) -> None:
        """
        Set list of available fps to fps_list.
        :param fps_list:
        :return None:
        """
        self._logger.debug("running")
        self._fps_selector.clear()
        for item in fps_list:
            self._fps_selector.addItem(str(item))
        self._logger.debug("done")

    @property
    def fps(self) -> str:
        """
        Get the current fps selection.
        :return str: The current fps selection.
        """
        return self._fps_selector.currentText()

    @fps.setter
    def fps(self, fps: str) -> None:
        """
        Set the current fps selection.
        :param fps: The fps to set to.
        :return None:
        """
        self._logger.debug("running")
        self._fps_selector.setCurrentIndex(self._fps_selector.findText(fps))
        self._logger.debug("done")

    @property
    def use_feed(self) -> bool:
        """
        Get the current use_cam setting.
        :return bool: User selection for using cam.
        """
        return self._show_feed_checkbox.isChecked()

    @use_feed.setter
    def use_feed(self, useable: bool) -> None:
        """
        Set use_cam setting.
        :param useable: The setting to set to.
        :return None:
        """
        self._logger.debug("running")
        self._show_feed_checkbox.setChecked(useable)
        self._logger.debug("Done")

    @property
    def use_cam(self) -> bool:
        """
        Get the current use_cam setting.
        :return bool: User selection for using cam.
        """
        return self._use_cam_checkbox.isChecked()

    @use_cam.setter
    def use_cam(self, useable: bool) -> None:
        """
        Set use_cam setting.
        :param useable: The setting to set to.
        :return None:
        """
        self._logger.debug("running")
        self._use_cam_checkbox.setChecked(useable)
        self._logger.debug("Done")

    @property
    def use_overlay(self) -> bool:
        """
        Get the current use_overlay setting.
        :return bool: User selection for using overlay.
        """
        return self._use_overlay_checkbox.isChecked()

    @use_overlay.setter
    def use_overlay(self, useable: bool) -> None:
        """
        Set use_overlay setting.
        :param useable: The setting to set to.
        :return None:
        """
        self._logger.debug("running")
        self._use_overlay_checkbox.setChecked(useable)
        self._logger.debug("Done")

    def heightForWidth(self, w: int) -> int:
        return int(w * self._aspect_ratio)

    def widthForHeight(self, h: int) -> int:
        return int(h / self._aspect_ratio)

    def hideEvent(self, hideEvent: QHideEvent):
        """
        Track minimize event.
        :param hideEvent:
        :return None:
        """
        self._hidden = True

    def showEvent(self, showEvent: QShowEvent):
        """
        Track restore event.
        :param showEvent:
        :return None:
        """
        self._hidden = False

    def update_image(self, image: QPixmap = None, msg: str = None) -> None:
        """
        Update image viewer with new image.
        :param image: The new image to show.
        :param msg: The text to show if no image.
        :return None:
        """
        self._logger.debug("running")
        if not self._window_changing:
            if image is not None:
                temp_image_w = image.scaledToWidth(self.width() - 15)
                temp_image_h = image.scaledToHeight(self.height() - 35)
                if temp_image_w.height() > self.height() - 35:
                    self._image_display.setPixmap(temp_image_h)
                else:
                    self._image_display.setPixmap(temp_image_w)
            elif msg is not None:
                self._image_display.setText(msg)
        self._logger.debug("done")

    def show_images(self) -> None:
        """
        Show image display and hide initialization bar.
        :return None:
        """
        self._logger.debug("running")
        geo = self.geometry()
        self._showing_images = True
        self._initialization_bar_frame.hide()
        self._image_display.show()
        self.config_button.show()
        self.setStyleSheet("background-color: black")
        self.setGeometry(geo)
        self._logger.debug("done")

    def show_initialization(self) -> None:
        """
        Show initialization bar and hide image display.
        :return None:
        """
        self._logger.debug("running")
        self._showing_images = False
        self._image_display.hide()
        self.config_button.hide()
        self._initialization_bar_frame.show()
        self._logger.debug("done")

    def update_init_bar(self, progress: int) -> None:
        """
        set progress bar value to progress.
        :param progress: The value to set progress bar to.
        :return None:
        """
        self._logger.debug("running")
        if progress > 100:
            progress = 100
        elif progress < 0:
            progress = 0
        self._initialization_bar.setValue(progress)
        self._logger.debug("done")

    def set_config_active(self, is_active: bool) -> None:
        """
        Set whether this camera config options are usable.
        :param is_active: Usable.
        :return None:
        """
        self._logger.debug("running")
        if self._showing_images:
            if is_active:
                self._rec_label.hide()
            elif self.use_cam:
                self._rec_label.show()
        for item in self._config_items:
            item.setEnabled(is_active)
        self._logger.debug("done")

    def _set_texts(self) -> None:
        """
        Set the texts in this view object.
        :return None:
        """
        self._logger.debug("running")
        self._initialization_bar_label.setText(
            self._strings[StringsEnum.INITIALIZATION_BAR_LABEL])
        self._initialization_bar.setValue(0)
        self._image_display_label.setText(
            self._strings[StringsEnum.IMAGE_DISPLAY_LABEL])
        self._image_display.setText(self._strings[StringsEnum.IMAGE_DISPLAY])
        self._show_feed_checkbox_label.setText(
            self._strings[StringsEnum.SHOW_FEED_CHECKBOX_LABEL])
        self._use_cam_checkbox_label.setText(
            self._strings[StringsEnum.USE_CAM_CHECKBOX_LABEL])
        self._use_overlay_checkbox_label.setText(
            self._strings[StringsEnum.USE_OVERLAY_CHECKBOX_LABEL])
        self._resolution_selector_label.setText(
            self._strings[StringsEnum.RESOLUTION_SELECTOR_LABEL])
        self._fps_selector_label.setText(
            self._strings[StringsEnum.FPS_SELECTOR_LABEL])
        self._config_win.setWindowTitle(
            self.get_name() + " " +
            self._strings[StringsEnum.CONFIG_TAB_LABEL])
        self.config_button.setText("...")
        self._rec_label.setText("rec ●")
        self._logger.debug("done")

    def _set_tooltips(self) -> None:
        """
        Set the tooltips in this view object.
        :return None:
        """
        self._logger.debug("running")
        self._resolution_selector_label.setToolTip(
            self._strings[StringsEnum.RESOLUTION_SELECTOR_TOOLTIP])
        self._resolution_selector.setToolTip(
            self._strings[StringsEnum.RESOLUTION_SELECTOR_TOOLTIP])
        self._fps_selector_label.setToolTip(
            self._strings[StringsEnum.FPS_SELECTOR_TOOLTIP])
        self._fps_selector.setToolTip(
            self._strings[StringsEnum.FPS_SELECTOR_TOOLTIP])
        self._show_feed_checkbox_label.setToolTip(
            self._strings[StringsEnum.SHOW_FEED_CHECKBOX_TOOLTIP])
        self._show_feed_checkbox.setToolTip(
            self._strings[StringsEnum.SHOW_FEED_CHECKBOX_TOOLTIP])
        self._use_cam_checkbox_label.setToolTip(
            self._strings[StringsEnum.USE_CAM_CHECKBOX_TOOLTIP])
        self._use_cam_checkbox.setToolTip(
            self._strings[StringsEnum.USE_CAM_CHECKBOX_TOOLTIP])
        self._use_overlay_checkbox_label.setToolTip(
            self._strings[StringsEnum.USE_OVERLAY_TOOLTIP])
        self._use_overlay_checkbox.setToolTip(
            self._strings[StringsEnum.USE_OVERLAY_TOOLTIP])
        self._image_display.setToolTip(
            self._strings[StringsEnum.IMAGE_DISPLAY_TOOLTIP])
        self._logger.debug("done")
Exemplo n.º 14
0
class TTVSetsImporterWidget(QWidget):
    ttv_updated = Signal(TTVSets)

    def __init__(
        self,
        format_to_widget,
        parent: "QWidget" = None,
    ):
        super().__init__(parent)

        # Components
        self._ttv = None

        # Maps a  with its respective Widget
        self._format_to_widget = format_to_widget

        self._stacked_widgets = QStackedWidget()

        self._name_textbox = QLineEdit("Unnamed")

        self._formatter_selector = QComboBox()
        for (dataset_io_name,
             widget_factory) in self._format_to_widget.items():
            self._formatter_selector.addItem(
                dataset_io_name, getattr(DatasetIORegistry, dataset_io_name))
            self._stacked_widgets.addWidget(
                self._format_to_widget[dataset_io_name]())

        def horizontal_line():
            line = QFrame()
            line.setFrameShape(QFrame.HLine)
            line.setFrameShadow(QFrame.Sunken)
            line.setFixedHeight(2)
            line.setContentsMargins(0, 30, 0, 0)
            return line

        self._x_datatype_selector = DatatypeSelectorFactory(
            title="X (Input) Datatype")
        self._y_datatype_selector = DatatypeSelectorFactory(
            title="Y (Output) Datatype")

        datatypes_layout = QHBoxLayout()
        datatypes_layout.addWidget(self._x_datatype_selector)
        datatypes_layout.addWidget(self._y_datatype_selector)

        self._info_layout = QFormLayout()
        self._info_layout.addRow("Name", self._name_textbox)
        self._info_layout.addRow("Format", self._formatter_selector)

        self._main_layout = QVBoxLayout()
        self._main_layout.addLayout(self._info_layout)
        self._main_layout.addWidget(horizontal_line())
        self._main_layout.addWidget(self._stacked_widgets)
        self._main_layout.addWidget(horizontal_line())
        self._main_layout.addLayout(datatypes_layout)

        self._load_ttv_from_file_button = QPushButton("Load from file...")
        self._load_ttv_from_file_button.clicked.connect(
            self._load_ttv_from_file)

        self._update_ttv_button = QPushButton("Load TTV")
        self._update_ttv_button.clicked.connect(self._update_ttv)

        self._button_box = QDialogButtonBox()
        self._button_box.addButton(self._load_ttv_from_file_button,
                                   QDialogButtonBox.ResetRole)
        self._button_box.addButton(self._update_ttv_button,
                                   QDialogButtonBox.ApplyRole)

        self._main_layout.addWidget(self._button_box)

        self.setLayout(self._main_layout)

        self._formatter_selector.currentIndexChanged[int].connect(
            lambda i: self._stacked_widgets.setCurrentIndex(i))

    def get_ttv(self) -> "TTVSets":
        return self._ttv

    def _update_ttv(self):
        self._ttv = self._stacked_widgets.currentWidget().load_ttv(
            self._name_textbox.text(),
            self._x_datatype_selector.selected_datatype,
            self._y_datatype_selector.selected_datatype,
        )

        self.ttv_updated.emit(self._ttv)

    def _load_ttv_from_file(self):
        print("Loading from file...")

        description_file_path = QFileDialog.getOpenFileName(
            self, "Open TTV .json file")[0]

        if description_file_path:
            LOGGER.debug("Loading %s...", description_file_path)

            ttv_dir = os.path.dirname(description_file_path)
            ttv_description = TTVSetsIO.load_ttv_description(
                description_file_path)

            # Update name
            self._name_textbox.setText(ttv_description["name"])

            # Pick the new formatter
            formatter_idx = self._formatter_selector.findText(
                ttv_description["format"])

            if formatter_idx != -1:
                self._formatter_selector.setCurrentIndex(formatter_idx)
                self._selected_index_changed(formatter_idx)

            # TODO: Cover case when "train" is null
            self._x_datatype_selector.change_current_datatype(
                ttv_description["train"]["x_type"])
            self._y_datatype_selector.change_current_datatype(
                ttv_description["train"]["y_type"])

            self._stacked_widgets.currentWidget().update_widgets(
                ttv_dir, ttv_description)

            self._update_ttv()

        else:
            LOGGER.debug("Loading cancelled")

    def _selected_index_changed(self, index: int):
        self._stacked_widgets.setCurrentIndex(index)

    def sizeHint(self) -> "QSize":
        """Optimal size of the widget."""
        return QSize(450, 150)

    def __reduce__(self):
        return (
            TTVSetsImporterWidget,
            (self._ttv_sets_dialog, None),
        )
Exemplo n.º 15
0
    def account_dialog(self, new_account=False):
        self.account_dialog_window = QDialog(self)
        self.account_dialog_window.setMinimumSize(300, 125)
        if self.account_dialog_window.isVisible():
            self.account_dialog_window.hide()

        # Main layout
        dialog_layout = QVBoxLayout()
        self.account_dialog_window.setLayout(dialog_layout)

        account_name_edit = QLineEdit()

        comment_edit = QLineEdit()
        comment_edit.setPlaceholderText(_("Comment"))

        steam_skin_select = QComboBox()
        steam_skin_select.addItems(self.switcher.steam_skins)

        if new_account:
            user = {}
            self.account_dialog_window.setWindowTitle(_("Add account"))
            self.submit_button = QPushButton(_("Add"))
            self.submit_button.setDisabled(True)
        else:
            login_name_selected = self.accounts_list.currentItem().data(5)
            user = self.switcher.settings["users"].get(login_name_selected, {})
            self.account_dialog_window.setWindowTitle(
                _("Edit account {0}").format(login_name_selected))
            self.submit_button = QPushButton(_("Edit"))
            account_name_edit.setText(login_name_selected)
            comment_edit.setText(user.get("comment"))
            steam_skin_select_index = steam_skin_select.findText(
                user.get("steam_skin", _("default")))
            if steam_skin_select_index != -1:
                steam_skin_select.setCurrentIndex(steam_skin_select_index)
            else:
                steam_skin_select.setCurrentIndex(1)

        def submit_enabled(item):
            if 3 < len(item) < 32:
                self.submit_button.setEnabled(True)
            else:
                self.submit_button.setEnabled(False)

        account_name_edit.setPlaceholderText(_("Login name"))
        account_name_edit.textChanged.connect(submit_enabled)

        close_button = QPushButton(_("Close"))

        dialog_layout.addWidget(account_name_edit)
        dialog_layout.addWidget(comment_edit)
        dialog_layout.addWidget(steam_skin_select)

        def update_user(u: dict) -> dict:
            u["comment"] = comment_edit.text()
            u["steam_skin"] = steam_skin_select.currentText()
            return u

        self.submit_button.clicked.connect(lambda: self.save_account(
            account_name_edit.text(), update_user(user), login_name_selected
            if not new_account else None))
        close_button.clicked.connect(self.account_dialog_window.close)

        buttons = QHBoxLayout()
        buttons.addWidget(self.submit_button)
        buttons.addWidget(close_button)

        dialog_layout.addLayout(buttons)

        self.account_dialog_window.show()
Exemplo n.º 16
0
class RootsApp(QMainWindow):
    standard_deviation_threshold = 0.1                      # when I receive a measurement from the sensor I check if its standard deviation; if it's too low it means the sensor is not working
    temporary_database_filename = "temporary.db"            # the current session is stored in a temporary database. When the user saves, it is copied at the desired location
    def __init__(self):
        super().__init__();
        self.setWindowTitle("Roots")
        self.setFixedWidth(1200)
        self.resize(1200, 1200)
        self.threadpool = QThreadPool();
        self.object_list = list()
        self.is_training_on = False
        self.interaction_under_training = None
        self.n_measurements_collected = 0
        self.n_measurements_to_collect = 3
        self.sensor_not_responding = True
        self.sensor_not_responding_timeout = 2000        # milliseconds
        self.database_connection = self.create_temporary_database()
        self.active_object = None
        self.number_of_objects_added = 0
        self.sensor_start_freq = 250000
        self.sensor_end_freq = 3000000

    # creates the plot
        self.plotWidget = pyqtgraph.PlotWidget(title = "Sensor Response")
        self.plotWidget.setFixedHeight(300)
        self.plotWidget.getAxis("bottom").setLabel("Excitation frequency", "Hz")
        self.plotWidget.getAxis("left").setLabel("Volts", "V")
        self.dataPlot = self.plotWidget.plot()

    # timer used to see if the sensor is responding
        self.timer = QTimer()
        self.timer.setInterval(self.sensor_not_responding_timeout)
        self.timer.timeout.connect(self.timer_timeout)
        self.timer_timeout()

    # defines the actions in the file menu with button actions
        iconExit = QIcon("icons/icon_exit.png")
        btnActionExit = QAction(iconExit, "Exit", self)
        btnActionExit.setStatusTip("Click to terminate the program")
        btnActionExit.triggered.connect(self.exit)

        iconSave = QIcon("icons/icon_save.ico")
        buttonActionSave = QAction(iconSave, "Save current set of objects", self)
        # buttonActionSave.setStatusTip("Click to perform action 2")
        buttonActionSave.triggered.connect(self.save)

        iconOpen = QIcon("icons/icon_load.png")
        buttonActionOpen = QAction(iconOpen, "Load set of objects", self)
        buttonActionOpen.triggered.connect(self.open)

    # toolbar
        toolBar = QToolBar("Toolbar")
        toolBar.addAction(buttonActionSave)
        toolBar.addAction(buttonActionOpen)
        toolBar.setIconSize(QSize(64, 64))
        toolBar.setStyleSheet(styles.toolbar)
        self.addToolBar(toolBar)

    # menu
        menuBar = self.menuBar()
        menuBar.setStyleSheet(styles.menuBar)
        menuFile = menuBar.addMenu("File")
        menuOptions = menuBar.addMenu("Options")
        menuView = menuBar.addMenu("View")
        menuConnect = menuBar.addMenu("Connect")
        menuFile.addAction(buttonActionSave)
        menuFile.addAction(buttonActionOpen)
        menuFile.addAction(btnActionExit)

    # status bar
        self.setStatusBar(QStatusBar(self))

    # creates the "My Objects" label
        labelMyObjects = QLabel("My Objects")
        labelMyObjects.setFixedHeight(100)
        labelMyObjects.setAlignment(Qt.AlignCenter)
        labelMyObjects.setStyleSheet(styles.labelMyObjects)

    # button "add object"
        icon_plus = QIcon("icons/icon_add.png")
        self.btn_create_object = QPushButton("Add Object")
        self.btn_create_object.setCheckable(False)
        self.btn_create_object.setIcon(icon_plus)
        self.btn_create_object.setFixedHeight(80)
        self.btn_create_object.setStyleSheet(styles.addObjectButton)
        self.btn_create_object.clicked.connect(self.create_object)

    # defines the layout of the "My Objects" section
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setContentsMargins(0,0,0,0)
        self.verticalLayout.addWidget(labelMyObjects)
        self.verticalLayout.addWidget(self.btn_create_object)
        self.spacer = QSpacerItem(0,2000, QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.verticalLayout.setSpacing(0)
        self.verticalLayout.addSpacerItem(self.spacer)  #adds spacer

    # defines the ComboBox which holds the names of the objects
        self.comboBox = QComboBox()
        self.comboBox.addItem("- no object selected")
        self.comboBox.currentIndexChanged.connect(self.comboBox_index_changed)
        self.comboBox.setFixedSize(300, 40)
        self.comboBox.setStyleSheet(styles.comboBox)
        self.update_comboBox()

    # defines the label "Selected Object" (above the comboBox)
        self.labelComboBox = QLabel()
        self.labelComboBox.setText("Selected Object:")
        self.labelComboBox.setStyleSheet(styles.labelComboBox)
        self.labelComboBox.adjustSize()

    # vertical layout for the combobox and its label
        self.VLayoutComboBox = QVBoxLayout()
        self.VLayoutComboBox.addWidget(self.labelComboBox)
        self.VLayoutComboBox.addWidget(self.comboBox)

    # label with the output text (the big one on the right)
        self.labelClassification = QLabel()
        self.labelClassification.setText("No interaction detected")
        self.labelClassification.setFixedHeight(80)
        self.labelClassification.setStyleSheet(styles.labelClassification)
        self.labelClassification.adjustSize()

        HLayoutComboBox = QHBoxLayout()
        HLayoutComboBox.addLayout(self.VLayoutComboBox)
        HLayoutComboBox.addSpacerItem(QSpacerItem(1000,0, QSizePolicy.Expanding, QSizePolicy.Expanding));  #adds spacer
        HLayoutComboBox.addWidget(self.labelClassification)

    # creates a frame that contains the combobox and the labels
        frame = QFrame()
        frame.setStyleSheet(styles.frame)
        frame.setLayout(HLayoutComboBox)

    # sets the window layout with the elements created before
        self.windowLayout = QVBoxLayout()
        self.windowLayout.addWidget(self.plotWidget)
        self.windowLayout.addWidget(frame)
        self.windowLayout.addLayout(self.verticalLayout)

    # puts everything into a frame and displays it on the window
        self.mainWindowFrame = QFrame()
        self.mainWindowFrame.setLayout(self.windowLayout)
        self.mainWindowFrame.setStyleSheet(styles.mainWindowFrame)
        self.setCentralWidget(self.mainWindowFrame)

        self.create_object()        # creates one object at the beginning



# -----------------------------------------------------------------------------------------------------------
# Shows a welcome message
    def show_welcome_msg(self):
        welcome_msg = QMessageBox()
        welcome_msg.setText("Welcome to the Roots application!")
        welcome_msg.setIcon(QMessageBox.Information)
        welcome_msg.setInformativeText(strings.welcome_text)
        welcome_msg.setWindowTitle("Welcome")
        welcome_msg.exec_()


# -----------------------------------------------------------------------------------------------------------
# When the user changes the object in the combobox, updates the active object
    def comboBox_index_changed(self, index):
        object_name = self.comboBox.currentText()
        for object in self.object_list:
            if object.name == object_name:
                self.set_active_object(object)
                print("DEBUG: selected object changed. Object name: {0}".format(object.name))
                return

# -----------------------------------------------------------------------------------------------------------
# This function allows to save the current objects on a file
    def save(self):
        current_path = os.getcwd()
        directory_path = current_path + "/Saved_Workspaces"

        if not os.path.exists(directory_path):
            os.mkdir(directory_path)

        file_path = None
        [file_path, file_extension] = QFileDialog.getSaveFileName(self,"Roots", directory_path, "Roots database (*.db)")
        if file_path is None:
            return

        temp_database_path = current_path + "/" + RootsApp.temporary_database_filename
        shutil.copyfile(temp_database_path, file_path)      # copies the temporary database to save the current workspace
        return



# -----------------------------------------------------------------------------------------------------------
# this function creates a clean database where all the data of this session will be temporarily stored
    def create_temporary_database(self):
        current_path = os.getcwd()
        file_path = current_path + "/" + RootsApp.temporary_database_filename

        if os.path.exists(file_path):   # if the database is already there it deletes it to reset it
            os.remove(file_path)
            print("DEBUG: removing database. (in 'RootsApp.create_temporary_database()'")

        database_connection = database.create_connection(RootsApp.temporary_database_filename)  # creates the temporary database
        database.create_tables(database_connection)                                             # initializes the database
        database.reset_db(database_connection)                                                  # resets the database (not needed but it doesn't cost anything to put it)

        return database_connection


# -----------------------------------------------------------------------------------------------------------
# This function allows to load previously created objects from a file
    def open(self):
        current_path = os.getcwd()
        saved_files_directory = current_path + "/Saved_Workspaces"

        [file_path, file_extension] = QFileDialog.getOpenFileName(self,"Roots", saved_files_directory, "Roots database (*.db)");
        if file_path == '':
            return

        for object in self.object_list.copy():     # deletes all the objects
            print("DEBUG: deleting object {0} (in 'open()')".format(object.name))
            self.delete_object(object)

        temp_database_path = current_path + "/" + RootsApp.temporary_database_filename
        self.database_connection.close()
        os.remove(temp_database_path)
        shutil.copyfile(file_path, temp_database_path)      # replaces the temporary database with the file to open
        self.database_connection = database.create_connection(temp_database_path)

        object_tuples = database.get_all_objects(self.database_connection)
        for object_tuple in object_tuples:
            object_ID, object_name = object_tuple
            location_IDs = database.get_locations_id_for_object(self.database_connection, object_ID)
            formatted_location_IDs = []
            for location_ID in location_IDs:
                formatted_location_IDs.append(location_ID[0])

            print("DEBUG: loading object {0} with location IDs {1}. (in 'RootsApp.open()')".format(object_name, formatted_location_IDs))
            self.add_object(object_name, object_ID, formatted_location_IDs)
            self.train_classifiers()
        return


# -----------------------------------------------------------------------------------------------------------
# This function updates the ComboBox whenever objects are created, destroyed or the active object has changed
    def update_comboBox(self):
        print("DEBUG: repainting ComboBox. (in 'RootsApp.update_comboBox()'")
        self.comboBox.clear()
        self.comboBox.addItem("none")
        for object in self.object_list:
            self.comboBox.addItem(object.name)
        self.comboBox.adjustSize()


# -----------------------------------------------------------------------------------------------------------
# This is a timer which is restarted every time a measurement is received. If it elapses it means that the sesnor is not connected
    def timer_timeout(self):
        print("DEBUG: timer timeout. (in 'RootsApp.timer_timeout()'")
        self.sensor_not_responding = True
        self.statusBar().showMessage(strings.sensor_disconnected)
        self.statusBar().setStyleSheet(styles.statusBarError)
        self.plotWidget.setTitle("Sensor not connected")

# -----------------------------------------------------------------------------------------------------------
# This function creates a new object in the database and then calls the "add_object" function, which adds the newly created object to the application
    def create_object(self):
        new_object_name = "Object {0}".format(self.number_of_objects_added + 1)
        [new_object_ID, location_IDs] = database.create_object(self.database_connection, new_object_name)
        self.add_object(new_object_name, new_object_ID, location_IDs)


# -----------------------------------------------------------------------------------------------------------
# This function deletes an object from the database, and from the application object list. It alsos destroys the object
    def delete_object(self, object):
        print("DEBUG: deleting object {0}. (in 'RootsApp.delete_object()')".format(object.ID))
        database.delete_object(self.database_connection, object.ID)
        self.object_list.remove(object)
        self.verticalLayout.removeItem(object.layout)
        self.update_comboBox()
        object.delete()


# -----------------------------------------------------------------------------------------------------------
# This function adds an object to the current application. Note that if you want to create an object ex-novo you should call "create_object". This function is useful when loading existing objects from a file
    def add_object(self, name, object_ID, location_IDs):
        self.number_of_objects_added += 1
        new_object = Object(name, object_ID, location_IDs, self)
        self.object_list.append(new_object)

        for ID in location_IDs:                                         # initializes the measurements with 0 if the measurement is empty
            #print("DEBUG: initializing location ID {0}".format(ID))
            measurements = database.get_measurements_for_location(self.database_connection, ID)

            print("DEBUG: location {0} of object {1} is trained: {2}. (in 'RootsApp.add_object()')".format(ID, new_object.name, database.is_location_trained(self.database_connection, ID)))
            if len(measurements) == 0:
                database.save_points(self.database_connection, [0], ID)
                database.set_location_trained(self.database_connection, ID, "FALSE")
            elif database.is_location_trained(self.database_connection, ID) == "TRUE":
                new_object.get_interaction_by_ID(ID).setCalibrated(True)

        # inserts the newly created object before the "Add Object" button
        index = self.verticalLayout.indexOf(self.btn_create_object)
        self.verticalLayout.insertLayout(index, new_object.layout)
        self.update_comboBox()
        print("DEBUG: object {0} added. (in 'RootsApp.add_object()')".format(new_object.name))
        return



# -----------------------------------------------------------------------------------------------------------
# This function takes as input the measurement data and formats it to plot it on the graph
    def update_graph(self, data):
        frequency_step = (self.sensor_end_freq - self.sensor_start_freq) / len(data)
        x_axis = numpy.arange(self.sensor_start_freq, self.sensor_end_freq, frequency_step)
        formatted_data = numpy.transpose(numpy.asarray([x_axis, data]))
        self.dataPlot.setData(formatted_data)


# -----------------------------------------------------------------------------------------------------------
# This function starts the UDP server that receives the measurements
    def run_UDP_server(self, UDP_IP, UDP_PORT):
        self.UDPServer = UDPServer(UDP_IP, UDP_PORT)
        self.UDPServer.signals.measurementReceived.connect(self.process_measurement)
        self.threadpool.start(self.UDPServer)


# -----------------------------------------------------------------------------------------------------------
# This function changes some global variables to tell the application to save the incoming measurements into the database. The measurements belong to the interaction passed as argument
    def start_collecting_measurements(self, interaction):
        if self.sensor_not_responding:
            print("DEBUG: warning! Can't start calibration, the sensor is not responding! (in 'RootsApp.start_collecting_measurements()')")
            error_msg = QMessageBox()
            error_msg.setText("Can't start calibration!")
            error_msg.setIcon(QMessageBox.Critical)
            error_msg.setInformativeText('The sensor is not responding, make sure it is connected')
            error_msg.setWindowTitle("Error")
            error_msg.exec_()
        else:
            print("starting to collect measurements into the database at location ID {0} (in 'RootsApp.start_collecting_measurements()')".format(interaction.ID));
            self.is_training_on = True
            self.interaction_under_training = interaction
            database.delete_measurements_from_location(self.database_connection, interaction.ID)   # resets the location measurements

            self.progress_dialog = QProgressDialog("Calibrating", "Abort", 0, self.n_measurements_to_collect, self)
            self.progress_dialog.setWindowModality(Qt.WindowModal)
            self.progress_dialog.setWindowTitle("Calibration")
            self.progress_dialog.setFixedSize(400, 200)
            self.progress_dialog.setValue(0)
            self.progress_dialog.exec_()



# -----------------------------------------------------------------------------------------------------------
# This function is called by the UDP thread every time that a measurement is received. It does the following:
#   1. Plots the incoming measurement
#   2. IF training mode IS on:
#           Predicts the interaction (tries to guess where the user is touching)
#      ELSE:
#           Saves the measurement and retrains the classifier with the new data
    def process_measurement(self, received_data):
        self.sensor_not_responding = False
        self.plotWidget.setTitle("Sensor response")
        self.timer.start()                                          # starts the timer that checks if we are receiving data from the sensor

        measurement = received_data.split(' ')                      # get rid of separator
        measurement = [float(i) for i in measurement]               # convert strings to float
        self.update_graph(measurement)
        self.predict_interaction(measurement)

        # checks the standard deviation of the received data to see if the sensor is working well
        if (numpy.std(measurement) < self.standard_deviation_threshold):
            self.statusBar().showMessage(strings.sensor_not_working)
            self.statusBar().setStyleSheet(styles.statusBarError)
        else:
            self.statusBar().setStyleSheet(styles.statusBar)

        if self.is_training_on:
            print("saving measurement {0} into database at location_ID {1}. (in 'RootsApp.process_measurement()')".format(self.n_measurements_collected + 1, self.interaction_under_training.ID))
            database.save_points(self.database_connection, measurement, self.interaction_under_training.ID)
            self.n_measurements_collected += 1
            self.progress_dialog.setValue(self.n_measurements_collected)
            if (self.n_measurements_collected >= self.n_measurements_to_collect):
                self.is_training_on = False
                self.n_measurements_collected = 0
                print("DEBUG: {0} measurements were saved at location_ID {1}. (in 'RootsApp.process_measurement()')".format(self.n_measurements_to_collect, self.interaction_under_training.ID))
                self.train_classifiers()
                self.interaction_under_training.setCalibrated(True)     # this makes the button "Calibrate" change coulour


# -----------------------------------------------------------------------------------------------------------
# This function retrains the classifiers using all the measurements present in the database and assigns to each object its classifier
    def train_classifiers(self):
        #[objects_ID, classifiers]
        classifiers = classifier.get_classifiers(self.database_connection)
        print("DEBUG: the following classifiers were created: {0}. (in 'RootsApp.train_classifiers')".format(classifiers))
        for object in self.object_list:
            for index, tuple in enumerate(classifiers):
                object_ID, classif = tuple;  # extracts the object ID and the classifier from the tuple
                if object_ID == object.ID:
                    object.classifier = classif
                    del classifiers[index]


# -----------------------------------------------------------------------------------------------------------
# This function changes the current active object (the software tries to guess where the user is touching using the calibration data from the active object)
    def set_active_object(self, active_object):
        self.active_object = active_object

        for obj in self.object_list:
            if obj == active_object:
                active_object.set_highlighted(True)
            else:
                obj.set_highlighted(False)

        index = self.comboBox.findText(self.active_object.name)     # updates the index of the ComboBox
        self.comboBox.setCurrentIndex(index)


# -----------------------------------------------------------------------------------------------------------
# This function changes the name of an object. It updates the database AND the application data structure.
    def rename_object(self, object, new_name):
        print("DEBUG: changing name of object '{0}' (in 'RootsApp.rename_object')".format(object.name))
        object.set_name(new_name)
        database.rename_object(self.database_connection, object.ID, new_name)
        self.update_comboBox()



# -----------------------------------------------------------------------------------------------------------
# This function uses the classifier of the active object to guess where the user is touching, based on the incoming measurement
    def predict_interaction(self, measurement):
        if (len(self.object_list) <= 0):
            self.labelClassification.setText("No objects available")
            self.statusBar().showMessage(strings.no_objects)
            return
        if self.active_object is None:
            self.labelClassification.setText("No object selected")
            self.statusBar().showMessage(strings.no_object_selected)
            return
        if self.active_object.classifier is None:
            self.labelClassification.setText("The object is not calibrated")
            self.statusBar().showMessage(strings.object_not_calibrated)
            return
        else:
            predicted_interaction_id = self.active_object.classifier(measurement)
            interaction = self.active_object.get_interaction_by_ID(predicted_interaction_id)
            self.labelClassification.setText(interaction.name)
            self.statusBar().showMessage("")
            #print("DEBUG: predicted interaction ID: ", interaction.ID)



# -----------------------------------------------------------------------------------------------------------
# This is a system event that gets called whenever the user tries to close the application. It calls the "exit()"
# function (just below) to open a dialog to make sure the user really wants to quit.
    def closeEvent(self, event):
        if not self.exit():
            event.ignore()


# -----------------------------------------------------------------------------------------------------------
# This function gets called when the user cliks on the "Exit" button in the "File" menu or when it tries to close the window (indirectly)
# Here we open a dialog to make sure the user really wants to quit.
    def exit(self):
        dialogWindow = DialogExit()
        answer = dialogWindow.exec_()
        if (answer == True):
            self.UDPServer.stop()
            self.close()
        return answer
Exemplo n.º 17
0
class MainWindow(QObject):
    """ Appliaction GUI """
    current_port_signal = Signal(str)
    current_table = Signal(str)

    def __init__(self, ui_fil, parent=None):
        super(MainWindow, self).__init__(parent)
        self.ui_file = QFile(ui_fil)
        self.ui_file.open(QFile.ReadOnly)
        self.loader = QUiLoader()
        self.loader.setLanguageChangeEnabled(True)
        self.window = self.loader.load(self.ui_file)
        self.window.setGeometry(50, 50, 860, 640)
        self.window.setWindowIcon(QIcon('icons/icons8-wi-fi-64.png'))
        self.ui_file.close()

        self.trans = QTranslator()
        self.trans.load('lang/pl_PL.qm')
        self.conn_baudrates = [
            "9600", "115200", "300", "1200", "2400", "4800", "14400", "19200",
            "31250", "38400", "57600"
        ]
        self.conn_boards = ["ESP32", "ESP8266"]

        self.widget_tab = self.window.findChild(QTabWidget, 'tabWidget')
        self.widget_tab.setIconSize(QSize(36, 36))
        self.widget_tab.setTabIcon(0, QIcon('icons/icons8-automatic-64.png'))
        self.widget_tab.setTabIcon(1, QIcon('icons/icons8-bar-chart-50.png'))
        self.widget_tab.setTabIcon(2, QIcon('icons/icons8-menu-64.png'))
        self.widget_tab.setTabIcon(3, QIcon('icons/icons8-timeline-64.png'))
        self.widget_tab.setTabIcon(4, QIcon('icons/icons8-bluetooth-50.png'))
        self.widget_tab.setTabIcon(5, QIcon('icons/icons8-console-64.png'))

        self.lang_combo_box = self.window.findChild(QComboBox,
                                                    'lang_combo_box')
        self.lang_combo_box.addItem("English")
        self.lang_combo_box.addItem("Polski")
        self.lang_combo_box.currentTextChanged.connect(self.change_language)
        self.serial_port_box = self.window.findChild(QComboBox,
                                                     'serial_port_box')
        self.baud_rate_box = self.window.findChild(QComboBox, 'baud_rate_box')
        self.select_board_box = self.window.findChild(QComboBox,
                                                      'select_board_box')
        self.scan_time_edit = self.window.findChild(QTimeEdit,
                                                    'scan_time_edit')
        self.wifi_scan_box = self.window.findChild(QCheckBox, 'wifi_scan_box')
        self.blue_scan_box = self.window.findChild(QCheckBox, 'blue_scan_box')
        self.save_data_check = self.window.findChild(QCheckBox,
                                                     'save_data_check')
        self.connection_status_edit = self.window.findChild(
            QLineEdit, 'connection_status_edit')
        self.start_button = self.window.findChild(QPushButton, 'start_button')
        self.stop_button = self.window.findChild(QPushButton, 'stop_button')
        self.stop_button.setEnabled(False)
        self.vertical_wifi_layout = self.window.findChild(
            QVBoxLayout, 'verticalLayout_5')
        self.wifi_list_view = self.window.findChild(QListWidget,
                                                    'wifi_list_view')
        self.wifi_list_view.setIconSize(QSize(64, 64))
        self.vertical_timeline_layout = self.window.findChild(
            QVBoxLayout, 'verticalLayout_7')
        self.blue_list_view = self.window.findChild(QListWidget,
                                                    'blue_list_view')
        self.blue_list_view.setIconSize(QSize(64, 64))
        self.console_logging_check = self.window.findChild(
            QCheckBox, 'console_logging_check')
        self.console_autoscroll_check = self.window.findChild(
            QCheckBox, 'console_autoscroll_check')
        self.console_text_edit = self.window.findChild(QTextEdit,
                                                       'console_text_edit')

        self.select_board_box.activated[str].connect(self.change_board)

        #Settings tab
        for i in self.conn_baudrates:
            self.baud_rate_box.addItem(i)
        for i in self.conn_boards:
            self.select_board_box.addItem(i)
        self.connection_status_edit.setText('Not connected')
        self.connection_status_edit.setStyleSheet(
            "background: red; color: white; font-size: 14px; border-width: 1px; \
            border-style: solid; border-radius: 2px; border-color: red;")

        thread1 = ReadSerialPortsThread.ReadSerialPortsThread(self)
        thread1.add_serial_port.connect(
            lambda p: self.serial_port_box.addItem(p))
        thread1.remove_serial_port.connect(
            lambda p: self.serial_port_box.removeItem(
                self.serial_port_box.findText(p)))
        thread1.start()
        thread2 = MakeSerialConnection.MakeSerialConnection(self)
        thread4 = WriteToDatabase.WriteToDatabase(self)

        self.serial_port_box.currentTextChanged.connect(thread2.get_curr_port)
        self.baud_rate_box.activated[str].connect(thread2.get_curr_baud)
        self.select_board_box.activated[str].connect(thread2.get_curr_board)
        self.scan_time_edit.timeChanged.connect(thread2.get_curr_time)
        self.start_button.clicked.connect(thread2.start)
        self.stop_button.clicked.connect(thread2.stop_serial_communication)
        self.wifi_scan_box.clicked.connect(thread2.get_wifi_check)
        self.blue_scan_box.clicked.connect(thread2.get_blue_check)
        self.save_data_check.clicked.connect(thread2.enable_saving_to_db)
        self.save_data_check.clicked.connect(thread4.enable_saving_data_func)
        self.lang_combo_box.currentTextChanged.connect(
            lambda s: thread2.get_current_lang(s))

        thread2.baud_box_state.connect(
            lambda b: self.baud_rate_box.setEnabled(b))
        thread2.port_box_state.connect(
            lambda b: self.serial_port_box.setEnabled(b))
        thread2.board_box_state.connect(
            lambda b: self.select_board_box.setEnabled(b))
        thread2.time_edit_state.connect(
            lambda b: self.scan_time_edit.setEnabled(b))
        thread2.wifi_check_state.connect(
            lambda b: self.wifi_scan_box.setEnabled(b))
        thread2.blue_check_state.connect(
            lambda b: self.blue_scan_box.setEnabled(b))
        thread2.serial_port_placeholder.connect(
            lambda t: self.serial_port_box.addItem(t))
        thread2.serial_port_clear.connect(self.serial_port_box.clear)
        thread2.send_text_signal.connect(
            lambda t: self.console_text_edit.append(t))
        thread2.start_btn_state.connect(
            lambda b: self.start_button.setEnabled(b))
        thread2.stop_btn_state.connect(
            lambda b: self.stop_button.setEnabled(b))
        thread2.conn_stat_text.connect(
            lambda t: self.connection_status_edit.setText(t))
        thread2.conn_stat_style.connect(
            lambda s: self.connection_status_edit.setStyleSheet(s))

        #Wi-Fi Chart tab
        self.chart = QtCharts.QChart()
        self.axis_x = QtCharts.QValueAxis()
        self.axis_y = QtCharts.QValueAxis()

        self.line_series = QtCharts.QLineSeries()
        self.line_series.append(QPoint(0, 0))
        self.chart.setAxisX(self.axis_x, self.line_series)
        self.axis_x.setRange(2400, 2483)
        self.axis_x.setTickCount(10)
        self.axis_x.setMinorTickCount(4)
        self.axis_x.applyNiceNumbers()
        self.axis_x.setTitleText("Frequency [MHz]")
        self.chart.setAxisY(self.axis_y, self.line_series)
        self.axis_y.setRange(-100, -30)
        self.axis_y.applyNiceNumbers()
        self.axis_y.setTickCount(9)
        self.axis_y.setMinorTickCount(4)
        self.axis_y.setTitleText("RSSI [dBm]")
        self.chart.legend().setVisible(True)
        self.chart.legend().setAlignment(Qt.AlignRight)
        self.chart.setBackgroundRoundness(0)
        self.chart_view = QtCharts.QChartView(self.chart)
        self.chart_view.setRenderHint(QPainter.Antialiasing)
        self.vertical_wifi_layout.addWidget(self.chart_view)

        #WiFi List tab
        thread2.clear_wifi_list.connect(self.wifi_list_view.clear)
        thread2.append_wifi_list_item.connect(
            lambda i: self.wifi_list_view.addItem(i))
        thread2.append_wifi_timeline_data.connect(
            lambda d: self.append_data(d))
        thread2.save_wifi_timeline_data.connect(
            lambda t: thread4.update_db_file(t))
        thread2.clear_wifi_series.connect(self.chart.removeAllSeries)
        thread2.add_wifi_series.connect(lambda s: self.chart.addSeries(s))
        thread2.set_axis_x_series.connect(
            lambda s: self.chart.setAxisX(self.axis_x, s))
        thread2.set_axis_y_series.connect(
            lambda s: self.chart.setAxisY(self.axis_y, s))
        thread2.wifi_data_to_func.connect(
            lambda d: thread2.append_wifi_data(d))
        thread2.wifi_data_to_func.connect(
            lambda d: thread2.append_data_to_wifi_graph(d))
        thread2.wifi_data_to_func.connect(
            lambda d: thread2.append_data_to_wifi_timeline(d))
        thread2.blue_data_to_func.connect(
            lambda d: thread2.append_blue_data(d))

        #Wi-Fi Timeline tab
        self.wifi_channels_occupancy_array = []
        self.wifi_channels_timestamps = []
        self.deleted_empty_vals = False
        self.freeze_graph_bool_val = False
        self.last_item = 0
        self.graph_item_color = QColor(255, 195, 0)

        self.bars = QtDataVisualization.Q3DBars()
        self.column_axis = QtDataVisualization.QCategory3DAxis()
        self.column_axis.setTitle('Channels')
        self.column_axis.setTitleVisible(True)
        self.column_axis.setLabels([
            'Channel 1', 'Channel 2', 'Channel 3', 'Channel 4', 'Channel 5',
            'Channel 6', 'Channel 7', 'Channel 8', 'Channel 9', 'Channel 10',
            'Channel 11', 'Channel 12', 'Channel 13'
        ])
        self.column_axis.setLabelAutoRotation(45)
        self.column_axis.setAutoAdjustRange(True)
        self.row_axis = QtDataVisualization.QCategory3DAxis()
        self.row_axis.setTitle('Timeline')
        self.row_axis.setTitleVisible(True)
        self.value_axis = QtDataVisualization.QValue3DAxis()
        self.value_axis.setTitle('RSSI [dBm]')
        self.value_axis.setTitleVisible(True)
        self.value_axis.setRange(-100, -10)

        self.bars.setRowAxis(self.row_axis)
        self.bars.setColumnAxis(self.column_axis)
        self.bars.setValueAxis(self.value_axis)
        self.bars.setBarSpacingRelative(False)
        self.bars.setFloorLevel(-100)

        self.series = QtDataVisualization.QBar3DSeries()
        self.array_data = [[]]
        self.series.dataProxy().addRows(
            self.data_to_bar_data_array(self.array_data))
        self.series.setBaseColor(self.graph_item_color)

        self.bars.setPrimarySeries(self.series)
        self.container = QWidget.createWindowContainer(self.bars)

        if not self.bars.hasContext():
            print("Couldn't initialize the OpenGL context")
            sys.exit(-1)

        camera = self.bars.scene().activeCamera()
        camera.setXRotation(-45.0)
        camera.setYRotation(22.5)

        geometry = QGuiApplication.primaryScreen().geometry()
        size = geometry.height() * 3 / 4
        self.container.setMinimumSize(size, size)
        self.container.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        self.container.setFocusPolicy(Qt.StrongFocus)
        self.append_data([
            -100, -80, -100, -80, -100, -80, -100, -80, -100, -80, -100, -80,
            -100
        ])
        self.nav_layout_h = QHBoxLayout()
        self.freeze_check = QCheckBox()
        self.freeze_check.setText("Freeze")
        self.freeze_check.clicked.connect(self.enable_scrolling_data)
        self.freeze_check.stateChanged.connect(self.freeze_graph)
        self.prev_button = QPushButton()
        self.prev_button.setText("Previous")
        self.prev_button.setEnabled(False)
        self.prev_button.clicked.connect(self.previous_data)
        self.next_button = QPushButton()
        self.next_button.setText("Next")
        self.next_button.setEnabled(False)
        self.next_button.clicked.connect(self.next_data)
        self.nav_layout_h.addWidget(self.freeze_check)
        self.nav_layout_h.addWidget(self.prev_button)
        self.nav_layout_h.addWidget(self.next_button)

        self.load_data_check = QCheckBox()
        self.load_data_check.setText("Load archival data")
        self.load_data_check.clicked.connect(self.enable_load_data)
        self.load_data_combo = QComboBox()
        self.load_data_combo.addItem("No data found")
        self.load_data_combo.setEnabled(False)
        self.load_data_btn = QPushButton()
        self.load_data_btn.setText("Load")
        self.load_data_btn.setEnabled(False)
        self.nav_layout_h2 = QHBoxLayout()
        self.nav_layout_h2.addWidget(self.load_data_check)
        self.nav_layout_h2.addWidget(self.load_data_combo)
        self.nav_layout_h2.addWidget(self.load_data_btn)
        thread4.start()
        thread4.remove_defualt_item.connect(
            lambda: self.load_data_combo.clear())
        thread4.append_available_day.connect(
            lambda s: self.load_data_combo.addItem(s))
        thread4.send_data_from_database.connect(
            lambda t: self.append_data_from_database(t))
        self.load_data_combo.currentTextChanged.connect(
            lambda t: thread4.get_curr_table(t))
        self.load_data_btn.clicked.connect(thread4.load_data_button)

        self.vertical_timeline_layout.addWidget(self.container)
        self.vertical_timeline_layout.addLayout(self.nav_layout_h)
        self.vertical_timeline_layout.addLayout(self.nav_layout_h2)

        #Bluetooth tab
        thread2.clear_blue_list.connect(self.blue_list_view.clear)
        thread2.append_blue_list_item.connect(
            lambda i: self.blue_list_view.addItem(i))

        #Console tab
        self.console_autoscroll_check.stateChanged.connect(
            self.enable_auto_scroll)
        thread3 = WriteToFile.WriteToFile(self)
        self.console_logging_check.stateChanged.connect(thread3.enable_logging)
        thread2.send_text_signal.connect(lambda t: thread3.write_to_file(t))

        self.window.show()

    def change_board(self):
        """ Disable Bluetooth scan option if ESP8266 board is selected """
        print(self.select_board_box.currentText())
        if self.select_board_box.currentText() == "ESP8266":
            self.blue_scan_box.setEnabled(False)
        elif self.select_board_box.currentText() == "ESP32":
            self.blue_scan_box.setEnabled(True)

    def enable_auto_scroll(self):
        """ Enable scrolling in text console """
        if self.console_autoscroll_check.checkState() == Qt.Checked:
            self.console_text_edit.moveCursor(QTextCursor.End)
        else:
            self.console_text_edit.moveCursor(QTextCursor.Start)

    def freeze_graph(self, state):
        """ Stop showing live data in 3d Wi-Fi graph """
        if state == 2:
            self.freeze_graph_bool_val = True
        else:
            self.freeze_graph_bool_val = False

    def data_to_bar_data_row(self, data):
        """ DOCSTRING """
        return list(QtDataVisualization.QBarDataItem(d) for d in data)

    def data_to_bar_data_array(self, data):
        """ DOCSTRING """
        return list(self.data_to_bar_data_row(row) for row in data)

    def append_data(self, data):
        """ DOCSTRING """
        self.wifi_channels_occupancy_array.append(data)
        self.wifi_channels_timestamps.append(str(datetime.datetime.now()))
        self.update_graph()

    def update_graph(self):
        """ DOCSTRING """
        if len(self.wifi_channels_occupancy_array) < 10:
            missing_vals = 10 - len(self.wifi_channels_occupancy_array)
            for z in range(missing_vals):
                self.wifi_channels_occupancy_array.append([
                    -100, -100, -100, -100, -100, -100, -100, -100, -100, -100,
                    -100, -100, -100
                ])
                self.wifi_channels_timestamps.append("")
            self.print_freshes_ten()

        elif len(self.wifi_channels_occupancy_array
                 ) > 20 and self.deleted_empty_vals is False:
            for y in range(
                    self.wifi_channels_occupancy_array.count([
                        -100, -100, -100, -100, -100, -100, -100, -100, -100,
                        -100, -100, -100, -100
                    ])):
                self.wifi_channels_occupancy_array.remove([
                    -100, -100, -100, -100, -100, -100, -100, -100, -100, -100,
                    -100, -100, -100
                ])
                self.wifi_channels_timestamps.remove("")
                self.deleted_empty_vals = True
                self.print_freshes_ten()
        else:
            self.print_freshes_ten()

    def previous_data(self):
        """ DOCSTRING """
        if self.last_item < 9 and len(self.wifi_channels_occupancy_array) < 9:
            QMessageBox.warning(self.window, 'ISM 2.4GHz Scanner - Warning',
                                "To few information to rewind!",
                                QMessageBox.Ok)
        elif self.last_item < 9:
            print('out of range')
            QMessageBox.warning(self.window, 'ISM 2.4GHz Scanner - Warning',
                                "No more data to rewind!", QMessageBox.Ok)
        else:
            temp_array = []
            temp_timestamp_array = []
            if self.last_item - 9 < 0:
                print('out of range')
                QMessageBox.warning(self.window,
                                    'ISM 2.4GHz Scanner - Warning',
                                    "No more data to rewind!", QMessageBox.Ok)
            else:
                for x in range(self.last_item - 10, self.last_item - 1):
                    temp_array.append(self.wifi_channels_occupancy_array[x])
                    temp_timestamp_array.append(
                        self.wifi_channels_timestamps[x])
                self.last_item = self.last_item - 9
                self.row_axis.setLabels(temp_timestamp_array)
                self.series.dataProxy().resetArray()
                self.series.dataProxy().addRows(
                    self.data_to_bar_data_array(temp_array))

    def next_data(self):
        """ DOCSTRING """
        if self.last_item < 9 and len(self.wifi_channels_occupancy_array) < 9:
            QMessageBox.warning(self.window, 'ISM 2.4GHz Scanner - Warning',
                                "To few information to rewind!",
                                QMessageBox.Ok)
        elif self.last_item > len(self.wifi_channels_occupancy_array):
            print('out of range')
            QMessageBox.warning(self.window, 'ISM 2.4GHz Scanner - Warning',
                                "No more data to rewind!", QMessageBox.Ok)
        else:
            temp_array = []
            temp_timestamp_array = []
            if self.last_item + 9 > len(self.wifi_channels_occupancy_array):
                print('out of range')
                QMessageBox.warning(self.window,
                                    'ISM 2.4GHz Scanner - Warning',
                                    "No more data to rewind!", QMessageBox.Ok)
            else:
                for x in range(self.last_item + 1, self.last_item + 10):
                    temp_array.append(self.wifi_channels_occupancy_array[x])
                    temp_timestamp_array.append(
                        self.wifi_channels_timestamps[x])

                self.last_item = self.last_item + 9
                self.row_axis.setLabels(temp_timestamp_array)
                self.series.dataProxy().resetArray()
                self.series.dataProxy().addRows(
                    self.data_to_bar_data_array(temp_array))

    def print_freshes_ten(self):
        """ DOCSTRING """
        if self.freeze_graph_bool_val is False:
            i = 0
            temp_array = []
            temp_timestamp_array = []
            self.last_item = 0
            for x in range(len(self.wifi_channels_occupancy_array) - 1):
                if i < 10:
                    temp_array.append(self.wifi_channels_occupancy_array[
                        len(self.wifi_channels_occupancy_array) - x - 1])
                    temp_timestamp_array.append(self.wifi_channels_timestamps[
                        len(self.wifi_channels_timestamps) - x - 1])
                    i += 1
                elif i == 10:
                    self.last_item = len(
                        self.wifi_channels_occupancy_array) - 10
                    i += 1

            self.row_axis.setLabels(temp_timestamp_array)
            self.series.dataProxy().resetArray()
            self.series.dataProxy().addRows(
                self.data_to_bar_data_array(temp_array))

    def enable_scrolling_data(self, state):
        """ DOCSTRING """
        if state is True:
            self.prev_button.setEnabled(True)
            self.next_button.setEnabled(True)
        else:
            self.prev_button.setEnabled(False)
            self.next_button.setEnabled(False)

    def enable_load_data(self, state):
        """ DOCSTRING """
        if state is True:
            self.load_data_combo.setEnabled(True)
            if (self.load_data_combo.findText("No data found") == -1
                    or self.load_data_combo.findText("Nie znaleziono danych")):
                self.load_data_btn.setEnabled(True)
        else:
            self.load_data_combo.setEnabled(False)
            self.load_data_btn.setEnabled(False)
            self.wifi_channels_occupancy_array = []
            self.wifi_channels_timestamps = []
            self.print_freshes_ten()

    def change_language(self, lang):
        """ DOCSTRING """
        if lang == "Polski":
            QCoreApplication.installTranslator(self.trans)
            self.axis_x.setTitleText("Częstotliwość [MHz]")
            self.freeze_check.setText("Zamróź")
            self.load_data_check.setText("Otwórz dane archiwalne")
            self.load_data_combo.removeItem(
                self.load_data_combo.findText("No data found"))
            self.load_data_combo.addItem("Nie znaleziono danych")
            self.load_data_btn.setText("Otwórz")
            self.next_button.setText("Następny")
            self.prev_button.setText("Poprzedni")
            self.column_axis.setTitle('Kanały')
            self.column_axis.setLabels([
                'Kanał 1', 'Kanał 2', 'Kanał 3', 'Kanał 4', 'Kanał 5',
                'Kanał 6', 'Kanał 7', 'Kanał 8', 'Kanał 9', 'Kanał 10',
                'Kanał 11', 'Kanał 12', 'Kanał 13'
            ])
            self.row_axis.setTitle('Oś czasu')
            self.bars.setColumnAxis(self.column_axis)
            self.bars.setRowAxis(self.row_axis)
        else:
            QCoreApplication.removeTranslator(self.trans)
            self.axis_x.setTitleText("Frequency [MHz]")
            self.freeze_check.setText("Freeze")
            self.load_data_check.setText("Load archival data")
            self.load_data_combo.removeItem(
                self.load_data_combo.findText("Nie znaleziono danych"))
            self.load_data_combo.addItem("No data found")
            self.load_data_btn.setText("Load")
            self.next_button.setText("Next")
            self.prev_button.setText("Previous")
            self.column_axis.setTitle('Channels')
            self.column_axis.setLabels([
                'Channel 1', 'Channel 2', 'Channel 3', 'Channel 4',
                'Channel 5', 'Channel 6', 'Channel 7', 'Channel 8',
                'Channel 9', 'Channel 10', 'Channel 11', 'Channel 12',
                'Channel 13'
            ])
            self.row_axis.setTitle('Timeline')
            self.bars.setColumnAxis(self.column_axis)
            self.bars.setRowAxis(self.row_axis)

    def append_data_from_database(self, data):
        """ DOCSTRING !!! """
        self.wifi_channels_occupancy_array = []
        self.wifi_channels_timestamps = []
        self.print_freshes_ten()

        for row in data:
            itm_nmbr = 0
            self.temp_db_array = []
            for item in row:
                if itm_nmbr == 1:
                    self.wifi_channels_timestamps.append(
                        "" + str(self.load_data_combo.currentText()) + " " +
                        item + "")
                elif itm_nmbr > 1:
                    self.temp_db_array.append(item)
                itm_nmbr += 1
            self.wifi_channels_occupancy_array.append(self.temp_db_array)
        self.print_freshes_ten()
Exemplo n.º 18
0
class ControlBox(qtw.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.jointlabel = QLabel("Joint name")
        self.humannum = QLabel("Human number")
        self.mkhuman = QPushButton("Create(&Z)")
        self.rmhuman = QPushButton("Remove(&x)")
        self.joint_next = QPushButton("Next_joint(&A)")
        self.joint_prev = QPushButton("Pre_joint(&S)")
        self.nextButton = QPushButton("Next")
        self.prevButton = QPushButton("Prev")

        self.jointcombo = QComboBox()
        self.jointcombo.addItem("0.nose")
        self.jointcombo.addItem("1.neck")
        self.jointcombo.addItem("2.Right shoulder")
        self.jointcombo.addItem("3.Right elbow")
        self.jointcombo.addItem("4.Right hand")
        self.jointcombo.addItem("5.Left shoulder")
        self.jointcombo.addItem("6.Left elbow")
        self.jointcombo.addItem("7.Left hand")
        self.jointcombo.addItem("8.Right hip")
        self.jointcombo.addItem("9.Right knee")
        self.jointcombo.addItem("10.Right foot")
        self.jointcombo.addItem("11.Left hip")
        self.jointcombo.addItem("12.Left knee")
        self.jointcombo.addItem("13.Left foot")
        self.jointcombo.addItem("14.Right eye")
        self.jointcombo.addItem("15.Left eye")
        self.jointcombo.addItem("16.Right ear")
        self.jointcombo.addItem("17.Left ear")

        self.humancombo = QComboBox()
        self.humancombo.addItem("None")

        self.controlBox = self.createMainControl()

        self.mkhuman.clicked.connect(self.add_new_human)
        self.rmhuman.clicked.connect(self.rm_current_human)
        self.joint_next.clicked.connect(self.next_to_joint)
        self.joint_prev.clicked.connect(self.prev_to_joint)

    def createMainControl(self):
        self.grid = QGridLayout()
        self.grid.addWidget(self.jointlabel, 0, 0)
        self.grid.addWidget(self.jointcombo, 0, 1)
        self.grid.addWidget(self.joint_next, 0, 2)
        self.grid.addWidget(self.joint_prev, 0, 3)
        self.grid.addWidget(self.humannum, 1, 0)
        self.grid.addWidget(self.humancombo, 1, 1)
        self.grid.addWidget(self.mkhuman, 1, 2)
        self.grid.addWidget(self.rmhuman, 1, 3)
        self.grid.addWidget(self.prevButton, 3, 0, 1, 1)
        self.grid.addWidget(self.nextButton, 3, 1, 1, 1)

        return self.grid

    def add_new_human(self):
        if (self.humancombo.currentText()
                == 'None') | (self.humancombo.currentText() == ''):
            self.nonenum = self.humancombo.findText('None')
            self.humancombo.removeItem(self.nonenum)
            self.humancombo.addItem('1')

        else:
            currentNum = int(self.humancombo.currentText())
            # print(currentNum)
            nextNum = currentNum
            # print('next ', nextNum)
            if nextNum < 100:
                self.humancombo.setCurrentIndex(nextNum)

    def rm_current_human(self):
        nowText = self.humancombo.currentText()
        nowNum = self.humancombo.findText(nowText)
        if nowNum >= 1:
            self.humancombo.setCurrentIndex(nowNum - 1)

    def next_to_joint(self):
        #print('現在のコンボindex', self.jointcombo.currentIndex())
        next_combo = self.jointcombo.currentIndex() + 1
        #print('次のコンボ', next_combo)
        if next_combo < 18:
            self.jointcombo.setCurrentIndex(next_combo)

    def prev_to_joint(self):
        #print('現在のコンボindex', self.jointcombo.currentIndex())
        prev_combo = self.jointcombo.currentIndex() - 1
        #print('前のコンボ', prev_combo)
        if prev_combo >= 0:
            self.jointcombo.setCurrentIndex(prev_combo)
Exemplo n.º 19
0
class WMatSelectV(QGroupBox):
    """
    Material related widget including a Label, a Combobox to select a material
    and a Button to edit a material libary.
    WMatSelect is instantiated to empty material data, so it has to be referenced
    to actual material data with the update method prior to its first usage.
    """

    # Signal to W_MachineSetup to know that the save popup is needed
    saveNeeded = Signal()

    def __init__(self, parent=None):
        """
        Set a reference to a material libray and material data path,
        updates the Combobox by the material names of the libary
        and set a referenced material by name.

        Parameters
        ----------
        self :
            A WMatSelect object
        parent :
            A reference to the widgets parent

        Returns
        -------

        """

        # Build the interface according to the .ui file
        QGroupBox.__init__(self, parent)

        self.verticalLayout = QVBoxLayout(self)
        self.c_mat_type = QComboBox(self)
        self.c_mat_type.setObjectName(u"c_mat_type")
        self.verticalLayout.addWidget(self.c_mat_type)

        self.b_matlib = QPushButton(self)
        self.b_matlib.setObjectName(u"b_matlib")
        self.b_matlib.setText("Edit Materials")
        self.verticalLayout.addWidget(self.b_matlib)

        # Create the property of the widget
        self.mat_win = None  # DMatLib widget
        self.obj = None  # object that has a material attribute
        self.mat_attr_name = ""  # material attribute name
        self.matlib = list()  # Matlib
        self.matlib_path = ""  # Path to save the matlib
        self.def_mat = "M400-50A"  # Default material
        self.is_hide_button = False  # To hide the "Edit material" button

        # Connect the signals
        self.c_mat_type.currentIndexChanged.connect(self.set_mat_type)
        self.b_matlib.clicked.connect(self.s_open_matlib)

    def update(self, obj, mat_attr_name, matlib, matlib_path=""):
        """
        Set a reference to a material libray and material data path,
        updates the Combobox by the material names of the libary
        and set a referenced material by name.

        Parameters
        ----------
        self :
            A WMatSelect object
        obj :
            A pyleecan object that has a material attribute
        mat_attr_name :
            A string of the material attribute name
        matlib :
            A material libary, i.e. a list of Material objects
        matlib_path :
            A string containing the path of material data

        Returns
        -------

        """
        self.c_mat_type.blockSignals(True)

        # Set material combobox according to matlib names
        self.obj = obj
        self.mat_attr_name = mat_attr_name
        self.matlib = matlib
        self.matlib_path = matlib_path

        if self.is_hide_button:
            self.b_matlib.hide()
        else:
            self.b_matlib.show()

        # Update the list of materials
        self.c_mat_type.clear()
        items_to_add = []
        # Add RefMatLib materials
        items_to_add.extend([mat.name for mat in matlib.dict_mat["RefMatLib"]])
        # Add machine-specific materials
        items_to_add.extend(
            [mat.name for mat in matlib.dict_mat["MachineMatLib"]])
        self.c_mat_type.addItems(items_to_add)

        mat = getattr(self.obj, mat_attr_name, None)
        if mat is None or mat.name is None:
            # Default lamination material: M400-50A
            index = self.c_mat_type.findText(self.def_mat)
            if index != -1:
                # self.mat.__init__(init_dict=self.matlib[index].as_dict())
                setattr(
                    self.obj,
                    self.mat_attr_name,
                    self.matlib.dict_mat["RefMatLib"][index],
                )
        else:
            index = self.c_mat_type.findText(mat.name)
        self.c_mat_type.setCurrentIndex(index)
        self.c_mat_type.blockSignals(False)

    def setText(self, txt):
        """
        Set the Label's text

        Parameters
        ----------
        self :
            A WMatSelect object
        txt :
            A text string

        Returns
        -------

        """
        self.setTitle(txt)

    def set_mat_type(self, index):
        """
        Signal to set the referenced material from the material libary
        by the selected Combobox index

        Parameters
        ----------
        self :
            A WMatSelect object
        index :
            Current index of the combobox

        Returns
        -------

        """
        if index >= len(self.matlib.dict_mat["RefMatLib"]):
            index -= len(self.matlib.dict_mat["RefMatLib"])
            dict_key = "MachineMatLib"
        else:
            dict_key = "RefMatLib"

        setattr(self.obj, self.mat_attr_name,
                self.matlib.dict_mat[dict_key][index])
        # Notify the machine GUI that the machine has changed
        self.saveNeeded.emit()

    def s_open_matlib(self):
        """
        Open the GUI (DMatLib widget) to Edit the Material library

        Parameters
        ----------
        self :
            A WMatSelect object

        Returns
        -------

        """
        if self.c_mat_type.currentIndex() >= len(
                self.matlib.dict_mat["RefMatLib"]):
            index = self.c_mat_type.currentIndex() - len(
                self.matlib.dict_mat["RefMatLib"])
            key = "MachineMatLib"
        else:
            index = self.c_mat_type.currentIndex()
            key = "RefMatLib"
        self.mat_win = DMatLib(self.matlib, key, index)
        self.mat_win.accepted.connect(self.set_matlib)
        self.mat_win.saveNeeded.connect(self.emit_save)
        self.mat_win.show()

    def emit_save(self):
        """
        Emit saveNeeded if a material has been edited
        """
        self.saveNeeded.emit()

    def set_matlib(self):
        """Update the matlib with the new value

        Parameters
        ----------
        self :
            A WMatSelect object

        Returns
        -------

        """
        # Empty and fill the list to keep the same object (to change it everywhere)
        # del self.matlib[:]
        # self.matlib.extend(self.mat_win.matlib)
        # Update the material
        # index = int(self.mat_win.nav_mat.currentItem().text()[:3]) - 1

        # not needed if machine materials are "connected" properly
        # mat_dict = (self.mat_win.matlib[index]).as_dict()
        # self.mat.__init__(init_dict=mat_dict)

        # Do not clear for now to keep editor (DMatLib) open
        # # Clear the window
        # self.mat_win.deleteLater()
        # self.mat_win = None

        # Update the widget
        # Avoid trigger signal currentIndexChanged
        self.c_mat_type.blockSignals(True)

        self.c_mat_type.clear()

        items_to_add = []
        # Add RefMatLib materials
        items_to_add.extend(
            [mat.name for mat in self.matlib.dict_mat["RefMatLib"]])
        # Add machine-specific materials
        items_to_add.extend(
            [mat.name for mat in self.matlib.dict_mat["MachineMatLib"]])
        self.c_mat_type.addItems(items_to_add)

        index = self.c_mat_type.findText(
            getattr(self.obj, self.mat_attr_name).name)
        self.c_mat_type.setCurrentIndex(index)

        self.c_mat_type.blockSignals(False)
Exemplo n.º 20
0
    def initialise(self):
        self.settingsFile = os.path.join(self.findNukeHomeDir(),
                                         "deadline_settings.ini")
        print("Loading settings: " + self.settingsFile)

        # Initialize the submission settings.
        self.settings = QSettings(self.settingsFile, QSettings.IniFormat)

        print("Grabbing submitter info...")
        try:
            dcOutput = CallDeadlineCommand([
                "-prettyJSON",
                "-GetSubmissionInfo",
                "Pools",
                "Groups",
                "MaxPriority",
                "TaskLimit",
                "UserHomeDir",
                "RepoDir:submission/Hiero/Main",
                "RepoDir:submission/Integration/Main",
            ],
                                           useDeadlineBg=True)
            output = json.loads(dcOutput, encoding="utf-8")
        except ValueError as e:
            print("Unable to get submitter info from Deadline:\n\n" +
                  e.message)
            raise

        if output["ok"]:
            self.submissionInfo = output["result"]
        else:
            raise ValueError(
                "DeadlineCommand returned a bad result and was unable to grab the submitter info.\n\n"
                + output["result"])

        # Get the Deadline temp directory.
        deadlineHome = self.submissionInfo["UserHomeDir"].strip()
        self.deadlineTemp = os.path.join(deadlineHome, "temp")

        self.integrationDir = self.submissionInfo["RepoDirs"][
            "submission/Integration/Main"].strip()

        # Get maximum priority.
        maximumPriority = self.submissionInfo["MaxPriority"]

        # Collect the pools and groups.
        pools = self.submissionInfo["Pools"]

        secondaryPools = [""]
        secondaryPools.extend(pools)

        groups = self.submissionInfo["Groups"]

        # Set up the other default arrays.
        onJobComplete = ("Nothing", "Archive", "Delete")
        nukeVersions = ("6.0", "6.1", "6.2", "6.3", "6.4", "7.0", "7.1", "7.2",
                        "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4", "9.0",
                        "9.1", "9.2", "9.3", "9.4", "10.0", "10.1", "10.2",
                        "10.3", "10.4", "11.0", "11.1", "11.2", "11.3")
        buildsToForce = ("None", "32bit", "64bit")

        # Main Window
        mainWindow = hiero.ui.mainWindow()
        dialog = QDialog(mainWindow)
        self.dialog = dialog
        dialog.setWindowTitle("Submit to Deadline (and render with Nuke)")

        # Main Layout
        topLayout = QVBoxLayout()
        dialog.setLayout(topLayout)
        tabWidget = QTabWidget(dialog)

        jobTab = QWidget()
        jobTabLayout = QVBoxLayout()
        jobTab.setLayout(jobTabLayout)

        # Job Info Layout
        jobInfoGroupBox = QGroupBox("Job Description")
        jobTabLayout.addWidget(jobInfoGroupBox)
        jobInfoLayout = QGridLayout()
        jobInfoGroupBox.setLayout(jobInfoLayout)

        # Job Name
        jobInfoLayout.addWidget(QLabel("Job Name"), 0, 0)
        jobNameWidget = QLineEdit(self.settings.value("JobName", ""))
        jobInfoLayout.addWidget(jobNameWidget, 0, 1)

        # Comment
        jobInfoLayout.addWidget(QLabel("Comment"), 1, 0)
        commentWidget = QLineEdit(self.settings.value("Comment", ""))
        jobInfoLayout.addWidget(commentWidget, 1, 1)

        # Department
        jobInfoLayout.addWidget(QLabel("Department"), 2, 0)
        departmentWidget = QLineEdit(self.settings.value("Department", ""))
        jobInfoLayout.addWidget(departmentWidget, 2, 1)

        # Job Options Layout
        jobOptionsGroupBox = QGroupBox("Job Options")
        jobTabLayout.addWidget(jobOptionsGroupBox)
        jobOptionsLayout = QGridLayout()
        jobOptionsGroupBox.setLayout(jobOptionsLayout)

        # Pool
        jobOptionsLayout.addWidget(QLabel("Pool"), 0, 0)
        poolWidget = QComboBox()
        for pool in pools:
            poolWidget.addItem(pool)

        defaultPool = self.settings.value("Pool", "none")
        defaultIndex = poolWidget.findText(defaultPool)
        if defaultIndex != -1:
            poolWidget.setCurrentIndex(defaultIndex)

        jobOptionsLayout.addWidget(poolWidget, 0, 1, 1, 3)

        # Secondary Pool
        jobOptionsLayout.addWidget(QLabel("Secondary Pool"), 1, 0)
        secondaryPoolWidget = QComboBox()
        for secondaryPool in secondaryPools:
            secondaryPoolWidget.addItem(secondaryPool)

        defaultSecondaryPool = self.settings.value("SecondaryPool", "")
        defaultIndex = secondaryPoolWidget.findText(defaultSecondaryPool)
        if defaultIndex != -1:
            secondaryPoolWidget.setCurrentIndex(defaultIndex)

        jobOptionsLayout.addWidget(secondaryPoolWidget, 1, 1, 1, 3)

        # Group
        jobOptionsLayout.addWidget(QLabel("Group"), 2, 0)
        groupWidget = QComboBox()
        for group in groups:
            groupWidget.addItem(group)

        defaultGroup = self.settings.value("Group", "none")
        defaultIndex = groupWidget.findText(defaultGroup)
        if defaultIndex != -1:
            groupWidget.setCurrentIndex(defaultIndex)

        jobOptionsLayout.addWidget(groupWidget, 2, 1, 1, 3)

        # Priority
        initPriority = int(self.settings.value("Priority", "50"))
        if initPriority > maximumPriority:
            initPriority = maximumPriority / 2

        jobOptionsLayout.addWidget(QLabel("Priority"), 3, 0)
        priorityWidget = QSpinBox()
        priorityWidget.setRange(0, maximumPriority)
        priorityWidget.setValue(initPriority)
        jobOptionsLayout.addWidget(priorityWidget, 3, 1)

        # Task Timeout
        jobOptionsLayout.addWidget(QLabel("Task Timeout"), 4, 0)
        taskTimeoutWidget = QSpinBox()
        taskTimeoutWidget.setRange(0, 1000000)
        taskTimeoutWidget.setValue(int(self.settings.value("TaskTimeout",
                                                           "0")))
        jobOptionsLayout.addWidget(taskTimeoutWidget, 4, 1)

        # Auto Task Timeout
        autoTaskTimeoutWidget = QCheckBox("Enable Auto Task Timeout")
        autoTaskTimeoutWidget.setChecked(
            strtobool(self.settings.value("AutoTaskTimeout", "False")))
        jobOptionsLayout.addWidget(autoTaskTimeoutWidget, 4, 2)

        # Concurrent Tasks
        jobOptionsLayout.addWidget(QLabel("Concurrent Tasks"), 5, 0)
        concurrentTasksWidget = QSpinBox()
        concurrentTasksWidget.setRange(1, 16)
        concurrentTasksWidget.setValue(
            int(self.settings.value("ConcurrentTasks", "1")))
        jobOptionsLayout.addWidget(concurrentTasksWidget, 5, 1)

        # Limit Tasks To Slave's Task Limit
        limitConcurrentTasksWidget = QCheckBox(
            "Limit Tasks To Slave's Task Limit")
        limitConcurrentTasksWidget.setChecked(
            strtobool(self.settings.value("LimitConcurrentTasks", "True")))
        jobOptionsLayout.addWidget(limitConcurrentTasksWidget, 5, 2)

        # Machine Limit
        jobOptionsLayout.addWidget(QLabel("Machine Limit"), 6, 0)
        machineLimitWidget = QSpinBox()
        machineLimitWidget.setRange(0, 1000000)
        machineLimitWidget.setValue(
            int(self.settings.value("MachineLimit", "1")))
        jobOptionsLayout.addWidget(machineLimitWidget, 6, 1)

        # Machine List Is A Blacklist
        isBlacklistWidget = QCheckBox("Machine List Is A Blacklist")
        isBlacklistWidget.setChecked(
            strtobool(self.settings.value("IsBlacklist", "False")))
        jobOptionsLayout.addWidget(isBlacklistWidget, 6, 2)

        # Machine List
        jobOptionsLayout.addWidget(QLabel("Machine List"), 7, 0)
        machineListWidget = QLineEdit(self.settings.value("MachineList", ""))
        jobOptionsLayout.addWidget(machineListWidget, 7, 1, 1, 2)

        def browseMachineList():
            output = CallDeadlineCommand(
                ["-selectmachinelist",
                 str(machineListWidget.text())], False)
            output = output.replace("\r", "").replace("\n", "")
            if output != "Action was cancelled by user":
                machineListWidget.setText(output)

        machineListButton = QPushButton("Browse")
        machineListButton.pressed.connect(browseMachineList)
        jobOptionsLayout.addWidget(machineListButton, 7, 3)

        # Limits
        jobOptionsLayout.addWidget(QLabel("Limits"), 8, 0)
        limitsWidget = QLineEdit(self.settings.value("Limits", ""))
        jobOptionsLayout.addWidget(limitsWidget, 8, 1, 1, 2)

        def browseLimitList():
            output = CallDeadlineCommand(
                ["-selectlimitgroups",
                 str(limitsWidget.text())], False)
            output = output.replace("\r", "").replace("\n", "")
            if output != "Action was cancelled by user":
                limitsWidget.setText(output)

        limitsButton = QPushButton("Browse")
        limitsButton.pressed.connect(browseLimitList)
        jobOptionsLayout.addWidget(limitsButton, 8, 3)

        # On Job Complete
        jobOptionsLayout.addWidget(QLabel("On Job Complete"), 9, 0)
        onJobCompleteWidget = QComboBox()
        for option in onJobComplete:
            onJobCompleteWidget.addItem(option)

        defaultOption = self.settings.value("OnJobComplete", "Nothing")
        defaultIndex = onJobCompleteWidget.findText(defaultOption)
        if defaultIndex != -1:
            onJobCompleteWidget.setCurrentIndex(defaultIndex)

        jobOptionsLayout.addWidget(onJobCompleteWidget, 9, 1)

        # Submit Job As Suspended
        submitSuspendedWidget = QCheckBox("Submit Job As Suspended")
        submitSuspendedWidget.setChecked(
            strtobool(self.settings.value("SubmitSuspended", "False")))
        jobOptionsLayout.addWidget(submitSuspendedWidget, 9, 2)

        # Nuke Options
        nukeOptionsGroupBox = QGroupBox("Nuke Options")
        jobTabLayout.addWidget(nukeOptionsGroupBox)
        nukeOptionsLayout = QGridLayout()
        nukeOptionsGroupBox.setLayout(nukeOptionsLayout)

        # Version
        nukeOptionsLayout.addWidget(QLabel("Version"), 0, 0)
        versionWidget = QComboBox()
        for version in nukeVersions:
            versionWidget.addItem(version)

        defaultVersion = self.settings.value("Version", "7.0")
        defaultIndex = versionWidget.findText(defaultVersion)
        if defaultIndex != -1:
            versionWidget.setCurrentIndex(defaultIndex)

        nukeOptionsLayout.addWidget(versionWidget, 0, 1)

        # Submit Nuke Script File With Job
        submitScriptWidget = QCheckBox("Submit Nuke Script File With Job")
        submitScriptWidget.setChecked(
            strtobool(self.settings.value("SubmitScript", "False")))
        nukeOptionsLayout.addWidget(submitScriptWidget, 0, 2)

        # Build To Force
        nukeOptionsLayout.addWidget(QLabel("Build To Force"), 1, 0)
        buildWidget = QComboBox()
        for build in buildsToForce:
            buildWidget.addItem(build)

        defaultBuild = self.settings.value("Build", "None")
        defaultIndex = buildWidget.findText(defaultBuild)
        if defaultIndex != -1:
            buildWidget.setCurrentIndex(defaultIndex)

        nukeOptionsLayout.addWidget(buildWidget, 1, 1)

        # Render With NukeX
        useNukeXWidget = QCheckBox("Render With NukeX")
        useNukeXWidget.setChecked(
            strtobool(self.settings.value("UseNukeX", "False")))
        nukeOptionsLayout.addWidget(useNukeXWidget, 1, 2)

        # Max RAM Usage (MB)
        nukeOptionsLayout.addWidget(QLabel("Max RAM Usage (MB)"), 2, 0)
        memoryWidget = QSpinBox()
        memoryWidget.setRange(0, 5000)
        memoryWidget.setValue(int(self.settings.value("Memory", "0")))
        nukeOptionsLayout.addWidget(memoryWidget, 2, 1)

        # Continue On Error
        continueOnErrorWidget = QCheckBox("Continue On Error")
        continueOnErrorWidget.setChecked(
            strtobool(self.settings.value("ContinueOnError", "False")))
        nukeOptionsLayout.addWidget(continueOnErrorWidget, 2, 2)

        # Threads
        nukeOptionsLayout.addWidget(QLabel("Threads"), 3, 0)
        threadsWidget = QSpinBox()
        threadsWidget.setRange(0, 256)
        threadsWidget.setValue(int(self.settings.value("Threads", "0")))
        nukeOptionsLayout.addWidget(threadsWidget, 3, 1)

        # Use Batch Mode
        batchModeWidget = QCheckBox("Use Batch Mode")
        batchModeWidget.setChecked(
            strtobool(self.settings.value("BatchMode", "False")))
        nukeOptionsLayout.addWidget(batchModeWidget, 3, 2)

        # Frames Per Task
        nukeOptionsLayout.addWidget(QLabel("Frames Per Task"), 4, 0)
        framesPerTaskWidget = QSpinBox()
        framesPerTaskWidget.setRange(1, 1000000)
        framesPerTaskWidget.setValue(
            int(self.settings.value("FramesPerTask", "1")))
        nukeOptionsLayout.addWidget(framesPerTaskWidget, 4, 1)
        nukeOptionsLayout.addWidget(
            QLabel("(this only affects non-movie jobs)"), 4, 2)

        tabWidget.addTab(jobTab, "Job Options")

        # Button Box (Extra work required to get the custom ordering we want)
        self.pipelineToolStatusLabel.setAlignment(Qt.AlignRight
                                                  | Qt.AlignVCenter)
        pipelineToolStatus = self.retrievePipelineToolStatus()
        self.updatePipelineToolStatusLabel(pipelineToolStatus)

        integrationButton = QPushButton("Pipeline Tools")
        integrationButton.clicked.connect(self.OpenIntegrationWindow)

        submitButton = QPushButton("Submit")
        submitButton.clicked.connect(dialog.accept)
        submitButton.setDefault(True)

        cancelButton = QPushButton("Cancel")
        cancelButton.clicked.connect(dialog.reject)

        buttonGroupBox = QGroupBox()
        buttonLayout = QGridLayout()
        buttonLayout.setColumnStretch(
            0, 1)  # Makes the pipeline status label expand, not the buttons
        buttonGroupBox.setLayout(buttonLayout)
        buttonGroupBox.setAlignment(Qt.AlignRight)
        buttonGroupBox.setFlat(True)
        buttonLayout.addWidget(self.pipelineToolStatusLabel, 0, 0)
        buttonLayout.addWidget(integrationButton, 0, 1)
        buttonLayout.addWidget(submitButton, 0, 2)
        buttonLayout.addWidget(cancelButton, 0, 3)

        topLayout.addWidget(tabWidget)
        topLayout.addWidget(buttonGroupBox)

        # Show the dialog.
        result = (dialog.exec_() == QDialog.DialogCode.Accepted)
        if result:
            # Need to pass integration dir path to render task
            self.settings.setValue("IntegrationDir", self.integrationDir)

            self.settings.setValue("JobName", jobNameWidget.text())
            self.settings.setValue("Comment", commentWidget.text())
            self.settings.setValue("Department", departmentWidget.text())
            self.settings.setValue("Pool", poolWidget.currentText())
            self.settings.setValue("SecondaryPool",
                                   secondaryPoolWidget.currentText())
            self.settings.setValue("Group", groupWidget.currentText())
            self.settings.setValue("Priority", priorityWidget.value())
            self.settings.setValue("TaskTimeout", taskTimeoutWidget.value())
            self.settings.setValue("AutoTaskTimeout",
                                   str(autoTaskTimeoutWidget.isChecked()))
            self.settings.setValue("ConcurrentTasks",
                                   concurrentTasksWidget.value())
            self.settings.setValue("LimitConcurrentTasks",
                                   str(limitConcurrentTasksWidget.isChecked()))
            self.settings.setValue("MachineLimit", machineLimitWidget.value())
            self.settings.setValue("IsBlacklist",
                                   str(isBlacklistWidget.isChecked()))
            self.settings.setValue("MachineList", machineListWidget.text())
            self.settings.setValue("Limits", limitsWidget.text())
            self.settings.setValue("OnJobComplete",
                                   onJobCompleteWidget.currentText())
            self.settings.setValue("SubmitSuspended",
                                   str(submitSuspendedWidget.isChecked()))
            self.settings.setValue("Version", versionWidget.currentText())
            self.settings.setValue("SubmitScript",
                                   str(submitScriptWidget.isChecked()))
            self.settings.setValue("Build", buildWidget.currentText())
            self.settings.setValue("UseNukeX", str(useNukeXWidget.isChecked()))
            self.settings.setValue("FramesPerTask",
                                   framesPerTaskWidget.value())
            self.settings.setValue("ContinueOnError",
                                   str(continueOnErrorWidget.isChecked()))
            self.settings.setValue("Threads", threadsWidget.value())
            self.settings.setValue("BatchMode",
                                   str(batchModeWidget.isChecked()))
            self.settings.setValue("Memory", memoryWidget.value())

            print("Saving settings: " + self.settingsFile)
            self.settings.sync()
        else:
            print("Submission canceled")
            self.settings = None
            # Not sure if there is a better way to stop the export process. This works, but it leaves all the tasks
            # in the Queued state.
            self.setError("Submission was canceled")
Exemplo n.º 21
0
class SaveTab(QWidget):
    def __init__(self, parent):
        """Initialize the save tab
        """

        super(SaveTab, self).__init__(parent)

        self.prefs = parent.prefs
        self.order_options = {'SortedOrder': 'Sorted (based on IDD file)',
                              'OriginalOrderTop': 'Original order (With new objects on top)',
                              'OriginalOrderBottom': 'Original order (With new objects on bottom)'}
        self.format_options = {'UseSpecialFormat': 'Use special formatting for some objects',
                               'None': 'Do not use special formatting'}

        # Sort Order Code
        order_label = QLabel("Save Order for Objects:")
        self.order_edit = QComboBox(self)
        self.order_edit.addItems(list(self.order_options.values()))
        self.order_edit.setMaximumWidth(350)
        order_setting = self.order_options[self.prefs['sort_order']]
        self.order_edit.setCurrentIndex(self.order_edit.findText(order_setting))
        self.order_edit.currentIndexChanged.connect(self.update_order)

        format_label = QLabel("Special Formatting:")
        self.format_edit = QComboBox(self)
        self.format_edit.addItems(list(self.format_options.values()))
        self.format_edit.setMaximumWidth(350)
        format_setting = self.format_options[self.prefs['special_formatting']]
        self.format_edit.setCurrentIndex(self.format_edit.findText(format_setting))
        self.order_edit.currentIndexChanged.connect(self.update_format)

        self.save_group_box = QGroupBox("Default Save Options")
        save_box = QVBoxLayout()
        save_box.addWidget(order_label)
        save_box.addWidget(self.order_edit)
        save_box.addSpacing(10)
        save_box.addWidget(format_label)
        save_box.addWidget(self.format_edit)
        save_box.addStretch(1)
        self.save_group_box.setLayout(save_box)
        self.save_group_box.setEnabled(False)

        # Save additional options code
        self.save_units_check = QCheckBox('Units to display by default (SI vs IP)', self)
        checked_header = Qt.Checked if self.prefs['save_units'] == 1 else Qt.Unchecked
        self.save_units_check.setCheckState(checked_header)
        self.save_units_check.stateChanged.connect(self.update)
        self.save_hidden_classes_check = QCheckBox('Whether empty classes are hidden', self)
        checked_cells = Qt.Checked if self.prefs['save_hidden_classes'] == 1 else Qt.Unchecked
        self.save_hidden_classes_check.setCheckState(checked_cells)
        self.save_hidden_classes_check.stateChanged.connect(self.update)
        self.save_groups_check = QCheckBox('Whether to hide group headers', self)
        checked_groups = Qt.Checked if self.prefs['save_hide_groups'] == 1 else Qt.Unchecked
        self.save_groups_check.setCheckState(checked_groups)
        self.save_groups_check.stateChanged.connect(self.update)

        # Save additional options group box code
        self.save_additional_group_box = QGroupBox("Save Additional Options in IDF File")
        save_additional_box = QVBoxLayout()
        save_additional_box.addWidget(self.save_units_check)
        save_additional_box.addWidget(self.save_hidden_classes_check)
        save_additional_box.addWidget(self.save_groups_check)
        save_additional_box.addStretch(1)
        self.save_additional_group_box.setLayout(save_additional_box)

        # Main layout code
        main_layout = QVBoxLayout()
        main_layout.addWidget(self.save_additional_group_box)
        main_layout.addSpacing(10)
        main_layout.addWidget(self.save_group_box)
        main_layout.addStretch(1)
        self.setLayout(main_layout)

    def update_order(self):
        text = self.order_edit.currentText()
        for key, val in list(self.order_options.items()):
            if val == text:
                to_save = key
        self.prefs['sort_order'] = to_save

    def update_format(self):
        text = self.format_edit.currentText()
        for key, val in self.format_options.items():
            if val == text:
                to_save = key
        self.prefs['format'] = to_save

    def update(self):
        self.prefs['save_units'] = 1 if self.save_units_check.checkState() else 0
        self.prefs['save_hidden_classes'] = 1 if self.save_hidden_classes_check.checkState() else 0
        self.prefs['save_hide_groups'] = 1 if self.save_groups_check.checkState() else 0
Exemplo n.º 22
0
class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        layout = QHBoxLayout()

        self.ax = pg.PlotWidget()
        self.ax.showGrid(True, True)

        self.line = pg.InfiniteLine(
            pos=-20,
            pen=pg.mkPen('k', width=3),
            movable=False  # We have our own code to handle dragless moving.
        )

        self.ax.addItem(self.line)
        self.ax.setLimits(xMin=-HISTORIC_DAYS_N + 1, xMax=0)
        self.ax.getPlotItem().scene().sigMouseMoved.connect(
            self.mouse_move_handler)

        self.base_currency = DEFAULT_BASE_CURRENCY

        # Store a reference to lines on the plot, and items in our
        # data viewer we can update rather than redraw.
        self._data_lines = dict()
        self._data_items = dict()
        self._data_colors = dict()
        self._data_visible = DEFAULT_DISPLAY_CURRENCIES

        self._last_updated = None

        self.listView = QTableView()
        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels(["Currency", "Rate"])
        self.model.itemChanged.connect(self.check_check_state)

        self.listView.setModel(self.model)

        self.threadpool = QThreadPool()
        self.worker = False

        layout.addWidget(self.ax)
        layout.addWidget(self.listView)

        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)
        self.listView.setFixedSize(226, 400)
        self.setFixedSize(650, 400)

        toolbar = QToolBar("Main")
        self.addToolBar(toolbar)
        self.currencyList = QComboBox()

        toolbar.addWidget(self.currencyList)
        self.update_currency_list(DEFAULT_DISPLAY_CURRENCIES)
        self.currencyList.setCurrentText(self.base_currency)
        self.currencyList.currentTextChanged.connect(self.change_base_currency)

        self.progress = QProgressBar()
        self.progress.setRange(0, 100)
        toolbar.addWidget(self.progress)

        self.refresh_historic_rates()
        self.setWindowTitle("Doughnut")
        self.show()

    def update_currency_list(self, currencies):
        for currency in currencies:
            if self.currencyList.findText(currency) == -1:
                self.currencyList.addItem(currency)

        self.currencyList.model().sort(0)

    def check_check_state(self, i):
        if not i.isCheckable():  # Skip data columns.
            return

        currency = i.text()
        checked = i.checkState() == Qt.Checked

        if currency in self._data_visible:
            if not checked:
                self._data_visible.remove(currency)
                self.redraw()
        else:
            if checked:
                self._data_visible.append(currency)
                self.redraw()

    def get_currency_color(self, currency):
        if currency not in self._data_colors:
            self._data_colors[currency] = next(BREWER12PAIRED)

        return self._data_colors[currency]

    def add_data_row(self, currency):
        citem = QStandardItem()
        citem.setText(currency)
        citem.setForeground(QBrush(QColor(self.get_currency_color(currency))))
        citem.setColumnCount(2)
        citem.setCheckable(True)
        if currency in DEFAULT_DISPLAY_CURRENCIES:
            citem.setCheckState(Qt.Checked)

        vitem = QStandardItem()

        vitem.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.model.setColumnCount(2)
        self.model.appendRow([citem, vitem])
        self.model.sort(0)
        return citem, vitem

    def get_or_create_data_row(self, currency):
        if currency not in self._data_items:
            self._data_items[currency] = self.add_data_row(currency)
        return self._data_items[currency]

    def mouse_move_handler(self, pos):
        pos = self.ax.getViewBox().mapSceneToView(pos)
        self.line.setPos(pos.x())
        self.update_data_viewer(int(pos.x()))

    def update_data_row(self, currency, value):
        citem, vitem = self.get_or_create_data_row(currency)
        vitem.setText("%.4f" % value)

    def update_data_viewer(self, d):
        try:
            data = self.data[d]
        except IndexError:  # Skip update if out of bounds.
            return

        if not data:  # Skip update if we have no data.
            return

        for k, v in data.items():
            self.update_data_row(k, v)

    def change_base_currency(self, currency):
        self.base_currency = currency
        self.refresh_historic_rates()

    def refresh_historic_rates(self):
        if self.worker:
            # If we have a current worker, send a kill signal
            self.worker.signals.cancel.emit()

        # Prefill our data store with None ('no data')
        self.data = [None] * HISTORIC_DAYS_N

        self.worker = UpdateWorker(self.base_currency)
        # Handle callbacks with data and trigger refresh.
        self.worker.signals.data.connect(self.result_data_callback)
        self.worker.signals.finished.connect(self.refresh_finished)
        self.worker.signals.progress.connect(self.progress_callback)
        self.threadpool.start(self.worker)

    def result_data_callback(self, n, rates):
        self.data[n] = rates

        # Refresh plot if we haven't for >1 second.
        if (self._last_updated is None
                or self._last_updated < datetime.now() - timedelta(seconds=1)):
            self.redraw()
            self._last_updated = datetime.now()

    def progress_callback(self, progress):
        self.progress.setValue(progress)

    def refresh_finished(self):
        self.worker = False
        self.redraw()
        # Ensure all currencies we know about are in the dropdown list now.
        self.update_currency_list(self._data_items.keys())

    def redraw(self):
        """
        Process data from store and prefer to draw.
        :return:
        """
        today = date.today()
        plotd = defaultdict(list)
        x_ticks = []

        tick_step_size = HISTORIC_DAYS_N / 6
        # Pre-process data into lists of x, y values
        for n, data in enumerate(self.data):
            if data:
                for currency, v in data.items():
                    plotd[currency].append((-n, v))

            when = today - timedelta(days=n)
            if (n - tick_step_size // 2) % tick_step_size == 0:
                x_ticks.append((-n, when.strftime('%d-%m')))

        # Update the plot
        keys = sorted(plotd.keys())
        y_min, y_max = sys.maxsize, 0

        for currency in keys:
            x, y = zip(*plotd[currency])

            if currency in self._data_visible:
                y_min = min(y_min, *y)
                y_max = max(y_max, *y)
            else:
                x, y = [], []

            if currency in self._data_lines:
                self._data_lines[currency].setData(x, y)
            else:
                self._data_lines[currency] = self.ax.plot(
                    x,
                    y,  # Unpack a list of tuples into two lists, passed as individual args.
                    pen=pg.mkPen(self.get_currency_color(currency), width=2))

        self.ax.setLimits(yMin=y_min * 0.9, yMax=y_max * 1.1)
        self.ax.getAxis('bottom').setTicks([x_ticks, []])
Exemplo n.º 23
0
class mainScreen(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        self.setWindowTitle('PER Lap Timer')

        self.connectionStatus = 'Disconnected'
        self.stopEvent = threading.Event()
        self.lastLapNumber = 0
        self.lastLapTime = 0

        self.connectionLabel = QLabel(self.connectionStatus)
        self.connectButton = QPushButton('Connect')
        self.lapNumberLabel = QLabel('Lap Number')
        self.lapTimeLabel = QLabel('Lap Time')
        self.lapNumber = QLabel('')
        self.lapTime = QLabel('')
        self.filler = QLabel(' ')
        self.portBox = QComboBox()
        self.portBox.addItem('Port')

        self.layout = QGridLayout()

        self.layout.addWidget(self.connectionLabel, 0, 0, 1, 2)
        self.layout.addWidget(self.lapNumberLabel, 1, 0, 1, 1)
        self.layout.addWidget(self.lapTimeLabel, 1, 4, 1, 1)
        self.layout.addWidget(self.lapNumber, 2, 0, 1, 1)
        self.layout.addWidget(self.lapTime, 2, 4, 1, 1)
        self.layout.addWidget(self.filler, 3, 0, 1, 4)
        self.layout.addWidget(self.portBox, 5, 0, 1, 3)
        self.layout.addWidget(self.connectButton, 5, 4, 1, 2)

        self.setLayout(self.layout)
        self.connectButton.clicked.connect(self.connect)
        self.portBox.activated.connect(self.comboHandler)

        self.findThread = threading.Thread(name='portFind',
                                           target=self.findPorts)
        self.findThread.setDaemon(True)
        self.findThread.start()

    def findPorts(self):
        while True:
            oldPorts = []
            if sys.platform.startswith('win'):
                ports = ['COM%s' % (i + 1) for i in range(256)]
            elif sys.platform.startswith('linux') or sys.platform.startswith(
                    'cygwin'):
                ports = glob.glob('/dev/tty[A-Za-z]*')
            elif sys.platform.startswith('darwin'):
                ports = glob.glob('/dev/tty.*')
            else:
                raise EnvironmentError('Unsupported platform')

            if oldPorts != ports:
                self.portBox.clear()
                self.portBox.addItem('Port')
                for port in ports:
                    self.portBox.addItem(port)
                try:
                    index = self.portBox.findText(self.port)
                except:
                    index = 0
                self.portBox.setCurrentIndex(index)

            oldPorts = ports
            time.sleep(5)

    def setStatusLabel(self):
        self.connectionLabel.setText(self.connectionStatus)

    def connect(self):
        try:
            self.serialStream = serial.Serial(self.port, 9600, timeout=10)
        except:
            self.connectionLabel.setText('Could not connect to lap timer!')
            t = Timer(3, self.setStatusLabel)
            t.start()

            return None
        self.connectionStatus = 'Connected'
        self.connectionLabel.setText(self.connectionStatus)
        self.connectButton.setText('   Stop   ')
        self.connectButton.clicked.connect(self.stop)
        self.stopEvent.clear()

        self.daemonRead = threading.Thread(name='serialRead',
                                           target=logSerial,
                                           args=(self, ))
        self.daemonRead.setDaemon(True)
        self.daemonRead.start()

    def stop(self):
        self.stopEvent.set()
        try:
            self.serialStream.close()
        except:
            None
        self.connectionStatus = 'Disconnected'
        self.connectionLabel.setText('Device disconnected')
        self.connectButton.setText('Connect')
        self.connectButton.clicked.connect(self.connect)
        t = Timer(3, self.setStatusLabel)
        t.start()

    def comboHandler(self, index):
        self.port = self.portBox.itemText(index)
Exemplo n.º 24
0
class MainWidget(QWidget):

    # CONSTANTS
    EMPTY_STRING = ""

    # TOGGLE BUTTON CONSTANTS
    BUTTON_CLOSED_ICON_PATH = 'resources/menu_closed_button_icon.png'
    BUTTON_OPENED_ICON_PATH = 'resources/menu_opened_button_icon.png'

    TOOGLE_BUTTON_CSS_PROPERTY = "QPushButton {background-color: rgb(1,150,250); border:  none ; qproperty-iconSize: 80px}"
    CURRENT_PATH_LINE_EDIT_PROPERTY = "QLineEdit {background-color: rgba(240, 240, 240, 1);}"

    TOOGLE_CLOSED_COLOR = "background-color: rgb(1,150,250);"
    TOOGLE_OPENED_COLOR = "background-color: rgba(44, 53, 57, 0.2);"

    WHITE = "background-color: rgb(255, 255, 255);"

    FRAME_BUTTON_STYLE = "background-color: rgb(0, 191, 255); color: rgb(255, 255, 255);"
    FRAME_LINE_EDIT_STYLE = "background-color: rgb(255, 255, 255); color: rgb(0, 0, 0);"
    FRAME_LABEL_STYLE = "QLabel { background-color : rgba(44, 53, 57, 0); }"

    SEARCH_ICON_STYLE = "QPushButton {background-color: rgb(1,150,250);}"
    BACK_ICON_STYLE = "QPushButton {background-color: rgb(1,150,250);} QPushButton:pressed {background-color: rgb(40,170,250);}"

    WIDTH = 1440
    HEIGHT = 900

    # Size of the operations widget buttons
    OPERATION_BUTTON_WIDTH = 40
    OPERATION_BUTTON_HEIGHT = 40

    FILES_LIST_VIEW_WIDTH = 820
    FILES_LIST_VIEW_HEIGHT = 680

    TOGGLE_BUTTON_ANIMATION_DURATION = 200
    RIGHT_MENU_ANIMATION_DURATION = 250

    # ICONS PATHS

    # Actions icons
    ADD_FILE_ICON_PATH = "resources/add_file_icon.png"
    ADD_DIRECTORY_ICON_PATH = "resources/add_directory_icon.png"
    COPY_ELEMENT_ICON_PATH = "resources/copy_element_icon.png"
    MOVE_ELEMENT_ICON_PATH = "resources/move_element_icon.png"
    DELETE_ELEMENT_ICON_PATH = "resources/delete_element_icon.png"
    SEARCH_ICON_PATH = "resources/search_icon_white.png"
    CREATE_ARCHIVE_ICON_PATH = "resources/create_archive_icon.png"
    UNARCHIVE_FILE_ICON_PATH = "resources/unarchive_file_icon.png"
    RENAME_ELEMENT_ICON_PATH = "resources/rename_icon_white.png"
    BACK_ICON_PATH = "resources/back_icon.png"

    # Elements icons
    FILE_ICON_PATH = "resources/file_icon.png"
    FOLDER_ICON_PATH = "resources/folder_icon.png"
    ZIP_ICON_PATH = "resources/zip_icon.png"

    # Tooltips
    COPY_TOOLTIP = "Copy files / folders"
    MOVE_TOOLTIP = "Move files / folders"
    DELETE_TOOLTIP = "Delete files / folders"
    ARCHIVE_TOOLTIP = "Archive files / folders"
    UNARCHIVE_TOOLTIP = "Unarchive files / folders"
    CREATE_FILE_TOOLTIP = "Create a new text file"
    CREATE_DIRECTORY_TOOLTIP = "Create a new folder"
    RENAME_TOOLTIP = "Rename a file / folder"
    BACK_TOOLTIP = "Move up one directory"

    # Buttons name
    COPY = "Copy"
    MOVE = "Move"
    DELETE = "Delete"
    ARCHIVE = "Archive"
    UNARCHIVE = "Unarchive"
    RENAME = "Rename"
    CREATE_FILE = "Create file"
    CREATE_FOLDER = "Create folder"

    # Labels
    SELECTED_ITEMS_TEXT = "Selected items:"
    ARCHIVE_NAME_TEXT = "Archive name:"
    CREATE_FILE_NAME_TEXT = "File name:"
    CREATE_FOLDER_NAME_TEXT = "Folder name:"
    RENAME_ELEMENT_TEXT = "New name:"

    def __init__(self, parent, model, controller):
        super(MainWidget, self).__init__(parent)

        self._model = model
        self._controller = controller

        # FILES LIST VIEW

        self.filesListView = FilesListView(self.FILES_LIST_VIEW_WIDTH,
                                           self.FILES_LIST_VIEW_HEIGHT,
                                           self._model, self._controller, self)
        self.filesListView.move(230, 120)

        # TREE VIEW FOR SYSTEM DIRECTORY HIERARCHY
        self.treeView = TreeView(self._model, self._controller, self)
        self.treeView.setFixedSize(200, 820)
        self.treeView.move(0, 60)

        # DISC SELECTION COMBO BOX
        self.discSelectionComboBox = QComboBox(self)
        self.discSelectionComboBox.setFixedSize(100, 30)
        self.discSelectionComboBox.move(230, 60)
        self.discSelectionComboBox.addItems(self._model.combo_box_list)

        # CONNECT WIDGETS TO CONTROLLER
        self.discSelectionComboBox.currentTextChanged.connect(
            self._controller.change_combo_box_selection)

        # LISTEN FOR MODEL EVENT SIGNALS
        self._model.combo_box_selection_changed.connect(
            self.on_combo_box_selection_changed)

        self.frameRightMenu = QWidget(self)
        self.frameRightMenu.setFixedSize(360, self.HEIGHT)
        self.frameRightMenu.move(1450, 15)
        self.frameRightMenu.setStyleSheet(self.TOOGLE_CLOSED_COLOR)

        # BUTTON WHICH TOOGLE ON/OFF THE TREE VIEW CONTAINING THE SELECTED ITEMS TREE VIEW
        self.toggleButton = QPushButton(QIcon(self.BUTTON_CLOSED_ICON_PATH),
                                        self.EMPTY_STRING, self)
        self.toggleButton.setFixedSize(100, 70)
        self.toggleButton.move(1300, 0)
        self.toggleButton.setStyleSheet(self.TOOGLE_BUTTON_CSS_PROPERTY)

        self._enable = True

        self.toggleButton.clicked.connect(
            lambda: Animations.toggleMenu(self, self._enable))

        # Label that shows "Selected items:"
        self.selectedItemsLabel = QLabel(self.SELECTED_ITEMS_TEXT,
                                         self.frameRightMenu)
        self.selectedItemsLabel.move(100, 20)
        self.selectedItemsLabel.setStyleSheet(self.FRAME_LABEL_STYLE)

        # The list with selected elements from FilesListView
        self.selectedFilesListWidget = QListWidget(self.frameRightMenu)
        self.selectedFilesListWidget.setFixedSize(320, 500)
        self.selectedFilesListWidget.move(23, 60)
        self.selectedFilesListWidget.setStyleSheet(self.WHITE)

        # ACTIONS BUTTONS

        # Copy button
        self.copyElementButton = OperationsWidgetButton(
            QIcon(self.COPY_ELEMENT_ICON_PATH), self.EMPTY_STRING, self)
        self.copyElementButton.clicked.connect(self.doCopy)
        self.copyElementButton.move(230, 0)
        self.copyElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH,
                                            self.OPERATION_BUTTON_HEIGHT)
        self.copyElementButton.setToolTip(self.COPY_TOOLTIP)

        # Move button
        self.moveElementButton = OperationsWidgetButton(
            QIcon(self.MOVE_ELEMENT_ICON_PATH), self.EMPTY_STRING, self)
        self.moveElementButton.clicked.connect(self.doMove)
        self.moveElementButton.move(290, 0)
        self.moveElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH,
                                            self.OPERATION_BUTTON_HEIGHT)
        self.moveElementButton.setToolTip(self.MOVE_TOOLTIP)

        # Delete button
        self.deleteElementButton = OperationsWidgetButton(
            QIcon(self.DELETE_ELEMENT_ICON_PATH), self.EMPTY_STRING, self)
        self.deleteElementButton.clicked.connect(self.doDelete)
        self.deleteElementButton.move(350, 0)
        self.deleteElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH,
                                              self.OPERATION_BUTTON_HEIGHT)
        self.deleteElementButton.setToolTip(self.DELETE_TOOLTIP)

        # Archive button
        self.archiveElementButton = OperationsWidgetButton(
            QIcon(self.CREATE_ARCHIVE_ICON_PATH), self.EMPTY_STRING, self)
        self.archiveElementButton.clicked.connect(self.doArchive)
        self.archiveElementButton.move(410, 0)
        self.archiveElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH,
                                               self.OPERATION_BUTTON_HEIGHT)
        self.archiveElementButton.setToolTip(self.ARCHIVE_TOOLTIP)

        # Unarchive button
        self.unarchiveElementButton = OperationsWidgetButton(
            QIcon(self.UNARCHIVE_FILE_ICON_PATH), self.EMPTY_STRING, self)
        self.unarchiveElementButton.clicked.connect(self.doUnarchive)
        self.unarchiveElementButton.move(470, 0)
        self.unarchiveElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH,
                                                 self.OPERATION_BUTTON_HEIGHT)
        self.unarchiveElementButton.setToolTip(self.UNARCHIVE_TOOLTIP)

        # Add file button
        self.addFileButton = OperationsWidgetButton(
            QIcon(self.ADD_FILE_ICON_PATH), self.EMPTY_STRING, self)
        self.addFileButton.clicked.connect(self.doCreateFile)
        self.addFileButton.move(530, 0)
        self.addFileButton.setFixedSize(self.OPERATION_BUTTON_WIDTH,
                                        self.OPERATION_BUTTON_HEIGHT)
        self.addFileButton.setToolTip(self.CREATE_FILE_TOOLTIP)

        # Add directory button
        self.addDirectoryButton = OperationsWidgetButton(
            QIcon(self.ADD_DIRECTORY_ICON_PATH), self.EMPTY_STRING, self)
        self.addDirectoryButton.clicked.connect(self.doCreateFolder)
        self.addDirectoryButton.move(590, 0)
        self.addDirectoryButton.setFixedSize(self.OPERATION_BUTTON_WIDTH,
                                             self.OPERATION_BUTTON_HEIGHT)
        self.addDirectoryButton.setToolTip(self.CREATE_DIRECTORY_TOOLTIP)

        # Move button
        self.renameElementButton = OperationsWidgetButton(
            QIcon(self.RENAME_ELEMENT_ICON_PATH), self.EMPTY_STRING, self)
        self.renameElementButton.clicked.connect(self.doRename)
        self.renameElementButton.move(650, 0)
        self.renameElementButton.setFixedSize(self.OPERATION_BUTTON_WIDTH,
                                              self.OPERATION_BUTTON_HEIGHT)
        self.renameElementButton.setToolTip(self.RENAME_TOOLTIP)

        # Text field needed for displaying the current path
        self.currentPathLineEdit = QLineEdit(self.EMPTY_STRING, self)
        self.currentPathLineEdit.move(350, 80)
        self.currentPathLineEdit.setFixedSize(400, 27)
        self.currentPathLineEdit.setStyleSheet(
            self.CURRENT_PATH_LINE_EDIT_PROPERTY)
        self.currentPathLineEdit.setReadOnly(True)
        self.currentPathLineEdit.setText(self._model.current_path)
        self.currentPathLineEdit.textChanged.connect(
            self._controller.change_current_path_text)

        self._model.current_path_changed.connect(self.on_current_path_changed)

        # Text field needed for searching file / folder by the name
        self.searchLineEdit = QLineEdit(self.EMPTY_STRING, self)
        self.searchLineEdit.move(810, 80)
        self.searchLineEdit.setFixedSize(200, 27)
        self.searchLineEdit.textChanged.connect(
            self._controller.change_search_text)

        self._model.current_search_changed.connect(
            self.on_current_search_changed)

        self.searchIconButton = OperationsWidgetButton(
            QIcon(self.SEARCH_ICON_PATH), self.EMPTY_STRING, self)
        self.searchIconButton.move(1015, 78)
        self.searchIconButton.setFixedSize(30, 30)
        self.searchIconButton.setStyleSheet(self.SEARCH_ICON_STYLE)
        self.searchIconButton.setEnabled(False)

        self.backButton = OperationsWidgetButton(QIcon(self.BACK_ICON_PATH),
                                                 self.EMPTY_STRING, self)
        self.backButton.clicked.connect(self.doBack)
        self.backButton.move(765, 80)
        self.backButton.setFixedSize(25, 25)
        self.backButton.setStyleSheet(self.BACK_ICON_STYLE)
        self.backButton.setToolTip(self.BACK_TOOLTIP)
        self.backButton.setEnabled(True)

        # ACTIONS LABELS
        self.archiveLabel = QLabel(self.ARCHIVE_NAME_TEXT, self.frameRightMenu)
        self.createFolderLabel = QLabel(self.CREATE_FOLDER_NAME_TEXT,
                                        self.frameRightMenu)
        self.createFileLabel = QLabel(self.CREATE_FILE_NAME_TEXT,
                                      self.frameRightMenu)
        self.renameElementLabel = QLabel(self.RENAME_ELEMENT_TEXT,
                                         self.frameRightMenu)

        # ACTIONS LINE EDITS
        self.archiveNameEditLine = QLineEdit(self.EMPTY_STRING,
                                             self.frameRightMenu)
        self.createFileEditLine = QLineEdit(self.EMPTY_STRING,
                                            self.frameRightMenu)
        self.createFolderEditLine = QLineEdit(self.EMPTY_STRING,
                                              self.frameRightMenu)
        self.renameElementEditLine = QLineEdit(self.EMPTY_STRING,
                                               self.frameRightMenu)

        # ACTIONS BUTTONS
        self.copyButton = ToggleMenuButton(self.COPY, self.frameRightMenu)
        self.moveButton = ToggleMenuButton(self.MOVE, self.frameRightMenu)
        self.deleteButton = ToggleMenuButton(self.DELETE, self.frameRightMenu)
        self.archiveButton = ToggleMenuButton(self.ARCHIVE,
                                              self.frameRightMenu)
        self.unarchiveButton = ToggleMenuButton(self.UNARCHIVE,
                                                self.frameRightMenu)
        self.createFileButton = ToggleMenuButton(self.CREATE_FILE,
                                                 self.frameRightMenu)
        self.createFolderButton = ToggleMenuButton(self.CREATE_FOLDER,
                                                   self.frameRightMenu)
        self.renameElementButton = ToggleMenuButton(self.RENAME,
                                                    self.frameRightMenu)

        self.__createFrameLayoutElements()

    @Slot(str)
    def on_current_path_changed(self, path):
        self._model.elements_list.clear()
        self._model.selected_items.clear()
        self.selectedFilesListWidget.clear()
        self._model.elements_list = Directory.get_all_subelements(path)
        self.filesListView.model().populateList()

    @Slot(str)
    def on_current_search_changed(self, name):
        print(name)

    def removeFromSelectedItems(self, item):
        Animations.toggleMenu(self, True)
        count = self.selectedFilesListWidget.count()
        index = 0

        for i in range(count):
            if item.text() == self.selectedFilesListWidget.item(i).text():
                index = i
                break

        self.selectedFilesListWidget.takeItem(index)

    def appendToSelectedItems(self, item):
        Animations.toggleMenu(self, True)
        listItem = ListWidgetItem(item)
        self.selectedFilesListWidget.insertItem(0, listItem)

    def setCurrentPath(self, path):
        self.currentPathLineEdit.setText(path)

    @Slot(str)
    def on_combo_box_selection_changed(self, value):
        index = self.discSelectionComboBox.findText(value)
        self.discSelectionComboBox.setCurrentIndex(index)

    Slot()

    def doBack(self):
        path = self.currentPathLineEdit.text()
        parentPath = os.path.dirname(path)
        self.setCurrentPath(parentPath)

    @Slot()
    def doCopy(self):
        self.__setCopyLayout(True)
        Animations.toggleMenu(self, True)

    @Slot()
    def doMove(self):
        self.__setMoveLayout(True)
        Animations.toggleMenu(self, True)

    @Slot()
    def doDelete(self):
        self.__setDeleteLayout(True)
        Animations.toggleMenu(self, True)

    @Slot()
    def doArchive(self):
        self.__setArchiveLayout(True)
        Animations.toggleMenu(self, True)

    @Slot()
    def doUnarchive(self):
        self.__setUnarchiveLayout(True)
        Animations.toggleMenu(self, True)

    @Slot()
    def doCreateFile(self):
        self.__setCreateFileLayout(True)
        Animations.toggleMenu(self, True)

    @Slot()
    def doCreateFolder(self):
        self.__setCreateFolderLayout(True)
        Animations.toggleMenu(self, True)

    @Slot()
    def doRename(self):
        self.__setRenameLayout(True)
        Animations.toggleMenu(self, True)

    # Method that creates all layout object from the frame layout
    def __createFrameLayoutElements(self):

        # =================   COPY ACTION  =======================
        # Copy button on right frame
        self.copyButton.setStyleSheet(self.FRAME_BUTTON_STYLE)
        self.copyButton.move(120, 600)
        self.copyButton.setFixedSize(120, 32)
        self.copyButton.setVisible(False)

        # =================   MOVE ACTION  =======================
        # Move button on right frame
        self.moveButton.setStyleSheet(self.FRAME_BUTTON_STYLE)
        self.moveButton.move(120, 600)
        self.moveButton.setFixedSize(120, 32)
        self.moveButton.setVisible(False)

        # =================   DELETE ACTION  =======================
        # Delete button on right frame
        self.deleteButton.setStyleSheet(self.FRAME_BUTTON_STYLE)
        self.deleteButton.move(120, 600)
        self.deleteButton.setFixedSize(120, 32)
        self.deleteButton.setVisible(False)

        # =================   UNARCHIVE ACTION  =======================
        # Unarchive button on right frame
        self.unarchiveButton.setStyleSheet(self.FRAME_BUTTON_STYLE)
        self.unarchiveButton.move(120, 600)
        self.unarchiveButton.setFixedSize(120, 32)
        self.unarchiveButton.setVisible(False)

        # =================   ARCHIVE ACTION  =======================

        self.archiveLabel.move(100, 590)
        self.archiveLabel.setStyleSheet(self.FRAME_LABEL_STYLE)
        self.archiveLabel.setVisible(False)

        self.archiveNameEditLine.move(55, 620)
        self.archiveNameEditLine.setFixedSize(250, 30)
        self.archiveNameEditLine.setStyleSheet(self.FRAME_LINE_EDIT_STYLE)
        self.archiveNameEditLine.setVisible(False)

        self.archiveButton.setStyleSheet(self.FRAME_BUTTON_STYLE)
        self.archiveButton.move(120, 700)
        self.archiveButton.setFixedSize(120, 32)
        self.archiveButton.setVisible(False)

        # =================   CREATE NEW FILE ACTION  =======================

        self.createFileLabel.move(120, 590)
        self.createFileLabel.setStyleSheet(self.FRAME_LABEL_STYLE)
        self.createFileLabel.setVisible(False)

        self.createFileEditLine.move(55, 620)
        self.createFileEditLine.setFixedSize(250, 30)
        self.createFileEditLine.setStyleSheet(self.FRAME_LINE_EDIT_STYLE)
        self.createFileEditLine.setVisible(False)

        self.createFileButton.setStyleSheet(self.FRAME_BUTTON_STYLE)
        self.createFileButton.move(120, 700)
        self.createFileButton.setFixedSize(120, 32)
        self.createFileButton.setVisible(False)

        # =================   CREATE NEW FOLDER ACTION  =======================

        self.createFolderLabel.move(120, 590)
        self.createFolderLabel.setStyleSheet(self.FRAME_LABEL_STYLE)
        self.createFolderLabel.setVisible(False)

        self.createFolderEditLine.move(55, 620)
        self.createFolderEditLine.setFixedSize(250, 30)
        self.createFolderEditLine.setStyleSheet(self.FRAME_LINE_EDIT_STYLE)
        self.createFolderEditLine.setVisible(False)

        self.createFolderButton.setStyleSheet(self.FRAME_BUTTON_STYLE)
        self.createFolderButton.move(120, 700)
        self.createFolderButton.setFixedSize(120, 32)
        self.createFolderButton.setVisible(False)

        # =================  RENAME ELEMENT ACTION  =======================

        self.renameElementLabel.move(120, 590)
        self.renameElementLabel.setStyleSheet(self.FRAME_LABEL_STYLE)
        self.renameElementLabel.setVisible(False)

        self.renameElementEditLine.move(55, 620)
        self.renameElementEditLine.setFixedSize(250, 30)
        self.renameElementEditLine.setStyleSheet(self.FRAME_LINE_EDIT_STYLE)
        self.renameElementEditLine.setVisible(False)

        self.renameElementButton.setStyleSheet(self.FRAME_BUTTON_STYLE)
        self.renameElementButton.move(120, 700)
        self.renameElementButton.setFixedSize(120, 32)
        self.renameElementButton.setVisible(False)

    # Method that sets the frame layout for rename operation
    def __setRenameLayout(self, shown):

        if shown == True:
            self.renameElementLabel.setVisible(True)
            self.renameElementEditLine.setVisible(True)
            self.renameElementButton.setVisible(True)

            self.__setCopyLayout(False)
            self.__setDeleteLayout(False)
            self.__setMoveLayout(False)
            self.__setCreateFileLayout(False)
            self.__setCreateFolderLayout(False)
            self.__setArchiveLayout(False)
            self.__setUnarchiveLayout(False)

        else:
            self.renameElementLabel.setVisible(False)
            self.renameElementEditLine.setVisible(False)
            self.renameElementButton.setVisible(False)

    # Method that sets the frame layout for archive operation
    def __setCreateFileLayout(self, shown):

        if shown == True:
            self.createFileLabel.setVisible(True)
            self.createFileEditLine.setVisible(True)
            self.createFileButton.setVisible(True)

            self.__setCopyLayout(False)
            self.__setDeleteLayout(False)
            self.__setMoveLayout(False)
            self.__setRenameLayout(False)
            self.__setCreateFolderLayout(False)
            self.__setArchiveLayout(False)
            self.__setUnarchiveLayout(False)

        else:
            self.createFileLabel.setVisible(False)
            self.createFileEditLine.setVisible(False)
            self.createFileButton.setVisible(False)

    # Method that sets the frame layout for archive operation
    def __setCreateFolderLayout(self, shown):

        if shown == True:
            self.createFolderLabel.setVisible(True)
            self.createFolderEditLine.setVisible(True)
            self.createFolderButton.setVisible(True)

            self.__setCopyLayout(False)
            self.__setDeleteLayout(False)
            self.__setMoveLayout(False)
            self.__setRenameLayout(False)
            self.__setCreateFileLayout(False)
            self.__setArchiveLayout(False)
            self.__setUnarchiveLayout(False)

        else:
            self.createFolderLabel.setVisible(False)
            self.createFolderEditLine.setVisible(False)
            self.createFolderButton.setVisible(False)

    # Method that sets the frame layout for archive operation
    def __setArchiveLayout(self, shown):

        if shown == True:
            self.archiveLabel.setVisible(True)
            self.archiveNameEditLine.setVisible(True)
            self.archiveButton.setVisible(True)

            self.__setCopyLayout(False)
            self.__setDeleteLayout(False)
            self.__setMoveLayout(False)
            self.__setRenameLayout(False)
            self.__setCreateFileLayout(False)
            self.__setCreateFolderLayout(False)
            self.__setUnarchiveLayout(False)

        else:
            self.archiveLabel.setVisible(False)
            self.archiveNameEditLine.setVisible(False)
            self.archiveButton.setVisible(False)

    # Method that sets the frame layout for copy operation
    def __setCopyLayout(self, shown):

        if shown == True:
            self.copyButton.setVisible(True)
            self.__setMoveLayout(False)
            self.__setDeleteLayout(False)
            self.__setRenameLayout(False)
            self.__setCreateFileLayout(False)
            self.__setCreateFolderLayout(False)
            self.__setArchiveLayout(False)
            self.__setUnarchiveLayout(False)

        else:
            self.copyButton.setVisible(False)

    # Method that sets the frame layout for move operation
    def __setMoveLayout(self, shown):

        if shown == True:
            self.moveButton.setVisible(True)

            self.__setDeleteLayout(False)
            self.__setCopyLayout(False)
            self.__setRenameLayout(False)
            self.__setCreateFileLayout(False)
            self.__setCreateFolderLayout(False)
            self.__setArchiveLayout(False)
            self.__setUnarchiveLayout(False)

        else:
            self.moveButton.setVisible(False)

    # Method that sets the frame layout for delete operation
    def __setDeleteLayout(self, shown):

        if shown == True:
            self.deleteButton.setVisible(True)

            self.__setCopyLayout(False)
            self.__setMoveLayout(False)
            self.__setRenameLayout(False)
            self.__setCreateFileLayout(False)
            self.__setCreateFolderLayout(False)
            self.__setArchiveLayout(False)
            self.__setUnarchiveLayout(False)

        else:
            self.deleteButton.setVisible(False)

    # Method that sets the frame layout for unarchive operation
    def __setUnarchiveLayout(self, shown):

        if shown == True:
            self.unarchiveButton.setVisible(True)

            self.__setCopyLayout(False)
            self.__setMoveLayout(False)
            self.__setRenameLayout(False)
            self.__setCreateFileLayout(False)
            self.__setCreateFolderLayout(False)
            self.__setArchiveLayout(False)
            self.__setDeleteLayout(False)

        else:
            self.unarchiveButton.setVisible(False)