class ConnectionSettings(QWidget): def __init__(self): super(ConnectionSettings, self).__init__() self.name_label = QLabel("Grid name:") self.name_line_edit = QLineEdit() self.introducer_label = QLabel("Introducer fURL:") self.introducer_text_edit = QPlainTextEdit() self.introducer_text_edit.setMaximumHeight(70) self.introducer_text_edit.setTabChangesFocus(True) self.mode_label = QLabel("Connection mode:") self.mode_combobox = QComboBox() self.mode_combobox.addItem("Normal") self.mode_combobox.addItem("Tor") self.mode_combobox.model().item(1).setEnabled(False) self.mode_combobox.addItem("I2P") self.mode_combobox.model().item(2).setEnabled(False) form = QFormLayout(self) form.setWidget(0, QFormLayout.LabelRole, self.name_label) form.setWidget(0, QFormLayout.FieldRole, self.name_line_edit) form.setWidget(1, QFormLayout.LabelRole, self.introducer_label) form.setWidget(1, QFormLayout.FieldRole, self.introducer_text_edit) form.setWidget(2, QFormLayout.LabelRole, self.mode_label) form.setWidget(2, QFormLayout.FieldRole, self.mode_combobox)
class StaffGroup(_base.Container): @staticmethod def title(_=_base.translate): return _("Staff Group") def accepts(self): return (StaffGroup, _base.Part) def createWidgets(self, layout): self.systemStartLabel = QLabel() self.systemStart = QComboBox() self.systemStartLabel.setBuddy(self.systemStart) self.systemStart.setModel( listmodel.ListModel( ( # L10N: Brace like a piano staff (lambda: _("Brace"), 'system_start_brace'), # L10N: Bracket like a choir staff (lambda: _("Bracket"), 'system_start_bracket'), # L10N: Square bracket like a sub-group (lambda: _("Square"), 'system_start_square'), ), self.systemStart, display=listmodel.translate_index(0), icon=lambda item: symbols.icon(item[1]))) self.systemStart.setIconSize(QSize(64, 64)) self.connectBarLines = QCheckBox(checked=True) box = QHBoxLayout() box.addWidget(self.systemStartLabel) box.addWidget(self.systemStart) layout.addLayout(box) layout.addWidget(self.connectBarLines) def translateWidgets(self): self.systemStartLabel.setText(_("Type:")) self.connectBarLines.setText(_("Connect Barlines")) self.connectBarLines.setToolTip( _("If checked, barlines are connected between the staves.")) self.systemStart.model().update() def build(self, data, builder): s = self.systemStart.currentIndex() b = self.connectBarLines.isChecked() if s == 0: node = ly.dom.GrandStaff() if not b: ly.dom.Line("\\remove Span_bar_engraver", node.getWith()) else: node = ly.dom.StaffGroup() if b else ly.dom.ChoirStaff() if s == 2: node.getWith()['systemStartDelimiter'] = ly.dom.Scheme( "'SystemStartSquare") data.nodes.append(node) data.music = ly.dom.Simr(node)
def addItem(combo: QComboBox, db_manager, data: dict, check=False) -> int: """добавление элемента""" display_key = combo.model().display if check: index = findItem(combo, data[display_key]) if index >= 0: return index table_class = getattr(combo.model(), 'TableClass') new_id = db_manager.createRecord(table_class, data) data.update({'ID': new_id}) combo.addItem(data[display_key], data) return combo.count() - 1
def add_combo_box(self, type): ''' This function is called inside add_question. It adds the combo box with the question types. Currently the Binary type is disabled because it has not been implemented into the player. ''' comboBox = QComboBox(self) comboBox.addItem(self.parent.MultiLang.find_correct_word("continuous")) comboBox.addItem("binary") comboBox.model().item(1).setEnabled(False) comboBox.setCurrentIndex(type) self.layout.addWidget(comboBox, self.number_of_fields + 1, 3) self.combo_box_list.append(comboBox)
class StaffGroup(_base.Container): @staticmethod def title(_=_base.translate): return _("Staff Group") def accepts(self): return (StaffGroup, _base.Part) def createWidgets(self, layout): self.systemStartLabel = QLabel() self.systemStart = QComboBox() self.systemStartLabel.setBuddy(self.systemStart) self.systemStart.setModel(listmodel.ListModel(( # L10N: Brace like a piano staff (lambda: _("Brace"), 'system_start_brace'), # L10N: Bracket like a choir staff (lambda: _("Bracket"), 'system_start_bracket'), # L10N: Square bracket like a sub-group (lambda: _("Square"), 'system_start_square'), ), self.systemStart, display=listmodel.translate_index(0), icon=lambda item: symbols.icon(item[1]))) self.systemStart.setIconSize(QSize(64, 64)) self.connectBarLines = QCheckBox(checked=True) box = QHBoxLayout() box.addWidget(self.systemStartLabel) box.addWidget(self.systemStart) layout.addLayout(box) layout.addWidget(self.connectBarLines) def translateWidgets(self): self.systemStartLabel.setText(_("Type:")) self.connectBarLines.setText(_("Connect Barlines")) self.connectBarLines.setToolTip(_("If checked, barlines are connected between the staves.")) self.systemStart.model().update() def build(self, data, builder): s = self.systemStart.currentIndex() b = self.connectBarLines.isChecked() if s == 0: node = ly.dom.GrandStaff() if not b: ly.dom.Line("\\remove Span_bar_engraver", node.getWith()) else: node = ly.dom.StaffGroup() if b else ly.dom.ChoirStaff() if s == 2: node.getWith()['systemStartDelimiter'] = ly.dom.Scheme("'SystemStartSquare") data.nodes.append(node) data.music = ly.dom.Simr(node)
class comics_template_dialog(QDialog): templateDirectory = str() templates = QComboBox() buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) def __init__(self, templateDirectory): super().__init__() self.templateDirectory = templateDirectory self.setWindowTitle(i18n("Add new Template")) self.setLayout(QVBoxLayout()) self.templates = QComboBox() self.templates.setEnabled(False) self.buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.buttons.accepted.connect(self.accept) self.buttons.rejected.connect(self.reject) self.buttons.button(QDialogButtonBox.Ok).setEnabled(False) mainWidget = QWidget() self.layout().addWidget(mainWidget) self.layout().addWidget(self.buttons) mainWidget.setLayout(QVBoxLayout()) btn_create = QPushButton(i18n("Create Template")) btn_create.clicked.connect(self.slot_create_template) btn_import = QPushButton(i18n("Import Templates")) btn_import.clicked.connect(self.slot_import_template) mainWidget.layout().addWidget(self.templates) mainWidget.layout().addWidget(btn_create) mainWidget.layout().addWidget(btn_import) self.fill_templates() def fill_templates(self): self.templates.clear() for entry in os.scandir(self.templateDirectory): if entry.name.endswith('.kra') and entry.is_file(): name = os.path.relpath(entry.path, self.templateDirectory) self.templates.addItem(name) if self.templates.model().rowCount() > 0: self.templates.setEnabled(True) self.buttons.button(QDialogButtonBox.Ok).setEnabled(True) def slot_create_template(self): create = comics_template_create(self.templateDirectory) if create.exec_() == QDialog.Accepted: if (create.prepare_krita_file()): self.fill_templates() def slot_import_template(self): filenames = QFileDialog.getOpenFileNames(caption=i18n("Which files should be added to the template folder?"), directory=self.templateDirectory, filter=str(i18n("Krita files") + "(*.kra)"))[0] for file in filenames: shutil.copy2(file, self.templateDirectory) self.fill_templates() def url(self): return os.path.join(self.templateDirectory, self.templates.currentText())
class ChordNames(object): def createWidgets(self, layout): self.chordStyleLabel = QLabel() self.chordStyle = QComboBox() self.chordStyleLabel.setBuddy(self.chordStyle) self.chordStyle.setModel( listmodel.ListModel(chordNameStyles, self.chordStyle, display=listmodel.translate)) self.guitarFrets = QCheckBox() box = QHBoxLayout() box.addWidget(self.chordStyleLabel) box.addWidget(self.chordStyle) layout.addLayout(box) layout.addWidget(self.guitarFrets) def translateWidgets(self): self.chordStyleLabel.setText(_("Chord style:")) self.guitarFrets.setText(_("Guitar fret diagrams")) self.guitarFrets.setToolTip( _("Show predefined guitar fret diagrams below the chord names " "(LilyPond 2.12 and above).")) self.chordStyle.model().update() def build(self, data, builder): p = ly.dom.ChordNames() a = data.assign('chordNames') ly.dom.Identifier(a.name, p) s = ly.dom.ChordMode(a) ly.dom.Identifier(data.globalName, s).after = 1 i = self.chordStyle.currentIndex() if i > 0: ly.dom.Line( '\\{0}Chords'.format( ('german', 'semiGerman', 'italian', 'french')[i - 1]), s) ly.dom.LineComment(_("Chords follow here."), s) ly.dom.BlankLine(s) data.nodes.append(p) if self.guitarFrets.isChecked(): f = ly.dom.FretBoards() ly.dom.Identifier(a.name, f) data.nodes.append(f) data.includes.append("predefined-guitar-fretboards.ly")
def createDefaultWidget(self, parent): cboPorts = QComboBox() for port, name in QgsGpsDetector.availablePorts(): if port.startswith('COM'): cboPorts.addItem(name, port) cboPorts.model().sort(0) port = self.getPort() cboPorts.currentIndexChanged.connect( lambda: self.setPort(cboPorts.currentData())) idx = cboPorts.findData(port) if idx == -1: idx = 1 cboPorts.setCurrentIndex(idx) # create the widget wid = QWidget(parent) layout = QHBoxLayout(wid) layout.addWidget(QLabel('GPS:')) layout.addWidget(cboPorts) wid.setLayout(layout) return wid
class ChordNames(object): def createWidgets(self, layout): self.chordStyleLabel = QLabel() self.chordStyle = QComboBox() self.chordStyleLabel.setBuddy(self.chordStyle) self.chordStyle.setModel(listmodel.ListModel(chordNameStyles, self.chordStyle, display=listmodel.translate)) self.guitarFrets = QCheckBox() box = QHBoxLayout() box.addWidget(self.chordStyleLabel) box.addWidget(self.chordStyle) layout.addLayout(box) layout.addWidget(self.guitarFrets) def translateWidgets(self): self.chordStyleLabel.setText(_("Chord style:")) self.guitarFrets.setText(_("Guitar fret diagrams")) self.guitarFrets.setToolTip(_( "Show predefined guitar fret diagrams below the chord names " "(LilyPond 2.12 and above).")) self.chordStyle.model().update() def build(self, data, builder): p = ly.dom.ChordNames() a = data.assign('chordNames') ly.dom.Identifier(a.name, p) s = ly.dom.ChordMode(a) ly.dom.Identifier(data.globalName, s).after = 1 i = self.chordStyle.currentIndex() if i > 0: ly.dom.Line('\\{0}Chords'.format( ('german', 'semiGerman', 'italian', 'french')[i-1]), s) ly.dom.LineComment(_("Chords follow here."), s) ly.dom.BlankLine(s) data.nodes.append(p) if self.guitarFrets.isChecked(): f = ly.dom.FretBoards() ly.dom.Identifier(a.name, f) data.nodes.append(f) data.includes.append("predefined-guitar-fretboards.ly")
def create_surface_dropdown(self, model_faces=None): """ Populates the surfaces dropdown """ self.model_faces = model_faces surfaces = QComboBox() if model_faces is not None: for i, face in enumerate(model_faces): if np.array_equal(face.normal.vec, [0.0, 1.0, 0.0]): faceStr = "Ceiling [" + str(i) + "]" elif np.array_equal(face.normal.vec, [0.0, -1.0, 0.0]): faceStr = "Floor [" + str(i) + "]" else: faceStr = "Wall [" + str(i) + "]" surfaces.addItem(faceStr, face) surfaces.addItem("All", None) surfaces.model().sort(0) return surfaces
def choose_standard_level(self): self.chooseStandardDialog = QDialog() layout = QGridLayout() noXMLLabel = QLabel("No XML found", self) layout.addWidget(noXMLLabel, 0, 0) chooseStandardLabel = QLabel("Standard", self) chooseStandardCombo = QComboBox(self) chooseStandardCombo.addItem("Factur-X") chooseStandardCombo.addItem("Zugferd") chooseStandardCombo.addItem("UBL") chooseStandardCombo.model().item(2).setEnabled(False) chooseStandardCombo.activated[str].connect(self.on_select_level) chooseLevelLabel = QLabel("Level", self) self.chooseLevelCombo = QComboBox(self) self.chooseLevelCombo.addItem("Minimum") self.chooseLevelCombo.addItem("Basic WL") self.chooseLevelCombo.addItem("Basic") self.chooseLevelCombo.addItem("EN16931") self.chooseLevelCombo.activated[str].connect(self.set_level) applyStandard = QPushButton("Apply") applyStandard.clicked.connect(self.set_standard_level) discardStandard = QPushButton("Cancel") discardStandard.clicked.connect(self.discard_standard_level) layout.addWidget(chooseStandardLabel, 1, 0) layout.addWidget(chooseStandardCombo, 1, 1) layout.addWidget(chooseLevelLabel, 2, 0) layout.addWidget(self.chooseLevelCombo, 2, 1) layout.addWidget(discardStandard, 3, 0) layout.addWidget(applyStandard, 3, 1) self.chooseStandardDialog.setLayout(layout) self.chooseStandardDialog.setWindowTitle("Choose Standard") self.chooseStandardDialog.setWindowModality(Qt.ApplicationModal) self.chooseStandardDialog.exec_()
class BarcodePropsEdit(PropsEdit): def __init__(self, data: BarcodeData, parent, printable): super().__init__(data, parent, printable) self.setMinimumWidth(256) self.combo_type = QComboBox() model = QStandardItemModel(0, 2) curr_index = 0 for key in barcode.PROVIDED_BARCODES: bc = barcode.get(key) model.appendRow([QStandardItem(bc.name), QStandardItem(key)]) if data.code_type == key: curr_index = model.rowCount() - 1 self.combo_type.setModel(model) self.combo_type.setCurrentIndex(curr_index) self.combo_type.currentIndexChanged.connect(self.combo_type_changed) self.layout.addWidget(QLabel('Barcode type:')) self.layout.addWidget(self.combo_type) self.edit_text = QLineEdit(data.text, self) self.edit_text.textChanged.connect(self.edit_text_changed) self.layout.addWidget(QLabel('Value:')) self.layout.addWidget(self.edit_text) self.show_label = QCheckBox("Include label", self) self.show_label.setChecked(data.draw_label) self.layout.addWidget(self.show_label) self.layout.addStretch() def combo_type_changed(self): model: QStandardItemModel = self.combo_type.model() item = model.item(self.combo_type.currentIndex(), 1) print(item.text(), item.data()) self.data.code_type = item.text() self.save() pass def serialize(self, clone=False): data = super().serialize(clone) data.text = self.edit_text.text() data.draw_label = self.show_label.isChecked() return data def edit_text_changed(self): self.save()
def __init__(self, form_context, parent=None): super().__init__(parent) self._form_context = form_context self.setObjectName("PaymentAmount") amount_widget = QLineEdit() currency_widget = QLineEdit() currency_combo = QComboBox() currency_combo.setEditable(True) filter_model = QSortFilterProxyModel(currency_combo) filter_model.setFilterCaseSensitivity(Qt.CaseInsensitive) filter_model.setSourceModel(currency_combo.model()) contact_completer = QCompleter(filter_model, currency_combo) contact_completer.setCompletionMode( QCompleter.UnfilteredPopupCompletion) currency_combo.setCompleter(contact_completer) # base unit. # selected fiat currency. options = [] base_unit = form_context.wallet_api.get_base_unit() options.append(base_unit) fiat_unit = form_context.wallet_api.get_fiat_unit() if fiat_unit is not None: options.append(fiat_unit) currency_combo.addItems(options) currency_combo.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(currency_combo) layout.addWidget(amount_widget) self.setLayout(layout) self._currency_combo_options = options self._currency_combo = currency_combo self._amount_widget = amount_widget self._form_context.set_payment_amount.connect(self._set_payment_amount)
def apply(self): self.froms = [] self.tos = [] self.colors = [] self.num_intervals = self.editor2.text() self.range = self.editor1.text() self.current_value = self.comboBox.currentText() for _ in range(int(self.num_intervals)): hbox = QHBoxLayout() mylabel_1 = QLabel() mylabel_1.setText("From:") myeditor_1 = QLineEdit() self.froms.append(myeditor_1) hbox.addWidget(mylabel_1) hbox.addWidget(myeditor_1) mylabel_2 = QLabel() mylabel_2.setText("to:") myeditor_2 = QLineEdit() self.tos.append(myeditor_2) hbox.addWidget(mylabel_2) hbox.addWidget(myeditor_2) mylabel_3 = QLabel() mylabel_3.setText("Color:") color_combobox = QComboBox() model = color_combobox.model() for a,b,c,color in colors: entry = QStandardItem(color) entry.setForeground(QColor(a,b,c)) # color_combobox.addItem(color) model.appendRow(entry) self.colors.append(color_combobox) hbox.addWidget(mylabel_3) hbox.addWidget(color_combobox) self.v_lay.addLayout(hbox)
class stats(QWidget): def __init__(self, parent=None): super().__init__(parent) self.bold_font = QFont() self.bold_font.setBold(True) stats_content = get_home_stats() # -- LEVEL TWO GRID self.grid = QGridLayout() self.grid.setSpacing(20) self.grid.setContentsMargins(0, 1, 0, 1) self.setLayout(self.grid) # -- CELL ZERO self.funds_group = QGroupBox("Funds Status") self.stats_pie = QLabel() self.image = QPixmap('pie.png') self.resized_image = self.image.scaled(500, 500, Qt.KeepAspectRatio, Qt.FastTransformation) self.stats_pie.setPixmap(self.resized_image) self.stats_pie.setAlignment(Qt.AlignCenter) self.currency_label = QLabel() currency_content = f"FUNDS COLLECTED IN {all_months_values[currentMonth-1].upper()} : {stats_content['funds']} INR" self.currency_label.setText(currency_content) self.currency_label.setWordWrap(True) self.currency_label.setAlignment(Qt.AlignCenter) self.currency_label.setStyleSheet("font: bold 10pt") self.funds_layout = QFormLayout() self.funds_layout.addRow(self.stats_pie) self.funds_layout.addRow(self.currency_label) self.funds_layout.setVerticalSpacing(10) self.funds_group.setLayout(self.funds_layout) # -- CELL ONE self.members_group = QGroupBox("Members Status") stats_content, self.defaulters = get_stats_content() self.stats_result_table = QTableWidget() self.stats_result_table.setRowCount(len(stats_content)) self.stats_result_table.setColumnCount(3) self.stats_result_table.setHorizontalHeaderLabels( ["Flat", "Name", "Fees Paid Upto"]) for index, row in enumerate(stats_content): for inner_index, row_content in enumerate(row): table_item = QTableWidgetItem(str(row_content)) if inner_index != 1: table_item.setTextAlignment(Qt.AlignCenter) if index in self.defaulters: table_item.setForeground(QBrush(QColor(249, 56, 34))) if inner_index == 2: table_item.setFont(self.bold_font) self.stats_result_table.setItem(index, inner_index, table_item) header = self.stats_result_table.horizontalHeader() header.setSectionResizeMode(QHeaderView.Stretch) self.members_layout = QHBoxLayout() self.members_layout.addWidget(self.stats_result_table) self.members_group.setLayout(self.members_layout) # -- CELL TWO self.additional_layout = QVBoxLayout() self.remainder_group = QGroupBox("Remainders") self.backup_group = QGroupBox("Backup") self.excel_group = QGroupBox("Excel") self.backup_h = QHBoxLayout() self.backup_h.addWidget(self.backup_group) self.backup_h.addWidget(self.excel_group) self.responsibility_group = QGroupBox("Responsibility") self.additional_layout.addWidget(self.remainder_group) self.additional_layout.addLayout(self.backup_h) self.additional_layout.addWidget(self.responsibility_group) self.additional_layout.setSpacing(20) self.additional_layout.setContentsMargins(0, 0, 0, 0) # --- self.remainder_desc = QLabel( "Send a mail to all the pending members for this month, as a remainder to pay the fees." ) self.remainder_desc.setWordWrap(True) self.remainder_button = QPushButton("Send REMAINDERS") self.rbar = QProgressBar() self.rbar.setValue(0) self.rbar.setMaximum(100) self.rbar.setTextVisible(True) self.rbar.setFixedSize(472, 15) self.remainder_layout = QVBoxLayout() self.remainder_layout.addWidget(self.remainder_desc) self.remainder_layout.addWidget(self.remainder_button) self.remainder_layout.addWidget(self.rbar) self.remainder_group.setLayout(self.remainder_layout) self.remainder_group.setFixedWidth(500) # --- self.backup_desc = QLabel( "Backup the current state of database, and save it online.") self.backup_desc.setWordWrap(True) self.backup_button = QPushButton("Generate BACKUP") self.backup_button.setToolTip( "Backups are automatically generated at the start of every month.") self.backup_layout = QVBoxLayout() self.backup_layout.addWidget(self.backup_desc) self.backup_layout.addWidget(self.backup_button) self.backup_group.setLayout(self.backup_layout) self.excel_desc = QLabel( "Generate an Excel file for current state of database.") self.excel_desc.setWordWrap(True) self.excel_button = QPushButton("Generate EXCEL") self.excel_button.setToolTip( "Create Excel files of Members and Records.") self.excel_layout = QVBoxLayout() self.excel_layout.addWidget(self.excel_desc) self.excel_layout.addWidget(self.excel_button) self.excel_group.setLayout(self.excel_layout) # --- self.responsibility_desc = QLabel( "Pass on the responsibility of fee collection to a different member." ) self.responsibility_desc.setWordWrap(True) self.responsibility_combo = QComboBox() model = self.responsibility_combo.model() for flat in flats: model.appendRow(QStandardItem(flat)) self.responsibility_combo.setStyleSheet( 'text-color: black; selection-background-color: rgb(215,215,215)') self.responsibility_combo.setFixedWidth(140) self.responsibility_button = QPushButton("TRANSFER") self.responsibility_button.setToolTip( "This will send a mail with latest database and the software to new member." ) self.responsibility_h = QHBoxLayout() self.responsibility_h.addWidget(self.responsibility_combo) self.responsibility_h.addWidget(self.responsibility_button) self.responsibility_layout = QVBoxLayout() self.responsibility_layout.addWidget(self.responsibility_desc) self.responsibility_layout.addLayout(self.responsibility_h) self.responsibility_group.setLayout(self.responsibility_layout) # -- FUNCTIONALITY self.backup_button.clicked.connect(backup) self.excel_button.clicked.connect(csv) self.responsibility_button.clicked.connect(self.transfer) self.remainder_button.clicked.connect(self.remainder) # -- STATS GRID self.grid.addWidget(self.funds_group, 0, 0, 2, 1) self.grid.addWidget(self.members_group, 0, 1, 2, 2) self.grid.addLayout(self.additional_layout, 0, 3, 2, 1) def transfer(self): flat = self.responsibility_combo.currentText() transfer_responsibility(flat=flat) def remainder(self): self.backup_group.setEnabled(False) self.excel_group.setEnabled(False) self.responsibility_group.setEnabled(False) self.remainder_desc.setText( "Sending Remainders.\nPlease do not perform any other operations until its complete." ) defaulters = [f"A - {x + 1}" for x in self.defaulters] self.rbar.setValue(1) for index, defaulter in enumerate(defaulters): send_remainder(defaulter=defaulter, month=all_months_values[currentMonth - 1]) self.rbar.setValue((index + 1) * 100 // len(defaulters)) self.rbar.setValue(100) self.backup_group.setEnabled(True) self.excel_group.setEnabled(True) self.responsibility_group.setEnabled(True) self.rbar.setValue(0) self.remainder_desc.setText( "Send a mail to all the pending members for this month, as a remainder to pay the fees." )
class TablaturePart(_base.Part): """Base class for tablature instrument part types.""" octave = 0 clef = None transposition = None tunings = () # may contain a list of tunings. tabFormat = '' # can contain a tablatureFormat value. def createWidgets(self, layout): self.staffTypeLabel = QLabel() self.staffType = QComboBox() self.staffTypeLabel.setBuddy(self.staffType) self.staffType.setModel(listmodel.ListModel(tablatureStaffTypes, self.staffType, display=listmodel.translate)) box = QHBoxLayout() layout.addLayout(box) box.addWidget(self.staffTypeLabel) box.addWidget(self.staffType) if self.tunings: self.createTuningWidgets(layout) self.staffType.activated.connect(self.slotTabEnable) self.slotTabEnable(0) def createTuningWidgets(self, layout): self.tuningLabel = QLabel() self.tuning = QComboBox() self.tuningLabel.setBuddy(self.tuning) tunings = [('', lambda: _("Default"))] tunings.extend(self.tunings) tunings.append(('', lambda: _("Custom tuning"))) self.tuning.setModel(listmodel.ListModel(tunings, self.tuning, display=listmodel.translate_index(1))) self.tuning.setCurrentIndex(1) self.customTuning = QLineEdit(enabled=False) completionmodel.complete(self.customTuning, "scorewiz/completion/plucked_strings/custom_tuning") self.tuning.currentIndexChanged.connect(self.slotCustomTuningEnable) box = QHBoxLayout() layout.addLayout(box) box.addWidget(self.tuningLabel) box.addWidget(self.tuning) layout.addWidget(self.customTuning) def translateWidgets(self): self.staffTypeLabel.setText(_("Staff type:")) self.staffType.model().update() if self.tunings: self.translateTuningWidgets() def translateTuningWidgets(self): self.tuningLabel.setText(_("Tuning:")) self.customTuning.setToolTip('<qt>' + _( "Select custom tuning in the combobox and " "enter a custom tuning here, e.g. <code>e, a d g b e'</code>. " "Use absolute note names in the same language as you want to use " "in your document (by default: \"nederlands\").")) try: self.customTuning.setPlaceholderText(_("Custom tuning...")) except AttributeError: pass # only in Qt 4.7+ self.tuning.model().update() def slotTabEnable(self, enable): """Called when the user changes the staff type. Non-zero if the user wants a TabStaff. """ self.tuning.setEnabled(bool(enable)) if enable: self.slotCustomTuningEnable(self.tuning.currentIndex()) else: self.customTuning.setEnabled(False) def slotCustomTuningEnable(self, index): self.customTuning.setEnabled(index > len(self.tunings)) def voiceCount(self): """Returns the number of voices. Inherit to make this user-settable. """ return 1 def build(self, data, builder): # First make assignments for the voices we want to create numVoices = self.voiceCount() if numVoices == 1: voices = (ly.util.mkid(data.name()),) elif numVoices == 2: order = 1, 2 voices = 'upper', 'lower' elif numVoices == 3: order = 1, 3, 2 voices = 'upper', 'middle', 'lower' else: order = 1, 2, 3, 4 voices = [ly.util.mkid(data.name(), "voice") + ly.util.int2text(i) for i in order] assignments = [data.assignMusic(name, self.octave, self.transposition) for name in voices] staffType = self.staffType.currentIndex() if staffType in (0, 2): # create a normal staff staff = ly.dom.Staff() seq = ly.dom.Seqr(staff) if self.clef: ly.dom.Clef(self.clef, seq) mus = ly.dom.Simr(seq) for a in assignments[:-1]: ly.dom.Identifier(a.name, mus) ly.dom.VoiceSeparator(mus) ly.dom.Identifier(assignments[-1].name, mus) builder.setMidiInstrument(staff, self.midiInstrument) if staffType in (1, 2): # create a tab staff tabstaff = ly.dom.TabStaff() if self.tabFormat: tabstaff.getWith()['tablatureFormat'] = ly.dom.Scheme(self.tabFormat) self.setTunings(tabstaff) sim = ly.dom.Simr(tabstaff) if numVoices == 1: ly.dom.Identifier(assignments[0].name, sim) else: for num, a in zip(order, assignments): s = ly.dom.Seq(ly.dom.TabVoice(parent=sim)) ly.dom.Text('\\voice' + ly.util.int2text(num), s) ly.dom.Identifier(a.name, s) if staffType == 0: # only a normal staff p = staff elif staffType == 1: # only a TabStaff builder.setMidiInstrument(tabstaff, self.midiInstrument) p = tabstaff else: # both TabStaff and normal staff p = ly.dom.StaffGroup() s = ly.dom.Sim(p) s.append(staff) s.append(tabstaff) builder.setInstrumentNamesFromPart(p, self, data) data.nodes.append(p) def setTunings(self, tab): if self.tunings: i = self.tuning.currentIndex() if i == 0: return elif i > len(self.tunings): value = ly.dom.Text("\\stringTuning <{0}>".format(self.customTuning.text())) else: tuning = self.tunings[self.tuning.currentIndex() - 1][0] value = ly.dom.Scheme(tuning) tab.getWith()['stringTunings'] = value
class ScoreProperties(object): """This is only the base class, it should be mixed in with a widget or a different way.""" def createWidgets(self): """Creates all widgets.""" self.createKeySignatureWidget() self.createTimeSignatureWidget() self.createPickupWidget() self.createMetronomeWidget() self.createTempoWidget() def layoutWidgets(self, layout): """Adds all widgets to a vertical layout.""" self.layoutKeySignatureWidget(layout) self.layoutTimeSignatureWidget(layout) self.layoutPickupWidget(layout) self.layoutMetronomeWidget(layout) self.layoutTempoWidget(layout) def translateWidgets(self): self.translateKeySignatureWidget() self.translateTimeSignatureWidget() self.translatePickupWidget() self.tranlateMetronomeWidget() self.translateTempoWidget() def ly(self, node, builder): """Adds appropriate LilyPond command nodes to the parent node. Settings from the builder are used where that makes sense. All widgets must be present. """ self.lyKeySignature(node, builder) self.lyTimeSignature(node, builder) self.lyPickup(node, builder) self.lyTempo(node, builder) def globalSection(self, builder): """Returns a sequential expression between { } containing the output of ly().""" seq = ly.dom.Seq() self.ly(seq, builder) return seq # Key signature def createKeySignatureWidget(self): self.keySignatureLabel = QLabel() self.keyNote = QComboBox() self.keyNote.setModel(listmodel.ListModel(keyNames['nederlands'], self.keyNote)) self.keyMode = QComboBox() self.keyMode.setModel(listmodel.ListModel(modes, self.keyMode, display=listmodel.translate_index(1))) self.keySignatureLabel.setBuddy(self.keyNote) def translateKeySignatureWidget(self): self.keySignatureLabel.setText(_("Key signature:")) self.keyMode.model().update() def layoutKeySignatureWidget(self, layout): """Adds our widgets to a layout, assuming it is a QVBoxLayout.""" box = QHBoxLayout() box.addWidget(self.keySignatureLabel) box.addWidget(self.keyNote) box.addWidget(self.keyMode) layout.addLayout(box) def setPitchLanguage(self, language='nederlands'): self.keyNote.model()._data = keyNames[language or 'nederlands'] self.keyNote.model().update() def lyKeySignature(self, node, builder): """Adds the key signature to the ly.dom node parent.""" note, alter = keys[self.keyNote.currentIndex()] alter = fractions.Fraction(alter, 2) mode = modes[self.keyMode.currentIndex()][0] ly.dom.KeySignature(note, alter, mode, node).after = 1 # Time signature def createTimeSignatureWidget(self): self.timeSignatureLabel = QLabel() self.timeSignature = QComboBox(editable=True) icons = { '(4/4)': symbols.icon('time_c44'), '(2/2)': symbols.icon('time_c22'), } self.timeSignature.setModel(listmodel.ListModel(timeSignaturePresets, self.timeSignature, icon=icons.get)) self.timeSignature.setCompleter(None) self.timeSignatureLabel.setBuddy(self.timeSignature) def translateTimeSignatureWidget(self): self.timeSignatureLabel.setText(_("Time signature:")) def layoutTimeSignatureWidget(self, layout): """Adds our widgets to a layout, assuming it is a QVBoxLayout.""" box = QHBoxLayout() box.addWidget(self.timeSignatureLabel) box.addWidget(self.timeSignature) layout.addLayout(box) def lyTimeSignature(self, node, builder): """Adds the time signature to the ly.dom node parent.""" sig = self.timeSignature.currentText().strip() if '+' in sig: pass # TODO: implement support for \compoundMeter else: if sig == '(2/2)': ly.dom.TimeSignature(2, 2, node).after = 1 elif sig == '(4/4)': ly.dom.TimeSignature(4, 4, node).after = 1 else: match = re.search(r'(\d+).*?(\d+)', sig) if match: if builder.lyVersion >= (2, 11, 44): ly.dom.Line(r"\numericTimeSignature", node) else: ly.dom.Line(r"\override Staff.TimeSignature #'style = #'()", node) num, beat = map(int, match.group(1, 2)) ly.dom.TimeSignature(num, beat, node).after = 1 # Pickup bar def createPickupWidget(self): self.pickupLabel = QLabel() self.pickup = QComboBox() pickups = [''] pickups.extend(durations) self.pickup.setModel(listmodel.ListModel(pickups, self.pickup, display = lambda item: item or _("None"), icon = lambda item: symbols.icon('note_{0}'.format(item.replace('.', 'd'))) if item else None)) self.pickup.view().setIconSize(QSize(22, 22)) self.pickupLabel.setBuddy(self.pickup) def translatePickupWidget(self): self.pickupLabel.setText(_("Pickup measure:")) self.pickup.model().update() def layoutPickupWidget(self, layout): box = QHBoxLayout() box.addWidget(self.pickupLabel) box.addWidget(self.pickup) layout.addLayout(box) def lyPickup(self, node, builder): if self.pickup.currentIndex() > 0: dur, dots = partialDurations[self.pickup.currentIndex() - 1] ly.dom.Partial(dur, dots, parent=node) # Metronome value def createMetronomeWidget(self): self.metronomeLabel = QLabel() self.metronomeNote = QComboBox() self.metronomeNote.setModel(listmodel.ListModel(durations, display=None, icon = lambda item: symbols.icon('note_{0}'.format(item.replace('.', 'd'))))) self.metronomeNote.setCurrentIndex(durations.index('4')) self.metronomeNote.view().setIconSize(QSize(22, 22)) self.metronomeEqualSign = QLabel('=') self.metronomeEqualSign.setFixedWidth(self.metronomeEqualSign.minimumSizeHint().width()) self.metronomeValue = QComboBox(editable=True) self.metronomeValue.setModel(listmodel.ListModel(metronomeValues, self.metronomeValue, display=format)) self.metronomeValue.setCompleter(None) self.metronomeValue.setValidator(QIntValidator(0, 999, self.metronomeValue)) self.metronomeValue.setCurrentIndex(metronomeValues.index(100)) self.metronomeTempo = widgets.tempobutton.TempoButton() self.metronomeTempo.tempo.connect(self.setMetronomeValue) self.metronomeLabel.setBuddy(self.metronomeNote) self.metronomeRound = QCheckBox() def layoutMetronomeWidget(self, layout): grid = QGridLayout() grid.addWidget(self.metronomeLabel, 0, 0) box = QHBoxLayout(spacing=0) box.addWidget(self.metronomeNote) box.addWidget(self.metronomeEqualSign) box.addWidget(self.metronomeValue) box.addWidget(self.metronomeTempo) grid.addLayout(box, 0, 1) grid.addWidget(self.metronomeRound, 1, 1) layout.addLayout(grid) def tranlateMetronomeWidget(self): self.metronomeLabel.setText(_("Metronome mark:")) self.metronomeRound.setText(_("Round tap tempo value")) self.metronomeRound.setToolTip(_( "Round the entered tap tempo to a common value." )) def setMetronomeValue(self, bpm): """ Tap the tempo tap button """ if self.metronomeRound.isChecked(): l = [abs(t - bpm) for t in metronomeValues] m = min(l) if m < 6: self.metronomeValue.setCurrentIndex(l.index(m)) else: self.metronomeValue.setEditText(str(bpm)) # Tempo indication def createTempoWidget(self): self.tempoLabel = QLabel() self.tempo = widgets.lineedit.LineEdit() completionmodel.complete(self.tempo, "scorewiz/completion/scoreproperties/tempo") self.tempo.completer().setCaseSensitivity(Qt.CaseInsensitive) self.tempoLabel.setBuddy(self.tempo) def layoutTempoWidget(self, layout): box = QHBoxLayout() box.addWidget(self.tempoLabel) box.addWidget(self.tempo) layout.addLayout(box) def translateTempoWidget(self): self.tempoLabel.setText(_("Tempo indication:")) def lyTempo(self, node, builder): """Returns an appropriate tempo indication.""" text = self.tempo.text().strip() if builder.showMetronomeMark: dur = durations[self.metronomeNote.currentIndex()] val = self.metronomeValue.currentText() or '60' elif text: dur = None val = None else: return tempo = ly.dom.Tempo(dur, val, node) if text: ly.dom.QuotedString(text, tempo) def lyMidiTempo(self, node): """Sets the configured tempo in the tempoWholesPerMinute variable.""" node['tempoWholesPerMinute'] = ly.dom.Scheme(self.schemeMidiTempo()) def schemeMidiTempo(self): """Returns a string with the tempo like '(ly:make-moment 100 4)' from the settings.""" base, mul = midiDurations[self.metronomeNote.currentIndex()] val = int(self.metronomeValue.currentText() or '60') * mul return "(ly:make-moment {0} {1})".format(val, base) def lySimpleMidiTempo(self, node): r"""Return a simple \tempo x=y node for the currently set tempo.""" dur = durations[self.metronomeNote.currentIndex()] val = self.metronomeValue.currentText() or '60' return ly.dom.Tempo(dur, val, node)
class FluidPropertyInterrogatorPlugin(QtWidgets.QWidget): """ Fluid property interrogator GUI """ SINGLE_PHASE = 1 TWO_PHASE = 2 TWO_PHASE_NCG = 3 def __init__(self, **kwargs): super(FluidPropertyInterrogatorPlugin, self).__init__(**kwargs) self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.layoutMain = QVBoxLayout(self) self.ctlFPType = QComboBox(self) self.layoutMain.addWidget(self.ctlFPType) self.layoutFPParams = QStackedLayout() self.ctlSinglePhaseWidget = self.setupSinglePhaseUI(self.layoutFPParams) self.ctlTwoPhaseWidget = self.setupTwoPhaseUI(self.layoutFPParams) self.layoutFPParams.addWidget(self.ctlSinglePhaseWidget) self.layoutFPParams.addWidget(self.ctlTwoPhaseWidget) self.layoutMain.addLayout(self.layoutFPParams) self.ctlFPType.currentIndexChanged.connect(self.onFluidPropertyChanged) def setupSinglePhaseUI(self, layout): widget = QTabWidget(self) widget.addTab(FluidPropertyWidget1PhasePT(self), "p, T") widget.addTab(FluidPropertyWidget1PhaseRhoE(self), "rho, e") widget.addTab(FluidPropertyWidget1PhaseRhoP(self), "rho, p") return widget def setupTwoPhaseUI(self, layout): widget = QTabWidget(self) widget.addTab(FluidPropertyWidget2PhaseP(self), "p") widget.addTab(FluidPropertyWidget2PhaseT(self), "T") return widget def fillFluidProperties(self): """ Fill the combo box with single phase fluid property classes """ fp_classes = [ { 'name': 'Single phase', 'classes': [], 'data': self.SINGLE_PHASE }, { 'name': 'Two phase', 'classes': [], 'data': self.TWO_PHASE } ] json_fps = self.exe_info.json_data.json_data["blocks"]['Modules']['subblocks']['FluidProperties']['star']['subblock_types'] for class_name, vals in json_fps.items(): params = vals['parameters'] if 'fp_type' in params: fp_type = params['fp_type']['default'] if fp_type == 'single-phase-fp': fp_classes[0]['classes'].append(class_name) elif fp_type == 'two-phase-fp': fp_classes[1]['classes'].append(class_name) for fpc in fp_classes: fpc['classes'].sort() sep_indices = [] model = QStandardItemModel() for fpc in fp_classes: parent = QStandardItem(fpc['name']) parent.setEnabled(False) model.appendRow(parent) for c in fpc['classes']: item = QStandardItem(c) item.setData(fpc['data']) model.appendRow(item) sep_indices.append(model.rowCount()) self.ctlFPType.setModel(model) for idx in sep_indices[:-1]: self.ctlFPType.insertSeparator(idx) def onFluidPropertyChanged(self, index): fp_type = self.ctlFPType.model().item(index).data() if fp_type == self.SINGLE_PHASE: self.layoutFPParams.setCurrentWidget(self.ctlSinglePhaseWidget) self.ctlSinglePhaseWidget.currentWidget().updateWidgets() elif fp_type == self.TWO_PHASE: self.layoutFPParams.setCurrentWidget(self.ctlTwoPhaseWidget) self.ctlTwoPhaseWidget.currentWidget().updateWidgets() else: raise SystemExit("Unknown fp_type") def fluidPropertyInputFileBlock(self): str = "" str += "[./fp]\n" str += "type = {}\n".format(self.ctlFPType.currentText()) str += "[../]\n" return str def setExecutablePath(self, exe_path): self.exe_path = exe_path self.exe_info = ExecutableInfo() self.exe_info.setPath(self.exe_path) self.fillFluidProperties() for tab in range(self.ctlSinglePhaseWidget.count()): self.ctlSinglePhaseWidget.widget(tab).setExecutablePath(exe_path) for tab in range(self.ctlTwoPhaseWidget.count()): self.ctlTwoPhaseWidget.widget(tab).setExecutablePath(exe_path)
class InstrumentNames(QGroupBox): def __init__(self, parent): super(InstrumentNames, self).__init__(parent, checkable=True, checked=True) grid = QGridLayout() self.setLayout(grid) self.firstSystemLabel = QLabel() self.firstSystem = QComboBox() self.firstSystemLabel.setBuddy(self.firstSystem) self.otherSystemsLabel = QLabel() self.otherSystems = QComboBox() self.otherSystemsLabel.setBuddy(self.otherSystems) self.languageLabel = QLabel() self.language = QComboBox() self.languageLabel.setBuddy(self.language) self.firstSystem.setModel(listmodel.ListModel( (lambda: _("Long"), lambda: _("Short")), self.firstSystem, display = listmodel.translate)) self.otherSystems.setModel(listmodel.ListModel( (lambda: _("Long"), lambda: _("Short"), lambda: _("None")), self.otherSystems, display = listmodel.translate)) self._langs = l = ['','C'] l.extend(sorted(po.available())) def display(lang): if lang == 'C': return _("English (untranslated)") elif not lang: return _("Default") return language_names.languageName(lang, po.setup.current()) self.language.setModel(listmodel.ListModel(l, self.language, display=display)) grid.addWidget(self.firstSystemLabel, 0, 0) grid.addWidget(self.firstSystem, 0, 1) grid.addWidget(self.otherSystemsLabel, 1, 0) grid.addWidget(self.otherSystems, 1, 1) grid.addWidget(self.languageLabel, 2, 0) grid.addWidget(self.language, 2, 1) app.translateUI(self) self.loadSettings() self.window().finished.connect(self.saveSettings) def translateUI(self): self.setTitle(_("Instrument names")) self.firstSystemLabel.setText(_("First system:")) self.otherSystemsLabel.setText(_("Other systems:")) self.languageLabel.setText(_("Language:")) self.firstSystem.setToolTip(_( "Use long or short instrument names before the first system.")) self.otherSystems.setToolTip(_( "Use short, long or no instrument names before the next systems.")) self.language.setToolTip(_( "Which language to use for the instrument names.")) self.firstSystem.model().update() self.otherSystems.model().update() self.language.model().update() def getLanguage(self): """Returns the language the user has set. '' means: default (use same translation as system) 'C' means: English (untranslated) or a language code that is available in Frescobaldi's translation. """ return self._langs[self.language.currentIndex()] def loadSettings(self): s = QSettings() s.beginGroup('scorewiz/instrumentnames') self.setChecked(s.value('enabled', True, bool)) allow = ['long', 'short'] first = s.value('first', '', str) self.firstSystem.setCurrentIndex(allow.index(first) if first in allow else 0) allow = ['long', 'short', 'none'] other = s.value('other', '', str) self.otherSystems.setCurrentIndex(allow.index(other) if other in allow else 2) language = s.value('language', '', str) self.language.setCurrentIndex(self._langs.index(language) if language in self._langs else 0) def saveSettings(self): s = QSettings() s.beginGroup('scorewiz/instrumentnames') s.setValue('enable', self.isChecked()) s.setValue('first', ('long', 'short')[self.firstSystem.currentIndex()]) s.setValue('other', ('long', 'short', 'none')[self.otherSystems.currentIndex()]) s.setValue('language', self._langs[self.language.currentIndex()])
class GuiPreferencesEditor(QWidget): def __init__(self, theParent): QWidget.__init__(self, theParent) self.mainConf = nw.CONFIG self.theParent = theParent self.theTheme = theParent.theTheme # The Form self.mainForm = QConfigLayout() self.mainForm.setHelpTextStyle(self.theTheme.helpText) self.setLayout(self.mainForm) # Spell Checking # ============== self.mainForm.addGroupLabel("Spell Checking") ## Spell Check Provider and Language self.spellLangList = QComboBox(self) self.spellToolList = QComboBox(self) self.spellToolList.addItem("Internal (difflib)", nwConst.SP_INTERNAL) self.spellToolList.addItem("Spell Enchant (pyenchant)", nwConst.SP_ENCHANT) theModel = self.spellToolList.model() idEnchant = self.spellToolList.findData(nwConst.SP_ENCHANT) theModel.item(idEnchant).setEnabled(self.mainConf.hasEnchant) self.spellToolList.currentIndexChanged.connect(self._doUpdateSpellTool) toolIdx = self.spellToolList.findData(self.mainConf.spellTool) if toolIdx != -1: self.spellToolList.setCurrentIndex(toolIdx) self._doUpdateSpellTool(0) self.mainForm.addRow( "Spell check provider", self.spellToolList, "Note that the internal spell check tool is quite slow.") self.mainForm.addRow( "Spell check language", self.spellLangList, "Available languages are determined by your system.") ## Big Document Size Limit self.bigDocLimit = QSpinBox(self) self.bigDocLimit.setMinimum(10) self.bigDocLimit.setMaximum(10000) self.bigDocLimit.setSingleStep(10) self.bigDocLimit.setValue(self.mainConf.bigDocLimit) self.mainForm.addRow( "Big document limit", self.bigDocLimit, "Full spell checking is disabled above this limit.", theUnit="kB") # Word Count # ========== self.mainForm.addGroupLabel("Word Count") ## Word Count Timer self.wordCountTimer = QDoubleSpinBox(self) self.wordCountTimer.setDecimals(1) self.wordCountTimer.setMinimum(2.0) self.wordCountTimer.setMaximum(600.0) self.wordCountTimer.setSingleStep(0.1) self.wordCountTimer.setValue(self.mainConf.wordCountTimer) self.mainForm.addRow("Word count interval", self.wordCountTimer, "How often the word count is updated.", theUnit="seconds") # Writing Guides # ============== self.mainForm.addGroupLabel("Writing Guides") ## Show Tabs and Spaces self.showTabsNSpaces = QSwitch() self.showTabsNSpaces.setChecked(self.mainConf.showTabsNSpaces) self.mainForm.addRow( "Show tabs and spaces", self.showTabsNSpaces, "Add symbols to indicate tabs and spaces in the editor.") ## Show Line Endings self.showLineEndings = QSwitch() self.showLineEndings.setChecked(self.mainConf.showLineEndings) self.mainForm.addRow( "Show line endings", self.showLineEndings, "Add a symbol to indicate line endings in the editor.") # Scroll Behaviour # ================ self.mainForm.addGroupLabel("Scroll Behaviour") ## Scroll Past End self.scrollPastEnd = QSwitch() self.scrollPastEnd.setChecked(self.mainConf.scrollPastEnd) self.mainForm.addRow( "Scroll past end of the document", self.scrollPastEnd, "Also improves trypewriter scrolling for short documents.") ## Typewriter Scrolling self.autoScroll = QSwitch() self.autoScroll.setChecked(self.mainConf.autoScroll) self.mainForm.addRow( "Typewriter style scrolling when you type", self.autoScroll, "Try to keep the cursor at a fixed vertical position.") ## Typewriter Position self.autoScrollPos = QSpinBox(self) self.autoScrollPos.setMinimum(10) self.autoScrollPos.setMaximum(90) self.autoScrollPos.setSingleStep(1) self.autoScrollPos.setValue(int(self.mainConf.autoScrollPos)) self.mainForm.addRow("Minimum position for Typewriter scrolling", self.autoScrollPos, "Percentage of the editor height from the top.", theUnit="%") return def saveValues(self): """Save the values set for this tab. """ # Spell Checking self.mainConf.spellTool = self.spellToolList.currentData() self.mainConf.spellLanguage = self.spellLangList.currentData() self.mainConf.bigDocLimit = self.bigDocLimit.value() # Word Count self.mainConf.wordCountTimer = self.wordCountTimer.value() # Writing Guides self.mainConf.showTabsNSpaces = self.showTabsNSpaces.isChecked() self.mainConf.showLineEndings = self.showLineEndings.isChecked() # Scroll Behaviour self.mainConf.scrollPastEnd = self.scrollPastEnd.isChecked() self.mainConf.autoScroll = self.autoScroll.isChecked() self.mainConf.autoScrollPos = self.autoScrollPos.value() self.mainConf.confChanged = True return ## # Internal Functions ## def _doUpdateSpellTool(self, currIdx): """Update the list of dictionaries based on spell tool selected. """ spellTool = self.spellToolList.currentData() self._updateLanguageList(spellTool) return def _updateLanguageList(self, spellTool): """Updates the list of available spell checking dictionaries available for the selected spell check tool. It will try to preserve the language choice, if the language exists in the updated list. """ if spellTool == nwConst.SP_ENCHANT: theDict = NWSpellEnchant() else: theDict = NWSpellSimple() self.spellLangList.clear() for spTag, spName in theDict.listDictionaries(): self.spellLangList.addItem(spName, spTag) spellIdx = self.spellLangList.findData(self.mainConf.spellLanguage) if spellIdx != -1: self.spellLangList.setCurrentIndex(spellIdx) return
class GuiConfigEditEditingTab(QWidget): def __init__(self, theParent): QWidget.__init__(self, theParent) self.mainConf = nw.CONFIG self.theParent = theParent self.theTheme = theParent.theTheme # The Form self.mainForm = QConfigLayout() self.mainForm.setHelpTextStyle(self.theTheme.helpText) self.setLayout(self.mainForm) # Spell Checking # ============== self.mainForm.addGroupLabel("Syntax Highlighting") ## Syntax Highlighting self.selectSyntax = QComboBox() self.selectSyntax.setMinimumWidth(self.mainConf.pxInt(200)) self.theSyntaxes = self.theTheme.listSyntax() for syntaxFile, syntaxName in self.theSyntaxes: self.selectSyntax.addItem(syntaxName, syntaxFile) syntaxIdx = self.selectSyntax.findData(self.mainConf.guiSyntax) if syntaxIdx != -1: self.selectSyntax.setCurrentIndex(syntaxIdx) self.mainForm.addRow( "Highlight theme", self.selectSyntax, "Colour theme to apply to the editor and viewer.") self.highlightQuotes = QSwitch() self.highlightQuotes.setChecked(self.mainConf.highlightQuotes) self.mainForm.addRow("Highlight text wrapped in quotes", self.highlightQuotes, "Applies to single, double and straight quotes.") self.highlightEmph = QSwitch() self.highlightEmph.setChecked(self.mainConf.highlightEmph) self.mainForm.addRow("Add highlight colour to emphasised text", self.highlightEmph, "Applies to emphasis, strong and strikethrough.") # Spell Checking # ============== self.mainForm.addGroupLabel("Spell Checking") ## Spell Check Provider and Language self.spellLangList = QComboBox(self) self.spellToolList = QComboBox(self) self.spellToolList.addItem("Internal (difflib)", nwConst.SP_INTERNAL) self.spellToolList.addItem("Spell Enchant (pyenchant)", nwConst.SP_ENCHANT) theModel = self.spellToolList.model() idEnchant = self.spellToolList.findData(nwConst.SP_ENCHANT) theModel.item(idEnchant).setEnabled(self.mainConf.hasEnchant) self.spellToolList.currentIndexChanged.connect(self._doUpdateSpellTool) toolIdx = self.spellToolList.findData(self.mainConf.spellTool) if toolIdx != -1: self.spellToolList.setCurrentIndex(toolIdx) self._doUpdateSpellTool(0) self.mainForm.addRow( "Spell check provider", self.spellToolList, "Note that the internal spell check tool is quite slow.") self.mainForm.addRow( "Spell check language", self.spellLangList, "Available languages are determined by your system.") ## Big Document Size Limit self.bigDocLimit = QSpinBox(self) self.bigDocLimit.setMinimum(10) self.bigDocLimit.setMaximum(10000) self.bigDocLimit.setSingleStep(10) self.bigDocLimit.setValue(self.mainConf.bigDocLimit) self.mainForm.addRow( "Big document limit", self.bigDocLimit, "Full spell checking is disabled above this limit.", theUnit="kB") # Writing Guides # ============== self.mainForm.addGroupLabel("Writing Guides") ## Show Tabs and Spaces self.showTabsNSpaces = QSwitch() self.showTabsNSpaces.setChecked(self.mainConf.showTabsNSpaces) self.mainForm.addRow( "Show tabs and spaces", self.showTabsNSpaces, "Add symbols to indicate tabs and spaces in the editor.") ## Show Line Endings self.showLineEndings = QSwitch() self.showLineEndings.setChecked(self.mainConf.showLineEndings) self.mainForm.addRow( "Show line endings", self.showLineEndings, "Add a symbol to indicate line endings in the editor.") return def saveValues(self): """Save the values set for this tab. """ validEntries = True needsRestart = False guiSyntax = self.selectSyntax.currentData() highlightQuotes = self.highlightQuotes.isChecked() highlightEmph = self.highlightEmph.isChecked() spellTool = self.spellToolList.currentData() spellLanguage = self.spellLangList.currentData() bigDocLimit = self.bigDocLimit.value() showTabsNSpaces = self.showTabsNSpaces.isChecked() showLineEndings = self.showLineEndings.isChecked() self.mainConf.guiSyntax = guiSyntax self.mainConf.highlightQuotes = highlightQuotes self.mainConf.highlightEmph = highlightEmph self.mainConf.spellTool = spellTool self.mainConf.spellLanguage = spellLanguage self.mainConf.bigDocLimit = bigDocLimit self.mainConf.showTabsNSpaces = showTabsNSpaces self.mainConf.showLineEndings = showLineEndings self.mainConf.confChanged = True return validEntries, needsRestart ## # Internal Functions ## def _doUpdateSpellTool(self, currIdx): """Update the list of dictionaries based on spell tool selected. """ spellTool = self.spellToolList.currentData() self._updateLanguageList(spellTool) return def _updateLanguageList(self, spellTool): """Updates the list of available spell checking dictionaries available for the selected spell check tool. It will try to preserve the language choice, if the language exists in the updated list. """ if spellTool == nwConst.SP_ENCHANT: theDict = NWSpellEnchant() else: theDict = NWSpellSimple() self.spellLangList.clear() for spTag, spName in theDict.listDictionaries(): self.spellLangList.addItem(spName, spTag) spellIdx = self.spellLangList.findData(self.mainConf.spellLanguage) if spellIdx != -1: self.spellLangList.setCurrentIndex(spellIdx) return
class OWCSVFileImport(widget.OWWidget): name = "CSV File Import" description = "Import a data table from a CSV formatted file." icon = "icons/CSVFile.svg" outputs = [ widget.OutputSignal( name="Data", type=Orange.data.Table, doc="Loaded data set."), widget.OutputSignal( name="Data Frame", type=pd.DataFrame, doc="" ) ] class Error(widget.OWWidget.Error): error = widget.Msg( "Unexpected error" ) encoding_error = widget.Msg( "Encoding error\n" "The file might be encoded in an unsupported encoding or it " "might be binary" ) #: Paths and options of files accessed in a 'session' _session_items = settings.Setting( [], schema_only=True) # type: List[Tuple[str, dict]] #: Saved dialog state (last directory and selected filter) dialog_state = settings.Setting({ "directory": "", "filter": "" }) # type: Dict[str, str] MaxHistorySize = 50 want_main_area = False buttons_area_orientation = None def __init__(self, *args, **kwargs): super().__init__(self, *args, **kwargs) self.__committimer = QTimer(self, singleShot=True) self.__committimer.timeout.connect(self.commit) self.__executor = qconcurrent.ThreadExecutor() self.__watcher = None # type: Optional[qconcurrent.FutureWatcher] self.controlArea.layout().setSpacing(-1) # reset spacing grid = QGridLayout() grid.addWidget(QLabel("File:", self), 0, 0, 1, 1) self.import_items_model = QStandardItemModel(self) self.recent_combo = QComboBox( self, objectName="recent-combo", toolTip="Recent files.", sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, minimumContentsLength=16, ) self.recent_combo.setModel(self.import_items_model) self.recent_combo.activated.connect(self.activate_recent) self.recent_combo.setSizePolicy( QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) self.browse_button = QPushButton( "…", icon=self.style().standardIcon(QStyle.SP_DirOpenIcon), toolTip="Browse filesystem", autoDefault=False, ) self.browse_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.browse_button.clicked.connect(self.browse) grid.addWidget(self.recent_combo, 0, 1, 1, 1) grid.addWidget(self.browse_button, 0, 2, 1, 1) self.controlArea.layout().addLayout(grid) ########### # Info text ########### box = gui.widgetBox(self.controlArea, "Info", addSpace=False) self.summary_text = QTextBrowser( verticalScrollBarPolicy=Qt.ScrollBarAsNeeded, readOnly=True, ) self.summary_text.viewport().setBackgroundRole(QPalette.NoRole) self.summary_text.setFrameStyle(QTextBrowser.NoFrame) self.summary_text.setMinimumHeight(self.fontMetrics().ascent() * 2 + 4) self.summary_text.viewport().setAutoFillBackground(False) box.layout().addWidget(self.summary_text) button_box = QDialogButtonBox( orientation=Qt.Horizontal, standardButtons=QDialogButtonBox.Cancel | QDialogButtonBox.Retry ) self.load_button = b = button_box.button(QDialogButtonBox.Retry) b.setText("Load") b.clicked.connect(self.__committimer.start) b.setEnabled(False) b.setDefault(True) self.cancel_button = b = button_box.button(QDialogButtonBox.Cancel) b.clicked.connect(self.cancel) b.setEnabled(False) b.setAutoDefault(False) self.import_options_button = QPushButton( "Import Options…", enabled=False, autoDefault=False, clicked=self._activate_import_dialog ) self.recent_combo.currentIndexChanged.connect( lambda idx: self.import_options_button.setEnabled(idx != -1) or self.load_button.setEnabled(idx != -1) ) button_box.addButton( self.import_options_button, QDialogButtonBox.ActionRole ) button_box.setStyleSheet( "button-layout: {:d};".format(QDialogButtonBox.MacLayout) ) self.controlArea.layout().addWidget(button_box) self._restoreState() if self.current_item() is not None: self._invalidate() self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Maximum) @Slot(int) def activate_recent(self, index): """ Activate an item from the recent list. """ if 0 <= index < self.import_items_model.rowCount(): item = self.import_items_model.item(index) assert item is not None path = item.data(ImportItem.PathRole) opts = item.data(ImportItem.OptionsRole) if not isinstance(opts, Options): opts = None self.set_selected_file(path, opts) else: self.recent_combo.setCurrentIndex(-1) @Slot() def browse(self): """ Open a file dialog and select a user specified file. """ formats = [ "Text - comma separated (*.csv, *)", "Text - tab separated (*.tsv, *)", "Text - all files (*)" ] dlg = QFileDialog( self, windowTitle="Open Data File", acceptMode=QFileDialog.AcceptOpen, fileMode=QFileDialog.ExistingFile ) dlg.setNameFilters(formats) state = self.dialog_state lastdir = state.get("directory", "") lastfilter = state.get("filter", "") if lastdir and os.path.isdir(lastdir): dlg.setDirectory(lastdir) if lastfilter: dlg.selectNameFilter(lastfilter) status = dlg.exec_() dlg.deleteLater() if status == QFileDialog.Accepted: self.dialog_state["directory"] = dlg.directory().absolutePath() self.dialog_state["filter"] = dlg.selectedNameFilter() selected_filter = dlg.selectedNameFilter() path = dlg.selectedFiles()[0] # pre-flight check; try to determine the nature of the file mtype = _mime_type_for_path(path) if not mtype.inherits("text/plain"): mb = QMessageBox( parent=self, windowTitle="", icon=QMessageBox.Question, text="The '{basename}' may be a binary file.\n" "Are you sure you want to continue?".format( basename=os.path.basename(path)), standardButtons=QMessageBox.Cancel | QMessageBox.Yes ) mb.setWindowModality(Qt.WindowModal) if mb.exec() == QMessageBox.Cancel: return # initialize dialect based on selected extension if selected_filter in formats[:-1]: filter_idx = formats.index(selected_filter) if filter_idx == 0: dialect = csv.excel() elif filter_idx == 1: dialect = csv.excel_tab() else: dialect = csv.excel_tab() header = True else: try: dialect, header = sniff_csv_with_path(path) except Exception: dialect, header = csv.excel(), True options = None # Search for path in history. # If found use the stored params to initialize the import dialog items = self.itemsFromSettings() idx = index_where(items, lambda t: samepath(t[0], path)) if idx is not None: _, options_ = items[idx] if options_ is not None: options = options_ if options is None: if not header: rowspec = [] else: rowspec = [(range(0, 1), RowSpec.Header)] options = Options( encoding="utf-8", dialect=dialect, rowspec=rowspec) dlg = CSVImportDialog( self, windowTitle="Import Options", sizeGripEnabled=True) dlg.setWindowModality(Qt.WindowModal) dlg.setPath(path) dlg.setOptions(options) status = dlg.exec_() dlg.deleteLater() if status == QDialog.Accepted: self.set_selected_file(path, dlg.options()) def current_item(self): # type: () -> Optional[ImportItem] """ Return the current selected item (file) or None if there is no current item. """ idx = self.recent_combo.currentIndex() if idx == -1: return None item = self.recent_combo.model().item(idx) # type: QStandardItem if isinstance(item, ImportItem): return item else: return None def _activate_import_dialog(self): """Activate the Import Options dialog for the current item.""" item = self.current_item() assert item is not None dlg = CSVImportDialog( self, windowTitle="Import Options", sizeGripEnabled=True, ) dlg.setWindowModality(Qt.WindowModal) dlg.setAttribute(Qt.WA_DeleteOnClose) settings = QSettings() qualname = qname(type(self)) settings.beginGroup(qualname) size = settings.value("size", QSize(), type=QSize) # type: QSize if size.isValid(): dlg.resize(size) path = item.data(ImportItem.PathRole) options = item.data(ImportItem.OptionsRole) dlg.setPath(path) # Set path before options so column types can if isinstance(options, Options): dlg.setOptions(options) def update(): newoptions = dlg.options() item.setData(newoptions, ImportItem.OptionsRole) # update the stored item self._add_recent(path, newoptions) if newoptions != options: self._invalidate() dlg.accepted.connect(update) def store_size(): settings.setValue("size", dlg.size()) dlg.finished.connect(store_size) dlg.show() def set_selected_file(self, filename, options=None): """ Set the current selected filename path. """ self._add_recent(filename, options) self._invalidate() #: Saved options for a filename SCHEMA = { "path": str, # Local filesystem path "options": str, # json encoded 'Options' } @classmethod def _local_settings(cls): # type: () -> QSettings """Return a QSettings instance with local persistent settings.""" filename = "{}.ini".format(qname(cls)) fname = os.path.join(settings.widget_settings_dir(), filename) return QSettings(fname, QSettings.IniFormat) def _add_recent(self, filename, options=None): # type: (str, Optional[Options]) -> None """ Add filename to the list of recent files. """ model = self.import_items_model index = index_where( (model.index(i, 0).data(ImportItem.PathRole) for i in range(model.rowCount())), lambda path: isinstance(path, str) and samepath(path, filename) ) if index is not None: item, *_ = model.takeRow(index) else: item = ImportItem.fromPath(filename) model.insertRow(0, item) if options is not None: item.setOptions(options) self.recent_combo.setCurrentIndex(0) # store items to local persistent settings s = self._local_settings() arr = QSettings_readArray(s, "recent", OWCSVFileImport.SCHEMA) item = {"path": filename} if options is not None: item["options"] = json.dumps(options.as_dict()) arr = [item for item in arr if item.get("path") != filename] arr.append(item) QSettings_writeArray(s, "recent", arr) # update workflow session items items = self._session_items[:] idx = index_where(items, lambda t: samepath(t[0], filename)) if idx is not None: del items[idx] items.insert(0, (filename, options.as_dict())) self._session_items = items[:OWCSVFileImport.MaxHistorySize] def _invalidate(self): # Invalidate the current output and schedule a new commit call. # (NOTE: The widget enters a blocking state) self.__committimer.start() if self.__watcher is not None: self.__cancel_task() self.setBlocking(True) def commit(self): """ Commit the current state and submit the load task for execution. Note ---- Any existing pending task is canceled. """ self.__committimer.stop() if self.__watcher is not None: self.__cancel_task() self.error() item = self.current_item() if item is None: return path = item.data(ImportItem.PathRole) opts = item.data(ImportItem.OptionsRole) if not isinstance(opts, Options): return task = state = TaskState() state.future = ... state.watcher = qconcurrent.FutureWatcher() state.progressChanged.connect(self.__set_read_progress, Qt.QueuedConnection) def progress_(i, j): task.emitProgressChangedOrCancel(i, j) task.future = self.__executor.submit( clear_stack_on_cancel(load_csv), path, opts, progress_, ) task.watcher.setFuture(task.future) w = task.watcher w.done.connect(self.__handle_result) w.progress = state self.__watcher = w self.__set_running_state() @Slot('qint64', 'qint64') def __set_read_progress(self, read, count): if count > 0: self.progressBarSet(100 * read / count) def __cancel_task(self): # Cancel and dispose of the current task assert self.__watcher is not None w = self.__watcher w.future().cancel() w.progress.cancel = True w.done.disconnect(self.__handle_result) w.progress.progressChanged.disconnect(self.__set_read_progress) w.progress.deleteLater() # wait until completion futures.wait([w.future()]) self.__watcher = None def cancel(self): """ Cancel current pending or executing task. """ if self.__watcher is not None: self.__cancel_task() self.__clear_running_state() self.setStatusMessage("Cancelled") self.summary_text.setText( "<div>Cancelled<br/><small>Press 'Reload' to try again</small></div>" ) def __set_running_state(self): self.progressBarInit() self.setBlocking(True) self.setStatusMessage("Running") self.cancel_button.setEnabled(True) self.load_button.setText("Restart") path = self.current_item().path() self.Error.clear() self.summary_text.setText( "<div>Loading: <i>{}</i><br/>".format(prettyfypath(path)) ) def __clear_running_state(self, ): self.progressBarFinished() self.setStatusMessage("") self.setBlocking(False) self.cancel_button.setEnabled(False) self.load_button.setText("Reload") def __set_error_state(self, err): self.Error.clear() if isinstance(err, UnicodeDecodeError): self.Error.encoding_error(exc_info=err) else: self.Error.error(exc_info=err) path = self.current_item().path() basename = os.path.basename(path) if isinstance(err, UnicodeDecodeError): text = ( "<div><i>{basename}</i> was not loaded due to a text encoding " "error. The file might be saved in an unknown or invalid " "encoding, or it might be a binary file.</div>" ).format( basename=escape(basename) ) else: text = ( "<div><i>{basename}</i> was not loaded due to an error:" "<p style='white-space: pre;'>{err}</p>" ).format( basename=escape(basename), err="".join(traceback.format_exception_only(type(err), err)) ) self.summary_text.setText(text) def __clear_error_state(self): self.Error.error.clear() self.summary_text.setText("") def onDeleteWidget(self): """Reimplemented.""" if self.__watcher is not None: self.__cancel_task() self.__executor.shutdown() super().onDeleteWidget() @Slot(object) def __handle_result(self, f): # type: (qconcurrent.Future[pd.DataFrame]) -> None assert f.done() assert f is self.__watcher.future() self.__watcher = None self.__clear_running_state() try: df = f.result() assert isinstance(df, pd.DataFrame) except pd.errors.EmptyDataError: df = pd.DataFrame({}) except Exception as e: # pylint: disable=broad-except self.__set_error_state(e) df = None else: self.__clear_error_state() if df is not None: table = pandas_to_table(df) else: table = None self.send("Data Frame", df) self.send('Data', table) self._update_status_messages(table) def _update_status_messages(self, data): if data is None: return def pluralize(seq): return "s" if len(seq) != 1 else "" summary = ("{n_instances} row{plural_1}, " "{n_features} feature{plural_2}, " "{n_meta} meta{plural_3}").format( n_instances=len(data), plural_1=pluralize(data), n_features=len(data.domain.attributes), plural_2=pluralize(data.domain.attributes), n_meta=len(data.domain.metas), plural_3=pluralize(data.domain.metas)) self.summary_text.setText(summary) def itemsFromSettings(self): # type: () -> List[Tuple[str, Options]] """ Return items from local history. """ s = self._local_settings() items_ = QSettings_readArray(s, "recent", OWCSVFileImport.SCHEMA) items = [] # type: List[Tuple[str, Options]] for item in items_: path = item.get("path", "") if not path: continue opts_json = item.get("options", "") try: opts = Options.from_dict(json.loads(opts_json)) except (csv.Error, LookupError, TypeError, json.JSONDecodeError): _log.error("Could not reconstruct options for '%s'", path, exc_info=True) pass else: items.append((path, opts)) return items[::-1] def _restoreState(self): # Restore the state. Merge session (workflow) items with the # local history. model = self.import_items_model # local history items = self.itemsFromSettings() # stored session items sitems = [] for p, m in self._session_items: try: item_ = (p, Options.from_dict(m)) except (csv.Error, LookupError) as e: # Is it better to fail then to lose a item slot? _log.error("Failed to restore '%s'", p, exc_info=True) else: sitems.append(item_) items = sitems + items items = unique(items, key=lambda t: pathnormalize(t[0])) curr = self.recent_combo.currentIndex() if curr != -1: currentpath = self.recent_combo.currentData(ImportItem.PathRole) else: currentpath = None for path, options in items: item = ImportItem.fromPath(path) item.setOptions(options) model.appendRow(item) if currentpath is not None: idx = self.recent_combo.findData(currentpath, ImportItem.PathRole) if idx != -1: self.recent_combo.setCurrentIndex(idx)
def run_iface_config_window(icon): ifaces = list_ifaces() win = QDialog() win.setWindowTitle('CAN Interface Configuration') win.setWindowIcon(icon) win.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowCloseButtonHint) combo = QComboBox(win) combo.setEditable(True) combo.setInsertPolicy(QComboBox.NoInsert) combo.setSizeAdjustPolicy(QComboBox.AdjustToContents) combo.addItems(ifaces.keys()) combo_completer = QCompleter() combo_completer.setCaseSensitivity(Qt.CaseSensitive) combo_completer.setModel(combo.model()) combo.setCompleter(combo_completer) bitrate = QSpinBox() bitrate.setMaximum(1000000) bitrate.setMinimum(10000) bitrate.setValue(1000000) extra_args = QLineEdit() extra_args.setFont(get_monospace_font()) ok = QPushButton('OK', win) result = None kwargs = {} def on_ok(): nonlocal result, kwargs a = str(extra_args.text()) if a: try: kwargs = dict(eval(a)) except Exception as ex: show_error('Invalid parameters', 'Could not parse optional arguments', ex, parent=win) return kwargs['bitrate'] = int(bitrate.value()) result_key = str(combo.currentText()).strip() try: result = ifaces[result_key] except KeyError: result = result_key win.close() ok.clicked.connect(on_ok) layout = QVBoxLayout() layout.addWidget(QLabel('Select CAN interface or serial port for SLCAN:')) layout.addWidget(combo) layout.addWidget(QLabel('Interface bitrate (SLCAN only):')) layout.addWidget(bitrate) layout.addWidget(QLabel('Optional arguments (refer to Pyuavcan for info):')) layout.addWidget(extra_args) layout.addWidget(ok) layout.setSizeConstraint(layout.SetFixedSize) win.setLayout(layout) win.exec() return result, kwargs
class Choir(VocalPart): @staticmethod def title(_=_base.translate): return _("Choir") def createWidgets(self, layout): self.label = QLabel(wordWrap=True) self.voicingLabel = QLabel() self.voicing = QComboBox(editable=True) self.voicingLabel.setBuddy(self.voicing) self.voicing.setCompleter(None) self.voicing.setValidator(QRegExpValidator( QRegExp("[SATB]+(-[SATB]+)*", Qt.CaseInsensitive), self.voicing)) self.voicing.addItems(( 'SA-TB', 'S-A-T-B', 'SA', 'S-A', 'SS-A', 'S-S-A', 'TB', 'T-B', 'TT-B', 'T-T-B', 'SS-A-T-B', 'S-A-TT-B', 'SS-A-TT-B', 'S-S-A-T-T-B', 'S-S-A-A-T-T-B-B', )) self.lyricsLabel = QLabel() self.lyrics = QComboBox() self.lyricsLabel.setBuddy(self.lyrics) self.lyrics.setModel(listmodel.ListModel(lyricStyles, self.lyrics, display=listmodel.translate_index(0), tooltip=listmodel.translate_index(1))) self.lyrics.setCurrentIndex(0) self.pianoReduction = QCheckBox() self.rehearsalMidi = QCheckBox() layout.addWidget(self.label) box = QHBoxLayout() layout.addLayout(box) box.addWidget(self.voicingLabel) box.addWidget(self.voicing) self.createStanzaWidget(layout) box = QHBoxLayout() layout.addLayout(box) box.addWidget(self.lyricsLabel) box.addWidget(self.lyrics) self.createAmbitusWidget(layout) layout.addWidget(self.pianoReduction) layout.addWidget(self.rehearsalMidi) def translateWidgets(self): self.translateStanzaWidget() self.translateAmbitusWidget() self.lyrics.model().update() self.label.setText('<p>{0} <i>({1})</i></p>'.format( _("Please select the voices for the choir. " "Use the letters S, A, T, or B. A hyphen denotes a new staff."), _("Hint: For a double choir you can use two choir parts."))) self.voicingLabel.setText(_("Voicing:")) self.lyricsLabel.setText(_("Lyrics:")) self.pianoReduction.setText(_("Piano reduction")) self.pianoReduction.setToolTip(_( "Adds an automatically generated piano reduction.")) self.rehearsalMidi.setText(_("Rehearsal MIDI files")) self.rehearsalMidi.setToolTip(_( "Creates a rehearsal MIDI file for every voice, " "even if no MIDI output is generated for the main score.")) def build(self, data, builder): # normalize voicing staves = self.voicing.currentText().upper() # remove unwanted characters staves = re.sub(r'[^SATB-]+', '', staves) # remove double hyphens, and from begin and end staves = re.sub('-+', '-', staves).strip('-') if not staves: return splitStaves = staves.split('-') numStaves = len(splitStaves) staffCIDs = collections.defaultdict(int) # number same-name staff Context-IDs voiceCounter = collections.defaultdict(int) # dict to number same voice types maxNumVoices = max(map(len, splitStaves)) # largest number of voices numStanzas = self.stanzas.value() lyrics = collections.defaultdict(list) # lyrics grouped by stanza number pianoReduction = collections.defaultdict(list) rehearsalMidis = [] p = ly.dom.ChoirStaff() choir = ly.dom.Sim(p) data.nodes.append(p) # print main instrumentName if there are more choirs, and we # have more than one staff. if numStaves > 1 and data.num: builder.setInstrumentNames(p, builder.instrumentName(lambda _: _("Choir"), data.num), builder.instrumentName(lambda _: _("abbreviation for Choir", "Ch."), data.num)) # get the preferred way of adding lyrics lyrAllSame, lyrEachSame, lyrEachDiff, lyrSpread = ( self.lyrics.currentIndex() == i for i in range(4)) lyrEach = lyrEachSame or lyrEachDiff # stanzas to print (0 = don't print stanza number): if numStanzas == 1: allStanzas = [0] else: allStanzas = list(range(1, numStanzas + 1)) # Which stanzas to print where: if lyrSpread and numStanzas > 1 and numStaves > 2: spaces = numStaves - 1 count, rest = divmod(max(numStanzas, spaces), spaces) stanzaSource = itertools.cycle(allStanzas) stanzaGroups = (itertools.islice(stanzaSource, num) for num in itertools.chain( itertools.repeat(count + 1, rest), itertools.repeat(count, numStaves - rest))) else: stanzaGroups = itertools.repeat(allStanzas, numStaves) # a function to set staff affinity (in LilyPond 2.13.4 and above): if builder.lyVersion >= (2, 13, 4): def setStaffAffinity(context, affinity): ly.dom.Line("\\override VerticalAxisGroup " "#'staff-affinity = #" + affinity, context.getWith()) else: def setStaffAffinity(lyricsContext, affinity): pass # a function to make a column markup: if builder.lyVersion >= (2, 11, 57): columnCommand = 'center-column' else: columnCommand = 'center-align' def makeColumnMarkup(names): node = ly.dom.Markup() column = ly.dom.MarkupEnclosed(columnCommand, node) for name in names: ly.dom.QuotedString(name, column) return node stavesLeft = numStaves for staff, stanzas in zip(splitStaves, stanzaGroups): # are we in the last staff? stavesLeft -= 1 # the number of voices in this staff numVoices = len(staff) # sort the letters in order SATB staff = ''.join(i * staff.count(i) for i in 'SATB') # Create the staff for the voices s = ly.dom.Staff(parent=choir) builder.setMidiInstrument(s, self.midiInstrument) # Build a list of the voices in this staff. # Each entry is a tuple(name, num). # name is one of 'S', 'A', 'T', or 'B' # num is an integer: 0 when a voice occurs only once, or >= 1 when # there are more voices of the same type (e.g. Soprano I and II) voices = [] for voice in staff: if staves.count(voice) > 1: voiceCounter[voice] += 1 voices.append((voice, voiceCounter[voice])) # Add the instrument names to the staff: if numVoices == 1: voice, num = voices[0] longName = builder.instrumentName(voice2Voice[voice].title, num) shortName = builder.instrumentName(voice2Voice[voice].short, num) builder.setInstrumentNames(s, longName, shortName) else: # stack instrument names (long and short) in a markup column. # long names longNames = makeColumnMarkup( builder.instrumentName(voice2Voice[voice].title, num) for voice, num in voices) shortNames = makeColumnMarkup( builder.instrumentName(voice2Voice[voice].short, num) for voice, num in voices) builder.setInstrumentNames(s, longNames, shortNames) # Make the { } or << >> holder for this staff's children. # If *all* staves have only one voice, addlyrics is used. # In that case, don't remove the braces. staffMusic = (ly.dom.Seq if lyrEach and maxNumVoices == 1 else ly.dom.Seqr if numVoices == 1 else ly.dom.Simr)(s) # Set the clef for this staff: if 'B' in staff: ly.dom.Clef('bass', staffMusic) elif 'T' in staff: ly.dom.Clef('treble_8', staffMusic) # Determine voice order (\voiceOne, \voiceTwo etc.) if numVoices == 1: order = (0,) elif numVoices == 2: order = 1, 2 elif staff in ('SSA', 'TTB'): order = 1, 3, 2 elif staff in ('SAA', 'TBB'): order = 1, 2, 4 elif staff in ('SSAA', 'TTBB'): order = 1, 3, 2, 4 else: order = range(1, numVoices + 1) # What name would the staff get if we need to refer to it? # If a name (like 's' or 'sa') is already in use in this part, # just add a number ('ss2' or 'sa2', etc.) staffCIDs[staff] += 1 cid = ly.dom.Reference(staff.lower() + str(staffCIDs[staff] if staffCIDs[staff] > 1 else "")) # Create voices and their lyrics: for (voice, num), voiceNum in zip(voices, order): name = voice2id[voice] if num: name += ly.util.int2text(num) a = data.assignMusic(name, voice2Voice[voice].octave) lyrName = name + 'Verse' if lyrEachDiff else 'verse' # Use \addlyrics if all staves have exactly one voice. if lyrEach and maxNumVoices == 1: for verse in stanzas: lyrics[verse].append((ly.dom.AddLyrics(s), lyrName)) ly.dom.Identifier(a.name, staffMusic) else: voiceName = voice2id[voice] + str(num or '') v = ly.dom.Voice(voiceName, parent=staffMusic) voiceMusic = ly.dom.Seqr(v) if voiceNum: ly.dom.Text('\\voice' + ly.util.int2text(voiceNum), voiceMusic) ly.dom.Identifier(a.name, voiceMusic) if stanzas and (lyrEach or (voiceNum <= 1 and (stavesLeft or numStaves == 1))): # Create the lyrics. If they should be above the staff, # give the staff a suitable name, and use alignAbove- # Context to align the Lyrics above the staff. above = voiceNum & 1 if lyrEach else False if above and s.cid is None: s.cid = cid for verse in stanzas: l = ly.dom.Lyrics(parent=choir) if above: l.getWith()['alignAboveContext'] = cid setStaffAffinity(l, "DOWN") elif not lyrEach and stavesLeft: setStaffAffinity(l, "CENTER") lyrics[verse].append((ly.dom.LyricsTo(voiceName, l), lyrName)) # Add ambitus: if self.ambitus.isChecked(): ambitusContext = (s if numVoices == 1 else v).getWith() ly.dom.Line('\\consists "Ambitus_engraver"', ambitusContext) if voiceNum > 1: ly.dom.Line("\\override Ambitus #'X-offset = #{0}".format( (voiceNum - 1) * 2.0), ambitusContext) pianoReduction[voice].append(a.name) rehearsalMidis.append((voice, num, a.name, lyrName)) # Assign the lyrics, so their definitions come after the note defs. # (These refs are used again below in the midi rehearsal routine.) refs = {} for verse in allStanzas: for node, name in lyrics[verse]: if (name, verse) not in refs: refs[(name, verse)] = self.assignLyrics(data, name, verse).name ly.dom.Identifier(refs[(name, verse)], node) # Create the piano reduction if desired if self.pianoReduction.isChecked(): a = data.assign('pianoReduction') data.nodes.append(ly.dom.Identifier(a.name)) piano = ly.dom.PianoStaff(parent=a) sim = ly.dom.Sim(piano) rightStaff = ly.dom.Staff(parent=sim) leftStaff = ly.dom.Staff(parent=sim) right = ly.dom.Seq(rightStaff) left = ly.dom.Seq(leftStaff) # Determine the ordering of voices in the staves upper = pianoReduction['S'] + pianoReduction['A'] lower = pianoReduction['T'] + pianoReduction['B'] preferUpper = 1 if not upper: # Male choir upper = pianoReduction['T'] lower = pianoReduction['B'] ly.dom.Clef("treble_8", right) ly.dom.Clef("bass", left) preferUpper = 0 elif not lower: # Female choir upper = pianoReduction['S'] lower = pianoReduction['A'] else: ly.dom.Clef("bass", left) # Otherwise accidentals can be confusing ly.dom.Line("#(set-accidental-style 'piano)", right) ly.dom.Line("#(set-accidental-style 'piano)", left) # Move voices if unevenly spread if abs(len(upper) - len(lower)) > 1: voices = upper + lower half = (len(voices) + preferUpper) // 2 upper = voices[:half] lower = voices[half:] for staff, voices in (ly.dom.Simr(right), upper), (ly.dom.Simr(left), lower): if voices: for v in voices[:-1]: ly.dom.Identifier(v, staff) ly.dom.VoiceSeparator(staff).after = 1 ly.dom.Identifier(voices[-1], staff) # Make the piano part somewhat smaller ly.dom.Line("fontSize = #-1", piano.getWith()) ly.dom.Line("\\override StaffSymbol #'staff-space = #(magstep -1)", piano.getWith()) # Nice to add Mark engravers ly.dom.Line('\\consists "Mark_engraver"', rightStaff.getWith()) ly.dom.Line('\\consists "Metronome_mark_engraver"', rightStaff.getWith()) # Keep piano reduction out of the MIDI output if builder.midi: ly.dom.Line('\\remove "Staff_performer"', rightStaff.getWith()) ly.dom.Line('\\remove "Staff_performer"', leftStaff.getWith()) # Create MIDI files if desired if self.rehearsalMidi.isChecked(): a = data.assign('rehearsalMidi') rehearsalMidi = a.name func = ly.dom.SchemeList(a) func.pre = '#\n(' # hack ly.dom.Text('define-music-function', func) ly.dom.Line('(parser location name midiInstrument lyrics) ' '(string? string? ly:music?)', func) choir = ly.dom.Sim(ly.dom.Command('unfoldRepeats', ly.dom.SchemeLily(func))) data.afterblocks.append(ly.dom.Comment(_("Rehearsal MIDI files:"))) for voice, num, ref, lyrName in rehearsalMidis: # Append voice to the rehearsalMidi function name = voice2id[voice] + str(num or '') seq = ly.dom.Seq(ly.dom.Voice(name, parent=ly.dom.Staff(name, parent=choir))) if builder.lyVersion < (2, 18, 0): ly.dom.Text('<>\\f', seq) # add one dynamic ly.dom.Identifier(ref, seq) # add the reference to the voice book = ly.dom.Book() # Append score to the aftermath (stuff put below the main score) suffix = "choir{0}-{1}".format(data.num, name) if data.num else name if builder.lyVersion < (2, 12, 0): data.afterblocks.append( ly.dom.Line('#(define output-suffix "{0}")'.format(suffix))) else: ly.dom.Line('\\bookOutputSuffix "{0}"'.format(suffix), book) data.afterblocks.append(book) data.afterblocks.append(ly.dom.BlankLine()) score = ly.dom.Score(book) # TODO: make configurable midiInstrument = voice2Midi[voice] cmd = ly.dom.Command(rehearsalMidi, score) ly.dom.QuotedString(name, cmd) ly.dom.QuotedString(midiInstrument, cmd) ly.dom.Identifier(refs[(lyrName, allStanzas[0])], cmd) ly.dom.Midi(score) ly.dom.Text("\\context Staff = $name", choir) seq = ly.dom.Seq(choir) ly.dom.Line("\\set Score.midiMinimumVolume = #0.5", seq) ly.dom.Line("\\set Score.midiMaximumVolume = #0.5", seq) ly.dom.Line("\\set Score.tempoWholesPerMinute = #" + data.scoreProperties.schemeMidiTempo(), seq) ly.dom.Line("\\set Staff.midiMinimumVolume = #0.8", seq) ly.dom.Line("\\set Staff.midiMaximumVolume = #1.0", seq) ly.dom.Line("\\set Staff.midiInstrument = $midiInstrument", seq) lyr = ly.dom.Lyrics(parent=choir) lyr.getWith()['alignBelowContext'] = ly.dom.Text('$name') ly.dom.Text("\\lyricsto $name $lyrics", lyr)
class QDataSet(DataSet, QWidget, Ui_DataSet): """[summary] [description] """ def __init__(self, name="QDataSet", parent=None): """ **Constructor** [description] Keyword Arguments: - name {[type]} -- [description] (default: {"QDataSet"}) - parent {[type]} -- [description] (default: {None}) """ super().__init__(name=name, parent=parent) QWidget.__init__(self) Ui_DataSet.__init__(self) self.setupUi(self) self.DataSettreeWidget = DataSetWidget(self) self.splitter.insertWidget(0, self.DataSettreeWidget) self.DataSettreeWidget.setIndentation(0) self.DataSettreeWidget.setHeaderItem(QTreeWidgetItem([""])) self.DataSettreeWidget.setSelectionMode( 1) #QAbstractItemView::SingleSelection hd = self.DataSettreeWidget.header() hd.setSectionsMovable(False) w = self.DataSettreeWidget.width() w /= hd.count() for i in range(hd.count()): hd.resizeSection(0, w) # Theory Toolbar tb = QToolBar() tb.setIconSize(QSize(24, 24)) tb.addAction(self.actionNew_Theory) self.cbtheory = QComboBox() model = self.cbtheory.model() self.cbtheory.setToolTip("Choose a Theory") item = QStandardItem('Select:') item.setForeground(QColor('grey')) model.appendRow(item) i = 1 for th_name in self.parent_application.theories: if th_name not in self.parent_application.common_theories: item = QStandardItem(th_name) item.setToolTip( self.parent_application.theories[th_name].description) model.appendRow(item) flag_first = True for th_name in self.parent_application.theories: if th_name in self.parent_application.common_theories: if flag_first: # add separator if al least one common theories is added self.cbtheory.insertSeparator(self.cbtheory.count()) flag_first = False item = QStandardItem(th_name) item.setToolTip( self.parent_application.theories[th_name].description) model.appendRow(item) self.cbtheory.setCurrentIndex(0) ### self.cbtheory.setMaximumWidth(115) self.cbtheory.setMinimumWidth(50) tb.addWidget(self.cbtheory) tb.addAction(self.actionCalculate_Theory) tb.addAction(self.actionMinimize_Error) #Buttons not wired yet # tb.addAction(self.actionTheory_Options) # self.actionTheory_Options.setDisabled(True) tbut = QToolButton() tbut.setPopupMode(QToolButton.MenuButtonPopup) tbut.setDefaultAction(self.actionShow_Limits) menu = QMenu() menu.addAction(self.actionVertical_Limits) menu.addAction(self.actionHorizontal_Limits) tbut.setMenu(menu) tb.addWidget(tbut) tbut2 = QToolButton() tbut2.setPopupMode(QToolButton.MenuButtonPopup) self.action_save_theory_data = QAction( QIcon(':/Icon8/Images/new_icons/icons8-save_TH.png'), "Save Theory Data", self) tbut2.setDefaultAction(self.action_save_theory_data) menu2 = QMenu() menu2.addAction(self.actionCopy_Parameters) menu2.addAction(self.actionPaste_Parameters) tbut2.setMenu(menu2) tb.addWidget(tbut2) self.TheoryLayout.insertWidget(0, tb) self.splitter.setSizes((1000, 3000)) #desactive buttons when no theory tab self.theory_actions_disabled(True) connection_id = self.actionNew_Theory.triggered.connect( self.handle_actionNew_Theory) connection_id = self.DataSettreeWidget.itemChanged.connect( self.handle_itemChanged) #connection_id = self.DataSettreeWidget.itemClicked.connect(self.handle_itemClicked) connection_id = self.DataSettreeWidget.itemDoubleClicked.connect( self.handle_itemDoubleClicked) connection_id = self.DataSettreeWidget.header( ).sortIndicatorChanged.connect(self.handle_sortIndicatorChanged) connection_id = self.DataSettreeWidget.itemSelectionChanged.connect( self.handle_itemSelectionChanged) # connection_id = self.DataSettreeWidget.currentItemChanged.connect(self.handle_currentItemChanged) connection_id = self.TheorytabWidget.tabCloseRequested.connect( self.handle_thTabCloseRequested) connection_id = self.TheorytabWidget.tabBarDoubleClicked.connect( self.handle_thTabBarDoubleClicked) connection_id = self.TheorytabWidget.currentChanged.connect( self.handle_thCurrentChanged) connection_id = self.actionMinimize_Error.triggered.connect( self.handle_actionMinimize_Error) connection_id = self.actionCalculate_Theory.triggered.connect( self.handle_actionCalculate_Theory) connection_id = self.action_save_theory_data.triggered.connect( self.handle_action_save_theory_data) connection_id = self.actionCopy_Parameters.triggered.connect( self.copy_parameters) connection_id = self.actionPaste_Parameters.triggered.connect( self.paste_parameters) connection_id = self.actionVertical_Limits.triggered.connect( self.toggle_vertical_limits) connection_id = self.actionHorizontal_Limits.triggered.connect( self.toggle_horizontal_limits) def copy_parameters(self): """Copy the parameters of the currently active theory to the clipboard""" th = self.current_theory if th: self.theories[th].copy_parameters() def paste_parameters(self): """Paste the parameters from the clipboard to the currently active theory""" th = self.current_theory if th: self.theories[th].paste_parameters() def handle_action_save_theory_data(self): """Save theory data of current theory""" th = self.current_theory if th: # file browser window dir_start = "data/" dilogue_name = "Select Folder" folder = QFileDialog.getExistingDirectory(self, dilogue_name, dir_start) if os.path.isdir(folder): dialog = QInputDialog(self) dialog.setWindowTitle('Add label to filename(s)?') dialog.setLabelText( 'Add the following text to each saved theory filename(s):') dialog.setTextValue('') dialog.setCancelButtonText('None') if dialog.exec(): txt = dialog.textValue() if txt != '': txt = '_' + txt else: txt = '' self.theories[th].do_save(folder, txt) def set_table_icons(self, table_icon_list): """The list 'table_icon_list' contains tuples (file_name_short, marker_name, face, color) [description] Arguments: - table_icon_list {[type]} -- [description] """ self.DataSettreeWidget.blockSignals( True ) #avoid triggering 'itemChanged' signal that causes a call to do_plot() for fname, marker_name, face, color in table_icon_list: item = self.DataSettreeWidget.findItems( fname, Qt.MatchCaseSensitive, column=0) #returns list of items matching file name if item: #paint icon folder = ':/Markers/Images/Matplotlib_markers/' if face == 'none': #empty symbol marker_path = folder + 'marker_%s' % marker_name else: #filled symbol marker_path = folder + 'marker_filled_%s' % marker_name qp = QPixmap(marker_path) mask = qp.createMaskFromColor(QColor(0, 0, 0), Qt.MaskOutColor) qpainter = QPainter() qpainter.begin(qp) qpainter.setPen( QColor(int(255 * color[0]), int(255 * color[1]), int(255 * color[2]), 255)) qpainter.drawPixmap(qp.rect(), mask, qp.rect()) qpainter.end() item[0].setIcon(0, QIcon(qp)) self.DataSettreeWidget.blockSignals(False) def theory_actions_disabled(self, state): """Disable theory buttons if no theory tab is open [description] Arguments: - state {[type]} -- [description] """ self.actionCalculate_Theory.setDisabled(state) self.actionMinimize_Error.setDisabled(state) # self.actionTheory_Options.setDisabled(state) self.actionShow_Limits.setDisabled(state) self.actionVertical_Limits.setDisabled(state) self.actionHorizontal_Limits.setDisabled(state) self.action_save_theory_data.setDisabled(state) def set_limit_icon(self): """[summary] [description] """ if self.current_theory: th = self.theories[self.current_theory] vlim = th.is_xrange_visible hlim = th.is_yrange_visible if hlim and vlim: img = "Line Chart Both Limits" elif vlim: img = "Line Chart Vertical Limits" elif hlim: img = "Line Chart Horizontal Limits" else: img = "Line Chart" self.actionShow_Limits.setIcon(QIcon(':/Images/Images/%s.png' % img)) def set_no_limits(self, th_name): """Turn the x and yrange selectors off [description] Arguments: - th_name {[type]} -- [description] """ if th_name in self.theories: self.theories[self.current_theory].set_xy_limits_visible( False, False) #hide xrange and yrange def toggle_vertical_limits(self, checked): """Show/Hide the xrange selector for fit [description] """ if self.current_theory: th = self.theories[self.current_theory] th.do_xrange("", checked) th.is_xrange_visible = checked self.set_limit_icon() def toggle_horizontal_limits(self, checked): """Show/Hide the yrange selector for fit [description] """ if self.current_theory: th = self.theories[self.current_theory] th.do_yrange("", checked) th.is_yrange_visible = checked self.set_limit_icon() def end_of_computation(self, th_name): """Action when theory has finished computations""" try: th = self.theories[th_name] th.stop_theory_flag = False except KeyError: pass if self.current_theory == th_name: self.icon_calculate_is_stop(False) self.icon_fit_is_stop(False) def handle_actionCalculate_Theory(self): if self.current_theory and self.files: th = self.theories[self.current_theory] if th.thread_calc_busy: # request stop if in do_calculate th.request_stop_computations() return elif th.is_fitting or th.thread_fit_busy: #do nothing if already busy in do_fit th.Qprint("Busy minimising theory...") return if th.single_file and (len(self.files) - len(self.inactive_files)) > 1: header = "Calculate" message = "<p>Too many active files: \"%s\" uses only one data file.</p>\ <p>The theory will be applied to the highlighted file if any or to the first active file.</p>" % th.thname QMessageBox.warning(self, header, message) self.icon_calculate_is_stop(True) th.handle_actionCalculate_Theory() def handle_actionMinimize_Error(self): """Minimize the error [description] """ if self.current_theory and self.files: th = self.theories[self.current_theory] if th.is_fitting or th.thread_fit_busy: # request stop if in do_fit th.request_stop_computations() return elif th.calculate_is_busy or th.thread_calc_busy: #do nothing if already busy in do_calculate th.Qprint("Busy calculating theory...") return if th.single_file and (len(self.files) - len(self.inactive_files)) > 1: header = "Minimization" message = "<p>Too many active files: \"%s\" uses only one data file.</p>\ <p>The theory will be applied to the highlighted file if any or to the first active file.</p>" % th.thname QMessageBox.warning(self, header, message) self.icon_fit_is_stop(True) th.handle_actionMinimize_Error() def icon_calculate_is_stop(self, ans): """Change the "calculate" button to "stop" button""" if ans: self.actionCalculate_Theory.setIcon( QIcon(":/Icon8/Images/new_icons/icons8-stop-sign.png")) self.actionCalculate_Theory.setToolTip("Stop current calculations") else: self.actionCalculate_Theory.setIcon( QIcon(":/Icon8/Images/new_icons/icons8-abacus.png")) self.actionCalculate_Theory.setToolTip("Calculate Theory (Alt+C)") def icon_fit_is_stop(self, ans): """Change the "fit" button to "stop" button""" if ans: self.actionMinimize_Error.setIcon( QIcon(":/Icon8/Images/new_icons/icons8-stop-sign.png")) self.actionCalculate_Theory.setToolTip("Stop current calculations") else: self.actionMinimize_Error.setIcon( QIcon(":/Icon8/Images/new_icons/icons8-minimum-value.png")) self.actionCalculate_Theory.setToolTip("Calculate Theory (Alt+C)") def handle_thCurrentChanged(self, index): """Change figure when the active theory tab is changed [description] Arguments: - index {[type]} -- [description] """ self.icon_calculate_is_stop(False) self.icon_fit_is_stop(False) th = self.TheorytabWidget.widget(index) if th: self.current_theory = th.name ntab = self.TheorytabWidget.count() #hide all theory curves for i in range(ntab): if i != index: th_to_hide = self.TheorytabWidget.widget(i) th_to_hide.do_hide() th.do_show() #must be called last, after hiding other theories if th.thread_calc_busy or th.thread_fit_busy: self.icon_calculate_is_stop(th.thread_calc_busy) self.icon_fit_is_stop(th.thread_fit_busy) return else: self.current_theory = None self.theory_actions_disabled(True) self.parent_application.update_plot() self.parent_application.update_Qplot() def handle_thTabBarDoubleClicked(self, index): """Edit Theory name Edit the theory tab name, leave 'theories' dictionary keys unchanged. Two tabs can share the same name Arguments: - index {[type]} -- [description] """ old_name = self.TheorytabWidget.tabText(index) dlg = QInputDialog(self) dlg.setWindowTitle("Change Theory Name") dlg.setLabelText("New Theory Name:") dlg.setTextValue(old_name) dlg.resize(400, 100) success = dlg.exec() new_tab_name = dlg.textValue() if (success and new_tab_name != ""): self.TheorytabWidget.setTabText(index, new_tab_name) # self.theories[old_name].name = new_tab_name # self.theories[new_tab_name] = self.theories.pop(old_name) # self.current_theory = new_tab_name def handle_thTabCloseRequested(self, index): """Delete a theory tab from the current dataset [description] Arguments: - index {[type]} -- [description] """ th_name = self.TheorytabWidget.widget(index).name th = self.theories[th_name] th.Qprint("Close theory tab requested") th.request_stop_computations() self.set_no_limits(th_name) self.do_theory_delete(th_name) #call DataSet.do_theory_delete self.TheorytabWidget.removeTab(index) def handle_itemSelectionChanged(self): """Define actions for when a file table is selected [description] """ selection = self.DataSettreeWidget.selectedItems() if selection == []: self.selected_file = None self.highlight_series() return for f in self.files: if f.file_name_short == selection[0].text(0): self.parent_application.disconnect_curve_drag() self.selected_file = f self.highlight_series() self.populate_inspector() self.parent_application.handle_actionShiftTriggered() def highlight_series(self): """Highligh the data series of the selected file [description] """ self.do_plot() #remove current series highlight file = self.selected_file thname = self.current_theory if thname: th = self.theories[thname] else: th = None if file is not None: dt = file.data_table if th: tt = th.tables[file.file_name_short] for i in range(dt.MAX_NUM_SERIES): for nx in range(self.nplots): view = self.parent_application.multiviews[nx] if (i < view.n and file.active): dt.series[nx][i].set_marker('.') # dt.series[nx][i].set_linestyle(":") dt.series[nx][i].set_markerfacecolor( dt.series[nx][i].get_markeredgecolor()) dt.series[nx][i].set_markeredgecolor('peachpuff') dt.series[nx][i].set_markersize(self.marker_size + 3) dt.series[nx][i].set_markeredgewidth(2) dt.series[nx][i].set_zorder( self.parent_application.zorder) #put series on top if th: if th.active: tt.series[nx][i].set_color('k') tt.series[nx][i].set_path_effects([ pe.Stroke(linewidth=self.th_line_width + 3, foreground='chartreuse'), pe.Normal() ]) tt.series[nx][i].set_zorder( self.parent_application.zorder) self.parent_application.zorder += 1 self.parent_application.update_plot() def populate_inspector(self): """[summary] [description] """ file = self.selected_file if not file: self.parent_application.inspector_table.setRowCount(0) self.parent_application.DataInspectordockWidget.setWindowTitle( "File:") return if self.parent_application.DataInspectordockWidget.isHidden(): return dt = file.data_table nrow = dt.num_rows ncol = dt.num_columns inspec_tab = self.parent_application.inspector_table inspec_tab.file_repr = file inspec_tab.setRowCount(nrow) inspec_tab.setColumnCount(ncol) for i in range(nrow): for j in range(ncol): item = QTableWidgetItem("%.3e" % dt.data[i, j]) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) inspec_tab.setItem(i, j, item) # dt.setItem(row, column, item) ds_index = self.parent_application.DataSettabWidget.currentIndex() self.parent_application.DataInspectordockWidget.setWindowTitle( "File: \"%s\" in %s" % (file.file_name_short, self.parent_application.DataSettabWidget.tabText(ds_index))) inspec_tab.resizeColumnsToContents() inspec_tab.resizeRowsToContents() # Update shift factors for i in range(DataTable.MAX_NUM_SERIES): self.parent_application.update_shifts(0, 0, i) def handle_itemChanged(self, item, column): """[summary] [description] Arguments: - item {[type]} -- [description] - column {[type]} -- [description] """ if column == 0: self.change_file_visibility(item.text(0), item.checkState(column) == Qt.Checked) def handle_sortIndicatorChanged(self, column, order): """Sort files according to the selected parameter (column) and replot [description] Arguments: - column {[type]} -- [description] - order {[type]} -- [description] """ # if column == 0: #do not sort file name # return if self.DataSettreeWidget.topLevelItemCount() > 0: # sort iff there are some files in the dataset sort_param = self.DataSettreeWidget.headerItem().text(column) rev = True if order == Qt.AscendingOrder else False if rev: sort_param = sort_param + ",reverse" self.do_sort(sort_param) self.do_plot() self.set_table_icons(self.table_icon_list) def Qshow_all(self): """Show all the files in this dataset, except those previously hiden [description] """ self.do_show_all() for i in range(self.DataSettreeWidget.topLevelItemCount()): file_name = self.DataSettreeWidget.topLevelItem(i).text(0) if file_name in self.inactive_files: self.DataSettreeWidget.topLevelItem(i).setCheckState(0, 0) else: self.DataSettreeWidget.topLevelItem(i).setCheckState(0, 2) def resizeEvent(self, evt=None): """[summary] [description] Keyword Arguments: - evt {[type]} -- [description] (default: {None}) """ hd = self.DataSettreeWidget.header() w = self.DataSettreeWidget.width() w /= hd.count() for i in range(hd.count()): hd.resizeSection(i, w) #hd.setTextAlignment(i, Qt.AlignHCenter) def handle_itemDoubleClicked(self, item, column): """Edit item entry upon double click [description] Arguments: - item {[type]} -- [description] - column {[type]} -- [description] """ # if column>0: # param = self.DataSettreeWidget.headerItem().text(column) #retrive parameter name # file_name_short = item.text(0) #retrive file name # header = "Edit Parameter" # message = "Do you want to edit %s of \"%s\"?"%(param, file_name_short) # answer = QMessageBox.question(self, header, message) # if answer == QMessageBox.Yes: # old_value = item.text(column) #old parameter value # message = "New value of %s"%param # new_value, success = QInputDialog.getDouble(self, header, message, float(old_value)) # if success: # for file in self.files: # if file.file_name_short == file_name_short: # file.file_parameters[param] = new_value #change value in DataSet # self.DataSettreeWidget.blockSignals(True) #avoid triggering 'itemChanged' signal that causes a false checkbox change # item.setText(column, str(new_value)) #change table label # self.DataSettreeWidget.blockSignals(False) # else: file_name_short = item.text(0) for file in self.files: if file.file_name_short == file_name_short: d = EditFileParametersDialog(self, file) if d.exec_(): for p in d.param_dict: if isinstance(file.file_parameters[p], str): file.file_parameters[p] = d.param_dict[p].text() else: try: file.file_parameters[p] = float( d.param_dict[p].text()) except Exception as e: print(e) for i in range(self.DataSettreeWidget.columnCount()): if p == self.DataSettreeWidget.headerItem().text( i): item.setText(i, str(file.file_parameters[p])) # theory xmin/max try: file.theory_xmin = float(d.th_xmin.text()) except ValueError: file.theory_xmin = "None" try: file.theory_xmax = float(d.th_xmax.text()) except ValueError: file.theory_xmax = "None" # theory logspace and Npoints try: file.th_num_pts = float(d.th_num_pts.text()) except ValueError: pass try: file.th_num_pts = max(int(d.th_num_pts.text()), 2) except ValueError: pass file.theory_logspace = d.th_logspace.isChecked() file.with_extra_x = d.with_extra_x.isChecked() and ( file.theory_xmin != "None" or file.theory_xmax != "None") def handle_actionNew_Theory(self): """Create new theory and do fit [description] """ self.actionNew_Theory.setDisabled(True) if self.cbtheory.currentIndex() == 0: # by default, open first theory in the list th_name = self.cbtheory.itemText(1) else: th_name = self.cbtheory.currentText() self.cbtheory.setCurrentIndex(0) # reset the combobox selection if th_name != '': self.new_theory(th_name) self.actionNew_Theory.setDisabled(False) def new_theory(self, th_name, th_tab_id="", calculate=True, show=True): """[summary] [description] Arguments: - th_name {[type]} -- [description] """ if not self.files: return if self.current_theory: self.set_no_limits( self.current_theory) #remove the xy-range limits self.theory_actions_disabled(False) #enable theory buttons newth = self.do_theory_new(th_name, calculate) # add new theory tab if th_tab_id == "": th_tab_id = newth.name th_tab_id = ''.join( c for c in th_tab_id if c.isupper()) #get the upper case letters of th_name th_tab_id = "%s%d" % (th_tab_id, self.num_theories) #append number #hide all theory curves ntab = self.TheorytabWidget.count() for i in range(ntab): th_to_hide = self.TheorytabWidget.widget(i) th_to_hide.do_hide() #add theory tab self.TheorytabWidget.blockSignals( True) #avoid trigger handle_thCurrentChanged() index = self.TheorytabWidget.addTab(newth, th_tab_id) self.TheorytabWidget.setCurrentIndex( index) #set new theory tab as curent tab self.TheorytabWidget.setTabToolTip(index, th_name) #set new-tab tool tip self.TheorytabWidget.blockSignals(False) if show: newth.update_parameter_table() newth.do_show("") return newth
def edit_contact_dialog(wallet_api, contact_key=None): editing = contact_key is not None if editing: title = _("Edit Contact") else: title = _("New Contact") d = WindowModalDialog(wallet_api.wallet_window, title) vbox = QVBoxLayout(d) vbox.addWidget(QLabel(title + ':')) def _contact_insert_completion(text): if text: index = combo1.findText(text) combo1.setCurrentIndex(index) identity_line = QLineEdit() name_line = QLineEdit() combo1 = QComboBox() combo1.setFixedWidth(280) combo1.setEditable(True) # add a filter model to filter matching items contact_filter_model = QSortFilterProxyModel(combo1) contact_filter_model.setFilterCaseSensitivity(Qt.CaseInsensitive) contact_filter_model.setSourceModel(combo1.model()) contact_completer = QCompleter(contact_filter_model, combo1) contact_completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) combo1.setCompleter(contact_completer) ok_button = OkButton(d) ok_button.setEnabled(False) def _validate_form() -> None: def _set_validation_state(element, is_valid) -> None: if not is_valid: element.setStyleSheet("border: 1px solid red") else: element.setStyleSheet("") can_submit = True system_name = combo1.currentText().lower().strip() is_valid = True try: system_id = get_system_id(system_name) except ContactDataError: system_id = None is_valid = False _set_validation_state(combo1, is_valid) can_submit = can_submit and is_valid identity_text = identity_line.text().strip() if system_id is None: identity_result = IdentityCheckResult.Invalid else: identity_result = wallet_api.check_identity_valid(system_id, identity_text, skip_exists=editing) is_valid = identity_result == IdentityCheckResult.Ok _set_validation_state(identity_line, is_valid) if is_valid: identity_line.setToolTip("") elif identity_result == IdentityCheckResult.Invalid: if system_id == IdentitySystem.OnChain: identity_line.setToolTip(_("Not a valid Bitcoin address")) else: identity_line.setToolTip(_("Incorrect format")) elif identity_result == IdentityCheckResult.InUse: identity_line.setToolTip(_("Already in use")) can_submit = can_submit and is_valid name_text = name_line.text().strip() name_result = wallet_api.check_label(name_text) is_valid = (name_result == IdentityCheckResult.Ok or editing and name_result == IdentityCheckResult.InUse) _set_validation_state(name_line, is_valid) if is_valid: name_line.setToolTip("") elif name_result == IdentityCheckResult.Invalid: name_line.setToolTip(_("Name too short")) elif name_result == IdentityCheckResult.InUse: name_line.setToolTip(_("Name already in use")) can_submit = can_submit and is_valid ok_button.setEnabled(can_submit) def _contact_text_changed(text: str) -> None: _validate_form() combo1.lineEdit().textEdited.connect(contact_filter_model.setFilterFixedString) combo1.editTextChanged.connect(_contact_text_changed) identity_line.textChanged.connect(_contact_text_changed) name_line.textChanged.connect(_contact_text_changed) contact_completer.activated.connect(_contact_insert_completion) combo1.addItems(list(IDENTITY_SYSTEM_NAMES.values())) grid = QGridLayout() identity_line.setFixedWidth(280) name_line.setFixedWidth(280) grid.addWidget(QLabel(_("Identity Type")), 1, 0) grid.addWidget(combo1, 1, 1) grid.addWidget(QLabel(_("Identity")), 2, 0) grid.addWidget(identity_line, 2, 1) grid.addWidget(QLabel(_("Name")), 3, 0) grid.addWidget(name_line, 3, 1) vbox.addLayout(grid) vbox.addLayout(Buttons(CancelButton(d), ok_button)) if contact_key is None: combo1.lineEdit().setText(IDENTITY_SYSTEM_NAMES[IdentitySystem.OnChain]) identity_line.setFocus() else: entry = wallet_api.get_contact(contact_key[0]) identity = [ ci for ci in entry.identities if ci.identity_id == contact_key[1] ][0] combo1.lineEdit().setText(IDENTITY_SYSTEM_NAMES[identity.system_id]) identity_line.setText(identity.system_data) name_line.setText(entry.label) name_line.setFocus() if d.exec_(): name_text = name_line.text().strip() identity_text = identity_line.text().strip() system_id = get_system_id(combo1.currentText()) if contact_key is not None: contact = wallet_api.get_contact(contact_key[0]) identity = [ ci for ci in contact.identities if ci.identity_id == contact_key[1] ][0] if contact_key[1] != identity.identity_id: wallet_api.remove_identity(contact_key[0], contact_key[1]) wallet_api.add_identity(contact_key[0], system_id, identity_text) if contact.label != name_text: wallet_api.set_label(contact_key[0], name_text) else: wallet_api.add_contact(system_id, name_text, identity_text)
class Palette_Docker(DockWidget): # Init the docker def __init__(self): super(Palette_Docker, self).__init__() # make base-widget and layout widget = QWidget() layout = QVBoxLayout() buttonLayout = QHBoxLayout() widget.setLayout(layout) self.setWindowTitle(i18n("Python Palette Docker")) # Make a combobox and add palettes self.cmb_palettes = QComboBox() allPalettes = Application.resources("palette") for palette_name in allPalettes: self.cmb_palettes.addItem(palette_name) self.cmb_palettes.model().sort(0) if len(allPalettes.keys()) > 0: self.currentPalette = Palette(allPalettes[list( allPalettes.keys())[0]]) else: self.currentPalette = None self.cmb_palettes.currentTextChanged.connect(self.slot_paletteChanged) layout.addWidget(self.cmb_palettes) # add combobox to the layout self.paletteView = PaletteView() self.paletteView.setPalette(self.currentPalette) layout.addWidget(self.paletteView) self.paletteView.entrySelectedForeGround.connect( self.slot_swatchSelected) self.colorComboBox = QComboBox() self.colorList = list() buttonLayout.addWidget(self.colorComboBox) self.bnSetColor = QToolButton() self.bnSetColor.setText(i18n("Set")) self.bnSetColor.clicked.connect(self.slot_get_color_from_combobox) buttonLayout.addWidget(self.bnSetColor) self.addEntry = QAction(self) self.addEntry.setIconText(i18n("+")) self.addEntry.triggered.connect(self.slot_add_entry) self.addGroup = QAction(self) self.addGroup.triggered.connect(self.slot_add_group) self.addGroup.setText(i18n("Add Group")) self.addGroup.setIconText(str("\U0001F4C2")) self.removeEntry = QAction(self) self.removeEntry.setText(i18n("Remove Entry")) self.removeEntry.setIconText("-") self.removeEntry.triggered.connect(self.slot_remove_entry) addEntryButton = QToolButton() addEntryButton.setDefaultAction(self.addEntry) buttonLayout.addWidget(addEntryButton) addGroupButton = QToolButton() addGroupButton.setDefaultAction(self.addGroup) buttonLayout.addWidget(addGroupButton) removeEntryButton = QToolButton() removeEntryButton.setDefaultAction(self.removeEntry) buttonLayout.addWidget(removeEntryButton) # QActions self.extra = QToolButton() self.editPaletteData = QAction(self) self.editPaletteData.setText(i18n("Edit Palette Settings")) self.editPaletteData.triggered.connect(self.slot_edit_palette_data) self.extra.setDefaultAction(self.editPaletteData) buttonLayout.addWidget(self.extra) self.actionMenu = QMenu() self.exportToGimp = QAction(self) self.exportToGimp.setText(i18n("Export as GIMP Palette File")) self.exportToGimp.triggered.connect(self.slot_export_to_gimp_palette) self.exportToInkscape = QAction(self) self.exportToInkscape.setText( i18n("Export as Inkscape SVG with Swatches")) self.exportToInkscape.triggered.connect( self.slot_export_to_inkscape_svg) self.sortColors = QAction(self) self.sortColors.setText(i18n("Sort Colors")) self.sortColors.triggered.connect(self.slot_sort_colors) self.actionMenu.addAction(self.editPaletteData) self.actionMenu.addAction(self.exportToGimp) self.actionMenu.addAction(self.exportToInkscape) # self.actionMenu.addAction(self.sortColors) self.extra.setMenu(self.actionMenu) layout.addLayout(buttonLayout) self.slot_fill_combobox() self.setWidget(widget) # add widget to the docker def slot_paletteChanged(self, name): allPalettes = Application.resources("palette") if len(allPalettes) > 0 and name in allPalettes: self.currentPalette = Palette( Application.resources("palette")[name]) self.paletteView.setPalette(self.currentPalette) self.slot_fill_combobox() @pyqtSlot('PaletteEntry') def slot_swatchSelected(self, entry): if (self.canvas()) is not None: if (self.canvas().view()) is not None: name = entry.name() if len(entry.id) > 0: name = entry.id() + " - " + entry.name() if len(name) > 0: if name in self.colorList: self.colorComboBox.setCurrentIndex( self.colorList.index(name)) color = self.currentPalette.colorForEntry(entry) self.canvas().view().setForeGroundColor(color) ''' A function for making a combobox with the available colors. We use QCompleter on the colorComboBox so that people can type in the name of a color to select it. This is useful for people with carefully made palettes where the colors are named properly, which makes it easier for them to find colors. ''' def slot_fill_combobox(self): if self.currentPalette is None: pass palette = self.currentPalette self.colorComboBox.clear() self.colorList = list() for i in range(palette.colorsCountTotal()): entry = palette.colorSetEntryByIndex(i) color = palette.colorForEntry(entry).colorForCanvas(self.canvas()) colorSquare = QPixmap(12, 12) if entry.spotColor() is True: img = colorSquare.toImage() circlePainter = QPainter() img.fill(self.colorComboBox.palette().color(QPalette.Base)) circlePainter.begin(img) brush = QBrush(Qt.SolidPattern) brush.setColor(color) circlePainter.setBrush(brush) circlePainter.pen().setWidth(0) circlePainter.drawEllipse(0, 0, 11, 11) circlePainter.end() colorSquare = QPixmap.fromImage(img) else: colorSquare.fill(color) name = entry.name() if len(entry.id()) > 0: name = entry.id() + " - " + entry.name() self.colorList.append(name) self.colorComboBox.addItem(QIcon(colorSquare), name) self.colorComboBox.setEditable(True) self.colorComboBox.setInsertPolicy(QComboBox.NoInsert) self.colorComboBox.completer().setCompletionMode( QCompleter.PopupCompletion) self.colorComboBox.completer().setCaseSensitivity(False) self.colorComboBox.completer().setFilterMode(Qt.MatchContains) def slot_get_color_from_combobox(self): if self.currentPalette is not None: entry = self.currentPalette.colorSetEntryByIndex( self.colorComboBox.currentIndex()) self.slot_swatchSelected(entry) def slot_add_entry(self): if (self.canvas()) is not None: if (self.canvas().view()) is not None: color = self.canvas().view().foregroundColor() success = self.paletteView.addEntryWithDialog(color) if success is True: self.slot_fill_combobox() def slot_add_group(self): success = self.paletteView.addGroupWithDialog() if success is True: self.slot_fill_combobox() def slot_remove_entry(self): success = self.paletteView.removeSelectedEntryWithDialog() if success is True: self.slot_fill_combobox() ''' A function for giving a gui to edit palette metadata... I also want this to be the way to edit the settings of the palette docker. ''' def slot_edit_palette_data(self): dialog = QDialog(self) tabWidget = QTabWidget() dialog.setWindowTitle(i18n("Edit Palette Data")) dialog.setLayout(QVBoxLayout()) dialog.layout().addWidget(tabWidget) paletteWidget = QWidget() paletteWidget.setLayout(QVBoxLayout()) tabWidget.addTab(paletteWidget, i18n("Palette Data")) paletteName = QLineEdit() paletteName.setText(self.cmb_palettes.currentText()) paletteWidget.layout().addWidget(paletteName) paletteColumns = QSpinBox() paletteColumns.setValue(self.currentPalette.columnCount()) paletteWidget.layout().addWidget(paletteColumns) paletteComment = QPlainTextEdit() paletteComment.appendPlainText(self.currentPalette.comment()) paletteWidget.layout().addWidget(paletteComment) buttons = QDialogButtonBox(QDialogButtonBox.Ok) dialog.layout().addWidget(buttons) buttons.accepted.connect(dialog.accept) # buttons.rejected.connect(dialog.reject()) if dialog.exec_() == QDialog.Accepted: Resource = Application.resources("palette")[ self.cmb_palettes.currentText()] Resource.setName(paletteName.text()) self.currentPalette = Palette(Resource) self.currentPalette.setColumnCount(paletteColumns.value()) self.paletteView.setPalette(self.currentPalette) self.slot_fill_combobox() self.currentPalette.setComment(paletteComment.toPlainText()) self.currentPalette.save() def slot_export_to_gimp_palette(self): palette_exporter_gimppalette.gimpPaletteExporter( self.cmb_palettes.currentText()) def slot_export_to_inkscape_svg(self): palette_exporter_inkscapeSVG.inkscapeSVGExporter( self.cmb_palettes.currentText()) def slot_sort_colors(self): colorSorter = palette_sortColors.sortColors( self.cmb_palettes.currentText()) self.paletteView.setPalette(colorSorter.palette()) def canvasChanged(self, canvas): self.cmb_palettes.clear() allPalettes = Application.resources("palette") for palette_name in allPalettes: self.cmb_palettes.addItem(palette_name) self.cmb_palettes.model().sort(0) if self.currentPalette == None and len(allPalettes.keys()) > 0: self.currentPalette = Palette(allPalettes[list( allPalettes.keys())[0]])
class OWCSVFileImport(widget.OWWidget): name = "CSV File Import" description = "Import a data table from a CSV formatted file." icon = "icons/CSVFile.svg" priority = 11 category = "Data" keywords = ["file", "load", "read", "open", "csv"] outputs = [ widget.OutputSignal( name="Data", type=Orange.data.Table, doc="Loaded data set."), widget.OutputSignal( name="Data Frame", type=pd.DataFrame, doc="" ) ] class Error(widget.OWWidget.Error): error = widget.Msg( "Unexpected error" ) encoding_error = widget.Msg( "Encoding error\n" "The file might be encoded in an unsupported encoding or it " "might be binary" ) #: Paths and options of files accessed in a 'session' _session_items = settings.Setting( [], schema_only=True) # type: List[Tuple[str, dict]] #: Saved dialog state (last directory and selected filter) dialog_state = settings.Setting({ "directory": "", "filter": "" }) # type: Dict[str, str] MaxHistorySize = 50 want_main_area = False buttons_area_orientation = None def __init__(self, *args, **kwargs): super().__init__(self, *args, **kwargs) self.__committimer = QTimer(self, singleShot=True) self.__committimer.timeout.connect(self.commit) self.__executor = qconcurrent.ThreadExecutor() self.__watcher = None # type: Optional[qconcurrent.FutureWatcher] self.controlArea.layout().setSpacing(-1) # reset spacing grid = QGridLayout() grid.addWidget(QLabel("File:", self), 0, 0, 1, 1) self.import_items_model = QStandardItemModel(self) self.recent_combo = QComboBox( self, objectName="recent-combo", toolTip="Recent files.", sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, minimumContentsLength=16, ) self.recent_combo.setModel(self.import_items_model) self.recent_combo.activated.connect(self.activate_recent) self.recent_combo.setSizePolicy( QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) self.browse_button = QPushButton( "…", icon=self.style().standardIcon(QStyle.SP_DirOpenIcon), toolTip="Browse filesystem", autoDefault=False, ) self.browse_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.browse_button.clicked.connect(self.browse) grid.addWidget(self.recent_combo, 0, 1, 1, 1) grid.addWidget(self.browse_button, 0, 2, 1, 1) self.controlArea.layout().addLayout(grid) ########### # Info text ########### box = gui.widgetBox(self.controlArea, "Info", addSpace=False) self.summary_text = QTextBrowser( verticalScrollBarPolicy=Qt.ScrollBarAsNeeded, readOnly=True, ) self.summary_text.viewport().setBackgroundRole(QPalette.NoRole) self.summary_text.setFrameStyle(QTextBrowser.NoFrame) self.summary_text.setMinimumHeight(self.fontMetrics().ascent() * 2 + 4) self.summary_text.viewport().setAutoFillBackground(False) box.layout().addWidget(self.summary_text) button_box = QDialogButtonBox( orientation=Qt.Horizontal, standardButtons=QDialogButtonBox.Cancel | QDialogButtonBox.Retry ) self.load_button = b = button_box.button(QDialogButtonBox.Retry) b.setText("Load") b.clicked.connect(self.__committimer.start) b.setEnabled(False) b.setDefault(True) self.cancel_button = b = button_box.button(QDialogButtonBox.Cancel) b.clicked.connect(self.cancel) b.setEnabled(False) b.setAutoDefault(False) self.import_options_button = QPushButton( "Import Options…", enabled=False, autoDefault=False, clicked=self._activate_import_dialog ) def update_buttons(cbindex): self.import_options_button.setEnabled(cbindex != -1) self.load_button.setEnabled(cbindex != -1) self.recent_combo.currentIndexChanged.connect(update_buttons) button_box.addButton( self.import_options_button, QDialogButtonBox.ActionRole ) button_box.setStyleSheet( "button-layout: {:d};".format(QDialogButtonBox.MacLayout) ) self.controlArea.layout().addWidget(button_box) self._restoreState() if self.current_item() is not None: self._invalidate() self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Maximum) @Slot(int) def activate_recent(self, index): """ Activate an item from the recent list. """ if 0 <= index < self.import_items_model.rowCount(): item = self.import_items_model.item(index) assert item is not None path = item.data(ImportItem.PathRole) opts = item.data(ImportItem.OptionsRole) if not isinstance(opts, Options): opts = None self.set_selected_file(path, opts) else: self.recent_combo.setCurrentIndex(-1) @Slot() def browse(self): """ Open a file dialog and select a user specified file. """ formats = [ "Text - comma separated (*.csv, *)", "Text - tab separated (*.tsv, *)", "Text - all files (*)" ] dlg = QFileDialog( self, windowTitle="Open Data File", acceptMode=QFileDialog.AcceptOpen, fileMode=QFileDialog.ExistingFile ) dlg.setNameFilters(formats) state = self.dialog_state lastdir = state.get("directory", "") lastfilter = state.get("filter", "") if lastdir and os.path.isdir(lastdir): dlg.setDirectory(lastdir) if lastfilter: dlg.selectNameFilter(lastfilter) status = dlg.exec_() dlg.deleteLater() if status == QFileDialog.Accepted: self.dialog_state["directory"] = dlg.directory().absolutePath() self.dialog_state["filter"] = dlg.selectedNameFilter() selected_filter = dlg.selectedNameFilter() path = dlg.selectedFiles()[0] # pre-flight check; try to determine the nature of the file mtype = _mime_type_for_path(path) if not mtype.inherits("text/plain"): mb = QMessageBox( parent=self, windowTitle="", icon=QMessageBox.Question, text="The '{basename}' may be a binary file.\n" "Are you sure you want to continue?".format( basename=os.path.basename(path)), standardButtons=QMessageBox.Cancel | QMessageBox.Yes ) mb.setWindowModality(Qt.WindowModal) if mb.exec() == QMessageBox.Cancel: return # initialize dialect based on selected extension if selected_filter in formats[:-1]: filter_idx = formats.index(selected_filter) if filter_idx == 0: dialect = csv.excel() elif filter_idx == 1: dialect = csv.excel_tab() else: dialect = csv.excel_tab() header = True else: try: dialect, header = sniff_csv_with_path(path) except Exception: # pylint: disable=broad-except dialect, header = csv.excel(), True options = None # Search for path in history. # If found use the stored params to initialize the import dialog items = self.itemsFromSettings() idx = index_where(items, lambda t: samepath(t[0], path)) if idx is not None: _, options_ = items[idx] if options_ is not None: options = options_ if options is None: if not header: rowspec = [] else: rowspec = [(range(0, 1), RowSpec.Header)] options = Options( encoding="utf-8", dialect=dialect, rowspec=rowspec) dlg = CSVImportDialog( self, windowTitle="Import Options", sizeGripEnabled=True) dlg.setWindowModality(Qt.WindowModal) dlg.setPath(path) dlg.setOptions(options) status = dlg.exec_() dlg.deleteLater() if status == QDialog.Accepted: self.set_selected_file(path, dlg.options()) def current_item(self): # type: () -> Optional[ImportItem] """ Return the current selected item (file) or None if there is no current item. """ idx = self.recent_combo.currentIndex() if idx == -1: return None item = self.recent_combo.model().item(idx) # type: QStandardItem if isinstance(item, ImportItem): return item else: return None def _activate_import_dialog(self): """Activate the Import Options dialog for the current item.""" item = self.current_item() assert item is not None dlg = CSVImportDialog( self, windowTitle="Import Options", sizeGripEnabled=True, ) dlg.setWindowModality(Qt.WindowModal) dlg.setAttribute(Qt.WA_DeleteOnClose) settings = QSettings() qualname = qname(type(self)) settings.beginGroup(qualname) size = settings.value("size", QSize(), type=QSize) # type: QSize if size.isValid(): dlg.resize(size) path = item.data(ImportItem.PathRole) options = item.data(ImportItem.OptionsRole) dlg.setPath(path) # Set path before options so column types can if isinstance(options, Options): dlg.setOptions(options) def update(): newoptions = dlg.options() item.setData(newoptions, ImportItem.OptionsRole) # update the stored item self._add_recent(path, newoptions) if newoptions != options: self._invalidate() dlg.accepted.connect(update) def store_size(): settings.setValue("size", dlg.size()) dlg.finished.connect(store_size) dlg.show() def set_selected_file(self, filename, options=None): """ Set the current selected filename path. """ self._add_recent(filename, options) self._invalidate() #: Saved options for a filename SCHEMA = { "path": str, # Local filesystem path "options": str, # json encoded 'Options' } @classmethod def _local_settings(cls): # type: () -> QSettings """Return a QSettings instance with local persistent settings.""" filename = "{}.ini".format(qname(cls)) fname = os.path.join(settings.widget_settings_dir(), filename) return QSettings(fname, QSettings.IniFormat) def _add_recent(self, filename, options=None): # type: (str, Optional[Options]) -> None """ Add filename to the list of recent files. """ model = self.import_items_model index = index_where( (model.index(i, 0).data(ImportItem.PathRole) for i in range(model.rowCount())), lambda path: isinstance(path, str) and samepath(path, filename) ) if index is not None: item, *_ = model.takeRow(index) else: item = ImportItem.fromPath(filename) model.insertRow(0, item) if options is not None: item.setOptions(options) self.recent_combo.setCurrentIndex(0) # store items to local persistent settings s = self._local_settings() arr = QSettings_readArray(s, "recent", OWCSVFileImport.SCHEMA) item = {"path": filename} if options is not None: item["options"] = json.dumps(options.as_dict()) arr = [item for item in arr if item.get("path") != filename] arr.append(item) QSettings_writeArray(s, "recent", arr) # update workflow session items items = self._session_items[:] idx = index_where(items, lambda t: samepath(t[0], filename)) if idx is not None: del items[idx] items.insert(0, (filename, options.as_dict())) self._session_items = items[:OWCSVFileImport.MaxHistorySize] def _invalidate(self): # Invalidate the current output and schedule a new commit call. # (NOTE: The widget enters a blocking state) self.__committimer.start() if self.__watcher is not None: self.__cancel_task() self.setBlocking(True) def commit(self): """ Commit the current state and submit the load task for execution. Note ---- Any existing pending task is canceled. """ self.__committimer.stop() if self.__watcher is not None: self.__cancel_task() self.error() item = self.current_item() if item is None: return path = item.data(ImportItem.PathRole) opts = item.data(ImportItem.OptionsRole) if not isinstance(opts, Options): return task = state = TaskState() state.future = ... state.watcher = qconcurrent.FutureWatcher() state.progressChanged.connect(self.__set_read_progress, Qt.QueuedConnection) def progress_(i, j): task.emitProgressChangedOrCancel(i, j) task.future = self.__executor.submit( clear_stack_on_cancel(load_csv), path, opts, progress_, ) task.watcher.setFuture(task.future) w = task.watcher w.done.connect(self.__handle_result) w.progress = state self.__watcher = w self.__set_running_state() @Slot('qint64', 'qint64') def __set_read_progress(self, read, count): if count > 0: self.progressBarSet(100 * read / count) def __cancel_task(self): # Cancel and dispose of the current task assert self.__watcher is not None w = self.__watcher w.future().cancel() w.progress.cancel = True w.done.disconnect(self.__handle_result) w.progress.progressChanged.disconnect(self.__set_read_progress) w.progress.deleteLater() # wait until completion futures.wait([w.future()]) self.__watcher = None def cancel(self): """ Cancel current pending or executing task. """ if self.__watcher is not None: self.__cancel_task() self.__clear_running_state() self.setStatusMessage("Cancelled") self.summary_text.setText( "<div>Cancelled<br/><small>Press 'Reload' to try again</small></div>" ) def __set_running_state(self): self.progressBarInit() self.setBlocking(True) self.setStatusMessage("Running") self.cancel_button.setEnabled(True) self.load_button.setText("Restart") path = self.current_item().path() self.Error.clear() self.summary_text.setText( "<div>Loading: <i>{}</i><br/>".format(prettyfypath(path)) ) def __clear_running_state(self, ): self.progressBarFinished() self.setStatusMessage("") self.setBlocking(False) self.cancel_button.setEnabled(False) self.load_button.setText("Reload") def __set_error_state(self, err): self.Error.clear() if isinstance(err, UnicodeDecodeError): self.Error.encoding_error(exc_info=err) else: self.Error.error(exc_info=err) path = self.current_item().path() basename = os.path.basename(path) if isinstance(err, UnicodeDecodeError): text = ( "<div><i>{basename}</i> was not loaded due to a text encoding " "error. The file might be saved in an unknown or invalid " "encoding, or it might be a binary file.</div>" ).format( basename=escape(basename) ) else: text = ( "<div><i>{basename}</i> was not loaded due to an error:" "<p style='white-space: pre;'>{err}</p>" ).format( basename=escape(basename), err="".join(traceback.format_exception_only(type(err), err)) ) self.summary_text.setText(text) def __clear_error_state(self): self.Error.error.clear() self.summary_text.setText("") def onDeleteWidget(self): """Reimplemented.""" if self.__watcher is not None: self.__cancel_task() self.__executor.shutdown() super().onDeleteWidget() @Slot(object) def __handle_result(self, f): # type: (qconcurrent.Future[pd.DataFrame]) -> None assert f.done() assert f is self.__watcher.future() self.__watcher = None self.__clear_running_state() try: df = f.result() assert isinstance(df, pd.DataFrame) except pandas.errors.EmptyDataError: df = pd.DataFrame({}) except Exception as e: # pylint: disable=broad-except self.__set_error_state(e) df = None else: self.__clear_error_state() if df is not None: table = pandas_to_table(df) else: table = None self.send("Data Frame", df) self.send('Data', table) self._update_status_messages(table) def _update_status_messages(self, data): if data is None: return def pluralize(seq): return "s" if len(seq) != 1 else "" summary = ("{n_instances} row{plural_1}, " "{n_features} feature{plural_2}, " "{n_meta} meta{plural_3}").format( n_instances=len(data), plural_1=pluralize(data), n_features=len(data.domain.attributes), plural_2=pluralize(data.domain.attributes), n_meta=len(data.domain.metas), plural_3=pluralize(data.domain.metas)) self.summary_text.setText(summary) def itemsFromSettings(self): # type: () -> List[Tuple[str, Options]] """ Return items from local history. """ s = self._local_settings() items_ = QSettings_readArray(s, "recent", OWCSVFileImport.SCHEMA) items = [] # type: List[Tuple[str, Options]] for item in items_: path = item.get("path", "") if not path: continue opts_json = item.get("options", "") try: opts = Options.from_dict(json.loads(opts_json)) except (csv.Error, LookupError, TypeError, json.JSONDecodeError): _log.error("Could not reconstruct options for '%s'", path, exc_info=True) else: items.append((path, opts)) return items[::-1] def _restoreState(self): # Restore the state. Merge session (workflow) items with the # local history. model = self.import_items_model # local history items = self.itemsFromSettings() # stored session items sitems = [] for p, m in self._session_items: try: item_ = (p, Options.from_dict(m)) except (csv.Error, LookupError): # Is it better to fail then to lose a item slot? _log.error("Failed to restore '%s'", p, exc_info=True) else: sitems.append(item_) items = sitems + items items = unique(items, key=lambda t: pathnormalize(t[0])) curr = self.recent_combo.currentIndex() if curr != -1: currentpath = self.recent_combo.currentData(ImportItem.PathRole) else: currentpath = None for path, options in items: item = ImportItem.fromPath(path) item.setOptions(options) model.appendRow(item) if currentpath is not None: idx = self.recent_combo.findData(currentpath, ImportItem.PathRole) if idx != -1: self.recent_combo.setCurrentIndex(idx)
class OptionsWidget(QWidget): ''' main class to create the tabs containing the different options to steer the analysis''' def __init__(self, parent): super().__init__() self.parent = parent self.layout = QGridLayout() self.group = QGroupBox() self.add_contents() self.group.setLayout(self.layout) self.setLayout(self.layout) def add_contents(self): pass def add_start_button(self, h): pushButton = QPushButton("Start") pushButton.clicked.connect(self.on_pushButton_start) self.layout.addWidget(pushButton, h, 0, 2, 3) def add_detail_button(self, h): pushButton = QPushButton("Details") pushButton.clicked.connect(self.on_pushButton_details) self.layout.addWidget(pushButton, h, 0, 2, 3) def add_time_period(self, h): inner_group = QGroupBox() inner_layout = QGridLayout() self.ComboBoxStart = QComboBox() for i,key in enumerate(self.parent.all_dates): self.ComboBoxStart.addItem(key) inner_layout.addWidget(self.ComboBoxStart, 0, 0) inner_layout.addWidget(QLabel("-"), 0, 1) self.ComboBoxEnd = QComboBox() for i,key in enumerate(self.parent.all_dates): self.ComboBoxEnd.addItem(key) self.ComboBoxEnd.setCurrentIndex(len(self.parent.all_dates)-1) inner_layout.addWidget(self.ComboBoxEnd, 0, 2) inner_group.setLayout(inner_layout) self.layout.addWidget(QLabel("Zeitraum"), h, 0) self.layout.addWidget(inner_group, h, 1, 1, 2) # self.layout.addWidget(QColumn(QLabel("Zeitraum"),inner_group)) # newl = QLabel() newl.setFrameStyle(QFrame.HLine ) self.layout.addWidget(newl, h+1, 0, 1, 3) def add_configure(self,h): pushButton = QPushButton("Auswahl") pushButton.clicked.connect(self.on_pushButton_config) # self.layout.addWidget(QColumn(QLabel("Kategorien"), pushButton)) self.layout.addWidget(QLabel("Kategorien"), h, 0) self.layout.addWidget(pushButton, h, 1, 1, 2) newl = QLabel() newl.setFrameStyle(QFrame.HLine ) self.layout.addWidget(newl, h+1, 0, 1, 3) def add_radio_log(self, h, lines=1): plot1_group=QButtonGroup(QWidget(self)) self.radioPlot1 = QRadioButton("Linear") self.radioPlot2 = QRadioButton("Log") plot1_group.addButton(self.radioPlot1) plot1_group.addButton(self.radioPlot2) self.radioPlot1.setChecked(True) # self.layout.addWidget(QColumn3(QLabel("Skala Plot 1"),self.radioPlot1, self.radioPlot2 )) self.layout.addWidget(QLabel("Skala Plot 1"), h, 0) self.layout.addWidget(self.radioPlot1, h, 1) self.layout.addWidget(self.radioPlot2, h, 2) if lines > 1: self.radioPlot1b = QRadioButton("Linear") self.radioPlot2b = QRadioButton("Log") self.radioPlot1b.setChecked(True) plot2_group=QButtonGroup(QWidget(self)) plot2_group.addButton(self.radioPlot1b) plot2_group.addButton(self.radioPlot2b) # self.layout.addWidget(QColumn3(QLabel("Skala Plot 2"),self.radioPlot1b, self.radioPlot2b)) self.layout.addWidget(QLabel("Skala Plot 2"), h+1, 0) self.layout.addWidget(self.radioPlot1b, h+1, 1) self.layout.addWidget(self.radioPlot2b, h+1, 2) newl = QLabel() newl.setFrameStyle(QFrame.HLine ) self.layout.addWidget(newl, h+2, 0, 1, 3) def add_radio_level(self, h): self.radioLevel1 = QRadioButton("fein") self.radioLevel2 = QRadioButton("grob") self.radioLevel2.setChecked(True) level_group=QButtonGroup(QWidget(self)) level_group.addButton(self.radioLevel1) level_group.addButton(self.radioLevel2) # self.layout.addWidget(QColumn(self.radioLevel1, self.radioLevel2 )) self.layout.addWidget(QLabel("Zusammenfassung"), h, 0) self.layout.addWidget(self.radioLevel1, h, 1) self.layout.addWidget(self.radioLevel2, h, 2) def add_fine_category(self,h): self.ComboBoxFine = QComboBox() for i,key in enumerate(self.parent.KEYS.OUT[1]): self.ComboBoxFine.addItem(key) item = self.ComboBoxFine.model().item(i, 0) item.setCheckState(Qt.Unchecked) newl = QLabel() newl.setFrameStyle(QFrame.HLine ) self.layout.addWidget(newl, h+1, 0, 1, 3) self.layout.addWidget(QLabel("Details"), h+2, 0) self.layout.addWidget(self.ComboBoxFine, h+2, 1, 1, 2) def on_pushButton_start(self): pass def on_pushButton_config(self): pass def on_pushButton_details(self): pass def set_dates(self): self.date_start = analyse.go_to_last_day(datetime.datetime.strptime(self.ComboBoxStart.currentText() ,"%m/%Y").date()) self.date_end = analyse.go_to_last_day(datetime.datetime.strptime(self.ComboBoxEnd.currentText() ,"%m/%Y").date())
class SvgView(QWidget): def __init__(self, dockwidget): super(SvgView, self).__init__(dockwidget) self._document = None self._setting_zoom = False self.view = view.View(self) self.pageLabel = QLabel() self.pageCombo = QComboBox(sizeAdjustPolicy=QComboBox.AdjustToContents) layout = QVBoxLayout(spacing=0) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) hbox = QHBoxLayout(spacing=0) hbox.addWidget(self.pageLabel) hbox.addWidget(self.pageCombo) self.zoomInButton = QToolButton(autoRaise=True) self.zoomOutButton = QToolButton(autoRaise=True) self.zoomOriginalButton = QToolButton(autoRaise=True) self.zoomNumber = QSpinBox(minimum=10, maximum=1000, suffix='%') ac = dockwidget.actionCollection self.zoomInButton.setDefaultAction(ac.svg_zoom_in) self.zoomOutButton.setDefaultAction(ac.svg_zoom_out) self.zoomOriginalButton.setDefaultAction(ac.svg_zoom_original) hbox.addWidget(self.zoomInButton) hbox.addWidget(self.zoomNumber) hbox.addWidget(self.zoomOutButton) hbox.addWidget(self.zoomOriginalButton) self.resetButton = QPushButton("reload", self) self.resetButton.clicked.connect(self.reLoadDoc) hbox.addWidget(self.resetButton) self.saveButton = QPushButton("save edits", self) self.saveButton.clicked.connect(self.callSave) hbox.addWidget(self.saveButton) hbox.addStretch(1) layout.addLayout(hbox) layout.addWidget(self.view) app.jobFinished.connect(self.initSvg) app.documentClosed.connect(self.slotDocumentClosed) app.documentLoaded.connect(self.initSvg) self.pageCombo.currentIndexChanged.connect(self.changePage) self.zoomNumber.valueChanged.connect(self.slotZoomNumberChanged) self.view.zoomFactorChanged.connect(self.slotViewZoomChanged) dockwidget.mainwindow().currentDocumentChanged.connect(self.initSvg) self.zoomNumber.setValue(100) doc = dockwidget.mainwindow().currentDocument() if doc: self.initSvg(doc) app.translateUI(self) def translateUI(self): self.pageLabel.setText(_("Page:")) def mainwindow(self): return self.parent().mainwindow() def initSvg(self, doc): """Opens first page of score after compilation""" if doc == self.mainwindow().currentDocument(): files = svgfiles.SvgFiles.instance(doc) model = files.model() # forces update if files: self._document = doc with qutil.signalsBlocked(self.pageCombo): self.pageCombo.setModel(model) self.pageCombo.setCurrentIndex(files.current) self.view.load(files.url(files.current)) def reLoadDoc(self): """Reloads current document.""" if self._document: self.initSvg(self._document) def callSave(self): """Call save function""" self.view.evalSave() def getCurrent(self): files = svgfiles.SvgFiles.instance(self._document) return files.filename(files.current) def slotZoomNumberChanged(self, value): self._setting_zoom = True self.view.setZoomFactor(value / 100.0) self._setting_zoom = False def slotViewZoomChanged(self): if not self._setting_zoom: self.zoomNumber.setValue(int(self.view.zoomFactor() * 100)) def changePage(self, page_index): """change page of score""" doc = self._document if doc: files = svgfiles.SvgFiles.instance(doc) if files: files.current = page_index svg = files.url(page_index) self.view.load(svg) def slotDocumentClosed(self, doc): if doc == self._document: self._document = None if self.pageCombo.model(): self.pageCombo.model().deleteLater() self.pageCombo.clear() self.pageCombo.update() # otherwise it doesn't redraw self.view.clear()
def run_iface_config_window(icon): win = QDialog() win.setWindowTitle('CAN Interface Configuration') win.setWindowIcon(icon) win.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowCloseButtonHint) win.setAttribute(Qt.WA_DeleteOnClose) # This is required to stop background timers! combo = QComboBox(win) combo.setEditable(True) combo.setInsertPolicy(QComboBox.NoInsert) combo.setSizeAdjustPolicy(QComboBox.AdjustToContents) combo.setFont(get_monospace_font()) combo_completer = QCompleter() combo_completer.setCaseSensitivity(Qt.CaseSensitive) combo_completer.setModel(combo.model()) combo.setCompleter(combo_completer) bitrate = QSpinBox(win) bitrate.setMaximum(1000000) bitrate.setMinimum(10000) bitrate.setValue(1000000) baudrate = QComboBox(win) baudrate.setEditable(True) baudrate.setInsertPolicy(QComboBox.NoInsert) baudrate.setSizeAdjustPolicy(QComboBox.AdjustToContents) baudrate.setFont(get_monospace_font()) baudrate_completer = QCompleter(win) baudrate_completer.setModel(baudrate.model()) baudrate.setCompleter(baudrate_completer) baudrate.setValidator(QIntValidator(min(STANDARD_BAUD_RATES), max(STANDARD_BAUD_RATES))) baudrate.insertItems(0, map(str, STANDARD_BAUD_RATES)) baudrate.setCurrentText(str(DEFAULT_BAUD_RATE)) ok = QPushButton('OK', win) def update_slcan_options_visibility(): if RUNNING_ON_LINUX: slcan_active = '/' in combo.currentText() else: slcan_active = True slcan_group.setEnabled(slcan_active) combo.currentTextChanged.connect(update_slcan_options_visibility) ifaces = None def update_iface_list(): nonlocal ifaces ifaces = iface_lister.get_list() known_keys = set() remove_indices = [] was_empty = combo.count() == 0 # Marking known and scheduling for removal for idx in count(): tx = combo.itemText(idx) if not tx: break known_keys.add(tx) if tx not in ifaces: logger.debug('Removing iface %r', tx) remove_indices.append(idx) # Removing - starting from the last item in order to retain indexes for idx in remove_indices[::-1]: combo.removeItem(idx) # Adding new items - starting from the last item in order to retain the final order for key in list(ifaces.keys())[::-1]: if key not in known_keys: logger.debug('Adding iface %r', key) combo.insertItem(0, key) # Updating selection if was_empty: combo.setCurrentIndex(0) result = None kwargs = {} def on_ok(): nonlocal result, kwargs try: baud_rate_value = int(baudrate.currentText()) except ValueError: show_error('Invalid parameters', 'Could not parse baud rate', 'Please specify correct baud rate', parent=win) return if not (min(STANDARD_BAUD_RATES) <= baud_rate_value <= max(STANDARD_BAUD_RATES)): show_error('Invalid parameters', 'Baud rate is out of range', 'Baud rate value should be within [%s, %s]' % (min(STANDARD_BAUD_RATES), max(STANDARD_BAUD_RATES)), parent=win) return kwargs['baudrate'] = baud_rate_value kwargs['bitrate'] = int(bitrate.value()) result_key = str(combo.currentText()).strip() if not result_key: show_error('Invalid parameters', 'Interface name cannot be empty', 'Please select a valid interface', parent=win) return try: result = ifaces[result_key] except KeyError: result = result_key win.close() ok.clicked.connect(on_ok) layout = QVBoxLayout(win) layout.addWidget(QLabel('Select CAN interface')) layout.addWidget(combo) slcan_group = QGroupBox('SLCAN adapter settings', win) slcan_layout = QVBoxLayout(slcan_group) slcan_layout.addWidget(QLabel('CAN bus bit rate:')) slcan_layout.addWidget(bitrate) slcan_layout.addWidget(QLabel('Adapter baud rate (not applicable to USB-CAN adapters):')) slcan_layout.addWidget(baudrate) slcan_group.setLayout(slcan_layout) layout.addWidget(slcan_group) layout.addWidget(ok) layout.setSizeConstraint(layout.SetFixedSize) win.setLayout(layout) with BackgroundIfaceListUpdater() as iface_lister: update_slcan_options_visibility() update_iface_list() timer = QTimer(win) timer.setSingleShot(False) timer.timeout.connect(update_iface_list) timer.start(int(BackgroundIfaceListUpdater.UPDATE_INTERVAL / 2 * 1000)) win.exec() return result, kwargs
def run_setup_window(icon): win = QDialog() win.setWindowTitle('Application Setup') win.setWindowIcon(icon) win.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowCloseButtonHint) win.setAttribute( Qt.WA_DeleteOnClose) # This is required to stop background timers! combo = QComboBox(win) combo.setEditable(True) combo.setInsertPolicy(QComboBox.NoInsert) combo.setSizeAdjustPolicy(QComboBox.AdjustToContents) combo.setFont(get_monospace_font()) combo_completer = QCompleter() combo_completer.setCaseSensitivity(Qt.CaseSensitive) combo_completer.setModel(combo.model()) combo.setCompleter(combo_completer) bitrate = QSpinBox(win) bitrate.setMaximum(1000000) bitrate.setMinimum(10000) bitrate.setValue(1000000) baudrate = QComboBox(win) baudrate.setEditable(True) baudrate.setInsertPolicy(QComboBox.NoInsert) baudrate.setSizeAdjustPolicy(QComboBox.AdjustToContents) baudrate.setFont(get_monospace_font()) baudrate_completer = QCompleter(win) baudrate_completer.setModel(baudrate.model()) baudrate.setCompleter(baudrate_completer) baudrate.setValidator( QIntValidator(min(STANDARD_BAUD_RATES), max(STANDARD_BAUD_RATES))) baudrate.insertItems(0, map(str, STANDARD_BAUD_RATES)) baudrate.setCurrentText(str(DEFAULT_BAUD_RATE)) dir_selection = DirectorySelectionWidget(win) ok = QPushButton('OK', win) def update_slcan_options_visibility(): if RUNNING_ON_LINUX: slcan_active = '/' in combo.currentText() else: slcan_active = True slcan_group.setEnabled(slcan_active) combo.currentTextChanged.connect(update_slcan_options_visibility) ifaces = None def update_iface_list(): nonlocal ifaces ifaces = iface_lister.get_list() known_keys = set() remove_indices = [] was_empty = combo.count() == 0 # Marking known and scheduling for removal for idx in count(): tx = combo.itemText(idx) if not tx: break known_keys.add(tx) if tx not in ifaces: logger.debug('Removing iface %r', tx) remove_indices.append(idx) # Removing - starting from the last item in order to retain indexes for idx in remove_indices[::-1]: combo.removeItem(idx) # Adding new items - starting from the last item in order to retain the final order for key in list(ifaces.keys())[::-1]: if key not in known_keys: logger.debug('Adding iface %r', key) combo.insertItem(0, key) # Updating selection if was_empty: combo.setCurrentIndex(0) result = None kwargs = {} def on_ok(): nonlocal result, kwargs try: baud_rate_value = int(baudrate.currentText()) except ValueError: show_error('Invalid parameters', 'Could not parse baud rate', 'Please specify correct baud rate', parent=win) return if not (min(STANDARD_BAUD_RATES) <= baud_rate_value <= max(STANDARD_BAUD_RATES)): show_error('Invalid parameters', 'Baud rate is out of range', 'Baud rate value should be within [%s, %s]' % (min(STANDARD_BAUD_RATES), max(STANDARD_BAUD_RATES)), parent=win) return kwargs['baudrate'] = baud_rate_value kwargs['bitrate'] = int(bitrate.value()) result_key = str(combo.currentText()).strip() if not result_key: show_error('Invalid parameters', 'Interface name cannot be empty', 'Please select a valid interface', parent=win) return try: result = ifaces[result_key] except KeyError: result = result_key win.close() ok.clicked.connect(on_ok) can_group = QGroupBox('CAN interface setup', win) can_layout = QVBoxLayout() can_layout.addWidget(QLabel('Select CAN interface')) can_layout.addWidget(combo) slcan_group = QGroupBox('SLCAN adapter settings', win) slcan_layout = QGridLayout() slcan_layout.addWidget(QLabel('CAN bus bit rate:'), 0, 0) slcan_layout.addWidget(bitrate, 0, 1) slcan_layout.addWidget( QLabel('Adapter baud rate (not applicable to USB-CAN adapters):'), 1, 0) slcan_layout.addWidget(baudrate, 1, 1) slcan_group.setLayout(slcan_layout) can_layout.addWidget(slcan_group) can_group.setLayout(can_layout) layout = QVBoxLayout() layout.addWidget(can_group) layout.addWidget(dir_selection) layout.addWidget(ok) layout.setSizeConstraint(layout.SetFixedSize) win.setLayout(layout) with BackgroundIfaceListUpdater() as iface_lister: update_slcan_options_visibility() update_iface_list() timer = QTimer(win) timer.setSingleShot(False) timer.timeout.connect(update_iface_list) timer.start(int(BackgroundIfaceListUpdater.UPDATE_INTERVAL / 2 * 1000)) win.exec() return result, kwargs, dir_selection.get_selection()
class SvgView(QWidget): def __init__(self, dockwidget): super(SvgView, self).__init__(dockwidget) self._document = None self._setting_zoom = False self.view = view.View(self) self.pageLabel = QLabel() self.pageCombo = QComboBox(sizeAdjustPolicy=QComboBox.AdjustToContents) layout = QVBoxLayout(spacing=0) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) hbox = QHBoxLayout(spacing=0) hbox.addWidget(self.pageLabel) hbox.addWidget(self.pageCombo) self.zoomInButton = QToolButton(autoRaise=True) self.zoomOutButton = QToolButton(autoRaise=True) self.zoomOriginalButton = QToolButton(autoRaise=True) self.zoomNumber = QSpinBox(minimum=10, maximum=1000, suffix="%") ac = dockwidget.actionCollection self.zoomInButton.setDefaultAction(ac.svg_zoom_in) self.zoomOutButton.setDefaultAction(ac.svg_zoom_out) self.zoomOriginalButton.setDefaultAction(ac.svg_zoom_original) hbox.addWidget(self.zoomInButton) hbox.addWidget(self.zoomNumber) hbox.addWidget(self.zoomOutButton) hbox.addWidget(self.zoomOriginalButton) self.resetButton = QPushButton("reload", self) self.resetButton.clicked.connect(self.reLoadDoc) hbox.addWidget(self.resetButton) self.saveButton = QPushButton("save edits", self) self.saveButton.clicked.connect(self.callSave) hbox.addWidget(self.saveButton) hbox.addStretch(1) layout.addLayout(hbox) layout.addWidget(self.view) app.jobFinished.connect(self.initSvg) app.documentClosed.connect(self.slotDocumentClosed) app.documentLoaded.connect(self.initSvg) self.pageCombo.currentIndexChanged.connect(self.changePage) self.zoomNumber.valueChanged.connect(self.slotZoomNumberChanged) self.view.zoomFactorChanged.connect(self.slotViewZoomChanged) dockwidget.mainwindow().currentDocumentChanged.connect(self.initSvg) self.zoomNumber.setValue(100) doc = dockwidget.mainwindow().currentDocument() if doc: self.initSvg(doc) app.translateUI(self) def translateUI(self): self.pageLabel.setText(_("Page:")) def mainwindow(self): return self.parent().mainwindow() def initSvg(self, doc): """Opens first page of score after compilation""" if doc == self.mainwindow().currentDocument(): files = svgfiles.SvgFiles.instance(doc) model = files.model() # forces update if files: self._document = doc with qutil.signalsBlocked(self.pageCombo): self.pageCombo.setModel(model) self.pageCombo.setCurrentIndex(files.current) self.view.load(files.url(files.current)) def reLoadDoc(self): """Reloads current document.""" if self._document: self.initSvg(self._document) def callSave(self): """Call save function""" self.view.evalSave() def getCurrent(self): files = svgfiles.SvgFiles.instance(self._document) return files.filename(files.current) def slotZoomNumberChanged(self, value): self._setting_zoom = True self.view.setZoomFactor(value / 100.0) self._setting_zoom = False def slotViewZoomChanged(self): if not self._setting_zoom: self.zoomNumber.setValue(int(self.view.zoomFactor() * 100)) def changePage(self, page_index): """change page of score""" doc = self._document if doc: files = svgfiles.SvgFiles.instance(doc) if files: files.current = page_index svg = files.url(page_index) self.view.load(svg) def slotDocumentClosed(self, doc): if doc == self._document: self._document = None if self.pageCombo.model(): self.pageCombo.model().deleteLater() self.pageCombo.clear() self.pageCombo.update() # otherwise it doesn't redraw self.view.clear()
class SelectModelWidget(QWidget): """QTabWidget that holds all of the selectable models and the accompanying ModelDialog for each. """ update_progressbar = pyqtSignal(int, bool) def __init__(self, parent=None): super(SelectModelWidget, self).__init__(parent) self.logger = logging.getLogger(__name__) self.parent = parent self.threadpool = QThreadPool() self.logger.info( f"Multithreading enabled with a maximum of {self.threadpool.maxThreadCount()} threads." ) print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount()) self.training_data = pd.DataFrame() self.training_predictions = pd.DataFrame() self.selected_version = CONFIG.get('PATHS', 'DefaultModelDirectory') self.comms = Communicate() self.selected_models = {} self.selected_models['sklearn'] = {} self.selected_models['tensorflow'] = {} self.model_checkboxes = [] # * Initialize training parameter dict. # * Has entry for both model base types self.training_params = {} self.training_params['sklearn'] = {} self.training_params['sklearn']['type'] = None self.training_params['sklearn']['value'] = None self.training_params['tensorflow'] = {} # * Init tuning param dict # * Currently only using gridsearch self.tuning_params = {} self.tuning_params['gridsearch'] = { 'n_iter': 20, 'cv': 3, 'n_jobs': -1, 'scoring': ['accuracy'], 'tune_stacker': False } self.sklearn_model_dialogs = [] self.sklearn_model_dialog_btns = [] self.sklearn_training_inputs = [] self.tensorflow_training_inputs = [] self.tensorflow_model_dialogs = [] self.tensorflow_model_dialog_btns = [] self.main_layout = QVBoxLayout() self.upper_hbox = QHBoxLayout() self.version_form = QFormLayout() self.header_hbox = QHBoxLayout() self.header_hbox.addLayout(self.version_form) self.header_hbox.addStretch() self.tune_models_chkbox = QCheckBox("Tune Models") self.header_hbox.addWidget(self.tune_models_chkbox) self.tune_models_chkbox.stateChanged.connect( lambda state: self._enable_tuning_ui(state)) self.main_layout.addLayout(self.header_hbox) self.main_layout.addLayout(self.upper_hbox) self.model_vbox = QVBoxLayout() self.tuning_vbox = QVBoxLayout() self.upper_hbox.addLayout(self.model_vbox) self.upper_hbox.addSpacing(10) self.upper_hbox.addLayout(self.tuning_vbox) self.upper_hbox.addSpacing(200) # * Build sklearn ui components self.sklearn_hbox = QHBoxLayout() self.sklearn_groupbox = QGroupBox("Sklearn") self.sklearn_groupbox.setLayout(self.sklearn_hbox) self.skmodel_groupbox = QGroupBox("Model Selection") self.sklearn_hbox.addWidget(self.skmodel_groupbox) self.sklearn_model_form = QFormLayout() self.sklearn_model_form.setFormAlignment(Qt.AlignTop) self.skmodel_groupbox.setLayout(self.sklearn_model_form) # * Sklearn training and tuning ui components self.sklearn_training_groupbox = QGroupBox("Training") self.sklearn_training_form = QFormLayout() self.sklearn_training_groupbox.setLayout(self.sklearn_training_form) self.sklearn_hbox.addWidget(self.sklearn_training_groupbox) self.model_vbox.addWidget(self.sklearn_groupbox) # * Build Tensorflow ui components self.tensorflow_hbox = QHBoxLayout() self.tensorflow_groupbox = QGroupBox("Tensorflow") self.tensorflow_groupbox.setLayout(self.tensorflow_hbox) self.tensorflow_model_groupbox = QGroupBox("Model Selection") self.tensorflow_hbox.addWidget(self.tensorflow_model_groupbox) self.tensorflow_model_form = QFormLayout() self.tensorflow_model_groupbox.setLayout(self.tensorflow_model_form) self.tensorflow_training_groupbox = QGroupBox("Training") self.tensorflow_training_form = QFormLayout() self.tensorflow_training_groupbox.setLayout( self.tensorflow_training_form) self.tensorflow_hbox.addWidget(self.tensorflow_training_groupbox) # * This is the tensorflow groupbox for models and training params. # self.model_vbox.addWidget(self.tensorflow_groupbox) self.tuning_groupbox = QGroupBox("Tuning") self.tuning_form = QFormLayout() self.tuning_groupbox.setLayout(self.tuning_form) self.tuning_vbox.addWidget(self.tuning_groupbox) self.tuning_groupbox.setEnabled(False) self.model_form_grid = QGridLayout() self.setup_model_selection_ui() self.setup_training_ui() self.setup_tuning_ui() # * QTextEdit box for training/tuning status self.training_logger = QTextEdit() self.training_logger.setReadOnly(True) self.training_logger.setAcceptRichText(True) self.training_logger.insertHtml( "<i>Multithreading with maximum %d threads</i><br>" % self.threadpool.maxThreadCount()) self.training_logger.setMinimumHeight(400) self.main_layout.addWidget(self.training_logger) self.clear_btn_hbox = QHBoxLayout() self.clear_text_btn = QPushButton('Clear') self.clear_text_btn.setMaximumWidth(50) self.clear_text_btn.clicked.connect( lambda: self.training_logger.clear()) self.clear_btn_hbox.addStretch() self.clear_btn_hbox.addWidget(self.clear_text_btn) self.main_layout.addLayout(self.clear_btn_hbox) self.main_layout.addStretch() self.run_btn = QPushButton("&Train Models") self.run_btn.setMinimumWidth(200) self.run_btn.clicked.connect(lambda: self.train_models()) self.run_btn.setEnabled(False) self.stop_btn = QPushButton('Sto&p') self.stop_btn.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.comms.enable_training_btn.connect(self.set_training_btn_state) self.button_hbox = QHBoxLayout() icon = QIcon() icon.addPixmap(QPixmap('icons/Programming-Save-icon.png')) self.save_results_btn = QPushButton() self.save_results_btn.setIcon(icon) self.save_results_btn.setEnabled(False) self.save_results_btn.setToolTip( 'Save model evaluation predictions, agreement ratio, and bamboozled score' ) self.save_results_btn.clicked.connect(lambda: self.save_predictions()) self.button_hbox.addWidget(self.run_btn) self.button_hbox.addWidget(self.stop_btn) self.button_hbox.addStretch() self.button_hbox.addWidget(self.save_results_btn) self.main_layout.addLayout(self.button_hbox) self.setLayout(self.main_layout) # Trigger update to load model parameters self._update_version(self.version_selection.currentData()) def setup_model_selection_ui(self): """ Setup model selection ui. The order of the parameters in ModelDialog matters. model_data must come first! """ self.version_selection_label = QLabel("Select version: ") self.version_selection = QComboBox(objectName='version_select') self.version_selection.setMinimumWidth(100) # Changed default models to a unique directory. This # is where default models will be saved. # self.version_selection.addItem( # 'default', '.\\package\\data\\default_models\\default') available_versions = os.listdir(BASE_VERSION_DIR) for version in available_versions: v_path = os.path.join(BASE_VERSION_DIR, version) if os.path.isdir(v_path): self.version_selection.addItem(version, v_path) self.version_selection.currentIndexChanged.connect( lambda x, y=self.version_selection: self._update_version( y.currentData())) self.version_form.addRow(self.version_selection_label, self.version_selection) # Load base TF-IDF features # and feature selection data try: with open(CONFIG.get('PATHS', 'BaseTfidfDirectory'), 'r') as f: tfidf_data = json.load(f) except IOError as ioe: self.logger.error("Error loading base TFIDF params", exc_info=True) exceptionWarning( 'Error occurred while loading base TFIDF parameters.', repr(ioe)) try: with open(CONFIG.get('PATHS', 'BaseFeatureSeletionDirectory'), 'r') as f: self.fs_params = json.load(f) except IOError as ioe: self.logger.error("Error loading base feature selector params", exc_info=True) exceptionWarning( 'Error occurred while loading base feature selector parameters.', repr(ioe)) # Dynamically generate ModelDialogs for each model in the base model directory. # Only considers *.json file extension. try: row = 0 for filename in os.listdir( CONFIG.get('PATHS', 'BaseModelDirectory')): if filename.endswith('.json'): with open( os.path.join( CONFIG.get('PATHS', 'BaseModelDirectory'), filename), 'r') as f: model_data = json.load(f) model = model_data['model_class'] model_base = model_data['model_base'] model_module = model_data['model_module'] #! The order of the arguments matters! model_data must come first. if model_base == 'tensorflow': continue # model_dialog = SkModelDialog(self, model_data) if model_module == 'tpot': model_dialog = TPOTModelDialog( self, model_data, tfidf_data) else: model_dialog = SkModelDialog( self, model_data, tfidf_data, self.fs_params) self.comms.version_change.connect( model_dialog.update_version) # Initialize model as unselected self.selected_models[model_base][model] = False btn = QPushButton(model, objectName=model + '_btn') # Partial allows the connection of dynamically generated QObjects btn.clicked.connect( partial(self.open_dialog, model_dialog)) chkbox = QCheckBox(objectName=model) chkbox.stateChanged.connect( lambda state, x=model, y=model_base: self. _update_selected_models(x, y, state)) if model_base == 'tensorflow': self.tensorflow_model_form.addRow(chkbox, btn) self.tensorflow_model_dialogs.append(model_dialog) self.tensorflow_model_dialog_btns.append(btn) else: self.sklearn_model_form.addRow(chkbox, btn) self.sklearn_model_dialogs.append(model_dialog) self.sklearn_model_dialog_btns.append(btn) self.model_checkboxes.append(chkbox) row += 1 except OSError as ose: self.logger.error("OSError opening model config files", exc_info=True) exceptionWarning('OSError opening model config files!', ose) tb = traceback.format_exc() print(tb) except Exception as e: self.logger.error("Error opening model config files", exc_info=True) exceptionWarning('Error occured.', e) tb = traceback.format_exc() print(tb) def setup_training_ui(self): """ Build ui components for training parameters for both Sklearn and Tensorflow """ # Sklearn training first self.cv_n_fold_input = QSpinBox(objectName='n_folds') self.cv_n_fold_input.setRange(2, 10) self.cv_n_fold_input.setValue(5) self.cv_n_fold_input.setEnabled(False) self.cv_n_fold_input.valueChanged.connect( lambda state, x=self.cv_n_fold_input: self.update_training_params( 'sklearn', 'cv', x.value())) self.cv_radio_btn = QRadioButton("Cross-validation", objectName='cv') self.cv_radio_btn.toggled.connect( lambda state, x=self.cv_n_fold_input: self. _update_sklearn_training_type('cv', x.value())) self.sklearn_training_form.addRow(self.cv_radio_btn, self.cv_n_fold_input) self.sk_validation_radio_btn = QRadioButton("Validation set") self.sk_validation_percent_input = QDoubleSpinBox( objectName='test_split') self.sk_validation_percent_input.setRange(0.05, 1) self.sk_validation_percent_input.setSingleStep(0.1) self.sk_validation_percent_input.setEnabled(False) self.sk_validation_percent_input.valueChanged.connect( lambda state, x=self.sk_validation_percent_input: self. update_training_params('sklearn', 'validation', x.value())) self.sk_validation_radio_btn.toggled.connect( lambda state, x=self.sk_validation_percent_input: self. _update_sklearn_training_type('validation', x.value())) # NOTE: Removing validation split option from evaluation. It seems less than useful and # requires time that could be spent elsewhere as we near the end of our time together. # self.sklearn_training_form.addRow(self.sk_validation_radio_btn, self.sk_validation_percent_input) self.no_eval_btn = QRadioButton("No evaluation set", objectName='no_eval') self.no_eval_btn.toggled.connect( lambda: self._update_sklearn_training_type(None, None)) self.sklearn_training_form.addRow(self.no_eval_btn) # TENSORFLOW TRAINING UI. Removed as of 10/04/19 # Toggle to set params on load self.cv_radio_btn.toggle() # * Select stacker # self.stacker_groupbox = QGroupBox('Stacking algorithm') # self.stacker_vbox = QVBoxLayout() # self.train_stacker def setup_tuning_ui(self): self.tuning_n_iter_label = QLabel("Number of iterations:") self.tuning_n_iter_input = QSpinBox(objectName='n_iter') self.tuning_n_iter_input.setRange(2, 1000) self.tuning_n_iter_input.setSingleStep(1) self.tuning_n_iter_input.setValue(10) self.tuning_n_iter_input.valueChanged.connect( lambda state, x=self.tuning_n_iter_input: self. update_tuning_params('gridsearch', 'n_iter', x.value())) self.tuning_form.addRow(self.tuning_n_iter_label, self.tuning_n_iter_input) self.tuning_cv_label = QLabel("CV folds:") self.tuning_cv_input = QSpinBox(objectName='cv') self.tuning_cv_input.setRange(2, 10) self.tuning_cv_input.setValue(3) self.tuning_cv_input.valueChanged.connect( lambda state, x=self.tuning_cv_input: self.update_tuning_params( 'gridsearch', 'cv', x.value())) self.tuning_form.addRow(self.tuning_cv_label, self.tuning_cv_input) self.tuning_n_jobs_label = QLabel("Number of parallel jobs:") self.tuning_n_jobs_input = QSpinBox(objectName='n_jobs') self.tuning_n_jobs_input.setRange(-1, 4) self.tuning_n_jobs_input.setValue(-1) self.tuning_n_jobs_input.valueChanged.connect( lambda state, x=self.tuning_n_jobs_input: self. update_tuning_params('gridsearch', 'n_jobs', x.value())) self.tuning_form.addRow(self.tuning_n_jobs_label, self.tuning_n_jobs_input) self.scoring_metric_groupbox = QGroupBox('Scoring metrics') self.scoring_metric_vbox = QVBoxLayout() # * The following code is for metric radio buttons. Left in for posterity # self.acc_checkbox = QRadioButton('Accuracy') # self.acc_checkbox.setChecked(True) # self.acc_checkbox.toggled.connect( # lambda state, x=self.acc_checkbox: # self.update_tuning_params('gridsearch', 'scoring', 'accuracy') # ) # self.scoring_metric_vbox.addWidget(self.acc_checkbox) # self.f1_weighted_checkbox = QRadioButton('F1 weighted') # self.f1_weighted_checkbox.setChecked(False) # self.f1_weighted_checkbox.toggled.connect( # lambda state, x=self.f1_weighted_checkbox: # self.update_tuning_params('gridsearch', 'scoring', 'f1_weighted') # ) # self.scoring_metric_vbox.addWidget(self.f1_weighted_checkbox) # self.prec_weighted_checkbox = QRadioButton('Precision weighted') # self.prec_weighted_checkbox.setChecked(False) # self.prec_weighted_checkbox.toggled.connect( # lambda state, x=self.prec_weighted_checkbox: # self.update_tuning_params( # 'gridsearch', 'scoring', 'precision_weighted') # ) # self.scoring_metric_vbox.addWidget(self.prec_weighted_checkbox) self.acc_checkbox = QCheckBox('Accuracy') self.acc_checkbox.setChecked(True) self.acc_checkbox.stateChanged.connect( lambda state, x=self.acc_checkbox: self.update_tuning_params( 'gridsearch', 'accuracy', state, True)) self.scoring_metric_vbox.addWidget(self.acc_checkbox) self.f1_weighted_checkbox = QCheckBox('F1 weighted') self.f1_weighted_checkbox.setChecked(False) self.f1_weighted_checkbox.stateChanged.connect( lambda state, x=self.f1_weighted_checkbox: self. update_tuning_params('gridsearch', 'f1_weighted', state, True)) self.scoring_metric_vbox.addWidget(self.f1_weighted_checkbox) self.prec_weighted_checkbox = QCheckBox('Precision weighted') self.prec_weighted_checkbox.setChecked(False) self.prec_weighted_checkbox.stateChanged.connect( lambda state, x=self. prec_weighted_checkbox: self.update_tuning_params( 'gridsearch', 'precision_weighted', state, True)) self.scoring_metric_vbox.addWidget(self.prec_weighted_checkbox) self.scoring_metric_groupbox.setLayout(self.scoring_metric_vbox) self.tune_stacker_checkbox = QCheckBox('Tune Stacking Algorithm') self.tune_stacker_checkbox.setChecked(False) self.tune_stacker_checkbox.stateChanged.connect( lambda state, x=self.tune_stacker_checkbox: self. update_tuning_params('gridsearch', 'tune_stacker', state)) self.tuning_form.addRow(self.scoring_metric_groupbox) self.tuning_form.addRow(self.tune_stacker_checkbox) def open_dialog(self, dialog): """ Opens the passed ModelDialog via the save_params function, allowing the user to specify hyperparameters for each available version field. # Arguments dialog: ModelDialog, Specified model dialog. """ dialog.save_params() @pyqtSlot(str) def add_new_version(self, v_dir): """ pyqtSlot to receive new version created pyqtSignal. # Arguments v_dir: string, directory of newly created version. """ version = v_dir.split('\\')[-1] self.version_selection.addItem(version, v_dir) self.version_selection.model().sort(0) @pyqtSlot(pd.DataFrame) def load_data(self, data): """ pyqtSlot to receive pandas DataFrame after DataLoader has completed it's work # Arguments data: pandas.DataFrame, training data """ self.training_data = data self.comms.enable_training_btn.emit(True) @pyqtSlot(Qt.CheckState) def set_training_btn_state(self): """ Sets the run button enabled state. Checks that there are models selected in sklearn or tensorflow """ if (not self.training_data.empty and (1 in self.selected_models['sklearn'].values() or 1 in self.selected_models['tensorflow'].values())): self.run_btn.setEnabled(True) else: self.run_btn.setEnabled(False) @pyqtSlot(str, bool) def model_exists(self, model_name, truth): """ Adds styling to button if a trained model exists for the model in the selected version # Arguments model_name: string, name of the model designated by the button. truth: bool, true if there exists any trained model of type model_name in the current version. """ btn = self.findChild(QPushButton, model_name + '_btn') if btn: text = btn.text() if text.endswith("*"): text = text[:-2] if truth: btn.setText(text + " *") else: btn.setText(text) else: return def train_models(self): try: tune_models = self.tune_models_chkbox.isChecked() self.model_trainer = ModelTrainer( selected_models=self.selected_models, version_directory=self.selected_version, training_eval_params=self.training_params, training_data=self.training_data, tune_models=tune_models, tuning_params=self.tuning_params) self.model_trainer.signals.update_training_logger.connect( self.update_training_logger) self.update_progressbar.emit(1, True) self.model_trainer.signals.training_complete.connect( self.training_complete) self.comms.stop_training.connect(self.model_trainer.stop_thread) self.run_btn.setEnabled(False) self.stop_btn.clicked.connect(lambda: self._abort_training()) self.training_predictions = pd.DataFrame() self.threadpool.start(self.model_trainer) except Exception as e: self.logger.error("SelectModelWidget.train_models", exc_info=True) exceptionWarning('Exception occured when training models.', e) tb = traceback.format_exc() print(tb) @pyqtSlot(str, bool, bool) def update_training_logger(self, msg, include_time=True, use_html=True): ''' Slot that receives signals updating the terminal. # Arguments msg: string, Message to display in terminal include_time: bool, prepend time to message use_html: bool, insert text as html ''' if (include_time): current_time = time.localtime() outbound = f"{time.strftime('%Y-%m-%d %H:%M:%S', current_time)} - {msg}<br>" else: outbound = f"{msg}<br>" if (use_html): self.training_logger.insertHtml(outbound) self.training_logger.moveCursor(QTextCursor.End) else: self.training_logger.insertPlainText(msg) @pyqtSlot(pd.DataFrame) def training_complete(self, prediction_df=None): """ Resets progressbar, unchecks 'Train models', and emits signal to refresh the parameter values in each ModelDialog # Arguments val: int or float, value used to set progressbar pulse: bool, used to toggle progressbar pulse """ self.update_progressbar.emit(0, False) self.run_btn.setEnabled(True) self.run_btn.setText("Train models") self.tune_models_chkbox.setChecked(False) self.save_results_btn.setEnabled(True) if (prediction_df is not None and not prediction_df.empty): self.training_predictions = prediction_df # Emitting a version change here reloads all parameters. i.e. we update the # parameters displayed in the dialog. self.comms.version_change.emit(self.selected_version) def save_predictions(self): ''' Save predictions to user specified file. Opens a QFileDialog to choose save directory. ''' try: if self.training_predictions.empty: exceptionWarning('No predictions to save') return file_name, filter = QFileDialog.getSaveFileName( self, 'Save to CSV', os.getenv('HOME'), 'CSV(*.csv)') if file_name: self.training_predictions.to_csv(file_name, index_label='testnum', quoting=1, encoding='utf-8') self.comms.update_statusbar.emit( "Predictions saved successfully.") except PermissionError as pe: self.logger.warning("SelectModelWidget.save_predictions", exc_info=True) exceptionWarning( f'Permission denied while attempting to save {file_name}') except Exception as e: self.logger.error("SelectModelWidget.save_predictions", exc_info=True) exceptionWarning( "Exception occured. SelectModelWidget.save_predictions.", exception=e) tb = traceback.format_exc() print(tb) def _abort_training(self): ''' Notifies the ModelTrainer to abort training. ! Note: training ends only after the current training or tuning event ends. ''' self.comms.stop_training.emit() def _update_version(self, directory): """ Parses selected version directory and emits pyqtSignal to update each ModelDialog # Arguments directory: string, directory selected by user. """ self.selected_version = directory # Emit pyqtSignal self.comms.version_change.emit(directory) def _update_selected_models(self, model, model_base, state): """ Update the models selected by the user. This function is connected to the checkboxes associated with each model. # Arguments: model: string, name of the selected model state: bool, the truth of the selection. True->selected, False->unselected """ truth = False if state == Qt.Checked: truth = True self.selected_models[model_base][model] = truth self.comms.enable_training_btn.emit(truth) def _enable_tuning_ui(self, state): """ Helper function to enable/disable the tuning parameter UI if selected by the user. # Arguments: state: bool, the state of tuning. False->no tuning, True->tune models """ self.run_btn.setText("Tune Models" if state else "Train Models") self.tuning_groupbox.setEnabled(state) def update_tuning_params(self, model_base, param, value, scorer=False): ''' Updates the tuning parameters passed to ModelTrainer. # Arguments model_base: string, Signifies which type of tuning parameter to update. Currently, only used by RandomizedSearchCV (sklearn) param: string, parameter name value: [int, float, string], parameter value ''' if model_base is None or param is None: return try: if scorer: if value: self.tuning_params[model_base]['scoring'].append(param) else: if param in self.tuning_params[model_base]['scoring']: self.tuning_params[model_base]['scoring'].remove(param) else: self.tuning_params[model_base][param] = value except KeyError as ke: self.tuning_params[model_base][param] = {} self.tuning_params[model_base][param] = value except Exception as e: self.logger.error("SelectModelWidget.update_tuning_params", exc_info=True) exceptionWarning('Exception occured when training models.', e) tb = traceback.format_exc() print(tb) print(self.tuning_params) def update_training_params(self, model_base, param, value): """ Update the various training parameters with values supplied by the user. Needs work as the sklearn training parameters are mutually exclusive. # Arguments model_base: string, model base for specified training params param: string, parameter name value: string, int, or double, value of specified parameter """ if model_base is None or param is None: return try: # FIXME: This is super hackish and brittle. Can it be done more eloquently? if model_base == 'sklearn': self._update_sklearn_training_type(param, value) else: self.training_params[model_base][param] = value except KeyError as ke: print(ke) def _update_sklearn_training_type(self, eval_type, value): """ SKlearn model tuning is mutually exclusive. This helper function Enables/disables the appropriate field and updates the appropriate parameters of self.training_params Currently, for Sklearn models, only cross-validation (cv) or a holdout set (validation) or None are model evaluation options. # Arguments eval_type: string, The type of model evaluation specified by the user. value: int or double, value corresponding to selected type """ truth = False if eval_type == 'cv': self.cv_n_fold_input.setEnabled(not truth) self.sk_validation_percent_input.setEnabled(truth) elif eval_type == 'validation': self.cv_n_fold_input.setEnabled(truth) self.sk_validation_percent_input.setEnabled(not truth) elif eval_type == None: self.cv_n_fold_input.setEnabled(False) self.sk_validation_percent_input.setEnabled(False) else: raise ValueError("eval_type %s is invalid" % (eval_type)) self.training_params['sklearn']['type'] = eval_type self.training_params['sklearn']['value'] = value
def run_iface_config_window(icon): win = QDialog() win.setWindowTitle('CAN Interface Configuration') win.setWindowIcon(icon) win.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowCloseButtonHint) combo = QComboBox(win) combo.setEditable(True) combo.setInsertPolicy(QComboBox.NoInsert) combo.setSizeAdjustPolicy(QComboBox.AdjustToContents) combo.setFont(get_monospace_font()) combo_completer = QCompleter() combo_completer.setCaseSensitivity(Qt.CaseSensitive) combo_completer.setModel(combo.model()) combo.setCompleter(combo_completer) bitrate = QSpinBox() bitrate.setMaximum(1000000) bitrate.setMinimum(10000) bitrate.setValue(1000000) extra_args = QLineEdit() extra_args.setFont(get_monospace_font()) ok = QPushButton('OK', win) ifaces = None def update_iface_list(): nonlocal ifaces ifaces = iface_lister.get_list() known_keys = set() remove_indices = [] was_empty = combo.count() == 0 # Marking known and scheduling for removal for idx in count(): tx = combo.itemText(idx) if not tx: break known_keys.add(tx) if tx not in ifaces: logger.debug('Removing iface %r', tx) remove_indices.append(idx) # Removing - starting from the last item in order to retain indexes for idx in remove_indices[::-1]: combo.removeItem(idx) # Adding new items - starting from the last item in order to retain the final order for key in list(ifaces.keys())[::-1]: if key not in known_keys: logger.debug('Adding iface %r', key) combo.insertItem(0, key) # Updating selection if was_empty: combo.setCurrentIndex(0) result = None kwargs = {} def on_ok(): nonlocal result, kwargs a = str(extra_args.text()) if a: try: kwargs = dict(eval(a)) except Exception as ex: show_error('Invalid parameters', 'Could not parse optional arguments', ex, parent=win) return kwargs['bitrate'] = int(bitrate.value()) result_key = str(combo.currentText()).strip() if not result_key: show_error('Invalid parameters', 'Interface name cannot be empty', 'Please select a valid interface', parent=win) return try: result = ifaces[result_key] except KeyError: result = result_key win.close() ok.clicked.connect(on_ok) layout = QVBoxLayout() layout.addWidget(QLabel('Select CAN interface or serial port for SLCAN:')) layout.addWidget(combo) layout.addWidget(QLabel('Interface bitrate (SLCAN only):')) layout.addWidget(bitrate) layout.addWidget(QLabel('Optional arguments (refer to PyUAVCAN for info):')) layout.addWidget(extra_args) layout.addWidget(ok) layout.setSizeConstraint(layout.SetFixedSize) win.setLayout(layout) with BackgroundIfaceListUpdater() as iface_lister: update_iface_list() timer = QTimer(win) timer.setSingleShot(False) timer.timeout.connect(update_iface_list) timer.start(int(BackgroundIfaceListUpdater.UPDATE_INTERVAL / 2 * 1000)) win.exec() return result, kwargs
class Drums(_base.Part): @staticmethod def title(_=_base.translate): return _("Drums") @staticmethod def short(_=_base.translate): return _("abbreviation for Drums", "Dr.") def createWidgets(self, layout): self.voicesLabel = QLabel() self.voices = QSpinBox(minimum=1, maximum=4, value=1) self.drumStyleLabel = QLabel() self.drumStyle = QComboBox() self.drumStyle.setModel(listmodel.ListModel(drumStyles, self.drumStyle, display=listmodel.translate)) self.drumStems = QCheckBox() box = QHBoxLayout() box.addWidget(self.voicesLabel) box.addWidget(self.voices) layout.addLayout(box) box = QHBoxLayout() box.addWidget(self.drumStyleLabel) box.addWidget(self.drumStyle) layout.addLayout(box) layout.addWidget(self.drumStems) def translateWidgets(self): self.voicesLabel.setText(_("Voices:")) self.drumStyleLabel.setText(_("Style:")) self.drumStems.setText(_("Remove stems")) self.drumStems.setToolTip(_("Remove the stems from the drum notes.")) self.drumStyle.model().update() def assignDrums(self, data, name = None): r"""Creates an empty name = \drummode assignment. Returns the assignment. """ a = data.assign(name) s = ly.dom.DrumMode(a) ly.dom.Identifier(data.globalName, s) ly.dom.LineComment(_("Drums follow here."), s) ly.dom.BlankLine(s) return a def build(self, data, builder): p = ly.dom.DrumStaff() s = ly.dom.Simr(p) if self.voices.value() > 1: for i in range(1, self.voices.value() + 1): q = ly.dom.Seq(ly.dom.DrumVoice(parent=s)) ly.dom.Text('\\voice' + ly.util.int2text(i), q) a = self.assignDrums(data, 'drum' + ly.util.int2text(i)) ly.dom.Identifier(a.name, q) else: a = self.assignDrums(data, 'drum') ly.dom.Identifier(a.name, s) builder.setInstrumentNamesFromPart(p, self, data) i = self.drumStyle.currentIndex() if i > 0: v = ('drums', 'timbales', 'congas', 'bongos', 'percussion')[i] p.getWith()['drumStyleTable'] = ly.dom.Scheme(v + '-style') v = (5, 2, 2, 2, 1)[i] ly.dom.Line("\\override StaffSymbol #'line-count = #{0}".format(v), p.getWith()) if self.drumStems.isChecked(): ly.dom.Line("\\override Stem #'stencil = ##f", p.getWith()) ly.dom.Line("\\override Stem #'length = #3 % " + _("keep some distance."), p.getWith()) data.nodes.append(p)
class SinglePlayerWindow(QMainWindow): def __init__(self): super().__init__() self.setGeometry(200, 200, 1000, 600) self.setWindowTitle("OnePlayer") self.initUI() def initUI(self): self.initWindow() self.username() self.chooseShip() self.buttonPlay() def initWindow(self): self.BackGround = QPixmap(get_full_image_path("galaxy.jpg")) self.BackGroundLabel = QtWidgets.QLabel(self) self.BackGroundLabel.setPixmap(self.BackGround) self.BackGroundLabel.setGeometry(0, 0, 1000, 600) def username(self): self.enterNameLabel = QtWidgets.QLabel(self) self.enterNameLabel.setText("Enter name") self.enterNameLabel.setGeometry(200, 150, 200, 50) self.enterNameLabel.setStyleSheet(" color: white;font-size: 26px; font-family: Arial Black;"); self.player1NameLineEdit = QLineEdit(self) self.player1NameLineEdit.setGeometry(200, 200, 200, 50) def chooseShip(self): self.choseShipLabel = QLabel(self) self.choseShipLabel.setText("Choose ship") self.choseShipLabel.setGeometry(410, 150, 200, 50) self.choseShipLabel.setStyleSheet(" color: white;font-size: 26px; font-family: Arial Black;"); self.player1Cb = QComboBox(self) self.player1Cb.setStyleSheet("border:1px solid rgb(220, 20, 60); color: red; font-family: Helvetica;"); self.player1Cb.addItem("") self.player1Cb.addItem("red") self.player1Cb.addItem("green") self.player1Cb.addItem("yellow") self.player1Cb.addItem("blue") self.player1Cb.model().item(0).setEnabled(False) self.player1Cb.setGeometry(410, 200, 200, 50) def buttonPlay(self): self.playButton = QtWidgets.QPushButton(self) self.playButton.setText("PLAY") self.playButton.setGeometry(750, 400, 200, 50) self.playButton.setStyleSheet( "border:2px solid rgb(120, 20, 60); color: blue;font-size: 26px; font-family: Arial Black;") self.playButton.clicked.connect(self.onPlayButtonClicked) def onPlayButtonClicked(self): if self.player1NameLineEdit.text() == "" or str(self.player1Cb.currentText()) == "": msg = QMessageBox() msg.setIcon(QMessageBox.NoIcon) msg.setText("Enter your username and choose ship") msg.setWindowTitle("Error") msg.exec_() else: player1_input = PlayerInput(player_id=self.player1NameLineEdit.text(), color=self.player1Cb.currentText()) _start_game_process(player1_input, title="Asteroids - SinglePlayer") self.hide() self.player1NameLineEdit.setText("")
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.gain = 0xffff self.shape = ecodes.FF_SQUARE self.period_ms = 10 self.magnitude = 0x7fff self.offset = 0 self.phase = 0 self.duration_ms = 1000 self.repeat_count = 1 self.envelope_attack_length = 0 self.envelope_attack_level = 0 self.envelope_fade_length = 0 self.envelope_fade_level = 0 self.id = None widget = QWidget(parent=self) self.setCentralWidget(widget) self.device_selector = QComboBox(parent=widget) self.device_selector.setModel(DeviceProvider()) refresh_button = QPushButton('Refresh', parent=widget) refresh_button.clicked.connect( lambda: self.device_selector.model().refresh()) play_button = QPushButton('Play', parent=widget) play_button.clicked.connect(self.play_clicked) stop_button = QPushButton('Stop', parent=widget) stop_button.clicked.connect(self.stop_clicked) layout = QGridLayout() layout.addWidget(QLabel("Device:"), 0, 0) layout.addWidget(self.device_selector, 0, 1) layout.addWidget(refresh_button, 0, 2) self.add_form(layout, 1, "Gain", 0, 100, 100, self.update_gain) effect_widget = QGroupBox("Effect") effect_layout = QGridLayout() effect_widget.setLayout(effect_layout) layout.addWidget(effect_widget, 2, 0, 1, -1) effect_layout.addWidget(QLabel("Shape:"), 0, 0) shape_selector = ShapeSelector() shape_selector.currentIndexChanged.connect(self.update_shape) effect_layout.addWidget(shape_selector, 0, 1) self.add_form(effect_layout, 1, "Period (ms)", 0, 0xffff, 10, self.update_period) self.add_form(effect_layout, 2, "Magnitude", -100, 100, 100, self.update_magnitude) self.add_form(effect_layout, 3, "Offset", -0x8000, 0x7fff, 0, self.update_offset) self.add_form(effect_layout, 4, "Phase", 0, 0xffff, 0, self.update_phase) self.add_form(effect_layout, 5, "Duration (ms)", 0, 0xffff, 1000, self.update_duration) self.add_form(effect_layout, 6, "Repeat count", 0, 0x7fffffff, 1, self.update_repeat_count) envelope_widget = QGroupBox("Envelope parameters") envelope_layout = QGridLayout() self.add_form(envelope_layout, 0, "Attack length (ms)", 0, 0xffff, 0, self.update_attack_length) self.add_form(envelope_layout, 1, "Attack level", 0, 0xffff, 0, self.update_attack_level) self.add_form(envelope_layout, 2, "Fade length (ms)", 0, 0xffff, 0, self.update_fade_length) self.add_form(envelope_layout, 3, "Fade level", 0, 0xffff, 0, self.update_fade_level) envelope_widget.setLayout(envelope_layout) effect_layout.addWidget(envelope_widget, 7, 0, 1, -1) w2 = QWidget() blayout = QHBoxLayout() blayout.addWidget(stop_button) blayout.addWidget(play_button) w2.setLayout(blayout) layout.addWidget(w2, 3, 0, 1, -1) layout.setRowStretch(0, 1) layout.setRowStretch(1, 1) layout.setRowStretch(2, 4) layout.setRowStretch(3, 0) widget.setLayout(layout) def add_form(self, layout, row, label, minimum, maximum, default_value, valueChanged_handler): sbox = QSpinBox() slider = QSlider() sbox.setMinimum(minimum) sbox.setMaximum(maximum) sbox.setValue(default_value) slider.setMinimum(minimum) slider.setMaximum(maximum) slider.setValue(default_value) slider.setOrientation(Qt.Horizontal) slider.valueChanged.connect(lambda value: sbox.setValue(value)) sbox.valueChanged.connect(valueChanged_handler) layout.addWidget(QLabel(label + ":"), row, 0) layout.addWidget(slider, row, 1) layout.addWidget(sbox, row, 2) def update_gain(self, value): self.gain = int(0xffff * value / 100) def update_shape(self, index): if index == 0: self.shape = ecodes.FF_SQUARE elif index == 1: self.shape = ecodes.FF_TRIANGLE else: self.shape = ecodes.FF_SINE def update_period(self, value): self.period_ms = value def update_magnitude(self, value): if value > 0: self.magnitude = int(0x7fff * value / 100) else: self.magnitude = int(0xffff * value / 100) def update_offset(self, value): self.offset = value def update_phase(self, value): self.phase = value def update_duration(self, value): self.duration_ms = value def update_repeat_count(self, value): self.repeat_count = value def update_attack_length(self, value): self.envelope_attack_length = value def update_attack_level(self, value): self.envelope_attack_level = value def update_fade_length(self, value): self.envelope_fade_length = value def update_fade_level(self, value): self.envelope_fade_level = value def play_clicked(self): path = self.device_selector.currentData(DEVICE_PATH_ROLE) if path is None: return self.device = InputDevice(path) # set the gain print("Setting gain to " + str(self.gain)) self.device.write(ecodes.EV_FF, ecodes.FF_GAIN, self.gain) envelope = ff.Envelope(attack_length=self.envelope_attack_length, attack_level=self.envelope_attack_level, fade_length=self.envelope_fade_length, fade_level=self.envelope_fade_level) periodic_effect = ff.Periodic(waveform=self.shape, period=self.period_ms, magnitude=self.magnitude, offset=self.offset, phase=self.phase, envelope=envelope) effect = ff.Effect(ecodes.FF_PERIODIC, -1, 0, ff.Trigger(0, 0), ff.Replay(self.duration_ms, 0), ff.EffectType(ff_periodic_effect=periodic_effect)) print("playing effect: period: " + str(self.period_ms) + ", magnitude: " + str(self.magnitude) + ", offset: " + str(self.offset) + ", phase: " + str(self.phase) + ", envelope: (" + str(self.envelope_attack_length) + ", " + str(self.envelope_fade_level) + ", " + str(self.envelope_fade_length) + ", " + str(self.envelope_fade_level) + ")") self.id = self.device.upload_effect(effect) self.device.write(ecodes.EV_FF, self.id, self.repeat_count) def stop_clicked(self): self.device = None
class MultiPlayerWindow(QMainWindow): def __init__(self): super().__init__() self.setGeometry(200, 200, 1000, 600) self.setWindowTitle("MultiPlayer") self.initUI() def initUI(self): self.initWindow() self.username() self.chooseShip() self.labels() self.buttonPlay() self.buttonCreateOnline() self.buttonConnect() def initWindow(self): self.BackGround = QPixmap(get_full_image_path("galaxy.jpg")) self.BackGroundLabel = QtWidgets.QLabel(self) self.BackGroundLabel.setPixmap(self.BackGround) self.BackGroundLabel.setGeometry(0, 0, 1000, 600) def username(self): self.lbl2 = QtWidgets.QLabel(self) self.lbl2.setText("Enter name") self.lbl2.setGeometry(200, 150, 200, 50) self.lbl2.setStyleSheet(" color: white;font-size: 26px; font-family: Arial Black;"); self.player1NameLineEdit = QLineEdit(self) self.player1NameLineEdit.setGeometry(200, 200, 200, 50) self.player2NameLineEdit = QLineEdit(self) self.player2NameLineEdit.setGeometry(200, 300, 200, 50) def chooseShip(self): self.lbl2 = QLabel(self) self.lbl2.setText("Choose ship") self.lbl2.setGeometry(410, 150, 200, 50) self.lbl2.setStyleSheet(" color: white;font-size: 26px; font-family: Arial Black;"); self.player1Cb = QComboBox(self) self.player1Cb.setStyleSheet( "border:1px solid rgb(220, 20, 60);font-size: 20px; color: red; font-family: Helvetica;"); self.player1Cb.addItem("") self.player1Cb.addItem("red") self.player1Cb.addItem("green") self.player1Cb.addItem("yellow") self.player1Cb.addItem("blue") self.player1Cb.model().item(0).setEnabled(False) self.player1Cb.setGeometry(410, 200, 200, 50) self.player2Cb = QComboBox(self) self.player2Cb.setStyleSheet( "border:1px solid rgb(220, 20, 60);font-size: 20px; color: red; font-family: Helvetica;"); self.player2Cb.addItem("") self.player2Cb.addItem("red") self.player2Cb.addItem("green") self.player2Cb.addItem("yellow") self.player2Cb.addItem("blue") self.player2Cb.model().item(0).setEnabled(False) self.player2Cb.setGeometry(410, 300, 200, 50) def labels(self): self.lbl3 = QtWidgets.QLabel(self) self.lbl3.setText("First player") self.lbl3.setGeometry(10, 200, 200, 50) self.lbl3.setStyleSheet(" color: red;font-size: 20px; font-family: Arial ;"); self.lbl4 = QtWidgets.QLabel(self) self.lbl4.setText("Second player") self.lbl4.setGeometry(10, 300, 200, 50) self.lbl4.setStyleSheet(" color: red;font-size: 20px; font-family: Arial ;"); def buttonPlay(self): self.playButton = QtWidgets.QPushButton(self) self.playButton.setText("PLAY LOCAL") self.playButton.setGeometry(750, 400, 200, 50) self.playButton.setStyleSheet( "border:2px solid rgb(120, 20, 60); color: blue;font-size: 26px; font-family: Arial Black;"); self.playButton.clicked.connect(self.onPlayButtonClicked) def buttonCreateOnline(self): self.onlineButton = QtWidgets.QPushButton(self) self.onlineButton.setText("CREATE GAME") self.onlineButton.setGeometry(750, 300, 200, 50) self.onlineButton.setStyleSheet( "border:2px solid rgb(120, 20, 60); color: blue;font-size: 22px; font-family: Arial Black;"); self.onlineButton.clicked.connect(self.onCreateButtonClicked) def buttonConnect(self): self.connectButton = QtWidgets.QPushButton(self) self.connectButton.setText("JOIN GAME") self.connectButton.setGeometry(750, 350, 200, 50) self.connectButton.setStyleSheet( "border:2px solid rgb(120, 20, 60); color: blue;font-size: 26px; font-family: Arial Black;"); def onPlayButtonClicked(self): if self.player1NameLineEdit.text() == "" or self.player2NameLineEdit.text() == "" or str( self.player1Cb.currentText()) == "" or str(self.player2Cb.currentText()) == "": msg = QMessageBox() msg.setIcon(QMessageBox.NoIcon) msg.setText("Enter your username and choose ship") msg.setWindowTitle("Error") msg.exec_() elif self.player1NameLineEdit.text() == self.player2NameLineEdit.text(): msg = QMessageBox() msg.setIcon(QMessageBox.NoIcon) msg.setText("Username must be unique") msg.setWindowTitle("Error") msg.exec_() else: player1_input = PlayerInput(player_id=self.player1NameLineEdit.text(), color=self.player1Cb.currentText()) player2_input = PlayerInput(player_id=self.player2NameLineEdit.text(), color=self.player2Cb.currentText()) _start_game_process(player1_input, player2_input, title="Asteroids - Multi Player") self.hide() self.player1NameLineEdit.setText("") self.player2NameLineEdit.setText("") def onCreateButtonClicked(self): if self.player1NameLineEdit.text() == "" or str(self.player1Cb.currentText()) == "": msg = QMessageBox() msg.setIcon(QMessageBox.NoIcon) msg.setText("Enter your username and choose ship") msg.setWindowTitle("Error") msg.exec_() else: player1_input = PlayerInput(player_id=self.player1NameLineEdit.text(), color=self.player1Cb.currentText()) self.server = Server(5) self.game = ClientAsteroidsGame('seed', player_inputs=[player1_input], title="Asteroids - Client") self.game.start()
class InOutTab(OptionsWidget): def __init__(self, parent): super().__init__(parent) def add_contents(self): self.add_categories(0) self.add_configure(2) self.add_radio_level(4) self.add_time_period(5) self.add_radio_log(7,lines=2) # self.add_button_data(8) self.add_start_button(10) self.add_fine_category(11) self.add_detail_button(14) def add_categories(self, h): self.ComboBox = QComboBox() for i,key in enumerate(['Einnahmen', 'Ausgaben']): self.ComboBox.addItem(key) item = self.ComboBox.model().item(i, 0) item.setCheckState(Qt.Unchecked) self.ComboBoxAccount = QComboBox() self.ComboBoxAccount.addItem("Alle") item = self.ComboBoxAccount.model().item(0, 0) for i,key in enumerate(self.parent.DATA.names): self.ComboBoxAccount.addItem(key) item = self.ComboBoxAccount.model().item(i+1, 0) item.setCheckState(Qt.Unchecked) self.layout.addWidget(QLabel("Geldfluss"), h, 0) self.layout.addWidget(self.ComboBox, h, 1, 1, 2) self.layout.addWidget(QLabel("Konto"), h+1, 0) self.layout.addWidget(self.ComboBoxAccount, h+1, 1, 1, 2) # new_frame = QFrame() # self.layout.addWidget(QColumn(QLabel("Geldfluss"),self.ComboBox)) # self.layout.addWidget(QColumn(QLabel("Konto"),self.ComboBoxAccount)) def on_pushButton_config(self): self.cw = ConfigWindow(self, [self.parent.KEYS.IN, self.parent.KEYS.OUT], ["Einnahmen","Ausgaben"], self.parent.KEYS, depth=2) self.cw.show() def update_data(self, target, df, keywords, level, start, end): use_data = analyse.last_entry_of_month_inout(df, keywords, level, start, end) data_tab = DataTabs(target, use_data) def on_pushButton_start(self): self.set_dates() if self.radioLevel1.isChecked(): level = 0 else: level = 1 if (self.ComboBox.currentText() == "Einnahmen"): all_keys = self.parent.KEYS.IN[level] else: all_keys = self.parent.KEYS.OUT[level] if (self.ComboBoxAccount.currentText() == "Alle"): used_data = self.parent.DATA.df_transactions else: print(self.ComboBoxAccount.currentText()) used_data = self.parent.DATA.df_transactions[self.parent.DATA.df_transactions['Account']==self.ComboBoxAccount.currentText()] print("used_data", used_data) s_inout = self.ComboBox.currentText() selected_keys = [key for key in all_keys.keys() if key in self.parent.KEYS.is_included[level]] arguments = [used_data, selected_keys, level, self.date_start, self.date_end] self.new_plot_window = NewPlotWindow( arg1=["StackedBar" if self.radioPlot1.isChecked() else "StackedBarLog", *analyse.prepare_stacked_bar(*arguments), s_inout + " pro Monat"], arg3 = [], arg4=["PieChart", *analyse.prepare_pie_chart(*arguments), "Prozentuale Verteilung der " + s_inout], arg2=["HorizontalBar" if self.radioPlot1b.isChecked() else "HorizontalBarLog", *analyse.prepare_horizontal_bar(*arguments), "Durchschnittliche " + s_inout], title="Plots") self.update_data(self.new_plot_window, *arguments) self.new_plot_window.show() def on_pushButton_details(self): self.set_dates() level = 0 all_keys = self.parent.KEYS.OUT[level] if (self.ComboBoxAccount.currentText() == "Alle"): used_data = self.parent.DATA.df_transactions else: used_data = self.parent.DATA.df_transactions[self.parent.DATA.df_transactions['Account']==self.ComboBoxAccount.currentText()] s_inout = self.ComboBox.currentText() selected_keys = [key for key in all_keys.keys() if key in self.parent.KEYS.OUT[1][self.ComboBoxFine.currentText()]] arguments = [used_data, selected_keys, level, self.date_start, self.date_end] self.new_plot_window = NewPlotWindow( arg1=["StackedBar" if self.radioPlot1.isChecked() else "StackedBarLog", *analyse.prepare_stacked_bar(*arguments), s_inout + " pro Monat"], arg3 = [], arg4=["PieChart", *analyse.prepare_pie_chart(*arguments), "Prozentuale Verteilung der " + s_inout], arg2=["HorizontalBar" if self.radioPlot1b.isChecked() else "HorizontalBarLog", *analyse.prepare_horizontal_bar(*arguments), "Durchschnittliche " + s_inout], title="Plots") self.update_data(self.new_plot_window, *arguments) self.new_plot_window.show()
class GuiConfigEditGeneral(QWidget): def __init__(self, theParent): QWidget.__init__(self, theParent) self.mainConf = nw.CONFIG self.theParent = theParent self.theTheme = theParent.theTheme self.outerBox = QGridLayout() # User Interface self.guiLook = QGroupBox("User Interface", self) self.guiLookForm = QGridLayout(self) self.guiLook.setLayout(self.guiLookForm) self.guiLookTheme = QComboBox() self.guiLookTheme.setMinimumWidth(200) self.theThemes = self.theTheme.listThemes() for themeDir, themeName in self.theThemes: self.guiLookTheme.addItem(themeName, themeDir) themeIdx = self.guiLookTheme.findData(self.mainConf.guiTheme) if themeIdx != -1: self.guiLookTheme.setCurrentIndex(themeIdx) self.guiLookSyntax = QComboBox() self.guiLookSyntax.setMinimumWidth(200) self.theSyntaxes = self.theTheme.listSyntax() for syntaxFile, syntaxName in self.theSyntaxes: self.guiLookSyntax.addItem(syntaxName, syntaxFile) syntaxIdx = self.guiLookSyntax.findData(self.mainConf.guiSyntax) if syntaxIdx != -1: self.guiLookSyntax.setCurrentIndex(syntaxIdx) self.guiDarkIcons = QCheckBox("Prefer icons for dark backgrounds", self) self.guiDarkIcons.setToolTip("This may improve the look of icons if the system theme is dark.") self.guiDarkIcons.setChecked(self.mainConf.guiDark) self.guiLookForm.addWidget(QLabel("Theme"), 0, 0) self.guiLookForm.addWidget(self.guiLookTheme, 0, 1) self.guiLookForm.addWidget(QLabel("Syntax"), 1, 0) self.guiLookForm.addWidget(self.guiLookSyntax, 1, 1) self.guiLookForm.addWidget(self.guiDarkIcons, 2, 0, 1, 2) self.guiLookForm.setColumnStretch(3, 1) # Spell Checking self.spellLang = QGroupBox("Spell Checker", self) self.spellLangForm = QGridLayout(self) self.spellLang.setLayout(self.spellLangForm) self.spellLangList = QComboBox(self) self.spellToolList = QComboBox(self) self.spellToolList.addItem("Internal (difflib)", NWSpellCheck.SP_INTERNAL) self.spellToolList.addItem("Spell Enchant (pyenchant)", NWSpellCheck.SP_ENCHANT) self.spellToolList.addItem("SymSpell (symspellpy)", NWSpellCheck.SP_SYMSPELL) theModel = self.spellToolList.model() idEnchant = self.spellToolList.findData(NWSpellCheck.SP_ENCHANT) idSymSpell = self.spellToolList.findData(NWSpellCheck.SP_SYMSPELL) theModel.item(idEnchant).setEnabled(self.mainConf.hasEnchant) theModel.item(idSymSpell).setEnabled(self.mainConf.hasSymSpell) self.spellToolList.currentIndexChanged.connect(self._doUpdateSpellTool) toolIdx = self.spellToolList.findData(self.mainConf.spellTool) if toolIdx != -1: self.spellToolList.setCurrentIndex(toolIdx) self._doUpdateSpellTool(0) self.spellBigDoc = QSpinBox(self) self.spellBigDoc.setMinimum(10) self.spellBigDoc.setMaximum(10000) self.spellBigDoc.setSingleStep(10) self.spellBigDoc.setToolTip(( "Disable spell checking when loading large documents. " "Spell checking will only run on paragraphs you edit." )) self.spellBigDoc.setValue(self.mainConf.bigDocLimit) self.spellLangForm.addWidget(QLabel("Provider"), 0, 0) self.spellLangForm.addWidget(self.spellToolList, 0, 1, 1, 3) self.spellLangForm.addWidget(QLabel("Language"), 1, 0) self.spellLangForm.addWidget(self.spellLangList, 1, 1, 1, 3) self.spellLangForm.addWidget(QLabel("Size limit"), 2, 0) self.spellLangForm.addWidget(self.spellBigDoc, 2, 1) self.spellLangForm.addWidget(QLabel("kb"), 2, 2) self.spellLangForm.setColumnStretch(4, 1) # AutoSave self.autoSave = QGroupBox("Automatic Save", self) self.autoSaveForm = QGridLayout(self) self.autoSave.setLayout(self.autoSaveForm) self.autoSaveDoc = QSpinBox(self) self.autoSaveDoc.setMinimum(5) self.autoSaveDoc.setMaximum(600) self.autoSaveDoc.setSingleStep(1) self.autoSaveDoc.setValue(self.mainConf.autoSaveDoc) self.autoSaveProj = QSpinBox(self) self.autoSaveProj.setMinimum(5) self.autoSaveProj.setMaximum(600) self.autoSaveProj.setSingleStep(1) self.autoSaveProj.setValue(self.mainConf.autoSaveProj) self.autoSaveForm.addWidget(QLabel("Document"), 0, 0) self.autoSaveForm.addWidget(self.autoSaveDoc, 0, 1) self.autoSaveForm.addWidget(QLabel("seconds"), 0, 2) self.autoSaveForm.addWidget(QLabel("Project"), 1, 0) self.autoSaveForm.addWidget(self.autoSaveProj, 1, 1) self.autoSaveForm.addWidget(QLabel("seconds"), 1, 2) self.autoSaveForm.setColumnStretch(3, 1) # Backup self.projBackup = QGroupBox("Backup Folder", self) self.projBackupForm = QGridLayout(self) self.projBackup.setLayout(self.projBackupForm) self.projBackupPath = QLineEdit() if path.isdir(self.mainConf.backupPath): self.projBackupPath.setText(self.mainConf.backupPath) self.projBackupGetPath = QPushButton(self.theTheme.getIcon("folder"),"") self.projBackupGetPath.clicked.connect(self._backupFolder) self.projBackupClose = QCheckBox("Run on close",self) self.projBackupClose.setToolTip("Backup automatically on project close.") self.projBackupClose.setChecked(self.mainConf.backupOnClose) self.projBackupAsk = QCheckBox("Ask before backup",self) self.projBackupAsk.setToolTip("Ask before backup.") self.projBackupAsk.setChecked(self.mainConf.askBeforeBackup) self.projBackupForm.addWidget(self.projBackupPath, 0, 0, 1, 2) self.projBackupForm.addWidget(self.projBackupGetPath, 0, 2) self.projBackupForm.addWidget(self.projBackupClose, 1, 0) self.projBackupForm.addWidget(self.projBackupAsk, 1, 1, 1, 2) self.projBackupForm.setColumnStretch(1, 1) # Assemble self.outerBox.addWidget(self.guiLook, 0, 0) self.outerBox.addWidget(self.spellLang, 1, 0) self.outerBox.addWidget(self.autoSave, 2, 0) self.outerBox.addWidget(self.projBackup, 3, 0, 1, 2) self.outerBox.setColumnStretch(1, 1) self.outerBox.setRowStretch(4, 1) self.setLayout(self.outerBox) return def saveValues(self): validEntries = True needsRestart = False guiTheme = self.guiLookTheme.currentData() guiSyntax = self.guiLookSyntax.currentData() guiDark = self.guiDarkIcons.isChecked() spellTool = self.spellToolList.currentData() spellLanguage = self.spellLangList.currentData() bigDocLimit = self.spellBigDoc.value() autoSaveDoc = self.autoSaveDoc.value() autoSaveProj = self.autoSaveProj.value() backupPath = self.projBackupPath.text() backupOnClose = self.projBackupClose.isChecked() askBeforeBackup = self.projBackupAsk.isChecked() # Check if restart is needed needsRestart |= self.mainConf.guiTheme != guiTheme self.mainConf.guiTheme = guiTheme self.mainConf.guiSyntax = guiSyntax self.mainConf.guiDark = guiDark self.mainConf.spellTool = spellTool self.mainConf.spellLanguage = spellLanguage self.mainConf.bigDocLimit = bigDocLimit self.mainConf.autoSaveDoc = autoSaveDoc self.mainConf.autoSaveProj = autoSaveProj self.mainConf.backupPath = backupPath self.mainConf.backupOnClose = backupOnClose self.mainConf.askBeforeBackup = askBeforeBackup self.mainConf.confChanged = True return validEntries, needsRestart ## # Internal Functions ## def _backupFolder(self): currDir = self.projBackupPath.text() if not path.isdir(currDir): currDir = "" dlgOpt = QFileDialog.Options() dlgOpt |= QFileDialog.ShowDirsOnly dlgOpt |= QFileDialog.DontUseNativeDialog newDir = QFileDialog.getExistingDirectory( self,"Backup Directory",currDir,options=dlgOpt ) if newDir: self.projBackupPath.setText(newDir) return True return False def _disableComboItem(self, theList, theValue): theIdx = theList.findData(theValue) theModel = theList.model() anItem = theModel.item(1) anItem.setFlags(anItem.flags() ^ Qt.ItemIsEnabled) return theModel def _doUpdateSpellTool(self, currIdx): spellTool = self.spellToolList.currentData() self._updateLanguageList(spellTool) return def _updateLanguageList(self, spellTool): """Updates the list of available spell checking dictionaries available for the selected spell check tool. It will try to preserve the language choice, if the language exists in the updated list. """ if spellTool == NWSpellCheck.SP_ENCHANT: theDict = NWSpellEnchant() else: theDict = NWSpellSimple() self.spellLangList.clear() for spTag, spName in theDict.listDictionaries(): self.spellLangList.addItem(spName, spTag) spellIdx = self.spellLangList.findData(self.mainConf.spellLanguage) if spellIdx != -1: self.spellLangList.setCurrentIndex(spellIdx) return