Exemple #1
1
class ExperimentSetup(QWidget):
    """ Class for setting-up the experiment: choosing condition"""

    def __init__(self, parent=None):
        super(ExperimentSetup, self).__init__(parent)
        self.title = QLabel("EXPERIMENTER ONLY")
        # titleFont = QFont()
        # titleFont.setPointSize(36)
        # titleFont.setItalic(True)
        # self.title.setFont(titleFont)
        import os
        print(os.getcwd())
        self.mypixmap = QPixmap(os.getcwd() + "/ido.jpg")
        self.title.setPixmap(self.mypixmap)
        self.title.setGeometry(10, 10, 10, 10)

        # conditions list
        self.conditions_combo = QComboBox()
        conditions_list = config.CONDITIONS['condition']
        self.conditions_combo.addItems(conditions_list)

        # layout
        formLayout = QGridLayout()
        formLayout.setSpacing(20)
        formLayout.setColumnStretch(0, 5)
        formLayout.setColumnStretch(1, 2)
        formLayout.setColumnStretch(2, 5)
        formLayout.setRowStretch(0, 1)
        formLayout.setRowStretch(3, 1)

        formLayout.addWidget(self.title, 1, 1, 1, 2)
        formLayout.setRowMinimumHeight(2, 5)
        formLayout.addWidget(self.conditions_combo, 2, 1)

        self.setLayout(formLayout)
class DocumentTab(QWidget):
    def __init__(self, parent):
        self.parent = parent
        super(DocumentTab, self).__init__(parent)
        self.name = 'Documents'
        self.formats = config.document_formats

        convertQL = QLabel(self.tr('Convert to:'))
        self.extQCB = QComboBox()
        final_layout = utils.add_to_layout('h', convertQL, self.extQCB, None)
        self.setLayout(final_layout)

    def fill_extension_combobox(self, extraformats):
        self.extQCB.clear()
        self.extQCB.addItems(sorted(self.formats + extraformats))

    def ok_to_continue(self):
        """
        Check if everything is ok with documenttab to continue conversion.

        Checks if:
        - unoconv is missing.

        Return True if all tests pass, else False.
        """
        if not self.parent.unoconv:
            QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr('Error!'),
                    self.tr('Unocov is not installed!'))
            return False
        return True
Exemple #3
0
class ChooseFixedFont( ChoiceWidget ) :
    def __init__( self, explainer ) :
        super().__init__( _TR( 'Preference item title line',
                               'Choose a monospaced font for the Editor' ),
                          explainer )
        self.fcb = QComboBox()
        self.fcb.addItems( fonts.list_of_good_families() )
        self.fcb.activated[str].connect( self.choice_made )
        self.layout().addWidget(self.fcb)
        self.reset() # set the current font
        self.explanation = _TR( 'Preference item details',
'''Select the font to use in the Edit panel. Choose a monospaced font that shows a clear difference 1/l and 0/O, and that has a wide selection of Unicode characters. Good choices are Cousine and Liberation Mono.

When you select a font from the menu, that font is applied to this window. To apply it to the Edit panel, click Apply.''')
        self.reset()

    def choice_made(self, family) :
        self.choice = family
        qf = fonts.font_from_family( family )
        self.explainer.setFont(qf)

    def reset(self) :
        self.choice = fonts.get_fixed().family()
        self.fcb.setCurrentText( self.choice )

    def apply(self) :
        fonts.set_fixed( fonts.font_from_family( self.choice ) )
Exemple #4
0
    def _get_combobox(self, column, relations, main_window):

        """
        Return combobox for foreign fields.
        """

        label = column.name
        if label.endswith('_id'):
            label = label[:-3]
        foreign_model = relations.get(label).mapper.class_
        items = list(db.SESSION.query(foreign_model).filter(foreign_model.deleted == False))
        self.foreigns[column.name] = items
        items_labels = [str(i) for i in items]
        widget = QWidget()
        widget.setStyleSheet('margin:0;')
        combo_box = QComboBox()
        combo_box.addItems(items_labels)
        combo_box.currentIndexChanged.connect(self._check_input)
        combo_box.setObjectName(column.name)
        hbox = QHBoxLayout()
        hbox.setContentsMargins(0, 0, 0, 0)
        hbox.setSpacing(0)
        hbox.addWidget(combo_box, stretch=95)
        for icon, new in zip(('pencil_g.png', 'plus.png'), (False, True)):
            b = QPushButton()
            b.setObjectName('icon')
            b.setIcon(QIcon(os.path.join(options.STATIC_DIR, 'icons', icon)))
            b.clicked.connect(functools.partial(
                self.open_crud, main_window, foreign_model, new, combo_box))
            hbox.addWidget(b, stretch=2)
        widget.setLayout(hbox)
        return label, widget
 def __init__(self):
     super().__init__()
     vbox = QVBoxLayout(self)
     self.setTitle("Python Project")
     frame = QFrame()
     frame.setLineWidth(2)
     vbox.addStretch(1)
     frame.setFrameShape(QFrame.StyledPanel)
     vbox.addWidget(frame)
     box = QGridLayout(frame)
     box.addWidget(QLabel("Project Name:"), 0, 0)
     self._line_project_name = QLineEdit()
     self.registerField("name*", self._line_project_name)
     box.addWidget(self._line_project_name, 0, 1)
     box.addWidget(QLabel("Create in:"), 1, 0)
     self.line = QLineEdit()
     self.registerField("path", self.line)
     choose_dir_action = self.line.addAction(
         QIcon(self.style().standardPixmap(
             self.style().SP_DirIcon)), QLineEdit.TrailingPosition)
     box.addWidget(self.line, 1, 1)
     box.addWidget(QLabel("Interpreter:"), 2, 0)
     line_interpreter = QComboBox()
     line_interpreter.setEditable(True)
     line_interpreter.addItems(utils.get_python())
     box.addWidget(line_interpreter, 2, 1)
     # from ninja_ide.utils import utils
     choose_dir_action.triggered.connect(self._choose_dir)
     self.line.setText(utils.get_home_dir())
    def refresh_table(self):
        self._manual_change = True
        self._custom_fields = list(
            self._configuration.scheduler_info.data.keys())
        labels = self._header + self._custom_fields
        self.setRowCount(len(labels))
        self.setVerticalHeaderLabels(labels)
        self.horizontalHeader().setStretchLastSection(False)
        header = self.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.Stretch)
        header.setSectionResizeMode(1, QHeaderView.Interactive)
        #header.setSectionResizeMode(2, QHeaderView.Interactive)
        self.horizontalHeader().hide()

        combo = QComboBox()
        combo.addItems(['Custom scheduler...'] + list(get_schedulers()))

        self.setCellWidget(0, 0, combo)
        self.setSpan(0, 0, 1, 2)

        name = self._configuration.scheduler_info.filename
        scheduler_item = QTableWidgetItem(name and os.path.relpath(
            name, self._configuration.cur_dir))
        scheduler_item.setFlags(scheduler_item.flags() ^ (Qt.ItemIsEditable))
        self.setItem(1, 0, scheduler_item)

        self._btn_open = QPushButton(self)
        self._btn_open.setText('Open')
        self._btn_open.clicked.connect(self._open_scheduler)
        self.setCellWidget(1, 1, self._btn_open)

        combo.currentIndexChanged['QString'].connect(self._select_scheduler)
        if self._configuration.scheduler_info.clas:
            i = combo.findText(self._configuration.scheduler_info.clas)
            if i <= 0:
                i = 0
            combo.setCurrentIndex(i)

        self.setItem(
            2, 0, QTableWidgetItem(str(
                self._configuration.scheduler_info.overhead))
        )
        self.setSpan(2, 0, 1, 2)
        self.setItem(
            3, 0, QTableWidgetItem(str(
                self._configuration.scheduler_info.overhead_activate))
        )
        self.setSpan(3, 0, 1, 2)

        self.setItem(
            4, 0, QTableWidgetItem(str(
                self._configuration.scheduler_info.overhead_terminate))
        )
        self.setSpan(4, 0, 1, 2)

        i = 5
        for name, value in self._configuration.scheduler_info.data.items():
            self.setItem(i, 0, QTableWidgetItem(str(value)))
            self.setSpan(i, 0, 1, 2)
            i += 1
    def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex):
        editor = QComboBox(parent)
        if sys.platform == "win32":
            # Ensure text entries are visible with windows combo boxes
            editor.setMinimumHeight(self.sizeHint(option, index).height() + 10)

        editor.addItems(self.items)

        if self.is_editable:
            editor.setEditable(True)
            editor.setInsertPolicy(QComboBox.NoInsert)

        if self.current_edit_text:
            editor.setEditText(self.current_edit_text)

        if self.colors:
            img = QImage(16, 16, QImage.Format_RGB32)
            painter = QPainter(img)

            painter.fillRect(img.rect(), Qt.black)
            rect = img.rect().adjusted(1, 1, -1, -1)
            for i, item in enumerate(self.items):
                color = self.colors[i]
                painter.fillRect(rect, QColor(color.red(), color.green(), color.blue(), 255))
                editor.setItemData(i, QPixmap.fromImage(img), Qt.DecorationRole)

            del painter
        editor.currentIndexChanged.connect(self.currentIndexChanged)
        editor.editTextChanged.connect(self.on_edit_text_changed)
        return editor
Exemple #8
0
class PropertyChanger(QWidget):
                                 
    @update_paths
    def __init__(self, objects, type, controller):
        super().__init__()
        
        # list of properties
        self.property_list = QComboBox()
        self.property_list.addItems(map(str, object_properties[type]))
                            
        self.value_edit = QLineEdit()

        confirmation_button = QPushButton()
        confirmation_button.setText('OK')
        confirmation_button.clicked.connect(lambda: self.confirm(objects))
                                       
        # position in the grid
        layout = QGridLayout()
        layout.addWidget(self.property_list, 0, 0)
        layout.addWidget(self.value_edit, 1, 0)
        layout.addWidget(confirmation_button, 2, 0)
        self.setLayout(layout)
        
    def confirm(self, objects):
        selected_property = pretty_name_to_class[self.property_list.currentText()]
        str_value = self.value_edit.text()
        value = self.network.objectizer(selected_property.name, str_value)
        for object in objects:
            setattr(object, selected_property.name, value)
        self.close()
Exemple #9
0
    def __init__(self, parent=None, *args, **kwargs):
        super(SettingsForm, self).__init__(parent, *args, **kwargs)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self.setWindowTitle('Settings')
        self.setModal(True)

        self.resize(240, 120)

        label = QLabel('Old Style (Username/Password)?')
        old_checkbox = QCheckBox(
            checked=KeyValue.get('old_style'))
        label2 = QLabel('Evaluation Type')
        box = QComboBox()
        box.addItems(EVALUATION_CHOICES)
        index = box.findText(
            KeyValue.get('evaluation_type'),
            QtCore.Qt.MatchFixedString)
        if not index < 0:
            box.setCurrentIndex(index)
        ok_button = QPushButton('OK')
        ok_button.setFixedWidth(90)

        layout = QGridLayout()
        layout.addWidget(label, 1, 1)
        layout.addWidget(old_checkbox, 1, 2)
        layout.addWidget(label2, 2, 1)
        layout.addWidget(box, 2, 2)
        layout.addWidget(ok_button, 3, 1, 3, 2, QtCore.Qt.AlignCenter)

        old_checkbox.stateChanged.connect(
            lambda: self.set_old_style(old_checkbox))
        box.currentIndexChanged.connect(lambda: self.set_eval_type(box))
        ok_button.clicked.connect(self.close)

        self.setLayout(layout)
Exemple #10
0
 def createEditor(self, parent, option, index):
     if index.column() == 1:
         combo = QComboBox(parent)
         combo.addItem('')
         combo.addItems(self._action_list)
         return combo
     return super().createEditor(parent, option, index)
Exemple #11
0
 def createEditor(self, parent, option, index):  # residNum,residNum_color, residName, atomName, atomNum, X,Y,Z
     if index.column() == residNum:
         spinbox = QSpinBox(parent)
         spinbox.setRange(1, 200000)
         spinbox.setSingleStep(1)
         spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
         return spinbox
     elif index.column() == residName:
         combobox = QComboBox(parent)
         combobox.addItems(comboBoxList)
         combobox.insertSeparator(23)
         combobox.setEditable(True)
         return combobox
     elif index.column() == atomName:
         editor = QLineEdit(parent)
         editor.returnPressed.connect(self.commitAndCloseEditor)
         return editor
     elif index.column() == atomNum:
         spinbox = QSpinBox(parent)
         spinbox.setRange(1, 200000)
         spinbox.setSingleStep(1)
         spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
         return spinbox
     elif index.column() in (X, Y, Z):  ###this works
         dspinbox = QDoubleSpinBox(parent)
         dspinbox.setRange(-200000, 200000)
         dspinbox.setSingleStep(0.1)
         dspinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
         return dspinbox
     else:
         return QStyledItemDelegate.createEditor(self, parent, option,
                                                 index)
Exemple #12
0
class OffsetRow(QWidget):
    def __init__(self):
        super(OffsetRow, self).__init__()
        self.layout = QHBoxLayout()
        self.layout.setContentsMargins(0,0,0,0)
        self.sign = QComboBox()
        self.sign.addItems(['-', '+'])
        self.amount = QLineEdit()
        self.amount.setInputMask('99999999')
        self.unit = QComboBox()
        self.unit.addItems(['sec', 'min', 'hrs', 'day'])
        self.layout.addWidget(self.sign)
        self.layout.addWidget(self.amount, stretch = 1)
        self.layout.addWidget(self.unit)

    def show(self):
        self.sign.show()
        self.amount.show()
        self.unit.show()

    def hide(self):
        self.sign.hide()
        self.amount.hide()
        self.unit.hide()

    def set_values(self, sign, amount, unit):
        self.sign.setCurrentText(sign)
        self.amount.setText(str(amount))
        self.unit.setCurrentText(unit)
 def __addRangesLine(self):
     """
     Private slot to add a line of entry widgets for character ranges.
     """
     hbox = QWidget(self.rangesItemsBox)
     hboxLayout = QHBoxLayout(hbox)
     hboxLayout.setContentsMargins(0, 0, 0, 0)
     hboxLayout.setSpacing(6)
     hbox.setLayout(hboxLayout)
     cb1 = QComboBox(hbox)
     cb1.setEditable(False)
     cb1.addItems(self.comboItems)
     hboxLayout.addWidget(cb1)
     l1 = QLabel(self.tr("Between:"), hbox)
     hboxLayout.addWidget(l1)
     le1 = QLineEdit(hbox)
     le1.setValidator(self.charValidator)
     hboxLayout.addWidget(le1)
     l2 = QLabel(self.tr("And:"), hbox)
     hboxLayout.addWidget(l2)
     le2 = QLineEdit(hbox)
     le2.setValidator(self.charValidator)
     hboxLayout.addWidget(le2)
     self.rangesItemsBoxLayout.addWidget(hbox)
     
     cb1.activated[int].connect(self.__rangesCharTypeSelected)
     
     hbox.show()
     
     self.rangesItemsBox.adjustSize()
     
     self.rangesEntries.append([cb1, le1, le2])
class CueItemWidget(QWidget):
    def __init__(self, target, action, cue_dialog, **kwargs):
        super().__init__(**kwargs)

        self.target = target
        self.cue_dialog = cue_dialog

        self.setLayout(QHBoxLayout(self))
        self.layout().setContentsMargins(2, 1, 2, 1)

        self.selectButton = QPushButton(self)
        self.selectButton.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed)
        self.selectButton.setText(target.name)
        self.selectButton.setToolTip(target.name)
        self.selectButton.clicked.connect(self.select_target)
        self.layout().addWidget(self.selectButton)

        self.targetActionsCombo = QComboBox(self)
        self.targetActionsCombo.addItems([a.name for a in CueAction])
        self.targetActionsCombo.setCurrentText(CueAction[action].name)
        self.layout().addWidget(self.targetActionsCombo)

        self.layout().setStretch(0, 3)
        self.layout().setStretch(1, 1)

    def get_target(self):
        return self.target.id, self.targetActionsCombo.currentText()

    def select_target(self):
        if self.cue_dialog.exec_() == QDialog.Accepted:
            self.target = self.cue_dialog.selected_cues()[0]
            self.selectButton.setText(self.target.name)
            self.selectButton.setToolTip(self.target.name)
Exemple #15
0
class StyleWindow(QWidget):
    
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Styles')
        
        self.original_palette = QApplication.palette()
        
        styles = QLabel('Styles :')
        self.style_list = QComboBox()
        self.style_list.addItems(QStyleFactory.keys())
        self.style_list.setCurrentIndex(3)
        self.style_list.activated[str].connect(self.change_style)
        
        self.standard_palette = QCheckBox("Standard palette")
        self.standard_palette.setChecked(False)
        self.standard_palette.toggled.connect(self.change_palette)
        
        self.change_style('Fusion')
        
        grid = QGridLayout()
        grid.addWidget(styles, 0, 0, 1, 1)
        grid.addWidget(self.style_list, 0, 1, 1, 1)
        grid.addWidget(self.standard_palette, 1, 0, 1, 2)
        self.setLayout(grid)
        
    def change_style(self, name):
        QApplication.setStyle(QStyleFactory.create(name))
        self.change_palette()

    def change_palette(self):
        if self.standard_palette.isChecked():
            QApplication.setPalette(QApplication.style().standardPalette())
        else:
            QApplication.setPalette(self.original_palette)
Exemple #16
0
class FormatChoice( ChoiceWidget ) :
    # combobox value
    def __init__( self, title, explainer ) :
        super().__init__( title, explainer )
        #Current color and line style are kept in this QTextCharFormat
        self.text_format = QTextCharFormat()
        # Set up the underline menu
        self.ul_menu = QComboBox()
        self.ul_menu.addItems( list( UNDERLINES.values() ) )
        self.ul_menu.currentIndexChanged[int].connect(self.ul_change)
        self.layout().addWidget( self.ul_menu, 0 )
        # Set up the color swatch
        self.swatch = Swatch( self )
        self.layout().addWidget( self.swatch, 0 )
        self.swatch.clicked.connect( self.color_change )
        # Set up the text sample
        self.sample = Sample()
        self.layout().addWidget( self.sample )
        self.reset() # set widgets to current value

    # Combine the underline choice and swatch color into a QTextCharFormat.
    def make_format( self, ul_index, qc ) :
        qtcf = QTextCharFormat()
        qtcf.setUnderlineStyle( ul_index )
        if ul_index == QTextCharFormat.NoUnderline :
            qtcf.setBackground(QBrush(qc))
        else :
            qtcf.setUnderlineColor(qc) # underline color gets a QColor
            qtcf.clearBackground()
        return qtcf

    # Parse self.text_format and display it in the swatch and combobox.
    def show_format( self ) :
        un = self.text_format.underlineStyle()
        if un == QTextCharFormat.NoUnderline :
            qc = self.text_format.background().color()
        else :
            qc = self.text_format.underlineColor()
        self.swatch.set_color( qc )
        self.ul_menu.setCurrentIndex( un )
        self.sample.change_format(self.text_format)

    # Handle a change in selection of the underline popup
    def ul_change( self, index ) :
        self.text_format = self.make_format( index, self.swatch.qc )
        self.show_format()

    # Handle a click on the color swatch. Show the color dialog. After it
    # ends, the Preferences dialog will be behind the main window. Why? Who
    # knows! But raise it back up to visibility.
    def color_change(self) :
        qc = colors.choose_color(
            _TR('Browse dialog for color preference',
                'Choose a color for scanno marking'),
            self.swatch.qc )
        BIG_FAT_KLUDGE.raise_()
        if qc is not None :
            self.text_format = self.make_format( self.ul_menu.currentIndex(), qc )
            self.show_format()
Exemple #17
0
class AlsaSinkSettings(SettingsSection):

    NAME = "ALSA Sink"
    ELEMENT = AlsaSink

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

        self.id = Id
        self.devs = self._discover_pcm_devices()
        self.devs['default'] = 'default'

        self.group = QGroupBox(self)
        self.group.setTitle('ALSA device')
        self.group.setGeometry(0, 0, self.width(), 100)
        self.group.setLayout(QHBoxLayout())

        self.device = QComboBox(self.group)
        self.device.addItems(self.devs.keys())
        self.device.setCurrentText('default')
        self.device.setToolTip('ALSA device, as defined in an asound '
                               'configuration file')
        self.group.layout().addWidget(self.device)

        self.label = QLabel('ALSA device', self.group)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.group.layout().addWidget(self.label)

    def sizeHint(self):
        return QSize(450, 100)

    def enable_check(self, enable):
        self.group.setCheckable(enable)
        self.group.setChecked(False)

    def set_configuration(self, conf):
        if self.id in conf:
            device = conf[self.id].get('device', 'default')
            for name in self.devs:
                if device == self.devs[name]:
                    self.device.setCurrentText(name)
                    break

    def get_configuration(self):
        if not (self.group.isCheckable() and not self.group.isChecked()):
            return {self.id: {'device': self.devs[self.device.currentText()]}}
        else:
            return {}

    def _discover_pcm_devices(self):
        devices = {}

        with open('/proc/asound/pcm', mode='r') as f:
            for dev in f.readlines():
                dev_name = dev[7:dev.find(':', 7)].strip()
                dev_code = 'hw:' + dev[:5].replace('-', ',')
                devices[dev_name] = dev_code

        return devices
Exemple #18
0
class SubFileDialog(QFileDialog):
    def __init__(self, parent = None, caption = "", directory = "", filter = ""):
        super().__init__(parent, caption, directory, filter)
        self.setOption(QFileDialog.DontUseNativeDialog)

    def _initAllSubFormats(self, formatList):
        self._formats = {}
        for f in formatList:
            self._formats[f.NAME] = f

    def _addEncodingsBox(self, row, addAuto):
        mainLayout = self.layout()

        encodingLabel = QLabel(_("File encoding:"), self)

        self._encodingBox = QComboBox(self)
        if addAuto is True:
            self._encodingBox.addItem(AUTO_ENCODING_STR)
        self._encodingBox.addItems(ALL_ENCODINGS)
        self._encodingBox.setToolTip(_("Change file encoding"))
        self._encodingBox.setEditable(True)

        mainLayout.addWidget(encodingLabel, row, 0)
        mainLayout.addWidget(self._encodingBox, row, 1)

    def _addFormatBox(self, row, formatList):
        self._initAllSubFormats(formatList)
        displayedFormats = list(self._formats.keys())
        displayedFormats.sort()

        mainLayout = self.layout()

        formatLabel = QLabel(_("Subtitle format:"), self)
        self._formatBox = QComboBox(self)
        self._formatBox.addItems(displayedFormats)

        mainLayout.addWidget(formatLabel, row, 0)
        mainLayout.addWidget(self._formatBox, row, 1)

    def getEncoding(self):
        encoding = self._encodingBox.currentText()
        if encoding == AUTO_ENCODING_STR:
            encoding = None
        return encoding

    def setEncoding(self, encoding):
        index = self._encodingBox.findText(encoding)
        self._encodingBox.setCurrentIndex(index)

    def getSubFormat(self):
        return self._formats.get(self._formatBox.currentText())

    def setSubFormat(self, subFormat):
        for key, val in self._formats.items():
            if val == subFormat:
                index = self._formatBox.findText(key)
                self._formatBox.setCurrentIndex(index)
                return
class General(SettingsPage):

    NAME = 'General'

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.setLayout(QVBoxLayout())
        self.layout().setAlignment(Qt.AlignTop)

        # Startup layout
        self.layoutGroup = QGroupBox(self)
        self.layoutGroup.setTitle('Startup layout')
        self.layoutGroup.setLayout(QVBoxLayout())
        self.layout().addWidget(self.layoutGroup)

        self.startupDialogCheck = QCheckBox(self.layoutGroup)
        self.startupDialogCheck.setText('Use startup dialog')
        self.layoutGroup.layout().addWidget(self.startupDialogCheck)

        self.layoutCombo = QComboBox(self.layoutGroup)
        self.layoutCombo.addItems([lay.NAME for lay in layouts.get_layouts()])
        self.layoutGroup.layout().addWidget(self.layoutCombo)

        self.startupDialogCheck.clicked.connect(
            lambda check: self.layoutCombo.setEnabled(not check))

        # Application style
        self.themeGroup = QGroupBox(self)
        self.themeGroup.setTitle('Application theme')
        self.themeGroup.setLayout(QVBoxLayout())
        self.layout().addWidget(self.themeGroup)

        self.themeCombo = QComboBox(self.themeGroup)
        self.themeCombo.addItems(styles.get_styles())
        self.themeGroup.layout().addWidget(self.themeCombo)

    def get_settings(self):
        conf = {'Layout': {}, 'Theme': {}}

        if self.startupDialogCheck.isChecked():
            conf['Layout']['default'] = 'NoDefault'
        else:
            conf['Layout']['default'] = self.layoutCombo.currentText()

        conf['Theme']['theme'] = self.themeCombo.currentText()
        styles.apply_style(self.themeCombo.currentText())

        return conf

    def load_settings(self, settings):
        if 'default' in settings['Layout']:
            if settings['Layout']['default'].lower() == 'nodefault':
                self.startupDialogCheck.setChecked(True)
                self.layoutCombo.setEnabled(False)
            else:
                self.layoutCombo.setCurrentText(settings['Layout']['default'])
        if 'theme' in settings['Theme']:
            self.themeCombo.setCurrentText(settings['Theme']['theme'])
Exemple #20
0
class StartSession(preferences.Group):
    def __init__(self, page):
        super(StartSession, self).__init__(page)
        
        grid = QGridLayout()
        self.setLayout(grid)
        
        def changed():
            self.changed.emit()
            self.combo.setEnabled(self.custom.isChecked())
        
        self.none = QRadioButton(toggled=changed)
        self.lastused = QRadioButton(toggled=changed)
        self.custom = QRadioButton(toggled=changed)
        self.combo = QComboBox(currentIndexChanged=changed)
        
        grid.addWidget(self.none, 0, 0, 1, 2)
        grid.addWidget(self.lastused, 1, 0, 1, 2)
        grid.addWidget(self.custom, 2, 0, 1, 1)
        grid.addWidget(self.combo, 2, 1, 1, 1)

        app.translateUI(self)
        
    def translateUI(self):
        self.setTitle(_("Session to load if Frescobaldi is started without arguments"))
        self.none.setText(_("Start with no session"))
        self.lastused.setText(_("Start with last used session"))
        self.custom.setText(_("Start with session:"))
        
    def loadSettings(self):
        s = QSettings()
        s.beginGroup("session")
        startup = s.value("startup", "none", str)
        if startup ==  "lastused":
            self.lastused.setChecked(True)
        elif startup == "custom":
            self.custom.setChecked(True)
        else:
            self.none.setChecked(True)
        sessionNames = sessions.sessionNames()
        self.combo.clear()
        self.combo.addItems(sessionNames)
        custom = s.value("custom", "", str)
        if custom in sessionNames:
            self.combo.setCurrentIndex(sessionNames.index(custom))

    def saveSettings(self):
        s = QSettings()
        s.beginGroup("session")
        s.setValue("custom", self.combo.currentText())
        if self.custom.isChecked():
            startup = "custom"
        elif self.lastused.isChecked():
            startup = "lastused"
        else:
            startup = "none"
        s.setValue("startup", startup)
Exemple #21
0
class DisjointSPWindow(QWidget):
    
    algorithms = (
    'Constrained A*', 
    'Bhandari algorithm', 
    'Suurbale algorithm', 
    'Linear programming'
    )
    
    def __init__(self, controller):
        super().__init__()
        self.controller = controller
        self.setWindowTitle('Disjoint shortest paths algorithms')
        
        algorithm = QLabel('Algorithm')        
        self.dsp_list = QComboBox()
        self.dsp_list.addItems(self.algorithms)

        source = QLabel('Source')
        self.source_edit = QLineEdit()
        
        destination = QLabel('Destination')
        self.destination_edit = QLineEdit()
        
        number_of_paths = QLabel('Number of paths')
        self.number_of_paths_edit = QLineEdit()
                
        # confirmation button
        button_compute = QPushButton()
        button_compute.setText('Compute')
        button_compute.clicked.connect(self.compute_dsp)
        
        # position in the grid
        layout = QGridLayout()
        layout.addWidget(algorithm, 0, 0, 1, 1)
        layout.addWidget(self.dsp_list, 0, 1, 1, 1)
        layout.addWidget(source, 1, 0, 1, 1)
        layout.addWidget(self.source_edit, 1, 1, 1, 1)
        layout.addWidget(destination, 2, 0, 1, 1)
        layout.addWidget(self.destination_edit, 2, 1, 1, 1)
        layout.addWidget(number_of_paths, 3, 0, 1, 1)
        layout.addWidget(self.number_of_paths_edit, 3, 1, 1, 1)
        layout.addWidget(button_compute, 4, 0, 1, 2)
        self.setLayout(layout)
        
    @update_paths
    def compute_dsp(self, _):
        source = self.network.nf(name=self.source_edit.text())
        destination = self.network.nf(name=self.destination_edit.text())
        algorithm = {
                    'Constrained A*': self.network.A_star_shortest_pair,
                    'Bhandari algorithm': self.network.bhandari,
                    'Suurbale algorithm': self.network.suurbale,
                    'Linear programming': lambda: 'to repair'
                    }[self.dsp_list.currentText()]
        nodes, physical_links = algorithm(source, destination)
        self.view.select(*(nodes + physical_links))
Exemple #22
0
class JackSinkSettings(SettingsSection):

    NAME = "Jack Sink"
    ELEMENT = JackSink

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

        self.id = Id

        self.group = QGroupBox(self)
        self.group.setTitle('Jack')
        self.group.setGeometry(0, 0, self.width(), 100)
        self.group.setLayout(QGridLayout())

        self.client = QLineEdit(self.group)
        self.client.setToolTip('The client name of the Jack instance')
        self.client.setText('Linux Show Player')
        self.group.layout().addWidget(self.client, 0, 0)

        self.clientLabel = QLabel('Client name', self.group)
        self.clientLabel.setAlignment(QtCore.Qt.AlignCenter)
        self.group.layout().addWidget(self.clientLabel, 0, 1)

        self.connection = QComboBox(self.group)
        self.connection.setToolTip('Specify how the output ports will be'
                                   'connected')
        self.connection.addItems([JackSink.CONNECT_NONE,
                                  JackSink.CONNECT_AUTO,
                                  JackSink.CONNECT_AUTO_FORCED])
        self.connection.setCurrentIndex(1)
        self.group.layout().addWidget(self.connection, 1, 0)

        self.connLabel = QLabel('Connection mode', self.group)
        self.connLabel.setAlignment(QtCore.Qt.AlignCenter)
        self.group.layout().addWidget(self.connLabel, 1, 1)

    def sizeHint(self):
        return QSize(450, 100)

    def enable_check(self, enable):
        self.group.setCheckable(enable)
        self.group.setChecked(False)

    def set_configuration(self, conf):
        if self.id in conf:
            if 'client-name' in conf[self.id]:
                self.client.setText(conf[self.id]['client-name'])
            if 'connection' in conf[self.id]:
                self.connection.setCurrentText(conf[self.id]['connection'])

    def get_configuration(self):
        if not (self.group.isCheckable() and not self.group.isChecked()):
            return {self.id: {'client-name': self.client.text(),
                              'connection': self.connection.currentText()}}
        else:
            return {}
Exemple #23
0
 def _make_cb(self, default, text) :
     cb = QComboBox()
     cb.addItems(stream_names)
     cb.setCurrentIndex(default)
     tt = _TR( 'Footnote panel popup menus',
              'Choose the format to use when renumbering Note Keys such as:',
              'will be followed by e.g. "[A]" or "[5]"' )
     cb.setToolTip(tt+text)
     return cb
Exemple #24
0
    def _add_task_to_table(self, row, task):
        self._ignore_cell_changed = True
        self.setItem(row, self._dict_header['id'],
                     QTableWidgetItem(str(task.identifier)))
        self.item(row, self._dict_header['id']) \
            .setTextAlignment(Qt.AlignCenter)
        self.setItem(row, self._dict_header['name'],
                     QTableWidgetItem(str(task.name)))

        combo = QComboBox()
        items = [task_type for task_type in Task.task_types_names]
        combo.addItems(items)
        combo.setCurrentIndex(combo.findText(task.task_type))
        combo.currentIndexChanged.connect(
            lambda x: self._cell_changed(row, self._dict_header['task_type']))
        self.setCellWidget(row, self._dict_header['task_type'], combo)

        item = QTableWidgetItem(task.abort_on_miss and 'Yes' or 'No')
        item.setFlags(
            Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsSelectable)
        item.setCheckState(task.abort_on_miss and Qt.Checked or Qt.Unchecked)
        self.setItem(row, self._dict_header['abort'], item)

        self.setItem(row, self._dict_header['list_activation_dates'],
                     QTableWidgetItem(
                         ', '.join(map(str, task.list_activation_dates))))
        self.item(row, self._dict_header['list_activation_dates']) \
            .setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)

        for i in ['activation_date', 'period',
                  'deadline', 'wcet', 'base_cpi', 'n_instr', 'mix', 'acet',
                  'et_stddev', 'preemption_cost']:
            self.setItem(row, self._dict_header[i],
                         QTableWidgetItem(str(task.__dict__[i])))
            self.item(row, self._dict_header[i]) \
                .setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)

        stack_item = QTableWidgetItem(str(task.stack_file))
        stack_item.setFlags(stack_item.flags() ^ (Qt.ItemIsEditable))
        self.setItem(row, self._dict_header['sdp'], stack_item)

        combo = QComboBox()
        combo.currentIndexChanged.connect(
            lambda x: self._cell_changed(row, self._dict_header['followed']))
        self.setCellWidget(row, self._dict_header['followed'], combo)

        for col in range(len(self._custom_fields)):
            key = self._custom_fields[col]
            if key in task.data and task.data[key] is not None:
                item = QTableWidgetItem(str(task.data[key]))
            else:
                item = QTableWidgetItem('')
            item.setBackgroundColor(QColor.fromRgb(200, 255, 200))
            self.setItem(row, col + len(self._header), item)

        self._ignore_cell_changed = False
        self._show_period(task, row)
Exemple #25
0
class ASOperation(QWidget):
    
    # - add objects to an AS
    # - remove objects from an AS
    # - enter the AS management window
    
    @update_paths
    def __init__(self, mode, obj, AS=set(), controller=None):
        super().__init__()
        
        title = {
        'add': 'Add to AS',
        'remove': 'Remove from AS',
        'manage': 'Manage AS'
        }[mode]
        
        self.setWindowTitle(title)
        
        if mode == 'add':
            # all AS are proposed 
            values = tuple(map(str, self.network.pnAS))
        else:
            # only the common AS among all selected objects
            values = tuple(map(str, AS))
        
        # list of existing AS
        self.AS_list = QComboBox()
        self.AS_list.addItems(values)
        
        # confirmation button
        button_AS_operation = QPushButton()
        button_AS_operation.setText('OK')
        button_AS_operation.clicked.connect(lambda: self.as_operation(mode, *obj))
        
        # cancel button
        cancel_button = QPushButton()
        cancel_button.setText('Cancel')
        
        # position in the grid
        layout = QGridLayout()
        layout.addWidget(self.AS_list, 0, 0, 1, 2)
        layout.addWidget(button_AS_operation, 1, 0, 1, 1)
        layout.addWidget(cancel_button, 1, 1, 1, 1)
        self.setLayout(layout)
        
    def as_operation(self, mode, *objects):
        selected_AS = self.network.AS_factory(name=self.AS_list.currentText())

        if mode == 'add':
            selected_AS.management.add_to_AS(*objects)
        elif mode == 'remove':
            selected_AS.management.remove_from_AS(*objects)
        else:
            selected_AS.management.show()
            
        self.close()
            
class General(SettingsSection):

    NAME = 'General'

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

        # Startup layout
        self.layoutGroup = QGroupBox(self)
        self.layoutGroup.setTitle('Startup layout')
        self.layoutGroup.setLayout(QVBoxLayout())
        self.layoutGroup.setGeometry(0, 0, self.width(), 120)

        self.startupDialogCheck = QCheckBox(self.layoutGroup)
        self.startupDialogCheck.setText('Use startup dialog')
        self.layoutGroup.layout().addWidget(self.startupDialogCheck)

        self.layoutCombo = QComboBox(self.layoutGroup)
        self.layoutCombo.addItems([lay.NAME for lay in layouts.get_layouts()])
        self.layoutGroup.layout().addWidget(self.layoutCombo)

        self.startupDialogCheck.clicked.connect(
            lambda check: self.layoutCombo.setEnabled(not check))

        # Application style
        self.themeGroup = QGroupBox(self)
        self.themeGroup.setTitle('Application theme')
        self.themeGroup.setLayout(QVBoxLayout())
        self.themeGroup.setGeometry(0, 125, self.width(), 80)

        self.themeCombo = QComboBox(self.themeGroup)
        self.themeCombo.addItems(styles.get_styles())
        self.themeGroup.layout().addWidget(self.themeCombo)

    def get_configuration(self):
        conf = {'Layout': {}, 'Theme': {}}

        if self.startupDialogCheck.isChecked():
            conf['Layout']['default'] = 'NoDefault'
        else:
            conf['Layout']['default'] = self.layoutCombo.currentText()

        conf['Theme']['current'] = self.themeCombo.currentText()
        styles.apply_style(self.themeCombo.currentText())

        return conf

    def set_configuration(self, conf):
        if 'default' in conf['Layout']:
            if conf['Layout']['default'].lower() == 'nodefault':
                self.startupDialogCheck.setChecked(True)
                self.layoutCombo.setEnabled(False)
            else:
                self.layoutCombo.setCurrentText(conf['Layout']['default'])
        if 'current' in conf['Theme']:
            self.themeCombo.setCurrentText(conf['Theme']['current'])
Exemple #27
0
 def createEditor(self, parent, option, index):
     if index.column() == 2:
         dictionary_paths = [
             shorten_path(dictionary.get_path())
             for dictionary in self._dictionary_list
         ]
         combo = QComboBox(parent)
         combo.addItems(dictionary_paths)
         return combo
     return super(DictionaryItemDelegate, self).createEditor(parent, option, index)
    def createEditor(self, parent, option, index):
        # Add null editor to action buttons column
        if index.column() == index.model().column_position[ACTION_BUTTONS]:
            return
        if index.column() == index.model().column_position['category']:
            cbox = QComboBox(parent)
            cbox.addItems(CATEGORY_LIST)
            return cbox

        return super(TriblerButtonsDelegate, self).createEditor(parent, option, index)
    def createEditor(self, parent, option, index):
        editor = QComboBox(parent=parent)

        editor.addItems(COMBO_BOX_ITEMS)

        # setFrame(): tell whether the line edit draws itself with a frame.
        # If enabled (the default) the line edit draws itself inside a frame, otherwise the line edit draws itself without any frame.
        editor.setFrame(False)

        return editor
class TestStripsDialog(QDialog):
    GHBox = None
    KHBox = None
    pHBox = None
    NO2Box = None
    NO3Box = None
 
    def __init__(self):
        super(TestStripsDialog, self).__init__()

        self.GHBox = QComboBox()
        self.KHBox = QComboBox()
        self.pHBox = QComboBox()
        self.NO2Box = QComboBox()
        self.NO3Box = QComboBox()

        self.createFormGroupBox()
 
        buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        buttonBox.accepted.connect(self.accept)
        buttonBox.rejected.connect(self.reject)
 
        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.formGroupBox)
        mainLayout.addWidget(buttonBox)
        self.setLayout(mainLayout)
 
        self.setWindowTitle("Aquarium Data Form")
 
    def createFormGroupBox(self):
        self.formGroupBox = QGroupBox("5-in-1 Test Strips")
        layout = QFormLayout()

        # Create the GH combobox
        GHItems = ['0','30','60','120','180']
        self.GHBox.addItems(GHItems)

        # Create the KH combobox
        KHItems = ['0','40','80','120','180','240']
        self.KHBox.addItems(KHItems)

        # Create the pH combobox
        pHItems = ['6.0','6.5','7.0','7.5','8.0','8.5','9.0']
        self.pHBox.addItems(pHItems)

        # Create the Nitrite combobox
        NO2Items = ['0 ppm','0.50 ppm','1.0 ppm','3.0 ppm','5.0 ppm','10.0 ppm']
        self.NO2Box.addItems(NO2Items)

        # Create the Nitrate combobox
        NO3Items = ['20 ppm','40 ppm','80 ppm','160 ppm','200 ppm']
        self.NO3Box.addItems(NO3Items)

        layout.addRow(QLabel("General Hardness (GH):"), self.GHBox)
        layout.addRow(QLabel("Carbonate Hardness (KH):"), self.KHBox)
        layout.addRow(QLabel("pH"), self.pHBox)
        layout.addRow(QLabel("Nitrite (NO2-):"), self.NO2Box)
        layout.addRow(QLabel("Nitrate (NO3-):"), self.NO3Box)
        self.formGroupBox.setLayout(layout)

    def accept(self):
        date = datetime.datetime.now()
        print("\n5-in-1 Test Strip Results - " + str(date))
        print("  GH Level:\t\t" + self.GHBox.currentText()) 
        print("  KH Level:\t\t" + self.KHBox.currentText()) 
        print("  pH Level:\t\t" + self.pHBox.currentText()) 
        print("  Nitrite Level:\t" + self.NO2Box.currentText()) 
        print("  Nitrate Level:\t" + self.NO3Box.currentText()) 

        self.writeTestStrips(self.GHBox.currentText(), self.KHBox.currentText(), self.pHBox.currentText(), self.NO2Box.currentText(), self.NO3Box.currentText())

        self.done(0)

    def writeTestStrips(self, GH, KH, pH, NO2, NO3):
        with open(".aquadata", "r") as fp:
            tsLine   = fp.readline()
            fmtkLine = fp.readline()
            tempLine = fp.readline()

        fmtkLine = GH + "," + KH + "," + pH + "," + NO2 + "," + NO3 + "\n"

        with open(".aquadata", "w") as fp:
            fp.write(tsLine)
            fp.write(fmtkLine)
            fp.write(tempLine)
class FileDialog(QWidget):
    def __init__(self, parent: DetectVideoApp = None):
        super().__init__()
        self.parent = parent
        self.args = argparse.Namespace()
        self.args.is_classifier = False
        self.classifier_cfg = None
        self.classifier_weights = None
        self.setWindowIcon(QIcon('../images/Logo.png'))
        layout = QVBoxLayout()

        self.startDir = os.getcwd()
        # Create video selector
        self.useWebCam = QCheckBox("Use web cam")
        self.useWebCam.setChecked(False)
        self.useWebCamLabel = QLabel("Use web cam")
        self.useWebCam.stateChanged.connect(self.use_webcam_clicked)
        horizontal_layout = QHBoxLayout()
        horizontal_layout.addWidget(self.useWebCamLabel)
        horizontal_layout.addWidget(self.useWebCam, alignment=Qt.AlignLeft)
        horizontal_layout.addStretch(1)
        self.btnIm = QPushButton("Select video to detect")
        self.btnIm.clicked.connect(self.get_video)
        self.textIm = QTextEdit()
        layout.addLayout(horizontal_layout, 1)
        layout.addStretch(1)
        layout.addLayout(SelectQPushButton(self.btnIm), 1)
        layout.addLayout(SelectQText(self.textIm), 2)
        layout.addStretch(1)
        self.textIm.setReadOnly(True)

        # Select data set
        self.select_ds_label = QLabel("Select dataset")
        self.select_ds = DataSetsManager.get_data_set_combo()
        self.select_ds.setObjectName("SelectCombo")
        self.select_ds.currentTextChanged.connect(self.on_data_set_changed)
        layout.addLayout(SelectQCombo(self.select_ds_label, self.select_ds), 2)
        layout.addStretch(1)
        # Select weights file
        self.btnW = QPushButton("Select weights file")
        self.btnW.clicked.connect(self.get_weights)
        self.textW = QLineEdit()
        self.textW.setReadOnly(True)
        layout.addLayout(SelectQPushButton(self.btnW), 1)
        layout.addLayout(SelectQPushButton(self.textW), 1)
        layout.addStretch(1)
        # Select Config file
        self.btnConf = QPushButton("Select Config file")
        self.btnConf.clicked.connect(self.get_config)
        self.textConf = QLineEdit()
        self.textConf.setReadOnly(True)
        layout.addLayout(SelectQPushButton(self.btnConf), 1)
        layout.addLayout(SelectQText(self.textConf), 1)
        layout.addStretch(1)
        # Select Names file
        self.btnNames = QPushButton("Select Names file")
        self.btnNames.clicked.connect(self.get_names)
        self.textNames = QLineEdit()
        self.textNames.setReadOnly(True)
        layout.addLayout(SelectQPushButton(self.btnNames), 1)
        layout.addLayout(SelectQText(self.textNames), 1)
        layout.addStretch(1)
        bs_label = QLabel('Batch size')
        conf_label = QLabel('Confidence')
        nms_label = QLabel('Nms threshold')
        res_label = QLabel('Resolution')

        self.bsEdit = QLineEdit()
        self.confEdit = QLineEdit()
        self.nmsEdit = QLineEdit()
        self.resEdit = QLineEdit()

        self.bsEdit.setText("1")
        self.confEdit.setText("0.5")
        self.nmsEdit.setText("0.4")
        self.resEdit.setText("416")

        self.textIm.setText("../vid1_Driving_in_Gothenburg_Sweden.mp4")
        self.args.video = "../vid1_Driving_in_Gothenburg_Sweden.mp4"
        self.on_data_set_changed('Swedish')
        self.select_ds.setCurrentText('Swedish')

        grid = QGridLayout()
        grid.setSpacing(10)

        grid.addWidget(bs_label, 1, 0)
        grid.addWidget(conf_label, 2, 0)
        grid.addWidget(nms_label, 3, 0)
        grid.addWidget(res_label, 4, 0)

        grid.addWidget(self.bsEdit, 1, 1)
        grid.addWidget(self.confEdit, 2, 1)
        grid.addWidget(self.nmsEdit, 3, 1)
        grid.addWidget(self.resEdit, 4, 1)

        grid.setColumnStretch(0, 1)
        grid.setColumnStretch(1, 1)
        grid.setColumnStretch(2, 2)

        layout.addLayout(grid, 5)

        tracking_layout = QHBoxLayout()
        self.use_tracking = QCheckBox("Use tracking")
        self.use_tracking.setChecked(True)
        self.use_tracking_label = QLabel("Use tracking: ")
        self.use_tracking.stateChanged.connect(self.use_tracking_clicked)
        tracking_layout.addWidget(self.use_tracking_label)
        tracking_layout.addWidget(self.use_tracking)
        tracking_layout.addStretch(1)
        layout.addLayout(tracking_layout, 1)

        self.tracking = None
        self.select_tracking_label = QLabel("Select tracking")
        self.select_tracking = QComboBox()
        self.select_tracking.setItemDelegate(QStyledItemDelegate())
        self.select_tracking.setObjectName("SelectCombo")
        self.select_tracking.addItems(["Sort", "Deep Sort"])
        self.select_tracking.currentIndexChanged.connect(self.selection_tracking_change)
        self.select_tracking.setCurrentIndex(1)
        layout.addLayout(SelectQCombo(self.select_tracking_label, self.select_tracking), 2)

        count_layout = QHBoxLayout()
        self.count_enabled = False
        self.use_count = QCheckBox("Count performance")
        self.use_count.setChecked(False)
        self.use_count_label = QLabel("Count statistics: ")
        count_layout.addWidget(self.use_count_label)
        count_layout.addWidget(self.use_count)
        count_layout.addStretch(1)
        layout.addLayout(count_layout, 1)

        layout.addStretch(1)

        back_button = QPushButton("Back")
        ok_button = QPushButton("OK")
        cancel_button = QPushButton("Cancel")
        hor_box = QHBoxLayout()
        hor_box.addWidget(back_button, alignment=Qt.AlignLeft)
        hor_box.addStretch(2)
        hor_box.addWidget(ok_button)
        hor_box.addWidget(cancel_button)
        back_button.clicked.connect(self.back_detection)
        ok_button.clicked.connect(self.start_detection)
        cancel_button.clicked.connect(cancel_detection)
        layout.addLayout(hor_box, 2)

        self.setLayout(layout)

    def get_video(self):
        file_names = QFileDialog.getOpenFileName(self, 'Open Video', self.startDir,
                                                 'Videos (*.webm *.mpg *.ogg *.mp4 *.avi *.mov)', "",
                                                 QFileDialog.DontUseNativeDialog)
        if file_names[0]:
            self.args.video = file_names[0]
            self.textIm.setText(file_names[0])
            self.startDir = str(Path(file_names[0][0]).parent)

    def use_webcam_clicked(self, checked):
        if checked:
            self.args.video = 0
            self.textIm.setText("")
            self.textIm.setReadOnly(True)
            self.btnIm.clicked.disconnect()
            self.btnIm.hide()
            self.textIm.hide()
        else:
            self.args.video = None
            self.textIm.setReadOnly(False)
            self.btnIm.clicked.connect(self.get_video)
            self.btnIm.show()
            self.textIm.show()

    def selection_tracking_change(self, i):
        if i == 0:
            self.tracking = "sort"
        else:
            self.tracking = "deep_sort"

    def use_tracking_clicked(self, checked):
        if checked:
            self.select_tracking.show()
            self.select_tracking.itemText(1)
            self.select_tracking_label.show()
            self.tracking = "deep_sort"
        else:
            self.select_tracking.hide()
            self.select_tracking_label.hide()
            self.tracking = None

    def get_weights(self):
        filename = QFileDialog.getOpenFileName(self, 'Open Weightsfile', self.startDir, 'Weightsfile (*.weights)',
                                               "", QFileDialog.DontUseNativeDialog)
        if filename[0]:
            self.args.weights = filename[0]
            self.textW.setText(filename[0])
            self.startDir = str(Path(filename[0]).parent)

    def get_config(self):
        filename = QFileDialog.getOpenFileName(self, 'Open Configfile', self.startDir, 'Configfile (*.cfg)',
                                               "", QFileDialog.DontUseNativeDialog)
        if filename[0]:
            self.args.cfg = filename[0]
            self.textConf.setText(filename[0])
            self.startDir = str(Path(filename[0]).parent)

    def get_names(self):
        filename = QFileDialog.getOpenFileName(self, 'Open Namesfile', self.startDir, 'Nmesfile (*.names)',
                                               "", QFileDialog.DontUseNativeDialog)
        if filename[0]:
            self.args.names = filename[0]
            self.textNames.setText(filename[0])
            self.startDir = str(Path(filename[0]).parent)

    def start_detection(self):
        self.args.bs = self.bsEdit.text()
        self.args.confidence = self.confEdit.text()
        self.args.nms_thresh = self.nmsEdit.text()
        self.args.reso = self.resEdit.text()

        for arg in vars(self.args):
            if not arg:
                QMessageBox.critical(self, "Error!", f"Parameter {arg} is empty!")

        self.count_enabled = self.use_count.isChecked()
        if self.select_ds.currentText() in ["European", "Belgium", "GTSRB"]:
            self.args.is_classifier = True
            base_model = "Croat"
            self.set_classifier_parameters(base_model)
        self.parent.show_video_viewer("Video Viewer")

    def set_classifier_parameters(self, set_name):
        self.args.classifier_cfg = f"../cfg/{set_name}.cfg"
        self.args.classifier_weights = f"../weights/{set_name}.weights"
        self.args.classifier_names = f"../data/{set_name}.names"
        self.args.classifier_inp_dim = 416
        self.args.classifier_confidence = 0.5
        self.args.classifier_nms_thresh = 0.4

    def back_detection(self):
        self.parent.back_to_parent()

    def on_data_set_changed(self, text):
        self.args.weights = f"../weights/{text}.weights"
        self.textW.setText(self.args.weights)

        self.args.cfg = f"../cfg/{text}.cfg"
        self.textConf.setText(self.args.cfg)

        self.args.names = f"../data/{text}.names"
        self.textNames.setText(self.args.names)
Exemple #32
0
class SettingMenu(QFrame):

    S_port_info = pyqtSignal(str, str, name='PortInfo')
    S_save_butt_clicked = pyqtSignal(bool, name='SaveButtClicked')
    S_update_ports = pyqtSignal(bool, name="UpdateButtClicked")

    def __init__(self, port, port_speed):
        super().__init__()
        self.setting_info_ = {'Port': port, 'Speed': port_speed}
        self.ports_ = {}
        speeds_ = {
            "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200"
        }

        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        portEditLabel = QLabel("Port Number:")
        portEditLabel.setObjectName("SettMenuLabel")

        self.portBox = QComboBox()
        self.portBox.addItems(self.ports_)
        self.portBox.setCurrentText(self.setting_info_["Port"])

        speedEditLabel = QLabel("Port Speed: ")
        speedEditLabel.setObjectName("SettMenuLabel")

        self.speedBox = QComboBox()
        self.speedBox.addItems(speeds_)
        self.speedBox.setCurrentText(self.setting_info_["Speed"])

        configSaveButt = QPushButton("SAVE")
        configSaveButt.setObjectName("SettMenuSaveButt")
        configSaveButt.clicked.connect(self.set_port_info)

        updateButt = QPushButton("Update")
        updateButt.clicked.connect(self.act_update_ports)

        hPortBoxLay = QHBoxLayout()

        hPortBoxLay.addWidget(portEditLabel)
        hPortBoxLay.addWidget(self.portBox)
        hPortBoxLay.addSpacing(20)
        hPortBoxLay.addWidget(speedEditLabel)
        hPortBoxLay.addWidget(self.speedBox)
        hPortBoxLay.addStretch()

        saveButtHBoxLay = QHBoxLayout()
        saveButtHBoxLay.addWidget(configSaveButt)

        updateButtHBoxLay = QHBoxLayout()
        updateButtHBoxLay.addWidget(updateButt)

        # Создаем вертикальное пространство
        vBoxLay = QVBoxLayout()
        # Прикрепляем пространство к левому верхнему краю
        vBoxLay.setAlignment(Qt.AlignTop | Qt.AlignLeft)
        vBoxLay.addLayout(hPortBoxLay)
        vBoxLay.addStretch(1)
        vBoxLay.addLayout(saveButtHBoxLay)
        vBoxLay.addLayout(updateButtHBoxLay)

        self.setLayout(vBoxLay)

        self.hide()

    def set_port_info(self):
        self.setting_info_['Port'] = self.portBox.currentText()
        self.setting_info_['Speed'] = self.speedBox.currentText()
        self.S_port_info.emit(self.setting_info_["Port"],
                              self.setting_info_['Speed'])
        self.S_save_butt_clicked.emit(True)

    def update_ports(self, ports):
        print("ports updated")
        self.ports_ = ports
        self.portBox.clear()
        self.portBox.addItems(self.ports_)

    def act_update_ports(self):
        self.S_update_ports.emit(True)
Exemple #33
0
class StatsWindow(QWidget):

    def __init__(self):
        super().__init__()
        self.setGeometry(150 + 1024, 150, 800, 600)

        main_box = QVBoxLayout()

        self.graph_rfi = PlotWidget()
        self.graph_rfi.setBackground("w")
        self.graph_rfi.setTitle("RFI", color="k")
        self.graph_rfi.plot = self.graph_rfi.plot([0,0], [0],
                                                  pen=mkPen('k', width=1),
                                                  stepMode=True)
        self.graph_cand = PlotWidget()
        self.graph_cand.setBackground("w")
        self.graph_cand.setTitle("Candidates", color="k")
        self.graph_cand.plot = self.graph_cand.plot([0,0], [0],
                                                  pen=mkPen('k', width=1),
                                                  stepMode=True)

        self.dist_plot = PlotWidget()
        self.dist_plot.setMouseEnabled(y=False)
        self.dist_plot.setBackground("w")
        self.dist_plot.setTitle("Full distribution", color="k")
        self.dist_plot.plot = self.dist_plot.plot([0,0], [0],
                                                  pen=mkPen('k', width=1),
                                                  stepMode=True)


        plots_box = QHBoxLayout()
        plots_box.addWidget(self.graph_rfi)
        plots_box.addWidget(self.graph_cand)
        main_box.addLayout(plots_box)
        main_box.addWidget(self.dist_plot)

        limits_box = QHBoxLayout()
        limits_box.setAlignment(Qt.AlignLeft)
        
        self.limits_choice = QComboBox()
        self.limits_choice.addItems(["DM", "MJD"])
        self.limits_choice.setFixedWidth(100)
        limits_box.addWidget(self.limits_choice)
        self.start_limit = QLineEdit()
        self.start_limit.setPlaceholderText("from")
        self.start_limit.setFixedWidth(150)
        limits_box.addWidget(self.start_limit)
        self.end_limit = QLineEdit()
        self.end_limit.setPlaceholderText("to")
        self.end_limit.setFixedWidth(150)
        limits_box.addWidget(self.end_limit)
        self.apply_limits_button = QPushButton()
        self.apply_limits_button.setFixedWidth(150)
        self.apply_limits_button.setText("Remove limits")
        limits_box.addWidget(self.apply_limits_button)
        self.remove_label = QLabel()
        limits_box.addWidget(self.remove_label)
        main_box.addLayout(limits_box)
        

        self.setLayout(main_box)

    def _update(self, rfi_data, cand_data):

        y_rfi, x_rfi = histogram([cand[1] for cand in rfi_data],
                                 bins=min(len(rfi_data) + 1, 100))
        self.graph_rfi.plot.setData(x_rfi, y_rfi)

        y_cand, x_cand = histogram([cand[1] for cand in cand_data],
                                   bins=min(len(cand_data) + 1, 100))
        self.graph_cand.plot.setData(x_cand, y_cand)

    def update_dist_plot(self, data, extra_dec=False):

        y_dist, x_dist = histogram(data, bins=100)
        ax = self.dist_plot.getAxis("bottom")

        min_val = min(data)
        max_val = max(data)
        tick_vals = linspace(min_val, max_val, num=6)
        decimals = 2 + extra_dec * 4
        ticks = [(val, "{:.{dec}f}".format(val, dec=decimals)) for val in tick_vals]
        ax.setTicks( [ticks, []])
        ax.setStyle(tickLength=-5)
        self.dist_plot.plot.setData(x_dist, y_dist)
        self.dist_plot.autoRange()
class QSessionWidget(QWidget):
    """
    Create a new session widget to be put inside a tab in the main window
    For each session we can have many displays
    """

    # define a signal when the user successful log in
    logged_in = pyqtSignal(str)

    sessions_changed = pyqtSignal(collections.deque)

    def __init__(self, parent):
        super(QWidget, self).__init__(parent)

        self.user = ""
        self.displays = {}

        self.config_file_name = os.path.join(os.path.expanduser('~'), '.rcm',
                                             'RCM2.cfg')
        self.sessions_list = None
        self.parser = RawConfigParser()

        # widgets
        self.session_combo = QComboBox(self)
        self.host_line = QLineEdit(self)
        self.user_line = QLineEdit(self)
        self.pssw_line = QLineEdit(self)

        # containers
        self.containerLoginWidget = QWidget()
        self.containerSessionWidget = QWidget()

        # layouts
        self.session_ver_layout = QVBoxLayout()
        self.rows_ver_layout = QVBoxLayout()

        # icons
        self.connect_ico = QIcon()
        self.kill_ico = QIcon()
        self.share_ico = QIcon()

        self.init_ui()

        self.uuid = uuid.uuid4().hex

    def init_ui(self):
        """
        Initialize the interface
        """

        # Login Layout
        # grid login layout
        grid_login_layout = QGridLayout()

        # parse config file to load the most recent sessions
        if os.path.exists(self.config_file_name):
            try:
                with open(self.config_file_name, 'r') as config_file:
                    self.parser.read_file(config_file,
                                          source=self.config_file_name)
                    sessions_list = self.parser.get('LoginFields', 'hostList')
                    self.sessions_list = collections.deque(
                        json.loads(sessions_list), maxlen=5)
            except:
                logger.error(
                    "Failed to load the sessions list from the config file")

        session_label = QLabel(self)
        session_label.setText('Sessions:')
        self.session_combo.clear()
        self.session_combo.addItems(self.sessions_list)

        self.session_combo.activated.connect(self.on_session_change)
        if self.sessions_list:
            self.session_combo.activated.emit(0)

        grid_login_layout.addWidget(session_label, 0, 0)
        grid_login_layout.addWidget(self.session_combo, 0, 1)

        host_label = QLabel(self)
        host_label.setText('Host:')

        grid_login_layout.addWidget(host_label, 1, 0)
        grid_login_layout.addWidget(self.host_line, 1, 1)

        user_label = QLabel(self)
        user_label.setText('User:'******'Password:'******'Login', self)
        pybutton.clicked.connect(self.login)
        pybutton.setShortcut("Return")

        login_hor_layout = QHBoxLayout()
        login_hor_layout.addStretch(1)
        login_hor_layout.addWidget(pybutton)
        login_hor_layout.addStretch(1)

        # login layout
        # it disappears when the user logged in
        login_layout = QVBoxLayout()
        login_layout.addLayout(grid_login_layout)
        login_layout.addLayout(login_hor_layout)

        self.containerLoginWidget.setLayout(login_layout)

        # Create the main layout
        new_tab_main_layout = QVBoxLayout()
        new_tab_main_layout.addWidget(self.containerLoginWidget)

        # Session Layout
        plusbutton_layout = QGridLayout()
        self.rows_ver_layout.setContentsMargins(0, 0, 0, 0)
        self.rows_ver_layout.setSpacing(0)

        self.session_ver_layout.addLayout(plusbutton_layout)
        self.session_ver_layout.addLayout(self.rows_ver_layout)
        self.session_ver_layout.addStretch(1)

        self.connect_ico.addFile(resource_path('icons/connect.png'))
        self.kill_ico.addFile(resource_path('icons/kill.png'))
        self.share_ico.addFile(resource_path('icons/share.png'))

        font = QFont()
        font.setBold(True)

        name = QLabel()
        name.setText("Name")
        name.setFont(font)
        plusbutton_layout.addWidget(name, 0, 0)

        status = QLabel()
        status.setText("Status")
        status.setFont(font)
        plusbutton_layout.addWidget(status, 0, 1)

        time = QLabel()
        time.setText("Time")
        time.setFont(font)
        plusbutton_layout.addWidget(time, 0, 2)

        resources = QLabel()
        resources.setText("Resources")
        resources.setFont(font)
        plusbutton_layout.addWidget(resources, 0, 3)

        x = QLabel()
        x.setText("")
        plusbutton_layout.addWidget(x, 0, 4)
        plusbutton_layout.addWidget(x, 0, 5)

        new_display_ico = QIcon()
        new_display_ico.addFile(resource_path('icons/plus.png'), QSize(16, 16))

        new_display_btn = QPushButton()
        new_display_btn.setIcon(new_display_ico)
        new_display_btn.setToolTip('Create a new display session')
        new_display_btn.clicked.connect(self.add_new_display)

        new_display_layout = QHBoxLayout()
        new_display_layout.addSpacing(100)
        new_display_layout.addWidget(new_display_btn)

        plusbutton_layout.addLayout(new_display_layout, 0, 6)

        self.containerSessionWidget.setLayout(self.session_ver_layout)
        new_tab_main_layout.addWidget(self.containerSessionWidget)
        self.containerSessionWidget.hide()

        self.setLayout(new_tab_main_layout)

    def on_session_change(self):
        """
        Update the user and host fields when the user selects a different session in the combo
        :return:
        """
        try:
            user, host = self.session_combo.currentText().split('@')
            self.user_line.setText(user)
            self.host_line.setText(host)
        except ValueError:
            pass

    def login(self):
        session_name = str(self.user_line.text()) + "@" + str(
            self.host_line.text())

        try:
            logger.info("Logging into " + session_name)
            ssh_login(self.host_line.text(), 22, self.user_line.text(),
                      self.pssw_line.text(), 'ls')
        except AuthenticationException:
            logger.error("Failed to login: invalid credentials")
            return

        logger.info("Logged in " + session_name)
        self.user = self.user_line.text()

        # update sessions list
        if session_name in list(self.sessions_list):
            self.sessions_list.remove(session_name)
        self.sessions_list.appendleft(session_name)

        self.sessions_changed.emit(self.sessions_list)

        # update config file
        self.update_config_file(session_name)

        # Hide the login view and show the session one
        self.containerLoginWidget.hide()
        self.containerSessionWidget.show()

        # Emit the logged_in signal.
        self.logged_in.emit(session_name)

    def add_new_display(self):
        # cannot have more than 5 sessions
        if len(self.displays) >= 5:
            logger.warning("You have already 5 displays")
            return

        display_win = QDisplayDialog(list(self.displays.keys()))
        display_win.setModal(True)

        if display_win.exec() != 1:
            return

        display_hor_layout = QHBoxLayout()
        display_hor_layout.setContentsMargins(0, 2, 0, 2)
        display_hor_layout.setSpacing(2)

        display_ver_layout = QVBoxLayout()
        display_ver_layout.setContentsMargins(0, 0, 0, 0)
        display_ver_layout.setSpacing(0)

        display_ver_layout.addLayout(display_hor_layout)

        display_widget = QWidget()
        display_widget.setLayout(display_ver_layout)

        id = display_win.display_name
        print(id)

        name = QLabel()
        name.setText(str(id)[:16])
        display_hor_layout.addWidget(name)

        status = QLabel()
        status.setText("Pending...")
        display_hor_layout.addWidget(status)

        time = QLabel()
        time.setText("24H")
        display_hor_layout.addWidget(time)

        resources = QLabel()
        resources.setText("1 Node")
        display_hor_layout.addWidget(resources)

        connect_btn = QPushButton()
        connect_btn.setIcon(self.connect_ico)
        connect_btn.setToolTip('Connect to the remote display')
        connect_btn.clicked.connect(lambda: self.connect_display(id))
        display_hor_layout.addWidget(connect_btn)

        share_btn = QPushButton()
        share_btn.setIcon(self.share_ico)
        share_btn.setToolTip('Share the remote display via file')
        share_btn.clicked.connect(lambda: self.share_display(id))
        display_hor_layout.addWidget(share_btn)

        kill_btn = QPushButton()
        kill_btn.setIcon(self.kill_ico)
        kill_btn.setToolTip('Kill the remote display')
        kill_btn.clicked.connect(lambda: self.kill_display(id))
        display_hor_layout.addWidget(kill_btn)

        separator = QFrame()
        separator.setFrameShape(QFrame.HLine)
        separator.setFrameShadow(QFrame.Sunken)
        display_ver_layout.addWidget(separator)

        self.rows_ver_layout.addWidget(display_widget)

        self.displays[id] = display_widget
        logger.info("Added new display")

    def update_config_file(self, session_name):
        """
        Update the config file with the new session name
        :param session_name: name of the last session inserted by the user
        :return:
        """
        if not self.parser.has_section('LoginFields'):
            self.parser.add_section('LoginFields')

        self.parser.set('LoginFields', 'hostList',
                        json.dumps(list(self.sessions_list)))

        try:
            config_file_dir = os.path.dirname(self.config_file_name)
            if not os.path.exists(config_file_dir):
                os.makedirs(config_file_dir)

            with open(
                    os.path.join(os.path.expanduser('~'), '.rcm', 'RCM2.cfg'),
                    'w') as config_file:
                self.parser.write(config_file)
        except:
            logger.error(
                "failed to dump the session list in the configuration file")

    def connect_display(self, id):
        print(self.displays[id])
        logger.info("Connected to remote display " + str(id))

    def share_display(self, id):
        print(self.displays[id])
        logger.info("Shared display " + str(id))

    def kill_display(self, id):
        # first we hide the display
        logger.debug("Hiding display " + str(id))
        self.displays[id].hide()

        # then we remove it from the layout and the dictionary
        self.rows_ver_layout.removeWidget(self.displays[id])
        del self.displays[id]

        logger.info("Killed display " + str(id))
Exemple #35
0
app = QApplication([])
print('initialised app')
data = networkData()
print('initialised data')
window = QWidget()
print('initialised window')
print('program initialised')
print('setting layout')
layout = QVBoxLayout()

layout.addWidget(QLabel('Program to graph network speeds and ping times'))
print('Added label')

QComboBox()
ssids = QComboBox()
ssids.addItems(data.ssids)
layout.addWidget(ssids)

metrics = QComboBox()
metrics.addItems(data.data[data.ssids[0]].columns)
layout.addWidget(metrics)

window.setLayout(layout)
window.show()

app.exec_()


data = networkData()
data.plotter(data.ssids[1])
class NetworkChoiceLayout(object):
    def __init__(self, network: Network, config: 'SimpleConfig', wizard=False):
        self.network = network
        self.config = config
        self.tor_proxy = None

        self.tabs = tabs = QTabWidget()
        proxy_tab = QWidget()
        blockchain_tab = QWidget()
        tabs.addTab(blockchain_tab, _('Overview'))
        tabs.addTab(proxy_tab, _('Proxy'))

        fixed_width_hostname = 24 * char_width_in_lineedit()
        fixed_width_port = 6 * char_width_in_lineedit()

        # Proxy tab
        grid = QGridLayout(proxy_tab)
        grid.setSpacing(8)

        # proxy setting
        self.proxy_cb = QCheckBox(_('Use proxy'))
        self.proxy_cb.clicked.connect(self.check_disable_proxy)
        self.proxy_cb.clicked.connect(self.set_proxy)
        self.proxy_cb.setEnabled(self.config.is_modifiable('proxy'))

        self.proxy_mode = QComboBox()
        self.proxy_mode.addItems(['SOCKS4', 'SOCKS5'])
        self.proxy_host = QLineEdit()
        self.proxy_host.setFixedWidth(fixed_width_hostname)
        self.proxy_port = QLineEdit()
        self.proxy_port.setFixedWidth(fixed_width_port)
        self.proxy_user = QLineEdit()
        self.proxy_user.setPlaceholderText(_("Proxy user"))
        self.proxy_password = PasswordLineEdit()
        self.proxy_password.setPlaceholderText(_("Password"))
        self.proxy_password.setFixedWidth(fixed_width_port)

        self.proxy_mode.currentIndexChanged.connect(self.set_proxy)
        self.proxy_host.editingFinished.connect(self.set_proxy)
        self.proxy_port.editingFinished.connect(self.set_proxy)
        self.proxy_user.editingFinished.connect(self.set_proxy)
        self.proxy_password.editingFinished.connect(self.set_proxy)

        self.proxy_mode.currentIndexChanged.connect(
            self.proxy_settings_changed)
        self.proxy_host.textEdited.connect(self.proxy_settings_changed)
        self.proxy_port.textEdited.connect(self.proxy_settings_changed)
        self.proxy_user.textEdited.connect(self.proxy_settings_changed)
        self.proxy_password.textEdited.connect(self.proxy_settings_changed)

        self.tor_cb = QCheckBox(_("Use Tor Proxy"))
        self.tor_cb.setIcon(read_QIcon("tor_logo.png"))
        self.tor_cb.hide()
        self.tor_cb.clicked.connect(self.use_tor_proxy)

        self.tor_auto_on_cb = QCheckBox(self.network.TOR_AUTO_ON_MSG)
        self.tor_auto_on_cb.setIcon(read_QIcon("tor_logo.png"))
        self.tor_auto_on_cb.setChecked(self.config.get('tor_auto_on', True))
        self.tor_auto_on_cb.clicked.connect(self.use_tor_auto_on)

        self.fiat_bypass_tor_cb = QCheckBox(self.network.FIAT_BYPASS_TOR_MSG)
        fiat_bypass_tor = self.config.get('fiat_bypass_tor', False)
        self.fiat_bypass_tor_cb.setChecked(fiat_bypass_tor)
        self.fiat_bypass_tor_cb.clicked.connect(self.fiat_bypass_tor)

        grid.addWidget(self.tor_cb, 1, 0, 1, 3)
        grid.addWidget(self.proxy_cb, 2, 0, 1, 3)
        grid.addWidget(
            HelpButton(
                _('Proxy settings apply to all connections: with Dash Electrum servers, but also with third-party services.'
                  )), 2, 4)
        grid.addWidget(self.proxy_mode, 4, 1)
        grid.addWidget(self.proxy_host, 4, 2)
        grid.addWidget(self.proxy_port, 4, 3)
        grid.addWidget(self.proxy_user, 5, 2)
        grid.addWidget(self.proxy_password, 5, 3)
        grid.addWidget(self.tor_auto_on_cb, 6, 0, 1, 3)
        grid.addWidget(
            HelpButton(
                _('During wallet startup try to detect and use Tor Proxy.')),
            6, 4)
        grid.addWidget(self.fiat_bypass_tor_cb, 7, 0, 1, 3)
        grid.setRowStretch(8, 1)

        # Blockchain Tab
        grid = QGridLayout(blockchain_tab)
        msg = ' '.join([
            _("Dash Electrum connects to several nodes in order to download block headers and find out the longest blockchain."
              ),
            _("This blockchain is used to verify the transactions sent by your transaction server."
              )
        ])
        self.status_label = QLabel('')
        grid.addWidget(QLabel(_('Status') + ':'), 0, 0)
        grid.addWidget(self.status_label, 0, 1, 1, 3)
        grid.addWidget(HelpButton(msg), 0, 4)

        self.autoconnect_cb = QCheckBox(_('Select server automatically'))
        self.autoconnect_cb.setEnabled(
            self.config.is_modifiable('auto_connect'))
        self.autoconnect_cb.clicked.connect(self.set_server)
        self.autoconnect_cb.clicked.connect(self.update)
        msg = ' '.join([
            _("If auto-connect is enabled, Dash Electrum will always use a server that is on the longest blockchain."
              ),
            _("If it is disabled, you have to choose a server you want to use. Dash Electrum will warn you if your server is lagging."
              )
        ])
        grid.addWidget(self.autoconnect_cb, 1, 0, 1, 3)
        grid.addWidget(HelpButton(msg), 1, 4)

        self.server_e = QLineEdit()
        self.server_e.setFixedWidth(fixed_width_hostname + fixed_width_port)
        self.server_e.editingFinished.connect(self.set_server)
        msg = _(
            "Dash Electrum sends your wallet addresses to a single server, in order to receive your transaction history."
        )
        grid.addWidget(QLabel(_('Server') + ':'), 2, 0)
        grid.addWidget(self.server_e, 2, 1, 1, 3)
        grid.addWidget(HelpButton(msg), 2, 4)

        self.height_label = QLabel('')
        msg = _('This is the height of your local copy of the blockchain.')
        grid.addWidget(QLabel(_('Blockchain') + ':'), 3, 0)
        grid.addWidget(self.height_label, 3, 1)
        grid.addWidget(HelpButton(msg), 3, 4)

        self.split_label = QLabel('')
        grid.addWidget(self.split_label, 4, 0, 1, 3)

        self.nodes_list_widget = NodesListWidget(self)
        grid.addWidget(self.nodes_list_widget, 6, 0, 1, 5)

        vbox = QVBoxLayout()
        vbox.addWidget(tabs)
        self.layout_ = vbox
        # tor detector
        self.td = td = TorDetector()
        td.found_proxy.connect(self.suggest_proxy)
        td.start()

        self.fill_in_proxy_settings()
        self.update()

    def clean_up(self):
        if self.td:
            self.td.found_proxy.disconnect()
            self.td.stop()
            self.td = None

    def check_disable_proxy(self, b):
        if not self.config.is_modifiable('proxy'):
            b = False
        for w in [
                self.proxy_mode, self.proxy_host, self.proxy_port,
                self.proxy_user, self.proxy_password
        ]:
            w.setEnabled(b)

    def enable_set_server(self):
        if self.config.is_modifiable('server'):
            enabled = not self.autoconnect_cb.isChecked()
            self.server_e.setEnabled(enabled)
        else:
            for w in [
                    self.autoconnect_cb, self.server_e, self.nodes_list_widget
            ]:
                w.setEnabled(False)

    def update(self):
        net_params = self.network.get_parameters()
        server = net_params.server
        auto_connect = net_params.auto_connect
        if not self.server_e.hasFocus():
            self.server_e.setText(server.to_friendly_name())
        self.autoconnect_cb.setChecked(auto_connect)

        height_str = "%d " % (self.network.get_local_height()) + _('blocks')
        self.height_label.setText(height_str)
        n = len(self.network.get_interfaces())
        status = _("Connected to {0} nodes.").format(n) if n > 1 else _(
            "Connected to {0} node.").format(n) if n == 1 else _(
                "Not connected")
        self.status_label.setText(status)
        chains = self.network.get_blockchains()
        if len(chains) > 1:
            chain = self.network.blockchain()
            forkpoint = chain.get_max_forkpoint()
            name = chain.get_name()
            msg = _('Chain split detected at block {0}').format(
                forkpoint) + '\n'
            msg += (_('You are following branch') if auto_connect else
                    _('Your server is on branch')) + ' ' + name
            msg += ' (%d %s)' % (chain.get_branch_size(), _('blocks'))
        else:
            msg = ''
        self.split_label.setText(msg)
        self.nodes_list_widget.update(network=self.network,
                                      servers=self.network.get_servers(),
                                      use_tor=self.tor_cb.isChecked())
        self.enable_set_server()

    def fill_in_proxy_settings(self):
        proxy_config = self.network.get_parameters().proxy
        if not proxy_config:
            proxy_config = {
                "mode": "none",
                "host": "localhost",
                "port": "9050"
            }

        b = proxy_config.get('mode') != "none"
        self.check_disable_proxy(b)
        if b:
            self.proxy_cb.setChecked(True)
            self.proxy_mode.setCurrentIndex(
                self.proxy_mode.findText(str(
                    proxy_config.get("mode").upper())))

        self.proxy_host.setText(proxy_config.get("host"))
        self.proxy_port.setText(proxy_config.get("port"))
        self.proxy_user.setText(proxy_config.get("user", ""))
        self.proxy_password.setText(proxy_config.get("password", ""))

    def layout(self):
        return self.layout_

    def follow_branch(self, chain_id):
        self.network.run_from_another_thread(
            self.network.follow_chain_given_id(chain_id))
        self.update()

    def follow_server(self, server: ServerAddr):
        self.network.run_from_another_thread(
            self.network.follow_chain_given_server(server))
        self.update()

    def accept(self):
        pass

    def set_server(self):
        net_params = self.network.get_parameters()
        try:
            server = ServerAddr.from_str_with_inference(
                str(self.server_e.text()))
            if not server: raise Exception("failed to parse")
        except Exception:
            return
        net_params = net_params._replace(
            server=server, auto_connect=self.autoconnect_cb.isChecked())
        self.network.run_from_another_thread(
            self.network.set_parameters(net_params))

    def set_proxy(self):
        net_params = self.network.get_parameters()
        if self.proxy_cb.isChecked():
            proxy = {
                'mode': str(self.proxy_mode.currentText()).lower(),
                'host': str(self.proxy_host.text()),
                'port': str(self.proxy_port.text()),
                'user': str(self.proxy_user.text()),
                'password': str(self.proxy_password.text())
            }
        else:
            proxy = None
            self.tor_cb.setChecked(False)
        net_params = net_params._replace(proxy=proxy)
        self.network.run_from_another_thread(
            self.network.set_parameters(net_params))

    def suggest_proxy(self, found_proxy):
        if found_proxy is None:
            self.tor_cb.hide()
            return
        self.tor_proxy = found_proxy
        self.tor_cb.setText("Use Tor proxy at port " + str(found_proxy[1]))
        if (self.proxy_cb.isChecked() and self.proxy_mode.currentIndex()
                == self.proxy_mode.findText('SOCKS5')
                and self.proxy_host.text() == "127.0.0.1"
                and self.proxy_port.text() == str(found_proxy[1])):
            self.tor_cb.setChecked(True)
        self.tor_cb.show()

    def use_tor_proxy(self, use_it):
        if not use_it:
            self.proxy_cb.setChecked(False)
        else:
            socks5_mode_index = self.proxy_mode.findText('SOCKS5')
            if socks5_mode_index == -1:
                _logger.info("can't find proxy_mode 'SOCKS5'")
                return
            self.proxy_mode.setCurrentIndex(socks5_mode_index)
            self.proxy_host.setText("127.0.0.1")
            self.proxy_port.setText(str(self.tor_proxy[1]))
            self.proxy_user.setText("")
            self.proxy_password.setText("")
            self.tor_cb.setChecked(True)
            self.proxy_cb.setChecked(True)
        self.check_disable_proxy(use_it)
        self.set_proxy()

    def fiat_bypass_tor(self, bypass):
        self.config.set_key('fiat_bypass_tor', bypass, False)
        coro = self.network.restart()
        self.network.run_from_another_thread(coro)

    def proxy_settings_changed(self):
        self.tor_cb.setChecked(False)

    def use_tor_auto_on(self, use_it):
        self.config.set_key('tor_auto_on', use_it, True)
Exemple #37
0
    def __init__(self, parent: 'ElectrumWindow', config: 'SimpleConfig'):
        WindowModalDialog.__init__(self, parent, _('Preferences'))
        self.config = config
        self.window = parent
        self.need_restart = False
        self.fx = self.window.fx
        self.wallet = self.window.wallet

        vbox = QVBoxLayout()
        tabs = QTabWidget()
        gui_widgets = []
        tx_widgets = []
        oa_widgets = []

        # language
        lang_help = _(
            'Select which language is used in the GUI (after restart).')
        lang_label = HelpLabel(_('Language') + ':', lang_help)
        lang_combo = QComboBox()
        lang_combo.addItems(list(languages.values()))
        lang_keys = list(languages.keys())
        lang_cur_setting = self.config.get("language", '')
        try:
            index = lang_keys.index(lang_cur_setting)
        except ValueError:  # not in list
            index = 0
        lang_combo.setCurrentIndex(index)
        if not self.config.is_modifiable('language'):
            for w in [lang_combo, lang_label]:
                w.setEnabled(False)

        def on_lang(x):
            lang_request = list(languages.keys())[lang_combo.currentIndex()]
            if lang_request != self.config.get('language'):
                self.config.set_key("language", lang_request, True)
                self.need_restart = True

        lang_combo.currentIndexChanged.connect(on_lang)
        gui_widgets.append((lang_label, lang_combo))

        nz_help = _(
            'Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"'
        )
        nz_label = HelpLabel(_('Zeros after decimal point') + ':', nz_help)
        nz = QSpinBox()
        nz.setMinimum(0)
        nz.setMaximum(self.config.decimal_point)
        nz.setValue(self.config.num_zeros)
        if not self.config.is_modifiable('num_zeros'):
            for w in [nz, nz_label]:
                w.setEnabled(False)

        def on_nz():
            value = nz.value()
            if self.config.num_zeros != value:
                self.config.num_zeros = value
                self.config.set_key('num_zeros', value, True)
                self.window.history_list.update()
                self.window.address_list.update()

        nz.valueChanged.connect(on_nz)
        gui_widgets.append((nz_label, nz))

        #use_rbf = bool(self.config.get('use_rbf', True))
        #use_rbf_cb = QCheckBox(_('Use Replace-By-Fee'))
        #use_rbf_cb.setChecked(use_rbf)
        #use_rbf_cb.setToolTip(
        #    _('If you check this box, your transactions will be marked as non-final,') + '\n' + \
        #    _('and you will have the possibility, while they are unconfirmed, to replace them with transactions that pay higher fees.') + '\n' + \
        #    _('Note that some merchants do not accept non-final transactions until they are confirmed.'))
        #def on_use_rbf(x):
        #    self.config.set_key('use_rbf', bool(x))
        #    batch_rbf_cb.setEnabled(bool(x))
        #use_rbf_cb.stateChanged.connect(on_use_rbf)
        #tx_widgets.append((use_rbf_cb, None))

        #batch_rbf_cb = QCheckBox(_('Batch RBF transactions'))
        #batch_rbf_cb.setChecked(bool(self.config.get('batch_rbf', False)))
        #batch_rbf_cb.setEnabled(use_rbf)
        #batch_rbf_cb.setToolTip(
        #    _('If you check this box, your unconfirmed transactions will be consolidated into a single transaction.') + '\n' + \
        #    _('This will save fees.'))
        #def on_batch_rbf(x):
        #    self.config.set_key('batch_rbf', bool(x))
        #batch_rbf_cb.stateChanged.connect(on_batch_rbf)
        #tx_widgets.append((batch_rbf_cb, None))

        # lightning
        lightning_widgets = []

        help_local_wt = _("""If this option is checked, Electrum will
run a local watchtower and protect your channels even if your wallet is not
open. For this to work, your computer needs to be online regularly.""")
        local_wt_cb = QCheckBox(_("Run a local watchtower"))
        local_wt_cb.setToolTip(help_local_wt)
        local_wt_cb.setChecked(
            bool(self.config.get('run_local_watchtower', False)))

        def on_local_wt_checked(x):
            self.config.set_key('run_local_watchtower', bool(x))

        local_wt_cb.stateChanged.connect(on_local_wt_checked)
        lightning_widgets.append((local_wt_cb, None))

        help_persist = _(
            """If this option is checked, Electrum will persist after
you close all your wallet windows, and the Electrum icon will be visible in the taskbar.
Use this if you want your local watchtower to keep running after you close your wallet."""
        )
        persist_cb = QCheckBox(_("Persist after all windows are closed"))
        persist_cb.setToolTip(help_persist)
        persist_cb.setChecked(bool(self.config.get('persist_daemon', False)))

        def on_persist_checked(x):
            self.config.set_key('persist_daemon', bool(x))

        persist_cb.stateChanged.connect(on_persist_checked)
        lightning_widgets.append((persist_cb, None))

        help_remote_wt = _(
            """To use a remote watchtower, enter the corresponding URL here""")
        remote_wt_cb = QCheckBox(_("Use a remote watchtower"))
        remote_wt_cb.setToolTip(help_remote_wt)
        remote_wt_cb.setChecked(bool(self.config.get('use_watchtower', False)))

        def on_remote_wt_checked(x):
            self.config.set_key('use_watchtower', bool(x))
            self.watchtower_url_e.setEnabled(bool(x))

        remote_wt_cb.stateChanged.connect(on_remote_wt_checked)
        watchtower_url = self.config.get('watchtower_url')
        self.watchtower_url_e = QLineEdit(watchtower_url)
        self.watchtower_url_e.setEnabled(
            self.config.get('use_watchtower', False))

        def on_wt_url():
            url = self.watchtower_url_e.text() or None
            watchtower_url = self.config.set_key('watchtower_url', url)

        self.watchtower_url_e.editingFinished.connect(on_wt_url)
        lightning_widgets.append((remote_wt_cb, self.watchtower_url_e))

        msg = _('OpenAlias record, used to receive coins and to sign payment requests.') + '\n\n'\
              + _('The following alias providers are available:') + '\n'\
              + '\n'.join(['https://cryptoname.co/', 'http://xmr.link']) + '\n\n'\
              + 'For more information, see https://openalias.org'
        alias_label = HelpLabel(_('OpenAlias') + ':', msg)
        alias = self.config.get('alias', '')
        self.alias_e = QLineEdit(alias)
        self.set_alias_color()
        self.alias_e.editingFinished.connect(self.on_alias_edit)
        oa_widgets.append((alias_label, self.alias_e))

        # units
        units = base_units_list
        msg = (_(
            'Base unit of your wallet.'
        ) + '\n1 BTC = 1000 mBTC. 1 mBTC = 1000 bits. 1 bit = 100 sat.\n' + _(
            'This setting affects the Send tab, and all balance related fields.'
        ))
        unit_label = HelpLabel(_('Base unit') + ':', msg)
        unit_combo = QComboBox()
        unit_combo.addItems(units)
        unit_combo.setCurrentIndex(units.index(self.window.base_unit()))

        def on_unit(x, nz):
            unit_result = units[unit_combo.currentIndex()]
            if self.window.base_unit() == unit_result:
                return
            edits = self.window.amount_e, self.window.receive_amount_e
            amounts = [edit.get_amount() for edit in edits]
            self.config.set_base_unit(unit_result)
            nz.setMaximum(self.config.decimal_point)
            self.window.history_list.update()
            self.window.request_list.update()
            self.window.address_list.update()
            for edit, amount in zip(edits, amounts):
                edit.setAmount(amount)
            self.window.update_status()

        unit_combo.currentIndexChanged.connect(lambda x: on_unit(x, nz))
        gui_widgets.append((unit_label, unit_combo))

        system_cameras = qrscanner._find_system_cameras()
        qr_combo = QComboBox()
        qr_combo.addItem("Default", "default")
        for camera, device in system_cameras.items():
            qr_combo.addItem(camera, device)
        #combo.addItem("Manually specify a device", config.get("video_device"))
        index = qr_combo.findData(self.config.get("video_device"))
        qr_combo.setCurrentIndex(index)
        msg = _("Install the zbar package to enable this.")
        qr_label = HelpLabel(_('Video Device') + ':', msg)
        qr_combo.setEnabled(qrscanner.libzbar is not None)
        on_video_device = lambda x: self.config.set_key(
            "video_device", qr_combo.itemData(x), True)
        qr_combo.currentIndexChanged.connect(on_video_device)
        gui_widgets.append((qr_label, qr_combo))

        colortheme_combo = QComboBox()
        colortheme_combo.addItem(_('Light'), 'default')
        colortheme_combo.addItem(_('Dark'), 'dark')
        index = colortheme_combo.findData(
            self.config.get('qt_gui_color_theme', 'default'))
        colortheme_combo.setCurrentIndex(index)
        colortheme_label = QLabel(_('Color theme') + ':')

        def on_colortheme(x):
            self.config.set_key('qt_gui_color_theme',
                                colortheme_combo.itemData(x), True)
            self.need_restart = True

        colortheme_combo.currentIndexChanged.connect(on_colortheme)
        gui_widgets.append((colortheme_label, colortheme_combo))

        updatecheck_cb = QCheckBox(
            _("Automatically check for software updates"))
        updatecheck_cb.setChecked(bool(self.config.get('check_updates',
                                                       False)))

        def on_set_updatecheck(v):
            self.config.set_key('check_updates', v == Qt.Checked, save=True)

        updatecheck_cb.stateChanged.connect(on_set_updatecheck)
        gui_widgets.append((updatecheck_cb, None))

        filelogging_cb = QCheckBox(_("Write logs to file"))
        filelogging_cb.setChecked(bool(self.config.get('log_to_file', False)))

        def on_set_filelogging(v):
            self.config.set_key('log_to_file', v == Qt.Checked, save=True)
            self.need_restart = True

        filelogging_cb.stateChanged.connect(on_set_filelogging)
        filelogging_cb.setToolTip(
            _('Debug logs can be persisted to disk. These are useful for troubleshooting.'
              ))
        gui_widgets.append((filelogging_cb, None))

        preview_cb = QCheckBox(_('Advanced preview'))
        preview_cb.setChecked(bool(self.config.get('advanced_preview', False)))
        preview_cb.setToolTip(
            _("Open advanced transaction preview dialog when 'Pay' is clicked."
              ))

        def on_preview(x):
            self.config.set_key('advanced_preview', x == Qt.Checked)

        preview_cb.stateChanged.connect(on_preview)
        tx_widgets.append((preview_cb, None))

        usechange_cb = QCheckBox(_('Use change addresses'))
        usechange_cb.setChecked(self.window.wallet.use_change)
        if not self.config.is_modifiable('use_change'):
            usechange_cb.setEnabled(False)

        def on_usechange(x):
            usechange_result = x == Qt.Checked
            if self.window.wallet.use_change != usechange_result:
                self.window.wallet.use_change = usechange_result
                self.window.wallet.db.put('use_change',
                                          self.window.wallet.use_change)
                multiple_cb.setEnabled(self.window.wallet.use_change)

        usechange_cb.stateChanged.connect(on_usechange)
        usechange_cb.setToolTip(
            _('Using change addresses makes it more difficult for other people to track your transactions.'
              ))
        tx_widgets.append((usechange_cb, None))

        def on_multiple(x):
            multiple = x == Qt.Checked
            if self.wallet.multiple_change != multiple:
                self.wallet.multiple_change = multiple
                self.wallet.db.put('multiple_change', multiple)

        multiple_change = self.wallet.multiple_change
        multiple_cb = QCheckBox(_('Use multiple change addresses'))
        multiple_cb.setEnabled(self.wallet.use_change)
        multiple_cb.setToolTip('\n'.join([
            _('In some cases, use up to 3 change addresses in order to break '
              'up large coin amounts and obfuscate the recipient address.'),
            _('This may result in higher transactions fees.')
        ]))
        multiple_cb.setChecked(multiple_change)
        multiple_cb.stateChanged.connect(on_multiple)
        tx_widgets.append((multiple_cb, None))

        def fmt_docs(key, klass):
            lines = [ln.lstrip(" ") for ln in klass.__doc__.split("\n")]
            return '\n'.join([key, "", " ".join(lines)])

        choosers = sorted(coinchooser.COIN_CHOOSERS.keys())
        if len(choosers) > 1:
            chooser_name = coinchooser.get_name(self.config)
            msg = _(
                'Choose coin (UTXO) selection method.  The following are available:\n\n'
            )
            msg += '\n\n'.join(
                fmt_docs(*item) for item in coinchooser.COIN_CHOOSERS.items())
            chooser_label = HelpLabel(_('Coin selection') + ':', msg)
            chooser_combo = QComboBox()
            chooser_combo.addItems(choosers)
            i = choosers.index(chooser_name) if chooser_name in choosers else 0
            chooser_combo.setCurrentIndex(i)

            def on_chooser(x):
                chooser_name = choosers[chooser_combo.currentIndex()]
                self.config.set_key('coin_chooser', chooser_name)

            chooser_combo.currentIndexChanged.connect(on_chooser)
            tx_widgets.append((chooser_label, chooser_combo))

        def on_unconf(x):
            self.config.set_key('confirmed_only', bool(x))

        conf_only = bool(self.config.get('confirmed_only', False))
        unconf_cb = QCheckBox(_('Spend only confirmed coins'))
        unconf_cb.setToolTip(_('Spend only confirmed inputs.'))
        unconf_cb.setChecked(conf_only)
        unconf_cb.stateChanged.connect(on_unconf)
        tx_widgets.append((unconf_cb, None))

        def on_outrounding(x):
            self.config.set_key('coin_chooser_output_rounding', bool(x))

        enable_outrounding = bool(
            self.config.get('coin_chooser_output_rounding', True))
        outrounding_cb = QCheckBox(_('Enable output value rounding'))
        outrounding_cb.setToolTip(
            _('Set the value of the change output so that it has similar precision to the other outputs.'
              ) + '\n' + _('This might improve your privacy somewhat.') +
            '\n' +
            _('If enabled, at most 100 satoshis might be lost due to this, per transaction.'
              ))
        outrounding_cb.setChecked(enable_outrounding)
        outrounding_cb.stateChanged.connect(on_outrounding)
        tx_widgets.append((outrounding_cb, None))

        block_explorers = sorted(util.block_explorer_info().keys())
        msg = _(
            'Choose which online block explorer to use for functions that open a web browser'
        )
        block_ex_label = HelpLabel(_('Online Block Explorer') + ':', msg)
        block_ex_combo = QComboBox()
        block_ex_combo.addItems(block_explorers)
        block_ex_combo.setCurrentIndex(
            block_ex_combo.findText(util.block_explorer(self.config)))

        def on_be(x):
            be_result = block_explorers[block_ex_combo.currentIndex()]
            self.config.set_key('block_explorer', be_result, True)

        block_ex_combo.currentIndexChanged.connect(on_be)
        tx_widgets.append((block_ex_label, block_ex_combo))

        # Fiat Currency
        hist_checkbox = QCheckBox()
        hist_capgains_checkbox = QCheckBox()
        fiat_address_checkbox = QCheckBox()
        ccy_combo = QComboBox()
        ex_combo = QComboBox()

        def update_currencies():
            if not self.window.fx: return
            currencies = sorted(
                self.fx.get_currencies(self.fx.get_history_config()))
            ccy_combo.clear()
            ccy_combo.addItems([_('None')] + currencies)
            if self.fx.is_enabled():
                ccy_combo.setCurrentIndex(
                    ccy_combo.findText(self.fx.get_currency()))

        def update_history_cb():
            if not self.fx: return
            hist_checkbox.setChecked(self.fx.get_history_config())
            hist_checkbox.setEnabled(self.fx.is_enabled())

        def update_fiat_address_cb():
            if not self.fx: return
            fiat_address_checkbox.setChecked(self.fx.get_fiat_address_config())

        def update_history_capgains_cb():
            if not self.fx: return
            hist_capgains_checkbox.setChecked(
                self.fx.get_history_capital_gains_config())
            hist_capgains_checkbox.setEnabled(hist_checkbox.isChecked())

        def update_exchanges():
            if not self.fx: return
            b = self.fx.is_enabled()
            ex_combo.setEnabled(b)
            if b:
                h = self.fx.get_history_config()
                c = self.fx.get_currency()
                exchanges = self.fx.get_exchanges_by_ccy(c, h)
            else:
                exchanges = self.fx.get_exchanges_by_ccy('USD', False)
            ex_combo.blockSignals(True)
            ex_combo.clear()
            ex_combo.addItems(sorted(exchanges))
            ex_combo.setCurrentIndex(
                ex_combo.findText(self.fx.config_exchange()))
            ex_combo.blockSignals(False)

        def on_currency(hh):
            if not self.fx: return
            b = bool(ccy_combo.currentIndex())
            ccy = str(ccy_combo.currentText()) if b else None
            self.fx.set_enabled(b)
            if b and ccy != self.fx.ccy:
                self.fx.set_currency(ccy)
            update_history_cb()
            update_exchanges()
            self.window.update_fiat()

        def on_exchange(idx):
            exchange = str(ex_combo.currentText())
            if self.fx and self.fx.is_enabled(
            ) and exchange and exchange != self.fx.exchange.name():
                self.fx.set_exchange(exchange)

        def on_history(checked):
            if not self.fx: return
            self.fx.set_history_config(checked)
            update_exchanges()
            self.window.history_model.refresh('on_history')
            if self.fx.is_enabled() and checked:
                self.fx.trigger_update()
            update_history_capgains_cb()

        def on_history_capgains(checked):
            if not self.fx: return
            self.fx.set_history_capital_gains_config(checked)
            self.window.history_model.refresh('on_history_capgains')

        def on_fiat_address(checked):
            if not self.fx: return
            self.fx.set_fiat_address_config(checked)
            self.window.address_list.refresh_headers()
            self.window.address_list.update()

        update_currencies()
        update_history_cb()
        update_history_capgains_cb()
        update_fiat_address_cb()
        update_exchanges()
        ccy_combo.currentIndexChanged.connect(on_currency)
        hist_checkbox.stateChanged.connect(on_history)
        hist_capgains_checkbox.stateChanged.connect(on_history_capgains)
        fiat_address_checkbox.stateChanged.connect(on_fiat_address)
        ex_combo.currentIndexChanged.connect(on_exchange)

        fiat_widgets = []
        fiat_widgets.append((QLabel(_('Fiat currency')), ccy_combo))
        fiat_widgets.append((QLabel(_('Source')), ex_combo))
        fiat_widgets.append((QLabel(_('Show history rates')), hist_checkbox))
        fiat_widgets.append((QLabel(_('Show capital gains in history')),
                             hist_capgains_checkbox))
        fiat_widgets.append((QLabel(_('Show Fiat balance for addresses')),
                             fiat_address_checkbox))

        tabs_info = [
            (gui_widgets, _('General')),
            (tx_widgets, _('Transactions')),
            (lightning_widgets, _('Lightning')),
            (fiat_widgets, _('Fiat')),
            (oa_widgets, _('OpenAlias')),
        ]
        for widgets, name in tabs_info:
            tab = QWidget()
            tab_vbox = QVBoxLayout(tab)
            grid = QGridLayout()
            for a, b in widgets:
                i = grid.rowCount()
                if b:
                    if a:
                        grid.addWidget(a, i, 0)
                    grid.addWidget(b, i, 1)
                else:
                    grid.addWidget(a, i, 0, 1, 2)
            tab_vbox.addLayout(grid)
            tab_vbox.addStretch(1)
            tabs.addTab(tab, name)

        vbox.addWidget(tabs)
        vbox.addStretch(1)
        vbox.addLayout(Buttons(CloseButton(self)))
        self.setLayout(vbox)
Exemple #38
0
class UploadCard(QWidget):
    def __init__(self, filename):
        super(UploadCard, self).__init__()
        self.filename = filename
        self.photo_index = 0  # 用于记录存储了几张图片
        self.powerStatus = False

        # 图像显示
        layout = QGridLayout()

        self.capture = None
        self.timer = QTimer(self)

        self.useBtn = QPushButton("亮证经营拍照取证")
        self.useBtn.setDisabled(True)
        self.useBtn.clicked.connect(self.useTake)

        self.noBtn = QPushButton("重新拍照")
        self.noBtn.setDisabled(True)
        self.noBtn.clicked.connect(self.restartTake)

        self.camera = QLabel("摄像头准备中。。。。")
        self.startBtn = QPushButton("打开摄像头")
        self.startBtn.clicked.connect(self.startCamera)
        self.takeBtn = QPushButton("拍照")
        self.takeBtn.clicked.connect(self.takePhoto)

        self.nextBtn = QPushButton("下一步")

        # 跳过上传许可证的备注说明
        self.remarkLable = QLabel("未亮证理由说明:")
        self.remarkComb = QComboBox()
        self.remarkComb.addItems(["无证", "其他"])
        self.edit_reason = QLineEdit()
        self.edit_reason.setPlaceholderText('选择"其他"时需要填入理由')

        layout.addWidget(self.camera, 0, 0, 1, 3)

        layout.addWidget(self.startBtn, 1, 0)
        layout.addWidget(self.takeBtn, 1, 1)
        layout.addWidget(self.noBtn, 1, 2)
        layout.addWidget(self.useBtn, 2, 0, 1, 3)
        layout.addWidget(self.remarkLable, 3, 0)
        layout.addWidget(self.remarkComb, 3, 1)
        layout.addWidget(self.edit_reason, 3, 2)
        layout.addWidget(self.nextBtn, 4, 0, 1, 3)

        self.takeBtn.setDisabled(True)
        self.noBtn.setDisabled(True)
        self.useBtn.setDisabled(True)

        self.setLayout(layout)

        # 绘制文件格式
        style_str = "QLabel{font-size: 30px;}" + "QLineEdit{font-size: 30px;}" + \
                    "QPushButton{font-size: 25px; background-color: green; min-height: 50px; min-width: 300px}" + \
                    "QComboBox{font-size: 30px;}"
        self.setStyleSheet(style_str)

    def startCamera(self):
        if not self.powerStatus:
            self.takeBtn.setDisabled(False)
            self.noBtn.setDisabled(True)
            self.useBtn.setDisabled(True)
            self.powerStatus = True
            self.startBtn.setText("关闭摄像头")
            self.capture = cv2.VideoCapture(1)
            self.timer.timeout.connect(self.display)
            self.timer.start(100)
        else:
            self.powerStatus = False
            self.startBtn.setText("打开摄像头")
            self.takeBtn.setDisabled(True)
            self.noBtn.setDisabled(True)
            self.useBtn.setDisabled(True)
            self.timer.stop()
            self.capture.release()

    # 下一步
    def release(self):
        try:
            self.timer.stop()
            self.capture.release()
        except Exception as e:
            print(e)
        # 如果没有上传过许可证,填入许可证明
        if self.photo_index == 0:
            # 判断选择无证还是其他原因
            if self.remarkComb.currentText() == "无证":
                reason = "无证"
            else:
                reason = self.edit_reason.text()
                if not reason:
                    QMessageBox.critical(self, "错误", "选择<其他>原因时需要填写具体原因", QMessageBox.Yes)
                    return False
            wb = openpyxl.load_workbook(self.filename)
            try:
                ws = wb["许可证照片"]
            except Exception as e:
                print(e)
                ws = wb.create_sheet(title="许可证照片")
            ws["A1"] = reason
            wb.save(self.filename)
        return True

    # 从摄像头中获取图片信息
    def get_image(self):
        ret, frame = self.capture.read()
        if ret:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            self.pil_image = PILImage.fromarray(frame)
            height, width = frame.shape[:2]
            img = QImage(frame, width, height, QImage.Format_RGB888)
            return img
        else:
            return None

    # 显示图片
    def display(self):
        img = self.get_image()
        if img:
            img = QPixmap.fromImage(img)
            self.camera.setPixmap(img)
            self.camera.setScaledContents(True)
        else:
            pass

    # 拍照
    def takePhoto(self):
        self.timer.stop()
        self.takeBtn.setDisabled(True)
        self.useBtn.setDisabled(False)
        self.noBtn.setDisabled(False)

    # 重新拍照
    def restartTake(self):
        self.timer.start(100)
        self.takeBtn.setDisabled(False)
        self.useBtn.setDisabled(True)
        self.noBtn.setDisabled(True)

    # 使用该照片并上传
    def useTake(self):
        # 读写excel并存储图片
        self.uploadPhoto()
        self.timer.start(100)
        self.takeBtn.setDisabled(False)
        self.useBtn.setDisabled(True)
        self.noBtn.setDisabled(True)

    # 读写excel数据
    def uploadPhoto(self):  # 1现场 2许可证
        wb = openpyxl.load_workbook(self.filename)
        try:
            ws = wb["许可证照片"]
        except Exception as e:
            print(e)
            ws = wb.create_sheet(title="许可证照片")
        self.pil_image.save("./tmp.jpg")
        img_file = Image("./tmp.jpg")
        ws.add_image(img_file, "A" + str(self.photo_index * 30 + 2))
        wb.save(self.filename)
        self.photo_index += 1
Exemple #39
0
class ctdSensorDifferencePlot(QMainPlotterTemplate):
    def __init__(self, database, type):
        super().__init__()
        self.database = database
        self.type = type

        self.apply_button.clicked.connect(self.draw_data)

        self.setWindowTitle(f'CTD {type} Sensor to Bottle Difference')

        self.main_plot.set_title('CTD Sensor - Bottle', fontsize=18)
        self.main_plot.set_xlabel('Deployment / Rosette Position', fontsize=15)
        self.main_plot.set_ylabel('Difference (CTD Sensor - Bottle)', fontsize=15)

        self.main_plot.grid(alpha=0.1)

        self.run_list_label.setText('Select Deployment:')

        sensor_label = QLabel('Sensor:', self)
        self.sensor_selector = QComboBox()
        self.sensor_selector.setFont(QFont('Segoe UI'))
        self.sensor_selector.addItems(['Salinity', 'Oxygen'])
        self.sensor_selector.setEditable(True)
        self.sensor_selector.setEditable(False)
        #self.sensor_selector.currentTextChanged.connect(self.populate_fields)

        sensor_number_label = QLabel('# Sensor:')
        self.sensor_number_selector = QComboBox()
        self.sensor_number_selector.setFont(QFont('Segoe UI'))
        self.sensor_number_selector.addItems(['Primary', 'Secondary', 'Both'])
        self.sensor_number_selector.setEditable(True)
        self.sensor_number_selector.setEditable(False)

        self.sensor_selector.setCurrentText(type)

        self.qvbox_layout.insertWidget(0, sensor_label)
        self.qvbox_layout.insertWidget(1, self.sensor_selector)

        self.qvbox_layout.insertWidget(2, sensor_number_label)
        self.qvbox_layout.insertWidget(3, self.sensor_number_selector)

        self.populate_fields()
        self.show()

        self.canvas.mpl_connect('pick_event', self.on_pick)

    def populate_fields(self):

        sensor = self.sensor_selector.currentText()
        print(sensor)
        conn = sqlite3.connect(self.database)
        c = conn.cursor()

        c.execute('SELECT DISTINCT deployment from %sData' % sensor.lower())

        available_deployments = sorted(list(c.fetchall()))

        conn.close()

        for dep in available_deployments:
            self.run_list.addItem(str(dep[0]))

    def draw_data(self):

        sensor = self.sensor_selector.currentText()
        sensor_number = self.sensor_number_selector.currentText()

        analyte_db_converter = {'Salinity': 'salinity', 'Oxygen': 'oxygenMoles'}
        ctd_db_converter = {'Salinity': 'salt', 'Oxygen': 'oxygen'}
        sensor_converter = {'Primary': 1, 'Secondary': 2}

        selected = self.run_list.selectedItems()
        selected_deps = [int(item.text()) for item in selected]

        if selected_deps:
            # Get data from database for both bottles and CTD
            conn = sqlite3.connect(self.database)
            query_placeholder = ', '.join('?' for unused in selected_deps)
            bottle_data_df = pd.read_sql_query(f'SELECT * FROM %sData WHERE deployment IN ({query_placeholder})'
                                       %sensor.lower(), conn, params=selected_deps)

            ctd_data_df = pd.read_sql_query(f'SELECT deployment, bottleposition, salt1, salt2, oxygen1, oxygen2 '
                                            f'FROM ctdData '
                                            f'WHERE deployment IN ({query_placeholder})', conn, params=selected_deps)

            self.bottle_deps = list(bottle_data_df['deployment'])
            self.bottle_rps = list(bottle_data_df['rosettePosition'])

            # Match up the CTD data to the bottle data, as there will always be less bottle data...
            matched_ctd_data = pd.DataFrame()
            for i, dep in enumerate(self.bottle_deps):
                rp = self.bottle_rps[i]
                matched = ctd_data_df.loc[(ctd_data_df['deployment'] == dep) & (ctd_data_df['bottleposition'] == rp)]
                matched_ctd_data = matched_ctd_data.append(matched, ignore_index=True)

            bottle_data = np.asarray(bottle_data_df[analyte_db_converter[sensor]])

            # If both sensors are to be plotted, use the correct data
            if sensor_number != 'Both':
                sensor_one = np.asarray(list(matched_ctd_data[str(ctd_db_converter[sensor]) +
                                                              str(sensor_converter[sensor_number])]))
            else:
                sensor_one = np.asarray(list(matched_ctd_data[str(ctd_db_converter[sensor]) + '1']))
                sensor_two = np.asarray(list(matched_ctd_data[str(ctd_db_converter[sensor]) + '2']))
                difference_two = sensor_two - bottle_data

            # Plotted the same as in oxygen processing
            difference_one = sensor_one - bottle_data

            max_rp = get_max_rp(self.bottle_rps)

            plottable_dep_rp = [(((dep - 1) * max_rp) + self.bottle_rps[i]) for i, dep in enumerate(self.bottle_deps)]

            sensor_difference_plot(self.figure, self.main_plot, plottable_dep_rp, difference_one, max_rp)

            if sensor_number == 'Both':
                sensor_difference_plot(self.figure, self.main_plot, plottable_dep_rp, difference_two, max_rp)
                self.main_plot.legend()

            self.canvas.draw()

    def on_pick(self, event):
        if self.sensor_selector.currentText() == 'Salinity':
            self.base_on_pick(event, self.database, self.bottle_deps, self.bottle_rps, salinity=True)
        elif self.sensor_selector.currentText() == 'Oxygen':
            self.base_on_pick(event, self.database, self.bottle_deps, self.bottle_rps, oxygen=True)
Exemple #40
0
class HistoryList(MyTreeView, AcceptFileDragDrop):
    filter_columns = [
        HistoryColumns.STATUS_TEXT, HistoryColumns.DESCRIPTION,
        HistoryColumns.COIN_VALUE, HistoryColumns.TXID
    ]

    def tx_item_from_proxy_row(self, proxy_row):
        hm_idx = self.model().mapToSource(self.model().index(proxy_row, 0))
        return self.hm.transactions.value_from_pos(hm_idx.row())

    def should_hide(self, proxy_row):
        if self.start_timestamp and self.end_timestamp:
            tx_item = self.tx_item_from_proxy_row(proxy_row)
            date = tx_item['date']
            if date:
                in_interval = self.start_timestamp <= date <= self.end_timestamp
                if not in_interval:
                    return True
            return False

    def __init__(self, parent, model: HistoryModel):
        super().__init__(parent,
                         self.create_menu,
                         stretch_column=HistoryColumns.DESCRIPTION)
        self.hm = model
        self.proxy = HistorySortModel(self)
        self.proxy.setSourceModel(model)
        self.setModel(self.proxy)

        self.config = parent.config
        AcceptFileDragDrop.__init__(self, ".txn")
        self.setSortingEnabled(True)
        self.start_timestamp = None
        self.end_timestamp = None
        self.years = []
        self.create_toolbar_buttons()
        self.wallet = self.parent.wallet  # type: Abstract_Wallet
        self.sortByColumn(HistoryColumns.STATUS_ICON, Qt.AscendingOrder)
        self.editable_columns |= {HistoryColumns.FIAT_VALUE}

        self.header().setStretchLastSection(False)
        for col in HistoryColumns:
            sm = QHeaderView.Stretch if col == self.stretch_column else QHeaderView.ResizeToContents
            self.header().setSectionResizeMode(col, sm)

    def format_date(self, d):
        return str(datetime.date(d.year, d.month, d.day)) if d else _('None')

    def on_combo(self, x):
        s = self.period_combo.itemText(x)
        x = s == _('Custom')
        self.start_button.setEnabled(x)
        self.end_button.setEnabled(x)
        if s == _('All'):
            self.start_timestamp = None
            self.end_timestamp = None
            self.start_button.setText("-")
            self.end_button.setText("-")
        else:
            try:
                year = int(s)
            except:
                return
            self.start_timestamp = start_date = datetime.datetime(year, 1, 1)
            self.end_timestamp = end_date = datetime.datetime(year + 1, 1, 1)
            self.start_button.setText(
                _('From') + ' ' + self.format_date(start_date))
            self.end_button.setText(_('To') + ' ' + self.format_date(end_date))
        self.hide_rows()

    def create_toolbar_buttons(self):
        self.period_combo = QComboBox()
        self.start_button = QPushButton('-')
        self.start_button.pressed.connect(self.select_start_date)
        self.start_button.setEnabled(False)
        self.end_button = QPushButton('-')
        self.end_button.pressed.connect(self.select_end_date)
        self.end_button.setEnabled(False)
        self.period_combo.addItems([_('All'), _('Custom')])
        self.period_combo.activated.connect(self.on_combo)

    def get_toolbar_buttons(self):
        return self.period_combo, self.start_button, self.end_button

    def on_hide_toolbar(self):
        self.start_timestamp = None
        self.end_timestamp = None
        self.hide_rows()

    def save_toolbar_state(self, state, config):
        config.set_key('show_toolbar_history', state)

    def select_start_date(self):
        self.start_timestamp = self.select_date(self.start_button)
        self.hide_rows()

    def select_end_date(self):
        self.end_timestamp = self.select_date(self.end_button)
        self.hide_rows()

    def select_date(self, button):
        d = WindowModalDialog(self, _("Select date"))
        d.setMinimumSize(600, 150)
        d.date = None
        vbox = QVBoxLayout()

        def on_date(date):
            d.date = date

        cal = QCalendarWidget()
        cal.setGridVisible(True)
        cal.clicked[QDate].connect(on_date)
        vbox.addWidget(cal)
        vbox.addLayout(Buttons(OkButton(d), CancelButton(d)))
        d.setLayout(vbox)
        if d.exec_():
            if d.date is None:
                return None
            date = d.date.toPyDate()
            button.setText(self.format_date(date))
            return datetime.datetime(date.year, date.month, date.day)

    def show_summary(self):
        h = self.model().sourceModel().summary
        if not h:
            self.parent.show_message(_("Nothing to summarize."))
            return
        start_date = h.get('start_date')
        end_date = h.get('end_date')
        format_amount = lambda x: self.parent.format_amount(
            x.value) + ' ' + self.parent.base_unit()
        d = WindowModalDialog(self, _("Summary"))
        d.setMinimumSize(600, 150)
        vbox = QVBoxLayout()
        grid = QGridLayout()
        grid.addWidget(QLabel(_("Start")), 0, 0)
        grid.addWidget(QLabel(self.format_date(start_date)), 0, 1)
        grid.addWidget(QLabel(str(h.get('fiat_start_value')) + '/BTC'), 0, 2)
        grid.addWidget(QLabel(_("Initial balance")), 1, 0)
        grid.addWidget(QLabel(format_amount(h['start_balance'])), 1, 1)
        grid.addWidget(QLabel(str(h.get('fiat_start_balance'))), 1, 2)
        grid.addWidget(QLabel(_("End")), 2, 0)
        grid.addWidget(QLabel(self.format_date(end_date)), 2, 1)
        grid.addWidget(QLabel(str(h.get('fiat_end_value')) + '/BTC'), 2, 2)
        grid.addWidget(QLabel(_("Final balance")), 4, 0)
        grid.addWidget(QLabel(format_amount(h['end_balance'])), 4, 1)
        grid.addWidget(QLabel(str(h.get('fiat_end_balance'))), 4, 2)
        grid.addWidget(QLabel(_("Income")), 5, 0)
        grid.addWidget(QLabel(format_amount(h.get('incoming'))), 5, 1)
        grid.addWidget(QLabel(str(h.get('fiat_incoming'))), 5, 2)
        grid.addWidget(QLabel(_("Expenditures")), 6, 0)
        grid.addWidget(QLabel(format_amount(h.get('outgoing'))), 6, 1)
        grid.addWidget(QLabel(str(h.get('fiat_outgoing'))), 6, 2)
        grid.addWidget(QLabel(_("Capital gains")), 7, 0)
        grid.addWidget(QLabel(str(h.get('fiat_capital_gains'))), 7, 2)
        grid.addWidget(QLabel(_("Unrealized gains")), 8, 0)
        grid.addWidget(QLabel(str(h.get('fiat_unrealized_gains', ''))), 8, 2)
        vbox.addLayout(grid)
        vbox.addLayout(Buttons(CloseButton(d)))
        d.setLayout(vbox)
        d.exec_()

    def plot_history_dialog(self):
        if plot_history is None:
            self.parent.show_message(
                _("Can't plot history.") + '\n' +
                _("Perhaps some dependencies are missing...") +
                " (matplotlib?)")
            return
        try:
            plt = plot_history(list(self.hm.transactions.values()))
            plt.show()
        except NothingToPlotException as e:
            self.parent.show_message(str(e))

    def on_edited(self, index, user_role, text):
        index = self.model().mapToSource(index)
        row, column = index.row(), index.column()
        tx_item = self.hm.transactions.value_from_pos(row)
        key = tx_item['txid']
        if column == HistoryColumns.DESCRIPTION:
            if self.wallet.set_label(key, text):  #changed
                self.hm.update_label(row)
                self.parent.update_completions()
        elif column == HistoryColumns.FIAT_VALUE:
            self.wallet.set_fiat_value(key, self.parent.fx.ccy, text,
                                       self.parent.fx, tx_item['value'].value)
            value = tx_item['value'].value
            if value is not None:
                self.hm.update_fiat(row, index)
        else:
            assert False

    def mouseDoubleClickEvent(self, event: QMouseEvent):
        idx = self.indexAt(event.pos())
        if not idx.isValid():
            return
        tx_item = self.tx_item_from_proxy_row(idx.row())
        if self.hm.flags(self.model().mapToSource(idx)) & Qt.ItemIsEditable:
            super().mouseDoubleClickEvent(event)
        else:
            self.show_transaction(tx_item['txid'])

    def show_transaction(self, tx_hash):
        tx = self.wallet.db.get_transaction(tx_hash)
        if not tx:
            return
        label = self.wallet.get_label(
            tx_hash
        ) or None  # prefer 'None' if not defined (force tx dialog to hide Description field if missing)
        self.parent.show_transaction(tx, label)

    def create_menu(self, position: QPoint):
        org_idx: QModelIndex = self.indexAt(position)
        idx = self.proxy.mapToSource(org_idx)
        if not idx.isValid():
            # can happen e.g. before list is populated for the first time
            return
        tx_item = self.hm.transactions.value_from_pos(idx.row())
        column = idx.column()
        if column == HistoryColumns.STATUS_ICON:
            column_title = _('Transaction ID')
            column_data = tx_item['txid']
        else:
            column_title = self.hm.headerData(column, Qt.Horizontal,
                                              Qt.DisplayRole)
            column_data = self.hm.data(idx, Qt.DisplayRole).value()
        tx_hash = tx_item['txid']
        tx = self.wallet.db.get_transaction(tx_hash)
        if not tx:
            return
        tx_URL = block_explorer_URL(self.config, 'tx', tx_hash)
        height = self.wallet.get_tx_height(tx_hash).height
        is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(tx)
        is_unconfirmed = height <= 0
        pr_key = self.wallet.invoices.paid.get(tx_hash)
        menu = QMenu()
        if height == TX_HEIGHT_LOCAL:
            menu.addAction(_("Remove"), lambda: self.remove_local_tx(tx_hash))

        amount_columns = [
            HistoryColumns.COIN_VALUE, HistoryColumns.RUNNING_COIN_BALANCE,
            HistoryColumns.FIAT_VALUE, HistoryColumns.FIAT_ACQ_PRICE,
            HistoryColumns.FIAT_CAP_GAINS
        ]
        if column in amount_columns:
            column_data = column_data.strip()
        menu.addAction(
            _("Copy {}").format(column_title),
            lambda: self.parent.app.clipboard().setText(column_data))

        for c in self.editable_columns:
            if self.isColumnHidden(c): continue
            label = self.hm.headerData(c, Qt.Horizontal, Qt.DisplayRole)
            # TODO use siblingAtColumn when min Qt version is >=5.11
            persistent = QPersistentModelIndex(
                org_idx.sibling(org_idx.row(), c))
            menu.addAction(_("Edit {}").format(label),
                           lambda p=persistent: self.edit(QModelIndex(p)))
        menu.addAction(_("Details"), lambda: self.show_transaction(tx_hash))
        if is_unconfirmed and tx:
            # note: the current implementation of RBF *needs* the old tx fee
            rbf = is_mine and not tx.is_final() and fee is not None
            if rbf:
                menu.addAction(_("Increase fee"),
                               lambda: self.parent.bump_fee_dialog(tx))
            else:
                child_tx = self.wallet.cpfp(tx, 0)
                if child_tx:
                    menu.addAction(_("Child pays for parent"),
                                   lambda: self.parent.cpfp(tx, child_tx))
        if pr_key:
            menu.addAction(read_QIcon("seal"), _("View invoice"),
                           lambda: self.parent.show_invoice(pr_key))
        if tx_URL:
            menu.addAction(_("View on block explorer"),
                           lambda: webbrowser.open(tx_URL))
        menu.exec_(self.viewport().mapToGlobal(position))

    def remove_local_tx(self, delete_tx):
        to_delete = {delete_tx}
        to_delete |= self.wallet.get_depending_transactions(delete_tx)
        question = _("Are you sure you want to remove this transaction?")
        if len(to_delete) > 1:
            question = _(
                "Are you sure you want to remove this transaction and {} child transactions?"
                .format(len(to_delete) - 1))
        answer = QMessageBox.question(self.parent, _("Please confirm"),
                                      question, QMessageBox.Yes,
                                      QMessageBox.No)
        if answer == QMessageBox.No:
            return
        for tx in to_delete:
            self.wallet.remove_transaction(tx)
        self.wallet.storage.write()
        # need to update at least: history_list, utxo_list, address_list
        self.parent.need_update.set()

    def onFileAdded(self, fn):
        try:
            with open(fn) as f:
                tx = self.parent.tx_from_text(f.read())
                self.parent.save_transaction_into_wallet(tx)
        except IOError as e:
            self.parent.show_error(e)

    def export_history_dialog(self):
        d = WindowModalDialog(self, _('Export History'))
        d.setMinimumSize(400, 200)
        vbox = QVBoxLayout(d)
        defaultname = os.path.expanduser('~/electrum-history.csv')
        select_msg = _('Select file to export your wallet transactions to')
        hbox, filename_e, csv_button = filename_field(self, self.config,
                                                      defaultname, select_msg)
        vbox.addLayout(hbox)
        vbox.addStretch(1)
        hbox = Buttons(CancelButton(d), OkButton(d, _('Export')))
        vbox.addLayout(hbox)
        #run_hook('export_history_dialog', self, hbox)
        self.update()
        if not d.exec_():
            return
        filename = filename_e.text()
        if not filename:
            return
        try:
            self.do_export_history(filename, csv_button.isChecked())
        except (IOError, os.error) as reason:
            export_error_label = _(
                "Electrum was unable to produce a transaction export.")
            self.parent.show_critical(export_error_label + "\n" + str(reason),
                                      title=_("Unable to export history"))
            return
        self.parent.show_message(
            _("Your wallet history has been successfully exported."))

    def do_export_history(self, file_name, is_csv):
        hist = self.wallet.get_full_history(domain=self.hm.get_domain(),
                                            from_timestamp=None,
                                            to_timestamp=None,
                                            fx=self.parent.fx,
                                            show_fees=True)
        txns = hist['transactions']
        lines = []
        if is_csv:
            for item in txns:
                lines.append([
                    item['txid'],
                    item.get('label', ''), item['confirmations'],
                    item['value'],
                    item.get('fiat_value', ''),
                    item.get('fee', ''),
                    item.get('fiat_fee', ''), item['date']
                ])
        with open(file_name, "w+", encoding='utf-8') as f:
            if is_csv:
                import csv
                transaction = csv.writer(f, lineterminator='\n')
                transaction.writerow([
                    "transaction_hash", "label", "confirmations", "value",
                    "fiat_value", "fee", "fiat_fee", "timestamp"
                ])
                for line in lines:
                    transaction.writerow(line)
            else:
                from electrum.util import json_encode
                f.write(json_encode(txns))

    def text_txid_from_coordinate(self, row, col):
        idx = self.model().mapToSource(self.model().index(row, col))
        tx_item = self.hm.transactions.value_from_pos(idx.row())
        return self.hm.data(idx, Qt.DisplayRole).value(), tx_item['txid']
Exemple #41
0
class mainWindow(QMainWindow):
    def __init__(self):
        super(mainWindow, self).__init__()

        self.full_filename_dict = {}  # {    full_filename:  group_name   }
        self.group_name_dict = {}  #group name dict, not necessary now?
        self.current_full_filename = None  #current selected full filename
        self.current_hdf5 = None  #open(  self.current_full_filename, r )
        self.current_hdf5_item = None
        self.current_group_name = None
        self.current_base_filename = ''  #current selected   base filename
        self.current_item_path = ''  #current item full path. /io/md/...
        self.current_item_name = ''  #current selected item name  md

        self.legend = None
        self.values = np.array([])
        self.logX_plot = False
        self.logY_plot = False

        self.X = None
        self.guiplot_count = 0
        self.testplot_count = 1
        self.image_plot_count = 0
        self.surface_plot_count = 0
        self.plot_type = 'curve'

        self.colormap_string = 'jet'
        self.colorscale_string = 'log'
        self.show_image_data = False
        self.rot_image_data = False
        self.attributes_flag = False
        self.current_selected_HDF = ''
        self.dataset_type_list = [
            'CFN',
            'LiX',
            'CHX',
        ]
        self.default_dataset_type = 'CFN'
        self.current_dataset_type = 'CFN'

        #########################Tobecleaned
        self.image_data_keys = [
            'avg_img', 'mask', 'pixel_mask', 'roi_mask', 'g12b'
        ]
        self.pds_keys = [
            'g2_fit_paras', 'g2b_fit_paras', 'spec_km_pds', 'spec_pds',
            'qr_1d_pds'
        ]
        #####################

        self.PWT = PlotWidget(self)
        self.MPWT = MATPlotWidget(self)
        self.initialise_user_interface()

        self.vstack_sampling = 20
        self.vstack_yshift = 10

    def initialise_user_interface(self):
        '''
        Initialises the main window. '''

        grid = QGridLayout()
        grid.setSpacing(10)
        self.grid = grid
        #self.file_items_list = ht.titledTree('File Tree')
        self.file_items_list = ht.tree()
        self.file_items_list_property = {}
        self.file_items_list.tree.itemClicked.connect(self.item_clicked)
        #self.file_items_list.tree.itemDoubleClicked.connect(self.item_double_clicked)
        self.guiplot_grid_fromRow = 5
        self.guiplot_grid_fromColumn = 1
        self.guiplot_grid_rowSpan = 5
        self.guiplot_grid_columnSpan = 8
        self.testplot_grid_fromRow = 6
        self.testplot_grid_fromColumn = 1
        self.testplot_grid_rowSpan = 4
        self.testplot_grid_columnSpan = 8
        self.plotLibrary = 'matplotlib'
        self.plot_buttons_array = []
        # Make dataset table
        self.dataset_table = ht.titledTable('Values')
        # Make attribute table
        self.attribute_table = ht.titledTable('Attribute')  # QTableWidget()
        self.attribute_table.table.setShowGrid(True)
        #dataset type to set buttons layout
        self.dataset_type_obj_string = self.default_dataset_type
        # Initialise all buttons
        self.open_button = self.add_open_button()
        self.remove_button = self.add_remove_button()
        self.create_button = self.add_create_button()
        self.dataset_type_box = self.add_dataset_type_box()
        self.add_all_plot_buttons()
        self.setX_button = self.add_setX_button()
        self.resetX_button = self.add_resetX_button()
        self.setlogX_box = self.add_setlogX_box()
        self.setlogY_box = self.add_setlogY_box()
        #self.clr_plot_checkbox = self.add_clr_plot_box()
        self.clr_plot_button = self.add_clr_plot_button()
        self.resizeEvent = self.onresize
        # Add 'extra' window components
        self.make_menu_bar()
        self.filename_label = QLabel('H5FileName')
        ## Add plot window
        self.guiplot = pg.PlotWidget()  ##using pg
        self.testplot = Figure()
        self.ax = self.testplot.add_subplot(111)
        self.canvas = FigureCanvas(self.testplot)
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.cbWidget = None
        #self.guiplot = pg.ImageView()
        # Add the created layouts and widgets to the window
        grid.addLayout(self.open_button, 1, 0, 1, 1, QtCore.Qt.AlignLeft)
        grid.addLayout(self.remove_button, 6, 0, 1, 1, QtCore.Qt.AlignLeft)
        grid.addLayout(self.create_button, 7, 0, 1, 1, QtCore.Qt.AlignLeft)
        grid.addLayout(self.dataset_type_box, 1, 0, 1, 1, QtCore.Qt.AlignRight)
        grid.addLayout(self.clr_plot_button, 1, 4, 1, 1, QtCore.Qt.AlignLeft)
        grid.addLayout(self.setX_button, 1, 8, 1, 1, QtCore.Qt.AlignLeft)
        grid.addLayout(self.resetX_button, 2, 8, 1, 1, QtCore.Qt.AlignLeft)
        grid.addLayout(self.setlogX_box, 1, 7, 1, 1, QtCore.Qt.AlignLeft)
        grid.addLayout(self.setlogY_box, 2, 7, 1, 1, QtCore.Qt.AlignLeft)

        grid.addWidget(self.filename_label, 2, 0, 1, 1)
        #filename list
        #grid.addLayout(self.file_items_list.layout, 4, 0, 3, 1)
        grid.addLayout(self.file_items_list.datalayout, 4, 0, 2, 1)
        #data dataset table
        grid.addLayout(self.dataset_table.layout, 4, 1, 1, 8)
        # Add toolbar
        grid.addWidget(self.toolbar, 5, 1, 1, 7)
        ## Add guiplot window, it's not the default so hide
        grid.addWidget(self.guiplot, self.guiplot_grid_fromRow,
                       self.guiplot_grid_fromColumn, self.guiplot_grid_rowSpan,
                       self.guiplot_grid_columnSpan)
        self.guiplot.setWindowOpacity(0)
        self.guiplot.hide()
        grid.addWidget(self.canvas, self.testplot_grid_fromRow,
                       self.testplot_grid_fromColumn,
                       self.testplot_grid_rowSpan,
                       self.testplot_grid_columnSpan)
        # attribute tabel
        grid.addLayout(self.attribute_table.layout, 8, 0, 3, 1)
        #grid.addWidget(self.attribute_table, 7, 0, 2, 1 )
        self.dev_cur_layout(plot_type='curve')
        self.dev_cur_layout(plot_type='image')
        self.setCentralWidget(QWidget(self))
        self.centralWidget().setLayout(grid)
        # Other tweaks to the window such as icons etc
        self.setWindowTitle('XSH5View--Ver1')
        #QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('Cleanlooks'))
        self.initialise_layout(
        )  #to add different type of layout based on self.dataset_type_obj_string

    ########Start Deal with layout
    def initialise_layout(self):
        if self.dataset_type_obj_string == 'CFN':
            self.delete_dataset_buttons('CHX')
            self.dev_dataset_buttons(self.dataset_type_obj_string)
        elif self.dataset_type_obj_string == 'LIX':
            self.delete_dataset_buttons('CHX')
        elif self.dataset_type_obj_string == 'CHX':
            self.dev_dataset_buttons(self.dataset_type_obj_string)
        else:
            pass

    def dev_cur_layout(self, plot_type):
        if plot_type in plot_curve_type:
            self.CurCrossHair = QLabel()
            self.CurCrossHair.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
            self.grid.addWidget(self.CurCrossHair, 9, 2, 1, 1)
            self.CrossHair_type = 'curve'
        elif plot_type in plot_image_type:
            self.imageCrossHair = QLabel()
            self.imageCrossHair.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
            self.grid.addWidget(self.imageCrossHair, 9, 1, 1, 1)
            self.CrossHair_type = 'image'
        else:
            self.CrossHair_type = 'None'

    def delete_cur_layout(self, plot_type):
        if plot_type in plot_curve_type:
            try:
                self.deleteLayout(self.imageCrossHair)
            except:
                pass
        elif plot_type in plot_image_type:
            try:
                self.deleteLayout(self.CurCrossHair)
            except:
                pass
        else:
            pass

    def dev_dataset_buttons(self, dataset_type):
        if dataset_type == 'CHX':
            self.plot_g2_button = self.add_plot_g2_button()
            self.plot_c12_button = self.add_plot_c12_button()
            self.q_box_input = self.add_q_box()
            self.plot_qiq_button = self.add_plot_qiq_button()
            self.grid.addLayout(self.plot_g2_button, 2, 1, 1, 1,
                                QtCore.Qt.AlignLeft)
            self.grid.addLayout(self.plot_c12_button, 2, 2, 1, 1,
                                QtCore.Qt.AlignLeft)
            self.grid.addLayout(self.plot_qiq_button, 2, 3, 1, 1,
                                QtCore.Qt.AlignLeft)
            self.grid.addLayout(self.q_box_input, 2, 6, 1, 1,
                                QtCore.Qt.AlignLeft)

        if dataset_type == 'CFN':
            self.rot_image_button = self.add_rot_image_button()
            self.grid.addLayout(self.rot_image_button, 2, 2, 1, 1,
                                QtCore.Qt.AlignLeft)
            self.stack_plot_button = self.add_stack_plot_button()
            self.grid.addLayout(self.stack_plot_button, 2, 1, 1, 1,
                                QtCore.Qt.AlignLeft)

    def add_rot_image_button(self):
        rot_image_button = QPushButton("rot image")
        rot_image_button.clicked.connect(self.rot_image)
        button_section = QHBoxLayout()
        button_section.addWidget(rot_image_button)
        return button_section

    def rot_image(self):
        #print('here')
        try:
            self.value = self.value.T
        except:
            pass

    def delete_dataset_buttons(self, dataset_type):
        if dataset_type == 'CHX' and self.current_dataset_type == 'CHX':
            self.deleteLayout(self.plot_g2_button)
            self.deleteLayout(self.plot_c12_button)
            self.deleteLayout(self.plot_qiq_button)
            self.deleteLayout(self.q_box_input)

    def deleteLayout(self, layout):
        for i in range(layout.count()):
            layout.itemAt(i).widget().close()

    ########End Deal with layout
    def onresize(self, event):
        #print('Here for resize')
        self.file_items_list.tree.setMaximumWidth(int(0.3 * self.width()))
        #self.dataset_table.table.setMinimumHeight(0.1*self.height())
        #self.dataset_table.table.setMaximumWidth( 0.3*self.height() )
        self.attribute_table.table.setMaximumWidth(int(0.3 * self.width()))
        #self.guiplot.setMinimumHeight( 0.6*self.height() )
        #self.guiplot.setMinimumHeight( 0.6*self.height() )
    def add_open_button(self):
        '''
        Initialises the buttons in the button bar at the top of the main window. '''
        open_file_btn = QPushButton('Open')
        open_file_btn.clicked.connect(self.choose_file)
        button_section = QHBoxLayout()
        button_section.addWidget(open_file_btn)
        #button_section.addStretch(0)
        return button_section

    def add_remove_button(self):
        remove_file_btn = QPushButton('Remove File')
        remove_file_btn.clicked.connect(self.remove_file)
        button_section = QHBoxLayout()
        button_section.addWidget(remove_file_btn)
        return button_section

    def add_create_button(self):
        create_file_btn = QPushButton('Create File')
        create_file_btn.clicked.connect(self.create_file)
        button_section = QHBoxLayout()
        button_section.addWidget(create_file_btn)
        return button_section

    def add_dataset_type_box(self):
        self.dataset_type_obj = QComboBox()
        self.dataset_type_obj.addItems(self.dataset_type_list)
        self.dataset_type_obj.currentIndexChanged.connect(
            self.dataset_type_selection_change)
        self.dataset_type_obj_string = self.dataset_type_obj.currentText()
        box_section = QHBoxLayout()
        box_section.addWidget(self.dataset_type_obj)
        return box_section

    def dataset_type_selection_change(self, i):
        self.dataset_type_obj_string = self.dataset_type_obj.currentText()
        self.initialise_layout()
        self.current_dataset_type = self.dataset_type_obj.currentText()
        #print( self.dataset_type_obj_string , self.dataset_type_obj.currentText() )

    def add_all_plot_buttons(self):
        self.plot_curve_button = self.add_plot_curve_button()
        self.plot_img_button = self.add_plot_img_button()
        if self.plotLibrary != 'matplotlib':
            self.plot_surface_button = self.add_plot_surface_button()
            self.grid.addLayout(self.plot_surface_button, 1, 3, 1, 1,
                                QtCore.Qt.AlignLeft)
        else:
            self.plot_acr_datasets_button = self.add_plot_acr_datasets_button()
            self.grid.addLayout(self.plot_acr_datasets_button, 2, 3, 1, 1,
                                QtCore.Qt.AlignLeft)
        self.grid.addLayout(self.plot_curve_button, 1, 1, 1, 1,
                            QtCore.Qt.AlignLeft)
        self.grid.addLayout(self.plot_img_button, 1, 2, 1, 1,
                            QtCore.Qt.AlignLeft)

    def add_stack_plot_button(self):
        return self.add_generic_plot_button(plot_type='plot_stack',
                                            button_name='Stack Plot')

    def add_plot_acr_datasets_button(self):
        return self.add_generic_plot_button(
            plot_type='stack_across', button_name='Stack Across Datasets')

    def add_plot_g2_button(self):
        return self.add_generic_plot_button(plot_type='g2',
                                            button_name='Plot_g2')

    def add_plot_c12_button(self):
        return self.add_generic_plot_button(plot_type='C12',
                                            button_name='Plot_TwoTime')

    def add_plot_curve_button(self):
        return self.add_generic_plot_button(plot_type='curve',
                                            button_name='Plot_Curve')

    def add_plot_qiq_button(self):
        return self.add_generic_plot_button(plot_type='qiq',
                                            button_name='Plot_qiq')

    def add_plot_img_button(self):
        return self.add_generic_plot_button(plot_type='image',
                                            button_name='Plot_Image')

    def add_plot_surface_button(self):
        return self.add_generic_plot_button(plot_type='surface',
                                            button_name='Plot_Surface')

    def add_generic_plot_button(self, plot_type, button_name):
        plot_btn = QPushButton(button_name)
        pg_plot_type_dict = {
            'curve': self.PWT.plot_curve,
            'g2': self.PWT.plot_g2,
            'qiq': self.PWT.plot_qiq,
            'surface': self.PWT.plot_surface,
            'image': self.PWT.plot_image,
            'C12': self.PWT.plot_C12,
            'plot_stack': self.PWT.plot_stack,
        }
        mat_plot_type_dict = {
            'curve': self.MPWT.plot_curve,
            'g2': self.PWT.plot_g2,
            'qiq': self.PWT.plot_qiq,
            'surface': self.MPWT.plot_surface,
            'image': self.MPWT.plot_image,
            'C12': self.PWT.plot_C12,
            'plot_stack': self.MPWT.plot_stack,
            'stack_across': self.MPWT.plot_across,
        }
        if self.plotLibrary == 'pyqtgraph':
            plot_btn.clicked.connect(pg_plot_type_dict[plot_type])
        if self.plotLibrary == 'matplotlib':
            plot_btn.clicked.connect(mat_plot_type_dict[plot_type])
        button_section = QHBoxLayout()
        button_section.addWidget(plot_btn)
        self.plot_buttons_array.append(plot_btn)
        return button_section

    def add_setlogX_box(self):
        self.setlogX_box_obj = QCheckBox("logX")
        self.setlogX_box_obj.stateChanged.connect(self.click_setlogX_box)
        button_section = QHBoxLayout()
        button_section.addWidget(self.setlogX_box_obj)
        return button_section

    def click_setlogX_box(self, state):
        if state == QtCore.Qt.Checked:
            self.logX_plot = True
        else:
            self.logX_plot = False
        try:
            self.guiplot.setLogMode(x=self.logX_plot, y=self.logY_plot)
        except:
            pass

    def add_setlogY_box(self):
        self.setlogY_box_obj = QCheckBox("logY")
        self.setlogY_box_obj.stateChanged.connect(self.click_setlogY_box)
        button_section = QHBoxLayout()
        button_section.addWidget(self.setlogY_box_obj)
        return button_section

    def click_setlogY_box(self, state):
        if state == QtCore.Qt.Checked:
            self.logY_plot = True
        else:
            self.logY_plot = False
        try:
            self.guiplot.setLogMode(x=self.logX_plot, y=self.logY_plot)
        except:
            pass

    def get_dict_from_qval_dict(self):
        l = list(self.current_hdf5['qval_dict'].attrs.items())
        dc = {int(i[0]): i[1] for i in l}
        return dc

    def add_setX_button(self):
        self.setX_btn = QPushButton('SetX')
        self.setX_btn.clicked.connect(self.setX)
        button_section = QHBoxLayout()
        button_section.addWidget(self.setX_btn)
        return button_section

    def add_resetX_button(self):
        self.resetX_btn = QPushButton('ReSetX')
        self.resetX_btn.clicked.connect(self.resetX)
        button_section = QHBoxLayout()
        button_section.addWidget(self.resetX_btn)
        return button_section

    def add_clr_plot_button(self):
        self.clr_plot_button = QPushButton("clear plot")
        self.clr_plot_button.clicked.connect(self.plot_clear)
        button_section = QHBoxLayout()
        button_section.addWidget(self.clr_plot_button)
        return button_section

    def plot_clear(self):
        if self.plotLibrary == 'matplotlib':
            if self.plot_type in plot_curve_type or self.plot_type in plot_image_type:
                if self.plot_type in plot_image_type:
                    self.grid.removeWidget(self.MPWT.cb)
                    self.MPWT.cb.setWindowOpacity(0)
                    self.MPWT.cb.hide()
                self.ax.clear()
                self.canvas.draw()
                self.canvas.hide()
                self.canvas.show()
                self.testplot_count = 0
        elif self.plotLibrary == 'pyqtgraph':
            self.guiplot.clear()
            #self.surface_plot_count = 0
            #self.grid.removeWidget(self.testplot)
            #self.guiplot.setWindowOpacity(0)
            #self.guiplot.hide()
        try:
            self.legend.scene().removeItem(self.legend)
        except:
            pass

    def add_q_box(self):
        # Create textbox
        self.q_box = QLineEdit(
            placeholderText="Please enter q-number (int) of two-time function."
        )
        button_section = QHBoxLayout()
        button_section.addWidget(self.q_box)
        return button_section

    def make_menu_bar(self):
        '''
        Initialises the menu bar at the top. '''
        menubar = self.menuBar()
        # Create a File menu and add an open button
        self.file_menu = menubar.addMenu('&File')
        open_action = QtGui.QAction('&Open', self)
        open_action.setShortcut('Ctrl+o')
        open_action.triggered.connect(self.choose_file)
        self.file_menu.addAction(open_action)
        # Add a shortcut to copy and paste data
        copy_data_action = QtGui.QAction('&Copy Data', self)
        copy_data_action.setShortcut('Ctrl+c')
        copy_data_action.triggered.connect(self.copy_data)
        self.file_menu.addAction(copy_data_action)
        paste_data_action = QtGui.QAction('&Paste Data', self)
        paste_data_action.setShortcut('Ctrl+v')
        paste_data_action.triggered.connect(self.paste_data)
        self.file_menu.addAction(paste_data_action)
        new_key_action = QtGui.QAction('&Add New Key', self)
        new_key_action.setShortcut('Ctrl+n')
        new_key_action.triggered.connect(self.create_key)
        self.file_menu.addAction(new_key_action)
        # Add an exit button to the file menu
        exit_action = QtGui.QAction('&Exit', self)
        exit_action.setShortcut('Ctrl+Z')
        exit_action.setStatusTip('Exit application')
        exit_action.triggered.connect(QtGui.qApp.quit)
        self.file_menu.addAction(exit_action)
        ## Create a view manu
        self.view_menu = menubar.addMenu('&View')
        #self.view_menu.setShortcut('Alt+v')
        self.plot_type_options_menu = self.view_menu.addMenu('&Plot Library')
        group = QActionGroup(self.plot_type_options_menu)
        texts = ["matplotlib", "pyqtgraph"]
        for text in texts:
            action = QAction(text,
                             self.plot_type_options_menu,
                             checkable=True,
                             checked=text == texts[0])
            self.plot_type_options_menu.addAction(action)
            group.addAction(action)
        group.setExclusive(True)
        group.triggered.connect(self.onTriggered_plotLibrary)

        self.image_plot_options_menu = self.view_menu.addMenu(
            '&Image Plot Options')
        self.colormap_options_menu = self.image_plot_options_menu.addMenu(
            '&Colormap')
        group = QActionGroup(self.colormap_options_menu)
        texts = image_colors
        for text in texts:
            action = QAction(text,
                             self.colormap_options_menu,
                             checkable=True,
                             checked=text == texts[0])
            self.colormap_options_menu.addAction(action)
            group.addAction(action)
        group.setExclusive(True)
        group.triggered.connect(self.onTriggered_colormap)
        self.colorscale_options_menu = self.image_plot_options_menu.addMenu(
            '&ColorScale')
        group = QActionGroup(self.colorscale_options_menu)
        texts = ["linear", "log"]
        for text in texts:
            action = QAction(text,
                             self.colormap_options_menu,
                             checkable=True,
                             checked=text == texts[1])
            self.colorscale_options_menu.addAction(action)
            group.addAction(action)
        group.setExclusive(True)
        group.triggered.connect(self.onTriggered_colorscale)
        self.display_image_data_options_menu = self.view_menu.addMenu(
            '&Display Image Data')
        show_image_data_action = QAction('show data',
                                         self,
                                         checkable=True,
                                         checked=False)
        show_image_data_action.triggered.connect(
            self.onTriggered_show_image_data)
        self.display_image_data_options_menu.addAction(show_image_data_action)

        self.stack_plot_options_menu = self.view_menu.addMenu(
            '&Stack Plot Options')
        set_stack_action = QtGui.QAction('Sampling and yshift', self)
        set_stack_action.triggered.connect(self.onTriggered_set_stack)
        self.stack_plot_options_menu.addAction(set_stack_action)

        # Create a Help menu and add an about button
        help_menu = menubar.addMenu('&Help')
        about_action = QtGui.QAction('About XSH5FView', self)
        about_action.setStatusTip('About this program')
        about_action.triggered.connect(self.show_about_menu)
        help_menu.addAction(about_action)

    def onTriggered_set_stack(self, action):
        print('set stack opt here.')
        i, okPressed = QInputDialog.getInt(self, "Set Sampling Number",
                                           "sampling:", self.vstack_sampling,
                                           0, 10000, 10)
        if okPressed:
            self.vstack_sampling = i
            print(i)
        d, okPressed = QInputDialog.getDouble(self, "Set yshift", "Value:",
                                              self.vstack_yshift, 0, 1e8, 2)
        if okPressed:
            self.vstack_yshift = d
            print(d)

    def onTriggered_show_image_data(self, action):
        #print(action.text())
        self.show_image_data = action  #.text()

    def onTriggered_colormap(self, action):
        #print(action.text())
        self.colormap_string = action.text()

    def onTriggered_colorscale(self, action):
        #print(action.text())
        self.colorscale_string = action.text()

    def onTriggered_plotLibrary(self, action):
        self.plotLibrary = action.text()
        for i in range(len(self.plot_buttons_array)):
            button_to_remove = self.plot_buttons_array.pop()
            self.grid.removeWidget(button_to_remove)
            button_to_remove.setWindowOpacity(0)
            button_to_remove.hide()
        if action.text() == 'matplotlib':
            self.toolbar.setWindowOpacity(100)
            self.toolbar.show()
            self.canvas.setWindowOpacity(100)
            self.canvas.show()
        else:
            self.toolbar.setWindowOpacity(0)
            self.toolbar.hide()
            self.canvas.setWindowOpacity(0)
            self.canvas.hide()
        if action.text() == 'pyqtgraph':
            self.guiplot.setWindowOpacity(100)
            self.guiplot.show()
        else:
            self.guiplot.setWindowOpacity(0)
            self.guiplot.hide()
        self.add_all_plot_buttons()
        self.initialise_layout()

    def show_about_menu(self):
        '''
        Shows the about menu by initialising an about_window object. This class is described in _window_classes.py '''
        self.about_window = ht.aboutWindow()
        self.about_window.show()

    def choose_file(self):
        '''
        Opens a QFileDialog window to allow the user to choose the hdf5 file they would like to view. '''
        filenames_list = QtGui.QFileDialog.getOpenFileNames(
            self,
            'Open file',
            '/home/yugang/Desktop/XPCS_GUI/TestData/test.h5',
            filter='*.hdf5 *.h5 *.lst')[0]
        for f in filenames_list:
            ext = f.split('/')[-1].split('.')[-1]
            if ext == 'lst':
                full_filename_list = np.loadtxt(
                    f,
                    dtype=object,
                )
                group_name = f.split('/')[-1]
                if group_name not in list(self.group_name_dict.keys()):
                    self.group_name_dict[group_name] = full_filename_list
                for fp in full_filename_list:
                    self.initiate_file_open(fp, group_name=group_name)
            else:
                self.initiate_file_open(f)

    def initiate_file_open(self, full_filename, group_name=None):
        base_filename = full_filename.split('/')[-1]
        self.full_filename_dict[full_filename] = group_name
        self.dataset_table.clear()
        self.attribute_table.clear()
        try:
            self.file_items_list.add_file(full_filename, group_name)
            if group_name is None:
                self.filename_label.setText(base_filename)
            else:
                self.filename_label.setText(group_name)
            self.setWindowTitle('XSH5View@CHX - ' + base_filename)
        except:
            self.filename = ''  # if it didn't work keep the old value
            self.filename_label.setText('')
            self.setWindowTitle('XSH5View@CHX')
            self.clear_file_items()
            self.dataset_table.clear()
            self.attribute_table.clear()
            print("Error opening file")

    def create_file(self):
        filename = self.file_items_list.create_file()
        self.initiate_file_open(filename)

    def remove_file(self, filename):
        self.file_items_list.remove_file()

    def clear_file_items(self):
        self.file_items_list.clear()

    def copy_data(self):
        self.file_items_list.copy_data()

    def paste_data(self):
        destination = self.file_items_list.tree.currentItem().text(1)
        item_path = self.file_items_list.tree.currentItem().text(2)
        #self.file_items_list.remove_file()
        self.file_items_list.paste_data(destination, item_path, self)
        #self.initiate_file_open(destination)

    def create_key(self):
        item = self.file_items_list.tree.currentItem()
        self.file_items_list.create_key(item.text(1), item.text(2), self)

    def get_selected_row_col(self):
        selected_items = self.dataset_table.table.selectedItems()
        shape = np.shape(self.value)
        Ns = len(shape)
        if len(selected_items) > 0:
            min_row = selected_items[0].row()
            max_row = selected_items[-1].row() + 1
            min_col = selected_items[0].column()
            max_col = selected_items[-1].column() + 1
            self.selected_flag = True
        else:
            if len(shape) == 1:
                max_col = 1
            else:
                max_col = shape[1]
            min_row = 0
            max_row = shape[0]
            min_col = 0
            self.selected_flag = False
        self.min_row, self.max_row, self.min_col, self.max_col = min_row, max_row, min_col, max_col

    def setX(self):
        self.get_selected_row_col()
        min_row, max_row, min_col, max_col = self.min_row, self.max_row, self.min_col, self.max_col
        if self.selected_flag:
            try:
                self.X = self.value[min_row:max_row, min_col]
            except:
                self.X = self.value[min_row:max_row]

    def resetX(self):
        self.X = None

    def get_filename_selected(self):
        self.dataset_table.clear()
        self.item = self.file_items_list.tree.currentItem()
        self.current_full_filename = self.item.text(1)
        self.current_group_name = self.full_filename_dict[
            self.current_full_filename]
        #print("in get filename selected:", self.current_full_filename)
        self.current_hdf5 = h5py.File(self.current_full_filename, 'r')
        self.current_base_filename = self.current_full_filename.split('/')[-1]
        self.current_item_path = self.item.text(2)
        if self.current_item_path == '':
            self.current_hdf5_item = self.current_hdf5
            self.current_item_name = self.item.text(2)
        else:
            self.current_hdf5_item = self.current_hdf5[self.current_item_path]
            self.current_item_name = self.item.text(2).split('/')[-1]

    def display_dataset(self):
        self.get_filename_selected()
        text = self.current_item_path  #self.item.text(2)
        if self.current_item_path != '':
            hdf5_file = self.current_hdf5_item
            if isinstance(hdf5_file, h5py.Dataset):
                #print( 'shows dataset-------------->')
                self.group_data = False
                #self.current_dataset = self.item_path.split('/')[-1]
                shape = hdf5_file.shape
                Ns = len(shape)
                if Ns == 0:
                    try:
                        self.value = bstring_to_string(hdf5_file)  #[0]
                    except:
                        self.value = np.array([hdf5_file])  #[0]
                    numrows = 1
                    numcols = 1
                elif Ns == 1:
                    numrows = shape[0]
                    numcols = 1
                    self.value = hdf5_file[:]
                elif Ns == 2:
                    numrows = shape[0]
                    numcols = shape[1]
                    self.value = hdf5_file[:]
                elif Ns >= 3:  #a 3D array, [x,y,z], show [x,y ]
                    if self.current_dataset_type == 'CHX':
                        numrows = shape[0]
                        numcols = shape[1]
                        try:
                            self.value = hdf5_file[:, :, self.qth]
                        except:
                            print('The max q-th is %s.' % shape[2])
                            self.value = hdf5_file[text][:, :, 0]
                    else:
                        numrows = shape[-2]
                        numcols = shape[-1]
                        try:
                            self.value = hdf5_file[self.qth, :, :]
                        except:
                            print('The max q-th is %s.' % shape[0])

            elif isinstance(hdf5_file, h5py.Group):
                print('display the group data here')
                if text in self.pds_keys:
                    d = pds.read_hdf(self.filename, key=text)  #[:]
                    self.value = np.array(d)
                    shape = self.value.shape
                    numrows = shape[0]
                    numcols = shape[1]
                    Ns = len(shape)
                    self.group_data_label = np.array(d.columns)[:]
                    self.group_data = True
                else:
                    self.dataset_table.clear()
                    self.value = np.array([])
                    self.plot_btn.hide()
            else:
                print('Other format!')
            try:
                self.dataset_table.table.setRowCount(numrows)
                self.dataset_table.table.setColumnCount(numcols)
                show_data_flag = True
                if not self.show_image_data:
                    if text in self.image_data_keys:
                        self.dataset_table.clear()
                        show_data_flag = False
                    try:
                        if self.value.shape[0] > 100 and self.value.shape[
                                1] > 100:
                            show_data_flag = False
                    except:
                        pass
                if show_data_flag:
                    if Ns != -1:
                        for i in range(numrows):
                            if numcols > 1:
                                for j in range(numcols):
                                    self.dataset_table.set_item(
                                        i, j, str(self.value[i, j]))
                            else:
                                self.dataset_table.set_item(
                                    i, 0, str(self.value[i]))
                #print( self.attributes_flag  )
                if not self.attributes_flag:
                    self.attribute_table.clear()
                    self.attribute_table.table.setRowCount(1)
                    self.attribute_table.table.setColumnCount(Ns + 1)
                    self.attribute_table.table.setItem(
                        0, 0, QTableWidgetItem('shape'))
                    for i, s in enumerate(shape):
                        self.attribute_table.table.setItem(
                            0, i + 1, QTableWidgetItem('%s' % s))
            except:
                pass
        self.current_hdf5.close()

    def display_attributes(self):
        # reset the value
        self.attribute_table.clear()
        self.get_filename_selected()
        if self.current_item_path != '':
            #print('Here shows the attributes')
            hdf5_file = self.current_hdf5_item
            try:
                attributes = list(hdf5_file.attrs.items())
                num_attributes = len(attributes)
                self.attribute_table.table.setRowCount(num_attributes)
                self.attribute_table.table.setColumnCount(0)
            except:
                num_attributes = 0

            if num_attributes > 0:
                self.attribute_table.table.setColumnCount(2)
                self.attributes_flag = True
            else:
                self.attributes_flag = False
            print(num_attributes, self.attributes_flag)
            # Populate the table
            for i in range(num_attributes):
                value = attributes[i][1]
                self.attribute_table.table.setItem(
                    i, 0, QTableWidgetItem(attributes[i][0]))
                if isinstance(value, np.ndarray):
                    N = len(value)
                    self.attribute_table.table.setColumnCount(N + 1)
                    j = 1
                    for v in value:
                        self.attribute_table.table.setItem(
                            i, j, QTableWidgetItem(str(v)))
                        #self.attribute_table.setItem(i, 1, QTableWidgetItem(str(value[0].decode())))
                        j += 1
                else:
                    self.attribute_table.table.setItem(
                        i, 1, QTableWidgetItem(str(value)))
        self.current_hdf5.close()

    def item_double_clicked(self):
        '''
        Responds to a double click on an item in the file_items_list.'''

        #self.display_attributes()
        try:
            self.display_attributes()
            #print('display attributes')
        except:
            pass

    def item_clicked(self):

        #############
        #self.display_dataset()
        #################3

        try:
            self.qth = int(self.q_box.text())
        except:
            self.qth = 0
        try:
            self.display_attributes()
            #print('display attributes')
        except:
            pass
        try:
            self.display_dataset()
        except:
            pass
        try:

            self.filename_label.setText(self.current_base_filename)
            self.setWindowTitle('XSH5View@CHX - ' + self.current_full_filename)
        except:
            pass
Exemple #42
0
class MIDISettings(SettingsPage):
    Name = QT_TRANSLATE_NOOP('SettingsPageName', 'MIDI settings')

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.setLayout(QVBoxLayout())
        self.layout().setAlignment(Qt.AlignTop)

        self.midiGroup = QGroupBox(self)
        self.midiGroup.setTitle(
            translate('MIDISettings', 'MIDI default devices'))
        self.midiGroup.setLayout(QGridLayout())
        self.layout().addWidget(self.midiGroup)

        self.inputLabel = QLabel(translate('MIDISettings', 'Input'),
                                 self.midiGroup)
        self.midiGroup.layout().addWidget(self.inputLabel, 0, 0)
        self.inputCombo = QComboBox(self.midiGroup)
        self.midiGroup.layout().addWidget(self.inputCombo, 0, 1)

        self.outputLabel = QLabel(translate('MIDISettings', 'Output'),
                                  self.midiGroup)
        self.midiGroup.layout().addWidget(self.outputLabel, 1, 0)
        self.outputCombo = QComboBox(self.midiGroup)
        self.midiGroup.layout().addWidget(self.outputCombo, 1, 1)

        self.midiGroup.layout().setColumnStretch(0, 2)
        self.midiGroup.layout().setColumnStretch(1, 3)

        if check_module('Midi'):
            self._load_devices()
        else:
            self.setEnabled(False)

    def get_settings(self):
        conf = {}

        if self.isEnabled():
            conf['inputdevice'] = self.inputCombo.currentText()
            MIDIInput().change_port(conf['inputdevice'])
        if self.isEnabled():
            conf['outputdevice'] = self.outputCombo.currentText()
            MIDIOutput().change_port(conf['outputdevice'])

        return {'MIDI': conf}

    def load_settings(self, settings):
        if 'inputdevice' in settings['MIDI']:
            self.inputCombo.setCurrentText('AppDefault')
            self.inputCombo.setCurrentText(settings['MIDI']['inputdevice'])

        if 'outputdevice' in settings['MIDI']:
            self.outputCombo.setCurrentText('AppDefaut')
            self.outputCombo.setCurrentText(settings['MIDI']['outputdevice'])

    def _load_devices(self):
        backend = mido_backend()

        self.inputCombo.clear()
        self.inputCombo.addItems(['AppDefault', 'SysDefault'])
        self.inputCombo.addItems(backend.get_input_names())

        self.outputCombo.clear()
        self.outputCombo.addItems(['AppDefault', 'SysDefault'])
        self.outputCombo.addItems(backend.get_output_names())
    def createEditor(self, parent, option, index):
        editor = QComboBox(parent)
        editor.addItems(self.options)
        editor.currentIndexChanged.connect(self.currentItemChanged)

        return editor
Exemple #44
0
class GalleryDialog(QWidget):
    """
	A window for adding/modifying gallery.
	Pass a list of QModelIndexes to edit their data
	or pass a path to preset path
	"""

    gallery_queue = queue.Queue()
    SERIES = pyqtSignal(list)
    SERIES_EDIT = pyqtSignal(list, int)

    #gallery_list = [] # might want to extend this to allow mass gallery adding

    def __init__(self, parent=None, arg=None):
        super().__init__(parent, Qt.Dialog)
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.parent_widget = parent
        log_d('Triggered Gallery Edit/Add Dialog')
        m_l = QVBoxLayout()
        self.main_layout = QVBoxLayout()
        dummy = QWidget(self)
        scroll_area = QScrollArea(self)
        scroll_area.setWidgetResizable(True)
        scroll_area.setFrameStyle(scroll_area.StyledPanel)
        dummy.setLayout(self.main_layout)
        scroll_area.setWidget(dummy)
        m_l.addWidget(scroll_area, 3)

        final_buttons = QHBoxLayout()
        final_buttons.setAlignment(Qt.AlignRight)
        m_l.addLayout(final_buttons)
        self.done = QPushButton("Done")
        self.done.setDefault(True)
        cancel = QPushButton("Cancel")
        final_buttons.addWidget(cancel)
        final_buttons.addWidget(self.done)

        def new_gallery():
            self.setWindowTitle('Add a new gallery')
            self.newUI()
            self.commonUI()
            self.done.clicked.connect(self.accept)
            cancel.clicked.connect(self.reject)

        if arg:
            if isinstance(arg, list):
                self.setWindowTitle('Edit gallery')
                self.position = arg[0].row()
                for index in arg:
                    gallery = index.data(Qt.UserRole + 1)
                    self.commonUI()
                    self.setGallery(gallery)
                self.done.clicked.connect(self.accept_edit)
                cancel.clicked.connect(self.reject_edit)
            elif isinstance(arg, str):
                new_gallery()
                self.choose_dir(arg)
        else:
            new_gallery()

        log_d('GalleryDialog: Create UI: successful')
        #TODO: Implement a way to mass add galleries
        #IDEA: Extend dialog in a ScrollArea with more forms...

        self.setLayout(m_l)
        self.resize(500, 560)
        frect = self.frameGeometry()
        frect.moveCenter(QDesktopWidget().availableGeometry().center())
        self.move(frect.topLeft())
        #self.setAttribute(Qt.WA_DeleteOnClose)

    def commonUI(self):
        f_web = QGroupBox("Metadata from the Web")
        f_web.setCheckable(False)
        self.main_layout.addWidget(f_web)
        web_main_layout = QVBoxLayout()
        web_layout = QHBoxLayout()
        web_main_layout.addLayout(web_layout)
        f_web.setLayout(web_main_layout)

        f_gallery = QGroupBox("Gallery Info")
        f_gallery.setCheckable(False)
        self.main_layout.addWidget(f_gallery)
        gallery_layout = QFormLayout()
        f_gallery.setLayout(gallery_layout)

        def basic_web(name):
            return QLabel(name), QLineEdit(), QPushButton(
                "Get metadata"), QProgressBar()

        url_lbl, self.url_edit, url_btn, url_prog = basic_web("URL:")
        url_btn.clicked.connect(
            lambda: self.web_metadata(self.url_edit.text(), url_btn, url_prog))
        url_prog.setTextVisible(False)
        url_prog.setMinimum(0)
        url_prog.setMaximum(0)
        web_layout.addWidget(url_lbl, 0, Qt.AlignLeft)
        web_layout.addWidget(self.url_edit, 0)
        web_layout.addWidget(url_btn, 0, Qt.AlignRight)
        web_layout.addWidget(url_prog, 0, Qt.AlignRight)
        self.url_edit.setPlaceholderText(
            "Paste g.e-hentai/exhentai gallery url or just press the button.")
        url_prog.hide()

        self.title_edit = QLineEdit()
        self.author_edit = QLineEdit()
        author_completer = misc.GCompleter(self, False, True, False)
        author_completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.author_edit.setCompleter(author_completer)
        self.descr_edit = QTextEdit()
        self.descr_edit.setFixedHeight(45)
        self.descr_edit.setAcceptRichText(True)
        self.lang_box = QComboBox()
        self.lang_box.addItems(["English", "Japanese", "Other"])
        self.lang_box.setCurrentIndex(0)
        tags_l = QVBoxLayout()
        tag_info = misc.ClickedLabel(
            "How do i write namespace & tags? (hover)", parent=self)
        tag_info.setToolTip(
            "Ways to write tags:\n\nNormal tags:\ntag1, tag2, tag3\n\n" +
            "Namespaced tags:\nns1:tag1, ns1:tag2\n\nNamespaced tags with one or more"
            +
            " tags under same namespace:\nns1:[tag1, tag2, tag3], ns2:[tag1, tag2]\n\n"
            +
            "Those three ways of writing namespace & tags can be combined freely.\n"
            +
            "Tags are seperated by a comma, NOT whitespace.\nNamespaces will be capitalized while tags"
            + " will be lowercased.")
        tag_info.setToolTipDuration(99999999)
        tags_l.addWidget(tag_info)
        self.tags_edit = misc.CompleterTextEdit()
        self.tags_edit.setCompleter(misc.GCompleter(self, False, False))
        tags_l.addWidget(self.tags_edit, 3)
        self.tags_edit.setFixedHeight(70)
        self.tags_edit.setPlaceholderText(
            "Press Tab to autocomplete (Ctrl + E to show popup)")
        self.type_box = QComboBox()
        self.type_box.addItems([
            "Manga", "Doujinshi", "Artist CG Sets", "Game CG Sets", "Western",
            "Image Sets", "Non-H", "Cosplay", "Other"
        ])
        self.type_box.setCurrentIndex(0)
        #self.type_box.currentIndexChanged[int].connect(self.doujin_show)
        #self.doujin_parent = QLineEdit()
        #self.doujin_parent.setVisible(False)
        self.status_box = QComboBox()
        self.status_box.addItems(["Unknown", "Ongoing", "Completed"])
        self.status_box.setCurrentIndex(0)
        self.pub_edit = QDateEdit()
        self.pub_edit.setCalendarPopup(True)
        self.pub_edit.setDate(QDate.currentDate())
        self.path_lbl = QLabel("")
        self.path_lbl.setWordWrap(True)

        link_layout = QHBoxLayout()
        self.link_lbl = QLabel("")
        self.link_lbl.setWordWrap(True)
        self.link_edit = QLineEdit()
        link_layout.addWidget(self.link_edit)
        link_layout.addWidget(self.link_lbl)
        self.link_edit.hide()
        self.link_btn = QPushButton("Modify")
        self.link_btn.setFixedWidth(50)
        self.link_btn2 = QPushButton("Set")
        self.link_btn2.setFixedWidth(40)
        self.link_btn.clicked.connect(self.link_modify)
        self.link_btn2.clicked.connect(self.link_set)
        link_layout.addWidget(self.link_btn)
        link_layout.addWidget(self.link_btn2)
        self.link_btn2.hide()

        gallery_layout.addRow("Title:", self.title_edit)
        gallery_layout.addRow("Author:", self.author_edit)
        gallery_layout.addRow("Description:", self.descr_edit)
        gallery_layout.addRow("Language:", self.lang_box)
        gallery_layout.addRow("Tags:", tags_l)
        gallery_layout.addRow("Type:", self.type_box)
        gallery_layout.addRow("Status:", self.status_box)
        gallery_layout.addRow("Publication Date:", self.pub_edit)
        gallery_layout.addRow("Path:", self.path_lbl)
        gallery_layout.addRow("Link:", link_layout)

        self.title_edit.setFocus()

    def _find_combobox_match(self, combobox, key, default):
        f_index = combobox.findText(key, Qt.MatchFixedString)
        try:
            combobox.setCurrentIndex(f_index)
        except:
            combobox.setCurrentIndex(default)

    def setGallery(self, gallery):
        "To be used for when editing a gallery"
        self.gallery = gallery

        self.url_edit.setText(gallery.link)

        self.title_edit.setText(gallery.title)
        self.author_edit.setText(gallery.artist)
        self.descr_edit.setText(gallery.info)

        self.tags_edit.setText(utils.tag_to_string(gallery.tags))

        self._find_combobox_match(self.lang_box, gallery.language, 2)
        self._find_combobox_match(self.type_box, gallery.type, 0)
        self._find_combobox_match(self.status_box, gallery.status, 0)

        gallery_pub_date = "{}".format(gallery.pub_date).split(' ')
        try:
            self.gallery_time = datetime.strptime(gallery_pub_date[1],
                                                  '%H:%M:%S').time()
        except IndexError:
            pass
        qdate_pub_date = QDate.fromString(gallery_pub_date[0], "yyyy-MM-dd")
        self.pub_edit.setDate(qdate_pub_date)

        self.link_lbl.setText(gallery.link)
        self.path_lbl.setText(gallery.path)

    def newUI(self):

        f_local = QGroupBox("Directory/Archive")
        f_local.setCheckable(False)
        self.main_layout.addWidget(f_local)
        local_layout = QHBoxLayout()
        f_local.setLayout(local_layout)

        choose_folder = QPushButton("From Directory")
        choose_folder.clicked.connect(lambda: self.choose_dir('f'))
        local_layout.addWidget(choose_folder)

        choose_archive = QPushButton("From Archive")
        choose_archive.clicked.connect(lambda: self.choose_dir('a'))
        local_layout.addWidget(choose_archive)

        self.file_exists_lbl = QLabel()
        local_layout.addWidget(self.file_exists_lbl)
        self.file_exists_lbl.hide()

    def choose_dir(self, mode):
        """
		Pass which mode to open the folder explorer in:
		'f': directory
		'a': files
		Or pass a predefined path
		"""
        self.done.show()
        self.file_exists_lbl.hide()
        if mode == 'a':
            name = QFileDialog.getOpenFileName(self,
                                               'Choose archive',
                                               filter=utils.FILE_FILTER)
            name = name[0]
        elif mode == 'f':
            name = QFileDialog.getExistingDirectory(self, 'Choose folder')
        elif mode:
            if os.path.exists(mode):
                name = mode
            else:
                return None
        if not name:
            return
        head, tail = os.path.split(name)
        name = os.path.join(head, tail)
        parsed = utils.title_parser(tail)
        self.title_edit.setText(parsed['title'])
        self.author_edit.setText(parsed['artist'])
        self.path_lbl.setText(name)
        l_i = self.lang_box.findText(parsed['language'])
        if l_i != -1:
            self.lang_box.setCurrentIndex(l_i)
        if gallerydb.GalleryDB.check_exists(name):
            self.file_exists_lbl.setText(
                '<font color="red">Gallery already exists.</font>')
            self.file_exists_lbl.show()
        # check galleries
        gs = 1
        if name.endswith(utils.ARCHIVE_FILES):
            gs = len(utils.check_archive(name))
        elif os.path.isdir(name):
            g_dirs, g_archs = utils.recursive_gallery_check(name)
            gs = len(g_dirs) + len(g_archs)
        if gs == 0:
            self.file_exists_lbl.setText(
                '<font color="red">Invalid gallery source.</font>')
            self.file_exists_lbl.show()
            self.done.hide()
        if app_constants.SUBFOLDER_AS_GALLERY:
            if gs > 1:
                self.file_exists_lbl.setText(
                    '<font color="red">More than one galleries detected in source! Use other methods to add.</font>'
                )
                self.file_exists_lbl.show()
                self.done.hide()

    def check(self):
        if len(self.title_edit.text()) is 0:
            self.title_edit.setFocus()
            self.title_edit.setStyleSheet(
                "border-style:outset;border-width:2px;border-color:red;")
            return False
        elif len(self.author_edit.text()) is 0:
            self.author_edit.setText("Unknown")

        if len(self.path_lbl.text()) == 0 or self.path_lbl.text(
        ) == 'No path specified':
            self.path_lbl.setStyleSheet("color:red")
            self.path_lbl.setText('No path specified')
            return False

        return True

    def set_chapters(self, gallery_object, add_to_model=True):
        path = gallery_object.path
        chap_container = gallerydb.ChaptersContainer(gallery_object)
        metafile = utils.GMetafile()
        try:
            log_d('Listing dir...')
            con = scandir.scandir(path)  # list all folders in gallery dir
            log_i('Gallery source is a directory')
            log_d('Sorting')
            chapters = sorted([
                sub.path for sub in con
                if sub.is_dir() or sub.name.endswith(utils.ARCHIVE_FILES)
            ])  #subfolders
            # if gallery has chapters divided into sub folders
            if len(chapters) != 0:
                log_d('Chapters divided in folders..')
                for ch in chapters:
                    chap = chap_container.create_chapter()
                    chap.title = utils.title_parser(ch)['title']
                    chap.path = os.path.join(path, ch)
                    metafile.update(utils.GMetafile(chap.path))
                    chap.pages = len(list(scandir.scandir(chap.path)))

            else:  #else assume that all images are in gallery folder
                chap = chap_container.create_chapter()
                chap.title = utils.title_parser(
                    os.path.split(path)[1])['title']
                chap.path = path
                metafile.update(utils.GMetafile(path))
                chap.pages = len(list(scandir.scandir(path)))

        except NotADirectoryError:
            if path.endswith(utils.ARCHIVE_FILES):
                gallery_object.is_archive = 1
                log_i("Gallery source is an archive")
                archive_g = sorted(utils.check_archive(path))
                for g in archive_g:
                    chap = chap_container.create_chapter()
                    chap.path = g
                    chap.in_archive = 1
                    metafile.update(utils.GMetafile(g, path))
                    arch = utils.ArchiveFile(path)
                    chap.pages = len(arch.dir_contents(g))
                    arch.close()

        metafile.apply_gallery(gallery_object)
        if add_to_model:
            self.SERIES.emit([gallery_object])
            log_d('Sent gallery to model')

    def reject(self):
        if self.check():
            msgbox = QMessageBox()
            msgbox.setText(
                "<font color='red'><b>Noo oniichan! You were about to add a new gallery.</b></font>"
            )
            msgbox.setInformativeText("Do you really want to discard?")
            msgbox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            msgbox.setDefaultButton(QMessageBox.No)
            if msgbox.exec() == QMessageBox.Yes:
                self.close()
        else:
            self.close()

    def web_metadata(self, url, btn_widget, pgr_widget):
        self.link_lbl.setText(url)
        f = fetch.Fetch()
        thread = QThread(self)
        thread.setObjectName('Gallerydialog web metadata')
        btn_widget.hide()
        pgr_widget.show()

        def status(stat):
            def do_hide():
                try:
                    pgr_widget.hide()
                    btn_widget.show()
                except RuntimeError:
                    pass

            if stat:
                do_hide()
            else:
                danger = """QProgressBar::chunk {
					background: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0,stop: 0 #FF0350,stop: 0.4999 #FF0020,stop: 0.5 #FF0019,stop: 1 #FF0000 );
					border-bottom-right-radius: 5px;
					border-bottom-left-radius: 5px;
					border: .px solid black;}"""
                pgr_widget.setStyleSheet(danger)
                QTimer.singleShot(3000, do_hide)
            f.deleteLater()

        def gallery_picker(gallery, title_url_list, q):
            self.parent_widget._web_metadata_picker(gallery, title_url_list, q,
                                                    self)

        try:
            dummy_gallery = self.make_gallery(self.gallery)
        except AttributeError:
            dummy_gallery = self.make_gallery(gallerydb.Gallery(), False)
        if not dummy_gallery:
            status(False)
            return None

        dummy_gallery.link = url
        f.galleries = [dummy_gallery]
        f.moveToThread(thread)
        f.GALLERY_PICKER.connect(gallery_picker)
        f.GALLERY_EMITTER.connect(self.set_web_metadata)
        thread.started.connect(f.auto_web_metadata)
        thread.finished.connect(thread.deleteLater)
        f.FINISHED.connect(status)
        thread.start()

    def set_web_metadata(self, metadata):
        assert isinstance(metadata, gallerydb.Gallery)
        self.link_lbl.setText(metadata.link)
        self.title_edit.setText(metadata.title)
        self.author_edit.setText(metadata.artist)
        tags = ""
        lang = ['English', 'Japanese']
        self._find_combobox_match(self.lang_box, metadata.language, 2)
        self.tags_edit.setText(utils.tag_to_string(metadata.tags))
        pub_string = "{}".format(metadata.pub_date)
        pub_date = QDate.fromString(pub_string.split()[0], "yyyy-MM-dd")
        self.pub_edit.setDate(pub_date)
        self._find_combobox_match(self.type_box, metadata.type, 0)

    def make_gallery(self, new_gallery, add_to_model=True, new=False):
        if self.check():
            new_gallery.title = self.title_edit.text()
            log_d('Adding gallery title')
            new_gallery.artist = self.author_edit.text()
            log_d('Adding gallery artist')
            log_d('Adding gallery path')
            if new and app_constants.MOVE_IMPORTED_GALLERIES:
                app_constants.OVERRIDE_MONITOR = True
                new_gallery.path = utils.move_files(self.path_lbl.text())
            else:
                new_gallery.path = self.path_lbl.text()
            new_gallery.info = self.descr_edit.toPlainText()
            log_d('Adding gallery descr')
            new_gallery.type = self.type_box.currentText()
            log_d('Adding gallery type')
            new_gallery.language = self.lang_box.currentText()
            log_d('Adding gallery lang')
            new_gallery.status = self.status_box.currentText()
            log_d('Adding gallery status')
            new_gallery.tags = utils.tag_to_dict(self.tags_edit.toPlainText())
            log_d('Adding gallery: tagging to dict')
            qpub_d = self.pub_edit.date().toString("ddMMyyyy")
            dpub_d = datetime.strptime(qpub_d, "%d%m%Y").date()
            try:
                d_t = self.gallery_time
            except AttributeError:
                d_t = datetime.now().time().replace(microsecond=0)
            dpub_d = datetime.combine(dpub_d, d_t)
            new_gallery.pub_date = dpub_d
            log_d('Adding gallery pub date')
            new_gallery.link = self.link_lbl.text()
            log_d('Adding gallery link')
            if not new_gallery.chapters:
                log_d('Starting chapters')
                thread = threading.Thread(target=self.set_chapters,
                                          args=(new_gallery, add_to_model),
                                          daemon=True)
                thread.start()
                thread.join()
                log_d('Finished chapters')
            return new_gallery

    def link_set(self):
        t = self.link_edit.text()
        self.link_edit.hide()
        self.link_lbl.show()
        self.link_lbl.setText(t)
        self.link_btn2.hide()
        self.link_btn.show()

    def link_modify(self):
        t = self.link_lbl.text()
        self.link_lbl.hide()
        self.link_edit.show()
        self.link_edit.setText(t)
        self.link_btn.hide()
        self.link_btn2.show()

    def accept(self):
        new_gallery = self.make_gallery(gallerydb.Gallery(), new=True)

        if new_gallery:
            self.close()

    def accept_edit(self):
        new_gallery = self.make_gallery(self.gallery)
        #for ser in self.gallery:
        if new_gallery:
            self.SERIES_EDIT.emit([new_gallery], self.position)
            self.close()

    def reject_edit(self):
        self.close()
Exemple #45
0
class MainGUI(QWidget):

    waveforms_generated = pyqtSignal(object, object, list, int)

    #%%
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        os.chdir('./')  # Set directory to current folder.
        self.setFont(QFont("Arial"))

        #        self.setMinimumSize(900, 1020)
        self.setWindowTitle("Screening Analysis")
        self.layout = QGridLayout(self)

        self.popnexttopimgcounter = 0
        self.Tag_round_infor = []
        self.Lib_round_infor = []
        #**************************************************************************************************************************************
        #-----------------------------------------------------------GUI for Billboard display------------------------------------------------------
        #**************************************************************************************************************************************
        ImageDisplayContainer = QGroupBox("Billboard")
        ImageDisplayContainerLayout = QGridLayout()

        self.GraphyDisplayTab = QTabWidget()

        #----------------------------------------------------------------------
        MatDsiplayPart = QWidget()
        MatDsiplayPart.layout = QGridLayout()

        # a figure instance to plot on
        self.Matdisplay_Figure = Figure()
        self.Matdisplay_Canvas = FigureCanvas(self.Matdisplay_Figure)

        self.Matdisplay_toolbar = NavigationToolbar(self.Matdisplay_Canvas,
                                                    self)
        MatDsiplayPart.layout.addWidget(self.Matdisplay_toolbar, 0, 0)
        MatDsiplayPart.layout.addWidget(self.Matdisplay_Canvas, 1, 0)
        MatDsiplayPart.setLayout(MatDsiplayPart.layout)

        self.OriginalImgWidget = pg.ImageView()
        self.OriginalImg_item = self.OriginalImgWidget.getImageItem(
        )  #setLevels
        self.OriginalImg_view = self.OriginalImgWidget.getView()
        self.OriginalImg_item.setAutoDownsample(True)

        self.OriginalImgWidget.ui.roiBtn.hide()
        self.OriginalImgWidget.ui.menuBtn.hide()
        self.OriginalImgWidget.ui.normGroup.hide()
        self.OriginalImgWidget.ui.roiPlot.hide()

        self.GraphyDisplayTab.addTab(self.OriginalImgWidget, "Image loaded")
        self.GraphyDisplayTab.addTab(MatDsiplayPart, "Scatter")

        ImageDisplayContainerLayout.addWidget(self.GraphyDisplayTab, 1, 1)

        #----------------------------------------------------------------------
        ImageButtonContainer = QGroupBox()
        ImageButtonContainerLayout = QGridLayout()

        ButtonRankResetCoordImg = QPushButton('Reset coord', self)
        ButtonRankResetCoordImg.clicked.connect(self.ResetRankCoord)
        ImageButtonContainerLayout.addWidget(ButtonRankResetCoordImg, 0, 6)

        ButtonRankPreviousCoordImg = QPushButton('Previous', self)
        ButtonRankPreviousCoordImg.setShortcut('a')
        ButtonRankPreviousCoordImg.clicked.connect(
            lambda: self.GoThroughTopCells('previous'))
        ImageButtonContainerLayout.addWidget(ButtonRankPreviousCoordImg, 1, 6)

        self.ButtonShowInScatter = QPushButton('Show in scatter', self)
        self.ButtonShowInScatter.setShortcut('s')
        self.ButtonShowInScatter.setCheckable(True)
        self.ButtonShowInScatter.clicked.connect(self.ShowScatterPos)
        ImageButtonContainerLayout.addWidget(self.ButtonShowInScatter, 2, 6)

        ButtonRankNextCoordImg = QPushButton('Next', self)
        ButtonRankNextCoordImg.setShortcut('d')
        ButtonRankNextCoordImg.clicked.connect(
            lambda: self.GoThroughTopCells('next'))
        ImageButtonContainerLayout.addWidget(ButtonRankNextCoordImg, 1, 7)

        GoSeqButton = QPushButton('Go to Cell_: ', self)
        GoSeqButton.clicked.connect(self.GotoSequence)
        ImageButtonContainerLayout.addWidget(GoSeqButton, 3, 6)

        self.ShowSequenceScatterButton = QPushButton(
            'Show this cell in scatter', self)
        self.ShowSequenceScatterButton.setCheckable(True)
        self.ShowSequenceScatterButton.clicked.connect(
            self.ShowSequenceScatter)
        ImageButtonContainerLayout.addWidget(self.ShowSequenceScatterButton, 4,
                                             6)

        self.CellSequenceBox = QSpinBox(self)
        self.CellSequenceBox.setMaximum(9000)
        self.CellSequenceBox.setMinimum(1)
        self.CellSequenceBox.setValue(1)
        self.CellSequenceBox.setSingleStep(1)
        ImageButtonContainerLayout.addWidget(self.CellSequenceBox, 3, 7)

        #        ButtonRankDeleteFromList = QPushButton('Delete', self)
        #        ButtonRankDeleteFromList.clicked.connect(self.DeleteFromTopCells)
        #        ImageButtonContainerLayout.addWidget(ButtonRankDeleteFromList, 2, 7)

        ButtonRankSaveList = QPushButton('Save Excel', self)
        ButtonRankSaveList.clicked.connect(self.SaveCellsDataframetoExcel)
        ImageButtonContainerLayout.addWidget(ButtonRankSaveList, 2, 7)

        self.ConsoleTextDisplay = QTextEdit()
        self.ConsoleTextDisplay.setFontItalic(True)
        self.ConsoleTextDisplay.setPlaceholderText(
            'Notice board from console.')
        self.ConsoleTextDisplay.setMaximumHeight(300)
        ImageButtonContainerLayout.addWidget(self.ConsoleTextDisplay, 5, 6, 3,
                                             2)

        ImageButtonContainer.setLayout(ImageButtonContainerLayout)

        ImageDisplayContainer.setLayout(ImageDisplayContainerLayout)
        ImageDisplayContainer.setMinimumHeight(700)
        ImageDisplayContainer.setMinimumWidth(700)

        self.layout.addWidget(ImageDisplayContainer, 0, 0, 2, 2)
        self.layout.addWidget(ImageButtonContainer, 0, 2)
        #**************************************************************************************************************************************
        #-----------------------------------------------------------GUI for Image processing settings------------------------------------------
        #**************************************************************************************************************************************
        self.PostProcessTab = QTabWidget()
        self.PostProcessTab.setMaximumWidth(400)
        self.PostProcessTab.setFixedHeight(250)

        ImageProcessingContainer = QGroupBox()
        IPLayout = QGridLayout()

        IPLayout.addWidget(QLabel("Contour/soma ratio threshold:"), 0, 0)
        self.Contour_soma_ratio_thres_box = QDoubleSpinBox(self)
        self.Contour_soma_ratio_thres_box.setDecimals(4)
        self.Contour_soma_ratio_thres_box.setMinimum(-10)
        self.Contour_soma_ratio_thres_box.setMaximum(10)
        self.Contour_soma_ratio_thres_box.setValue(1.000)
        self.Contour_soma_ratio_thres_box.setSingleStep(0.0001)
        IPLayout.addWidget(self.Contour_soma_ratio_thres_box, 0, 1)

        IPLayout.addWidget(QLabel("Mean intensity in contour threshold:"), 0,
                           2)
        self.Mean_intensity_in_contour_thres_box = QDoubleSpinBox(self)
        self.Mean_intensity_in_contour_thres_box.setDecimals(4)
        self.Mean_intensity_in_contour_thres_box.setMinimum(-10)
        self.Mean_intensity_in_contour_thres_box.setMaximum(10)
        self.Mean_intensity_in_contour_thres_box.setValue(0.250)
        self.Mean_intensity_in_contour_thres_box.setSingleStep(0.0001)
        IPLayout.addWidget(self.Mean_intensity_in_contour_thres_box, 0, 3)

        ImageProcessingContainer.setLayout(IPLayout)

        #---------------------------Loading------------------------------------
        LoadSettingContainer = QGroupBox()
        LoadSettingLayout = QGridLayout()

        self.FilepathSwitchBox = QComboBox()
        self.FilepathSwitchBox.addItems(['All', 'Tag', 'Lib'])
        LoadSettingLayout.addWidget(self.FilepathSwitchBox, 1, 0)

        self.AnalysisRoundBox = QSpinBox(self)
        self.AnalysisRoundBox.setMaximum(2000)
        self.AnalysisRoundBox.setValue(1)
        self.AnalysisRoundBox.setSingleStep(1)
        LoadSettingLayout.addWidget(self.AnalysisRoundBox, 1, 2)

        self.AddAnalysisRoundButton = QtWidgets.QPushButton('Add Round:')
        self.AddAnalysisRoundButton.clicked.connect(self.SetAnalysisRound)
        LoadSettingLayout.addWidget(self.AddAnalysisRoundButton, 1, 1)

        self.datasavedirectorytextbox = QLineEdit(self)
        self.datasavedirectorytextbox.setPlaceholderText('Data directory')
        LoadSettingLayout.addWidget(self.datasavedirectorytextbox, 0, 0, 1, 4)

        self.toolButtonOpenDialog = QtWidgets.QPushButton('Set path')
        self.toolButtonOpenDialog.clicked.connect(self.SetAnalysisPath)
        LoadSettingLayout.addWidget(self.toolButtonOpenDialog, 0, 4)

        ExecuteAnalysisButton = QPushButton('Load images', self)
        #        ExecuteAnalysisButton.setObjectName('Startbutton')
        ExecuteAnalysisButton.clicked.connect(lambda: self.ScreeningAnalysis())
        LoadSettingLayout.addWidget(ExecuteAnalysisButton, 1, 3)

        self.ClearAnalysisInforButton = QtWidgets.QPushButton('Clear infor')
        self.ClearAnalysisInforButton.clicked.connect(self.ClearAnalysisInfor)
        LoadSettingLayout.addWidget(self.ClearAnalysisInforButton, 1, 4)

        self.X_axisBox = QComboBox()
        self.X_axisBox.addItems(['Lib_Tag_contour_ratio'])
        LoadSettingLayout.addWidget(self.X_axisBox, 2, 1)
        LoadSettingLayout.addWidget(QLabel('X axis: '), 2, 0)

        self.WeightBoxSelectionFactor_1 = QDoubleSpinBox(self)
        self.WeightBoxSelectionFactor_1.setDecimals(2)
        self.WeightBoxSelectionFactor_1.setMinimum(0)
        self.WeightBoxSelectionFactor_1.setMaximum(1)
        self.WeightBoxSelectionFactor_1.setValue(1)
        self.WeightBoxSelectionFactor_1.setSingleStep(0.1)
        LoadSettingLayout.addWidget(self.WeightBoxSelectionFactor_1, 2, 3)
        LoadSettingLayout.addWidget(QLabel("Weight:"), 2, 2)

        self.Y_axisBox = QComboBox()
        self.Y_axisBox.addItems(['Contour_soma_ratio_Lib'])
        LoadSettingLayout.addWidget(self.Y_axisBox, 3, 1)
        LoadSettingLayout.addWidget(QLabel('Y axis: '), 3, 0)

        self.WeightBoxSelectionFactor_2 = QDoubleSpinBox(self)
        self.WeightBoxSelectionFactor_2.setDecimals(2)
        self.WeightBoxSelectionFactor_2.setMinimum(0)
        self.WeightBoxSelectionFactor_2.setMaximum(1)
        self.WeightBoxSelectionFactor_2.setValue(0.5)
        self.WeightBoxSelectionFactor_2.setSingleStep(0.1)
        LoadSettingLayout.addWidget(self.WeightBoxSelectionFactor_2, 3, 3)
        LoadSettingLayout.addWidget(QLabel("Weight:"), 3, 2)

        LoadSettingContainer.setLayout(LoadSettingLayout)

        #**************************************************************************************************************************************
        #-----------------------------------------------------------GUI for Selection threshold settings---------------------------------------
        #**************************************************************************************************************************************

        self.PostProcessTab.addTab(LoadSettingContainer, "Loading settings")
        self.PostProcessTab.addTab(ImageProcessingContainer,
                                   "Image analysis thresholds")

        self.layout.addWidget(self.PostProcessTab, 1, 2)

        self.setLayout(self.layout)

    #---------------------------------------------------------------functions for console display------------------------------------------------------------
    def normalOutputWritten(self, text):
        """Append text to the QTextEdit."""
        # Maybe QTextEdit.append() works as well, but this is how I do it:
        cursor = self.ConsoleTextDisplay.textCursor()
        cursor.movePosition(QTextCursor.End)
        cursor.insertText(text)
        self.ConsoleTextDisplay.setTextCursor(cursor)
        self.ConsoleTextDisplay.ensureCursorVisible()

    #%%
    """
    # =============================================================================
    #     FUNCTIONS FOR DATA ANALYSIS AND DISPLAY
    # =============================================================================
    """

    def SetAnalysisPath(self):
        self.Analysissavedirectory = str(
            QtWidgets.QFileDialog.getExistingDirectory())
        self.datasavedirectorytextbox.setText(self.Analysissavedirectory)

        if self.FilepathSwitchBox.currentText() == 'Tag':
            self.Tag_folder = self.Analysissavedirectory
        elif self.FilepathSwitchBox.currentText() == 'Lib':
            self.Lib_folder = self.Analysissavedirectory
        elif self.FilepathSwitchBox.currentText() == 'All':
            self.Tag_folder = self.Analysissavedirectory
            self.Lib_folder = self.Analysissavedirectory

    def SetAnalysisRound(self):

        if self.FilepathSwitchBox.currentText() == 'Tag':
            self.Tag_round_infor.append(self.AnalysisRoundBox.value())
        elif self.FilepathSwitchBox.currentText() == 'Lib':
            self.Lib_round_infor.append(self.AnalysisRoundBox.value())

        self.normalOutputWritten(
            'Tag_round_infor: {}\nLib_round_infor: {}\n'.format(
                str(self.Tag_round_infor), str(self.Lib_round_infor)))

    def ClearAnalysisInfor(self):
        self.Tag_folder = None
        self.Lib_folder = None
        self.Tag_round_infor = []
        self.Lib_round_infor = []

    def StartScreeningAnalysisThread(self):

        self.ScreeningAnalysis_thread = threading.Thread(
            target=self.ScreeningAnalysis, daemon=True)
        self.ScreeningAnalysis_thread.start()

    def ScreeningAnalysis(self):
        Mean_intensity_in_contour_thres = self.Mean_intensity_in_contour_thres_box.value(
        )
        Contour_soma_ratio_thres = self.Contour_soma_ratio_thres_box.value()
        # For the brightness screening
        self.ProcessML = ProcessImageML()

        self.normalOutputWritten('Start loading images...\n')
        tag_folder = self.Tag_folder
        lib_folder = self.Lib_folder

        tag_round = 'Round{}'.format(self.Tag_round_infor[0])
        lib_round = 'Round{}'.format(self.Lib_round_infor[0])

        cell_Data_1 = self.ProcessML.FluorescenceAnalysis(
            tag_folder, tag_round)
        cell_Data_2 = self.ProcessML.FluorescenceAnalysis(
            lib_folder, lib_round)
        Cell_DataFrame_Merged = self.ProcessML.MergeDataFrames(cell_Data_1,
                                                               cell_Data_2,
                                                               method='TagLib')
        DataFrames_filtered = self.ProcessML.FilterDataFrames(
            Cell_DataFrame_Merged, Mean_intensity_in_contour_thres,
            Contour_soma_ratio_thres)
        self.DataFrame_sorted = self.ProcessML.Sorting_onTwoaxes(
            DataFrames_filtered,
            axis_1=self.X_axisBox.currentText(),
            axis_2=self.Y_axisBox.currentText(),
            weight_1=self.WeightBoxSelectionFactor_1.value(),
            weight_2=self.WeightBoxSelectionFactor_2.value())

        self.SaveCellsDataframetoExcel()
        self.UpdateSelectionScatter()

    #%%
    def UpdateSelectionScatter(self):

        self.EvaluatingPara_list = [
            self.X_axisBox.currentText(),
            self.Y_axisBox.currentText()
        ]

        self.Matdisplay_Figure.clear()

        if len(self.EvaluatingPara_list) == 2:

            ax1 = self.Matdisplay_Figure.add_subplot(111)
            ax1.scatter(self.DataFrame_sorted.loc[:,
                                                  self.EvaluatingPara_list[0]],
                        self.DataFrame_sorted.loc[:,
                                                  self.EvaluatingPara_list[1]],
                        s=np.pi * 3,
                        c='blue',
                        alpha=0.5)
            ax1.set_xlabel(self.EvaluatingPara_list[0])
            ax1.set_ylabel(self.EvaluatingPara_list[1])
            self.Matdisplay_Figure.tight_layout()
            self.Matdisplay_Canvas.draw()

            # Some numbers ready for tracing back
            self.TotaNumofCellSelected = len(self.DataFrame_sorted)
            self.TotalCellNum = len(self.DataFrame_sorted)
            self.normalOutputWritten(
                '---- Total cells selected: {}; Total cells: {}----\n'.format(
                    self.TotaNumofCellSelected, self.TotalCellNum))

            saving_directory = os.path.join(
                self.Tag_folder,
                datetime.now().strftime('%Y-%m-%d_%H-%M-%S') +
                '_Screening scatters.html')
            self.ProcessML.showPlotlyScatter(
                self.DataFrame_sorted,
                x_axis=self.EvaluatingPara_list[0],
                y_axis=self.EvaluatingPara_list[1],
                saving_directory=saving_directory)

    def GoThroughTopCells(self, direction):
        """
        ! Cell dataframe index starts from Cell 1, which corresponds to popnexttopimgcounter = 0.
        """
        if direction == 'next':
            if self.popnexttopimgcounter > (
                    self.TotaNumofCellSelected -
                    1):  #Make sure it doesn't go beyond the last coords.
                self.popnexttopimgcounter -= 1

            self.CurrentRankCellpProperties = self.DataFrame_sorted.iloc[
                self.popnexttopimgcounter]

            #--------------------Show image with cell in box----------------------
            spec = self.CurrentRankCellpProperties.loc['ImgNameInfor_Tag']
            print(spec)
            #        #-------------- readin image---------------
            tag_imagefilename = os.path.join(self.Tag_folder,
                                             spec + '_PMT_0Zmax.tif')
            print(tag_imagefilename)
            loaded_tag_image_display = imread(tag_imagefilename, as_gray=True)
            # Retrieve boundingbox information
            Each_bounding_box = self.CurrentRankCellpProperties.loc[
                'BoundingBox_Tag']
            minr = int(Each_bounding_box[Each_bounding_box.index('minr') +
                                         4:Each_bounding_box.index('_maxr')])
            maxr = int(
                Each_bounding_box[Each_bounding_box.index('maxr') +
                                  4:Each_bounding_box.index('_minc')]) - 1
            minc = int(Each_bounding_box[Each_bounding_box.index('minc') +
                                         4:Each_bounding_box.index('_maxc')])
            maxc = int(Each_bounding_box[Each_bounding_box.index('maxc') +
                                         4:len(Each_bounding_box)]) - 1

            loaded_tag_image_display[minr, minc:maxc] = 4
            loaded_tag_image_display[maxr, minc:maxc] = 4
            loaded_tag_image_display[minr:maxr, minc] = 4
            loaded_tag_image_display[minr:maxr, maxc] = 4

            # -------Show image in imageview-------------
            self.OriginalImg_item.setImage(np.fliplr(
                np.rot90(loaded_tag_image_display)),
                                           autoLevels=True)
            self.OriginalImg_item.setLevels((0, 1))

            self.Matdisplay_Figure.clear()
            ax1 = self.Matdisplay_Figure.add_subplot(111)
            ax1.imshow(loaded_tag_image_display)  #Show the first image
            #--------------------------------------------------Add red boundingbox to axis----------------------------------------------
            rect = mpatches.Rectangle((minc, minr),
                                      maxc - minc,
                                      maxr - minr,
                                      fill=False,
                                      edgecolor='cyan',
                                      linewidth=2)
            ax1.add_patch(rect)
            ax1.text(maxc,
                     minr,
                     'NO_{}'.format(self.popnexttopimgcounter),
                     fontsize=10,
                     color='orange',
                     style='italic')
            self.Matdisplay_Figure.tight_layout()
            self.Matdisplay_Canvas.draw()

            #-------------------Print details of cell of interest----------------
            self.normalOutputWritten(
                '------------------No.{} out of {}----------------\n'.format(
                    self.popnexttopimgcounter + 1, self.TotaNumofCellSelected))
            self.normalOutputWritten('ID: {}\n{}: {}\n{}: {}\n{}: {}\n'.format(spec, self.EvaluatingPara_list[0], round(self.CurrentRankCellpProperties.loc[self.EvaluatingPara_list[0]], 4), \
                                                                     self.EvaluatingPara_list[1], round(self.CurrentRankCellpProperties.loc[self.EvaluatingPara_list[1]], 4),
                                                                     'IDNumber', self.CurrentRankCellpProperties.name))
            #------------------Stage move----------------------------------------
            #            self.CurrentPos = spec[spec.index('_R')+2:len(spec)].split('C')
            #            self.ludlStage.moveAbs(int(self.CurrentPos[0]),int(self.CurrentPos[1]))

            self.popnexttopimgcounter += 1  # Alwasy plus 1 to get it ready for next move.

        elif direction == 'previous':
            self.popnexttopimgcounter -= 2
            if self.popnexttopimgcounter >= 0:

                self.CurrentRankCellpProperties = self.DataFrame_sorted.iloc[
                    self.popnexttopimgcounter]

                #--------------------Show image with cell in box----------------------
                spec = self.CurrentRankCellpProperties.loc['ImgNameInfor_Tag']
                print(spec)
                #        #-------------- readin image---------------
                tag_imagefilename = os.path.join(self.Tag_folder,
                                                 spec + '_PMT_0Zmax.tif')
                print(tag_imagefilename)
                loaded_tag_image_display = imread(tag_imagefilename,
                                                  as_gray=True)
                # Retrieve boundingbox information
                Each_bounding_box = self.CurrentRankCellpProperties.loc[
                    'BoundingBox_Tag']
                minr = int(
                    Each_bounding_box[Each_bounding_box.index('minr') +
                                      4:Each_bounding_box.index('_maxr')])
                maxr = int(
                    Each_bounding_box[Each_bounding_box.index('maxr') +
                                      4:Each_bounding_box.index('_minc')]) - 1
                minc = int(
                    Each_bounding_box[Each_bounding_box.index('minc') +
                                      4:Each_bounding_box.index('_maxc')])
                maxc = int(Each_bounding_box[Each_bounding_box.index('maxc') +
                                             4:len(Each_bounding_box)]) - 1

                loaded_tag_image_display[minr, minc:maxc] = 4
                loaded_tag_image_display[maxr, minc:maxc] = 4
                loaded_tag_image_display[minr:maxr, minc] = 4
                loaded_tag_image_display[minr:maxr, maxc] = 4

                # -------Show image in imageview-------------
                self.OriginalImg_item.setImage(np.fliplr(
                    np.rot90(loaded_tag_image_display)),
                                               autoLevels=True)
                self.OriginalImg_item.setLevels((0, 1))

                self.Matdisplay_Figure.clear()
                ax1 = self.Matdisplay_Figure.add_subplot(111)
                ax1.imshow(loaded_tag_image_display)  #Show the first image
                #--------------------------------------------------Add red boundingbox to axis----------------------------------------------
                rect = mpatches.Rectangle((minc, minr),
                                          maxc - minc,
                                          maxr - minr,
                                          fill=False,
                                          edgecolor='cyan',
                                          linewidth=2)
                ax1.add_patch(rect)
                ax1.text(maxc,
                         minr,
                         'NO_{}'.format(self.popnexttopimgcounter),
                         fontsize=10,
                         color='orange',
                         style='italic')
                self.Matdisplay_Figure.tight_layout()
                self.Matdisplay_Canvas.draw()

                #-------------------Print details of cell of interest----------------
                self.normalOutputWritten(
                    '------------------No.{} out of {}----------------\n'.
                    format(self.popnexttopimgcounter + 1,
                           self.TotaNumofCellSelected))
                self.normalOutputWritten('ID: {}\n{}: {}\n{}: {}\n{}: {}\n'.format(spec, self.EvaluatingPara_list[0], round(self.CurrentRankCellpProperties.loc[self.EvaluatingPara_list[0]], 4), \
                                                                         self.EvaluatingPara_list[1], round(self.CurrentRankCellpProperties.loc[self.EvaluatingPara_list[1]], 4),
                                                                         'IDNumber', self.CurrentRankCellpProperties.name))

                #------------------Stage move----------------------------------------
                #                self.CurrentPos = spec[spec.index('_R')+2:len(spec)].split('C')
                #                self.ludlStage.moveAbs(int(self.CurrentPos[0]),int(self.CurrentPos[1]))

                if self.popnexttopimgcounter < (self.TotaNumofCellSelected -
                                                1):
                    self.popnexttopimgcounter += 1
            else:
                self.popnexttopimgcounter = 0

        elif direction == 'null':
            self.popnexttopimgcounter -= 1

            self.CurrentRankCellpProperties = self.DataFrame_sorted.iloc[
                self.popnexttopimgcounter]

            #--------------------Show image with cell in box----------------------
            spec = self.CurrentRankCellpProperties.loc['ImgNameInfor_Tag']
            print(spec)
            #        #-------------- readin image---------------
            tag_imagefilename = os.path.join(self.Tag_folder,
                                             spec + '_PMT_0Zmax.tif')
            print(tag_imagefilename)
            loaded_tag_image_display = imread(tag_imagefilename, as_gray=True)
            # Retrieve boundingbox information
            Each_bounding_box = self.CurrentRankCellpProperties.loc[
                'BoundingBox_Tag']
            minr = int(Each_bounding_box[Each_bounding_box.index('minr') +
                                         4:Each_bounding_box.index('_maxr')])
            maxr = int(
                Each_bounding_box[Each_bounding_box.index('maxr') +
                                  4:Each_bounding_box.index('_minc')]) - 1
            minc = int(Each_bounding_box[Each_bounding_box.index('minc') +
                                         4:Each_bounding_box.index('_maxc')])
            maxc = int(Each_bounding_box[Each_bounding_box.index('maxc') +
                                         4:len(Each_bounding_box)]) - 1

            loaded_tag_image_display[minr, minc:maxc] = 4
            loaded_tag_image_display[maxr, minc:maxc] = 4
            loaded_tag_image_display[minr:maxr, minc] = 4
            loaded_tag_image_display[minr:maxr, maxc] = 4

            # -------Show image in imageview-------------
            self.OriginalImg_item.setImage(np.fliplr(
                np.rot90(loaded_tag_image_display)),
                                           autoLevels=True)
            self.OriginalImg_item.setLevels((0, 1))

            self.Matdisplay_Figure.clear()
            ax1 = self.Matdisplay_Figure.add_subplot(111)
            ax1.imshow(loaded_tag_image_display)  #Show the first image
            #--------------------------------------------------Add red boundingbox to axis----------------------------------------------
            rect = mpatches.Rectangle((minc, minr),
                                      maxc - minc,
                                      maxr - minr,
                                      fill=False,
                                      edgecolor='cyan',
                                      linewidth=2)
            ax1.add_patch(rect)
            ax1.text(maxc,
                     minr,
                     'NO_{}'.format(self.popnexttopimgcounter),
                     fontsize=10,
                     color='orange',
                     style='italic')
            self.Matdisplay_Figure.tight_layout()
            self.Matdisplay_Canvas.draw()

            self.popnexttopimgcounter += 1

        elif direction == 'IDNumber':
            self.GotoSequence()

    def GotoSequence(self):
        """
        Go to a specific cell
        """
        self.SpecificIndexInArray = 'Cell ' + str(self.CellSequenceBox.value())
        self.CurrentRankCellpProperties = self.DataFrame_sorted.loc[
            self.SpecificIndexInArray, :]

        #--------------------Show image with cell in box----------------------
        spec = self.CurrentRankCellpProperties.loc['ImgNameInfor_Tag']
        print(spec)
        #        #-------------- readin image---------------
        tag_imagefilename = os.path.join(self.Tag_folder,
                                         spec + '_PMT_0Zmax.tif')
        print(tag_imagefilename)
        loaded_tag_image_display = imread(tag_imagefilename, as_gray=True)
        # Retrieve boundingbox information
        Each_bounding_box = self.CurrentRankCellpProperties.loc[
            'BoundingBox_Tag']
        minr = int(Each_bounding_box[Each_bounding_box.index('minr') +
                                     4:Each_bounding_box.index('_maxr')])
        maxr = int(Each_bounding_box[Each_bounding_box.index('maxr') +
                                     4:Each_bounding_box.index('_minc')]) - 1
        minc = int(Each_bounding_box[Each_bounding_box.index('minc') +
                                     4:Each_bounding_box.index('_maxc')])
        maxc = int(Each_bounding_box[Each_bounding_box.index('maxc') +
                                     4:len(Each_bounding_box)]) - 1

        loaded_tag_image_display[minr, minc:maxc] = 4
        loaded_tag_image_display[maxr, minc:maxc] = 4
        loaded_tag_image_display[minr:maxr, minc] = 4
        loaded_tag_image_display[minr:maxr, maxc] = 4

        # -------Show image in imageview-------------
        self.OriginalImg_item.setImage(np.fliplr(
            np.rot90(loaded_tag_image_display)),
                                       autoLevels=True)
        self.OriginalImg_item.setLevels((0, 1))

        self.Matdisplay_Figure.clear()
        ax1 = self.Matdisplay_Figure.add_subplot(111)
        ax1.imshow(loaded_tag_image_display)  #Show the first image
        #--------------------------------------------------Add red boundingbox to axis----------------------------------------------
        rect = mpatches.Rectangle((minc, minr),
                                  maxc - minc,
                                  maxr - minr,
                                  fill=False,
                                  edgecolor='cyan',
                                  linewidth=2)
        ax1.add_patch(rect)
        ax1.text(maxc,
                 minr,
                 'NO_{}'.format(self.CurrentRankCellpProperties.name),
                 fontsize=10,
                 color='orange',
                 style='italic')
        self.Matdisplay_Figure.tight_layout()
        self.Matdisplay_Canvas.draw()

        #-------------------Print details of cell of interest----------------
        self.normalOutputWritten(
            '------------------IDNumber {}----------------\n'.format(
                self.CurrentRankCellpProperties.name))
        self.normalOutputWritten('ID: {}\n{}: {}\n{}: {}\n'.format(spec, self.EvaluatingPara_list[0], round(self.CurrentRankCellpProperties.loc[self.EvaluatingPara_list[0]], 4), \
                                                                 self.EvaluatingPara_list[1], round(self.CurrentRankCellpProperties.loc[self.EvaluatingPara_list[1]], 4)))

    def ShowScatterPos(self):
        if self.ButtonShowInScatter.isChecked():
            self.Matdisplay_Figure.clear()
            ax1 = self.Matdisplay_Figure.add_subplot(111)
            ax1.scatter(self.DataFrame_sorted.loc[:,
                                                  self.EvaluatingPara_list[0]],
                        self.DataFrame_sorted.loc[:,
                                                  self.EvaluatingPara_list[1]],
                        s=np.pi * 3,
                        c='blue',
                        alpha=0.5)
            ax1.scatter(self.DataFrame_sorted.iloc[
                self.popnexttopimgcounter -
                1, :].loc[self.EvaluatingPara_list[0]],
                        self.DataFrame_sorted.iloc[
                            self.popnexttopimgcounter -
                            1, :].loc[self.EvaluatingPara_list[1]],
                        s=np.pi * 6,
                        c='red',
                        alpha=0.5)
            ax1.set_xlabel(self.EvaluatingPara_list[0])
            ax1.set_ylabel(self.EvaluatingPara_list[1])
            self.Matdisplay_Figure.tight_layout()
            self.Matdisplay_Canvas.draw()
        else:
            self.GoThroughTopCells('null')

    def ShowSequenceScatter(self):
        if self.ShowSequenceScatterButton.isChecked():
            self.Matdisplay_Figure.clear()
            ax1 = self.Matdisplay_Figure.add_subplot(111)

            ax1.scatter(self.DataFrame_sorted.loc[:,
                                                  self.EvaluatingPara_list[0]],
                        self.DataFrame_sorted.loc[:,
                                                  self.EvaluatingPara_list[1]],
                        s=np.pi * 3,
                        c='blue',
                        alpha=0.5)
            ax1.scatter(
                self.DataFrame_sorted.loc[self.SpecificIndexInArray, :].loc[
                    self.EvaluatingPara_list[0]],
                self.DataFrame_sorted.loc[self.SpecificIndexInArray, :].loc[
                    self.EvaluatingPara_list[1]],
                s=np.pi * 6,
                c='red',
                alpha=0.5)

            ax1.set_xlabel(self.EvaluatingPara_list[0])
            ax1.set_ylabel(self.EvaluatingPara_list[1])
            self.Matdisplay_Figure.tight_layout()
            self.Matdisplay_Canvas.draw()
        else:
            self.GoThroughTopCells('sequence')

    def SaveCellsDataframetoExcel(self):
        os.path.join(
            self.Tag_folder,
            datetime.now().strftime('%Y-%m-%d_%H-%M-%S') +
            '_CellsProperties.xlsx')
        self.DataFrame_sorted.to_excel(
            os.path.join(
                self.Tag_folder,
                datetime.now().strftime('%Y-%m-%d_%H-%M-%S') +
                '_CellsProperties.xlsx'))


#        np.save(os.path.join(self.Tag_folder, datetime.now().strftime('%Y-%m-%d_%H-%M-%S')+'_CellsProperties'), self.Overview_LookupBook)

    def ResetRankCoord(self):
        self.popnexttopimgcounter = 0
class SelectionWindowdemo(QWidget):
    def __init__(self):
        super(SelectionWindowdemo, self).__init__()
        self.initUI()

    def initUI(self):
        self.resize(800, 800)
        self.setWindowTitle('特征选择窗口')
        self.setWindowIcon(QIcon('../image/选择.png'))
        self.parameter_dict = None
        self.data = None
        self.y_predict = None
        self.df = None
        self.res_list = None
        self.var_list = None

        self.tool_bar = QToolBar()
        self.set_parameter = QAction(QIcon('../image/参数.png'), '设置参数', self)
        self.run = QAction(QIcon('../image/运行程序.png'), '运行程序', self)
        self.save = QAction(QIcon('../image/下载保存.png'), '保存结果', self)
        self.analysis = QAction(QIcon('../image/对比分析.png'), '分析预测', self)
        self.tool_bar.addAction(self.set_parameter)
        self.tool_bar.addAction(self.run)
        self.tool_bar.addAction(self.analysis)
        self.tool_bar.addAction(self.save)

        self.status_bar = QStatusBar()

        self.lable = QLabel('选择算法:')
        self.comb1 = QComboBox()
        self.comb1.addItems(['FSFS', 'Lasso'])
        # self.comb2 = QComboBox()
        # self.comb2.addItems(['算法','内容'])
        self.line_edit = QLineEdit()
        self.button = QPushButton('搜索')

        hlayout = QHBoxLayout()
        hlayout.addWidget(self.lable)
        hlayout.addWidget(self.comb1)

        # hlayout.addWidget(self.comb2)
        hlayout.addWidget(self.line_edit)
        hlayout.addWidget(self.button)
        hlayout.addWidget(self.tool_bar)
        hlayout.addStretch(3)
        hlayout.setSpacing(10)

        self.text_edit = QTextEdit()
        self.text_edit.setText(
            'Four steps for features selection:\nFliter,Semi_weapper,Union,Voting.'
        )
        self.text_edit.setReadOnly(True)
        self.run.setEnabled(False)

        vlayout = QVBoxLayout()
        vlayout.addItem(hlayout)
        vlayout.addWidget(self.text_edit)
        vlayout.addWidget(self.status_bar)
        self.setLayout(vlayout)

        self.comb1.currentIndexChanged.connect(self.selectionChange1)
        # self.comb2.currentIndexChanged(self.selecttionChange2)
        self.button.clicked.connect(self.clickSearch)
        self.set_parameter.triggered.connect(self.getParameter)
        self.run.triggered.connect(self.runProcess)
        self.analysis.triggered.connect(self.runAnalysis)
        self.save.triggered.connect(self.triggeredSave)

    #选择特征选择的算法
    def selectionChange1(self):
        self.status_bar.showMessage(self.comb1.currentText(), 5000)
        text = 'Features selection information'
        if self.comb1.currentText() == 'FSFS':
            text = 'four steps for features selection:\nFliter,Semi_weapper,Union,Voting.'
        elif self.comb1.currentText() == 'Lasso':
            text = '''
                  Lasso的全称叫做Least absolute shrinkage and selection operator,
                  直译过来为最小收缩与选择算子。
                  其本质就是在常规的线性回归的基础上对参数加了一个L1正则化约束。
                 '''
        self.text_edit.setText(text)

    #搜索算法
    def clickSearch(self):
        text = self.line_edit.text()
        index = self.comb1.findText(text)
        if index != -1:
            self.comb1.setCurrentIndex(index)
        else:
            print('没有找到{}'.format(text))

    #获取参数对话框的相关参数
    def getParameter(self):
        if self.comb1.currentText() == 'FSFS':
            self.dialog = SetParameterDialog.ParamerterDemo()
        elif self.comb1.currentText() == 'Lasso':
            self.dialog = SetParameterDialog.ParamerterDemo2()

        self.dialog.signal.sender.connect(self.setParameter)
        self.dialog.show()

    #设置算法的参数
    def setParameter(self, dic):
        print(dic)
        self.parameter_dict = dic
        self.text_edit.setText(str(dic))
        self.run.setEnabled(True)

    #执行特征选择
    def runProcess(self):
        if self.data is None or self.data[0][1] == '':
            QMessageBox.critical(self, '错误', '请先导入数据', QMessageBox.Yes,
                                 QMessageBox.No)
            return
        if self.var_list is None:
            QMessageBox.information(self, '提示', '请在数据导入页设置变量',
                                    QMessageBox.Yes | QMessageBox.No,
                                    QMessageBox.Yes)
            return
        try:
            self.run.setEnabled(False)
            # print(self.data)
            # print('-'*100)
            dtl = DTL()
            self.df = dtl.list_to_DataFrame(self.data)
            res_list = []
            start = time.time()
            self.status_bar.showMessage('特征选择中...')
            print('特征选择中...')
            f = None
            if self.comb1.currentText() == 'FSFS':
                f = FSFS.FSFSDemo(self.df, self.var_list, self.parameter_dict)
            elif self.comb1.currentText() == 'Lasso':
                f = Lasso.LassoDemo(self.df, self.var_list,
                                    self.parameter_dict)
            if f is None:
                return
            self.res_list = f.run()
            #得到用于分析的数据
            self.RMSE, self.y_predict = f.analysis()
            end = time.time()
            str_res = ',\n'.join(self.res_list)
            res = '最终选择出的特征共{0}个:\n{1}'.format(len(self.res_list), str_res)
            self.text_edit.setText(res)
            self.status_bar.showMessage('特征选择完成,耗时{}秒'.format(end - start))
        except Exception as e:
            print(e)

    #执行数据分析
    def runAnalysis(self):
        self.plot_widget = AnalysisWindow.AnalysisWindowDemo()
        if self.y_predict is not None:
            self.plot_widget.RMSE = self.RMSE
            self.plot_widget.y_predict = self.y_predict
        self.plot_widget.show()

    #将选出的特征所对应的数据分离出来保存为单独的文件
    def triggeredSave(self):
        if self.data is None or self.res_list is None:
            return
        file_path, _ = QFileDialog.getSaveFileName(
            self, '保存文件', '../result',
            'ALL Files(*);;xlsx(*.xlsx);;xls(*.xls);;csv(*.csv)')
        if file_path == '':
            return
        try:
            best_features_df = self.df[self.res_list]
            # print(best_features_df)
            name, type = file_path.split('.', maxsplit=1)
            best_features_df.to_excel(excel_writer='{}_best.{}'.format(
                name, type),
                                      index=True,
                                      encoding='utf-8')
            # print('-'*100)
            columns = self.df.columns.values.tolist()
            other_features_df = self.df[[
                column for column in columns if column not in self.res_list
            ]]
            # print(other_features_df)
            other_features_df.to_excel(excel_writer='{}_other.{}'.format(
                name, type),
                                       index=True,
                                       encoding='utf-8')
            self.status_bar.showMessage('保存完毕!')
            # print('保存完毕!')
        except Exception as e:
            print(e)
Exemple #47
0
class MainWidgetWindow(QWidget):
    def __init__(self, conf, obj):
        super().__init__()
        #self.reader = obj['reader']
        self.conf = conf
        self.obj = obj
        self.dm = DataManager(5000)
        self.initUI()

    #    self.vert_velo_list=[]
    def initUI(self):
        self.labels = {}
        #### Do wyrzucenia
        labels = self.conf['labels']
        #labels[0].update({'value': conf.get("elevation") }) #dodawanie value do "elevation"
        items = [
            'time/rssi', 'time/positionX', 'time/positionY',
            'time/temperature', 'time/pressure', 'time/altitude', 'time/pm25',
            'time/pm10', 'time/altitude_p', 'time/air_quality',
            'time/humidity', 'time/battery', 'time/send_num',
            'time/altitude_p_rel', 'time/vertical_velocity',
            'altitude_p_rel/pressure', 'altitude_p_rel/temperature',
            'altitude_p_rel/pm10', 'altitude_p_rel/air_quality',
            'altitude_p_rel/humidity'
        ]
        '''
        self.locationX_label=QLabel('Pozycja X:')
        self.locationY_label=QLabel('Pozycja Y:')
        self.height_label=QLabel('Wysokość:')
        self.speed_label=QLabel('Wysokość:')
        self.temperature_label=QLabel('Temperatura:')
        self.pressure_label=QLabel('Ciśnienie:')
        self.RRSI_label=QLabel('RRSI:')
        self.frequency_label=QLabel('Częstotliwość:')
        '''

        #menubar = self.menuBar()

        self.main_grid = QVBoxLayout()
        self.top_widget = QWidget()
        self.top_grid = QGridLayout()
        self.top_widget.setLayout(self.top_grid)
        self.bottom_widget = QWidget()
        self.bottom_grid = QGridLayout()
        self.bottom_widget.setLayout(self.bottom_grid)
        self.info_grid = QGridLayout()
        self.info_widget = QWidget()
        self.panel_grid = QGridLayout()
        self.option_grid = QGridLayout()
        self.panel_grid.addLayout(self.info_grid, 1, 0)
        self.panel_grid.addLayout(self.option_grid, 2, 0)
        self.info_widget.setLayout(self.panel_grid)
        self.info_grid_structure = {}
        self.top_splitter = QSplitter(QtCore.Qt.Horizontal)
        self.top_splitter.addWidget(self.info_widget)

        self.vertical_splitter = QSplitter(QtCore.Qt.Vertical)
        self.vertical_splitter.addWidget(self.top_splitter)
        self.vertical_splitter.addWidget(self.bottom_widget)
        self.info_grid.setSpacing(10)
        '''
        elements=len(labels)
        if elements%2==0:
            elements=elements/2
        else:
            elements=(elements+1)/2
        for i in range(0,len(labels)):
            if i<elements:
                k=i
                j=0
            else:
                k=i-elements
                j=3


            self.labels[labels[i]['id']]={'text':QLabel(labels[i]['text']),
            'value':QLabel('-')}


            self.info_grid.addWidget(self.labels[labels[i]['id']]['text'], k+1, j)
            self.info_grid.addWidget(self.labels[labels[i]['id']]['value'], k+1, j+1)

        frame=QFrame()
        frame.setFrameShape(QFrame.VLine)
        self.info_grid.addWidget(frame, 1, 3, elements, 1)
        '''
        cwd = os.getcwd() + "/maps/map.html"
        self.webView = QtWebEngineWidgets.QWebEngineView()
        self.webView.setUrl(QtCore.QUrl(cwd))  #MAPS PATH

        #self.webView.page.run
        #page().runJavaScript("[map.getBounds().getSouthWest().lat, map.getBounds().getSouthWest().lng, map.getBounds().getNorthEast().lat, map.getBounds().getNorthEast().lng]")
        self.top_grid.addWidget(self.webView, 1, 1)
        self.left_plot = self.draw_plot('time', 'rssi', self.dm)
        self.right_plot = self.draw_plot('time', 'rssi', self.dm)
        self.bottom_grid.addWidget(self.left_plot.get_widget(), 1, 0)
        self.bottom_grid.addWidget(self.right_plot.get_widget(), 1, 1)
        self.webView.loadFinished.connect(self.webView_loaded_event)
        self.top_splitter.addWidget(self.webView)

        self.new_flight_button = QPushButton('New Flight', self)
        self.new_flight_button.clicked.connect(self.new_flight)
        self.center_map_button = QPushButton('Center Map', self)
        self.center_map_button.clicked.connect(self.center_map)
        self.option_grid.addWidget(self.new_flight_button, 1, 0)
        self.option_grid.addWidget(self.center_map_button, 1, 1)

        self.load_button = QPushButton('Load Flight', self)
        self.load_button.clicked.connect(self.load_flight)
        self.configuration_button = QPushButton('Configuration', self)
        self.configuration_button.clicked.connect(self.open_configuration)
        self.option_grid.addWidget(self.load_button, 2, 0)
        self.option_grid.addWidget(self.configuration_button, 2, 1)

        self.prediction_button = QPushButton('Prediction', self)
        self.prediction_button.clicked.connect(self.change_prediction_state)
        self.option_grid.addWidget(self.prediction_button, 3, 1)
        self.change_prediction_state()

        self.left_plot_box = QComboBox(self)
        self.left_plot_box.addItems(items)  #dodawanie listy wykresów

        self.left_plot_box.currentIndexChanged.connect(self.change_plots)

        self.right_plot_box = QComboBox(self)
        self.right_plot_box.addItems(items)  #dodawanie listy wykresów

        self.right_plot_box.currentIndexChanged.connect(self.change_plots)

        self.left_plot_box_label = QLabel('Left Plot')
        self.right_plot_box_label = QLabel('Right Plot')

        self.option_grid.addWidget(self.left_plot_box_label, 4, 0)
        self.option_grid.addWidget(self.left_plot_box, 4, 1)
        self.option_grid.addWidget(self.right_plot_box_label, 5, 0)
        self.option_grid.addWidget(self.right_plot_box, 5, 1)

        self.time_control = TimeControlWidget(self)
        self.panel_grid.addWidget(self.time_control, 3, 0)

        self.main_grid.addWidget(self.vertical_splitter)
        self.setLayout(self.main_grid)
        #self.map_functions()
        '''
        self.plot=plt.plot([1,2,3,4])
        self.plot.ylabel('some numbers')
        self.main_grid.addWidget(self.plot,2,1)
        '''
        self.vertical_splitter.splitterMoved.connect(self.resize_map)
        self.top_splitter.splitterMoved.connect(self.resize_map)
        self.input_grid = QGridLayout()

        self.qtimer = QtCore.QTimer()
        self.qtimer.setInterval(200)  #IMPORTANT Update interval
        self.qtimer.timeout.connect(self.update)

        self.setGeometry(300, 300, 590, 350)
        self.setWindowTitle('SobieskiSat')
        self.show()

    def new_flight(self):
        info = copy.deepcopy(self.conf.all())
        info['type'] = 'radio'
        #self.reader(info, self.obj, self.update)
        self.obj['type'] = 'Radio'
        #self.obj['dm'].new_save()
        self.obj['dc'].new_radio()
        self.obj['timer'].reset()
        self.qtimer.start()

    def load_flight(self):
        self.obj['type'] = 'RawFile'
        self.obj['raw_file'] = 'C:/saves/2/raw.txt'
        self.obj['dc'].run_raw_file_reader()
        self.qtimer.start()

    def change_prediction_state(self):
        if 'prediction' not in self.obj:
            self.obj['prediction'] = True
        self.obj['prediction'] = not self.obj['prediction']
        if self.obj['prediction']:
            self.prediction_button.setStyleSheet("background-color: green")
        else:
            self.prediction_button.setStyleSheet("background-color: red")

    def open_configuration(self):
        self.conf_win = ConfiguratorWindow(self.conf, self.obj)
        self.conf_win.show()

    def change_plots(self):

        left = self.left_plot_box.currentText()
        right = self.right_plot_box.currentText()
        left = left.split('/')
        right = right.split('/')

        self.left_plot.lx = left[0]
        self.left_plot.ly = left[1]
        self.right_plot.lx = right[0]
        self.right_plot.ly = right[1]

    def center_map(self):
        try:
            posX = str(self.dm.get_by_id('positionX', 1)[0])
            posY = str(self.dm.get_by_id('positionY', 1)[0])

            self.webView.page().runJavaScript('centerMap(' + posX + ', ' +
                                              posY + ')')
        except Exception as e:
            print(e)

    def update(self):
        posX = None
        posY = None
        rssi = None
        data = self.obj['dc'].get()
        data.append({
            'id': 'Elevation',
            'num': 0,
            'text': 'Start Altitude: ',
            'value': str(self.conf['elevation'])
        })  #add elevation
        data = copy.deepcopy(data)  #copy data
        self.dm.add(data)
        elements = len(data)
        self.parsed_data = {}

        def haversine(lon1, lat1, lon2, lat2):
            # convert decimal degrees to radians
            #print(lon1)
            #print(lon2)
            #print(lat1)
            #print(lat2)
            lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
            # haversine formula

            dlon = lon2 - lon1
            dlat = lat2 - lat1
            a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
            c = 2 * asin(sqrt(a))
            r = 6300  # Radius of earth in kilometers. Use 3956 for miles
            #print(c*r*1000)
            return c * r * 1000  # km to m

        for d in data:
            self.parsed_data[d['id']] = d['value']

        try:
            data[11]['value'] = str(
                round(float(data[11]['value']) / 1024 * 100, 2))
        except Exception as e:
            print(e)

        try:
            altitude_p = 44330 * (1 - np.power(
                float(self.parsed_data['pressure']) /
                float(self.conf['pressure']), 0.1903))
            data.append({
                'id': 'altitude_p',
                'num': 0,
                'text': 'Altitude (pressure): ',
                'value': str(round(altitude_p, 2))
            })
            altitude_p_rel = altitude_p - float(self.conf['elevation'])
            data.append({
                'id': 'altitude_p_rel',
                'num': 0,
                'text': 'Rel Altitude (pressure): ',
                'value': str(round(altitude_p_rel, 2))
            })
            distance = haversine(float(self.conf['start_positionX']),
                                 float(self.conf['start_positionY']),
                                 float(self.parsed_data['positionX']),
                                 float(self.parsed_data['positionY']))
            data.append({
                'id': 'distance_plane',
                'num': 0,
                'text': 'Distance (plane-GPS): ',
                'value': str(round(distance, 2))
            })
            vertical_velocity = 0
            try:
                num = 20
                if (len(self.dm.get_by_id('altitude_p', num)) == num
                        and len(self.dm.get_by_id('time', num)) == num):
                    alts = self.dm.get_by_id('altitude_p', num)
                    d_alts = alts[num - 1] - alts[0]
                    times = self.dm.get_by_id('time', num)
                    d_times = times[num - 1] - times[0]
                    vertical_velocity = d_alts / d_times  # z 'num' pakietów # + w górę, - w dół

            #        self.vert_velo_list.append(vertical_velocity)
            #        print(np.mean(self.vert_velo_list))
            except Exception as e:
                print(e)
            data.append({
                'id': 'vertical_velocity',
                'num': 0,
                'text': 'Vertical velocity: ',
                'value': str(round(vertical_velocity, 2))
            })

        except Exception as e:
            print(e)

        try:
            self.map_add_point(self.conf['start_positionX'],
                               self.conf['start_positionY'], str(0),
                               str("start point"))
        except Exception as e:
            print(e)

        for d in data:
            if d['id'] in self.info_grid_structure.keys():
                self.info_grid_structure[d['id']].setText(d['value'])
            else:
                self.info_grid_structure = {}
        #print(self.info_grid_structure)
        if self.info_grid_structure == {}:
            while self.info_grid.count():
                child = self.info_grid.takeAt(0)
                if child.widget():
                    child.widget().deleteLater()
            if elements % 2 == 0:
                elements = elements / 2
            else:
                elements = (elements + 1) / 2
            for i in range(0, len(data)):
                if i < elements:
                    k = i
                    j = 0
                else:
                    k = i - elements
                    j = 3
                #print(data[i])
                self.info_grid_structure[data[i]['id']] = QLabel(
                    data[i]['value'])
                self.info_grid.addWidget(QLabel(data[i]['text']), k, j)
                self.info_grid.addWidget(
                    self.info_grid_structure[data[i]['id']], k, j + 1)

        #frame=QFrame()
        #frame.setFrameShape(QFrame.VLine)
        #self.info_grid.addWidget(frame, 1, 3, elements, 1)
        try:
            self.map_add_point(self.parsed_data['positionX'],
                               self.parsed_data['positionY'],
                               self.parsed_data['rssi'], str(self.parsed_data))
            #print(' try plot')
        except Exception as e:
            print(e)
        try:
            self.left_plot.update()
            self.right_plot.update()
        except Exception as e:
            print('Graf nie działa!!!' + str(e))

        if self.obj['prediction'] == True:
            try:
                predicts_num = 50
                if (len(self.dm.get_by_id('positionX',
                                          predicts_num)) == predicts_num):
                    pred = self.obj['predictor'].predict(
                        [
                            self.dm.get_by_id('positionX', predicts_num),
                            self.dm.get_by_id('positionY', predicts_num),
                            self.dm.get_by_id('altitude_p', predicts_num)
                        ], float(self.conf.get("elevation"))
                    )  #nowe zmiana stałej 202 na stałą ustalaną podczas startu programu w gui.py
                    try:
                        if self.conf['multi_prediction'] == False:
                            self.webView.page().runJavaScript(
                                'clearPrediction()')
                        self.webView.page().runJavaScript('drawPrediction(' +
                                                          str(pred['x']) +
                                                          ', ' +
                                                          str(pred['y']) +
                                                          ', ' +
                                                          str(pred['r']) + ')')
                    except Exception as e:
                        print(e)
            except Exception as e:
                print(e)

        super().update()

    def map_functions(self):
        #self.webView.page().runJavaScript('addPoint(50.05925, 19.92293, 13, "aaa")')
        self.webView.page().runJavaScript('alert("aa")')

    def map_add_point(self, posX, posY, signal, text):
        self.webView.page().runJavaScript('addPoint(' + posX + ', ' + posY +
                                          ', ' + signal + ', "' + text + '")')

    def resizeEvent(self, event):
        QWidget.resizeEvent(self, event)
        self.resize_map()

    def webView_loaded_event(self):
        self.webView_loaded = True
        self.webView.page().runJavaScript('init(' + self.conf['positionX'] +
                                          ',' + self.conf['positionY'] +
                                          ', 15)')
        self.resize_map()

    def resize_map(self):
        w = self.webView.frameSize().width()
        h = self.webView.frameSize().height()
        self.webView.page().runJavaScript('resizeMap("' + str(w) + 'px","' +
                                          str(h) + 'px")')

    def draw_plot(self, typex, typey, dm):
        return PlotG(typex, typey, dm, self.obj)

    def __del__(self):
        pass
        '''
Exemple #48
0
class SongsTableToolbar(QWidget):
    play_all_needed = pyqtSignal()
    filter_albums_needed = pyqtSignal([list])
    filter_text_changed = pyqtSignal([str])

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

        self.play_all_btn = QPushButton('Play All', self)
        self.play_all_btn.clicked.connect(self.play_all_needed.emit)

        # album filters
        self.filter_albums_combobox = QComboBox(self)
        self.filter_albums_combobox.addItems(['所有专辑', '标准', '单曲与EP', '现场', '合辑'])
        self.filter_albums_combobox.currentIndexChanged.connect(
            self.on_albums_filter_changed)
        # 8 works on macOS, don't know if it works on various Linux DEs
        self.filter_albums_combobox.setMinimumContentsLength(8)
        self.filter_albums_combobox.hide()
        self._setup_ui()

    def before_change_mode(self):
        """filter all filter buttons"""
        self.filter_albums_combobox.hide()
        self.play_all_btn.hide()

    def albums_mode(self):
        self.before_change_mode()
        self.filter_albums_combobox.show()

    def songs_mode(self):
        self.before_change_mode()
        self.play_all_btn.show()

    def enter_state_playall_start(self):
        self.play_all_btn.setEnabled(False)
        # currently, this is called only when feeluown is fetching songs,
        # so when we enter state_playall_start, we set play all btn text
        # to this.
        self.play_all_btn.setText('正在获取全部歌曲...')

    def enter_state_playall_end(self):
        self.play_all_btn.setText('正在获取全部歌曲...done')
        self.play_all_btn.setEnabled(True)
        self.play_all_btn.setText('播放全部')

    def _setup_ui(self):
        self._layout = QHBoxLayout(self)
        # left margin of meta widget is 30, we align with it
        # bottom margin of meta widget is 15, we should be larger than that
        self._layout.setContentsMargins(30, 15, 30, 10)
        self._layout.addWidget(self.play_all_btn)
        self._layout.addStretch(0)
        self._layout.addWidget(self.filter_albums_combobox)

    def on_albums_filter_changed(self, index):
        # ['所有', '专辑', '单曲与EP', '现场', '合辑']
        if index == 0:
            types = []
        elif index == 1:
            types = [AlbumType.standard]
        elif index == 2:
            types = [AlbumType.single, AlbumType.ep]
        elif index == 3:
            types = [AlbumType.live]
        else:
            types = [AlbumType.compilation, AlbumType.retrospective]
        self.filter_albums_needed.emit(types)
Exemple #49
0
class ConfiguratorWindow(QWidget):
    def __init__(self, conf, obj):
        super().__init__()
        self.conf = conf
        self.obj = obj
        self.initUI()
        self.structure = {
            'baudrate': self.r_baudrate_edit,
            'port': self.r_port_edit,
            'timeout': self.r_timeout_edit,
            'elevation': self.g_elevation_edit,
            'pressure': self.g_pressure_edit,
            'save_path': self.g_current_path_label,
            'multi_prediction': self.g_multi_prediction_edit,
            'start_positionX': self.g_start_positionX_edit,
            'start_positionY': self.g_start_positionY_edit
        }

    def initUI(self):
        self.main_grid = QGridLayout()
        self.tabs = QTabWidget()

        self.radio_tab = QWidget()
        self.parser_tab = QWidget()
        self.general_tab = QWidget()
        self.tabs.addTab(self.radio_tab, 'Radio')
        self.tabs.addTab(self.parser_tab, 'Parser')
        self.tabs.addTab(self.general_tab, 'General')
        self.setFixedSize(600, 400)

        #### Radio tab

        self.radio_layout = QGridLayout()
        self.r_port_label = QLabel('Port:')
        self.r_autoport_label = QLabel('Automatic Port Finder:')
        self.r_baudrate_label = QLabel('Baudrate:')
        self.r_timeout_label = QLabel('Timeout:')

        self.r_baudrate_edit = QLineEdit()
        self.r_port_edit = QComboBox()
        self.r_load_ports()
        self.r_autoport_edit = QCheckBox()
        self.r_timeout_edit = QLineEdit()

        self.radio_layout.addWidget(self.r_port_label, 1, 0)
        self.radio_layout.addWidget(self.r_port_edit, 1, 1)
        self.radio_layout.addWidget(self.r_autoport_label, 2, 0)
        self.radio_layout.addWidget(self.r_autoport_edit, 2, 1)
        self.radio_layout.addWidget(self.r_baudrate_label, 3, 0)
        self.radio_layout.addWidget(self.r_baudrate_edit, 3, 1)
        self.radio_layout.addWidget(self.r_timeout_label, 4, 0)
        self.radio_layout.addWidget(self.r_timeout_edit, 4, 1)

        self.radio_tab.setLayout(self.radio_layout)

        ### Parser tab
        self.parser_layout = QGridLayout()
        self.p_stu = QTableWidget()

        self.p_stu.setRowCount(5)
        self.p_stu.setColumnCount(3)
        self.p_stu.setHorizontalHeaderLabels(['ID', 'Name', 'Number'])
        self.p_stu.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.Stretch)

        self.p_tab_control_grid = QGridLayout()
        self.p_add_button = QPushButton('Add')
        self.p_add_button.clicked.connect(self.p_add)
        self.p_tab_control_grid.addWidget(self.p_add_button, 0, 0)

        self.p_remove_button = QPushButton('Remove')
        self.p_remove_button.clicked.connect(self.p_remove)
        self.p_tab_control_grid.addWidget(self.p_remove_button, 0, 1)

        self.parser_layout.addWidget(self.p_stu, 1, 0)
        self.parser_layout.addLayout(self.p_tab_control_grid, 2, 0)

        self.parser_tab.setLayout(self.parser_layout)

        ### General tab
        self.general_layout = QGridLayout()
        self.g_elevation_label = QLabel('Starting Altitude (from pressure):')
        self.g_pressure_label = QLabel('Absolute Pressure:')
        self.g_multi_prediction_label = QLabel('Multipoint Prediction:')
        self.g_save_path_label = QLabel('Set Save Path:')
        self.g_current_path_label_label = QLabel('Current Path:')
        self.g_current_path_label = QLabel('-')
        self.g_start_positionX_label = QLabel('Start Position X:')
        self.g_start_positionY_label = QLabel('Start Position Y:')

        self.g_elevation_edit = QLineEdit()
        self.g_pressure_edit = QLineEdit()
        self.g_multi_prediction_edit = QCheckBox()
        self.g_save_path_edit = QPushButton('Wybierz')
        self.g_start_positionX_edit = QLineEdit()
        self.g_start_positionY_edit = QLineEdit()

        self.g_save_path_edit.clicked.connect(self.r_file_dialog)

        self.general_layout.addWidget(self.g_elevation_label, 1, 0)
        self.general_layout.addWidget(self.g_elevation_edit, 1, 1)
        self.general_layout.addWidget(self.g_pressure_label, 2, 0)
        self.general_layout.addWidget(self.g_pressure_edit, 2, 1)
        self.general_layout.addWidget(self.g_start_positionX_label, 3, 0)
        self.general_layout.addWidget(self.g_start_positionX_edit, 3, 1)
        self.general_layout.addWidget(self.g_start_positionY_label, 4, 0)
        self.general_layout.addWidget(self.g_start_positionY_edit, 4, 1)
        self.general_layout.addWidget(self.g_multi_prediction_label, 5, 0)
        self.general_layout.addWidget(self.g_multi_prediction_edit, 5, 1)
        self.general_layout.addWidget(self.g_save_path_label, 6, 0)
        self.general_layout.addWidget(self.g_save_path_edit, 6, 1)
        self.general_layout.addWidget(self.g_current_path_label_label, 7, 0)
        self.general_layout.addWidget(self.g_current_path_label, 7, 1)

        self.general_tab.setLayout(self.general_layout)
        ### Finish

        self.main_grid.addWidget(self.tabs, 0, 0)

        self.bottom_grid = QGridLayout()
        self.save_button = QPushButton('Save')
        self.save_button.clicked.connect(self.save)

        self.bottom_grid.addWidget(self.save_button, 0, 3)
        self.main_grid.addLayout(self.bottom_grid, 1, 0)

        self.setLayout(self.main_grid)
        self.setWindowTitle('Configuration')

        #print(isinstance(self.r_port_edit, QLineEdit)) sprawdzanie typu
    def p_add(self):
        self.p_stu.insertRow(self.p_stu.currentRow() + 1)

    def p_remove(self):
        buttonReply = QMessageBox.question(
            self, 'Remove?', 'Do you want to remove ' +
            str(self.p_stu.currentRow() + 1) + ' row?',
            QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if buttonReply == QMessageBox.Yes:
            self.p_stu.removeRow(self.p_stu.currentRow())

    def r_file_dialog(self):
        file_name = QFileDialog.getExistingDirectory(self, 'Select', '/home')
        if file_name:
            self.conf['save_path'] = file_name
        self.load()

    def save(self):
        new = {}
        for k, v in self.structure.items():
            if isinstance(v, QLineEdit):
                new[k] = v.text()
            elif isinstance(v, QComboBox):
                new[k] = v.currentText()
            elif isinstance(v, QCheckBox):
                new[k] = v.isChecked()
            ### Dodać Obsługę Pliki
        self.p_save_structure()

        self.conf.update(new)
        self.close()

    def load(self):
        data = self.conf.all()

        for k, v in self.structure.items():
            if k in data:
                try:
                    if isinstance(v, QLineEdit):
                        v.setText(str(data[k]))
                    elif isinstance(v, QCheckBox):
                        v.setChecked(data[k])
                    elif isinstance(v, QComboBox):
                        v.setCurrentText(str(data[k]))  #może nie działać
                    elif isinstance(v, QLabel):
                        v.setText(str(data[k]))
                except Exception as e:
                    print(e)
        self.load_structure()

    def r_load_ports(self):
        sl = self.obj['sl']
        dev = sl.all_serials()
        names = []
        for d in dev:
            names.append(d.device)
        self.r_port_edit.addItems(names)
        if self.conf['port'] in names:
            self.r_port_edit.setCurrentText(self.conf['port'])

    def load_structure(self):
        labels = self.conf.all()['labels']
        self.p_stu.setRowCount(len(labels))
        counter = 0
        for i in labels:
            self.p_stu.setItem(counter, 0, QTableWidgetItem(i['id']))
            self.p_stu.setItem(counter, 1, QTableWidgetItem(i['text']))
            self.p_stu.setItem(counter, 2, QTableWidgetItem(str(i['num'])))
            counter += 1

    def p_save_structure(self):
        stru = []
        for r in range(0, self.p_stu.rowCount()):
            id = self.p_stu.item(r, 0).text()
            name = self.p_stu.item(r, 1).text()
            num = self.p_stu.item(r, 2).text()
            stru.append({'id': id, 'num': int(num), 'text': name})
        self.conf['labels'] = stru

    def show(self):
        self.load()
        super().show()
Exemple #50
0
class PID_Tuner_Widget(QWidget):
    '''
    This class is a PyQt widget for tunning the 6 degree of freedom PID control system.
    '''
    def __init__(self):
        '''
        Initialize the layout for the widget by setting its color and instantiating its
        components:

        Parameters:
            N/A

        Returns:
            N/A
        '''
        QWidget.__init__(self)

        configs = MechOS_Network_Configs(
            MECHOS_CONFIG_FILE_PATH)._get_network_parameters()

        self.pid_gui_node = mechos.Node("PID_TUNER_GUI", '192.168.1.2',
                                        '192.168.1.14')

        #Publisher to tell the navigation/movement controller when new PID values are saved.
        self.pid_configs_update_publisher = self.pid_gui_node.create_publisher(
            "UPDATE_PID_CONFIGS", Bool(), protocol="tcp")

        #Subscriber to get PID ERRORS
        #self.pid_errors_subscriber = self.pid_gui_node.create_subscriber("PE", self._update_error_plot, configs["sub_port"])
        #self.pid_error_proto = pid_errors_pb2.PID_ERRORS()

        #Mechos parameter server
        #Initialize parameter server client to get and set parameters related to sub
        self.param_serv = mechos.Parameter_Server_Client(
            configs["param_ip"], configs["param_port"])
        self.param_serv.use_parameter_database(configs["param_server_path"])

        #Set background color of the widget
        #nav_gui_palette = self.palette()
        #nav_gui_palette.setColor(self.backgroundRole(), QColor(64, 64, 64))
        #self.setPalette(nav_gui_palette)

        #Create widgets main layout structure
        self.primary_linking_layout = QVBoxLayout(self)
        self.setLayout(self.primary_linking_layout)

        #Options widget
        self.options_linking_layout = QGridLayout()

        self._error_plotter()
        self._PID_controller_select()
        self._PID_sliders()
        self.set_desired_position = Set_Desired_Position_GUI()

        #Set up QTimer to update the PID errors
        self.pid_error_update_timer = QTimer()

        #self.pid_error_update_timer.timeout.connect(lambda: self.pid_gui_node.spinOnce(self.pid_errors_subscriber))

        self.primary_linking_layout.addLayout(self.options_linking_layout, 1)
        self.primary_linking_layout.addWidget(self.set_desired_position, 2)
        #Start PID errors update errors. Update 100 timers a second
        self.pid_error_update_timer.start(10)

    def _PID_controller_select(self):
        '''
        '''
        self.PID_controller_layout = QGridLayout()

        #A combo box to select which PID channel to tune
        self.pid_channel_select = QComboBox()
        self.pid_channel_select.addItem("roll_pid")
        self.pid_channel_select.addItem("pitch_pid")
        self.pid_channel_select.addItem("yaw_pid")
        self.pid_channel_select.addItem("x_pid")
        self.pid_channel_select.addItem("y_pid")
        self.pid_channel_select.addItem("z_pid")

        #Signal to change which PID controller is being tunned when selection changes
        self.pid_channel_select.currentIndexChanged.connect(
            self._PID_controller_change)
        self.pid_channel_select_label = QLabel("PID Controller:")
        self.pid_channel_select_label.setStyleSheet("color: black")

        #A button to save the PID values to the parameter server. This is how to sub
        #will update its PID values
        self.PID_save_values_layout = QVBoxLayout()
        self.pid_values_save = QPushButton("Save PID Values")
        self.pid_values_save.setStyleSheet(
            "background-color:#2C878F; color:#01535B")
        self.pid_values_save.setIcon(QIcon(QPixmap("save_symbol.png")))
        self.pid_values_save.clicked.connect(self._save_pid_values)
        self.PID_save_values_layout.addWidget(self.pid_values_save, 0)

        self.PID_controller_layout.addWidget(self.pid_channel_select_label, 0,
                                             0)
        self.PID_controller_layout.addWidget(self.pid_channel_select, 0, 1)
        self.PID_save_values_layout.addLayout(self.PID_controller_layout, 1)

        self.options_linking_layout.addLayout(self.PID_save_values_layout, 0,
                                              1)

    def _PID_sliders(self):
        '''
        Set up the proportional, integral, and derivatives gain sliders for tunning
        the PID controls.

        Parameters:
            N/A

        Returns:
            N/A
        '''
        self.slider_layout = QGridLayout()
        self.k_p_precision_layout = QGridLayout()
        self.k_i_precision_layout = QGridLayout()
        self.k_d_precision_layout = QGridLayout()

        self.k_p_slider = QSlider(Qt.Horizontal)
        self.k_p_slider.setMaximum(10)
        self.k_p_slider.setMinimum(0)
        self.k_p_slider.setValue(0)
        self.k_p_slider.valueChanged.connect(self._update_gains_with_slider)
        self.k_p_label = QLabel("K_P:")
        self.k_p_label.setStyleSheet("color: black")
        self.k_p_display = QLineEdit()
        self.k_p_display.editingFinished.connect(
            self._update_gain_with_line_edits)

        self.k_p_max_value_line_edit = QLineEdit()
        self.max_k_p = 10.0
        self.k_p_max_value_line_edit.setText(str(self.max_k_p))
        self.k_p_max_value_line_edit.editingFinished.connect(
            self._update_PID_precision)
        self.k_p_max_value_label = QLabel("Max K_P:")
        self.k_p_max_value_label.setStyleSheet("color: black")
        self.k_p_precision_combobox = QComboBox()
        self.k_p_precision_combobox.addItems(["1", "0.1", "0.01", "0.001"])
        self.precision_k_p = float(self.k_p_precision_combobox.currentText())
        self.k_p_precision_combobox.currentIndexChanged.connect(
            self._update_PID_precision)
        self.k_p_precision_label = QLabel("K_P Precision:")
        self.k_p_precision_label.setStyleSheet("color: black")

        self.k_i_slider = QSlider(Qt.Horizontal)
        self.k_i_slider.setMaximum(10)
        self.k_i_slider.setMinimum(0)
        self.k_i_slider.setValue(0)
        self.k_i_slider.valueChanged.connect(self._update_gains_with_slider)
        self.k_i_label = QLabel("K_I:")
        self.k_i_label.setStyleSheet("color: black")
        self.k_i_display = QLineEdit()
        self.k_i_display.editingFinished.connect(
            self._update_gain_with_line_edits)

        self.k_i_max_value_line_edit = QLineEdit()
        self.max_k_i = 10.0
        self.k_i_max_value_line_edit.setText(str(self.max_k_i))
        self.k_i_max_value_line_edit.editingFinished.connect(
            self._update_PID_precision)
        self.k_i_max_value_label = QLabel("Max K_I:")
        self.k_i_max_value_label.setStyleSheet("color: black")
        self.k_i_precision_combobox = QComboBox()
        self.k_i_precision_combobox.addItems(["1", "0.1", "0.01", "0.001"])
        self.precision_k_i = float(self.k_i_precision_combobox.currentText())
        self.k_i_precision_combobox.currentIndexChanged.connect(
            self._update_PID_precision)
        self.k_i_precision_label = QLabel("K_I Precision:")
        self.k_i_precision_label.setStyleSheet("color: black")

        self.k_d_slider = QSlider(Qt.Horizontal)
        self.k_d_slider.setMaximum(10)
        self.k_d_slider.setMinimum(0)
        self.k_d_slider.setValue(0)
        self.k_d_slider.valueChanged.connect(self._update_gains_with_slider)
        self.k_d_label = QLabel("K_D:")
        self.k_d_label.setStyleSheet("color: black")
        self.k_d_display = QLineEdit()
        self.k_d_display.editingFinished.connect(
            self._update_gain_with_line_edits)

        self.k_d_max_value_line_edit = QLineEdit()
        self.max_k_d = 10.0
        self.k_d_max_value_line_edit.setText(str(self.max_k_d))
        self.k_d_max_value_line_edit.editingFinished.connect(
            self._update_PID_precision)
        self.k_d_max_value_label = QLabel("Max K_D:")
        self.k_d_max_value_label.setStyleSheet("color: black")
        self.k_d_precision_combobox = QComboBox()
        self.k_d_precision_combobox.addItems(["1", "0.1", "0.01", "0.001"])
        self.precision_k_d = float(self.k_d_precision_combobox.currentText())
        self.k_d_precision_combobox.currentIndexChanged.connect(
            self._update_PID_precision)
        self.k_d_precision_label = QLabel("K_D Precision:")
        self.k_d_precision_label.setStyleSheet("color: black")

        self.k_p_precision_layout.addWidget(self.k_p_max_value_label, 0, 0)
        self.k_p_precision_layout.addWidget(self.k_p_max_value_line_edit, 0, 1)
        self.k_p_precision_layout.addWidget(self.k_p_precision_label, 1, 0)
        self.k_p_precision_layout.addWidget(self.k_p_precision_combobox, 1, 1)

        self.k_i_precision_layout.addWidget(self.k_i_max_value_label, 0, 0)
        self.k_i_precision_layout.addWidget(self.k_i_max_value_line_edit, 0, 1)
        self.k_i_precision_layout.addWidget(self.k_i_precision_label, 1, 0)
        self.k_i_precision_layout.addWidget(self.k_i_precision_combobox, 1, 1)

        self.k_d_precision_layout.addWidget(self.k_d_max_value_label, 0, 0)
        self.k_d_precision_layout.addWidget(self.k_d_max_value_line_edit, 0, 1)
        self.k_d_precision_layout.addWidget(self.k_d_precision_label, 1, 0)
        self.k_d_precision_layout.addWidget(self.k_d_precision_combobox, 1, 1)

        self.slider_layout.addWidget(self.k_p_label, 0, 0)
        self.slider_layout.addWidget(self.k_p_slider, 0, 1)
        self.slider_layout.addWidget(self.k_p_display, 0, 2)
        self.slider_layout.addLayout(self.k_p_precision_layout, 0, 3)

        self.slider_layout.addWidget(self.k_i_label, 1, 0)
        self.slider_layout.addWidget(self.k_i_slider, 1, 1)
        self.slider_layout.addWidget(self.k_i_display, 1, 2)
        self.slider_layout.addLayout(self.k_i_precision_layout, 1, 3)

        self.slider_layout.addWidget(self.k_d_label, 2, 0)
        self.slider_layout.addWidget(self.k_d_slider, 2, 1)
        self.slider_layout.addWidget(self.k_d_display, 2, 2)
        self.slider_layout.addLayout(self.k_d_precision_layout, 2, 3)

        self.options_linking_layout.addLayout(self.slider_layout, 0, 0)

        self._PID_controller_change()

    def _error_plotter(self):
        '''
        Initialize a real time plotter widget to display the PID error of the sub.

        Parameters:
            N/A

        Returns:
            N/A
        '''
        self.error_plot = Real_Time_Plotter(title="PID Error")
        self.error_plot.add_curve("Current Error", (255, 0, 0))
        self.error_plot.add_curve("Zero Error", (0, 255, 0))
        self.primary_linking_layout.addWidget(self.error_plot, 0)

    def _update_error_plot(self, pid_error_proto):
        '''
        Update the error plot by calling the pid error subscriber. This function is
        the callback function to the pid_error_suscriber.

        Parameters:
            pid_error_proto: The pid error protobuf recieved from the pid error
                                subscriber.
        Returns:
            N/A
        '''
        self.pid_error_proto.ParseFromString(pid_error_proto)

        self.channel = self.pid_channel_select.currentIndex()

        if (self.channel == 0):
            current_error = self.pid_error_proto.roll_error
        elif (self.channel == 1):
            current_error = self.pid_error_proto.pitch_error
        elif (self.channel == 2):
            current_error = self.pid_error_proto.yaw_error
        elif (self.channel == 3):
            current_error = self.pid_error_proto.x_pos_error
        elif (self.channel == 4):
            current_error = self.pid_error_proto.y_pos_error
        elif (self.channel == 5):
            current_error = self.pid_error_proto.z_pos_error
        self.error_plot.update_values(current_error, 0)

    def _PID_controller_change(self):
        '''
        If the PID controller desired to be tune changes, this callback is called
        to position the sliders in the last set PID control position.

        Parameters:
            N/A
        Returns:
            N/A
        '''
        self.channel = self.pid_channel_select.currentText()

        k_p = self.param_serv.get_param('Control/PID/' + self.channel + '/p')
        k_i = self.param_serv.get_param('Control/PID/' + self.channel + '/i')
        k_d = self.param_serv.get_param('Control/PID/' + self.channel + '/d')

        #Set the max of each channel as the value from the Parameter server

        k_p_disp = "%.3f" % (float(k_p) + 0.10 * float(k_p))
        k_i_disp = "%.3f" % (float(k_i) + 0.10 * float(k_i))
        k_d_disp = "%.3f" % (float(k_d) + 0.10 * float(k_d))

        self.k_p_max_value_line_edit.setText(k_p_disp)
        self.k_i_max_value_line_edit.setText(k_i_disp)
        self.k_d_max_value_line_edit.setText(k_d_disp)

        #Set the precision to the max precision of the
        self.k_p_precision_combobox.setCurrentIndex(3)
        self.k_i_precision_combobox.setCurrentIndex(3)
        self.k_d_precision_combobox.setCurrentIndex(3)

        self._update_PID_precision()

        self._update_gain_displays(k_p, k_i, k_d)
        self._update_sliders(k_p, k_i, k_d)

    def _save_pid_values(self):
        '''
        This is the callback for the save pid values button. When it is pressed,
        it sets the PID gain values currently selected on the sliders/gain displays
        and writes it to the parameter server. Then it tells the navigation controller
        to update these values.

        Parameters:
            N/A

        Returns:
            N/A
        '''

        channel = self.pid_channel_select.currentText()

        #Get the current PID values seen by the sliders/gain displays. Set it
        #to the parameter server.
        k_p = self.k_p_display.text()
        k_i = self.k_i_display.text()
        k_d = self.k_d_display.text()

        self.param_serv.set_param('Control/PID/' + channel + '/p', k_p)
        self.param_serv.set_param('Control/PID/' + channel + '/i', k_i)
        self.param_serv.set_param('Control/PID/' + channel + '/d', k_d)

        time.sleep(0.01)  #Make sure that the parameters are properly sent.

        #Tell the navigation controller/movement controller to update its PIDs

        self.pid_configs_update_publisher.publish(bytes(
            '1', 'utf-8'))  #The value that is sent does not matter
        print("[INFO]: Saving and Updating PID Configurations.")

    def _update_PID_precision(self):
        '''
        This function is the callback for when the desired PID gain floating point
        precision is changed. It allows for the selection of the max p, i, and d values
        for each channel.

        Parameters:
            N/A

        Returns:
            N/A
        '''
        k_p = self.k_p_display.text()
        k_i = self.k_i_display.text()
        k_d = self.k_d_display.text()

        self.max_k_p = float(self.k_p_max_value_line_edit.text())
        self.precision_k_p = float(self.k_p_precision_combobox.currentText())
        self.k_p_slider.setMaximum(self.max_k_p * (1 / self.precision_k_p))

        self.max_k_i = float(self.k_i_max_value_line_edit.text())
        self.precision_k_i = float(self.k_i_precision_combobox.currentText())
        self.k_i_slider.setMaximum(self.max_k_i * (1 / self.precision_k_i))

        self.max_k_d = float(self.k_d_max_value_line_edit.text())
        self.precision_k_d = float(self.k_d_precision_combobox.currentText())
        self.k_d_slider.setMaximum(self.max_k_d * (1 / self.precision_k_d))

        #self._update_gain_displays(k_p, k_i, k_d)
        #self._update_sliders(k_p, k_i, k_d)

    def _update_gains_with_slider(self):
        '''
        This function is the callback called when any of the sliders change in
        value. It will update the gain displays to view what the current gain is
        via number.

        Parameters:
            N/A

        Returns:
            N/A
        '''
        k_p = self.k_p_slider.value() * self.precision_k_p
        k_i = self.k_i_slider.value() * self.precision_k_i
        k_d = self.k_d_slider.value() * self.precision_k_d
        self._update_gain_displays(k_p, k_i, k_d)

    def _update_gain_with_line_edits(self):
        '''
        This function is the callback called when any of the gain displays change in
        value and the enter key is pressed. It will update the slider position to
        view what the current gain isvia number.

        Parameters:
            N/A

        Returns:
            N/A
        '''
        k_p = float(self.k_p_display.text())
        if (k_p > self.max_k_p):
            k_p = self.max_k_p
        k_i = float(self.k_i_display.text())
        if (k_i > self.max_k_i):
            k_i = self.max_k_i
        k_d = float(self.k_d_display.text())
        if (k_d > self.max_k_d):
            k_d = self.max_k_d

        self._update_sliders(k_p, k_i, k_d)
        self._update_gain_displays(k_p, k_i, k_d)

    def _update_gain_displays(self, k_p, k_i, k_d):
        '''
        Set the text for the gain displays.

        Parameters:
            k_p: The proportional gain
            k_i: Integral gain
            k_d: Derivative gain

        Returns:
            N/A
        '''
        self.k_p_display.setText(str(round(float(k_p), 3)))
        self.k_i_display.setText(str(round(float(k_i), 3)))
        self.k_d_display.setText(str(round(float(k_d), 3)))

    def _update_sliders(self, k_p, k_i, k_d):
        '''
        Set the position for the sliders.

        Parameters:
            k_p: The proportional gain
            k_i: Integral gain
            k_d: Derivative gain

        Returns:
            N/A
        '''
        self.k_p_slider.setValue(float(k_p) / self.precision_k_p)
        self.k_i_slider.setValue(float(k_i) / self.precision_k_i)
        self.k_d_slider.setValue(float(k_d) / self.precision_k_d)
Exemple #51
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.config = ConfigParser()
        self.setting_widget = QWidget()
        self.show_widget = QWidget()
        self.heart_function_widget = QWidget()
        self.main_widget = QSplitter()
        self.main_layout = QHBoxLayout()
        self.left_layout = QVBoxLayout()
        self.show_layout = QVBoxLayout()

        self.open_serial_button = QPushButton()

        self.init_ui()

    def init_ui(self):
        self.config.read('config.ini')
        self.setGeometry(self.config.getint('Size Setting', 'Geometry_ax'),
                         self.config.getint('Size Setting', 'Geometry_ay'),
                         self.config.getint('Size Setting', 'Geometry_xs'),
                         self.config.getint('Size Setting', 'Geometry_ys'))
        # todo: change the version number automatically
        self.setWindowTitle(
            self.config.get('Text Setting', 'MainWindow_Title') + '--V1.0')

        self.setWindowIcon(
            QIcon(self.config.get('Picture Setting', 'MainWind_icon')))
        self.main_widget.addWidget(self.setting_widget)
        self.main_widget.addWidget(self.show_widget)
        self.main_widget.addWidget(self.heart_function_widget)
        self.main_widget.setStretchFactor(0, 2)
        self.main_widget.setStretchFactor(1, 12)
        self.main_widget.setStretchFactor(2, 2)
        self.open_serial_button.setText('')
        self.open_serial_button.setStyleSheet("background-color:red")
        self.init_show_widget()
        self.init_statue_bar()
        self.init_menu_bar()
        self.init_setting_widget()
        self.init_heart_function_widget()
        self.setCentralWidget(self.main_widget)

    def init_menu_bar(self):
        scan_action = QAction('Scan(&S)', self)
        self.load_action = QAction('Load(&L)', self)
        scan_action.setShortcut('Ctrl+S')
        port_menu = self.menuBar().addMenu('Port(&P)')
        port_menu.addAction(scan_action)
        view_menu = self.menuBar().addMenu('View(&V)')
        tools_menu = self.menuBar().addMenu('Tools(&T)')
        self.reload_action = QAction('Reload', self)
        tools_menu.addAction(self.reload_action)
        view_menu.addAction(self.load_action)

    def init_setting_widget(self):
        # port set part  # 结构一定要严谨
        group_box = QGroupBox('SerialSetting')
        serial_setting_layout = QFormLayout()
        self.serial_port_combobox = QComboBox()
        self.serial_baudrate_combobox = QComboBox()
        self.serial_bytes_combobox = QComboBox()
        self.serial_parity_combobox = QComboBox()
        self.serial_stop_combobox = QComboBox()
        self.serial_flow_combobox = QComboBox()
        self.serial_baudrate_combobox.addItems([
            '1200', '2400', '4800', '9600', '19200', '38400', '57600', '115200'
        ])
        self.serial_baudrate_combobox.setCurrentIndex(3)
        self.serial_baudrate_combobox.setEditable(True)
        self.serial_bytes_combobox.addItems(['5', '6', '7', '8'])
        self.serial_bytes_combobox.setCurrentIndex(3)
        self.serial_parity_combobox.addItems(
            ['No', 'Odd', 'Space', 'Even', 'Mark'])
        self.serial_parity_combobox.setCurrentIndex(0)
        self.serial_stop_combobox.addItems(['One', 'OneAndHalf', 'Two'])
        self.serial_flow_combobox.addItems(
            ['NoFlow', 'Hardware', 'Software', 'UnknownFlow'])
        self.serial_flow_combobox.setCurrentIndex(0)
        # learn QFromLayout
        serial_setting_layout.addRow(QLabel(r'端口'), self.serial_port_combobox)
        serial_setting_layout.addRow(QLabel(r'波特率'),
                                     self.serial_baudrate_combobox)
        serial_setting_layout.addRow(QLabel(r'分割符'),
                                     self.serial_parity_combobox)
        serial_setting_layout.addRow(QLabel(r'数据位数'),
                                     self.serial_bytes_combobox)
        serial_setting_layout.addRow(QLabel(r'流控制'), self.serial_flow_combobox)
        serial_setting_layout.addRow(QLabel(r'打开串口'), self.open_serial_button)
        group_box.setLayout(serial_setting_layout)

        # receive set part
        receive_group_box = QGroupBox('Receive')
        receive_hex_ascii_layout = QHBoxLayout()
        self.receive_hex_checkbox = QCheckBox('RECHEX')
        self.receive_asc_checkbox = QCheckBox('RECASCII')
        self.receive_hex_checkbox.setChecked(True)
        self.receive_asc_checkbox.setChecked(False)
        self.receive_asc_checkbox.setAutoExclusive(True)
        self.receive_hex_checkbox.setAutoExclusive(True)
        receive_hex_ascii_layout.addWidget(self.receive_hex_checkbox)
        receive_hex_ascii_layout.addWidget(self.receive_asc_checkbox)
        receive_group_box.setLayout(receive_hex_ascii_layout)

        # send
        send_group_box = QGroupBox("发送")
        send_formlayout = QFormLayout()
        send_layout = QVBoxLayout()
        self.send_code_combox = QComboBox()
        self.send_code_combox.addItems(['ASCII', 'HEX'])
        self.times_send_chebox = QCheckBox("启动定时发送")
        self.times_edit = QLineEdit()
        self.times_edit.setText(self.config.get('Send Config', 'send times'))
        self.send_interval_edit = QLineEdit()
        self.send_interval_edit.setText(
            self.config.get('Send Config', 'send interval'))
        self.send_area = QTextEdit()
        self.send_area.setText(self.config.get('Send Config', 'send data'))
        self.send_button = QPushButton("发送")
        send_formlayout.addRow(QLabel("字符编码"), self.send_code_combox)
        send_formlayout.addRow(QLabel("发送次数:"), self.times_edit)
        send_formlayout.addRow(QLabel("发送间隔:"), self.send_interval_edit)
        send_layout.addWidget(self.times_send_chebox)
        send_layout.addLayout(send_formlayout)
        send_layout.addWidget(self.send_area)
        send_layout.addWidget(self.send_button)
        send_group_box.setLayout(send_layout)

        # processing
        data_process_group_box = QGroupBox('数据处理')
        data_process_layout = QHBoxLayout()
        self.transform_data_checkbox = QCheckBox('转换')
        # todo:后面判断参数的时候可以通过ObjectName判断发送者
        # self.transform_data_checkbox.setObjectName('transform_data_checkbox')
        data_process_layout.addWidget(self.transform_data_checkbox)
        data_process_group_box.setLayout(data_process_layout)
        # collection

        self.left_layout.addWidget(group_box)
        self.left_layout.addWidget(receive_group_box)
        self.left_layout.addWidget(send_group_box)
        self.left_layout.addWidget(data_process_group_box)
        self.left_layout.addStretch()
        self.setting_widget.setLayout(self.left_layout)
        pass

    def init_show_widget(self):
        show_button_layout = QGridLayout()
        show_info_layout = QHBoxLayout()
        self.decoding_combobox = QComboBox()
        self.decoding_combobox.addItems(['ASCII', 'GB2312'])
        self.decoding_combobox.setEditable(False)
        self.heart_led_show = QLCDNumber()
        self.receive_area = QTextEdit()
        line_plot_area = pg.GraphicsLayoutWidget()
        self.plot_1 = line_plot_area.addPlot(title='Original Signal')
        self.plot_1.hideAxis('left')

        line_plot_area.nextRow()
        self.plot_2 = line_plot_area.addPlot(title='Processed Signal')
        line_plot_area.removeItem(self.plot_2)
        self.receive_area.setTabletTracking(True)

        self.clear_button = QPushButton(
            self.config.get('Button Setting', 'Clear'))

        show_button_layout.addWidget(self.clear_button, 0, 0)
        show_info_layout.addWidget(self.decoding_combobox)
        show_info_layout.addStretch()
        show_info_layout.addWidget(QLabel('Func:'))
        show_info_layout.addWidget(self.heart_led_show)

        self.show_widget.setLayout(self.show_layout)
        self.show_layout.addWidget(self.receive_area)
        self.show_layout.addWidget(line_plot_area)
        self.show_layout.addLayout(show_info_layout)
        self.show_layout.addLayout(show_button_layout)
        pass

    # detail information show and seq setting
    def init_heart_function_widget(self):
        function_layout = QVBoxLayout()
        # Data Format parameter
        data_format_group = QGroupBox('Data Format')
        data_format_layout = QFormLayout()
        self.bytes_of_stop_point = QLineEdit()
        self.bytes_of_start_point = QLineEdit()
        self.bytes_of_total_edit = QLineEdit()
        self.bytes_of_start_point.setText(
            self.config.get('Data Format', 'Data Begin'))
        self.bytes_of_stop_point.setText(
            self.config.get('Data Format', 'Data Stop'))
        self.bytes_of_total_edit.setText(
            self.config.get('Data Format', 'Total Len'))
        data_format_layout.addRow(QLabel('Data Begin:'),
                                  self.bytes_of_start_point)
        data_format_layout.addRow(QLabel('Data Stop'),
                                  self.bytes_of_stop_point)
        data_format_layout.addRow(QLabel('Total Bytes:'),
                                  self.bytes_of_total_edit)

        data_format_group.setLayout(data_format_layout)
        # Heart Rate Parameter
        heart_parameter = QGroupBox('Heart Rate Parameter')
        heart_parameter_layout = QFormLayout()
        self.fs_parameter = QLineEdit()
        self.fs_parameter.setValidator(QIntValidator(0, 96000))
        self.fs_parameter.setPlaceholderText('0~96000')
        self.fs_parameter.setText(self.config.get('Heart Rate', 'Fs'))
        self.threshold_parameter = QLineEdit()
        self.threshold_parameter.setValidator(QIntValidator(0, 96000))
        self.threshold_parameter.setPlaceholderText('0~96000')
        self.threshold_parameter.setText(
            self.config.get('Heart Rate', 'Threshold'))
        self.scalar_parameter = QLineEdit()
        self.scalar_parameter.setValidator(QIntValidator(1, 20))
        self.scalar_parameter.setPlaceholderText('1~20')
        self.scalar_parameter.setText(self.config.get('Heart Rate', 'Scalar'))
        self.smooth_level = QLineEdit()
        self.smooth_level.setValidator(QIntValidator(1, 20))
        self.smooth_level.setPlaceholderText('2~6')
        self.smooth_level.setText(self.config.get('Heart Rate',
                                                  'Smooth Level'))
        heart_parameter_layout.addRow(QLabel("FS:"), self.fs_parameter)
        heart_parameter_layout.addRow(QLabel('Threshold:'),
                                      self.threshold_parameter)
        heart_parameter_layout.addRow(QLabel('Scalar:'), self.scalar_parameter)
        heart_parameter_layout.addRow(QLabel('Smooth Level:'),
                                      self.smooth_level)
        heart_parameter.setLayout(heart_parameter_layout)
        # Heart Function parameter
        heart_function_group = QGroupBox("Heart rate cal")
        heart_function_layout = QGridLayout()
        self.heart_rate_debug_button = QPushButton("Debug")
        self.save_data_button = QPushButton("Save")
        self.heart_rate_release = QRadioButton("Release")
        self.smooth_switch = QCheckBox("Smooth")
        self.begin_cal_index_edit = QLineEdit()
        self.begin_cal_index_edit.setValidator(QIntValidator())
        self.end_cal_index_edit = QLineEdit()
        self.end_cal_index_edit.setValidator(QIntValidator())

        heart_function_layout.addWidget(self.heart_rate_debug_button, 0, 0)
        heart_function_layout.addWidget(self.save_data_button, 0, 1)
        heart_function_layout.addWidget(self.heart_rate_release, 1, 0)
        heart_function_layout.addWidget(self.smooth_switch, 1, 1)
        heart_function_layout.addWidget(self.begin_cal_index_edit, 2, 0)
        heart_function_layout.addWidget(self.end_cal_index_edit, 2, 1)

        heart_function_group.setLayout(heart_function_layout)

        function_layout.addWidget(data_format_group)
        function_layout.addWidget(heart_parameter)
        function_layout.addWidget(heart_function_group)
        self.heart_function_widget.setLayout(function_layout)
        function_layout.addStretch()
        pass

    def init_statue_bar(self):
        # todo: 可以增加状态闪烁的功能 使用QTime
        self.status_bar_status = QLabel()
        self.status_bar_status.setMinimumWidth(80)
        self.status_bar_status.setText(
            "<font color=%s>%s</font>" %
            ("#008200", self.config.get('Status Bar', 'OK')))
        self.status_bar_recieve_count = QLabel(r'Receive ' + r'Bytes:' + '0')
        self.statusBar().addWidget(self.status_bar_status)
        self.statusBar().addWidget(self.status_bar_recieve_count, 2)
        # todo: 加入每次串口打开使用时间
        pass
    def __init__(self, parent: 'ElectrumWindow', config: 'SimpleConfig'):
        WindowModalDialog.__init__(self, parent, _('Preferences'))
        self.config = config
        self.window = parent
        self.need_restart = False
        self.fx = self.window.fx
        self.wallet = self.window.wallet

        vbox = QVBoxLayout()
        tabs = QTabWidget()
        gui_widgets = []
        tx_widgets = []
        oa_widgets = []

        # language
        lang_help = _(
            'Select which language is used in the GUI (after restart).')
        lang_label = HelpLabel(_('Language') + ':', lang_help)
        lang_combo = QComboBox()
        lang_combo.addItems(list(languages.values()))
        lang_keys = list(languages.keys())
        lang_cur_setting = self.config.get("language", '')
        try:
            index = lang_keys.index(lang_cur_setting)
        except ValueError:  # not in list
            index = 0
        lang_combo.setCurrentIndex(index)
        if not self.config.is_modifiable('language'):
            for w in [lang_combo, lang_label]:
                w.setEnabled(False)

        def on_lang(x):
            lang_request = list(languages.keys())[lang_combo.currentIndex()]
            if lang_request != self.config.get('language'):
                self.config.set_key("language", lang_request, True)
                self.need_restart = True

        lang_combo.currentIndexChanged.connect(on_lang)
        gui_widgets.append((lang_label, lang_combo))

        nz_help = _(
            'Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"'
        )
        nz_label = HelpLabel(_('Zeros after decimal point') + ':', nz_help)
        nz = QSpinBox()
        nz.setMinimum(0)
        nz.setMaximum(self.config.decimal_point)
        nz.setValue(self.config.num_zeros)
        if not self.config.is_modifiable('num_zeros'):
            for w in [nz, nz_label]:
                w.setEnabled(False)

        def on_nz():
            value = nz.value()
            if self.config.num_zeros != value:
                self.config.num_zeros = value
                self.config.set_key('num_zeros', value, True)
                self.window.need_update.set()

        nz.valueChanged.connect(on_nz)
        gui_widgets.append((nz_label, nz))

        #use_rbf = bool(self.config.get('use_rbf', True))
        #use_rbf_cb = QCheckBox(_('Use Replace-By-Fee'))
        #use_rbf_cb.setChecked(use_rbf)
        #use_rbf_cb.setToolTip(
        #    _('If you check this box, your transactions will be marked as non-final,') + '\n' + \
        #    _('and you will have the possibility, while they are unconfirmed, to replace them with transactions that pay higher fees.') + '\n' + \
        #    _('Note that some merchants do not accept non-final transactions until they are confirmed.'))
        #def on_use_rbf(x):
        #    self.config.set_key('use_rbf', bool(x))
        #    batch_rbf_cb.setEnabled(bool(x))
        #use_rbf_cb.stateChanged.connect(on_use_rbf)
        #tx_widgets.append((use_rbf_cb, None))

        #batch_rbf_cb = QCheckBox(_('Batch RBF transactions'))
        #batch_rbf_cb.setChecked(bool(self.config.get('batch_rbf', False)))
        #batch_rbf_cb.setEnabled(use_rbf)
        #batch_rbf_cb.setToolTip(
        #    _('If you check this box, your unconfirmed transactions will be consolidated into a single transaction.') + '\n' + \
        #    _('This will save fees.'))
        #def on_batch_rbf(x):
        #    self.config.set_key('batch_rbf', bool(x))
        #batch_rbf_cb.stateChanged.connect(on_batch_rbf)
        #tx_widgets.append((batch_rbf_cb, None))

        # lightning
        lightning_widgets = []

        help_recov = _(messages.MSG_RECOVERABLE_CHANNELS)
        recov_cb = QCheckBox(_("Create recoverable channels"))
        enable_toggle_use_recoverable_channels = bool(
            self.wallet.lnworker
            and self.wallet.lnworker.can_have_recoverable_channels())
        recov_cb.setEnabled(enable_toggle_use_recoverable_channels)
        recov_cb.setToolTip(messages.to_rtf(help_recov))
        recov_cb.setChecked(
            bool(self.config.get('use_recoverable_channels', True))
            and enable_toggle_use_recoverable_channels)

        def on_recov_checked(x):
            self.config.set_key('use_recoverable_channels', bool(x))

        recov_cb.stateChanged.connect(on_recov_checked)
        lightning_widgets.append((recov_cb, None))

        help_trampoline = _(messages.MSG_HELP_TRAMPOLINE)
        trampoline_cb = QCheckBox(_("Use trampoline routing (disable gossip)"))
        trampoline_cb.setToolTip(messages.to_rtf(help_trampoline))
        trampoline_cb.setChecked(
            not bool(self.config.get('use_gossip', False)))

        def on_trampoline_checked(use_trampoline):
            use_gossip = not bool(use_trampoline)
            self.config.set_key('use_gossip', use_gossip)
            if use_gossip:
                self.window.network.start_gossip()
            else:
                self.window.network.run_from_another_thread(
                    self.window.network.stop_gossip())
            util.trigger_callback('ln_gossip_sync_progress')
            # FIXME: update all wallet windows
            util.trigger_callback('channels_updated', self.wallet)

        trampoline_cb.stateChanged.connect(on_trampoline_checked)
        lightning_widgets.append((trampoline_cb, None))

        help_remote_wt = ' '.join([
            _("A watchtower is a daemon that watches your channels and prevents the other party from stealing funds by broadcasting an old state."
              ),
            _("If you have private a watchtower, enter its URL here."),
            _("Check our online documentation if you want to configure Electrum as a watchtower."
              ),
        ])
        remote_wt_cb = QCheckBox(_("Use a remote watchtower"))
        remote_wt_cb.setToolTip('<p>' + help_remote_wt + '</p>')
        remote_wt_cb.setChecked(bool(self.config.get('use_watchtower', False)))

        def on_remote_wt_checked(x):
            self.config.set_key('use_watchtower', bool(x))
            self.watchtower_url_e.setEnabled(bool(x))

        remote_wt_cb.stateChanged.connect(on_remote_wt_checked)
        watchtower_url = self.config.get('watchtower_url')
        self.watchtower_url_e = QLineEdit(watchtower_url)
        self.watchtower_url_e.setEnabled(
            self.config.get('use_watchtower', False))

        def on_wt_url():
            url = self.watchtower_url_e.text() or None
            watchtower_url = self.config.set_key('watchtower_url', url)

        self.watchtower_url_e.editingFinished.connect(on_wt_url)
        lightning_widgets.append((remote_wt_cb, self.watchtower_url_e))

        msg = _('OpenAlias record, used to receive coins and to sign payment requests.') + '\n\n'\
              + _('The following alias providers are available:') + '\n'\
              + '\n'.join(['https://cryptoname.co/', 'http://xmr.link']) + '\n\n'\
              + 'For more information, see https://openalias.org'
        alias_label = HelpLabel(_('OpenAlias') + ':', msg)
        alias = self.config.get('alias', '')
        self.alias_e = QLineEdit(alias)
        self.set_alias_color()
        self.alias_e.editingFinished.connect(self.on_alias_edit)
        oa_widgets.append((alias_label, self.alias_e))

        msat_cb = QCheckBox(_("Show amounts with msat precision"))
        msat_cb.setChecked(
            bool(self.config.get('amt_precision_post_satoshi', False)))

        def on_msat_checked(v):
            prec = 3 if v == Qt.Checked else 0
            if self.config.amt_precision_post_satoshi != prec:
                self.config.amt_precision_post_satoshi = prec
                self.config.set_key('amt_precision_post_satoshi', prec)
                self.window.need_update.set()

        msat_cb.stateChanged.connect(on_msat_checked)
        lightning_widgets.append((msat_cb, None))

        # units
        units = base_units_list
        msg = (_(
            'Base unit of your wallet.'
        ) + '\n1 BTC = 1000 mBTC. 1 mBTC = 1000 bits. 1 bit = 100 sat.\n' + _(
            'This setting affects the Send tab, and all balance related fields.'
        ))
        unit_label = HelpLabel(_('Base unit') + ':', msg)
        unit_combo = QComboBox()
        unit_combo.addItems(units)
        unit_combo.setCurrentIndex(units.index(self.window.base_unit()))

        def on_unit(x, nz):
            unit_result = units[unit_combo.currentIndex()]
            if self.window.base_unit() == unit_result:
                return
            edits = self.window.amount_e, self.window.receive_amount_e
            amounts = [edit.get_amount() for edit in edits]
            self.config.set_base_unit(unit_result)
            nz.setMaximum(self.config.decimal_point)
            self.window.update_tabs()
            for edit, amount in zip(edits, amounts):
                edit.setAmount(amount)
            self.window.update_status()

        unit_combo.currentIndexChanged.connect(lambda x: on_unit(x, nz))
        gui_widgets.append((unit_label, unit_combo))

        thousandsep_cb = QCheckBox(
            _("Add thousand separators to bitcoin amounts"))
        thousandsep_cb.setChecked(
            bool(self.config.get('amt_add_thousands_sep', False)))

        def on_set_thousandsep(v):
            checked = v == Qt.Checked
            if self.config.amt_add_thousands_sep != checked:
                self.config.amt_add_thousands_sep = checked
                self.config.set_key('amt_add_thousands_sep', checked)
                self.window.need_update.set()

        thousandsep_cb.stateChanged.connect(on_set_thousandsep)
        gui_widgets.append((thousandsep_cb, None))

        qr_combo = QComboBox()
        qr_combo.addItem("Default", "default")
        msg = (_("For scanning QR codes.") + "\n" +
               _("Install the zbar package to enable this."))
        qr_label = HelpLabel(_('Video Device') + ':', msg)
        from .qrreader import find_system_cameras
        system_cameras = find_system_cameras()
        for cam_desc, cam_path in system_cameras.items():
            qr_combo.addItem(cam_desc, cam_path)
        index = qr_combo.findData(self.config.get("video_device"))
        qr_combo.setCurrentIndex(index)
        on_video_device = lambda x: self.config.set_key(
            "video_device", qr_combo.itemData(x), True)
        qr_combo.currentIndexChanged.connect(on_video_device)
        gui_widgets.append((qr_label, qr_combo))

        colortheme_combo = QComboBox()
        colortheme_combo.addItem(_('Light'), 'default')
        colortheme_combo.addItem(_('Dark'), 'dark')
        index = colortheme_combo.findData(
            self.config.get('qt_gui_color_theme', 'default'))
        colortheme_combo.setCurrentIndex(index)
        colortheme_label = QLabel(_('Color theme') + ':')

        def on_colortheme(x):
            self.config.set_key('qt_gui_color_theme',
                                colortheme_combo.itemData(x), True)
            #self.window.gui_object.reload_app_stylesheet()
            self.need_restart = True

        colortheme_combo.currentIndexChanged.connect(on_colortheme)
        gui_widgets.append((colortheme_label, colortheme_combo))

        updatecheck_cb = QCheckBox(
            _("Automatically check for software updates"))
        updatecheck_cb.setChecked(bool(self.config.get('check_updates',
                                                       False)))

        def on_set_updatecheck(v):
            self.config.set_key('check_updates', v == Qt.Checked, save=True)

        updatecheck_cb.stateChanged.connect(on_set_updatecheck)
        gui_widgets.append((updatecheck_cb, None))

        filelogging_cb = QCheckBox(_("Write logs to file"))
        filelogging_cb.setChecked(bool(self.config.get('log_to_file', False)))

        def on_set_filelogging(v):
            self.config.set_key('log_to_file', v == Qt.Checked, save=True)
            self.need_restart = True

        filelogging_cb.stateChanged.connect(on_set_filelogging)
        filelogging_cb.setToolTip(
            _('Debug logs can be persisted to disk. These are useful for troubleshooting.'
              ))
        gui_widgets.append((filelogging_cb, None))

        preview_cb = QCheckBox(_('Advanced preview'))
        preview_cb.setChecked(bool(self.config.get('advanced_preview', False)))
        preview_cb.setToolTip(
            _("Open advanced transaction preview dialog when 'Pay' is clicked."
              ))

        def on_preview(x):
            self.config.set_key('advanced_preview', x == Qt.Checked)

        preview_cb.stateChanged.connect(on_preview)
        tx_widgets.append((preview_cb, None))

        usechange_cb = QCheckBox(_('Use change addresses'))
        usechange_cb.setChecked(self.window.wallet.use_change)
        if not self.config.is_modifiable('use_change'):
            usechange_cb.setEnabled(False)

        def on_usechange(x):
            usechange_result = x == Qt.Checked
            if self.window.wallet.use_change != usechange_result:
                self.window.wallet.use_change = usechange_result
                self.window.wallet.db.put('use_change',
                                          self.window.wallet.use_change)
                multiple_cb.setEnabled(self.window.wallet.use_change)

        usechange_cb.stateChanged.connect(on_usechange)
        usechange_cb.setToolTip(
            _('Using change addresses makes it more difficult for other people to track your transactions.'
              ))
        tx_widgets.append((usechange_cb, None))

        def on_multiple(x):
            multiple = x == Qt.Checked
            if self.wallet.multiple_change != multiple:
                self.wallet.multiple_change = multiple
                self.wallet.db.put('multiple_change', multiple)

        multiple_change = self.wallet.multiple_change
        multiple_cb = QCheckBox(_('Use multiple change addresses'))
        multiple_cb.setEnabled(self.wallet.use_change)
        multiple_cb.setToolTip('\n'.join([
            _('In some cases, use up to 3 change addresses in order to break '
              'up large coin amounts and obfuscate the recipient address.'),
            _('This may result in higher transactions fees.')
        ]))
        multiple_cb.setChecked(multiple_change)
        multiple_cb.stateChanged.connect(on_multiple)
        tx_widgets.append((multiple_cb, None))

        def fmt_docs(key, klass):
            lines = [ln.lstrip(" ") for ln in klass.__doc__.split("\n")]
            return '\n'.join([key, "", " ".join(lines)])

        choosers = sorted(coinchooser.COIN_CHOOSERS.keys())
        if len(choosers) > 1:
            chooser_name = coinchooser.get_name(self.config)
            msg = _(
                'Choose coin (UTXO) selection method.  The following are available:\n\n'
            )
            msg += '\n\n'.join(
                fmt_docs(*item) for item in coinchooser.COIN_CHOOSERS.items())
            chooser_label = HelpLabel(_('Coin selection') + ':', msg)
            chooser_combo = QComboBox()
            chooser_combo.addItems(choosers)
            i = choosers.index(chooser_name) if chooser_name in choosers else 0
            chooser_combo.setCurrentIndex(i)

            def on_chooser(x):
                chooser_name = choosers[chooser_combo.currentIndex()]
                self.config.set_key('coin_chooser', chooser_name)

            chooser_combo.currentIndexChanged.connect(on_chooser)
            tx_widgets.append((chooser_label, chooser_combo))

        def on_unconf(x):
            self.config.set_key('confirmed_only', bool(x))

        conf_only = bool(self.config.get('confirmed_only', False))
        unconf_cb = QCheckBox(_('Spend only confirmed coins'))
        unconf_cb.setToolTip(_('Spend only confirmed inputs.'))
        unconf_cb.setChecked(conf_only)
        unconf_cb.stateChanged.connect(on_unconf)
        tx_widgets.append((unconf_cb, None))

        def on_outrounding(x):
            self.config.set_key('coin_chooser_output_rounding', bool(x))

        enable_outrounding = bool(
            self.config.get('coin_chooser_output_rounding', True))
        outrounding_cb = QCheckBox(_('Enable output value rounding'))
        outrounding_cb.setToolTip(
            _('Set the value of the change output so that it has similar precision to the other outputs.'
              ) + '\n' + _('This might improve your privacy somewhat.') +
            '\n' +
            _('If enabled, at most 100 satoshis might be lost due to this, per transaction.'
              ))
        outrounding_cb.setChecked(enable_outrounding)
        outrounding_cb.stateChanged.connect(on_outrounding)
        tx_widgets.append((outrounding_cb, None))

        block_explorers = sorted(util.block_explorer_info().keys())
        BLOCK_EX_CUSTOM_ITEM = _("Custom URL")
        if BLOCK_EX_CUSTOM_ITEM in block_explorers:  # malicious translation?
            block_explorers.remove(BLOCK_EX_CUSTOM_ITEM)
        block_explorers.append(BLOCK_EX_CUSTOM_ITEM)
        msg = _(
            'Choose which online block explorer to use for functions that open a web browser'
        )
        block_ex_label = HelpLabel(_('Online Block Explorer') + ':', msg)
        block_ex_combo = QComboBox()
        block_ex_custom_e = QLineEdit(
            str(self.config.get('block_explorer_custom') or ''))
        block_ex_combo.addItems(block_explorers)
        block_ex_combo.setCurrentIndex(
            block_ex_combo.findText(
                util.block_explorer(self.config) or BLOCK_EX_CUSTOM_ITEM))

        def showhide_block_ex_custom_e():
            block_ex_custom_e.setVisible(
                block_ex_combo.currentText() == BLOCK_EX_CUSTOM_ITEM)

        showhide_block_ex_custom_e()

        def on_be_combo(x):
            if block_ex_combo.currentText() == BLOCK_EX_CUSTOM_ITEM:
                on_be_edit()
            else:
                be_result = block_explorers[block_ex_combo.currentIndex()]
                self.config.set_key('block_explorer_custom', None, False)
                self.config.set_key('block_explorer', be_result, True)
            showhide_block_ex_custom_e()

        block_ex_combo.currentIndexChanged.connect(on_be_combo)

        def on_be_edit():
            val = block_ex_custom_e.text()
            try:
                val = ast.literal_eval(val)  # to also accept tuples
            except:
                pass
            self.config.set_key('block_explorer_custom', val)

        block_ex_custom_e.editingFinished.connect(on_be_edit)
        block_ex_hbox = QHBoxLayout()
        block_ex_hbox.setContentsMargins(0, 0, 0, 0)
        block_ex_hbox.setSpacing(0)
        block_ex_hbox.addWidget(block_ex_combo)
        block_ex_hbox.addWidget(block_ex_custom_e)
        block_ex_hbox_w = QWidget()
        block_ex_hbox_w.setLayout(block_ex_hbox)
        tx_widgets.append((block_ex_label, block_ex_hbox_w))

        # Fiat Currency
        hist_checkbox = QCheckBox()
        hist_capgains_checkbox = QCheckBox()
        fiat_address_checkbox = QCheckBox()
        ccy_combo = QComboBox()
        ex_combo = QComboBox()

        def update_currencies():
            if not self.window.fx: return
            currencies = sorted(
                self.fx.get_currencies(self.fx.get_history_config()))
            ccy_combo.clear()
            ccy_combo.addItems([_('None')] + currencies)
            if self.fx.is_enabled():
                ccy_combo.setCurrentIndex(
                    ccy_combo.findText(self.fx.get_currency()))

        def update_history_cb():
            if not self.fx: return
            hist_checkbox.setChecked(self.fx.get_history_config())
            hist_checkbox.setEnabled(self.fx.is_enabled())

        def update_fiat_address_cb():
            if not self.fx: return
            fiat_address_checkbox.setChecked(self.fx.get_fiat_address_config())

        def update_history_capgains_cb():
            if not self.fx: return
            hist_capgains_checkbox.setChecked(
                self.fx.get_history_capital_gains_config())
            hist_capgains_checkbox.setEnabled(hist_checkbox.isChecked())

        def update_exchanges():
            if not self.fx: return
            b = self.fx.is_enabled()
            ex_combo.setEnabled(b)
            if b:
                h = self.fx.get_history_config()
                c = self.fx.get_currency()
                exchanges = self.fx.get_exchanges_by_ccy(c, h)
            else:
                exchanges = self.fx.get_exchanges_by_ccy('USD', False)
            ex_combo.blockSignals(True)
            ex_combo.clear()
            ex_combo.addItems(sorted(exchanges))
            ex_combo.setCurrentIndex(
                ex_combo.findText(self.fx.config_exchange()))
            ex_combo.blockSignals(False)

        def on_currency(hh):
            if not self.fx: return
            b = bool(ccy_combo.currentIndex())
            ccy = str(ccy_combo.currentText()) if b else None
            self.fx.set_enabled(b)
            if b and ccy != self.fx.ccy:
                self.fx.set_currency(ccy)
            update_history_cb()
            update_exchanges()
            self.window.update_fiat()

        def on_exchange(idx):
            exchange = str(ex_combo.currentText())
            if self.fx and self.fx.is_enabled(
            ) and exchange and exchange != self.fx.exchange.name():
                self.fx.set_exchange(exchange)

        def on_history(checked):
            if not self.fx: return
            self.fx.set_history_config(checked)
            update_exchanges()
            self.window.history_model.refresh('on_history')
            if self.fx.is_enabled() and checked:
                self.fx.trigger_update()
            update_history_capgains_cb()

        def on_history_capgains(checked):
            if not self.fx: return
            self.fx.set_history_capital_gains_config(checked)
            self.window.history_model.refresh('on_history_capgains')

        def on_fiat_address(checked):
            if not self.fx: return
            self.fx.set_fiat_address_config(checked)
            self.window.address_list.refresh_headers()
            self.window.address_list.update()

        update_currencies()
        update_history_cb()
        update_history_capgains_cb()
        update_fiat_address_cb()
        update_exchanges()
        ccy_combo.currentIndexChanged.connect(on_currency)
        hist_checkbox.stateChanged.connect(on_history)
        hist_capgains_checkbox.stateChanged.connect(on_history_capgains)
        fiat_address_checkbox.stateChanged.connect(on_fiat_address)
        ex_combo.currentIndexChanged.connect(on_exchange)

        fiat_widgets = []
        fiat_widgets.append((QLabel(_('Fiat currency')), ccy_combo))
        fiat_widgets.append((QLabel(_('Source')), ex_combo))
        fiat_widgets.append((QLabel(_('Show history rates')), hist_checkbox))
        fiat_widgets.append((QLabel(_('Show capital gains in history')),
                             hist_capgains_checkbox))
        fiat_widgets.append((QLabel(_('Show Fiat balance for addresses')),
                             fiat_address_checkbox))

        tabs_info = [
            (gui_widgets, _('General')),
            (tx_widgets, _('Transactions')),
            (lightning_widgets, _('Lightning')),
            (fiat_widgets, _('Fiat')),
            (oa_widgets, _('OpenAlias')),
        ]
        for widgets, name in tabs_info:
            tab = QWidget()
            tab_vbox = QVBoxLayout(tab)
            grid = QGridLayout()
            for a, b in widgets:
                i = grid.rowCount()
                if b:
                    if a:
                        grid.addWidget(a, i, 0)
                    grid.addWidget(b, i, 1)
                else:
                    grid.addWidget(a, i, 0, 1, 2)
            tab_vbox.addLayout(grid)
            tab_vbox.addStretch(1)
            tabs.addTab(tab, name)

        vbox.addWidget(tabs)
        vbox.addStretch(1)
        vbox.addLayout(Buttons(CloseButton(self)))
        self.setLayout(vbox)
Exemple #53
0
class HistoryList(MyTreeView, AcceptFileDragDrop):
    filter_columns = [
        HistoryColumns.STATUS, HistoryColumns.DESCRIPTION,
        HistoryColumns.AMOUNT, HistoryColumns.TXID
    ]

    def tx_item_from_proxy_row(self, proxy_row):
        hm_idx = self.model().mapToSource(self.model().index(proxy_row, 0))
        return hm_idx.internalPointer().get_data()

    def should_hide(self, proxy_row):
        if self.start_timestamp and self.end_timestamp:
            tx_item = self.tx_item_from_proxy_row(proxy_row)
            date = tx_item['date']
            if date:
                in_interval = self.start_timestamp <= date <= self.end_timestamp
                if not in_interval:
                    return True
            return False

    def __init__(self, parent, model: HistoryModel):
        super().__init__(parent,
                         self.create_menu,
                         stretch_column=HistoryColumns.DESCRIPTION)
        self.config = parent.config
        self.hm = model
        self.proxy = HistorySortModel(self)
        self.proxy.setSourceModel(model)
        self.setModel(self.proxy)
        AcceptFileDragDrop.__init__(self, ".txn")
        self.setSortingEnabled(True)
        self.start_timestamp = None
        self.end_timestamp = None
        self.years = []
        self.create_toolbar_buttons()
        self.wallet = self.parent.wallet  # type: Abstract_Wallet
        self.sortByColumn(HistoryColumns.STATUS, Qt.AscendingOrder)
        self.editable_columns |= {HistoryColumns.FIAT_VALUE}
        self.setRootIsDecorated(True)
        self.header().setStretchLastSection(False)
        for col in HistoryColumns:
            sm = QHeaderView.Stretch if col == self.stretch_column else QHeaderView.ResizeToContents
            self.header().setSectionResizeMode(col, sm)

    def update(self):
        self.hm.refresh('HistoryList.update()')

    def format_date(self, d):
        return str(datetime.date(d.year, d.month, d.day)) if d else _('None')

    def on_combo(self, x):
        s = self.period_combo.itemText(x)
        x = s == _('Custom')
        self.start_button.setEnabled(x)
        self.end_button.setEnabled(x)
        if s == _('All'):
            self.start_timestamp = None
            self.end_timestamp = None
            self.start_button.setText("-")
            self.end_button.setText("-")
        else:
            try:
                year = int(s)
            except:
                return
            self.start_timestamp = start_date = datetime.datetime(year, 1, 1)
            self.end_timestamp = end_date = datetime.datetime(year + 1, 1, 1)
            self.start_button.setText(
                _('From') + ' ' + self.format_date(start_date))
            self.end_button.setText(_('To') + ' ' + self.format_date(end_date))
        self.hide_rows()

    def create_toolbar_buttons(self):
        self.period_combo = QComboBox()
        self.start_button = QPushButton('-')
        self.start_button.pressed.connect(self.select_start_date)
        self.start_button.setEnabled(False)
        self.end_button = QPushButton('-')
        self.end_button.pressed.connect(self.select_end_date)
        self.end_button.setEnabled(False)
        self.period_combo.addItems([_('All'), _('Custom')])
        self.period_combo.activated.connect(self.on_combo)

    def get_toolbar_buttons(self):
        return self.period_combo, self.start_button, self.end_button

    def on_hide_toolbar(self):
        self.start_timestamp = None
        self.end_timestamp = None
        self.hide_rows()

    def save_toolbar_state(self, state, config):
        config.set_key('show_toolbar_history', state)

    def select_start_date(self):
        self.start_timestamp = self.select_date(self.start_button)
        self.hide_rows()

    def select_end_date(self):
        self.end_timestamp = self.select_date(self.end_button)
        self.hide_rows()

    def select_date(self, button):
        d = WindowModalDialog(self, _("Select date"))
        d.setMinimumSize(600, 150)
        d.date = None
        vbox = QVBoxLayout()

        def on_date(date):
            d.date = date

        cal = QCalendarWidget()
        cal.setGridVisible(True)
        cal.clicked[QDate].connect(on_date)
        vbox.addWidget(cal)
        vbox.addLayout(Buttons(OkButton(d), CancelButton(d)))
        d.setLayout(vbox)
        if d.exec_():
            if d.date is None:
                return None
            date = d.date.toPyDate()
            button.setText(self.format_date(date))
            return datetime.datetime(date.year, date.month, date.day)

    def show_summary(self):
        fx = self.parent.fx
        show_fiat = fx and fx.is_enabled() and fx.get_history_config()
        if not show_fiat:
            self.parent.show_message(
                _("Enable fiat exchange rate with history."))
            return
        h = self.wallet.get_detailed_history(fx=fx)
        summary = h['summary']
        if not summary:
            self.parent.show_message(_("Nothing to summarize."))
            return
        start = summary['begin']
        end = summary['end']
        flow = summary['flow']
        start_date = start.get('date')
        end_date = end.get('date')
        format_amount = lambda x: self.parent.format_amount(
            x.value) + ' ' + self.parent.base_unit()
        format_fiat = lambda x: str(x) + ' ' + self.parent.fx.ccy

        d = WindowModalDialog(self, _("Summary"))
        d.setMinimumSize(600, 150)
        vbox = QVBoxLayout()
        msg = messages.to_rtf(messages.MSG_CAPITAL_GAINS)
        vbox.addWidget(WWLabel(msg))
        grid = QGridLayout()
        grid.addWidget(QLabel(_("Begin")), 0, 1)
        grid.addWidget(QLabel(_("End")), 0, 2)
        #
        grid.addWidget(QLabel(_("Date")), 1, 0)
        grid.addWidget(QLabel(self.format_date(start_date)), 1, 1)
        grid.addWidget(QLabel(self.format_date(end_date)), 1, 2)
        #
        grid.addWidget(QLabel(_("BTC balance")), 2, 0)
        grid.addWidget(QLabel(format_amount(start['BTC_balance'])), 2, 1)
        grid.addWidget(QLabel(format_amount(end['BTC_balance'])), 2, 2)
        #
        grid.addWidget(QLabel(_("BTC Fiat price")), 3, 0)
        grid.addWidget(QLabel(format_fiat(start.get('BTC_fiat_price'))), 3, 1)
        grid.addWidget(QLabel(format_fiat(end.get('BTC_fiat_price'))), 3, 2)
        #
        grid.addWidget(QLabel(_("Fiat balance")), 4, 0)
        grid.addWidget(QLabel(format_fiat(start.get('fiat_balance'))), 4, 1)
        grid.addWidget(QLabel(format_fiat(end.get('fiat_balance'))), 4, 2)
        #
        grid.addWidget(QLabel(_("Acquisition price")), 5, 0)
        grid.addWidget(QLabel(format_fiat(start.get('acquisition_price', ''))),
                       5, 1)
        grid.addWidget(QLabel(format_fiat(end.get('acquisition_price', ''))),
                       5, 2)
        #
        grid.addWidget(QLabel(_("Unrealized capital gains")), 6, 0)
        grid.addWidget(QLabel(format_fiat(start.get('unrealized_gains', ''))),
                       6, 1)
        grid.addWidget(QLabel(format_fiat(end.get('unrealized_gains', ''))), 6,
                       2)
        #
        grid2 = QGridLayout()
        grid2.addWidget(QLabel(_("BTC incoming")), 0, 0)
        grid2.addWidget(QLabel(format_amount(flow['BTC_incoming'])), 0, 1)
        grid2.addWidget(QLabel(_("Fiat incoming")), 1, 0)
        grid2.addWidget(QLabel(format_fiat(flow.get('fiat_incoming'))), 1, 1)
        grid2.addWidget(QLabel(_("BTC outgoing")), 2, 0)
        grid2.addWidget(QLabel(format_amount(flow['BTC_outgoing'])), 2, 1)
        grid2.addWidget(QLabel(_("Fiat outgoing")), 3, 0)
        grid2.addWidget(QLabel(format_fiat(flow.get('fiat_outgoing'))), 3, 1)
        #
        grid2.addWidget(QLabel(_("Realized capital gains")), 4, 0)
        grid2.addWidget(
            QLabel(format_fiat(flow.get('realized_capital_gains'))), 4, 1)
        vbox.addLayout(grid)
        vbox.addWidget(QLabel(_('Cash flow')))
        vbox.addLayout(grid2)
        vbox.addLayout(Buttons(CloseButton(d)))
        d.setLayout(vbox)
        d.exec_()

    def plot_history_dialog(self):
        if plot_history is None:
            self.parent.show_message(
                _("Can't plot history.") + '\n' +
                _("Perhaps some dependencies are missing...") +
                " (matplotlib?)")
            return
        try:
            plt = plot_history(list(self.hm.transactions.values()))
            plt.show()
        except NothingToPlotException as e:
            self.parent.show_message(str(e))

    def on_edited(self, index, user_role, text):
        index = self.model().mapToSource(index)
        tx_item = index.internalPointer().get_data()
        column = index.column()
        key = get_item_key(tx_item)
        if column == HistoryColumns.DESCRIPTION:
            if self.wallet.set_label(key, text):  #changed
                self.hm.update_label(index)
                self.parent.update_completions()
        elif column == HistoryColumns.FIAT_VALUE:
            self.wallet.set_fiat_value(key, self.parent.fx.ccy, text,
                                       self.parent.fx, tx_item['value'].value)
            value = tx_item['value'].value
            if value is not None:
                self.hm.update_fiat(index)
        else:
            assert False

    def mouseDoubleClickEvent(self, event: QMouseEvent):
        idx = self.indexAt(event.pos())
        if not idx.isValid():
            return
        tx_item = self.tx_item_from_proxy_row(idx.row())
        if self.hm.flags(self.model().mapToSource(idx)) & Qt.ItemIsEditable:
            super().mouseDoubleClickEvent(event)
        else:
            if tx_item.get('lightning'):
                if tx_item['type'] == 'payment':
                    self.parent.show_lightning_transaction(tx_item)
                return
            tx_hash = tx_item['txid']
            tx = self.wallet.db.get_transaction(tx_hash)
            if not tx:
                return
            self.show_transaction(tx_item, tx)

    def show_transaction(self, tx_item, tx):
        tx_hash = tx_item['txid']
        label = self.wallet.get_label_for_txid(
            tx_hash
        ) or None  # prefer 'None' if not defined (force tx dialog to hide Description field if missing)
        self.parent.show_transaction(tx, tx_desc=label)

    def add_copy_menu(self, menu, idx):
        cc = menu.addMenu(_("Copy"))
        for column in HistoryColumns:
            if self.isColumnHidden(column):
                continue
            column_title = self.hm.headerData(column, Qt.Horizontal,
                                              Qt.DisplayRole)
            idx2 = idx.sibling(idx.row(), column)
            column_data = (self.hm.data(idx2, Qt.DisplayRole).value()
                           or '').strip()
            cc.addAction(column_title,
                         lambda text=column_data, title=column_title: self.
                         place_text_on_clipboard(text, title=title))
        return cc

    def create_menu(self, position: QPoint):
        org_idx: QModelIndex = self.indexAt(position)
        idx = self.proxy.mapToSource(org_idx)
        if not idx.isValid():
            # can happen e.g. before list is populated for the first time
            return
        tx_item = idx.internalPointer().get_data()
        if tx_item.get('lightning') and tx_item['type'] == 'payment':
            menu = QMenu()
            menu.addAction(
                _("View Payment"),
                lambda: self.parent.show_lightning_transaction(tx_item))
            cc = self.add_copy_menu(menu, idx)
            cc.addAction(
                _("Payment Hash"),
                lambda: self.place_text_on_clipboard(tx_item['payment_hash'],
                                                     title="Payment Hash"))
            cc.addAction(
                _("Preimage"),
                lambda: self.place_text_on_clipboard(tx_item['preimage'],
                                                     title="Preimage"))
            key = tx_item['payment_hash']
            log = self.wallet.lnworker.logs.get(key)
            if log:
                menu.addAction(
                    _("View log"),
                    lambda: self.parent.invoice_list.show_log(key, log))
            menu.exec_(self.viewport().mapToGlobal(position))
            return
        tx_hash = tx_item['txid']
        if tx_item.get('lightning'):
            tx = self.wallet.lnworker.lnwatcher.db.get_transaction(tx_hash)
        else:
            tx = self.wallet.db.get_transaction(tx_hash)
        if not tx:
            return
        tx_URL = block_explorer_URL(self.config, 'tx', tx_hash)
        tx_details = self.wallet.get_tx_info(tx)
        is_unconfirmed = tx_details.tx_mined_status.height <= 0
        menu = QMenu()
        if tx_details.can_remove:
            menu.addAction(_("Remove"), lambda: self.remove_local_tx(tx_hash))
        cc = self.add_copy_menu(menu, idx)
        cc.addAction(
            _("Transaction ID"),
            lambda: self.place_text_on_clipboard(tx_hash, title="TXID"))
        for c in self.editable_columns:
            if self.isColumnHidden(c): continue
            label = self.hm.headerData(c, Qt.Horizontal, Qt.DisplayRole)
            # TODO use siblingAtColumn when min Qt version is >=5.11
            persistent = QPersistentModelIndex(
                org_idx.sibling(org_idx.row(), c))
            menu.addAction(_("Edit {}").format(label),
                           lambda p=persistent: self.edit(QModelIndex(p)))
        menu.addAction(_("View Transaction"),
                       lambda: self.show_transaction(tx_item, tx))
        channel_id = tx_item.get('channel_id')
        if channel_id:
            menu.addAction(
                _("View Channel"),
                lambda: self.parent.show_channel(bytes.fromhex(channel_id)))
        if is_unconfirmed and tx:
            if tx_details.can_bump:
                menu.addAction(_("Increase fee"),
                               lambda: self.parent.bump_fee_dialog(tx))
            else:
                if tx_details.can_cpfp:
                    menu.addAction(_("Child pays for parent"),
                                   lambda: self.parent.cpfp_dialog(tx))
            if tx_details.can_dscancel:
                menu.addAction(_("Cancel (double-spend)"),
                               lambda: self.parent.dscancel_dialog(tx))
        invoices = self.wallet.get_relevant_invoices_for_tx(tx)
        if len(invoices) == 1:
            menu.addAction(
                _("View invoice"),
                lambda inv=invoices[0]: self.parent.show_onchain_invoice(inv))
        elif len(invoices) > 1:
            menu_invs = menu.addMenu(_("Related invoices"))
            for inv in invoices:
                menu_invs.addAction(
                    _("View invoice"),
                    lambda inv=inv: self.parent.show_onchain_invoice(inv))
        if tx_URL:
            menu.addAction(_("View on block explorer"),
                           lambda: webopen(tx_URL))
        menu.exec_(self.viewport().mapToGlobal(position))

    def remove_local_tx(self, tx_hash: str):
        num_child_txs = len(self.wallet.get_depending_transactions(tx_hash))
        question = _("Are you sure you want to remove this transaction?")
        if num_child_txs > 0:
            question = (_(
                "Are you sure you want to remove this transaction and {} child transactions?"
            ).format(num_child_txs))
        if not self.parent.question(msg=question, title=_("Please confirm")):
            return
        self.wallet.remove_transaction(tx_hash)
        self.wallet.save_db()
        # need to update at least: history_list, utxo_list, address_list
        self.parent.need_update.set()

    def onFileAdded(self, fn):
        try:
            with open(fn) as f:
                tx = self.parent.tx_from_text(f.read())
        except IOError as e:
            self.parent.show_error(e)
            return
        if not tx:
            return
        self.parent.save_transaction_into_wallet(tx)

    def export_history_dialog(self):
        d = WindowModalDialog(self, _('Export History'))
        d.setMinimumSize(400, 200)
        vbox = QVBoxLayout(d)
        defaultname = os.path.expanduser('~/electrum-history.csv')
        select_msg = _('Select file to export your wallet transactions to')
        hbox, filename_e, csv_button = filename_field(self, self.config,
                                                      defaultname, select_msg)
        vbox.addLayout(hbox)
        vbox.addStretch(1)
        hbox = Buttons(CancelButton(d), OkButton(d, _('Export')))
        vbox.addLayout(hbox)
        #run_hook('export_history_dialog', self, hbox)
        self.update()
        if not d.exec_():
            return
        filename = filename_e.text()
        if not filename:
            return
        try:
            self.do_export_history(filename, csv_button.isChecked())
        except (IOError, os.error) as reason:
            export_error_label = _(
                "Electrum was unable to produce a transaction export.")
            self.parent.show_critical(export_error_label + "\n" + str(reason),
                                      title=_("Unable to export history"))
            return
        self.parent.show_message(
            _("Your wallet history has been successfully exported."))

    def do_export_history(self, file_name, is_csv):
        hist = self.wallet.get_detailed_history(fx=self.parent.fx)
        txns = hist['transactions']
        lines = []
        if is_csv:
            for item in txns:
                lines.append([
                    item['txid'],
                    item.get('label', ''), item['confirmations'],
                    item['bc_value'],
                    item.get('fiat_value', ''),
                    item.get('fee', ''),
                    item.get('fiat_fee', ''), item['date']
                ])
        with open(file_name, "w+", encoding='utf-8') as f:
            if is_csv:
                import csv
                transaction = csv.writer(f, lineterminator='\n')
                transaction.writerow([
                    "transaction_hash", "label", "confirmations", "value",
                    "fiat_value", "fee", "fiat_fee", "timestamp"
                ])
                for line in lines:
                    transaction.writerow(line)
            else:
                from electrum.util import json_encode
                f.write(json_encode(txns))

    def get_text_and_userrole_from_coordinate(self, row, col):
        idx = self.model().mapToSource(self.model().index(row, col))
        tx_item = idx.internalPointer().get_data()
        return self.hm.data(idx, Qt.DisplayRole).value(), get_item_key(tx_item)
class Window(QDialog):
    def __init__(self):
        super().__init__()

        self.title = "PyQt5 Window"
        self.top = 100
        self.left = 100
        self.width = 400
        self.height = 150
        self.lang = "java19"

        self.setWindowTitle(self.title)
        self.setFixedSize(self.width, self.height)

        self.create_layout()

        vbox_layout = QVBoxLayout()
        vbox_layout.addWidget(self.group_box)
        self.setLayout(vbox_layout)

        self.show()

    def create_layout(self):
        vbox_layout = QVBoxLayout()

        hbox_layout = QHBoxLayout()

        btn_source = QPushButton("Choose Source", self)
        btn_source.setMinimumHeight(28)
        btn_source.clicked.connect(self.click_source_btn)
        hbox_layout.addWidget(btn_source)

        btn_destination = QPushButton("Choose Destination", self)
        btn_destination.setMinimumHeight(28)
        btn_destination.clicked.connect(self.click_destination_btn)
        hbox_layout.addWidget(btn_destination)

        btn_start = QPushButton("Start", self)
        btn_start.setMinimumHeight(28)
        btn_start.clicked.connect(self.click_start_btn)
        hbox_layout.addWidget(btn_start)

        vbox_layout.addLayout(hbox_layout)

        self.lang_cb = QComboBox()
        self.lang_cb.addItems(
            "java19,java17,java15,java15dm,java12,java11,python3,c/c++,c#-1.2,char,text,scheme"
            .split(","))
        self.lang_cb.currentIndexChanged.connect(
            self.selection_changed_lang_gb)
        vbox_layout.addWidget(self.lang_cb)

        self.group_box = QGroupBox("JPlag Wrapper")
        self.group_box.setLayout(vbox_layout)

    def click_source_btn(self):
        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.DirectoryOnly)

        if dlg.exec_() == QFileDialog.Accepted:
            self.source_dir = dlg.selectedFiles()[0]
            logging.info("Source dir: '%s'", dlg.selectedFiles())
            print(dlg.selectedFiles())

    def click_destination_btn(self):
        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.DirectoryOnly)

        if dlg.exec_() == QFileDialog.Accepted:
            self.destination_dir = dlg.selectedFiles()[0]
            logging.info("Destination dir: '%s'", dlg.selectedFiles())
            print(dlg.selectedFiles())

    def click_start_btn(self):
        logging.info("JPlag started with source: '%s' and destination: '%s'",
                     self.source_dir, self.destination_dir)
        print("Started with source: {} and destination: {}".format(
            self.source_dir, self.destination_dir))
        jplag_process = subprocess.run(
            f"java -jar ./jplag.jar -l {self.lang} -s '{self.source_dir}' -r '{self.destination_dir}'",
            shell=True,
            stdout=subprocess.PIPE)

        with open("jplag_output.txt", "w") as jplag_output_fd:
            jplag_output_fd.write(jplag_process.stdout.decode())

        logging.info("JPlag completed.")
        print("JPlag completed.")

    def selection_changed_lang_gb(self, i):
        logging.info("Selection changed to %s", self.lang_cb.currentText())
        print("Selection changed to", self.lang_cb.currentText())
        self.lang = self.lang_cb.currentText()
Exemple #55
0
class WidgetGallery(QDialog):
    def __init__(self, parent=None):
        super(WidgetGallery, self).__init__(parent)

        QApplication.setStyle(QStyleFactory.create('Fusion'))
        QApplication.setPalette(QApplication.style().standardPalette())

        self.tabGroupboxes = []
        self.savePath = ""
        self.logMessages = ""

        self.setDarkMode()
        self.createSeasonsGroupBox()
        self.createExportGroupBox()
        self.createLogGroupBox()
        self.createSchemaTabWidget()
        self.createRequestsGroupBox()
        self.createProgressBar()
        self.initiateLogWatcher()

        mainLayout = QGridLayout()
        mainLayout.addWidget(self.schemaGroupBox, 0, 0, 3, 1)
        mainLayout.addWidget(self.seasonsGroupBox, 0, 1, 1, 1)
        mainLayout.addWidget(self.exportGroupBox, 1, 1, 1, 1)
        mainLayout.addWidget(self.requestsGroupBox, 2, 1, 1, 1)
        mainLayout.addWidget(self.logGroupBox, 3, 0, 1, 2)
        mainLayout.addWidget(self.progressBar, 4, 0, 1, 2)
        mainLayout.setRowStretch(1, 1)
        mainLayout.setRowStretch(2, 1)
        mainLayout.setColumnStretch(0, 1)
        mainLayout.setColumnStretch(1, 1)
        self.setLayout(mainLayout)
        self.setWindowTitle("MLB Data Fetch")

    def setDarkMode(self):
        palette = QPalette()
        palette.setColor(QPalette.Window, QColor(53, 53, 53))
        palette.setColor(QPalette.WindowText, Qt.white)
        palette.setColor(QPalette.Base, QColor(25, 25, 25))
        palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53))
        palette.setColor(QPalette.ToolTipBase, Qt.white)
        palette.setColor(QPalette.ToolTipText, Qt.white)
        palette.setColor(QPalette.Text, Qt.white)
        palette.setColor(QPalette.Button, QColor(53, 53, 53))
        palette.setColor(QPalette.ButtonText, Qt.white)
        palette.setColor(QPalette.BrightText, Qt.red)
        palette.setColor(QPalette.Link, QColor(42, 130, 218))
        palette.setColor(QPalette.Highlight, QColor(42, 130, 218))
        palette.setColor(QPalette.HighlightedText, Qt.black)
        app.setPalette(palette)

    def chooseFilePath(self):
        self.savePath = str(
            QFileDialog.getExistingDirectory(self, "Select Directory"))
        self.savePathLabel.setText(self.savePath)

    def validateSettings(self):
        error = ""
        if int(self.seasonsBeginComboBox.currentText()) > int(
                self.seasonsEndComboBox.currentText()):
            error += "Invalid seasons range.\n"
        if self.savePath == "":
            error += "No save directory chosen.\n"

        if error != "":
            msgbox = QMessageBox()
            msgbox.setFixedWidth(800)
            msgbox.setWindowTitle("Error")
            msgbox.setIcon(QMessageBox.Critical)
            msgbox.setText(error)
            msgbox.exec_()
            return False
        else:
            return True

    def fetchData(self):
        tables = []
        for groupbox in self.tabGroupboxes:
            if groupbox.isChecked():
                table = groupbox.objectName()
                cols = []
                checkboxes = groupbox.findChildren(QWidget)
                for checkbox in checkboxes:
                    if checkbox.isChecked():
                        cols.append(checkbox.objectName())
                tables.append({"tableName": table, "cols": cols})

        seasons = []
        for i in range(int(self.seasonsBeginComboBox.currentText()),
                       int(self.seasonsEndComboBox.currentText()) + 1):
            seasons.append(i)

        minSec = self.minSpinBox.value()
        maxSec = self.maxSpinBox.value()

        csv = True
        if csv:
            for table in tables:
                # Team and Venue are not based on season, so just get this data once
                if table["tableName"] == "Team":
                    fetch.export_team_data(table["cols"], self.savePath)
                    self.logMessages += "Team data written to " + self.savePath + "/Team.csv\n"
                    sleep(randint(minSec, maxSec))
                if table["tableName"] == "Venue":
                    fetch.export_venue_data(table["cols"], self.savePath)
                    self.logMessages += "Venue data written to " + self.savePath + "/Venue.csv\n"
                    sleep(randint(minSec, maxSec))

            for season in seasons:
                for table in tables:
                    if table["tableName"] == "Player":
                        fetch.export_player_data(season, table["cols"],
                                                 self.savePath)
                        self.logMessages += "Player data written to " + self.savePath + "/Player" + str(
                            season) + ".csv\n"
                        sleep(randint(minSec, maxSec))
                    if table["tableName"] == "Schedule":
                        fetch.export_schedule_data(season, table["cols"],
                                                   self.savePath)
                        self.logMessages += "Schedule data written to " + self.savePath + "/Schedule" + str(
                            season) + ".csv\n"
                        sleep(randint(minSec, maxSec))
                    if table["tableName"] == "Game":
                        fetch.export_game_data(season, table["cols"],
                                               self.savePath)
                        self.logMessages += "Game data written to " + self.savePath + "/Game" + str(
                            season) + ".csv\n"
                        sleep(randint(minSec, maxSec))
                    if table["tableName"] == "MlbBoxscoreBatting":
                        fetch.export_boxscore_data(season, table["cols"],
                                                   minSec, maxSec,
                                                   self.savePath)
                        self.logMessages += "Boxscore data written to " + self.savePath + "/MlbBoxscoreBatting" + str(
                            season) + ".csv\n"
                        sleep(randint(minSec, maxSec))
                    if table["tableName"] == "MlbBoxscorePitching":
                        fetch.export_boxscore_pitching_data(
                            season, table["cols"], minSec, maxSec,
                            self.savePath)
                        self.logMessages += "Boxscore data written to " + self.savePath + "/MlbBoxscorePitching" + str(
                            season) + ".csv\n"
                        sleep(randint(minSec, maxSec))
                    if table["tableName"] == "PlayByPlay":
                        fetch.export_pbp_data(season, table["cols"], minSec,
                                              maxSec, self.savePath)
                        self.logMessages += "PlayByPlay data written to " + self.savePath + "/PlayByPlay" + str(
                            season) + ".csv\n"
                        sleep(randint(minSec, maxSec))
        else:
            for table in tables:
                # Team and Venue are not based on season, so just get this data once
                if table["tableName"] == "Team":
                    fetch.export_team_data(table["cols"], self.savePath)
                    self.logMessages += "Team data written to " + self.savePath + "/Team.xls\n"
                    sleep(randint(minSec, maxSec))
                if table["tableName"] == "Venue":
                    fetch.export_venue_data(table["cols"], self.savePath)
                    self.logMessages += "Venue data written to " + self.savePath + "/Venue.xls\n"
                    sleep(randint(minSec, maxSec))

            for season in seasons:
                for table in tables:
                    if table["tableName"] == "Player":
                        fetch.export_player_data(season, table["cols"],
                                                 self.savePath)
                        self.logMessages += "Player data written to " + self.savePath + "/Player" + str(
                            season) + ".xls\n"
                        sleep(randint(minSec, maxSec))
                    if table["tableName"] == "Schedule":
                        fetch.export_schedule_data(season, table["cols"],
                                                   self.savePath)
                        self.logMessages += "Schedule data written to " + self.savePath + "/Schedule" + str(
                            season) + ".xls\n"
                        sleep(randint(minSec, maxSec))
                    if table["tableName"] == "Game":
                        fetch.export_game_data(season, table["cols"],
                                               self.savePath)
                        self.logMessages += "Game data written to " + self.savePath + "/Game" + str(
                            season) + ".xls\n"
                        sleep(randint(minSec, maxSec))
                    if table["tableName"] == "MlbBoxscoreBatting":
                        fetch.export_boxscore_data(season, table["cols"],
                                                   minSec, maxSec,
                                                   self.savePath)
                        self.logMessages += "MlbBoxscoreBatting data written to " + self.savePath + "/MlbBoxscoreBatting" + str(
                            season) + ".xls\n"
                        sleep(randint(minSec, maxSec))
                    if table["tableName"] == "MlbBoxscorePitching":
                        fetch.export_boxscore_pitching_data(
                            season, table["cols"], minSec, maxSec,
                            self.savePath)
                        self.logMessages += "MlbBoxscorePitching data written to " + self.savePath + "/MlbBoxscoreBatting" + str(
                            season) + ".xls\n"
                        sleep(randint(minSec, maxSec))
                    if table["tableName"] == "PlayByPlay":
                        fetch.export_pbp_data(season, table["cols"], minSec,
                                              maxSec, self.savePath)
                        self.logMessages += "PlayByPlay data written to " + self.savePath + "/PlayByPlay" + str(
                            season) + ".xls\n"
                        sleep(randint(minSec, maxSec))

    def goButtonClicked(self):
        validSettings = self.validateSettings()
        if validSettings:
            thread = Thread(target=self.fetchData, daemon=True)
            thread.start()

    def advanceProgressBar(self):
        curVal = self.progressBar.value()
        maxVal = self.progressBar.maximum()
        self.progressBar.setValue(curVal + (maxVal - curVal) / 100)

    def createSeasonsGroupBox(self):
        self.seasonsGroupBox = QGroupBox("Seasons")
        topLayout = QHBoxLayout()
        seasons = [
            "2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012",
            "2013", "2014", "2015", "2016", "2017", "2018", "2019"
        ]
        self.seasonsBeginComboBox = QComboBox()
        self.seasonsBeginComboBox.addItems(seasons)
        self.seasonsEndComboBox = QComboBox()
        self.seasonsEndComboBox.addItems(seasons)
        seasonsLabel = QLabel("Range:")
        seasonsLabel.setGeometry(QRect(10, 10, 20, 20))
        seasonsLabel.setBuddy(self.seasonsBeginComboBox)
        toLabel = QLabel("to")
        toLabel.setGeometry(QRect(70, 10, 20, 20))
        toLabel.setBuddy(self.seasonsEndComboBox)
        topLayout.addWidget(seasonsLabel)
        topLayout.addWidget(self.seasonsBeginComboBox)
        topLayout.addWidget(toLabel)
        topLayout.addWidget(self.seasonsEndComboBox)
        topLayout.addStretch(1)
        seasonsLayout = QGridLayout()
        seasonsLayout.addLayout(topLayout, 0, 0, 1, 1)
        self.seasonsGroupBox.setLayout(seasonsLayout)

    def createExportGroupBox(self):
        self.exportGroupBox = QGroupBox("Export")
        pathButton = QPushButton("Choose file path")
        pathButton.clicked.connect(self.chooseFilePath)
        self.savePathLabel = QLabel("")
        radioButton1 = QRadioButton(".xls")
        radioButton2 = QRadioButton(".csv")
        radioButton1.setChecked(True)
        layout = QVBoxLayout()
        layout.addWidget(pathButton)
        layout.addWidget(self.savePathLabel)
        layout.addWidget(radioButton1)
        layout.addWidget(radioButton2)
        layout.addStretch(1)
        self.exportGroupBox.setLayout(layout)

    def createLogGroupBox(self):
        self.logGroupBox = QGroupBox("Log")
        self.logTextbox = QTextEdit()
        #self.logTextbox.setDisabled(True)
        self.logTextbox.setReadOnly(True)
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.logTextbox)
        layout.addStretch(1)
        self.logGroupBox.setLayout(layout)

    def createSchemaTabWidget(self):
        self.schemaGroupBox = QGroupBox("Data")
        layout = QVBoxLayout()
        self.schemaTabWidget = QTabWidget()
        self.schemaTabWidget.setMinimumHeight(300)
        self.schemaTabWidget.setMinimumWidth(380)

        self.tabs = [
            "Team", "Venue", "Player", "Schedule", "Game",
            "MlbBoxscoreBatting", "MlbBoxscorePitching", "PlayByPlay"
        ]
        self.props = [
            [
                "MlbTeamID", "TeamName", "MlbVenueID", "TeamAbbrev",
                "LocationName", "MlbLeagueID", "MlbDivisionID"
            ], ["MlbVenueID", "VenueName"],
            [
                "MlbPlayerID", "Season", "FullName", "FirstName", "LastName",
                "BirthDate", "PlayerHeight", "PlayerWeight", "MlbTeamID",
                "Position", "DebutDate", "BatSide", "PitchHand"
            ],
            [
                "MlbScheduleID", "MlbGameID", "GameDateTime", "GameDate",
                "GameTime", "AwayTeamID", "HomeTeamID", "MlbVenueID"
            ],
            [
                "MlbGameID", "Season", "GameDateTime", "GameDate", "GameTime",
                "Status", "AwayTeamID", "AwayTeamScore", "AwayTeamRecordWins",
                "AwayTeamRecordLosses", "AwayTeamRecordPct", "HomeTeamID",
                "HomeTeamScore", "HomeTeamRecordWins", "HomeTeamRecordLosses",
                "HomeTeamRecordPct", "VenueID", "DayNight", "GamesInSeries",
                "SeriesGameNumber", "SeriesDescription"
            ],
            [
                "MlbBoxscoreBattingID", "MlbPlayerID", "MlbGameID",
                "AwayTeamID", "HomeTeamID", "IsAway", "BattingOrder", "AB",
                "R", "H", "2B", "3B", "HR", "RBI", "BB", "IBB", "SO", "HBP",
                "SH", "SF", "GDP", "SB", "CS"
            ],
            [
                "MlbBoxscorePitchingID", "MlbPlayerID", "MlbGameID",
                "AwayTeamID", "HomeTeamID", "IsAway", "StartedGame", "Win",
                "IP", "H", "R", "ER", "ERA", "SO", "HR", "BB", "HBP",
                "CompleteGame", "Shutout", "PitchCount"
            ],
            [
                "PlayByPlayID", "GameID", "BatterID", "BatSide", "PitcherID",
                "PitchHand", "MenOnBase", "Event", "EventType",
                "IsScoringPlay", "AwayTeamScore", "HomeTeamScore",
                "AtBatIndex", "HalfInning", "Inning", "Outs"
            ]
        ]

        for i in range(len(self.tabs)):
            tab = QWidget()
            tabVbox = QVBoxLayout()
            tabVbox.setContentsMargins(5, 5, 5, 5)
            tabGroupbox = QGroupBox(self.tabs[i])
            tabGroupbox.setObjectName(self.tabs[i])
            tabGroupbox.setCheckable(True)
            tabGroupbox.setChecked(True)
            tabGroupbox.setContentsMargins(5, 5, 5, 5)
            self.tabGroupboxes.append(tabGroupbox)
            cols = self.props[i]
            x_offset = 0
            y_multiplier = 0

            for j in range(len(cols)):
                if j == 10:
                    x_offset = 175
                    y_multiplier = 0
                checkbox = QCheckBox(tabGroupbox)
                checkbox.setGeometry(
                    QRect(20 + x_offset, 35 + (20 * y_multiplier), 150, 17))
                checkbox.setObjectName(cols[j])
                checkbox.setText(cols[j])
                checkbox.setChecked(True)
                y_multiplier += 1

            tabVbox.addWidget(tabGroupbox)
            tab.setLayout(tabVbox)
            self.schemaTabWidget.addTab(tab, self.tabs[i])

        layout.addWidget(self.schemaTabWidget)
        self.schemaGroupBox.setLayout(layout)

    def createRequestsGroupBox(self):
        self.requestsGroupBox = QGroupBox("Make Requests")
        self.requestsGroupBox.setMinimumWidth(380)

        topLayout = QHBoxLayout()
        self.minSpinBox = QSpinBox()
        self.minSpinBox.setValue(5)
        self.maxSpinBox = QSpinBox()
        self.maxSpinBox.setValue(15)
        waitTimeLabel = QLabel("Wait")
        waitTimeLabel.setGeometry(QRect(10, 10, 20, 20))
        waitTimeLabel.setBuddy(self.minSpinBox)
        toLabel = QLabel("to")
        toLabel.setGeometry(QRect(70, 10, 20, 20))
        toLabel.setBuddy(self.maxSpinBox)
        secondsLabel = QLabel("seconds between requests.")
        secondsLabel.setGeometry(QRect(130, 10, 20, 20))
        topLayout.addWidget(waitTimeLabel)
        topLayout.addWidget(self.minSpinBox)
        topLayout.addWidget(toLabel)
        topLayout.addWidget(self.maxSpinBox)
        topLayout.addWidget(secondsLabel)
        topLayout.addStretch(1)

        middleLayout = QHBoxLayout()
        estimatedTimeLabel = QLabel("Estimated run time:")
        middleLayout.addWidget(estimatedTimeLabel)
        middleLayout.addStretch(1)

        bottomLayout = QHBoxLayout()
        goButton = QPushButton("Go")
        goButton.setMinimumHeight(30)
        goButton.setMinimumWidth(300)
        goButton.clicked.connect(lambda: self.goButtonClicked())
        bottomLayout.addWidget(goButton)

        requestsLayout = QGridLayout()
        requestsLayout.addLayout(topLayout, 0, 0, 1, 1)
        requestsLayout.addLayout(middleLayout, 1, 0, 1, 1)
        requestsLayout.addLayout(bottomLayout, 2, 0, 1, 1)
        self.requestsGroupBox.setLayout(requestsLayout)

    def lol(self):
        self.logTextbox.setText(self.logMessages)

    def createProgressBar(self):
        self.progressBar = QProgressBar()
        self.progressBar.setRange(0, 10000)
        self.progressBar.setValue(0)
        timer = QTimer(self)
        timer.timeout.connect(self.advanceProgressBar)
        timer.start(1000)

    def initiateLogWatcher(self):
        logTimer = QTimer(self)
        logTimer.timeout.connect(self.lol)
        logTimer.start(3000)
Exemple #56
0
class BookManage(QGroupBox):
    def __init__(self):
        super().__init__()
        self.book_list = []
        self.body = QVBoxLayout()
        self.table = None
        self.setTitleBar()
        self.setSearchBar()
        self.searchFunction()

        self.setLayout(self.body)
        self.initUI()


    def errorBox(self, mes: str):
        msgBox = QMessageBox(
            QMessageBox.Warning,
            "警告!",
            mes,
            QMessageBox.NoButton,
            self
        )
        msgBox.addButton("确认", QMessageBox.AcceptRole)
        msgBox.exec_()

    # 标题栏
    def setTitleBar(self):
        self.title = QLabel()
        self.title.setText('书籍信息管理')
        self.title.setFixedHeight(25)
        titleLayout = QHBoxLayout()
        titleLayout.addSpacing(50)
        titleLayout.addWidget(self.title)
        self.titleBar = QWidget()
        self.titleBar.setFixedSize(1000, 50)
        self.titleBar.setLayout(titleLayout)
        self.body.addWidget(self.titleBar)

    # 设置搜索框
    def setSearchBar(self):
        self.selectBox = QComboBox()
        self.selectBox.addItems(['书号', '分类', '出版社', '作者', '书名'])
        self.selectBox.setFixedHeight(30)
        self.searchTitle = QLabel()
        self.searchTitle.setText('搜索书籍')
        self.searchInput = QLineEdit()
        self.searchInput.setText('')
        self.searchInput.setClearButtonEnabled(True)
        self.searchInput.setFixedSize(400, 40)
        self.searchButton = QToolButton()
        self.searchButton.setFixedSize(100, 40)
        self.searchButton.setText('搜索')
        self.searchButton.clicked.connect(self.searchFunction)
        self.addNewBookButton = QToolButton()
        self.addNewBookButton.setFixedSize(120, 40)
        self.addNewBookButton.setText('插入新书')
        self.addNewBookButton.clicked.connect(self.addNewBookFunction)
        searchLayout = QHBoxLayout()
        searchLayout.addStretch()
        searchLayout.addWidget(self.selectBox)
        searchLayout.addWidget(self.searchTitle)
        searchLayout.addWidget(self.searchInput)
        searchLayout.addWidget(self.searchButton)
        searchLayout.addWidget(self.addNewBookButton)
        searchLayout.addStretch()
        self.searchWidget = QWidget()
        self.searchWidget.setLayout(searchLayout)
        self.body.addWidget(self.searchWidget)

    # 搜索方法
    def searchFunction(self):
        convert = {'书号': 'BID', '分类': 'CLASSIFICATION', '出版社': 'PRESS', '作者': 'AUTHOR', '书名': 'BNAME', '': 'BNAME'}
        self.book_list = database.search_book(self.searchInput.text(), convert[self.selectBox.currentText()])
        if self.book_list == []:
            self.errorBox('未找到')
        if self.table is not None:
            self.table.deleteLater()
        self.setTable()

    # 设置表格
    def setTable(self):
        self.table = QTableWidget(1, 9)
        self.table.setContentsMargins(10, 10, 10, 10)
        self.table.verticalHeader().setVisible(False)
        self.table.horizontalHeader().setVisible(False)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.setFocusPolicy(Qt.NoFocus)
        self.table.setColumnWidth(0, 80)
        # self.table.setColumnWidth(1, 150)
        # self.table.setColumnWidth(2, 125)
        # self.table.setColumnWidth(3, 125)
        # self.table.setColumnWidth(4, 100)
        self.table.setColumnWidth(6, 80)

        self.table.setItem(0, 0, QTableWidgetItem('书号'))
        self.table.setItem(0, 1, QTableWidgetItem('书名'))
        self.table.setItem(0, 2, QTableWidgetItem('作者'))
        self.table.setItem(0, 3, QTableWidgetItem('出版日期'))
        self.table.setItem(0, 4, QTableWidgetItem('出版社'))
        self.table.setItem(0, 5, QTableWidgetItem('分类'))
        self.table.setItem(0, 6, QTableWidgetItem('位置'))
        self.table.setItem(0, 7, QTableWidgetItem('总数/剩余'))
        self.table.setItem(0, 8, QTableWidgetItem('操作'))

        for i in range(9):
            self.table.item(0, i).setTextAlignment(Qt.AlignCenter)
            self.table.item(0, i).setFont(QFont('微软雅黑', 15))

        # 显示借阅详情
        for i in self.book_list:
            self.insertRow(i)
        self.body.addWidget(self.table)

    # 插入行
    def insertRow(self, val: list):
        itemBID = QTableWidgetItem(val[0])
        itemBID.setTextAlignment(Qt.AlignCenter)

        itemNAME = QTableWidgetItem('《' + val[1] + '》')
        itemNAME.setTextAlignment(Qt.AlignCenter)

        itemAUTHOR = QTableWidgetItem(val[2])
        itemAUTHOR.setTextAlignment(Qt.AlignCenter)

        itemDATE = QTableWidgetItem(val[3])
        itemDATE.setTextAlignment(Qt.AlignCenter)

        itemPRESS = QTableWidgetItem(val[4])
        itemPRESS.setTextAlignment(Qt.AlignCenter)

        itemPOSITION = QTableWidgetItem(val[5])
        itemPOSITION.setTextAlignment(Qt.AlignCenter)

        itemSUM = QTableWidgetItem(str(val[6])+'/'+str(val[7]))
        itemSUM.setTextAlignment(Qt.AlignCenter)

        itemCLASSIFICATION = QTableWidgetItem(val[8])
        itemCLASSIFICATION.setTextAlignment(Qt.AlignCenter)

        itemModify = QToolButton(self.table)
        itemModify.setFixedSize(50, 25)
        itemModify.setText('修改')
        itemModify.clicked.connect(lambda: self.updateBookFunction(val[0]))
        itemModify.setStyleSheet('''
        *{
            color: white;
            font-family: 微软雅黑;
            background: rgba(38, 175, 217, 1);
            border: 0;
            border-radius: 10px;
        }
        ''')
        itemDelete = QToolButton(self.table)
        itemDelete.setFixedSize(50, 25)
        itemDelete.setText('删除')
        itemDelete.clicked.connect(lambda: self.deleteBookFunction(val[0]))
        itemDelete.setStyleSheet('''
        *{
            color: white;
                font-family: 微软雅黑;
                background: rgba(222, 52, 65, 1);
                border: 0;
                border-radius: 10px;
        }
        ''')

        itemLayout = QHBoxLayout()
        itemLayout.setContentsMargins(0, 0, 0, 0)
        itemLayout.addWidget(itemModify)
        itemLayout.addWidget(itemDelete)
        itemWidget = QWidget()
        itemWidget.setLayout(itemLayout)

        self.table.insertRow(1)
        self.table.setItem(1, 0, itemBID)
        self.table.setItem(1, 1, itemNAME)
        self.table.setItem(1, 2, itemAUTHOR)
        self.table.setItem(1, 3, itemDATE)
        self.table.setItem(1, 4, itemPRESS)
        self.table.setItem(1, 5, itemCLASSIFICATION)
        self.table.setItem(1, 6, itemPOSITION)
        self.table.setItem(1, 7, itemSUM)
        self.table.setCellWidget(1, 8, itemWidget)

    def updateBookFunction(self, BID: str):
        book_info = database.get_book_info(BID)
        if book_info is None:
            return
        self.sum = book_info['SUM']
        self.updateBookDialog = book_information.BookInfo(book_info)
        self.updateBookDialog.after_close.connect(self.updateBook)
        self.updateBookDialog.show()

    def updateBook(self, book_info: dict):
        change = self.sum - book_info['SUM']
        # 书本减少的数量不能大于未借出的书本数
        if change > book_info['NUM']:
            book_info['SUM'] = self.sum - book_info['NUM']
            book_info['NUM'] = 0
        else:
            book_info['NUM'] -= change
        ans = database.update_book(book_info)
        if ans:
            self.searchFunction()

    def addNewBookFunction(self):
        self.newBookDialog = book_information.BookInfo()
        self.newBookDialog.show()
        self.newBookDialog.after_close.connect(self.addNewBook)

    def addNewBook(self, book_info: dict):
        ans = database.new_book(book_info)
        if ans:
            self.searchFunction()

    def deleteBookFunction(self, BID: str):
        msgBox = QMessageBox(QMessageBox.Warning, "警告!", '您将会永久删除这本书以及相关信息!',
                             QMessageBox.NoButton, self)
        msgBox.addButton("确认", QMessageBox.AcceptRole)
        msgBox.addButton("取消", QMessageBox.RejectRole)
        if msgBox.exec_() == QMessageBox.AcceptRole:
            ans = database.delete_book(BID)
            if ans:
                self.searchFunction()

    def initUI(self):
        self.setFixedSize(1100, 600)
        self.setStyleSheet('''
        *{
            background-color: white;
            border:0px;
        }
        ''')
        self.titleBar.setStyleSheet('''
        QWidget {
            border:0;
            background-color: rgba(216, 216, 216, 1);
            border-radius: 20px;
            color: rgba(113, 118, 121, 1);
        }
        QLabel{
            font-size: 25px;
            font-family: 微软雅黑;
        }
        ''')
        self.searchTitle.setStyleSheet('''
            QLabel{
                font-size:25px;
                color: black;
                font-family: 微软雅黑;
            }
        ''')
        self.searchInput.setStyleSheet('''
            QLineEdit{
                border: 1px solid rgba(201, 201, 201, 1);
                border-radius: 5px;
                color: rgba(120, 120, 120, 1)
            }
        ''')
        self.searchButton.setStyleSheet('''
            QToolButton{
                border-radius: 10px;
                background-color:rgba(135, 206, 235, 1);
                color: white;
                font-size: 25px;
                font-family: 微软雅黑;
            }
        ''')
        self.addNewBookButton.setStyleSheet('''
            QToolButton{
                border-radius: 10px;
                background-color:rgba(135, 206, 235, 1);
                color: white;
                font-size: 25px;
                font-family: 微软雅黑;
            }
        ''')
        self.selectBox.setStyleSheet('''
        *{
            border: 0px;
        }
        QComboBox{
            border: 1px solid rgba(201, 201, 201, 1);
        }
        ''')
Exemple #57
0
class Run_CM110(QMainWindow):
	
	def __init__(self):
		super().__init__()
		
		self.cwd = os.getcwd()
		self.load_()
		
		# Enable antialiasing for prettier plots		
		pg.setConfigOptions(antialias=True)
		self.initUI()
		
		
	def initUI(self):
		
		################### MENU BARS START ##################
		
		MyBar = QMenuBar(self)
		fileMenu = MyBar.addMenu("File")
		fileSavePlt = fileMenu.addAction("Save plots")
		fileSavePlt.triggered.connect(self.save_plots)
		fileSavePlt.setShortcut('Ctrl+P')
		fileSaveSet = fileMenu.addAction("Save settings")        
		fileSaveSet.triggered.connect(self.save_) # triggers closeEvent()
		fileSaveSet.setShortcut('Ctrl+S')
		fileClose = fileMenu.addAction("Close")        
		fileClose.triggered.connect(self.close) # triggers closeEvent()
		fileClose.setShortcut('Ctrl+X')
		
		instMenu = MyBar.addMenu("Instruments")
		self.conMode = instMenu.addAction("Load instruments")
		self.conMode.triggered.connect(self.instrumentsDialog)
		
		################### MENU BARS END ##################
		
		#####################################################
		lbl1 = QLabel("MONOCHROMATOR CM110 settings:", self)
		lbl1.setStyleSheet("color: blue")
		intervals_lbl = QLabel("Number of intervals", self)
		self.combo4 = QComboBox(self)
		mylist4=["1","2"]
		self.combo4.addItems(mylist4)
		self.combo4.setCurrentIndex(mylist4.index(str(self.numofintervals)))
		start_lbl = QLabel("Start[nm]",self)
		stop_lbl = QLabel("Stop[nm]",self)
		step_lbl = QLabel("Step[nm]",self)
		dwelltime = QLabel("Dwell[s]",self)
		
		self.startEdit = [QLineEdit("",self) for tal in range(2)]
		self.stopEdit = [QLineEdit("",self) for tal in range(2)]
		self.stepEdit = [QLineEdit("",self) for tal in range(2)]
		self.dwelltimeEdit = [QLineEdit("",self) for tal in range(2)]
		# disable those fields that will be ignored anyway
		for tal in range(2):
			if tal<self.numofintervals:
				self.startEdit[tal].setText(str(self.start_[tal]))
				self.stopEdit[tal].setText(str(self.stop[tal]))
				self.stepEdit[tal].setText(str(self.step[tal]))
				self.dwelltimeEdit[tal].setText(str(self.dwell_time[tal]))
			else:
				self.startEdit[tal].setEnabled(False)
				self.stopEdit[tal].setEnabled(False)
				self.stepEdit[tal].setEnabled(False)
				self.dwelltimeEdit[tal].setEnabled(False)
		
		lbl3 = QLabel("NEWPORT stepper SMC100:", self)
		lbl3.setStyleSheet("color: blue")
		startst_lbl = QLabel("Start",self)
		stopst_lbl = QLabel("Stop",self)
		stepst_lbl = QLabel("Step",self)
		lcdst_lbl = QLabel("Current pos",self)
		self.startst_Edit = QLineEdit(str(self.startst),self) 
		self.stopst_Edit = QLineEdit(str(self.stopst),self) 
		self.stepst_Edit = QLineEdit(str(self.stepst),self)
		self.lcdst = QLCDNumber(self)
		self.lcdst.setStyleSheet("color: blue")
		#self.lcdst.setFixedHeight(40)
		self.lcdst.setSegmentStyle(QLCDNumber.Flat)
		self.lcdst.setNumDigits(5)
		self.lcdst.display("-----")
		
		lbl2 = QLabel("ARDUINO Mega2560 settings:", self)
		lbl2.setStyleSheet("color: blue")
		dwelltime_lbl = QLabel("Dwell time [ms]",self)
		self.dwelltimeEdit_ard = QLineEdit(str(self.dwell_time_ard),self)
		
		avgpts_lbl = QLabel("Averaging points", self)
		self.combo1 = QComboBox(self)
		mylist=["1","5","10","50","100","200"]
		self.combo1.addItems(mylist)
		self.combo1.setCurrentIndex(mylist.index(str(self.avg_pts)))
		
		lbl4 = QLabel("STORAGE filename and location settings:", self)
		lbl4.setStyleSheet("color: blue")
		filename = QLabel("folder/file",self)
		self.filenameEdit = QLineEdit(self.filename_str,self)
		
		lbl6 = QLabel("PLOT options:", self)
		lbl6.setStyleSheet("color: blue")
		mylist2=["200","400","800","1600","3200","6400"]
		
		schroll_lbl = QLabel("Schroll time after",self)
		self.combo2 = QComboBox(self)
		self.combo2.addItems(mylist2)
		self.combo2.setCurrentIndex(mylist2.index(str(self.schroll_time)))
		
		schroll2_lbl = QLabel("Schroll wavelength after",self)
		self.combo3 = QComboBox(self)
		self.combo3.addItems(mylist2)
		self.combo3.setCurrentIndex(mylist2.index(str(self.schroll_wl)))
		
		##############################################
		
		lbl5 = QLabel("RECORD data and save images:", self)
		lbl5.setStyleSheet("color: blue")
		
		#save_str = QLabel("Store settings", self)
		#self.saveButton = QPushButton("Save",self)
		#self.saveButton.setEnabled(True)
		
		run_str = QLabel("Record lock-in data", self)
		self.runButton = QPushButton("Load instruments",self)
		
		#saveplots_str = QLabel("Save plots as png", self)
		#self.saveplotsButton = QPushButton("Save plots",self)
		#self.saveplotsButton.setEnabled(True)
		'''
		elapsedtime_str = QLabel('Show voltage vs. time', self)
		self.elapsedtimeButton = QPushButton("Plot 2",self)
		self.elapsedtimeButton.setEnabled(False)
		'''
		cancel_str = QLabel("Stop current run", self)
		self.stopButton = QPushButton("STOP",self)
		self.stopButton.setEnabled(False)
		
		##############################################
		
		# status info which button has been pressed
		#self.status_str = QLabel("Edit settings and press SAVE!", self)
		#self.status_str.setStyleSheet("color: green")
		
		##############################################
		
		# status info which button has been pressed
		self.elapsedtime_str = QLabel("TIME trace for storing plots and data:", self)
		self.elapsedtime_str.setStyleSheet("color: blue")
		
		##############################################
		
		self.lcd = QLCDNumber(self)
		self.lcd.setStyleSheet("color: red")
		self.lcd.setFixedHeight(60)
		self.lcd.setSegmentStyle(QLCDNumber.Flat)
		self.lcd.setNumDigits(11)
		self.lcd.display(self.timestr)
			
		##############################################
		# Add all widgets		
		g1_0 = QGridLayout()
		g1_0.addWidget(MyBar,0,0)
		g1_0.addWidget(lbl1,1,0)
		g1_1 = QGridLayout()
		#g1_1.addWidget(cm110port,0,0)
		#g1_1.addWidget(self.cm110portEdit,0,1)
		
		g1_3 = QGridLayout()
		g1_3.addWidget(intervals_lbl,0,0)
		g1_3.addWidget(self.combo4,0,1)
		g1_2 = QGridLayout()
		g1_2.addWidget(start_lbl,0,0)
		g1_2.addWidget(stop_lbl,0,1)
		g1_2.addWidget(step_lbl,0,2)
		g1_2.addWidget(dwelltime,0,3)
		for tal in range(2):
			g1_2.addWidget(self.startEdit[tal],1+tal,0)
			g1_2.addWidget(self.stopEdit[tal],1+tal,1)
			g1_2.addWidget(self.stepEdit[tal],1+tal,2)
			g1_2.addWidget(self.dwelltimeEdit[tal],1+tal,3)
		v1 = QVBoxLayout()
		v1.addLayout(g1_0)
		v1.addLayout(g1_1)
		v1.addLayout(g1_3)
		v1.addLayout(g1_2)
		
		g9_0 = QGridLayout()
		g9_0.addWidget(lbl3,0,0)
		g9_1 = QGridLayout()
		g9_1.addWidget(startst_lbl,0,0)
		g9_1.addWidget(stopst_lbl,0,1)
		g9_1.addWidget(stepst_lbl,0,2)
		g9_1.addWidget(lcdst_lbl,0,3)
		g9_1.addWidget(self.startst_Edit,1,0)
		g9_1.addWidget(self.stopst_Edit,1,1)
		g9_1.addWidget(self.stepst_Edit,1,2)
		g9_1.addWidget(self.lcdst,1,3)
		v9 = QVBoxLayout()
		v9.addLayout(g9_0)
		v9.addLayout(g9_1)
		
		g2_0 = QGridLayout()
		g2_0.addWidget(lbl2,0,0)
		g2_1 = QGridLayout()
		#g2_1.addWidget(ardport,0,0)
		g2_1.addWidget(dwelltime_lbl,0,0)
		g2_1.addWidget(avgpts_lbl,1,0)
		#g2_1.addWidget(self.ardportEdit,0,1)
		g2_1.addWidget(self.dwelltimeEdit_ard,0,1)
		g2_1.addWidget(self.combo1,1,1)
		v2 = QVBoxLayout()
		v2.addLayout(g2_0)
		v2.addLayout(g2_1)
		
		g4_0 = QGridLayout()
		g4_0.addWidget(lbl4,0,0)
		g4_1 = QGridLayout()
		g4_1.addWidget(filename,0,0)
		g4_1.addWidget(self.filenameEdit,0,1)
		v4 = QVBoxLayout()
		v4.addLayout(g4_0)
		v4.addLayout(g4_1)
				
		g7_0 = QGridLayout()
		g7_0.addWidget(lbl6,0,0)
		g7_1 = QGridLayout()
		g7_1.addWidget(schroll2_lbl,0,0)
		g7_1.addWidget(self.combo3,0,1)
		g7_1.addWidget(schroll_lbl,1,0)
		g7_1.addWidget(self.combo2,1,1)
		v7 = QVBoxLayout()
		v7.addLayout(g7_0)
		v7.addLayout(g7_1)
		
		g5_0 = QGridLayout()
		g5_0.addWidget(lbl5,0,0)
		g5_1 = QGridLayout()
		#g5_1.addWidget(save_str,0,0)
		g5_1.addWidget(run_str,0,0)
		#g5_1.addWidget(saveplots_str,2,0)
		g5_1.addWidget(cancel_str,1,0)
		#g5_1.addWidget(self.saveButton,0,1)
		g5_1.addWidget(self.runButton,0,1)
		#g5_1.addWidget(self.saveplotsButton,2,1)
		g5_1.addWidget(self.stopButton,1,1)
		v5 = QVBoxLayout()
		v5.addLayout(g5_0)
		v5.addLayout(g5_1)
		
		g6_0 = QGridLayout()
		g6_0.addWidget(self.elapsedtime_str,0,0)
		g6_0.addWidget(self.lcd,1,0)
		v6 = QVBoxLayout()
		v6.addLayout(g6_0)
		
		# add all groups from v1 to v6 in one vertical group v7
		v8 = QVBoxLayout()
		v8.addLayout(v1)
		v8.addLayout(v9)
		v8.addLayout(v2)
		v8.addLayout(v4)
		v8.addLayout(v7)
		v8.addLayout(v5)
		v8.addLayout(v6)
	
		# set graph  and toolbar to a new vertical group vcan
		vcan = QVBoxLayout()
		self.pw1 = pg.PlotWidget(name="Plot1")  ## giving the plots names allows us to link their axes together
		vcan.addWidget(self.pw1)
		self.pw2 = pg.PlotWidget(name="Plot2")
		vcan.addWidget(self.pw2)

		# SET ALL VERTICAL COLUMNS TOGETHER
		hbox = QHBoxLayout()
		hbox.addLayout(v8,1)
		hbox.addLayout(vcan,3.75)
		
    ##############################################
    # PLOT 1 settings
		# create plot and add it to the figure canvas		
		self.p0 = self.pw1.plotItem
		self.curve1=[self.p0.plot()]
		# create plot and add it to the figure
		self.p0vb = pg.ViewBox()
		self.curve5=pg.PlotCurveItem(pen=None)
		self.p0vb.addItem(self.curve5)
		# connect respective axes to the plot 
		self.p0.showAxis('right')
		self.p0.getAxis('right').setLabel("10-bit Arduino output")
		self.p0.scene().addItem(self.p0vb)
		self.p0.getAxis('right').linkToView(self.p0vb)
		self.p0vb.setXLink(self.p0)
		# Use automatic downsampling and clipping to reduce the drawing load
		self.pw1.setDownsampling(mode='peak')
		self.pw1.setClipToView(True)
		
		# PLOT 2 settings
		# create plot and add it to the figure canvas
		self.p1 = self.pw2.plotItem
		self.curve2=self.p1.plot(pen='r')
		self.curve3=self.p1.plot()
		# create plot and add it to the figure
		self.p2 = pg.ViewBox()
		self.curve4=pg.PlotCurveItem(pen='y')
		self.curve6=pg.PlotCurveItem(pen='m')
		self.p2.addItem(self.curve4)
		self.p2.addItem(self.curve6)
		# connect respective axes to the plot 
		self.p1.showAxis('right')
		self.p1.getAxis('right').setLabel("Wavelength", units='m', color='yellow')
		self.p1.scene().addItem(self.p2)
		self.p1.getAxis('right').linkToView(self.p2)
		self.p2.setXLink(self.p1)
		# Use automatic downsampling and clipping to reduce the drawing load
		self.pw2.setDownsampling(mode='peak')
		self.pw2.setClipToView(True)
		
		# Initialize and set titles and axis names for both plots
		self.clear_vars_graphs()
		###############################################################################
		
		self.inst_list = {}
		self.colors = itertools.cycle(["r", "b", "g", "y", "m", "c", "w"])
		
		self.threadpool = QThreadPool()
		print("Multithreading in Run_COMPexPRO with maximum %d threads" % self.threadpool.maxThreadCount())
		
		# reacts to choises picked in the menu
		self.combo1.activated[str].connect(self.onActivated1)
		self.combo2.activated[str].connect(self.onActivated2)
		self.combo3.activated[str].connect(self.onActivated3)
		self.combo4.activated[str].connect(self.onActivated4)
		
		# save all paramter data in the config file
		#self.saveButton.clicked.connect(self.save_)
		#self.saveButton.clicked.connect(self.set_elapsedtime_text)
	
		# run the main script
		self.runButton.clicked.connect(self.set_run)
		
		# cancel the script run
		self.stopButton.clicked.connect(self.set_stop)
		
		self.allFields(False)
		
		##############################################
		
		self.timer = QTimer(self)
		self.timer.timeout.connect(self.set_disconnect)
		self.timer.setSingleShot(True)
		
		##############################################
		
		self.setGeometry(100, 100, 1100, 650)
		self.setWindowTitle("Monochromator CM110 Control And Data Acqusition")
		
		w = QWidget()
		w.setLayout(hbox)
		self.setCentralWidget(w)
		self.show()
		
		
	def instrumentsDialog(self):
		
		self.Inst = Instruments_dialog.Instruments_dialog(self,self.inst_list,self.cwd,self.lcdst)
		self.Inst.exec()
		
		if self.inst_list.get("CM110") or self.inst_list.get("Ard") or self.inst_list.get("SR530") or self.inst_list.get("SMC100"):
			self.allFields(True)
			self.runButton.setText("Scan")
			self.timer.start(1000*60*self.minutes)
		else:
			self.allFields(False)
			self.runButton.setText("Load instrument!")
			
			
	def allFields(self,trueorfalse):
		
		for tal in range(2):
			if tal<self.numofintervals:
				self.startEdit[tal].setEnabled(trueorfalse)
				self.stopEdit[tal].setEnabled(trueorfalse)
				self.stepEdit[tal].setEnabled(trueorfalse)
				self.dwelltimeEdit[tal].setEnabled(trueorfalse)
		
		self.startst_Edit.setEnabled(trueorfalse)
		self.stopst_Edit.setEnabled(trueorfalse)
		self.stepst_Edit.setEnabled(trueorfalse)
		
		self.dwelltimeEdit_ard.setEnabled(trueorfalse)
		
		self.combo1.setEnabled(trueorfalse)
		self.combo2.setEnabled(trueorfalse)
		self.combo3.setEnabled(trueorfalse)
		self.combo4.setEnabled(trueorfalse)
		
		self.filenameEdit.setEnabled(trueorfalse)
		self.runButton.setEnabled(trueorfalse)
		
		
	def onActivated1(self, text):
		
		self.avg_pts = str(text)
		
		
	def onActivated2(self, text):
		
		self.schroll_time=int(text)
		
		
	def onActivated3(self, text):
		
		self.schroll_wl=int(text)
		
		
	def onActivated4(self, text):
		
		self.numofintervals = int(text)
		for tal in range(2):
			if tal<self.numofintervals:
				self.startEdit[tal].setEnabled(True)
				self.stopEdit[tal].setEnabled(True)
				self.stepEdit[tal].setEnabled(True)
				self.dwelltimeEdit[tal].setEnabled(True)
			else:
				self.startEdit[tal].setEnabled(False)
				self.stopEdit[tal].setEnabled(False)
				self.stepEdit[tal].setEnabled(False)
				self.dwelltimeEdit[tal].setEnabled(False)
				
	
	# Check input if a number, ie. digits or fractions such as 3.141
	# Source: http://www.pythoncentral.io/how-to-check-if-a-string-is-a-number-in-python-including-unicode/
	def is_number(self,s):
		try:
			float(s)
			return True
		except ValueError:
			pass

		try:
			import unicodedata
			unicodedata.numeric(s)
			return True
		except (TypeError, ValueError):
			pass
		
		return False
	
	
	def create_file(self, mystr):
		
		head, ext = os.path.splitext(mystr)
		#print("head: ",head)
		#print("ext: ",ext)
		#print("filename: ",self.filenameEdit.text())
		
		totalpath = ''.join([self.cwd,os.sep,head,'_',self.timestr,ext])
		my_dir = os.path.dirname(totalpath)
		
		if not os.path.isdir(my_dir):
			QMessageBox.warning(self, "Message","".join(["Folder(s) named ",my_dir," will be created!"]))
			
		try:
			os.makedirs(my_dir, exist_ok=True)
		except Exception as e:
			QMessageBox.critical(self, "Message","".join(["Folder named ",head," not valid!\n\n",str(e)]))
			return ""
		
		return totalpath
	
	
	def set_run(self):
		
		# MINIMUM REQUIREMENTS for proper run
		if not self.inst_list.get("CM110") and not self.inst_list.get("SR530") and not self.inst_list.get("Ard") and not self.inst_list.get("SMC100"):
			QMessageBox.critical(self, 'Message',"No instruments connected. At least 1 instrument is required.")
			return
			
		########################################################
		
		if self.inst_list.get("SMC100"):
			val = self.inst_list.get("SMC100").return_ts(1)
			if val[-2:] not in ["32","33","34","35"]:
				# RESET the stepper if active
				self.Reset_dialog = Reset_dialog.Reset_dialog(self, self.inst_list)
				self.Reset_dialog.exec()
				# Checkif the stepper is ready
				val = self.inst_list.get("SMC100").return_ts(1)
				if val[-2:] not in ["32","33","34","35"]:
					return
				
		########################################################
		
		try:
			for i in range(self.numofintervals):
				arr = numpy.arange(int(self.startEdit[i].text()),int(self.stopEdit[i].text()),int(self.stepEdit[i].text()))
				if len(arr)==0:
					QMessageBox.warning(self, 'Message',''.join(["Empty array returned. Check wavelength start and stop values!"]))
					return
		except Exception as e:
			QMessageBox.warning(self, 'Message',''.join(["All wavelength scan parameters should be integers!\n\n",str(e)]))
			return
		
		try:
			arr = numpy.arange(float(self.startst_Edit.text()),float(self.stopst_Edit.text()),float(self.stepst_Edit.text()))
			if len(arr)==0:
				QMessageBox.warning(self, 'Message',''.join(["Empty array returned. Check Newport start and stop values!"]))
				return
		except Exception as e:
			QMessageBox.warning(self, 'Message',''.join(["All stepper position parameters should be real numbers!\n\n",str(e)]))
			return
		
		for i in range(self.numofintervals):
			if not self.is_number(self.dwelltimeEdit[i].text()):
				QMessageBox.warning(self, 'Message',"Dwell time scan parameter is not a real number!")
				return
		
		# For SAVING data
		if "\\" in self.filenameEdit.text():
			self.filenameEdit.setText(self.filenameEdit.text().replace("\\",os.sep))
			
		if "/" in self.filenameEdit.text():
			self.filenameEdit.setText(self.filenameEdit.text().replace("/",os.sep))
			
		if not self.filenameEdit.text():
			self.filenameEdit.setText(''.join(["data",os.sep,"data"]))
		
		if not os.sep in self.filenameEdit.text():
			self.filenameEdit.setText(''.join(["data", os.sep, self.filenameEdit.text()]))
			
		# Initial read of the config file		
		start_sc = [int(self.startEdit[i].text()) for i in range(self.numofintervals)]
		stop_sc = [int(self.stopEdit[i].text()) for i in range(self.numofintervals)]
		step_sc = [int(self.stepEdit[i].text()) for i in range(self.numofintervals)]
		start_st = float(self.startst_Edit.text())
		stop_st = float(self.stopst_Edit.text())
		step_st = float(self.stepst_Edit.text())
		dwelltime = [float(self.dwelltimeEdit[ii].text()) for ii in range(self.numofintervals)]
		dwell_ard = float(self.dwelltimeEdit_ard.text())
		file_txt = self.create_file(''.join([self.filenameEdit.text(),".txt"]))
		file_hdf5 = self.create_file(''.join([self.filenameEdit.text(),".hdf5"]))
		
		for start,stop,step,dwell in zip(start_sc,stop_sc,step_sc,dwelltime):
			
			if start<0 or start>9000:
				QMessageBox.warning(self, 'Message',"Minimum start wavelength is 0 nm and maximum 9000 nm!")
				return
			
			if stop<0 or stop>9000:
				QMessageBox.warning(self, 'Message',"Minimum stop wavelength is 0 nm and maximum 9000 nm!")
				return
			
			if step<0 or step>127:
				QMessageBox.warning(self, 'Message',"Minimum step is 0 units and maximum 127 units!")
				return
			
			if dwell<3*dwell_ard/1000 or dwell>100:
				QMessageBox.warning(self, 'Message',"Monochromator dwell time is minimum 3 times Arduino dwell time and maximum 100 s!")
				return
			
			if dwell_ard<10 or dwell_ard>dwell*1000:
				QMessageBox.warning(self, 'Message',"Arduino dwell time is minimum 10 ms and maximum CM110 dwell time!")
				return
		
		self.clear_vars_graphs()
		
		self.allFields(False)
		self.conMode.setEnabled(False)
		self.runButton.setEnabled(False)
		self.stopButton.setEnabled(True)
		self.stopButton.setText("STOP")
		self.runButton.setText("Scanning...")
		
		self.timer.stop()
		self.get_thread=Run_CM110_Thread(start_sc,stop_sc,step_sc,dwelltime,dwell_ard,self.avg_pts,file_txt,file_hdf5,self.timestr,self.analogref,self.inst_list,start_st,stop_st,step_st)
		
		self.get_thread.signals.make_update1.connect(self.make_update1)
		self.get_thread.signals.make_update2.connect(self.make_update2)
		self.get_thread.signals.make_update3.connect(self.make_update3)
		self.get_thread.signals.make_update4.connect(self.make_update4)
		self.get_thread.signals.finished.connect(self.finished)
		# Execute
		self.threadpool.start(self.get_thread)
		
		
	def make_update1(self,set_position,real_positions,endpoint_data,endpoints_times,raw_data):
		
		self.set_wl.extend([ 1e-9*set_position ])
		self.real_wl.extend([ 1e-9*real_positions ])
		self.all_volts.extend([ endpoint_data  ])	
		self.all_times.extend([ endpoints_times ])
		self.all_raw.extend([ raw_data ])
		
		if len(self.set_wl)>self.schroll_wl:
			self.plot_volts[:-1] = self.plot_volts[1:]  # shift data in the array one sample left
			self.plot_volts[-1] = endpoint_data
			self.plot_wl[:-1] = self.plot_wl[1:]  # shift data in the array one sample left
			self.plot_wl[-1] = 1e-9*set_position
			self.plot_set_wl[:-1] = self.plot_set_wl[1:]  # shift data in the array one sample left
			self.plot_set_wl[-1] = 1e-9*set_position
			self.plot_real_wl[:-1] = self.plot_real_wl[1:]  # shift data in the array one sample left
			self.plot_real_wl[-1] = 1e-9*real_positions
			self.plot_raw[:-1] = self.plot_raw[1:]  # shift data in the array one sample left
			self.plot_raw[-1] = raw_data
		else:
			self.plot_volts.extend([ float(endpoint_data)  ])
			self.plot_wl.extend([ 1e-9*set_position ])
			self.plot_set_wl.extend([ 1e-9*set_position ])
			self.plot_real_wl.extend([ 1e-9*real_positions ])
			self.plot_raw.extend([ int(raw_data)  ])
		
		self.curve1[-1].setData(self.plot_wl, self.plot_volts)
		self.curve5.setData(self.plot_set_wl, self.plot_raw)
		
		## Handle view resizing 
		def updateViews():
			## view has resized; update auxiliary views to match
			self.p0vb.setGeometry(self.p0.vb.sceneBoundingRect())
			## need to re-update linked axes since this was called
			## incorrectly while views had different shapes.
			## (probably this should be handled in ViewBox.resizeEvent)
			self.p0vb.linkedViewChanged(self.p0.vb, self.p0vb.XAxis)
		updateViews()
		self.p0.vb.sigResized.connect(updateViews)
		
		###########################################################
		# Update curve3 in different plot
		if len(self.set_wl_tr)>=self.schroll_time:
			local_times=self.all_times[-self.counter:]
			local_volts=self.all_volts[-self.counter:]
			self.curve3.setData(local_times, local_volts)
		else:
			self.curve3.setData(self.all_times, self.all_volts)
		
		
	def make_update2(self,set_position,real_positions,all_data,timelist):
		
		self.set_wl_tr.extend([ 1e-9*set_position ])
		self.real_wl_tr.extend([ 1e-9*real_positions ])
		#self.all_volts_tr.extend([ float(all_data) ])
		#self.all_time_tr.extend([ float(timelist) ])
				
		if len(self.set_wl_tr)==self.schroll_time:
			self.counter=len(self.set_wl)

		if len(self.set_wl_tr)>self.schroll_time:
			self.plot_time_tr[:-1] = self.plot_time_tr[1:]  # shift data in the array one sample left
			self.plot_time_tr[-1] = timelist
			self.plot_volts_tr[:-1] = self.plot_volts_tr[1:]  # shift data in the array one sample left
			self.plot_volts_tr[-1] = all_data
			self.plot_set_wl_tr[:-1] = self.plot_set_wl_tr[1:]  # shift data in the array one sample left
			self.plot_set_wl_tr[-1] = 1e-9*set_position
			self.plot_real_wl_tr[:-1] = self.plot_real_wl_tr[1:]  # shift data in the array one sample left
			self.plot_real_wl_tr[-1] = 1e-9*real_positions
		else:
			self.plot_set_wl_tr.extend([ 1e-9*set_position ])
			self.plot_real_wl_tr.extend([ 1e-9*real_positions ])
			self.plot_volts_tr.extend([ all_data ])
			self.plot_time_tr.extend([ timelist ])

		## Handle view resizing 
		def updateViews():
			## view has resized; update auxiliary views to match
			self.p2.setGeometry(self.p1.vb.sceneBoundingRect())
			#p3.setGeometry(p1.vb.sceneBoundingRect())

			## need to re-update linked axes since this was called
			## incorrectly while views had different shapes.
			## (probably this should be handled in ViewBox.resizeEvent)
			self.p2.linkedViewChanged(self.p1.vb, self.p2.XAxis)
			#p3.linkedViewChanged(p1.vb, p3.XAxis)
			
		updateViews()
		self.p1.vb.sigResized.connect(updateViews)
		self.curve2.setData(self.plot_time_tr, self.plot_volts_tr)
		self.curve4.setData(self.plot_time_tr, self.plot_set_wl_tr)
		self.curve6.setData(self.plot_time_tr, self.plot_real_wl_tr)
		
		
	def make_update3(self):
		
		self.plot_wl = []
		self.plot_volts = []
		
		mycol=next(self.colors)
		self.curve1.extend( [self.p0.plot(pen=pg.mkPen(mycol,width=1), symbolPen=mycol, symbolBrush=mycol, symbolSize=3)] )
		
		
	def make_update4(self,val):
		
		self.lcdst.display(str(val)[:5])
		
		
	def set_disconnect(self):
		
		##########################################
		
		if self.inst_list.get("CM110"):
			if self.inst_list.get("CM110").is_open():
				self.inst_list.get("CM110").close()
			self.inst_list.pop("CM110", None)
				
		##########################################
		
		if self.inst_list.get("Ard"):
			if self.inst_list.get("Ard").is_open():
				self.inst_list.get("Ard").close()
			self.inst_list.pop("Ard", None)
			
		##########################################
		
		if self.inst_list.get("SR530"):
			if self.inst_list.get("SR530").is_open():
				self.inst_list.get("SR530").close()
			self.inst_list.pop("SR530", None)
			
		##########################################
		
		if self.inst_list.get("SMC100"):
			if self.inst_list.get("SMC100").is_open():
				self.inst_list.get("SMC100").close()
			self.inst_list.pop("SMC100", None)
			
		##########################################
		
		print("All com ports DISCONNECTED")
		
		self.allFields(False)
		self.conMode.setEnabled(True)
		self.runButton.setText("Load instrument!")
		self.runButton.setEnabled(False)
		
		
	def set_stop(self):
		
		self.stopButton.setEnabled(False)
		self.stopButton.setText("Stopped")
		
		if hasattr(self, "get_thread"):
			self.get_thread.abort()
			
		self.stop_pressed = True
		
		
	def clear_vars_graphs(self):
		
		# PLOT 1 initial canvas settings
		self.set_wl=[]
		self.real_wl=[]
		self.all_volts=[]
		self.all_times=[]
		self.all_raw=[]
		self.plot_set_wl=[]
		self.plot_real_wl=[]
		self.plot_raw=[]
		self.plot_volts=[]
		self.plot_wl=[]
		for c in self.curve1:
			c.setData([],[])
		self.curve5.setData(self.plot_set_wl, self.plot_raw)
		self.curve3.setData([], [])
		self.pw1.enableAutoRange()
		# Labels and titels are placed here since they change dynamically
		self.pw1.setTitle(''.join(["CM110 scan as function of wavelength"]))
		self.pw1.setLabel('left', "Voltage", units='V')
		self.pw1.setLabel('bottom', "Wavelength", units='m')
		
		# PLOT 2 initial canvas settings
		self.set_wl_tr=[]
		self.real_wl_tr=[]
		self.plot_set_wl_tr=[]
		self.plot_real_wl_tr=[]
		self.plot_volts_tr=[]
		self.plot_time_tr=[]
		self.curve2.setData(self.plot_time_tr, self.plot_volts_tr)
		self.curve4.setData(self.plot_time_tr, self.plot_set_wl_tr)
		self.curve6.setData(self.plot_time_tr, self.plot_real_wl_tr)
		self.pw2.enableAutoRange()
		# Labels and titels are placed here since they change dynamically
		self.p1.setTitle(''.join(["CM110 scan as function of time"]))
		self.p1.setLabel('left', "Voltage", units='V', color='red')
		self.p1.setLabel('bottom', "Elapsed time", units='s')
		
		self.stop_pressed = False
		
		
	def load_(self):
		
		# Initial read of the config file
		self.config = configparser.ConfigParser()
		try:
			self.config.read(''.join([self.cwd,os.sep,"config.ini"]))
			self.last_used_scan = self.config.get("LastScan","last_used_scan")
			
			self.numofintervals = int(self.config.get(self.last_used_scan,"numofintervals"))
			self.start_ = [int(i) for i in self.config.get(self.last_used_scan,"start").strip().split(',')]
			self.stop = [int(i) for i in self.config.get(self.last_used_scan,"stop").strip().split(',')]
			self.step = [int(i) for i in self.config.get(self.last_used_scan,"step").strip().split(',')]
			
			self.startst = float(self.config.get(self.last_used_scan,"startst"))
			self.stopst = float(self.config.get(self.last_used_scan,"stopst"))
			self.stepst = float(self.config.get(self.last_used_scan,"stepst"))
			
			self.dwell_time = [int(i) for i in self.config.get(self.last_used_scan,"wait_time").strip().split(',')]
			self.dwell_time_ard = int(self.config.get(self.last_used_scan,"wait_time_ard"))
			self.avg_pts = int(self.config.get(self.last_used_scan,"avg_pts"))
			self.schroll_time = int(self.config.get(self.last_used_scan,"schroll_time"))
			self.schroll_wl = int(self.config.get(self.last_used_scan,"schroll_wl"))
			
			self.filename_str = self.config.get(self.last_used_scan,"filename")
			self.timestr = self.config.get(self.last_used_scan,"timestr")
			self.analogref = float(self.config.get(self.last_used_scan,"analogref"))
			self.minutes = float(self.config.get(self.last_used_scan,"timer"))
			
		except configparser.NoOptionError as nov:
			QMessageBox.critical(self, "Message","".join(["Main FAULT while reading the config.ini file\n",str(nov)]))
			raise
		
		
	def save_(self):
		
		self.timestr=time.strftime("%y%m%d-%H%M")
		self.lcd.display(self.timestr)
		
		self.config.set("LastScan","last_used_scan", self.last_used_scan )
		
		self.config.set(self.last_used_scan,"numofintervals",str(self.numofintervals) )
		self.config.set(self.last_used_scan,"start",','.join([str(self.startEdit[ii].text()) for ii in range(self.numofintervals)]) )
		self.config.set(self.last_used_scan,"stop",','.join([str(self.stopEdit[ii].text()) for ii in range(self.numofintervals)]) )
		self.config.set(self.last_used_scan,"step",','.join([str(self.stepEdit[ii].text()) for ii in range(self.numofintervals)]) )
		self.config.set(self.last_used_scan,"wait_time",','.join([str(self.dwelltimeEdit[ii].text()) for ii in range(self.numofintervals)]) )
		
		self.config.set(self.last_used_scan,"startst", str(self.startst_Edit.text()) )
		self.config.set(self.last_used_scan,"stopst", str(self.stopst_Edit.text()) )
		self.config.set(self.last_used_scan,"stepst", str(self.stepst_Edit.text()) )
		
		self.config.set(self.last_used_scan,"wait_time_ard", str(self.dwelltimeEdit_ard.text()) )
		self.config.set(self.last_used_scan,"avg_pts", str(self.avg_pts) )
		self.config.set(self.last_used_scan,"schroll_time", str(self.schroll_time) )
		self.config.set(self.last_used_scan,"schroll_wl", str(self.schroll_wl) )
		
		self.config.set(self.last_used_scan,"filename", self.filenameEdit.text() )
		self.config.set(self.last_used_scan,"timestr", str(self.timestr) )
		self.config.set(self.last_used_scan,"analogref", str(self.analogref) )
		
		with open(''.join([self.cwd,os.sep,"config.ini"]), "w") as configfile:
			self.config.write(configfile)
		
		
	def finished(self):
		
		if not self.stop_pressed:
			self.stopButton.setEnabled(False)
			if hasattr(self, "get_thread"):
				self.get_thread.abort()
			
			self.stop_pressed = True
		
		self.allFields(True)
		self.conMode.setEnabled(True)
		
		if self.inst_list.get("CM110") or self.inst_list.get("SR530") or self.inst_list.get("Ard") or self.inst_list.get("SMC100"):
			self.allFields(True)
			self.runButton.setText("Scan")
		else:
			self.allFields(False)
			self.runButton.setText("Load instrument!")
		
		self.timer.start(1000*60*self.minutes)
		
		
	def closeEvent(self, event):
		
		reply = QMessageBox.question(self, 'Message', "Quit now? Any changes that are not saved will stay unsaved!", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
		
		if reply == QMessageBox.Yes:
			
			if self.inst_list.get("CM110"):
				if not hasattr(self, "get_thread"):
					if self.inst_list.get("CM110").is_open():
						self.inst_list.get("CM110").close()
				else:
					if not self.stop_pressed:
						QMessageBox.warning(self, "Message", "Scan in progress. Stop the scan then quit!")
						event.ignore()
						return
					else:
						if self.inst_list.get("CM110").is_open():
							self.inst_list.get("CM110").close()
							
			if self.inst_list.get("SR530"):
				if not hasattr(self, "get_thread"):
					if self.inst_list.get("SR530").is_open():
						self.inst_list.get("SR530").close()
				else:
					if not self.stop_pressed:
						QMessageBox.warning(self, "Message", "Scan in progress. Stop the scan then quit!")
						event.ignore()
						return
					else:
						if self.inst_list.get("SR530").is_open():
							self.inst_list.get("SR530").close()
			
			if self.inst_list.get("SMC100"):
				if not hasattr(self, "get_thread"):
					if self.inst_list.get("SMC100").is_open():
						self.inst_list.get("SMC100").close()
				else:
					if not self.stop_pressed:
						QMessageBox.warning(self, "Message", "Scan in progress. Stop the scan then quit!")
						event.ignore()
						return
					else:
						if self.inst_list.get("SMC100").is_open():
							self.inst_list.get("SMC100").close()
							
			if self.inst_list.get("Ard"):
				if not hasattr(self, "get_thread"):
					if self.inst_list.get("Ard").is_open():
						self.inst_list.get("Ard").close()
				else:
					if not self.stop_pressed:
						QMessageBox.warning(self, "Message", "Scan in progress. Stop the scan then quit!")
						event.ignore()
						return
					else:
						if self.inst_list.get("Ard").is_open():
							self.inst_list.get("Ard").close()
							
			if hasattr(self, "timer"):
				if self.timer.isActive():
					self.timer.stop()
					
			event.accept()
		else:
		  event.ignore()
		
	##########################################
	
	def save_plots(self):
		
		# For SAVING data
		if "\\" in self.filenameEdit.text():
			self.filenameEdit.setText(self.filenameEdit.text().replace("\\",os.sep))
			
		if "/" in self.filenameEdit.text():
			self.filenameEdit.setText(self.filenameEdit.text().replace("/",os.sep))
			
		if not self.filenameEdit.text():
			self.filenameEdit.setText(''.join(["data",os.sep,"data"]))
		
		if not os.sep in self.filenameEdit.text():
			self.filenameEdit.setText(''.join(["data", os.sep, self.filenameEdit.text()]))
			
		save_plot1 = self.create_file(''.join([self.filenameEdit.text(),".png"]))
		save_plot2 = self.create_file(''.join([self.filenameEdit.text(),"_elapsedtime",".png"]))
		
		# create an exporter instance, as an argument give it
		# the item you wish to export
		exporter = pg.exporters.ImageExporter(self.pw1.plotItem)
		exporter.params.param('width').setValue(1920, blockSignal=exporter.widthChanged)
		exporter.params.param('height').setValue(1080, blockSignal=exporter.heightChanged)
		# set export parameters if needed
		#exporter.parameters()['width'] = 100   # (note this also affects height parameter)
		# save to file
		exporter.export(save_plot1)
		
		exporter = pg.exporters.ImageExporter(self.pw2.plotItem)
		exporter.params.param('width').setValue(1920, blockSignal=exporter.widthChanged)
		exporter.params.param('height').setValue(1080, blockSignal=exporter.heightChanged)
		# set export parameters if needed
		#exporter.parameters()['width'] = 100   # (note this also affects height parameter)
		# save to file
		exporter.export(save_plot2)
class MyWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MyWindow, self).__init__()
        self.setObjectName("MediathekQuery")
        self.root = QFileInfo(__file__).absolutePath()
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.settings = QSettings('Axel Schneider', self.objectName())
        self.viewer = QTableWidget()
        
        
        self.horizontalHeader = self.viewer.horizontalHeader()
        
        icon = self.root + "/icon.png"
        
        self.titleList = []
        self.topicList = []
        self.urlList = []
        self.urlKleinList = []
        self.beschreibungList = []
        self.idList = []
        self.chList = []
        self.lengthList = []
        self.results = ""
        
        self.myurl = ""
        self.fname = ""
        self.viewer.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.viewer.SelectionMode(QAbstractItemView.SingleSelection)
        self.viewer.setSortingEnabled(False)
        self.viewer.verticalHeader().setStretchLastSection(False)
        self.viewer.horizontalHeader().setStretchLastSection(True)

        self.viewer.setColumnCount(7)
        self.viewer.setColumnWidth(0, 48)
        self.viewer.setColumnWidth(1, 130)
        self.viewer.setColumnWidth(2, 160)
        self.viewer.setColumnWidth(3, 60)
        self.viewer.hideColumn(4)
        self.viewer.hideColumn(5)
        self.viewer.setHorizontalHeaderLabels(["Sender", "Thema", "Titel", "Länge", "HD", "SD", "Beschreibung"])

        self.viewer.verticalHeader().setVisible(True)
        self.viewer.horizontalHeader().setVisible(True)
        self.setStyleSheet(stylesheet(self))        
        self.viewer.selectionModel().selectionChanged.connect(self.getCellText)
        
        self.layout = QGridLayout()
        self.layout.addWidget(self.viewer,0, 0, 1, 7)

        self.findfield = QLineEdit()
        self.fAction = QAction(QIcon.fromTheme("edit-clear"), "", triggered = self.findfieldAction)
        self.findfield.addAction(self.fAction, 1)
        self.findfield.returnPressed.connect(self.myQuery)
        self.findfield.setFixedWidth(200)
        self.findfield.setPlaceholderText("suchen ...")
        self.findfield.setToolTip("ENTER to find")
        self.layout.addWidget(self.findfield,1, 0)
        
        self.chCombo = QComboBox()
        self.chCombo.setFixedWidth(80)
        self.chCombo.addItems(['ARD', 'ZDF', 'MDR', 'PHOENIX', 'RBB', 'BR', 'HR', 'SR', \
                               'SWR', 'NDR', 'DW', 'WDR', 'ARTE', '3SAT', 'KIKA', 'ORF', 'SRF'])
        self.chCombo.addItem("alle")
        self.chCombo.setToolTip("Sender wählen")
        self.chCombo.currentIndexChanged.connect(self.myQuery)
        self.layout.addWidget(self.chCombo,1, 1)
        
        self.btnPlay = QPushButton("Play")
        self.btnPlay.setFixedWidth(80)
        self.btnPlay.setIcon(QIcon.fromTheme("media-playback-start"))
        self.layout.addWidget(self.btnPlay,1, 2)
        self.btnPlay.clicked.connect(self.playVideo)
        
        self.btnDownload = QPushButton("Download")
        self.btnDownload.setFixedWidth(100)
        self.btnDownload.setIcon(QIcon.fromTheme("download"))
        self.layout.addWidget(self.btnDownload,1, 3)
        self.btnDownload.clicked.connect(self.downloadVideo)
        
        self.chBox = QPushButton("SD")
        self.chBox.setToolTip("umschalten HD / SD")
        self.chBox.setStyleSheet("background: #729fcf;")
        self.chBox.setFixedWidth(44)
        self.chBox.clicked.connect(self.toggleQuality)
        self.layout.addWidget(self.chBox,1, 4)
        
        self.lbl = QLabel("Info")
        self.layout.addWidget(self.lbl,1, 5)

        self.chkbox = QCheckBox("nach Filmlänge sortieren")
        self.layout.addWidget(self.chkbox,1, 6)
        self.chkbox.setCheckState(0)
        self.chkbox.setToolTip("Standard-Sortierung ist nach Erscheinungsdatum")
        self.chkbox.stateChanged.connect(self.myQuery)
        
        self.myWidget = QWidget()
        self.myWidget.setLayout(self.layout)

        self.msg("Ready")
        self.setCentralWidget(self.myWidget)
        self.setWindowIcon(QIcon(icon))
        self.setGeometry(20,20,600,450)
        self.setWindowTitle("Mediathek Suche")
        self.readSettings()
        self.msg("Ready")
        self.findfield.setFocus()
        self.player = MediathekPlayer.VideoPlayer('')
        self.player.hide()
        wildcards = "Wildcards:    + Titel    # Thema    * Beschreibung\n '<xx Suchbegriff' kleiner als xx Minuten    '>xx Suchbegriff' grösser als xx Minuten "
        help_label = QLabel(wildcards)
        help_label.setToolTip("ohne Wildcard werden alle Felder durchsucht")
        help_label.setStyleSheet("font-size: 8pt; color: #1a2334;")
        self.statusBar().addPermanentWidget(help_label)
        self.statusBar().showMessage("Ready")
        
    def toggleQuality(self):
        if self.chBox.text() == "SD":
            self.chBox.setText("HD")
            self.chBox.setStyleSheet("background: #8ae234;")
            self.getCellText()
        else:
            self.chBox.setText("SD")
            self.chBox.setStyleSheet("background: #729fcf;")
            self.getCellText()
        
    def myQuery(self):
        if not self.findfield.text() == "":
            self.viewer.setRowCount(0)
            self.viewer.clearContents()
            self.titleList = []
            self.topicList = []
            self.urlList = []
            self.urlKleinList = []
            self.beschreibungList = []
            self.idList = []
            self.chList = []
            self.lengthList = []

            channels = [self.chCombo.currentText()]
            if channels == ["alle"]:
                channels = ["ard", "zdf", "mdr", "phoenix", "rbb", "br", "hr", "sr", "swr", "ndr",\
                            "dw", "wdr", "arte", "3sat", "kika", "orf", "srf"]
            print("suche",  self.findfield.text(), "in", ','.join(channels).upper())
            
            if self.findfield.text().startswith("*"):
                ### nur Beschreibung
                for ch in channels:
                    r = self.makeQueryBeschreibung(ch, self.findfield.text()[1:])
            elif self.findfield.text().startswith("#"):
                ### nur Thema
                for ch in channels:
                    r = self.makeQueryTopic(ch, self.findfield.text()[1:])
            elif self.findfield.text().startswith("+"):
                ### nur Titel
                for ch in channels:
                    r = self.makeQueryTitle(ch, self.findfield.text()[1:])
            elif self.findfield.text().startswith(">"):
                ### Zeit grösser
                for ch in channels:
                    r = self.makeQueryBigger(ch, self.findfield.text())
            elif self.findfield.text().startswith("<"):
                ### Zeit kleiner
                for ch in channels:
                    r = self.makeQuerySmaller(ch, self.findfield.text())
            else:
                ### alle Felder
                for ch in channels:
                    r = self.makeQuery(ch, self.findfield.text())

            for b in range(len(self.titleList)):
                self.idList.append(str(b))
            self.viewer.setSortingEnabled(False)   
            for x in range(len(self.titleList)):
                self.viewer.insertRow(x)
                self.viewer.setItem(x, 0, QTableWidgetItem(self.chList[x]))
                self.viewer.setItem(x, 1, QTableWidgetItem(self.topicList[x]))
                self.viewer.setItem(x, 2, QTableWidgetItem(self.titleList[x]))
                self.viewer.setItem(x, 3, QTableWidgetItem(self.lengthList[x]))
                self.viewer.setItem(x, 4, QTableWidgetItem(self.urlList[x]))
                self.viewer.setItem(x, 5, QTableWidgetItem(self.urlKleinList[x]))
                self.viewer.setItem(x, 6, QTableWidgetItem(self.beschreibungList[x]))
            for x in range(len(self.titleList)):
                self.viewer.resizeRowToContents(x)

        
    def makeQuery(self, channel, myquery):
        headers = {
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0',
            'Accept': '*/*',
            'Accept-Language': 'de-DE,en;q=0.5',
            'Content-Type': 'text/plain;charset=UTF-8',
            'Connection': 'keep-alive',
        }
        if self.chkbox.checkState() == 2:
            data = {"future":"true", "size":"500", "sortBy":"duration", "sortOrder":"desc", \
                    "queries":[{"fields":["title", "topic", "description"],
                    "query":"" + myquery + ""},{"fields":["channel"],
                    "query":"" + channel + ""}]}
        else:
            data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"asc", \
                    "queries":[{"fields":["title", "topic", "description"],
                    "query":"" + myquery + ""},{"fields":["channel"],
                    "query":"" + channel + ""}]}            
        
        response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data)
        response_json = response.json()
        count = int(response_json['result']['queryInfo']['resultCount'])
        for x in range(count):
            topic = response_json['result']['results'][x]['topic']
            title = response_json['result']['results'][x]['title']
            url = response_json['result']['results'][x]['url_video']
            url_klein = response_json['result']['results'][x]['url_video_low']
            beschreibung = response_json['result']['results'][x]['description']
            l = response_json['result']['results'][x]['duration']
            if not l == "":
                length = time.strftime('%H:%M:%S', time.gmtime(l))
                self.lengthList.append(length)
            else:
                self.lengthList.append("")
            ch = response_json['result']['results'][x]['channel']
            if not ch == "":
                self.chList.append(ch)
            else:
                self.chList.append("")
            if not title == "":    
                self.titleList.append(title)
            else:
                self.titleList.append("")
            if not topic == "":
                self.topicList.append(topic)
            else:
                self.topicList.append("")
            if not url == "":
                self.urlList.append(url)
            else:
                self.urlList.append("")
            if not url_klein == "":
                self.urlKleinList.append(url_klein)
            else:
                self.urlKleinList.append("")
            if not beschreibung == "":
                self.beschreibungList.append(beschreibung)
            else:
                self.beschreibungList.append("")
            
        print(count, "Beiträge gefunden")
        self.lbl.setText(f"{count} Beiträge gefunden")
        
    def makeQueryBeschreibung(self, channel, myquery):
        headers = {
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0',
            'Accept': '*/*',
            'Accept-Language': 'de-DE,en;q=0.5',
            'Content-Type': 'text/plain;charset=UTF-8',
            'Connection': 'keep-alive',
        }
        
        data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"desc", \
                "queries":[{"fields":["description"],
                "query":"" + myquery + ""},{"fields":["channel"],
                "query":"" + channel + ""}]}
        
        response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data)
        response_json = response.json()
        count = int(response_json['result']['queryInfo']['resultCount'])
        for x in range(count):
            topic = response_json['result']['results'][x]['topic']
            title = response_json['result']['results'][x]['title']
            url = response_json['result']['results'][x]['url_video']
            url_klein = response_json['result']['results'][x]['url_video_low']
            beschreibung = response_json['result']['results'][x]['description']
            l = response_json['result']['results'][x]['duration']
            if not l == "":
                length = time.strftime('%H:%M:%S', time.gmtime(l))
                self.lengthList.append(length)
            else:
                self.lengthList.append("")
            ch = response_json['result']['results'][x]['channel']
            if not ch == "":
                self.chList.append(ch)
            else:
                self.chList.append("")
            if not title == "":    
                self.titleList.append(title)
            else:
                self.titleList.append("")
            if not topic == "":
                self.topicList.append(topic)
            else:
                self.topicList.append("")
            if not url == "":
                self.urlList.append(url)
            else:
                self.urlList.append("")
            if not url_klein == "":
                self.urlKleinList.append(url_klein)
            else:
                self.urlKleinList.append("")
            if not beschreibung == "":
                self.beschreibungList.append(beschreibung)
            else:
                self.beschreibungList.append("")
            
        print(count, "Beiträge gefunden")
        self.lbl.setText(f"{count} Beiträge gefunden")
        
    def makeQueryTopic(self, channel, myquery):
        headers = {
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0',
            'Accept': '*/*',
            'Accept-Language': 'de-DE,en;q=0.5',
            'Content-Type': 'text/plain;charset=UTF-8',
            'Connection': 'keep-alive',
        }
        
        data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"desc", \
                "queries":[{"fields":["topic"],
                "query":"" + myquery + ""},{"fields":["channel"],
                "query":"" + channel + ""}]}
        
        response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data)
        response_json = response.json()
        count = int(response_json['result']['queryInfo']['resultCount'])
        for x in range(count):
            topic = response_json['result']['results'][x]['topic']
            title = response_json['result']['results'][x]['title']
            url = response_json['result']['results'][x]['url_video']
            url_klein = response_json['result']['results'][x]['url_video_low']
            beschreibung = response_json['result']['results'][x]['description']
            l = response_json['result']['results'][x]['duration']
            if not l == "":
                length = time.strftime('%H:%M:%S', time.gmtime(l))
                self.lengthList.append(length)
            else:
                self.lengthList.append("")
            ch = response_json['result']['results'][x]['channel']
            if not ch == "":
                self.chList.append(ch)
            else:
                self.chList.append("")
            if not title == "":    
                self.titleList.append(title)
            else:
                self.titleList.append("")
            if not topic == "":
                self.topicList.append(topic)
            else:
                self.topicList.append("")
            if not url == "":
                self.urlList.append(url)
            else:
                self.urlList.append("")
            if not url_klein == "":
                self.urlKleinList.append(url_klein)
            else:
                self.urlKleinList.append("")
            if not beschreibung == "":
                self.beschreibungList.append(beschreibung)
            else:
                self.beschreibungList.append("")
            
        print(count, "Beiträge gefunden")
        self.lbl.setText(f"{count} Beiträge gefunden")
        
    def makeQueryTitle(self, channel, myquery):
        headers = {
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0',
            'Accept': '*/*',
            'Accept-Language': 'de-DE,en;q=0.5',
            'Content-Type': 'text/plain;charset=UTF-8',
            'Connection': 'keep-alive',
        }
        
        data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"desc", \
                "queries":[{"fields":["title"],
                "query":"" + myquery + ""},{"fields":["channel"],
                "query":"" + channel + ""}]}
        
        response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data)
        response_json = response.json()
        count = int(response_json['result']['queryInfo']['resultCount'])
        for x in range(count):
            topic = response_json['result']['results'][x]['topic']
            title = response_json['result']['results'][x]['title']
            url = response_json['result']['results'][x]['url_video']
            url_klein = response_json['result']['results'][x]['url_video_low']
            beschreibung = response_json['result']['results'][x]['description']
            l = response_json['result']['results'][x]['duration']
            if not l == "":
                length = time.strftime('%H:%M:%S', time.gmtime(l))
                self.lengthList.append(length)
            else:
                self.lengthList.append("")
            ch = response_json['result']['results'][x]['channel']
            if not ch == "":
                self.chList.append(ch)
            else:
                self.chList.append("")
            if not title == "":    
                self.titleList.append(title)
            else:
                self.titleList.append("")
            if not topic == "":
                self.topicList.append(topic)
            else:
                self.topicList.append("")
            if not url == "":
                self.urlList.append(url)
            else:
                self.urlList.append("")
            if not url_klein == "":
                self.urlKleinList.append(url_klein)
            else:
                self.urlKleinList.append("")
            if not beschreibung == "":
                self.beschreibungList.append(beschreibung)
            else:
                self.beschreibungList.append("")
            
        print(count, "Beiträge gefunden")
        self.lbl.setText(f"{count} Beiträge gefunden")
        
#######################################################################
    def makeQueryBigger(self, channel, myquery):
        headers = {
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0',
            'Accept': '*/*',
            'Accept-Language': 'de-DE,en;q=0.5',
            'Content-Type': 'text/plain;charset=UTF-8',
            'Connection': 'keep-alive',
        }
        if self.chkbox.checkState() == 2:
            data = {"future":"true", "size":"500", "sortBy":"duration", "sortOrder":"desc", \
                    "queries":[{"fields":["duration"],
                    "query":"" + myquery[1:].partition(" ")[2] + ""},{"fields":["channel"],
                    "query":"" + channel + ""}]}
        else:
            data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"asc", \
                    "queries":[{"fields":["title", "topic", "description"],
                    "query":"" + myquery[1:].partition(" ")[2] + ""},{"fields":["channel"],
                    "query":"" + channel + ""}]}            
        
        response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data)
        response_json = response.json()
        count = int(response_json['result']['queryInfo']['resultCount'])
        for x in range(count):
            topic = response_json['result']['results'][x]['topic']
            title = response_json['result']['results'][x]['title']
            url = response_json['result']['results'][x]['url_video']
            url_klein = response_json['result']['results'][x]['url_video_low']
            beschreibung = response_json['result']['results'][x]['description']
            l = response_json['result']['results'][x]['duration']
            if not l == "":
                length = time.strftime('%H:%M:%S', time.gmtime(l))
                mydur = myquery[1:].partition(" ")[0]
                hour = time.strftime('%H', time.gmtime(l))
                minute = time.strftime('%M', time.gmtime(l))
                dur = int(hour) * 60 + int(minute)
                if dur > int(mydur) - 1:
                    self.lengthList.append(length)
                    ch = response_json['result']['results'][x]['channel']
                    if not ch == "":
                        self.chList.append(ch)
                    else:
                        self.chList.append("")
                    if not title == "":    
                        self.titleList.append(title)
                    else:
                        self.titleList.append("")
                    if not topic == "":
                        self.topicList.append(topic)
                    else:
                        self.topicList.append("")
                    if not url == "":
                        self.urlList.append(url)
                    else:
                        self.urlList.append("")
                    if not url_klein == "":
                        self.urlKleinList.append(url_klein)
                    else:
                        self.urlKleinList.append("")
                    if not beschreibung == "":
                        self.beschreibungList.append(beschreibung)
                    else:
                        self.beschreibungList.append("")
            
        print(count, "Beiträge gefunden")
        self.lbl.setText(f"{count} Beiträge gefunden")
#######################################################################
    def makeQuerySmaller(self, channel, myquery):
        headers = {
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0',
            'Accept': '*/*',
            'Accept-Language': 'de-DE,en;q=0.5',
            'Content-Type': 'text/plain;charset=UTF-8',
            'Connection': 'keep-alive',
        }
        if self.chkbox.checkState() == 2:
            data = {"future":"true", "size":"500", "sortBy":"duration", "sortOrder":"desc", \
                    "queries":[{"fields":["duration"],
                    "query":"" + myquery[1:].partition(" ")[2] + ""},{"fields":["channel"],
                    "query":"" + channel + ""}]}
        else:
            data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"asc", \
                    "queries":[{"fields":["title", "topic", "description"],
                    "query":"" + myquery[1:].partition(" ")[2] + ""},{"fields":["channel"],
                    "query":"" + channel + ""}]}            
        
        response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data)
        response_json = response.json()
        count = int(response_json['result']['queryInfo']['resultCount'])
        for x in range(count):
            topic = response_json['result']['results'][x]['topic']
            title = response_json['result']['results'][x]['title']
            url = response_json['result']['results'][x]['url_video']
            url_klein = response_json['result']['results'][x]['url_video_low']
            beschreibung = response_json['result']['results'][x]['description']
            l = response_json['result']['results'][x]['duration']
            if not l == "":
                length = time.strftime('%H:%M:%S', time.gmtime(l))
                mydur = myquery[1:].partition(" ")[0]
                hour = time.strftime('%H', time.gmtime(l))
                minute = time.strftime('%M', time.gmtime(l))
                dur = int(hour) * 60 + int(minute)
                if dur < int(mydur):
                    self.lengthList.append(length)
                    ch = response_json['result']['results'][x]['channel']
                    if not ch == "":
                        self.chList.append(ch)
                    else:
                        self.chList.append("")
                    if not title == "":    
                        self.titleList.append(title)
                    else:
                        self.titleList.append("")
                    if not topic == "":
                        self.topicList.append(topic)
                    else:
                        self.topicList.append("")
                    if not url == "":
                        self.urlList.append(url)
                    else:
                        self.urlList.append("")
                    if not url_klein == "":
                        self.urlKleinList.append(url_klein)
                    else:
                        self.urlKleinList.append("")
                    if not beschreibung == "":
                        self.beschreibungList.append(beschreibung)
                    else:
                        self.beschreibungList.append("")
            
        print(count, "Beiträge gefunden")
        self.lbl.setText(f"{count} Beiträge gefunden")
#######################################################################

    def findfieldAction(self):
        self.findfield.setText("")
        
    def downloadVideo(self):
        if not self.url == "":
            self.downloader = Downloader.Downloader()
            self.downloader.setWindowTitle("Downloader")
            self.downloader.url = self.url
            item = self.viewer.selectedIndexes()[2]
            if not item == "":
                filename = str(item.data())
            self.downloader.fname = filename + self.url[-4:]
            self.downloader.fname = self.downloader.fname.replace(' (', '_').replace(') ', '_')\
            .replace(')', '_').replace('/', '_')
            if '_.' in self.downloader.fname:
                self.downloader.fname = self.downloader.fname.replace('_.', '.')
            self.downloader.lbl.setText("speichern als: " + self.downloader.homepath + self.downloader.fname)
            self.downloader.move(self.x() + 2, self.y() + 28)
            self.downloader.show()
        else:
            print("keine URL")
            self.msg("keine URL")
        
        
    def getCellText(self):
        if self.viewer.selectionModel().hasSelection():
            row = self.selectedRow()
            if not self.chBox.text() == "SD":
                item = self.urlList[row]
            else:
                item = self.urlKleinList[row]
            if not item == "":
                name = item
                self.url = str(item)
                QApplication.clipboard().setText(self.url)
                print(self.url)
            infotext = f"{self.chList[row]}: {self.topicList[row]} - {self.titleList[row]} \
                        ({self.chBox.text()}) Dauer: {self.lengthList[row]}"
            self.msg(infotext)
            self.fname = str(self.viewer.selectedIndexes()[1].data())

        
    def playVideo(self):
        if self.viewer.selectionModel().hasSelection():
            row = self.selectedRow()
            if not self.chBox.text() == "SD":
                item = item = self.urlList[row]
                print("play HD")
            else:
                item = self.urlKleinList[row]
                print("play SD")
            if not item == "":
                self.url = item
                if not self.url == "":
                    print("url =", self.url)
                    self.player.show()
                    self.player.playMyURL(self.url)
                else:
                    print("keine URL vorhanden")
                    self.msg("keine URL vorhanden")
            else:
                print("keine URL vorhanden")
        else:
            print("keine URL vorhanden")

    def selectedRow(self):
        if self.viewer.selectionModel().hasSelection():
            row =  self.viewer.selectionModel().selectedIndexes()[0].row()
            return int(row)           

    def closeEvent(self, e):
        self.writeSettings()
        self.player.close()
        e.accept()

    def readSettings(self):
        print("lese Fensterposition")
        if self.settings.contains('geometry'):
            self.setGeometry(self.settings.value('geometry'))

    def writeSettings(self):
        print("Fensterposition gespeichert")
        self.settings.setValue('geometry', self.geometry())

    def msg(self, message):
        self.statusBar().showMessage(message, 0)
class DyStockHistDaysDataSourceConfigDlg(QDialog):
    tradeDaysMode = OrderedDict\
                    ([
                        ('Wind和TuShare相互验证(默认)', 'Verify'),
                        ('若冲突,则以Wind为主', 'Wind'),
                        ('若冲突,则以TuShare为主', 'TuShare'),
                    ])

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

        self._read()
        self._initUi()
        
    def _initUi(self):
        self.setWindowTitle('配置-股票历史日线数据源')
 
        # 控件
        label = QLabel('股票历史日线数据源')

        self._windCheckBox = QCheckBox('Wind')
        self._windCheckBox.clicked.connect(self._windCheckBoxClicked)

        self._tuShareCheckBox = QCheckBox('TuShare')
        self._tuShareCheckBox.clicked.connect(self._tuShareCheckBoxClicked)

        self._tuShareProCheckBox = QCheckBox('TuSharePro')

        tuShareProTokenLabel = QLabel('TuSharePro token')
        self._tuShareProTokenLineEdit = QLineEdit()

        description = """默认使用Wind

只选Wind:更新交易日数据,股票代码表和股票历史日线数据到Wind对应的数据库

只选TuShare:更新交易日数据,股票代码表和股票历史日线数据到TuShare对应的数据库

选两个:更新交易日数据,股票代码表和股票历史日线数据到Wind对应的数据库,并同时做两个源的数据验证

交易日数据,股票代码表和股票历史日线数据的载入也是基于上面选择的数据库
        """
        textEdit = QTextEdit()
        textEdit.setPlainText(description)
        textEdit.setReadOnly(True)

        cancelPushButton = QPushButton('Cancel')
        okPushButton = QPushButton('OK')
        cancelPushButton.clicked.connect(self._cancel)
        okPushButton.clicked.connect(self._ok)

        self._tradeDaysComboBox = QComboBox()
        descriptionTradeDays = "Wind有时交易日数据可能出错,所以选Wind时,总是跟TuShare做验证,由用户选择该如何做。"
        tradeDaysTextEdit = QTextEdit()
        tradeDaysTextEdit.setPlainText(descriptionTradeDays)
        tradeDaysTextEdit.setReadOnly(True)

        self._tuShareDaysIntervalLineEdit = QLineEdit() # TuShare日线数据每次下载间隔时间(秒)
        self._tuShareProDaysIntervalLineEdit = QLineEdit() # TuSharePro日线数据每次下载间隔时间(秒)

        # 布局
        grid = QGridLayout()
        grid.setSpacing(10)
 
        grid.addWidget(label, 0, 0)
        grid.addWidget(self._windCheckBox, 1, 0)
        grid.addWidget(self._tuShareCheckBox, 2, 0)
        grid.addWidget(self._tuShareProCheckBox, 3, 0)
        grid.addWidget(tuShareProTokenLabel, 4, 0)
        grid.addWidget(self._tuShareProTokenLineEdit, 5, 0)

        grid.addWidget(textEdit, 6, 0)

        grid.addWidget(QLabel("                                                                 "), 7, 0)
        grid.addWidget(QLabel("交易日数据模式"), 8, 0)
        grid.addWidget(self._tradeDaysComboBox, 9, 0)
        grid.addWidget(tradeDaysTextEdit, 10, 0)

        grid.addWidget(QLabel("                                                                 "), 11, 0)
        grid.addWidget(QLabel("TuShare日线数据下载间隔时间(秒)"), 12, 0)
        grid.addWidget(self._tuShareDaysIntervalLineEdit, 13, 0)

        grid.addWidget(QLabel("TuSharePro日线数据下载间隔时间(秒)"), 14, 0)
        grid.addWidget(self._tuShareProDaysIntervalLineEdit, 15, 0)

        grid.addWidget(okPushButton, 0, 1)
        grid.addWidget(cancelPushButton, 1, 1)
 
        self.setLayout(grid)

        # set data source to UI
        if self._data.get('Wind'):
            self._windCheckBox.setChecked(True)

        if sys.platform != 'win32': # Wind only supported at Windows.
            self._windCheckBox.setEnabled(False)
            self._windCheckBox.setChecked(False)

        enableTuSharePro = False
        if self._data.get('TuShare'):
            self._tuShareCheckBox.setChecked(True)
            enableTuSharePro = True

        self._tuShareProCheckBox.setEnabled(enableTuSharePro)

        # set tushare pro
        enableTushareProToken = False
        if self._tuShareProData.get('TuSharePro'):
            self._tuShareProCheckBox.setChecked(True)
            enableTushareProToken = True

        if self._tuShareProData.get('Token'):
            self._tuShareProTokenLineEdit.setText(self._tuShareProData.get('Token'))

        # set according to days source checkbox
        self._tradeDaysComboBox.addItems(list(self.tradeDaysMode))
        self._enableTradeDaysComboBox()
        
        for k, v in self.tradeDaysMode.items():
            if v == self._tradeDaysModeData["tradeDaysMode"]:
                self._tradeDaysComboBox.setCurrentText(k)
                break

        # tushare days downloading interval
        self._tuShareDaysIntervalLineEdit.setText(str(self._tuShareDaysIntervalData['interval']))

        # tusharepro days downloading interval
        self._tuShareProDaysIntervalLineEdit.setText(str(self._tuShareProDaysIntervalData['interval']))

        self.resize(QApplication.desktop().size().width()//2, QApplication.desktop().size().height()//4*3)
        
    def _read(self):
        # data source
        file = DyStockConfig.getStockHistDaysDataSourceFileName()

        try:
            with open(file) as f:
                self._data = json.load(f)
        except:
            self._data = DyStockConfig.getDefaultHistDaysDataSource()

        # tushare pro
        file = DyStockConfig.getStockHistDaysTuShareProFileName()

        try:
            with open(file) as f:
                self._tuShareProData = json.load(f)
        except:
            self._tuShareProData = DyStockConfig.getDefaultHistDaysTuSharePro()

        # trade days mode
        file = DyStockConfig.getStockTradeDaysModeFileName()

        try:
            with open(file) as f:
                self._tradeDaysModeData = json.load(f)
        except:
            self._tradeDaysModeData = DyStockConfig.defaultTradeDaysMode

        # interval of tushare days downloading
        file = DyStockConfig.getStockTuShareDaysIntervalFileName()

        try:
            with open(file) as f:
                self._tuShareDaysIntervalData = json.load(f)
        except:
            self._tuShareDaysIntervalData = DyStockConfig.defaultTuShareDaysInterval

        # interval of tusharepro days downloading
        file = DyStockConfig.getStockTuShareProDaysIntervalFileName()

        try:
            with open(file) as f:
                self._tuShareProDaysIntervalData = json.load(f)
        except:
            self._tuShareProDaysIntervalData = DyStockConfig.defaultTuShareProDaysInterval

    def _ok(self):
        # data source
        data = {'Wind': False, 'TuShare': False}
        if self._windCheckBox.isChecked():
            data['Wind'] = True

        if self._tuShareCheckBox.isChecked():
            data['TuShare'] = True

        # config to variables
        DyStockConfig.configStockHistDaysDataSource(data)

        # save config
        file = DyStockConfig.getStockHistDaysDataSourceFileName()
        with open(file, 'w') as f:
            f.write(json.dumps(data, indent=4))

        # tushare pro
        data = {'TuSharePro': False, 'Token': None}
        if self._tuShareProCheckBox.isChecked():
            data['TuSharePro'] = True

        data['Token'] = self._tuShareProTokenLineEdit.text()

        DyStockConfig.configStockHistDaysTuSharePro(data)

        file = DyStockConfig.getStockHistDaysTuShareProFileName()
        with open(file, 'w') as f:
            f.write(json.dumps(data, indent=4))

        # trade days mode
        data = {}
        data["tradeDaysMode"] = self.tradeDaysMode[self._tradeDaysComboBox.currentText()]

        DyStockConfig.configStockTradeDaysMode(data)

        file = DyStockConfig.getStockTradeDaysModeFileName()
        with open(file, 'w') as f:
            f.write(json.dumps(data, indent=4))

        # tushare days downloading interval
        data = {}
        text = self._tuShareDaysIntervalLineEdit.text()
        try:
            data["interval"] = int(text)
        except:
            try:
                data["interval"] = float(text)
            except:
                data = DyStockConfig.defaultTuShareDaysInterval

        DyStockConfig.configStockTuShareDaysInterval(data)

        file = DyStockConfig.getStockTuShareDaysIntervalFileName()
        with open(file, 'w') as f:
            f.write(json.dumps(data, indent=4))

        # tusharepro days downloading interval
        data = {}
        text = self._tuShareProDaysIntervalLineEdit.text()
        try:
            data["interval"] = int(text)
        except:
            try:
                data["interval"] = float(text)
            except:
                data = DyStockConfig.defaultTuShareProDaysInterval

        DyStockConfig.configStockTuShareProDaysInterval(data)

        file = DyStockConfig.getStockTuShareProDaysIntervalFileName()
        with open(file, 'w') as f:
            f.write(json.dumps(data, indent=4))

        self.accept()

    def _cancel(self):
        self.reject()

    def _enableTradeDaysComboBox(self):
        if self._windCheckBox.isChecked():
            self._tradeDaysComboBox.setEnabled(True)
        else:
            self._tradeDaysComboBox.setEnabled(False)

    def _checkBoxClicked(self):
        if not self._windCheckBox.isChecked() and not self._tuShareCheckBox.isChecked():
            if sys.platform == 'win32':
                self._windCheckBox.setChecked(True)
            else:
                self._tuShareCheckBox.setChecked(True)

        self._enableTradeDaysComboBox()

    def _windCheckBoxClicked(self):
        self._checkBoxClicked()

    def _tuShareCheckBoxClicked(self):
        self._checkBoxClicked()

        enable = self._tuShareCheckBox.isChecked()
        self._tuShareProCheckBox.setEnabled(enable)
Exemple #60
-1
class EditForm(QDialog):
    def __init__(self):
        super(EditForm, self).__init__()
        self.initUI(self)

    def initUI(self, EditForm):
        layout = QGridLayout(self)

        self.title_label = QLabel("Title:")
        self.title_line_edit = QLineEdit()
        self.rating_label = QLabel("Rating:")
        self.rating_slider = QSlider(Qt.Horizontal)
        self.rating_slider.setMinimum(0)
        self.rating_slider.setMaximum(5)
        self.rating_slider.setValue(0)
        self.rating_slider.setTickPosition(QSlider.TicksBelow)
        self.rating_slider.setTickInterval(5)

        self.review_label = QLabel("Review:")
        self.review_text_edit = QTextEdit()

        self.status_label = QLabel("Status:")
        self.status_combo_box = QComboBox()
        self.status_combo_box.addItems(["Read",
                                        "Currently Reading",
                                        "Want Тo Read"])
        self.edit_button = QPushButton("Edit book")

        layout.addWidget(self.title_label, 0, 0)
        layout.addWidget(self.title_line_edit, 0, 1)
        layout.addWidget(self.rating_label, 1, 0)
        layout.addWidget(self.rating_slider, 1, 1)
        layout.addWidget(self.review_label, 2, 0)
        layout.addWidget(self.review_text_edit, 2, 1)
        layout.addWidget(self.status_label, 3, 0)
        layout.addWidget(self.status_combo_box, 3, 1)
        layout.addWidget(self.edit_button, 4, 0, 1, 2, Qt.AlignCenter)

        self.setLayout(layout)
        self.edit_button.clicked.connect(self.edit_button_click)
        self.layout().setSizeConstraint(QLayout.SetFixedSize)
        self.setWindowTitle("Edit Book")
        self.setWindowIcon(QIcon(QPixmap('../images/edit.png')))

    def edit_button_click(self):
        title = self.title_line_edit.text()
        rating = self.rating_slider.value()
        review = self.review_text_edit.toPlainText()
        status = self.status_combo_box.currentText()

        if select_by_title(string.capwords(title)) == []:
            QMessageBox(QMessageBox.Critical, "Error",
                        "There is no such book in the library!").exec_()
        else:
            if update_entry(string.capwords(title), rating, review, status):
                QMessageBox(QMessageBox.Information, "Updated book info",
                            "You updated the info about this book!").exec_()
            else:
                QMessageBox(QMessageBox.Information, "Information",
                            "The book was NOT edited! Try again.").exec_()