class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.title = 'To The Beat' self.can_start = {'vid_chooser_list': False, 'music_file_textbox': False, 'output_file_textbox': False, 'isRendering': False} self.vids = [] self.was_canceled = False self.initUI() def initUI(self): self.setWindowTitle(self.title) self.central_widget = QWidget() self.layout = QVBoxLayout() self.tabs = QTabWidget() self.inputTab = QWidget() self.inputLayout = QVBoxLayout() self.inputTab.setLayout(self.inputLayout) self.optionsTab = QWidget() self.optionsGrid = QGridLayout() self.optionsLayout = QVBoxLayout() self.optionsTab.setLayout(self.optionsLayout) self.tabs.addTab(self.inputTab, 'Input') self.tabs.addTab(self.optionsTab, 'Options') # Video chooser self.vid_chooser_list = QListWidget() self.vid_chooser_list.setSelectionMode(QAbstractItemView.ExtendedSelection) self.vid_chooser_list.setIconSize(QSize(320/3, 240/3)) self.vid_chooser_list.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) self.vid_chooser_model = self.vid_chooser_list.model() self.vid_chooser_model.rowsInserted.connect(self.changeVidChooserBtnState) self.vid_chooser_model.rowsRemoved.connect(self.changeVidChooserBtnState) self.vid_add_btn = QPushButton('Add') self.vid_add_btn.clicked.connect(self.addVideos) self.vid_rm_btn = QPushButton('Remove') self.vid_rm_btn.clicked.connect(self.removeVideos) self.vid_up_btn = QPushButton('Up') self.vid_up_btn.clicked.connect(self.moveVideosUp) self.vid_down_btn = QPushButton('Down') self.vid_down_btn.clicked.connect(self.moveVideosDown) self.vid_chooser_btn_layout = QVBoxLayout() self.vid_chooser_btn_layout.setContentsMargins(0, 0, 0, 0) self.vid_chooser_btn_layout.setSpacing(0) self.vid_chooser_btn_layout.addWidget(self.vid_add_btn) self.vid_chooser_btn_layout.addWidget(self.vid_rm_btn) self.vid_chooser_btn_layout.addWidget(self.vid_up_btn) self.vid_chooser_btn_layout.addWidget(self.vid_down_btn) self.vid_chooser_btn_layout.addStretch(0) self.vid_chooser_layout = QHBoxLayout() self.vid_chooser_layout.addWidget(self.vid_chooser_list) self.vid_chooser_layout.addLayout(self.vid_chooser_btn_layout) self.vid_chooser_group_box = QGroupBox('Video files') self.vid_chooser_group_box.setLayout(self.vid_chooser_layout) # Music chooser self.music_file_textbox = QLineEdit() self.music_file_textbox.textChanged.connect(self.musicFileTextboxChanged) self.music_file_browse_btn = QPushButton('Browse') self.music_file_browse_btn.clicked.connect(self.browseMusicFile) self.music_chooser_layout = QHBoxLayout() self.music_chooser_layout.addWidget(self.music_file_textbox) self.music_chooser_layout.addWidget(self.music_file_browse_btn) self.music_chooser_group_box = QGroupBox('Music') self.music_chooser_group_box.setLayout(self.music_chooser_layout) # Output vid chooser self.output_file_textbox = QLineEdit() self.output_file_textbox.textChanged.connect(self.outputFileTextboxChanged) self.output_file_browse_btn = QPushButton('Browse') self.output_file_browse_btn.clicked.connect(self.browseOutputFile) self.output_chooser_layout = QHBoxLayout() self.output_chooser_layout.addWidget(self.output_file_textbox) self.output_chooser_layout.addWidget(self.output_file_browse_btn) self.output_chooser_group_box = QGroupBox('Output') self.output_chooser_group_box.setLayout(self.output_chooser_layout) # OPTIONS split_beat_tooltip = 'Change this option to change when in the music the video cuts to another clip. Multiples of 3 and 4 work best for most music.' self.split_beat_spinbox = QSpinBox() self.split_beat_spinbox.setMinimum(1) self.split_beat_spinbox.setValue(4) self.split_beat_spinbox.setPrefix('Cut every ') self.split_beat_spinbox.setSuffix(' beats') self.split_beat_spinbox.setToolTip(split_beat_tooltip) sep_tooltip = 'Clips from the same video must be at least this many seconds apart.' self.sep_spinbox = QSpinBox() self.sep_spinbox.setMinimum(1) self.sep_spinbox.setValue(5) self.sep_spinbox.setSuffix(' seconds') self.sep_spinbox.setToolTip(sep_tooltip) # TODO: Add a button in this combobox that says 'Custom resolution', and it pops up with a dialog box allowing you to input custom resolution resolution_tooltip = 'Sets the output resolution of the video. Select "Custom resolution" to set your own. Higher resolutions will take longer to render.' self.resolution_combobox = QComboBox() self.resolution_combobox.addItems([ '1280 x 720 (720p)', '1920 x 1080 (1080p)', '3840 x 2160 (4K)', 'Custom resolution' ]) self.resolution_combobox.insertSeparator(3) self.resolution_combobox.setToolTip(resolution_tooltip) fps_tooltip = 'Sets the output frames per second of the video. The default value of 30fps should work well for most videos.' self.fps_spinbox = QSpinBox() self.fps_spinbox.setMinimum(1) self.fps_spinbox.setValue(30) self.fps_spinbox.setSuffix(' fps') self.fps_spinbox.setToolTip(fps_tooltip) preset_tooltip = 'Sets the FFmpeg render preset. Faster presets will result in faster render times but bigger file sizes.' self.preset_combobox = QComboBox() self.preset_combobox.addItems([ 'ultrafast', 'superfast', 'veryfast', 'faster', 'fast', 'medium', 'slow', 'slower', 'veryslow' ]) self.preset_combobox.setCurrentIndex(0) #ultrafast self.preset_combobox.setToolTip(preset_tooltip) self.options = [ [QLabel('Beat to cut at'), self.split_beat_spinbox], [QLabel('Minimum separation time'), self.sep_spinbox], [QLabel('Frames per second'), self.fps_spinbox], [QLabel('Resolution'), self.resolution_combobox], [QLabel('FFmpeg render preset'), self.preset_combobox] ] for r, row in enumerate(self.options): for c, widget in enumerate(row): self.optionsGrid.addWidget(widget, r, c) self.optionsLayout.addWidget(QLabel('Hover over an option to learn more about it')) self.optionsLayout.addLayout(self.optionsGrid) self.optionsLayout.addStretch() # Start button (create video?) # Maybe make button bigger vertically so it's more obvious? self.start_btn = QPushButton('Start') self.start_btn.clicked.connect(self.start) self.changeVidChooserBtnState() self.stop_btn = QPushButton('Cancel') self.stop_btn.clicked.connect(self.stop) self.stop_btn.hide() self.progress_bar = QProgressBar() self.progress_bar.setMaximum(100) self.progress_bar.setValue(0) self.progress_bar.hide() # Add everything to the main layout self.inputLayout.addWidget(self.vid_chooser_group_box) self.inputLayout.addWidget(self.music_chooser_group_box) self.layout.addWidget(self.tabs) self.layout.addWidget(self.output_chooser_group_box) self.layout.addWidget(self.start_btn) self.layout.addWidget(self.stop_btn) self.layout.addWidget(self.progress_bar) self.central_widget.setLayout(self.layout) self.setCentralWidget(self.central_widget) self.show() def checkCanStart(self): if self.can_start['vid_chooser_list'] and self.can_start['music_file_textbox'] and self.can_start['output_file_textbox'] and not self.can_start['isRendering']: self.start_btn.setEnabled(True) else: self.start_btn.setEnabled(False) def changeVidChooserBtnState(self): if len(self.vid_chooser_list) > 0: self.vid_rm_btn.setEnabled(True) self.vid_up_btn.setEnabled(True) self.vid_down_btn.setEnabled(True) self.can_start['vid_chooser_list'] = True else: self.vid_rm_btn.setEnabled(False) self.vid_up_btn.setEnabled(False) self.vid_down_btn.setEnabled(False) self.can_start['vid_chooser_list'] = False self.checkCanStart() def musicFileTextboxChanged(self): if len(self.music_file_textbox.text()) > 0: self.can_start['music_file_textbox'] = True else: self.can_start['music_file_textbox'] = False self.checkCanStart() def outputFileTextboxChanged(self): if len(self.output_file_textbox.text()) > 0: self.can_start['output_file_textbox'] = True else: self.can_start['output_file_textbox'] = False self.checkCanStart() def addVideos(self): file_names = QFileDialog.getOpenFileNames(self, 'Select video files', '', ( 'Video and Image files (*.mp4 *.avi *.mov *.flv *.wmv *.png *.jpg *.bpm *.tiff *.gif *.webp)' ))[0] QApplication.setOverrideCursor(Qt.WaitCursor) with tempfile.TemporaryDirectory() as dir: for i, name in enumerate(file_names): thumbnail_name = f'{dir}/{str(uuid.uuid4())}.jpg' tothebeat.createThumbnail(name, thumbnail_name) short_name = name.split('/')[-1] self.vid_chooser_list.addItem(QListWidgetItem(QIcon(thumbnail_name), short_name)) self.vids.append(name) QApplication.restoreOverrideCursor() def removeVideos(self): for selected_widget in self.vid_chooser_list.selectedItems(): index = self.vid_chooser_list.row(selected_widget) self.vid_chooser_list.takeItem(index) self.vids.pop(index) def moveVideosUp(self): selected_rows = [self.vid_chooser_list.row(selected_widget) for selected_widget in self.vid_chooser_list.selectedItems()] selected_rows.sort() if 0 not in selected_rows: for row in selected_rows: widget = self.vid_chooser_list.takeItem(row) self.vid_chooser_list.insertItem(row-1, widget) widget.setSelected(True) self.vids.insert(row-1, self.vids.pop(row)) def moveVideosDown(self): selected_rows = [self.vid_chooser_list.row(selected_widget) for selected_widget in self.vid_chooser_list.selectedItems()] selected_rows.sort(reverse=True) if len(self.vid_chooser_list)-1 not in selected_rows: for row in selected_rows: widget = self.vid_chooser_list.takeItem(row) self.vid_chooser_list.insertItem(row+1, widget) widget.setSelected(True) self.vids.insert(row+1, self.vids.pop(row)) def browseMusicFile(self): file_name = QFileDialog.getOpenFileName(self, 'Select a music file', '', 'Audio files (*.3gp *.aa *.aac *.aax *.act *.aiff *.amr *.ape *.au *.awb *.dct *.dss *.dvf *.flac *.gsm *.iklax *.ivs *.m4a *.m4b *.m4p *.mmf *.mp3 *.mpc *.msv *.nmf *.nsf *.ogg *.oga *.mogg *.opus *.ra *.rm *.raw *.sln *.tt *.vox *.wav *.webm *.wma *.wv)')[0] self.music_file_textbox.setText(file_name) def browseOutputFile(self): file_name = QFileDialog.getSaveFileName(self, 'Save output video as...', '', 'Video files (*.mp4 *.avi *.mov *.flv *.wmv)')[0] self.output_file_textbox.setText(file_name) def start(self): self.output_file_name = self.output_file_textbox.text() resolution = self.resolution_combobox.currentText().split('(')[0].strip().split('x') resolution_w = int(resolution[0].strip()) resolution_h = int(resolution[1].strip()) sep = self.sep_spinbox.value() fps = self.fps_spinbox.value() split_every_n_beat = self.split_beat_spinbox.value() preset = self.preset_combobox.currentText() self.progress_bar.show() self.progress_bar.setValue(0) self.render_thread = RenderVideoThread( self.music_file_textbox.text(), self.output_file_name, resolution_w, resolution_h, sep=sep, fps=fps, split_every_n_beat=split_every_n_beat, preset=preset, vids=self.vids ) self.render_thread.setProgress.connect(self.setProgress) self.render_thread.showErrorMessage.connect(self.showErrorMessage) self.render_thread.canceled.connect(self.canceled) self.render_thread.finished.connect(self.done) self.render_thread.start() #self.stop_btn.clicked.connect(self.render_thread.terminate) self.stop_btn.show() self.can_start['isRendering'] = True self.checkCanStart() def stop(self): ans = QMessageBox.warning(None, 'Cancel render', 'Are you sure you want to cancel the rendering of this video?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if ans == QMessageBox.Yes: self.render_thread.stop(canceled=True) self.render_thread.wait() def setProgress(self, progress): self.progress_bar.setValue(progress) def showErrorMessage(self, error_log_path): QMessageBox.critical(self, 'Something went wrong!', f'The video could not be rendered for some reason. A log of the error can be found at: {error_log_path}') self.render_thread.stop() self.render_thread.wait() def canceled(self): self.was_canceled = True QMessageBox.information(self, 'Canceled', 'The rendering of the video has been successfully canceled.') def done(self): if os.path.isfile(self.output_file_name) and not self.was_canceled: self.progress_bar.setValue(100) QMessageBox.information(self, 'Render complete!', f'Video has been successfully rendered to {self.output_file_name}!') self.was_canceled = False self.progress_bar.hide() self.progress_bar.setValue(0) self.stop_btn.hide() self.can_start['isRendering'] = False self.checkCanStart()
class FileChooser(QWidget): fileOpened = pyqtSignal(str) def __init__(self, parent=None): super().__init__(parent) self.folderBox = QComboBox(self) self.explorerTree = FileTreeView(self) self.explorerTree.doubleClickCallback = self._fileOpened self.explorerModel = QFileSystemModel(self) self.explorerModel.setFilter( QDir.AllDirs | QDir.Files | QDir.NoDotAndDotDot) self.explorerModel.setNameFilters(["*.py"]) self.explorerModel.setNameFilterDisables(False) self.explorerTree.setModel(self.explorerModel) for index in range(1, self.explorerModel.columnCount()): self.explorerTree.hideColumn(index) self.setCurrentFolder() self.folderBox.currentIndexChanged[int].connect( self.updateCurrentFolder) layout = QVBoxLayout(self) layout.addWidget(self.folderBox) layout.addWidget(self.explorerTree) layout.setContentsMargins(5, 5, 0, 0) def _fileOpened(self, modelIndex): path = self.explorerModel.filePath(modelIndex) if os.path.isfile(path): self.fileOpened.emit(path) def currentFolder(self): return self.explorerModel.rootPath() def setCurrentFolder(self, path=None): if path is None: app = QApplication.instance() path = app.getScriptsDirectory() else: assert os.path.isdir(path) self.explorerModel.setRootPath(path) self.explorerTree.setRootIndex(self.explorerModel.index(path)) self.folderBox.blockSignals(True) self.folderBox.clear() style = self.style() dirIcon = style.standardIcon(style.SP_DirIcon) self.folderBox.addItem(dirIcon, os.path.basename(path)) self.folderBox.insertSeparator(1) self.folderBox.addItem(self.tr("Browse…")) self.folderBox.setCurrentIndex(0) self.folderBox.blockSignals(False) def updateCurrentFolder(self, index): if index < self.folderBox.count() - 1: return path = QFileDialog.getExistingDirectory( self, self.tr("Choose Directory"), self.currentFolder(), QFileDialog.ShowDirsOnly) if path: QSettings().setValue("scripting/path", path) self.setCurrentFolder(path)
def createEditor(self, parent, option, index): # residNum,residNum_color, residName, atomName, atomNum, X,Y,Z if index.column() == residNum: spinbox = QSpinBox(parent) spinbox.setRange(1, 200000) spinbox.setSingleStep(1) spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter) return spinbox elif index.column() == residName: combobox = QComboBox(parent) combobox.addItems(comboBoxList) combobox.insertSeparator(23) combobox.setEditable(True) return combobox elif index.column() == atomName: editor = QLineEdit(parent) editor.returnPressed.connect(self.commitAndCloseEditor) return editor elif index.column() == atomNum: spinbox = QSpinBox(parent) spinbox.setRange(1, 200000) spinbox.setSingleStep(1) spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter) return spinbox elif index.column() in (X, Y, Z): ###this works dspinbox = QDoubleSpinBox(parent) dspinbox.setRange(-200000, 200000) dspinbox.setSingleStep(0.1) dspinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter) return dspinbox else: return QStyledItemDelegate.createEditor(self, parent, option, index)
def createEditor(self, parent, *args): editor = QComboBox(parent) editor.addItems(self.type_names) editor.insertSeparator(len(self.type_names)) if self.custom_types: editor.addItems(self.custom_types) editor.insertSeparator( len(self.type_names) + len(self.custom_types) + 1) editor.addItem(self.tr("custom")) return editor
def g_type_combobox(self, type_str, root=False): cb = QComboBox() items = [list, dict] if not root: items.append(self.lang.node_none) for item in [str, int, bool, None.__class__]: items.append(item) items = [type_map.get(item, item) for item in items] for index, item in enumerate(items): if item == self.lang.node_none: cb.insertSeparator(index) else: cb.insertItem(index, item) cb.setCurrentText(type_str) return cb
class Choices(QWidget): def __init__(self, encoder, optname, attrname, choices, *args, **kwargs): super().__init__(*args, **kwargs) self.encoder = encoder self.optname = optname self.attrname = attrname layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.label = QLabel(optname, self) layout.addWidget(self.label) layout.addStretch() self.selection = QComboBox(self) layout.addWidget(self.selection) self.selection.addItem("Not set", None) self.selection.insertSeparator(1) currentvalue = getattr(encoder, attrname) for choice in choices: if isinstance(choice, (list, tuple)): name, value, *_ = choice elif isinstance(choice, str): name = value = choice elif isinstance(choice, int): value = choice name = f"{choice}" self.selection.addItem(name, value) if currentvalue == value: self.selection.setCurrentIndex(self.selection.count() - 1) self.selection.currentIndexChanged.connect(self.indexChanged) def indexChanged(self, value): data = self.selection.currentData() setattr(self.encoder, self.attrname, data)
def init_widget(self): """ 현재 위젯의 모양등을 초기화 """ self.setWindowTitle("QComboBox Widget") form_lbx = QBoxLayout(QBoxLayout.TopToBottom, parent=self) self.setLayout(form_lbx) lb = QLabel() qb = QComboBox() qb.addItem("Banana") # 단일 아이템 추가시 qb.addItems(["Apple", "Tomato", "Carrot"]) # 다수 아이템 추가시 qb.insertSeparator(2) # 구분 선 qb.currentTextChanged.connect(lb.setText) # 현재 인덱스의 데이터가 바뀔 때 form_lbx.addWidget(qb) form_lbx.addWidget(lb)
def createEditor(self, parent, option, index): if index.column() == ATOM: combobox = QComboBox(parent) combobox.addItems(['ATOM', 'HETATM']) combobox.setEditable(True) return combobox elif index.column() == serial: spinbox = QSpinBox(parent) spinbox.setRange(1, 200000) spinbox.setSingleStep(1) spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter) return spinbox elif index.column() == name: editor = QLineEdit(parent) editor.returnPressed.connect(self.commitAndCloseEditor) return editor elif index.column() == resName: combobox = QComboBox(parent) combobox.addItems(comboBoxList) combobox.insertSeparator(23) combobox.setEditable(True) return combobox # editor = QLineEdit(parent) # editor.returnPressed.connect(self.commitAndCloseEditor) # return editor elif index.column() == ChainID: editor = QLineEdit(parent) editor.returnPressed.connect(self.commitAndCloseEditor) return editor elif index.column() == resNum: spinbox = QSpinBox(parent) spinbox.setRange(1, 200000) spinbox.setSingleStep(1) spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter) return spinbox elif index.column() in (X, Y, Z, occupancy, charge): ###this works dspinbox = QDoubleSpinBox(parent) dspinbox.setRange(-200000, 200000) dspinbox.setSingleStep(0.1) dspinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter) return dspinbox else: return QStyledItemDelegate.createEditor(self, parent, option, index)
def __init__(self): super(MainWindow, self).__init__() self.ports = serial.listports() self.port = None # remove close & maximize window buttons #self.setWindowFlags(Qt.CustomizeWindowHint|Qt.WindowMinimizeButtonHint) self.setMinimumSize(850, 450) self.mdiArea = QMdiArea() self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setCentralWidget(self.mdiArea) self.mdiArea.subWindowActivated.connect(self.updateMenus) self.mdiArea.setViewMode(QMdiArea.TabbedView) self.windowMapper = QSignalMapper(self) self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow) self.child = None self.createActions() self.createMenus() self.createStatusBar() self.updateMenus() self.readSettings() self.setWindowTitle("VISCAM") mytoolbar = QToolBar() ports_menu = QComboBox() ports_menu.addItem('Output Port') ports_menu.insertSeparator(1) for port in self.ports: ports_menu.addItem(port) self.ports_menu = ports_menu ports_menu.currentTextChanged.connect(self.setActivePort) mytoolbar.addWidget(ports_menu) mytoolbar.addSeparator() mytoolbar.setMovable(False) mytoolbar.setFixedHeight(60) self.addToolBar(Qt.TopToolBarArea, mytoolbar)
def createEditor(self, parent, option, index): if index.column() == ATOM: combobox = QComboBox(parent) combobox.addItems(["ATOM", "HETATM"]) combobox.setEditable(True) return combobox elif index.column() == serial: spinbox = QSpinBox(parent) spinbox.setRange(1, 200000) spinbox.setSingleStep(1) spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter) return spinbox elif index.column() == name: editor = QLineEdit(parent) editor.returnPressed.connect(self.commitAndCloseEditor) return editor elif index.column() == resName: combobox = QComboBox(parent) combobox.addItems(comboBoxList) combobox.insertSeparator(23) combobox.setEditable(True) return combobox # editor = QLineEdit(parent) # editor.returnPressed.connect(self.commitAndCloseEditor) # return editor elif index.column() == ChainID: editor = QLineEdit(parent) editor.returnPressed.connect(self.commitAndCloseEditor) return editor elif index.column() == resNum: spinbox = QSpinBox(parent) spinbox.setRange(1, 200000) spinbox.setSingleStep(1) spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter) return spinbox elif index.column() in (X, Y, Z, occupancy, charge): ###this works dspinbox = QDoubleSpinBox(parent) dspinbox.setRange(-200000, 200000) dspinbox.setSingleStep(0.1) dspinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter) return dspinbox else: return QStyledItemDelegate.createEditor(self, parent, option, index)
def recreate_sequence(self): self.layout.removeWidget(self.btn_plus) for w in self.widgets: self.layout.removeWidget(w) w.deleteLater() self.widgets.clear() for item in self.act.sequence: w = QComboBox() w.view().setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) w.setStyleSheet("QComboBox { combobox-popup: 0; }") w.addItem(tr("MacroEditor", "Remove")) w.insertSeparator(1) for k in MACRO_SEQUENCE_KEYCODES: w.addItem(k.label.replace("\n", "")) w.setCurrentIndex(2 + MACRO_SEQUENCE_KEYCODES.index(item)) w.currentIndexChanged.connect(self.on_change) self.layout.addWidget(w) self.widgets.append(w) self.layout.addWidget(self.btn_plus)
def createEditor(self, parent, option, index): obj = index.data(Qt.UserRole) if isinstance(obj, SimpleTag): widget = QComboBox(parent) widget.setEditable(True) for k, (section, items) in enumerate(SECTIONS): if k > 0: widget.insertSeparator(len(widget)) for item in items: widget.addItem(titlecase(item.replace("_", " ")), item) elif isinstance(obj, Tag): widget = QComboBox(parent) for (type, typeValue) in TYPES: widget.addItem(f"{titlecase(type)} ({typeValue})", [ type, typeValue]) return widget
def createEditor(self, parent, option, index): editor = QComboBox(parent) editor.addItem("Unknown (und)", None) editor.insertSeparator(editor.count()) common_langs = ["eng", "deu", "ita", "spa", "fra", "por", "nld", "swe", "nor", "fin", "pol", "ron", "rus", "tur", "vie", "kor", "arz", "pes", "hin", "zho", "jpn"] for key in common_langs: lang = LANGUAGES[key] editor.addItem(f"{lang} ({key})", key) editor.insertSeparator(editor.count()) for key, lang in sorted(LANGUAGES.items(), key=lambda item: item[1]): if key in common_langs: continue editor.addItem(f"{lang} ({key})", key) return editor
def c_combobox(self, text, choices, confkey, restart=False, tip=None): label = QLabel(text) combobox = QComboBox() combobox.restart_required = restart combobox.label_text = text if tip: combobox.setToolTip(tip) for name, key in choices: if name and key: combobox.addItem(name, key) i = 0 for idx, item in enumerate(choices): name, key = item if not name and not key: combobox.insertSeparator(idx + i) i += 1 self.comboboxes[combobox] = confkey layout = make_layout(self, Qt.Horizontal, label, combobox) layout.addStretch(1) widget = QWidget(self) widget.label = label widget.combobox = combobox widget.setLayout(layout) return widget
class CSVOptionsWindow(QWidget): def __init__(self, mainwindow): QWidget.__init__(self, mainwindow, Qt.Window) self._setupUi() self.doc = mainwindow.doc self.model = mainwindow.model.csv_options self.tableModel = CSVOptionsTableModel(self.model, self.tableView) self.model.view = self self.encodingComboBox.addItems(SUPPORTED_ENCODINGS) self.cancelButton.clicked.connect(self.hide) self.continueButton.clicked.connect(self.model.continue_import) self.targetComboBox.currentIndexChanged.connect( self.targetIndexChanged) self.layoutComboBox.currentIndexChanged.connect( self.layoutIndexChanged) self.rescanButton.clicked.connect(self.rescanClicked) def _setupUi(self): self.setWindowTitle(tr("CSV Options")) self.resize(526, 369) self.verticalLayout = QVBoxLayout(self) msg = tr( "Specify which CSV columns correspond to which transaction fields. You must also " "uncheck the \"Import\" column for lines that don\'t represent a transaction " "(header, footer, comments).") self.label = QLabel(msg) self.label.setWordWrap(True) self.verticalLayout.addWidget(self.label) self.gridLayout = QGridLayout() self.label_2 = QLabel(tr("Layout:")) self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1) self.layoutComboBox = QComboBox(self) self.layoutComboBox.setMinimumSize(QtCore.QSize(160, 0)) self.gridLayout.addWidget(self.layoutComboBox, 0, 1, 1, 1) self.label_4 = QLabel(tr("Delimiter:")) self.gridLayout.addWidget(self.label_4, 0, 3, 1, 1) self.fieldSeparatorEdit = QLineEdit(self) self.fieldSeparatorEdit.setMaximumSize(QtCore.QSize(30, 16777215)) self.gridLayout.addWidget(self.fieldSeparatorEdit, 0, 4, 1, 1) self.targetComboBox = QComboBox(self) self.gridLayout.addWidget(self.targetComboBox, 1, 1, 1, 1) self.label_3 = QLabel(tr("Target:")) self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1) self.encodingComboBox = QComboBox(self) self.gridLayout.addWidget(self.encodingComboBox, 1, 4, 1, 1) spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem, 2, 2, 1, 1) self.horizontalLayout_2 = QHBoxLayout() self.horizontalLayout_2.setSpacing(0) spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem1) self.rescanButton = QPushButton(tr("Rescan")) sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.rescanButton.sizePolicy().hasHeightForWidth()) self.rescanButton.setSizePolicy(sizePolicy) self.horizontalLayout_2.addWidget(self.rescanButton) self.gridLayout.addLayout(self.horizontalLayout_2, 2, 3, 1, 2) self.label_5 = QLabel(tr("Encoding:")) self.gridLayout.addWidget(self.label_5, 1, 3, 1, 1) self.verticalLayout.addLayout(self.gridLayout) self.tableView = QTableView(self) self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.setShowGrid(False) self.tableView.horizontalHeader().setHighlightSections(False) self.tableView.verticalHeader().setVisible(False) self.tableView.verticalHeader().setDefaultSectionSize(18) self.verticalLayout.addWidget(self.tableView) self.horizontalLayout = QHBoxLayout() spacerItem2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem2) self.cancelButton = QPushButton(tr("Cancel")) self.cancelButton.setShortcut("Esc") self.horizontalLayout.addWidget(self.cancelButton) self.continueButton = QPushButton(tr("Continue Import")) self.continueButton.setDefault(True) self.horizontalLayout.addWidget(self.continueButton) self.verticalLayout.addLayout(self.horizontalLayout) # --- Private def _newLayout(self): title = tr("New Layout") msg = tr("Choose a name for your new layout:") name, ok = QInputDialog.getText(self, title, msg) if ok and name: self.model.new_layout(name) def _renameLayout(self): title = tr("Rename Layout") msg = tr("Choose a name for your layout:") name, ok = QInputDialog.getText(self, title, msg) if ok and name: self.model.rename_selected_layout(name) # --- Event Handling def layoutIndexChanged(self, index): # This one is a little complicated. We want to only be able to select the layouts. If # anything else is clicked, we revert back to the old index. If the item has user data, # it means that an action has to be performed. if index < 0: return elif index < len(self.model.layout_names): layout_name = None if index == 0 else str( self.layoutComboBox.itemText(index)) self.model.select_layout(layout_name) else: self.layoutComboBox.setCurrentIndex( self.layoutComboBox.findText(self.model.layout.name)) data = str(self.layoutComboBox.itemData(index)) if data == NEW_LAYOUT: self._newLayout() elif data == RENAME_LAYOUT: self._renameLayout() elif data == DELETE_LAYOUT: self.model.delete_selected_layout() def rescanClicked(self): self.model.encoding_index = self.encodingComboBox.currentIndex() self.model.field_separator = str(self.fieldSeparatorEdit.text()) self.model.rescan() def targetIndexChanged(self, index): self.model.selected_target_index = index # --- model --> view # hide() is called from the model, but is already covered by QWidget def refresh_columns(self): self.tableModel.beginResetModel() self.tableModel.endResetModel() def refresh_columns_name(self): self.tableModel.refreshColumnsName() def refresh_layout_menu(self): self.layoutComboBox.currentIndexChanged.disconnect( self.layoutIndexChanged) self.layoutComboBox.clear() self.layoutComboBox.addItems(self.model.layout_names) self.layoutComboBox.insertSeparator(self.layoutComboBox.count()) self.layoutComboBox.addItem(tr("New Layout..."), NEW_LAYOUT) self.layoutComboBox.addItem(tr("Rename Selected Layout..."), RENAME_LAYOUT) self.layoutComboBox.addItem(tr("Delete Selected Layout"), DELETE_LAYOUT) self.layoutComboBox.setCurrentIndex( self.layoutComboBox.findText(self.model.layout.name)) self.layoutComboBox.currentIndexChanged.connect( self.layoutIndexChanged) def refresh_lines(self): self.tableModel.beginResetModel() self.tableModel.endResetModel() self.fieldSeparatorEdit.setText(self.model.field_separator) def refresh_targets(self): self.targetComboBox.currentIndexChanged.disconnect( self.targetIndexChanged) self.targetComboBox.clear() self.targetComboBox.addItems(self.model.target_account_names) self.targetComboBox.currentIndexChanged.connect( self.targetIndexChanged) def show(self): # For non-modal dialogs, show() is not enough to bring the window at the forefront, we have # to call raise() as well QWidget.show(self) self.raise_() def show_message(self, msg): title = "Warning" QMessageBox.warning(self, title, msg)
class TextEditor(QWidget): '''Class creating a TextEditor object.''' def __init__(self, txt_width=500, txt_height=220, txt_text=tr('Text :'), parent=None): '''Create the text.''' #------ini super().__init__(parent) self.fn = tr('-- Select a file --') self.lst_f_hist = [] self.style = GuiStyle().style_sheet #------widgets #---layout main_lay = QGridLayout() main_lay.setRowStretch(0, 1) self.setLayout(main_lay) #---text #-Radio button self.rb_txt = QRadioButton(txt_text) self.rb_txt.setChecked(True) main_lay.addWidget(self.rb_txt, 0, 0) #-font self.fixed_font = QFont('monospace') self.fixed_font.setStyleHint(QFont.TypeWriter) #-text self.txt = QTextEdit() self.txt.setMinimumSize(txt_width, txt_height) self.txt.setAcceptRichText(False) self.txt.setStyleSheet(self.style) self.txt.setObjectName('orange_border_hover') self.txt.setFont(self.fixed_font) main_lay.addWidget(self.txt, 0, 1, 1, 7) #---clear self.bt_clear = QPushButton(tr('Clear')) self.bt_clear.setMaximumSize(len(tr('Clear')) * 13, 50) self.bt_clear.clicked.connect(self.clear) main_lay.addWidget(self.bt_clear, 0, 0, alignment=Qt.AlignTop) #---file #-radio button self.rb_fn = QRadioButton(tr('File') + ' :') main_lay.addWidget(self.rb_fn, 1, 0) #-option menu files self.lst_f = (tr('-- Select a file --'), *list_files()) self.opt_fn = QComboBox() self.opt_fn.addItems(self.lst_f) self.opt_fn.insertSeparator(1) self.opt_fn.activated[str].connect(self.select_fn) main_lay.addWidget(self.opt_fn, 1, 1, 1, 2) #-buttons self.bt_select = QPushButton(tr('Select a file ...')) self.bt_select.setMaximumSize(len(tr('Select a file ...')) * 13, 50) self.bt_select.clicked.connect(self.select_fn) main_lay.addWidget(self.bt_select, 1, 3) self.bt_select_load = QPushButton(tr('Select and load') + ' ▲') self.bt_select_load.setMaximumSize( (len(tr('Select and load')) + 2) * 13, 50) self.bt_select_load.clicked.connect(self.select_load_fn) main_lay.addWidget(self.bt_select_load, 1, 4) self.bt_load = QPushButton(tr('Load') + ' ▲') self.bt_load.setMaximumSize((len(tr('Load')) + 2) * 13, 50) self.bt_load.clicked.connect(self.load_fn) main_lay.addWidget(self.bt_load, 1, 5) self.bt_save = QPushButton(tr('Save') + ' ▼') self.bt_save.setMaximumSize((len(tr('Save')) + 2) * 13, 50) self.bt_save.clicked.connect(self.save_fn) main_lay.addWidget(self.bt_save, 1, 6) self.bt_reload = QPushButton(tr('Reload')) self.bt_reload.setMaximumSize(len(tr('Reload')) * 13, 50) self.bt_reload.clicked.connect(self.reload) main_lay.addWidget(self.bt_reload, 1, 7, alignment=Qt.AlignRight) #-encoding self.rb_encod = QRadioButton(tr('Text encoding :')) main_lay.addWidget(self.rb_encod, 2, 1) self.opt_encod = QComboBox() self.opt_encod.addItems(lst_encod) main_lay.addWidget(self.opt_encod, 2, 2) rb_lay = QHBoxLayout() main_lay.addLayout(rb_lay, 2, 3, 1, 3) #-binary mode self.rb_bin = QRadioButton(tr('Binary mode')) rb_lay.addWidget(self.rb_bin) #-hexa mode self.rb_hexa = QRadioButton(tr('Hexa mode')) rb_lay.addWidget(self.rb_hexa) #-bytes mode self.rb_bytes = QRadioButton(tr('Bytes mode')) rb_lay.addWidget(self.rb_bytes) self.rb_txt.toggled.connect(self.check_bytes) self.rb_fn.toggled.connect(self.check_bytes) self.rb_fn.toggled.connect(self.select_fn_rb) self.rb_bytes.toggled.connect(self.check_bytes) self.rb_bt_grp1 = QButtonGroup() self.rb_bt_grp1.addButton(self.rb_txt) self.rb_bt_grp1.addButton(self.rb_fn) self.rb_bt_grp2 = QButtonGroup() self.rb_bt_grp2.addButton(self.rb_encod) self.rb_bt_grp2.addButton(self.rb_bin) self.rb_bt_grp2.addButton(self.rb_hexa) self.rb_bt_grp2.addButton(self.rb_bytes) #------show self.setMinimumSize(txt_width + 100, txt_height + 110) self.check_bytes() #------check def check_bytes(self): ''' Check the bytes mode checkbutton's status to dislable or not the encoding menu, and check the radiobuttons to dislable or not the bytes checkbuttons. ''' if self.rb_txt.isChecked(): self.opt_encod.setDisabled(False) self.rb_bytes.setDisabled(True) self.rb_bytes.setChecked(False) elif self.rb_fn.isChecked(): self.rb_bytes.setDisabled(False) if self.rb_bytes.isChecked(): self.opt_encod.setDisabled(True) else: self.opt_encod.setDisabled(False) #------clear def clear(self): '''Clear the text widget.''' if self.txt.toPlainText() != '': sure = QMessageBox.question(self, tr('Sure') + ' ?', '<h2>' + tr('Are you sure ?') + '</h2>', \ QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Yes) if sure != QMessageBox.Yes: return None self.txt.clear() #------select_fn_rb def select_fn_rb(self): ''' Activated when pressing the radio button "plain file". If no file is selected, launch select_fn. ''' if self.opt_fn.currentText() == tr('-- Select a file --'): self.select_fn() self.rb_bytes.setChecked(True) self.check_bytes() #---------select file "fn" def select_fn(self, fn=False): ''' Select a file using the PyQt5 file dialog. fn : the filename. It is given when choosing with the combo box. ''' if fn == False: fn = QFileDialog.getOpenFileName(self, tr('Open file'), getcwd())[0] if fn in ((), ''): #cancel fn = tr('-- Select a file --') self.fn = fn self.rb_txt.setChecked(True) self.rb_fn.setChecked(False) return None self.fn = fn f = fn.split('/')[-1] if f not in self.lst_f: if len(self.lst_f_hist) == 0: self.opt_fn.insertSeparator(10000) if fn not in self.lst_f_hist: self.lst_f_hist.append(fn) self.opt_fn.addItem(fn) self.opt_fn.setCurrentText(fn) else: self.opt_fn.setCurrentText(f) #------select and load def select_load_fn(self): '''Uses the functions select and load.''' self.select_fn() self.load_fn() #------load file "fn" def load_fn(self): '''Load the selected file to the text widget.''' #self.fn = self.opt_fn.currentText() if self.fn == tr('-- Select a file --'): QMessageBox.warning(QWidget(), '!!! ' + tr('No file selected') + ' !!!', \ '<h1>' + tr('Please select a file') + ' !</h1>\n' + tr('Or use the button "Select and load"')) return -3 try: if self.rb_encod.isChecked(): with open(self.fn, mode='r', encoding=str(self.opt_encod.currentText())) as f: file_content = f.read() else: with open(self.fn, mode='rb') as f: file_content = f.read() if self.rb_hexa.isChecked() or self.rb_bin.isChecked(): file_content = file_content.hex() if self.rb_bin.isChecked(): d = { '0': '0000', '1': '0001', '2': '0010', '3': '0011', '4': '0100', '5': '0101', '6': '0110', '7': '0111', '8': '1000', '9': '1001', 'a': '1010', 'b': '1011', 'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111' } for k in d: file_content = file_content.replace(k, d[k]) except FileNotFoundError: QMessageBox.critical( QWidget(), '!!! ' + tr('Error') + ' !!!', '<h2>' + tr('The file was NOT found') + ' !!!</h2>') return -1 #stop except UnicodeDecodeError: QMessageBox.critical(QWidget(), '!!! ' + tr('Encoding error') + ' !!!', \ '<h2>' + tr('The file can\'t be decoded with this encoding') + ' !!!</h2>\n' + tr('Try bytes mode')) return -2 #stop txt = self.txt.toPlainText() if txt != '': sure = QMessageBox.question(self, '!!! ' + tr('Erase Text data') + ' !!!', \ '<h2>' + tr('Text is detected in the box ! Remplace by the file\'s data ?') + '</h2>', \ QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if sure != QMessageBox.Yes: return -3 #stop if type(file_content) == str: self.txt.setPlainText(file_content) elif type(file_content) == bytes: try: self.txt.setPlainText(file_content.decode()) except UnicodeDecodeError: QMessageBox.critical( None, '!!! ' + tr('Decoding error') + ' !!!', '<h2>' + tr("The file can't be decoded in bytes mode") + '!</h2>') return -2 #------save in file "fn" def save_fn(self, data=False): ''' Save the content of the text widget in a file. data : the text to write. If False, write text which is in the text widget. Default is False. return -3 if canceled or aborted, -2 if an encoding error occur, None otherwise. ''' if self.fn == tr('-- Select a file --'): filename = QFileDialog.getSaveFileName(self, tr('Save file'), getcwd())[0] if filename in ((), ''): return -3 #Canceled else: filename = self.fn try: if not self.rb_bytes.isChecked(): with open(filename, 'r', encoding=str(self.opt_encod.currentText())) as f: line = f.readline() else: with open(filename, mode='rb') as f: line = f.readline() except FileNotFoundError: #the file can be created, it don't exists pass except UnicodeDecodeError: pass else: if line not in ('', '\n'): sure = QMessageBox.question(self, '!!! ' + tr('Erase file data') + ' !!!', \ '<h2>' + tr('The selected file is NOT empty') + ' !!!</h2>\n<h3>' + tr('Overwrite with text data ?') + '</h3>', \ QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if sure != QMessageBox.Yes: return -3 #Aborted if data == False: txt = self.txt.toPlainText() else: txt = data if txt == '': emp = QMessageBox.question(self, tr('Text is empty'), \ '<h2>' + tr('There is no text in the box') + '.\n' + tr('Write anyway ?') + '</h2>', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if emp != QMessageBox.Yes: return -3 #Aborted if self.rb_encod.isChecked(): with open(filename, 'w', encoding=str(self.opt_encod.currentText())) as f: if type(txt) == str: f.write(txt) else: f.write(txt.decode()) else: try: if not self.rb_bytes.isChecked(): if self.rb_bin.isChecked(): if len(txt) % 8 != 0: QMessageBox.critical(QWidget(), '!!! ' + tr('Value Error') + ' !!!', \ '<h2>' + tr('The number of binary digits is not a multiple of 8') + ' !!!</h2>') return -2 #stop else: d = { '0000': '0', '0001': '1', '0010': '2', '0011': '3', '0100': '4', '0101': '5', '0110': '6', '0111': '7', '1000': '8', '1001': '9', '1010': 'a', '1011': 'b', '1100': 'c', '1101': 'd', '1110': 'e', '1111': 'f' } txt2 = "" for k in range(len(txt) // 4): if txt[k * 4:k * 4 + 4] not in d: QMessageBox.critical(QWidget(), '!!! ' + tr('Value Error') + ' !!!', \ '<h2>' + tr('A binary number is composed only of 0 and 1') + ' !!!</h2>') return -2 #stop else: txt2 += d[txt[k * 4:k * 4 + 4]] txt = txt2 try: if len(txt) % 2 != 0: QMessageBox.critical(QWidget(), '!!! ' + tr('Value Error') + ' !!!', \ "<h2>The number of hexadecimal digits is not a multiple of 2 !!!</h2>") return -2 #stop txt = bytes.fromhex(txt) except ValueError: QMessageBox.critical(QWidget(), '!!! ' + tr('Value Error') + ' !!!', \ '<h2>' + tr('Error in the conversion of hexadecimal to bytes') + ' !!!</h2>') return -2 #stop with open(filename, mode='wb') as f: if type(txt) == str: f.write( txt.encode( encoding=str(self.opt_encod.currentText()))) else: f.write(txt) except UnicodeEncodeError: QMessageBox.critical(QWidget(), '!!! ' + tr('Encoding error') + ' !!!', \ '<h2>' + tr("The file can't be encoded with this encoding") + ' !!!</h2>') return -2 #stop self.reload() QMessageBox.about( QWidget(), tr('Done') + ' !', '<h2>' + tr('Your text has been be wrote') + ' !</h2>') #------read_file def read_file(self, fn, bytes_md=False, encod='utf-8', silent=True): ''' Read the content of a file and return its content in a string. fn : filename ; bytes_md : the bytes mode. Should be False for text (default) or True for binary (bytes) ; encod : the encoding. Should be "utf-8", "latin-1", "ascii". Default is "utf-8" ; silent : should be a bool. If False, show error message box in case if one occur. return -1 if the file "fn" was not found, -2 if an encoding error occur, the text otherwise. ''' if bytes_md not in (True, False): return 'The bytes_md should be "True" or "False", but "' + str( bytes_md) + '" was found !!!' try: if not bytes_md: #text with open(fn, mode='r', encoding=encod) as file: txt = file.read() else: with open(fn, mode='rb') as file: txt = file.read() except FileNotFoundError: if not silent: QMessageBox.critical(QWidget(), '!!! ' + tr('File error') + ' !!!', \ '<h2>' + tr('The file') + ' "' + str(fn) + '"' + tr(' was NOT found') + ' !!!</h2>') return -1 except UnicodeDecodeError: if not silent: QMessageBox.critical(QWidget(), '!!! ' + tr('Encoding error') + ' !!!', \ '<h2>' + tr('The file can\'t be decoded with this encoding') + ' !!!</h2>') return -2 return txt #------reload def reload(self): ''' Function which reload the files combo boxes. It can be used if a new file was copied while running, for example. ''' self.lst_f = (tr('-- Select a file --'), *list_files(), *self.lst_f_hist) self.opt_fn.clear() self.opt_fn.addItems((tr('-- Select a file --'), *list_files())) self.opt_fn.insertSeparator(1) self.opt_fn.insertSeparator(10000) if len(self.lst_f_hist) > 0: self.opt_fn.addItems(self.lst_f_hist) self.opt_fn.insertSeparator(20000) if self.fn not in self.lst_f: self.fn = tr('-- Select a file --') self.opt_fn.setCurrentText(tr('-- Select a file --')) else: self.opt_fn.setCurrentText(self.fn) #------get encoding def get_encod(self): '''Return the currend selected encoding.''' return self.opt_encod.currentText() #------get bytes mode def get_bytes(self): '''Return the bytes, either 't' for text, or 'b' for bytes.''' return ('t', 'b')[self.rb_bytes.isChecked()] #------getText def getText(self, silent=False, from_=None): ''' Return the text selected by the user. silent : should be a bool. If False, show popup pointing out the error, if one occur ; from_ : where read. Can be None, 'text', 'file'. if None, check the radiobutton. Default is None. Return : -1 if the file was not found ; -2 if an encoding error occur ; -3 if aborted ; The text otherwise. ''' if from_ not in (None, 'text', 'file'): raise ValueError( tr('Parameter "from_" should be None, "text" or "file", but') + ' "' + str(from_) + '" ' + tr('was found') + ' !!!') txt_t = self.txt.toPlainText() if self.opt_fn.currentText() != tr('-- Select a file --'): txt_f = self.read_file(self.opt_fn.currentText(), \ self.rb_bytes.isChecked(), self.opt_encod.currentText()) else: txt_f = None if from_ == 'text': return txt_t elif from_ == 'file': return txt_f if self.rb_txt.isChecked(): # Text is in the text widget if txt_t == '' and txt_f not in (None, ''): rep = QMessageBox.question(self, '!!! ' + tr('Text is empty') + ' !!!', \ '<h3>' + tr('The text widget seem to be empty') + '.</h3>\n<h2>' + tr('Read the file ?') + '</h2>', \ QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if rep == QMessageBox.Yes: return txt_f else: return -3 # Abort elif txt_t == '': if not silent: QMessageBox.critical(QWidget(), '!!! ' + tr('Text is empty') + ' !!!', \ '<h2>' + tr('The text widget is empty') + ' !!!</h2>') return -3 #Abort return txt_t else: # Text is in the file if txt_f == -1: if not silent: QMessageBox.critical(QWidget(), '!!! ' + tr('File error') + ' !!!', \ '<h2>' + tr('The file') + ' "' + str(fn) + '" ' + tr('was NOT found') + ' !!!</h2>') return -1 elif txt_f == -2: if not silent: QMessageBox.critical(QWidget(), '!!! ' + tr('Encoding error') + ' !!!', \ '<h2>' + tr("The file can't be decoded with this encoding") + ' !!!</h2>') return -2 if txt_f == None and txt_t != '': rep = QMessageBox.question(self, '!!! ' + tr('No file selected') + ' !!!', \ '<h3>' + tr('You did not select a file') + ' !!!</h3>\n<h2>' + tr('Read the text widget ?') + '</h2>', \ QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if rep == QMessageBox.Yes: return txt_t else: return -3 # Abort elif txt_f == None: if not silent: QMessageBox.critical(QWidget(), '!!! ' + tr('No file selected') + ' !!!', \ '<h2>' + tr('Please select a file') + ' !</h2>') return -3 if txt_f in ('', b'') and txt_t != '': rep = QMessageBox.question(self, '!!! ' + tr('File is empty') + ' !!!', \ '<h3>' + tr('The file seem to be empty') + '.</h3>\n<h2>' + tr('Read the text widget ?') + '</h2>', \ QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if rep == QMessageBox.Yes: return txt_t else: return -3 # Abort elif txt_f in ('', b''): if not silent: QMessageBox.critical( QWidget(), '!!! ' + tr('File is empty') + ' !!!', '<h2>' + tr('The file is empty') + ' !!!</h2>') return -3 return txt_f def setText(self, txt): '''Fill the text widget or the file with txt, according to the radiobuttons.''' txt_t = self.txt.toPlainText() if self.opt_fn.currentText() != tr('-- Select a file --'): txt_f = self.read_file(self.opt_fn.currentText(), \ self.rb_bytes.isChecked(), self.opt_encod.currentText()) else: txt_f = None if self.rb_txt.isChecked(): # The text widget is chosen if txt_t != '' and txt_f == '': rep = QMessageBox.question(self, '!!! ' + tr('Text is not empty') + ' !!!', \ '<h2>' + tr('The text widget is not empty, but the file is') + '.</h2>\n<h3>' + tr('Write the file (Yes) or overwrite text (Ignore) ?') + '</h3>', \ QMessageBox.Yes | QMessageBox.Ignore | QMessageBox.Cancel, QMessageBox.Ignore) if rep == QMessageBox.Yes: self.save_fn(txt) elif rep == QMessageBox.Ignore: self.txt.setPlainText(txt) else: return -3 # Abort else: self.txt.setPlainText(txt) else: # The file is chosen if txt_f == -1: rep = QMessageBox.question(self, '!!! ' + tr('File error') + ' !!!', \ '<h2>' + tr('The file') + ' "' + str(fn) + '" ' + tr('was NOT found') + ' !!!</h2>\n<h3>' + tr('Write in the text widget ?') + '</h3>', \ QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if rep == QMessageBox.Yes: self.txt.setPlainText(txt) else: return -1 else: self.save_fn(txt)
class QualityRateControlTab(QWidget): optionchanged = pyqtSignal() def __init__(self, encoder, *args, **kwargs): super(QualityRateControlTab, self).__init__(*args, **kwargs) self.encoder = encoder layout = QVBoxLayout() layout.setSpacing(4) self.setLayout(layout) self.rateControlSelection = QComboBox(self) self.rateControlSelection.addItem("Not set") self.rateControlSelection.insertSeparator(1) self.rateControlSelection.addItem("Bitrate", 0) self.rateControlSelection.addItem("CRF", 1) self.rateControlSelection.addItem("QP", 2) self.rateControlSelection.addItem("Lossless", 3) self.bitrateSpinBox = QSpinBox(self) self.bitrateSpinBox.setMinimum(200) self.bitrateSpinBox.setValue(8000) self.bitrateSpinBox.setSuffix("kbps") self.bitrateSpinBox.setMaximum(60000) self.bitrateSpinBox.setSingleStep(100) self.bitrateSpinBox.setHidden(True) self.crfSpinBox = QDoubleSpinBox(self) self.crfSpinBox.setMinimum(0) self.crfSpinBox.setValue(28) self.crfSpinBox.setMaximum(51) self.crfSpinBox.setSingleStep(0.1) self.crfSpinBox.setDecimals(2) self.crfSpinBox.setHidden(True) self.qpSpinBox = QSpinBox(self) self.qpSpinBox.setMinimum(0) self.qpSpinBox.setValue(22) self.qpSpinBox.setMaximum(54) self.qpSpinBox.setSingleStep(1) self.qpSpinBox.setHidden(True) self.rcSpacer = QWidget(self) self.rcSpacer.setHidden(True) self.bitrateSpinBox.setFixedWidth(96) self.crfSpinBox.setFixedWidth(96) self.qpSpinBox.setFixedWidth(96) self.rcSpacer.setFixedWidth(96) if encoder.bitrate is not None: idx = self.rateControlSelection.findData(0) self.rateControlSelection.setCurrentIndex(idx) self.bitrateSpinBox.setValue(encoder.bitrate) self.bitrateSpinBox.setVisible(True) elif encoder.crf is not None: idx = self.rateControlSelection.findData(1) self.rateControlSelection.setCurrentIndex(idx) self.crfSpinBox.setValue(encoder.crf) self.crfSpinBox.setVisible(True) elif encoder.qp is not None: idx = self.rateControlSelection.findData(2) self.rateControlSelection.setCurrentIndex(idx) self.qpSpinBox.setValue(encoder.qp) self.qpSpinBox.setVisible(True) elif encoder.lossless: idx = self.rateControlSelection.findData(3) self.rateControlSelection.setCurrentIndex(idx) else: self.rateControlSelection.setCurrentIndex(0) self.rcSpacer.setVisible(True) self.rateControlSelection.currentIndexChanged.connect( self.onRateControlModeChange) self.bitrateSpinBox.valueChanged.connect(self.setBitrate) self.crfSpinBox.valueChanged.connect(self.setCRF) self.qpSpinBox.valueChanged.connect(self.setQP) hlayout = QHBoxLayout() hlayout.addWidget(QLabel("Rate Control")) hlayout.addStretch() hlayout.addWidget(self.rateControlSelection) hlayout.addWidget(self.bitrateSpinBox) hlayout.addWidget(self.crfSpinBox) hlayout.addWidget(self.qpSpinBox) hlayout.addWidget(self.rcSpacer) layout.addLayout(hlayout) self.aqmotion = BoolOption(encoder, "AQ Motion", "aq-motion", self) self.aqmotion.stateChanged.connect(self.optionchanged.emit) self.aqmotion.setToolTip(""" <b>--aq-motion, --no-aq-motion</b> <p>Adjust the AQ offsets based on the relative motion of each block with respect to the motion of the frame. The more the relative motion of the block, the more quantization is used.</p> <p>Default disabled. <b>Experimental Feature.</b></p> """) layout.addWidget(self.aqmotion) self.aqmode = Choices( encoder, "AQ Mode", "aq-mode", [("Disabled", 0), ("AQ Enabled", 1), ("AQ enabled with auto-variance", 2), ("AQ enabled with auto-variance and bias to dark scenes", 3), ("AQ enabled with auto-variance and edge information", 4)], self) self.aqmode.selection.currentIndexChanged.connect( self.optionchanged.emit) self.aqmode.setToolTip(""" <b>--aq-mode <0|1|2|3|4></b> <p>Adaptive Quantization operating mode. Raise or lower per-block quantization based on complexity analysis of the source image. The more complex the block, the more quantization is used. These offsets the tendency of the encoder to spend too many bits on complex areas and not enough in flat areas.</p> """) layout.addWidget(self.aqmode) self.aqstrength = FloatOption(encoder, "AQ Strength", "aq-strength", 0, 3, 1, 2, self) self.aqstrength.spinbox.valueChanged.connect(self.optionchanged.emit) self.aqstrength.setToolTip(""" <b>--aq-strength <float></b> <p>Adjust the strength of the adaptive quantization offsets. Setting <span class="pre">--aq-strength</span> to 0 disables AQ. At aq-modes 2 and 3, high aq-strengths will lead to high QP offsets resulting in a large difference in achieved bitrates.</p> <p>Default 1.0. Range of values: 0.0 to 3.0</p> """) layout.addWidget(self.aqstrength) self.qgsize = Choices(encoder, "QG Size", "qg-size", [("8", 8), ("16", 16), ("32", 32), ("64", 64)], self) self.qgsize.selection.currentIndexChanged.connect( self.optionchanged.emit) self.qgsize.setToolTip(""" <b>--qg-size <64|32|16|8></b> <p>Enable adaptive quantization for sub-CTUs. This parameter specifies the minimum CU size at which QP can be adjusted, ie. Quantization Group size. Allowed range of values are 64, 32, 16, 8 provided this falls within the inclusive range [maxCUSize, minCUSize].</p> <p>Default: same as maxCUSize</p> """) layout.addWidget(self.qgsize) """ TODO: --vbv-bufsize --vbv-maxrate --vbv-init --vbv-end --vbv-end-fr-adj --crf-max --crf-min --qpmin --qpmax --lossless --aq-motion --hevc-aq --qp-adaptation-range #--qg-size --cutree --slow-firstpass --multi-pass-opt-analysis --multi-pass-opt-distortion --strict-cbr --cbqpoffs --crqpoffs --ipratio --pbratio --qcomp --qpstep --rc-grain --const-vbv --qblur --cplxblur --scenecut-aware-qp --scenecut-window --max-qp-delta """ layout.addStretch() def onRateControlModeChange(self, index): data = self.rateControlSelection.currentData() if data == 0: self.encoder.bitrate = self.bitrateSpinBox.value() self.encoder.crf = None self.encoder.qp = None self.encoder.lossless = None self.crfSpinBox.setHidden(True) self.qpSpinBox.setHidden(True) self.rcSpacer.setHidden(True) self.bitrateSpinBox.setHidden(False) elif data == 1: self.encoder.bitrate = None self.encoder.crf = self.crfSpinBox.value() self.encoder.qp = None self.encoder.lossless = None self.bitrateSpinBox.setHidden(True) self.qpSpinBox.setHidden(True) self.rcSpacer.setHidden(True) self.crfSpinBox.setHidden(False) elif data == 2: self.encoder.bitrate = None self.encoder.crf = None self.encoder.qp = self.qpSpinBox.value() self.encoder.lossless = None self.bitrateSpinBox.setHidden(True) self.crfSpinBox.setHidden(True) self.rcSpacer.setHidden(True) self.qpSpinBox.setHidden(False) elif data == 3: self.encoder.bitrate = None self.encoder.crf = None self.encoder.qp = None self.encoder.lossless = True self.bitrateSpinBox.setHidden(True) self.crfSpinBox.setHidden(True) self.qpSpinBox.setHidden(True) self.rcSpacer.setHidden(False) else: self.encoder.bitrate = None self.encoder.crf = None self.encoder.qp = None self.encoder.lossless = None self.crfSpinBox.setHidden(True) self.qpSpinBox.setHidden(True) self.bitrateSpinBox.setHidden(True) self.rcSpacer.setHidden(False) self.optionchanged.emit() def setBitrate(self, value): self.encoder.bitrate = value self.optionchanged.emit() def setCRF(self, value): self.encoder.crf = value self.optionchanged.emit() def setQP(self, value): self.encoder.qp = value self.optionchanged.emit()
class ControlButtonsHolder(QWidget): """ +---- Control ButtonsHolder (QWidget) -----------------+ | +---- self_layout (QHBoxLayout) -------------------+ | | | +----+ +----++--------------+ +----+ | | | | |Back| |Play|| List | |Hier| | | | | +----+ +----++--------------+ +----+ | | | +--------------------------------------------------+ | +------------------------------------------------------+ """ def __init__(self, control_panel): super().__init__() self.control_panel = control_panel self_layout = QHBoxLayout(self) self.setLayout(self_layout) self_layout.setContentsMargins(0, 0, 0, 0) self_layout.setSpacing(5) # ------------- # # Back Button # # ------------- self.back_button_method = None back_button = QPushButton() back_button.setFocusPolicy(Qt.NoFocus) back_button.clicked.connect(self.back_button_on_click) back_icon = QIcon() back_icon.addPixmap( QPixmap( resource_filename( __name__, os.path.join( CONTROL_IMG_FOLDER, CONTROL_IMG_BACK_BUTTON + "-" + ON + "." + CONTROL_IMG_EXTENTION))), QIcon.Active) back_icon.addPixmap( QPixmap( resource_filename( __name__, os.path.join( CONTROL_IMG_FOLDER, CONTROL_IMG_BACK_BUTTON + "-" + OFF + "." + CONTROL_IMG_EXTENTION))), QIcon.Disabled) back_button.setIcon(back_icon) back_button.setIconSize(QSize(CONTROL_IMG_SIZE, CONTROL_IMG_SIZE)) back_button.setCursor(QCursor(Qt.PointingHandCursor)) back_button.setStyleSheet("background:transparent; border:none") # Back button on the left self_layout.addWidget(back_button) self_layout.addStretch(1) # ================================================ # ================================================ # ------------------- # # Play Sequentially Button # # ------------------- self.play_continously_button = QPushButton() self.play_continously_button.setFocusPolicy(Qt.NoFocus) self.play_continously_button.clicked.connect( self.play_continously_button_on_click) play_continously_icon = QIcon() play_continously_icon.addPixmap( QPixmap( resource_filename( __name__, os.path.join( CONTROL_IMG_FOLDER, CONTROL_IMG_PLAY_BUTTON + "." + CONTROL_IMG_EXTENTION))), QIcon.Normal, QIcon.On) # play_continously_icon.addPixmap(QPixmap( resource_filename(__name__,os.path.join(CONTROL_IMG_FOLDER, CONTROL_IMG_PLAY_BUTTON + "-" + ON + "." + CONTROL_IMG_EXTENTION)) ), QIcon.Normal, QIcon.On) self.play_continously_button.setIcon(play_continously_icon) self.play_continously_button.setIconSize(QSize(25, 25)) self.play_continously_button.setCursor(QCursor(Qt.PointingHandCursor)) self.play_continously_button.setStyleSheet( "background:transparent; border:none") # Play button on the middle self_layout.addWidget(self.play_continously_button) # ------------------- # # Stop Button # # ------------------- self.stop_continously_button = QPushButton() self.stop_continously_button.setFocusPolicy(Qt.NoFocus) self.stop_continously_button.clicked.connect( self.stop_continously_button_on_click) stop_continously_icon = QIcon() stop_continously_icon.addPixmap( QPixmap( resource_filename( __name__, os.path.join( CONTROL_IMG_FOLDER, CONTROL_IMG_STOP_BUTTON + "." + CONTROL_IMG_EXTENTION))), QIcon.Normal, QIcon.On) # stop_continously_icon.addPixmap(QPixmap( resource_filename(__name__,os.path.join(CONTROL_IMG_FOLDER, CONTROL_IMG_STOP_BUTTON + "-" + OFF + "." + CONTROL_IMG_EXTENTION)) ), QIcon.Normal, QIcon.Off) self.stop_continously_button.setIcon(stop_continously_icon) self.stop_continously_button.setIconSize(QSize(25, 25)) self.stop_continously_button.setCursor(QCursor(Qt.PointingHandCursor)) self.stop_continously_button.setStyleSheet( "background:transparent; border:none") # Stop button on the middle self_layout.addWidget(self.stop_continously_button) # ---------------------------------- # # Playing Continously list drop-down # # ---------------------------------- self.dropdown_play_continously = QComboBox(self) self.dropdown_play_continously.setFocusPolicy(Qt.NoFocus) self.dropdown_play_continously.setEditable(False) # listener for selection changed #self.dropdown_play_continously.currentIndexChanged.connect(self.play_continously_selection_changed_listener) style_box = ''' QComboBox { max-width: 500px; min-width: 300px; border: 1px solid gray; border-radius: 5px; } ''' style_drop_down = ''' QComboBox QAbstractItemView::item { color: red; max-height: 15px; } ''' self.dropdown_play_continously.setStyleSheet(style_box) #self.dropdown_play_continously.addItem("") self_layout.addWidget(self.dropdown_play_continously) self.disablePlayStopContinously() self_layout.addStretch(1) # ================================================ # ================================================ # ---------------- # # Hierarchy Button # # ---------------- self.hierarchy_button_method = None self.hierarchy_button = QPushButton() self.hierarchy_button.setFocusPolicy(Qt.NoFocus) self.hierarchy_button.setCheckable(True) self.hierarchy_button.toggled.connect(self.hierarchy_button_on_toggle) hierarchy_icon = QIcon() hierarchy_icon.addPixmap( QPixmap( resource_filename( __name__, os.path.join( CONTROL_IMG_FOLDER, CONTROL_IMG_HIERARCHY_BUTTON + "-" + ON + "." + CONTROL_IMG_EXTENTION))), QIcon.Normal, QIcon.On) hierarchy_icon.addPixmap( QPixmap( resource_filename( __name__, os.path.join( CONTROL_IMG_FOLDER, CONTROL_IMG_HIERARCHY_BUTTON + "-" + OFF + "." + CONTROL_IMG_EXTENTION))), QIcon.Normal, QIcon.Off) self.hierarchy_button.setIcon(hierarchy_icon) self.hierarchy_button.setIconSize( QSize(CONTROL_IMG_SIZE, CONTROL_IMG_SIZE)) self.hierarchy_button.setCursor(QCursor(Qt.PointingHandCursor)) self.hierarchy_button.setStyleSheet( "background:transparent; border:none") # Hierarchy button on the right self_layout.addWidget(self.hierarchy_button) # # ================================================ # # ================================================ # Initiate the PlayerThread ins = PlayerThread.getInstance() ins.startNextPlaying.connect(self.start_next_playing_emmitted) ins.stopPlayingAll.connect(self.stop_playing_all_emmitted) # ------------------- # # Fast Search Button # # ------------------- # self.fast_search_button = QPushButton() # self.fast_search_button.setFocusPolicy(Qt.NoFocus) # self.fast_search_button.setCheckable(True) # self.fast_search_button.setAutoExclusive(False) # self.fast_search_button.toggled.connect(self.fast_search_button_on_click) # # fast_search_icon = QIcon() # fast_search_icon.addPixmap(QPixmap( resource_filename(__name__,os.path.join("img", IMG_FAST_SEARCH_BUTTON_ON)) ), QIcon.Normal, QIcon.On) # fast_search_icon.addPixmap(QPixmap( resource_filename(__name__,os.path.join("img", IMG_FAST_SEARCH_BUTTON_OFF)) ), QIcon.Normal, QIcon.Off) # self.fast_search_button.setIcon( fast_search_icon ) # self.fast_search_button.setIconSize(QSize(25,25)) # self.fast_search_button.setCursor(QCursor(Qt.PointingHandCursor)) # self.fast_search_button.setStyleSheet("background:transparent; border:none") # self_layout.addWidget( self.fast_search_button ) # # # ------------------- # # # # Advanced Search Button # # # # ------------------- # self.advanced_search_button = QPushButton() # self.advanced_search_button.setFocusPolicy(Qt.NoFocus) # self.advanced_search_button.setCheckable(True) # self.advanced_search_button.setAutoExclusive(False) # self.advanced_search_button.toggled.connect(self.advanced_search_button_on_click) # # advanced_search_icon = QIcon() # advanced_search_icon.addPixmap(QPixmap( resource_filename(__name__,os.path.join("img", IMG_ADVANCED_SEARCH_BUTTON_ON)) ), QIcon.Normal, QIcon.On) # advanced_search_icon.addPixmap(QPixmap( resource_filename(__name__,os.path.join("img", IMG_ADVANCED_SEARCH_BUTTON_OFF)) ), QIcon.Normal, QIcon.Off) # self.advanced_search_button.setIcon( advanced_search_icon ) # self.advanced_search_button.setIconSize(QSize(25,25)) # self.advanced_search_button.setCursor(QCursor(Qt.PointingHandCursor)) # self.advanced_search_button.setStyleSheet("background:transparent; border:none") # self_layout.addWidget( self.advanced_search_button ) # # # ================================================ # # ================================================ # # # ------------------- # # # # Config Button # # # # ------------------- # self.config_button = QPushButton() # self.config_button.setFocusPolicy(Qt.NoFocus) # self.config_button.setCheckable(False) # self.config_button.clicked.connect(self.config_button_on_click) # # config_icon = QIcon() # config_icon.addPixmap(QPixmap( resource_filename(__name__,os.path.join("img", IMG_CONFIG_BUTTON)) ), QIcon.Normal, QIcon.On) # self.config_button.setIcon( config_icon ) # self.config_button.setIconSize(QSize(25,25)) # self.config_button.setCursor(QCursor(Qt.PointingHandCursor)) # self.config_button.setStyleSheet("background:transparent; border:none") # self_layout.addWidget( self.config_button ) # # self.enableSearchIcons(False) # self.disablePlayStopContinously() # # # ====================================================== # def clear_play_continously_elements(self): self.dropdown_play_continously.clear() def add_play_continously_separator(self): self.dropdown_play_continously.insertSeparator( self.dropdown_play_continously.__len__()) def add_play_continously_element(self, title, media_path, media_type): self.dropdown_play_continously.addItem(title, (media_path, media_type)) def get_play_continously_selected_path(self): return self.dropdown_play_continously.itemData( self.dropdown_play_continously.currentIndex()) def get_play_continously_media_path_by_index(self, index): return self.dropdown_play_continously.itemData(index)[0] def get_play_continously_media_type_by_index(self, index): return self.dropdown_play_continously.itemData(index)[1] def get_play_continously_data_list(self): items = [] for index in range(self.dropdown_play_continously.count()): items.append((self.dropdown_play_continously.itemText(index), ) + self.dropdown_play_continously.itemData(index)) return items def get_play_continously_selected_title(self): return self.dropdown_play_continously.itemText( self.dropdown_play_continously.currentIndex()) def get_play_continously_title_by_index(self, index): return self.dropdown_play_continously.itemText(index) def get_play_continously_selected_index(self): return self.dropdown_play_continously.currentIndex() def get_play_continously_last_index(self): return self.dropdown_play_continously.count() - 1 def select_play_continously_element_by_index(self, index): self.dropdown_play_continously.setCurrentIndex(index) # ====================================================== def disablePlayStopContinously(self): self.play_continously_button.setEnabled(False) self.stop_continously_button.setEnabled(False) self.dropdown_play_continously.setEnabled(False) def enablePlayContinously(self, enabled): self.play_continously_button.setEnabled(enabled) self.stop_continously_button.setEnabled(not enabled) self.dropdown_play_continously.setEnabled(enabled) # ===================================================== # ================================================= # # Image/Appendix CLICK button # # ================================================= def image_or_appendix_on_click(self, list_to_play): # self.control_panel.gui.refreshPlayContinouslyListBeforeStartPlaying(index) # print("Disabled Play, Enabled Stop and selected Index:", index) PlayerThread.play(list_to_play) # ================================================= # # Play Contionusly STOP button # # ================================================= def stop_continously_button_on_click(self): """ Stops the continous play This method is called when the Play continously Stop button is pushed It stops the actually playing media, It breaks Play Continouisly list in the PlayerThread.stop() method it sets the __run=False and emit the stopPlaying event the stopPlaying is connected to the stop_playing_listener() method """ PlayerThread.stop() # ========================================= # # Play Continously PLAY button # # ========================================= def play_continously_button_on_click(self): """ Select the list from the actual media till the end and starts to play it This method is called when the Play Continously Play button is pushed """ start_index = self.get_play_continously_selected_index() last_index = self.get_play_continously_last_index() list_to_play = [] for actual_index in range(start_index, last_index + 1): list_to_play.append({ 'media-index': actual_index, 'media-path': self.get_play_continously_media_path_by_index(actual_index), 'media-type': self.get_play_continously_media_type_by_index(actual_index) }) PlayerThread.play(list_to_play) # --------------------------------------------- # # startNextPlaying Emmitted in PlayThread # # --------------------------------------------- def start_next_playing_emmitted(self, index): """ Disable the Play button, Enable the Stop button and select the next value in the Play list according to the index. This method is called from the PlayerThread object when the next media is started """ self.select_play_continously_element_by_index(index) self.control_panel.gui.refreshPlayContinouslyListBeforeStartPlaying( index) # --------------------------------------------- # # startNextPlaying Emmitted in PlayThread # # --------------------------------------------- def stop_playing_all_emmitted(self): """ This method is called from the PlayedThread object when the Stop button is pushed Enables the the Play button and disable the Stop button Refreshes the Play Continously List """ #self.enablePlayContinously(True) self.control_panel.gui.refreshPlayContinouslyListAfterStopPlaying() def play_continously_selection_changed_listener(self, index): """ Focus the card according to the selected value in the Play list This method is called when the selected element changed in the Play list """ if index >= 0: self.control_panel.gui.card_holder.focus_index(index) # # -------------------------- # # # # Fast Search Button Clicked # # # # -------------------------- # def fast_search_button_on_click(self, checked): # if checked: # self.advanced_search_button.setChecked(False) # # hide/show fast filter # self.control_panel.fast_filter_holder.setHidden(not checked) # # filter the list # self.control_panel.fast_filter_on_change() # # # ------------------------------ # # # # Advanced Search Button Clicked # # # # ------------------------------ # def advanced_search_button_on_click(self, checked): # if checked: # self.fast_search_button.setChecked(False) # # hide/show advanced filter # self.control_panel.advanced_filter_holder.setHidden(not checked) # # filter the list # self.control_panel.advanced_filter_filter_on_click() def setBackButtonMethod(self, back_button_method): self.back_button_method = back_button_method def setHierarchyButtonMethod(self, hierarchy_button_method): self.hierarchy_button_method = hierarchy_button_method def setHierarchy(self, show): self.hierarchy_button.setChecked(show) # ------------------- # # Back Button Clicked # # ------------------- def back_button_on_click(self): if self.back_button_method: self.back_button_method() # ------------------- # # Back Button Clicked # # ------------------- def hierarchy_button_on_toggle(self, checked): if self.hierarchy_button_method: self.hierarchy_button_method(checked)
class GUIToolMaterialsDatabase(BaseToolMaterialsDatabase, QTool): """[summary] [description] """ def __init__(self, name='', parent_app=None): """ **Constructor** Keyword Arguments: - name {[type]} -- [description] (default: {''}) - parent_dataset {[type]} -- [description] (default: {None}) - ax {[type]} -- [description] (default: {None}) """ super().__init__(name, parent_app) self.update_parameter_table() self.parent_application.update_all_ds_plots() # add widgets specific to the Tool here: self.active = False self.applytotheory = False self.actionActive.setVisible(False) self.actionApplyToTheory.setVisible(False) self.cbmaterial = QComboBox() self.cbmaterial.setToolTip("Choose a Material from the database") model = self.cbmaterial.model() i = 0 for polymer in materials_database.keys(): item = QStandardItem(polymer) item.setToolTip(materials_database[polymer].data['long']) model.appendRow(item) i += 1 self.num_materials_base = i self.cbmaterial.insertSeparator(i) for polymer in materials_user_database.keys(): item = QStandardItem(polymer) item.setToolTip(materials_user_database[polymer].data['long']) model.appendRow(item) self.tb.addWidget(self.cbmaterial) connection_id = self.cbmaterial.currentIndexChanged.connect( self.change_material) self.actionCalculate = QAction( QIcon(':/Icon8/Images/new_icons/icons8-ok.png'), "Calculate stuff", self) self.tb.addAction(self.actionCalculate) self.actionNew = QAction( QIcon(':/Icon8/Images/new_icons/icons8-add-file.png'), "New Material", self) self.tb.addAction(self.actionNew) self.actionEdit = QAction( QIcon(':/Icon8/Images/new_icons/icons8-edit-property.png'), "Edit/View Material Properties", self) self.tb.addAction(self.actionEdit) self.actionSave = QAction( QIcon(':/Icon8/Images/new_icons/icons8-save.png'), "Save User Material Database", self) self.tb.addAction(self.actionSave) connection_id = self.actionCalculate.triggered.connect( self.calculate_stuff) self.labelPolymer = QLabel("None") self.labelPolymer.setFont(QFont("Times", weight=QFont.Bold)) self.verticalLayout.insertWidget(1, self.labelPolymer) self.tbMwT = QToolBar() self.tbMwT.setIconSize(QSize(24, 24)) lbl1 = QLabel("Mw (kDa)") lbl1.setFont(QFont("Times", weight=QFont.Bold)) self.tbMwT.addWidget(lbl1) self.editMw = QLineEdit("1") self.editMw.setStyleSheet( "QLineEdit { background: rgb(255, 255, 205);}") self.editMw.setFixedWidth(40) self.tbMwT.addWidget(self.editMw) lbl2 = QLabel("T (°C)") lbl2.setFont(QFont("Times", weight=QFont.Bold)) self.tbMwT.addWidget(lbl2) self.editT = QLineEdit("0") self.editT.setStyleSheet( "QLineEdit { background: rgb(255, 255, 205);}") self.editT.setFixedWidth(40) self.tbMwT.addWidget(self.editT) self.verticalshift = self.tbMwT.addAction( QIcon(':/Icon8/Images/new_icons/icons8-vertical-shift.png'), 'Vertical shift') self.verticalshift.setCheckable(True) self.verticalshift.setChecked(True) self.isofrictional = self.tbMwT.addAction( QIcon(':/Icon8/Images/new_icons/icons8-iso.png'), "Shift to isofrictional state") self.isofrictional.setCheckable(True) self.isofrictional.setChecked(True) self.verticalLayout.insertWidget(2, self.tbMwT) self.change_material() def change_material(self): selected_material_name = self.cbmaterial.currentText() if (self.cbmaterial.currentIndex() < self.num_materials_base): dbindex = 1 else: dbindex = 0 self.labelPolymer.setText( materials_db[dbindex][selected_material_name].data['long']) for k in materials_db[dbindex][selected_material_name].data.keys(): self.set_param_value( k, materials_db[dbindex][selected_material_name].data[k]) self.update_parameter_table() def calculate_stuff(self): Mw = float(self.editMw.text()) T = float(self.editT.text()) B1 = self.parameters['B1'].value B2 = self.parameters['B2'].value logalpha = self.parameters['logalpha'].value alpha = np.power(10.0, logalpha) CTg = self.parameters['CTg'].value tau_e = self.parameters['tau_e'].value Ge = self.parameters['Ge'].value Me = self.parameters['Me'].value c_nu = self.parameters['c_nu'].value rho0 = self.parameters['rho0'].value Te = self.parameters['Te'].value iso = self.isofrictional.isChecked() vert = self.verticalshift.isChecked() if iso: B2 += CTg / Mw #- 68.7 * dx12 Trcorrected = T - CTg / Mw #+ 68.7 * dx12 else: Trcorrected = T aT = np.power( 10.0, -B1 * (Te - Trcorrected) / (B2 + Trcorrected) / (B2 + Te)) if vert: bT = (1 + alpha * Te) * (T + 273.15) / (1 + alpha * T) / (Te + 273.15) else: bT = 1 self.Qprint('<hr><h3>WLF TTS Shift Factors</h3>') # Need T1 (to shift from) and T2 (to shift to), if we want to report aT and bT self.Qprint("<b>C1</b> = %g" % (B1 / (B2 + T))) self.Qprint("<b>C2</b> = %g<br>" % (B2 + T)) self.Qprint('<h3>Tube Theory parameters</h3>') Ge /= bT tau_e /= aT self.Qprint("<b>tau_e</b> = %g" % tau_e) self.Qprint("<b>Ge</b> = %g<br>" % Ge) self.Qprint('<h3>Other Results</h3>') CC1 = 1.69 CC2 = 4.17 CC3 = -1.55 Z = Mw / Me tR = tau_e * Z * Z tD = 3 * tau_e * Z**3 * (1 - 2 * CC1 / np.sqrt(Z) + CC2 / Z + CC3 / Z**1.5) self.Qprint("<b>Z</b> = %g" % Z) self.Qprint("<b>tau_R</b> = %g" % tR) self.Qprint("<b>tau_D</b> = %g<br>" % tD)
def init_options(self): if self.layout() is None: self.center() self.setWindowTitle('Options') # Grid for checkbox options pref_header = QLabel('Preferences') pref_header.setObjectName('preferences') # In order to customize style in stylesheet set_header = QLabel('Settings') set_header.setObjectName('settings') h_line = QFrame() h_line.setFrameShape(QFrame.HLine) set_dir = QLabel('Set Screenshot Directory:') set_album = QLabel('Set imgur Album:') cb_click_send = QCheckBox('Click Balloon to Copy Image Link', self) cb_click_send.setChecked(True) cb_no_copy = QCheckBox('Never Copy Image Link') cb_auto_open = QCheckBox('Open Image in Browser') cb_auto_send = QCheckBox('Automatically Copy Image Link') cb_launch_start = QCheckBox('Launch on Start up') cb_launch_start.setDisabled(True) cb_no_copy.setChecked(True) cb_no_copy.setDisabled(True) cb_click_send.stateChanged.connect(lambda: cb_no_copy.setChecked(not cb_no_copy.isChecked())) cb_click_send.stateChanged.connect(lambda: cb_auto_send.setDisabled(cb_auto_send.isEnabled())) cb_click_send.stateChanged.connect(lambda: cb_auto_send.setChecked(cb_auto_send.isChecked())) cb_click_send.stateChanged.connect(self.toggle_click) cb_click_send.stateChanged.emit(1) cb_auto_send.stateChanged.connect(lambda: cb_click_send.setDisabled(cb_click_send.isEnabled())) cb_auto_send.stateChanged.connect(lambda: cb_click_send.setChecked(cb_click_send.isChecked())) cb_auto_send.stateChanged.connect(lambda: cb_no_copy.setChecked(not cb_no_copy.isChecked())) cb_auto_send.stateChanged.connect(self.toggle_auto_upload) cb_auto_open.stateChanged.connect(self.toggle_auto_open) dir_field = QLineEdit() dir_field.insert(self.scan_dir) album_choice = QComboBox() album_list = [alb for alb in self.albums.keys() if alb != 'Main'] album_choice.addItems(album_list) album_choice.insertSeparator(len(album_list) + 1) album_choice.insertItem(len(album_list) + 2, 'Main') album_choice.setCurrentIndex(len(album_list) + 1) album_choice.activated[str].connect(self.set_album) set_dir_button = QPushButton("Set") set_dir_button.clicked.connect(lambda: self.select_dir(dir_field)) set_dir_button.setMaximumWidth(80) options_layout = QGridLayout() options_layout.addWidget(pref_header, 0, 0) options_layout.addWidget(cb_click_send, 1, 0) options_layout.addWidget(cb_auto_send, 2, 0) options_layout.addWidget(cb_no_copy, 3, 0) options_layout.addWidget(cb_auto_open, 4, 0) options_layout.addWidget(h_line, 5, 0) options_layout.addWidget(cb_launch_start, 6, 0) options_layout.addWidget(set_header, 7, 0) options_layout.addWidget(set_dir, 8, 0) options_layout.addWidget(dir_field, 9, 0) options_layout.addWidget(set_dir_button, 10, 0) options_layout.addWidget(set_album, 11, 0) options_layout.addWidget(album_choice, 12, 0) ok_button = QPushButton("Ok") ok_button.clicked.connect(self.close) # cancel_button = QPushButton("Cancel") # Window Layout hbox = QHBoxLayout() hbox.addWidget(ok_button) # hbox.addWidget(cancel_button) # Add this later hbox.addStretch(1) vbox = QVBoxLayout() vbox.addLayout(options_layout) vbox.addLayout(hbox) self.setLayout(vbox) self.setStyleSheet(""" QWidget { background-color: rgb(50,50,50); } QLineEdit { border-color: 1px white; border-radius: 3px; padding: 0 8px; selection-color: #85BF25; background-color: white; } QComboBox { color: black; background-color: white; selection-background-color: rgb(50,50,50); selection-color: #85BF25; border: 1px black; border-radius: 3px; padding: 1px 18px 1px 3px; min-width: 6em; } QComboBox QListView{ color: white; border: 1px black; border-radius: 3px; padding: 1px 18px 1px 3px; min-width: 6em; border-color: #85BF25; } QComboBox::drop-down { width: 15px; } QLabel#preferences { color: #85BF25; font: bold 14px; } QLabel#settings { color: #85BF25; font: bold 14px; } QLabel { color: white; } QLabel#set_header { color: white; font: bold 14px; } QCheckBox { color: white; } QListWidget { color: white; } QPushButton { background-color: rgb(50,50,50); border-color: solid black; border-width: 2px; color: rgb(255,255,255); font: bold 12px; } """) else: pass
class QCodecSelection(QWidget): contentsModified = pyqtSignal() def __init__(self, track, savedencoders, *args, **kwargs): super().__init__(*args, **kwargs) self.track = track self.savedencoders = savedencoders layout = QHBoxLayout() layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.encoderSelectionComboBox = QComboBox(self) layout.addWidget(self.encoderSelectionComboBox) self.configBtn = QPushButton(self) layout.addWidget(self.configBtn) self.configBtn.setIcon(QIcon.fromTheme("preferences-other")) self.encoderSelectionComboBox.addItem("Copy Track", None) self.encoderSelectionComboBox.insertSeparator( self.encoderSelectionComboBox.count()) if track.type == "video": common_encoders = ["libx265", "libx264", "mpeg2video"] encoders = vencoders elif track.type == "audio": common_encoders = ["dca", "ac3", "libfdk_aac", "aac", "mp3", "flac"] encoders = aencoders elif track.type == "subtitle": common_encoders = ["ass", "srt"] encoders = sencoders else: common_encoders = ["libx265", "libx264", "mpeg2video", "dca", "ac3", "libfdk_aac", "aac", "mp3", "flac", "ass", "srt"] encoders = OrderedDict() encoders.update(vencoders) encoders.update(aencoders) encoders.update(sencoders) for key in common_encoders: try: self.encoderSelectionComboBox.addItem( f"{encoders[key]} ({key})", key) except KeyError: pass self.encoderSelectionComboBox.insertSeparator( self.encoderSelectionComboBox.count()) for key, encoder in sorted(encoders.items(), key=lambda item: item[1]): if key in common_encoders: continue self.encoderSelectionComboBox.addItem(f"{encoder} ({key})", key) self.encoderSelectionComboBox.currentIndexChanged.connect( self.encoderSelectionComboBoxChanged) self.configBtn.clicked.connect(self.configureCodec) self.configBtn.setEnabled(track.encoder is not None) def encoderSelectionComboBoxChanged(self, value): data = self.encoderSelectionComboBox.currentData() if ((id(self.track), data) not in self.savedencoders and data is not None): self.savedencoders[id(self.track), data] = createCodecConfigObj(data) self.configBtn.setDisabled(data is None) def configureCodec(self): data = self.encoderSelectionComboBox.currentData() encoder = self.savedencoders[id(self.track), data] dlg = encoder.copy().QtDlg(self) if (hasattr(dlg, "settingsApplied") and isinstance(dlg.settingsApplied, pyqtBoundSignal)): dlg.settingsApplied.connect(self.contentsModified) if dlg is not None and dlg.exec_(): encoder.__setstate__(dlg.encoder.__getstate__()) def setEncoderSelection(self, encoder): self.configBtn.setEnabled(encoder is not None) if encoder is not None: self.savedencoders[id(self.track), encoder.codec] = encoder if encoder: codecindex = self.encoderSelectionComboBox.findData(encoder.codec) else: codecindex = self.encoderSelectionComboBox.findData(None) self.encoderSelectionComboBox.blockSignals(True) if codecindex >= 0: self.encoderSelectionComboBox.setCurrentIndex(codecindex) else: self.encoderSelectionComboBox.setCurrentIndex(0) self.encoderSelectionComboBox.blockSignals(False) def encoderSelection(self): data = self.encoderSelectionComboBox.currentData() return self.savedencoders.get((id(self.track), data))
class GuiOutlineToolBar(QToolBar): loadNovelRootRequest = pyqtSignal(str) viewColumnToggled = pyqtSignal(bool, Enum) def __init__(self, theOutline): QTreeWidget.__init__(self, theOutline) logger.debug("Initialising GuiOutlineToolBar ...") self.mainConf = novelwriter.CONFIG self.mainGui = theOutline.mainGui self.theProject = theOutline.mainGui.theProject self.mainTheme = theOutline.mainGui.mainTheme iPx = self.mainConf.pxInt(22) mPx = self.mainConf.pxInt(12) self.setMovable(False) self.setIconSize(QSize(iPx, iPx)) self.setContentsMargins(0, 0, 0, 0) self.setStyleSheet("QToolBar {border: 0px;}") stretch = QWidget(self) stretch.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # Novel Selector self.novelLabel = QLabel(self.tr("Outline of")) self.novelLabel.setContentsMargins(0, 0, mPx, 0) self.novelValue = QComboBox(self) self.novelValue.setMinimumWidth(self.mainConf.pxInt(200)) self.novelValue.currentIndexChanged.connect(self._novelValueChanged) # Actions self.aRefresh = QAction(self.tr("Refresh"), self) self.aRefresh.setIcon(self.mainTheme.getIcon("refresh")) self.aRefresh.triggered.connect(self._refreshRequested) # Column Menu self.mColumns = GuiOutlineHeaderMenu(self) self.mColumns.columnToggled.connect( lambda isChecked, tItem: self.viewColumnToggled.emit( isChecked, tItem)) self.tbColumns = QToolButton(self) self.tbColumns.setIcon(self.mainTheme.getIcon("menu")) self.tbColumns.setMenu(self.mColumns) self.tbColumns.setPopupMode(QToolButton.InstantPopup) # Assemble self.addWidget(self.novelLabel) self.addWidget(self.novelValue) self.addSeparator() self.addAction(self.aRefresh) self.addWidget(self.tbColumns) self.addWidget(stretch) logger.debug("GuiOutlineToolBar initialisation complete") return ## # Methods ## def populateNovelList(self): """Fill the novel combo box with a list of all novel folders. """ self.novelValue.clear() tIcon = self.mainTheme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL]) for tHandle, nwItem in self.theProject.tree.iterRoots( nwItemClass.NOVEL): self.novelValue.addItem(tIcon, nwItem.itemName, tHandle) self.novelValue.insertSeparator(self.novelValue.count()) self.novelValue.addItem(tIcon, self.tr("All Novel Folders"), "") return def setColumnHiddenState(self, hiddenState): """Forward the change of column hidden states to the menu. """ self.mColumns.setHiddenState(hiddenState) return ## # Private Slots ## @pyqtSlot(int) def _novelValueChanged(self, index): """Emit a signal containing the handle of the selected item. """ if index >= 0: self.loadNovelRootRequest.emit(self.novelValue.currentData()) return @pyqtSlot() def _refreshRequested(self): """Emit a signal containing the handle of the selected item. """ self.loadNovelRootRequest.emit(self.novelValue.currentData()) return
class PyView(QApplication): '''PyView class''' def __init__(self, argv): '''Constructor. Parse args and build UI.''' super(PyView, self).__init__(argv) self.win = None self.scene = None self.gfxView = None self.layoutCombo = None self.appPath = os.path.abspath(os.path.dirname(argv[0])) self.currentLayout = ('createColumnCollage', ('3/2B/3', )) # Init GUI self.initUI() self.win.show() def initUI(self): '''Init UI of the PyView application''' # The QWidget widget is the base class of all user interface objects in PyQt5. self.win = QWidget() # Set window title self.win.setWindowTitle("PyView") self.win.setWindowIcon( QIcon(os.path.join(self.appPath, 'icons', DefaultPhoto))) self.win.resize(800, 800 * (1 / CollageAspectRatio)) vbox = QVBoxLayout() self.win.setLayout(vbox) # Add toolbar toolbar = QToolBar() toolbar.setStyleSheet('QToolBar{spacing:5px;}') vbox.addWidget(toolbar) # Standard Qt Pixmaps: http://doc.qt.io/qt-5/qstyle.html#StandardPixmap-enum icon = self.style().standardIcon(getattr(QStyle, 'SP_FileIcon')) toolbar.addAction(icon, 'New', getattr(self, 'newCollage')) icon = self.style().standardIcon(getattr(QStyle, 'SP_DialogSaveButton')) toolbar.addAction(icon, 'Save', getattr(self, 'saveCollage')) # Layout combobox toolbar.addSeparator() label = QLabel('Layout: ') toolbar.addWidget(label) self.layoutCombo = QComboBox() self.layoutCombo.addItem('Grid 2x2', ('createGridCollage', (2, 2))) self.layoutCombo.addItem('Grid 3x3', ('createGridCollage', (3, 3))) self.layoutCombo.addItem('Grid 3x4', ('createGridCollage', (3, 4))) self.layoutCombo.addItem('Grid 4x3', ('createGridCollage', (4, 3))) self.layoutCombo.addItem('Grid 4x4', ('createGridCollage', (4, 4))) self.layoutCombo.addItem('Grid 5x5', ('createGridCollage', (5, 5))) self.layoutCombo.addItem('Grid 7x1', ('createGridCollage', (7, 1))) self.layoutCombo.addItem('Columns 1B/3', ('createColumnCollage', ('1B/3', ))) self.layoutCombo.addItem('Columns 2/2B/2', ('createColumnCollage', ('2/2B/2', ))) self.layoutCombo.addItem('Columns 3/1B/3', ('createColumnCollage', ('3/1B/3', ))) self.layoutCombo.addItem('Columns 3/2B/3', ('createColumnCollage', ('3/2B/3', ))) self.layoutCombo.addItem('Rows 1B/2/3/2B', ('createRowCollage', ('1B/2/3/2B', ))) self.layoutCombo.setCurrentIndex(8) self.layoutCombo.currentIndexChanged[str].connect( self.layoutChangedHandler) toolbar.addWidget(self.layoutCombo) # Aspect ratio combobox label = QLabel('Aspect Ratio: ') toolbar.addWidget(label) self.aspectRatioCombo = QComboBox() self.aspectRatioCombo.addItem('1:1') self.aspectRatioCombo.insertSeparator(99) self.aspectRatioCombo.addItem('3:2') self.aspectRatioCombo.addItem('4:3') self.aspectRatioCombo.addItem('16:9') self.aspectRatioCombo.addItem('16:10') self.aspectRatioCombo.insertSeparator(99) self.aspectRatioCombo.addItem('2:3') self.aspectRatioCombo.addItem('3:4') self.aspectRatioCombo.setCurrentIndex(2) self.aspectRatioCombo.currentIndexChanged[str].connect( self.aspectRatioChangedHandler) toolbar.addWidget(self.aspectRatioCombo) # Frame color button toolbar.addSeparator() icon = QIcon(os.path.join(self.appPath, 'icons', 'frame-color.svg')) toolbar.addAction(icon, 'Choose frame color', getattr(self, 'setFrameColor')) # Create GraphicsView self.gfxView = ImageView() self.arWidget = AspectRatioWidget(self.gfxView, CollageAspectRatio) vbox.addWidget(self.arWidget) self.gfxView.setBackgroundBrush(QBrush(FrameColor)) # Set OpenGL renderer if OpenGLRender: self.gfxView.setViewport(QOpenGLWidget()) # Add scene self.scene = CollageScene() # Create initial collage funcname, args = self.currentLayout self.setLayout(funcname, *args) self.gfxView.setScene(self.scene) def setLayout(self, funcname, *args): logger.debug('funcname=%s *args=%s', funcname, str(args)) # Clear all items from scene self.scene.clear() # Create new collage func = getattr(self, funcname) if args: func(self.scene, *args) else: func(self.scene) def createGridCollage(self, scene, numx, numy): '''Create a collage with specified number of rows and columns''' f = LoopIter(filenames) photoWidth = CollageSize.width() / numx photoHeight = CollageSize.height() / numy for x in range(0, numx): for y in range(0, numy): scene.addPhoto( QRect(x * photoWidth, y * photoHeight, photoWidth, photoHeight), f.next()) def createColumnCollage(self, scene, desc): '''Create a collage based on the string passed in''' columns = desc.split('/') # Calculate base width # - Big photos are twice as wide as normal ones baseWidth = CollageSize.width() / (len(columns) + desc.count('B')) # Loop through all columns f = LoopIter(filenames) x = 0 for col in columns: logger.debug('col=%s', col) photoCount = int(col.replace('B', '')) if 'B' in col: photoWidth = baseWidth * 2 else: photoWidth = baseWidth photoHeight = CollageSize.height() / photoCount for y in range(0, photoCount): scene.addPhoto( QRect(x, y * photoHeight, photoWidth, photoHeight), f.next()) x += photoWidth def createRowCollage(self, scene, desc): '''Create a collage based on the string passed in''' rows = desc.split('/') # Calculate base height # - Big photos are twice as high as normal ones baseHeight = CollageSize.height() / (len(rows) + desc.count('B')) # Loop through all columns f = LoopIter(filenames) y = 0 for row in rows: logger.debug('row=%s', row) photoCount = int(row.replace('B', '')) if 'B' in row: photoHeight = baseHeight * 2 else: photoHeight = baseHeight photoWidth = CollageSize.width() / photoCount for x in range(0, photoCount): scene.addPhoto( QRect(x * photoWidth, y, photoWidth, photoHeight), f.next()) y += photoHeight def layoutChangedHandler(self, desc): '''Handler for layoutCombo signal''' global filenames self.currentLayout = self.layoutCombo.currentData() # Save list of displayed photos filenames = self.scene.getPhotosPaths() # Set new layout funcname, args = self.currentLayout self.setLayout(funcname, *args) def aspectRatioChangedHandler(self, desc): '''Handler for aspectRatioCombo signal''' global CollageAspectRatio global CollageSize global filenames width, height = [int(i) for i in desc.split(':')] CollageAspectRatio = width / height CollageSize = QRectF(0, 0, 2048, 2048 * (1 / CollageAspectRatio)) self.win.resize(self.win.width(), self.win.width() * (1 / CollageAspectRatio)) self.arWidget.setAspectRatio(CollageAspectRatio) # Save list of displayed photos filenames = self.scene.getPhotosPaths() # Clear scene self.scene.clear() # Re-create collage funcname, args = self.currentLayout self.setLayout(funcname, *args) #self.gfxView.setScene(self.scene) def newCollage(self): '''New collage''' ret = QMessageBox.question( self.win, 'New collage', 'Are you sure you want to reset your collage?', defaultButton=QMessageBox.Yes) if ret == QMessageBox.Yes: self.scene.clear() funcname, args = self.currentLayout self.setLayout(funcname, *args) def saveCollage(self, saveas=True): '''Save action handler''' global OutFileName global LastDirectory if saveas or not OutFileName: if not LastDirectory: LastDirectory = os.getcwd() OutFileName, filetype = QFileDialog.getSaveFileName( None, 'Save Collage', LastDirectory, "Images (*.png *.gif *.jpg);;All Files (*)") if OutFileName: LastDirectory = os.path.dirname(OutFileName) self.win.setWindowTitle('PyView - %s' % OutFileName) self.gfxView.save(OutFileName) def setFrameColor(self): '''Set color of the photo frames''' global FrameColor FrameColor = QColorDialog.getColor() self.gfxView.setBackgroundBrush(QBrush(FrameColor))
class NewFolderWindow(QDialog): def __init__(self, parent): super(NewFolderWindow, self).__init__() self.parent = parent self.setWindowTitle("Gridsync - Add New Sync Folder") self.resize(500, 225) self.layout = QVBoxLayout(self) self.folder = None layout = QVBoxLayout() grid_group_box = QGroupBox(self) grid_group_box.setTitle("Select remote storage grid to use:") grid_layout = QHBoxLayout(grid_group_box) self.grid_combo_box = QComboBox(grid_group_box) self.populate_combo_box() grid_layout.addWidget(self.grid_combo_box) layout.addWidget(grid_group_box) folder_group_box = QGroupBox(self) folder_group_box.setTitle("Select local folder to sync:") folder_layout = QHBoxLayout(folder_group_box) self.folder_text = QLineEdit(folder_group_box) folder_layout.addWidget(self.folder_text) folder_button = QPushButton(folder_group_box) folder_button.setText("Browse...") folder_button.clicked.connect(self.get_folder) folder_layout.addWidget(folder_button) layout.addWidget(folder_group_box) self.layout.addLayout(layout) button_box = QDialogButtonBox(self) button_box.setStandardButtons( QDialogButtonBox.Cancel | QDialogButtonBox.Ok) button_box.rejected.connect(self.close) button_box.accepted.connect(self.create_new_folder) self.layout.addWidget(button_box) def populate_combo_box(self): logging.debug("(Re-)populating combo box...") self.grid_combo_box.clear() for gateway in self.parent.gateways: self.grid_combo_box.addItem(gateway.location, gateway) self.grid_combo_box.insertSeparator(len(self.parent.gateways)) self.grid_combo_box.addItem("Add New Grid...") #self.grid_combo_box.setEnabled(False) def get_folder(self): self.folder = QFileDialog.getExistingDirectory( self, "Select local folder to sync") if self.folder: self.folder_text.setText(self.folder) def create_new_folder(self): if self.folder_text.text() and self.grid_combo_box.currentText(): self.close() selected_folder = str(self.folder_text.text()) selected_grid = str(self.grid_combo_box.currentText()) for gateway in self.parent.gateways: if gateway.name == selected_grid: tahoe = gateway tahoe.add_sync_folder(selected_folder)
class FileChooser(QWidget): fileOpened = pyqtSignal(str) def __init__(self, parent=None): super().__init__(parent) # TODO: migrate to FolderComboBox? self.folderBox = QComboBox(self) self.explorerTree = FileTreeView(self) self.explorerTree.doubleClickCallback = self._fileOpened self.explorerModel = QFileSystemModel(self) self.explorerModel.setFilter(QDir.AllDirs | QDir.Files | QDir.NoDotAndDotDot) self.explorerModel.setNameFilters(["*.py"]) self.explorerModel.setNameFilterDisables(False) self.explorerTree.setModel(self.explorerModel) for index in range(1, self.explorerModel.columnCount()): self.explorerTree.hideColumn(index) self.setCurrentFolder() self.folderBox.currentIndexChanged[int].connect( self.updateCurrentFolder) layout = QVBoxLayout(self) layout.addWidget(self.folderBox) layout.addWidget(self.explorerTree) layout.setContentsMargins(5, 5, 0, 0) def _fileOpened(self, modelIndex): path = self.explorerModel.filePath(modelIndex) if os.path.isfile(path): self.fileOpened.emit(path) def currentFolder(self): return self.explorerModel.rootPath() def setCurrentFolder(self, path=None): if path is None: app = QApplication.instance() path = app.getScriptsDirectory() else: assert os.path.isdir(path) self.explorerModel.setRootPath(path) self.explorerTree.setRootIndex(self.explorerModel.index(path)) self.folderBox.blockSignals(True) self.folderBox.clear() style = self.style() dirIcon = style.standardIcon(style.SP_DirIcon) self.folderBox.addItem(dirIcon, os.path.basename(path)) self.folderBox.insertSeparator(1) self.folderBox.addItem(self.tr("Browse…")) self.folderBox.setCurrentIndex(0) self.folderBox.blockSignals(False) def updateCurrentFolder(self, index): if index < self.folderBox.count() - 1: return path = QFileDialog.getExistingDirectory(self, self.tr("Choose Directory"), self.currentFolder(), QFileDialog.ShowDirsOnly) if path: QSettings().setValue("scripting/path", path) self.setCurrentFolder(path)
class CSVOptionsWindow(QWidget): def __init__(self, mainwindow): QWidget.__init__(self, mainwindow, Qt.Window) self._setupUi() self.doc = mainwindow.doc self.model = mainwindow.model.csv_options self.tableModel = CSVOptionsTableModel(self.model, self.tableView) self.model.view = self self.encodingComboBox.addItems(SUPPORTED_ENCODINGS) self.cancelButton.clicked.connect(self.hide) self.continueButton.clicked.connect(self.model.continue_import) self.targetComboBox.currentIndexChanged.connect(self.targetIndexChanged) self.layoutComboBox.currentIndexChanged.connect(self.layoutIndexChanged) self.rescanButton.clicked.connect(self.rescanClicked) def _setupUi(self): self.setWindowTitle(tr("CSV Options")) self.resize(526, 369) self.verticalLayout = QVBoxLayout(self) msg = tr( "Specify which CSV columns correspond to which transaction fields. You must also " "uncheck the \"Import\" column for lines that don\'t represent a transaction " "(header, footer, comments)." ) self.label = QLabel(msg) self.label.setWordWrap(True) self.verticalLayout.addWidget(self.label) self.gridLayout = QGridLayout() self.label_2 = QLabel(tr("Layout:")) self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1) self.layoutComboBox = QComboBox(self) self.layoutComboBox.setMinimumSize(QtCore.QSize(160, 0)) self.gridLayout.addWidget(self.layoutComboBox, 0, 1, 1, 1) self.label_4 = QLabel(tr("Delimiter:")) self.gridLayout.addWidget(self.label_4, 0, 3, 1, 1) self.fieldSeparatorEdit = QLineEdit(self) self.fieldSeparatorEdit.setMaximumSize(QtCore.QSize(30, 16777215)) self.gridLayout.addWidget(self.fieldSeparatorEdit, 0, 4, 1, 1) self.targetComboBox = QComboBox(self) self.gridLayout.addWidget(self.targetComboBox, 1, 1, 1, 1) self.label_3 = QLabel(tr("Target:")) self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1) self.encodingComboBox = QComboBox(self) self.gridLayout.addWidget(self.encodingComboBox, 1, 4, 1, 1) spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem, 2, 2, 1, 1) self.horizontalLayout_2 = QHBoxLayout() self.horizontalLayout_2.setSpacing(0) spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem1) self.rescanButton = QPushButton(tr("Rescan")) sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.rescanButton.sizePolicy().hasHeightForWidth()) self.rescanButton.setSizePolicy(sizePolicy) self.horizontalLayout_2.addWidget(self.rescanButton) self.gridLayout.addLayout(self.horizontalLayout_2, 2, 3, 1, 2) self.label_5 = QLabel(tr("Encoding:")) self.gridLayout.addWidget(self.label_5, 1, 3, 1, 1) self.verticalLayout.addLayout(self.gridLayout) self.tableView = QTableView(self) self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.setShowGrid(False) self.tableView.horizontalHeader().setHighlightSections(False) self.tableView.verticalHeader().setVisible(False) self.tableView.verticalHeader().setDefaultSectionSize(18) self.verticalLayout.addWidget(self.tableView) self.horizontalLayout = QHBoxLayout() spacerItem2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem2) self.cancelButton = QPushButton(tr("Cancel")) self.cancelButton.setShortcut("Esc") self.horizontalLayout.addWidget(self.cancelButton) self.continueButton = QPushButton(tr("Continue Import")) self.continueButton.setDefault(True) self.horizontalLayout.addWidget(self.continueButton) self.verticalLayout.addLayout(self.horizontalLayout) # --- Private def _newLayout(self): title = tr("New Layout") msg = tr("Choose a name for your new layout:") name, ok = QInputDialog.getText(self, title, msg) if ok and name: self.model.new_layout(name) def _renameLayout(self): title = tr("Rename Layout") msg = tr("Choose a name for your layout:") name, ok = QInputDialog.getText(self, title, msg) if ok and name: self.model.rename_selected_layout(name) # --- Event Handling def layoutIndexChanged(self, index): # This one is a little complicated. We want to only be able to select the layouts. If # anything else is clicked, we revert back to the old index. If the item has user data, # it means that an action has to be performed. if index < 0: return elif index < len(self.model.layout_names): layout_name = None if index == 0 else str(self.layoutComboBox.itemText(index)) self.model.select_layout(layout_name) else: self.layoutComboBox.setCurrentIndex(self.layoutComboBox.findText(self.model.layout.name)) data = str(self.layoutComboBox.itemData(index)) if data == NEW_LAYOUT: self._newLayout() elif data == RENAME_LAYOUT: self._renameLayout() elif data == DELETE_LAYOUT: self.model.delete_selected_layout() def rescanClicked(self): self.model.encoding_index = self.encodingComboBox.currentIndex() self.model.field_separator = str(self.fieldSeparatorEdit.text()) self.model.rescan() def targetIndexChanged(self, index): self.model.selected_target_index = index # --- model --> view # hide() is called from the model, but is already covered by QWidget def refresh_columns(self): self.tableModel.beginResetModel() self.tableModel.endResetModel() def refresh_columns_name(self): self.tableModel.refreshColumnsName() def refresh_layout_menu(self): self.layoutComboBox.currentIndexChanged.disconnect(self.layoutIndexChanged) self.layoutComboBox.clear() self.layoutComboBox.addItems(self.model.layout_names) self.layoutComboBox.insertSeparator(self.layoutComboBox.count()) self.layoutComboBox.addItem(tr("New Layout..."), NEW_LAYOUT) self.layoutComboBox.addItem(tr("Rename Selected Layout..."), RENAME_LAYOUT) self.layoutComboBox.addItem(tr("Delete Selected Layout"), DELETE_LAYOUT) self.layoutComboBox.setCurrentIndex(self.layoutComboBox.findText(self.model.layout.name)) self.layoutComboBox.currentIndexChanged.connect(self.layoutIndexChanged) def refresh_lines(self): self.tableModel.beginResetModel() self.tableModel.endResetModel() self.fieldSeparatorEdit.setText(self.model.field_separator) def refresh_targets(self): self.targetComboBox.currentIndexChanged.disconnect(self.targetIndexChanged) self.targetComboBox.clear() self.targetComboBox.addItems(self.model.target_account_names) self.targetComboBox.currentIndexChanged.connect(self.targetIndexChanged) def show(self): # For non-modal dialogs, show() is not enough to bring the window at the forefront, we have # to call raise() as well QWidget.show(self) self.raise_() def show_message(self, msg): title = "Warning" QMessageBox.warning(self, title, msg)
class FontsPreviewWidget(QWidget): """Show a preview score using the font selection.""" # Permanently cache compilations of the provided samples persistent_cache_dir = get_persistent_cache_dir() # Cache compilations of custom samples for Frescobaldi's lifetime only temp_dir = util.tempdir() def __init__(self, parent): super(FontsPreviewWidget, self).__init__(parent) # Create the cache directory for default samples os.makedirs(self.persistent_cache_dir, 0o700, exist_ok=True) layout = QVBoxLayout(margin=0) self.setLayout(layout) # Label with text "Example:" self.lb_sample = QLabel() # ComboBox for provided default samples and other options self.cb_samples = QComboBox() # Select custom file self.custom_sample_url = widgets.urlrequester.UrlRequester( fileMode=QFileDialog.ExistingFile, mustExist=True) # put the default sample in the combobox self.populate_default_samples() # add other actions self.cb_samples.insertSeparator(self.cb_samples.count()) self.cb_samples.addItem(_("Custom"), "<CUSTOM>") self.cb_samples.addItem(_("Current Document"), "<CURRENT>") # Add sample source widgets to layout bl = QHBoxLayout(margin=0) bl.addWidget(self.lb_sample) bl.addWidget(self.cb_samples) bl.addWidget(self.custom_sample_url) layout.addLayout(bl) # The score preview widget self.musicFontPreview = mfp = musicpreview.MusicPreviewWidget( parent, showProgress=False, showWaiting=True, showLog=False) layout.addWidget(mfp) app.translateUI(self) self.loadSettings() # Trigger showing of new samples self.cb_samples.currentIndexChanged.connect(self.show_sample) self.custom_sample_url.editingFinished.connect(self.show_sample) parent.finished.connect(self.saveSettings) def translateUI(self): self.lb_sample.setText("Example:") csu = self.custom_sample_url csu.setToolTip( _("Use custom sample for music font.\n" + "NOTE: This should not include a version statement " + "or a \\paper {...} block.")) csu.setDialogTitle(_("Select sample score")) csu.fileDialog(True).setNameFilters(['LilyPond files (*.ly)']) i = self.cb_samples.findData("<CURRENT>") self.cb_samples.setItemData( i, _("Use current document as music font sample.\n" + "NOTE: This is not robust if the document contains " + "a \\paper {...} block."), Qt.ToolTipRole) i = self.cb_samples.findData("<CUSTOM>") self.cb_samples.setItemData(i, csu.toolTip(), Qt.ToolTipRole) def loadSettings(self): s = QSettings() s.beginGroup('document-fonts-dialog') sample = s.value('default-music-sample', '', str) index = max(0, self.cb_samples.findData(sample)) self.cb_samples.setCurrentIndex(index) custom_sample = s.value('custom-music-sample-url', '', str) self.custom_sample_url.setPath(custom_sample) if custom_sample: sample_dir = os.path.dirname(custom_sample) else: sample_dir = os.path.dirname( self.window().parent().currentDocument().url().toLocalFile()) self.custom_sample_url.fileDialog().setDirectory(sample_dir) def saveSettings(self): s = QSettings() s.beginGroup('document-fonts-dialog') s.setValue('default-music-sample', self.cb_samples.currentData()) s.setValue('custom-music-sample-url', self.custom_sample_url.path()) def populate_default_samples(self): """Populate hte default samples ComboBox. This is just factored out to unclutter __init__. """ cb = self.cb_samples def add_entry(entry): cb.addItem(entry['label'], entry['file']) cb.setItemData(cb.count() - 1, entry['tooltip'], Qt.ToolTipRole) add_entry({ 'label': _('Bach (Piano)'), 'file': 'bach.ly', 'tooltip': _("Baroque music lends itself to traditional fonts") }) add_entry({ 'label': _('Scriabine (Piano)'), 'file': 'scriabine.ly', 'tooltip': _("Late romantic, complex piano music") }) add_entry({ 'label': _('Berg (String Quartet)'), 'file': 'berg-string-quartet.ly', 'tooltip': _("Complex score, requires a 'clean' font") }) add_entry({ 'label': _('Real Book (Lead Sheet)'), 'file': 'realbook.ly', 'tooltip': _("Jazz-like lead sheet.\n" + "NOTE: beautiful results rely on appropriate text fonts.\n" + "Good choices are \"lilyjazz-text\" for roman and\n" + "\"lilyjazz-chords\" for sans text fonts.") }) add_entry({ 'label': _('Schenker Diagram'), 'file': 'schenker.ly', 'tooltip': _("Schenker diagram with absolutely\n" + "non-standard notation.") }) add_entry({ 'label': _('Glyphs'), 'file': 'glyphs.ly', 'tooltip': _("Non-comprehensive specimen sheet") }) def show_sample(self): """Display a sample document for the selected notation font.""" print("Enter show_sample") global_size = '' base_dir = None sample_content = '' cache_persistently = False target = self.cb_samples.currentData() self.custom_sample_url.setEnabled(target == "<CUSTOM>") def handle_staff_size(): """ If the sample file *starts with* a staff-size definition it will be injected *after* our paper block. """ nonlocal sample_content, global_size match = re.match('#\(set-global-staff-size \d+\)', sample_content) if match: global_size = match.group(0) sample_content = sample_content[len(global_size):] def load_content(): """ Load the content to be engraved as sample, either from the active editor or from a file. """ nonlocal sample_content, base_dir nonlocal cache_persistently, target custom_file = self.custom_sample_url.path() if target == "<CUSTOM>" and not custom_file: target = self.cb_samples.itemData(0) # Provided sample files will be cached persistently cache_persistently = target not in ("<CUSTOM>", "<CURRENT>") if target == "<CURRENT>": # Engrave active document import engrave current_doc = engrave.engraver(app.activeWindow()).document() sample_content = current_doc.toPlainText() if not current_doc.url().isEmpty(): base_dir = os.path.dirname(current_doc.url().toLocalFile()) else: if target == "<CUSTOM>": print("Custom file:", custom_file) sample_file = custom_file else: # Engrave from a file import fonts template_dir = os.path.join(fonts.__path__[0], 'templates') sample_file = os.path.join(template_dir, 'musicfont-' + target) print("Default:", sample_file) base_dir = os.path.dirname(sample_file) with open(sample_file, 'r') as f: sample_content = f.read() def sample_document(): """ Steps of composing the used sample document. """ load_content() handle_staff_size() result = [ '\\version "{}"\n'.format(self.window( ).available_fonts.music_fonts().lilypond_info.versionString()), '{}\n'.format(global_size) if global_size else '', # TODO: "Protect" this regarding openLilyLib. # It would be easy to simply pass 'lily' as an argument # to always use the generic approach. However, that would # prevent the use of font extensions and stylesheets. self.window().font_full_cmd(), sample_content ] return '\n'.join(result) sample = sample_document() cache_dir = (self.persistent_cache_dir if cache_persistently else self.temp_dir) self.musicFontPreview.preview(sample, title='Music font preview', base_dir=base_dir, temp_dir=cache_dir, cached=True)
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
class main_principal(QWidget): fecha_actual = datetime.datetime.now( ) # datetime es la libreria que nos ayuda con las fechas horas minutos y hsta segundos #en este caso nos referimos a que nos de la fecha actual contador_hilo = 1 cursor = None lista_hilos = [] def banner_anonymous(self): #banner un bannner es solo un mensaje de texto #el \32 es para indicarle que queremos un espacio en blanco #puedes ver que hay muchos \32 en este paratado eso es debido a que #se necesitan espacios para imprimir bien el banner self.textarea_proceso.append( "$$$$$\32$\32\32\32\32$\32\32$$$$$\32$\32\32\32\32\32$$$$$$$\32\32\32\32\32\32######\32#####\32######\32##\32\32\32##" ) self.textarea_proceso.append( "$\32\32\32\32\32\32\32\32$\32\32\32\32$\32\32\32\32\32$\32\32\32\32$\32\32\32\32\32$\32\32\32\32\32$\32\32\32\32\32$\32\32\32\32\32\32#\32\32\32\32\32\32#" ) self.textarea_proceso.append( "$$$$$\32\32\32$\32\32\32\32\32$$$$$\32$\32\32\32\32\32$\32\32\32\32\32$||||||\32\32\32\32\32######\32#####\32######\32#\32\32\32\32\32#" ) self.textarea_proceso.append( "$\32\32\32\32\32\32$\32\32$\32\32\32$\32\32\32\32\32$\32\32\32\32\32$\32\32\32\32\32\32$\32\32\32\32\32\32\32\32\32\32\32#|#\32\32\32\32\32#\32\32\32\32#\32#\32\32\32\32\32#" ) self.textarea_proceso.append( "$$$$$\32$\32\32\32\32$\32\32$\32\32\32\32\32$$$$$\32$$$$$$$\32\32\32\32\32\32######\32#\32\32\32\32\32#\32\32\32\32#\32#\32\32\32\32\32#" ) self.textarea_proceso.append( "Autor: Aldair Martinez Alias Hans Krammler Junior" ) # Aqui declaramos mi nombre jajaj XD def spam_uno_a_uno(self): self.banner_anonymous() print(self.fecha_actual) def spam_uno_a_varios(self): self.banner_anonymous() print(self.fecha_actual) print(Fore.GREEN + "HAZ ELEGIDO ENVIAR DESDE TU COREO A OTROS CORREO") def mensaje(self): print("SE TERMINO EL HILO") contador_hilo_aux = 0 lista_hilos = [] workers = [] threads = [] def incializa_hilos(self): if self.contador_hilo == 1: self.thread = QThread() self.thread.setObjectName("Hilo_1") self.worker = Worker(self.contador_hilo, self.textarea_proceso, self.label_proceso_verificacion, None) self.worker.moveToThread(self.thread) self.thread.setTerminationEnabled(True) self.thread.started.connect(self.worker.run) self.worker.finished.connect(self.terminado) self.thread.finished.connect( lambda: self.verificar_resultado_hilo(self.thread)) self.worker.progressed.connect( lambda: self.reportProgress(self.worker)) self.worker.siguiente.connect( lambda: self.siguiente_hilo(self.thread)) self.thread.finished.connect(self.thread.quit) self.lista_hilos.append(self.thread) return self.lista_hilos else: self.lista_hilos = [] self.threads.append(QThread()) self.threads[self.contador_hilo_aux].setObjectName("Hilo_2") if self.contador_hilo == 2: print("Aqui tambien funciona") self.workers.append( Worker(self.contador_hilo, self.textarea_proceso, None, self.label_proceso_verificacion2)) elif self.contador_hilo == 3: self.workers.append( Worker(self.contador_hilo, self.textarea_proceso, None, self.label_proceso_verificacion3)) self.workers[self.contador_hilo_aux].moveToThread( self.threads[self.contador_hilo_aux]) self.threads[self.contador_hilo_aux].started.connect( self.workers[self.contador_hilo_aux].run) self.workers[self.contador_hilo_aux].finished.connect( self.terminado) print("Pasando terminado") self.threads[self.contador_hilo_aux].finished.connect( lambda: self.verificar_resultado_hilo(self.threads[ self.contador_hilo_aux])) print("Pasando verificar resultado") self.workers[self.contador_hilo_aux].progressed.connect( lambda: self.reportProgress(self.workers[self.contador_hilo_aux ])) print("Pasando reportprogress") self.workers[self.contador_hilo_aux].siguiente.connect( lambda: self.siguiente_hilo(self.threads[self.contador_hilo_aux ])) self.threads[self.contador_hilo_aux].finished.connect( self.threads[self.contador_hilo_aux].quit) print("Pasando quit") self.lista_hilos.append(self.threads[self.contador_hilo_aux]) return self.lista_hilos return None def siguiente_hilo(self, hilo): if self.contador_hilo == 1: if hilo.isRunning() == False: if hilo.isFinished() == True: print("si funciono") hilo.finished.connect(hilo.deleteLater) hilo.finished.connect(hilo.terminate) self.contador_hilo = self.contador_hilo + 1 self.incializa_hilos()[0].start() elif self.contador_hilo > 1: if self.get_verificado() == -1: return -1 elif self.get_verificado() == -2: return -2 else: return -3 if hilo.isRunning() == False: if hilo.isFinished() == True: self.contador_hilo = self.contador_hilo + 1 self.contador_hilo_aux = self.contador_hilo_aux + 1 self.incializa_hilos()[0].start() return 0 cursor = None estado_hilo_x = 0 lista_verificado = [] def set_verificado(self, estado): self.estado_hilo_x = estado def get_verificado(self): self.lista_verificado.append(self.estado_hilo_x) print("get.lista.verificado" + str(self.lista_verificado[0])) return int(self.lista_verificado[0]) def terminado(self): if self.contador_hilo == 1: print("TRABAJO TERMINADO") self.thread.finished.emit() elif self.contador_hilo > 1: self.threads[self.contador_hilo_aux].finished.emit() def verificar_resultado_hilo(self, thread): if self.contador_hilo == 1: if self.thread.isRunning() == False: print("EL HILO 1 HA TERMINADO SU TAREA") if self.thread.isFinished() == True: print("EL HILI 1 TERMINO CON EXITO") self.worker.progressed.emit() elif self.contador_hilo > 1: print(str(self.contador_hilo_aux)) if thread.isRunning() == False: print("EL HILO" + str(self.contador_hilo_aux) + "ESTA CORRIENDO") if thread.isFinished() == True: print("EL HILO" + str(self.contador_hilo_aux) + "HA TERMINADO") self.workers[self.contador_hilo_aux].progressed.emit() porcentaje = 10 _i = 0 lista_progreso = ["INICIANDO HILO DE EJECUCION......"] def reportProgress(self, worker): print(self.contador_hilo) if self.contador_hilo == 1: print("REPORTANDO HILO") #print("POSICION ACTUAL DEL CURSOR"+str(int(self.textarea_proceso.textCursor().position()))) worker.siguiente.emit() else: if self.contador_hilo == 2: email = self.line_edit_user_email.text() password = self.line_edit_user_password.text() longitud_email = len(email) longitud_password = len(password) if longitud_email == 0 or longitud_password == 0: self.set_verificado(-1) elif self.contador_hilo == 3: email = self.line_edit_user_email.text() email_to_list = list(email) contador = 1 for _x in len(email): if email_to_list[_x] == "@": contador = contador + 1 if contador > 1: self.set_verificado(-2) elif self.contador_hilo == 4: contador = 1 email_dominio = email.split(".") textarea_proceso.append("DIVIDIENDO TU EMAIL--->" + email_dominio) longitud_dominio_email = len(email_dominio) textarea_proceso.append( "VERIFICANDO COINCIDENCIA DE DOMINIO DE EMAIL....") dominios = [ "gmail.com", "outlook.com", "outlook.es", "hotmail.com", "hotmail.mx", "hotmail.es" ] longitud_dominio_gmail = len(dominios[0]) longitud_dominio_outlook_com = len(dominios[1]) longitud_dominio_outlook_es = len(dominios[2]) longitud_dominio_hotmail_com = len(dominios[3]) longitud_dominio_hotmail_mx = len(dominios[4]) longitud_dominio_hotmail_es = len(dominios[5]) for _i in range(longitud_dominio_email): for _j in (range(longitud_dominio_gmail) or range(longitud_dominio_outlook_com) or range(longitud_dominio_outlook_es) or range(longitud_dominio_hotmail_com) or range(longitud_dominio_hotmail_mx) or range(longitud_dominio_hotmail_es)): if _j < longitud_dominio_gmail: if dominios[0][_j] == email_dominio[1][_j]: print(dominios[0][j]) contador = contador + 1 elif _j < longitud_dominio_outlook_com: if dominios[1][_j] == email_dominio[1][_j]: contador = contador + 1 elif _j < longitud_dominio_outlook_es: if dominios[2][_j] == email_dominio[1][_j]: contador = contador + 1 elif _j < longitud_dominio_hotmail_com: if dominios[3][_j] == email_dominio[1][_j]: contador = contador + 1 elif _j < longitud_dominio_hotmail_mx: if dominios[4][_j] == email_dominio[1][_j]: contador = contador + 1 elif _j < longitud_dominio_hotmail_es: if dominios[5][_j] == email_dominio[1][_j]: contador = contador + 1 if contador > longitud_dominio_gmail: return -3 else: contador = 1 print("AQUI MEN") posicion_textarea = len(self.lista_progreso[self._i]) self.cursor = self.textarea_proceso.textCursor() print("CURSOR ACTUAL" + str(self.cursor)) print("POSICION CURSOR ACTUAL++" + str(self.cursor.position())) if self.cursor.atEnd() == True: print("FIN DEL CURSOR True") print("TEXTO SELECCIONADO ANTES" + self.cursor.selectedText()) posicion_inicial = (self.cursor.position() - 1) - (posicion_textarea - 1) + 1 print("posicion inicial" + str(posicion_inicial)) time.sleep(0.4) self.cursor.setPosition(posicion_inicial, QTextCursor.KeepAnchor) print("TEXTO SELECCIONADO AHORA" + self.cursor.selectedText()) print("POSICION CURSOR ACTUAL--" + str(self.cursor.position())) self.progreso = self.cursor.selectedText() + str( self.porcentaje) self.porcentaje = self.porcentaje + 10 self.textarea_proceso.append(self.progreso) print("POSICION CURSOR ACTUAL++" + str(self.cursor.position())) self._i = self._i + 1 worker.siguiente.emit() def verificar_opcion(self): pass def validar_oprciones(self): if self.checkbox_opcion_spam_uno_a_uno.isChecked( ) == True and self.checkbox_opcion_spam_uno_a_varios.isChecked(): self.label_estado_proceso.setText( Fore.RED + "LO SIENTO NO PUEDES SELECCIONAR DOS OPCIONES A LA VEZ") return False else: return True def escannear_red(self): scan = nmap.PortScanner() informacion_sistema = os.uname() def presionado(self): resultado_validar_opciones = self.validar_oprciones() if resultado_validar_opciones == True: self.inciar_hilo_principal() self.resultado_verificacion_email = 0 if self.resultado_verificacion_email == 0: print("PASANDO AL SIGUIENTE HILO DE EJECUCION") if self.resultado_verificacion_email == 1: if self.checkbox_opcion_spam_uno_a_uno.isChecked() == True: print( "LAS OCPIONES SELECCIONADAAS EN LOS CASILLA SON VALIDAS" ) else: if self.resultado_verificacion_email == -1 or self.resultado_verificacion_email == -2 or self.resultado_verificacion_email == -3: if self.resultado_verificacion_email == -1: self.label_estado_proceso.setText( "NO HAS INGRESADO NADA EN EL PRIMER CAMPO") self.textarea_proceso.append( "ERROR NO HAS INGRESADO NADA EN EL PRIMER CAMPO") elif self.resultado_verificacion_email == -2: self.label_estado_proceso.setText( "HAS MAS DE UN ARROBA EN TU CORREO") self.textarea_proceso.append( "ERROR HAY MAS DE UN ARROBA EN TU CORREO") elif self.resultado_verificacion_email == -3: self.label_estado_proceso.setText( "TERMINACION DE CORREO NO VALIDA") else: self.textarea_proceso.append( "INTENTE DE NUEVO RELLENAR LOS CAMPOS ADECUADAMENTE") def __init__(self, parent=None): #Parte de intefaz grafica super().__init__(parent) self.color = QColor(0, 0, 0, 0.5) self.setGeometry(550, 100, 1500, 500) self.pallette = QPalette(self.color) self.pallette.setColor(QPalette.Text, Qt.cyan) self.titulo_ventana = "ENVIO DE CORREO PARA HACER SPAM" self.setWindowTitle(self.titulo_ventana) self.setStyleSheet( "border-color: cyan; border-style: dashed; border-width: 2px; color:white" ) self.setPalette(self.pallette) self.checkbox_opcion_spam_uno_a_uno = QCheckBox( "REALIZAR SPAM UNO A UN CORREO") self.checkbox_opcion_spam_uno_a_uno.clicked.connect( self.spam_uno_a_uno) self.checkbox_opcion_spam_uno_a_varios = QCheckBox( "REALIZAR SPAM UNO A VARIOS COOREOS") self.checkbox_opcion_spam_uno_a_varios.clicked.connect( self.spam_uno_a_varios) self.label_user_email = QLabel("Ingresa tu direccion de correo: ") self.label_user_email.setFont(QFont("Times", 14, QFont.Bold, True)) self.label_user_email.setStyleSheet("color: white") self.line_edit_user_email = QLineEdit(self) self.line_edit_user_email.setPlaceholderText( "Ingresa tu direccion de cooreo:") self.line_edit_user_email.setFont(QFont("Times", 14, QFont.Bold, True)) self.line_edit_user_email.setStyleSheet("color : black") self.label_user_password = QLabel("Ingresa tu password de correo") self.label_user_password.setFont(QFont("Times", 14, QFont.Bold, True)) self.label_user_password.setStyleSheet("color: white") self.line_edit_user_password = QLineEdit(self) self.line_edit_user_password.setPlaceholderText( "Ingresa tu password de tu correo:") self.line_edit_user_password.setFont( QFont("Times", 14, QFont.Bold, True)) self.line_edit_user_password.setStyleSheet("color : black") self.label_victima_email = QLabel( "Ingresa direccion de correo destinatario: ") self.label_victima_email.setFont(QFont("Times", 14, QFont.Bold, True)) self.label_victima_email.setStyleSheet("color: white") self.line_edit_victima_email = QLineEdit(self) self.line_edit_victima_email.setPlaceholderText( "Ingresa tu direccion de cooreo:") self.line_edit_victima_email.setFont( QFont("Times", 14, QFont.Bold, True)) self.line_edit_victima_email.setStyleSheet("color : black") self.label_user_asunto = QLabel("Ingresa el asunto ") self.label_user_asunto.setFont(QFont("Times", 14, QFont.Bold, True)) self.label_user_asunto.setStyleSheet("color: white") self.line_edit_user_asunto = QLineEdit(self) self.line_edit_user_asunto.setPlaceholderText( "Ingresa tu direccion de cooreo:") self.line_edit_user_asunto.setFont(QFont("Times", 14, QFont.Bold, True)) self.line_edit_user_asunto.setStyleSheet("color : black") self.pushbutton_enviar = QPushButton("ENVIAR SPAM") self.pushbutton_enviar.setFont(QFont("Times", 14, QFont.Bold, True)) self.pushbutton_enviar.setPalette(self.pallette) self.label_estado_proceso = QLabel("") self.label_estado_proceso.setText("ESPERANDO DATOS....") self.label_proceso = QLabel("Estado verificacion email y password") self.label_proceso_verificacion = QLabel("") self.label_proceso2 = QLabel( "Estado verificacion arroba de email origen y destino") self.label_proceso_verificacion2 = QLabel("") self.label_proceso3 = QLabel( "Estado verificacion terminacion correo origen y destino") self.label_proceso_verificacion3 = QLabel("") self.combobox_dominios_from = QComboBox() self.combobox_dominios_from.addItem("Gmail.com") self.combobox_dominios_from.insertSeparator(1) self.combobox_dominios_from.addItem("Outlook.com") self.combobox_dominios_from.addItem("Outlook.es") self.combobox_dominios_from.insertSeparator(4) self.combobox_dominios_from.addItem("Hotmail.com") self.combobox_dominios_from.addItem("Hotmail.es") self.combobox_dominios_from.addItem("Hotmail.mx") self.combobox_dominios_from.setStyleSheet( "background-color:black; color: cyan") self.combobox_dominios_to = QComboBox() self.combobox_dominios_to.addItem("Gmail.com") self.combobox_dominios_to.insertSeparator(1) self.combobox_dominios_to.addItem("Outlook.com") self.combobox_dominios_to.addItem("Outlook.es") self.combobox_dominios_to.insertSeparator(4) self.combobox_dominios_to.addItem("Hotmail.com") self.combobox_dominios_to.addItem("Hotmail.es") self.combobox_dominios_to.addItem("Hotmail.mx") self.combobox_dominios_to.setStyleSheet( "background-color:black; color: cyan") self.combobox_dominios_from.currentTextChanged.connect( self.verificar_opcion) self.combobox_dominios_to.currentTextChanged.connect( self.verificar_opcion) self.pushbutton_enviar.clicked.connect(self.presionado) self.layout_main = QHBoxLayout(self) self.layout_principal = QVBoxLayout() self.layout_principal.addWidget(self.label_user_email) self.layout_principal.addWidget(self.line_edit_user_email) self.layout_principal.addWidget(self.label_user_password) self.layout_principal.addWidget(self.line_edit_user_password) self.layout_principal.addWidget(self.label_victima_email) self.layout_principal.addWidget(self.line_edit_victima_email) self.layout_principal.addWidget(self.label_user_asunto) self.layout_principal.addWidget(self.line_edit_user_asunto) self.layout_principal.addWidget(self.checkbox_opcion_spam_uno_a_uno) self.layout_principal.addWidget(self.checkbox_opcion_spam_uno_a_varios) self.layout_principal.addWidget(self.pushbutton_enviar) self.layout_principal.addWidget(self.label_estado_proceso) self.layout_principal.addWidget(self.combobox_dominios_from) self.layout_principal.addWidget(self.combobox_dominios_to) self.layout_principal.addWidget(self.label_proceso) self.layout_principal.addWidget(self.label_proceso_verificacion) self.layout_principal.addWidget(self.label_proceso2) self.layout_principal.addWidget(self.label_proceso_verificacion2) self.layout_principal.addWidget(self.label_proceso3) self.layout_principal.addWidget(self.label_proceso_verificacion3) self.layout_secundario = QVBoxLayout() self.textarea_proceso = QTextEdit() self.textarea_proceso.setPlaceholderText("ESPERANDO PARA PROCESAR") self.textarea_proceso.setFont(QFont("Times", 14, QFont.Bold, True)) self.textarea_proceso.setGeometry(0, 0, 500, 400) self.textarea_proceso.setStyleSheet( "color: yellow; background-color:black; border-style:solid") self.textarea_proceso.setReadOnly(False) self.textarea_proceso.setOverwriteMode(QTextEdit.WidgetWidth) self.layout_secundario.addWidget(self.textarea_proceso) self.layout_main.addLayout(self.layout_principal, 4) self.layout_main.addLayout(self.layout_secundario, 4) def inciar_hilo_principal(self): self.incializa_hilos()[0].start() return 0
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 EditStructure(ToolInstance): help = "https://github.com/QChASM/SEQCROW/wiki/Structure-Modification-Tool" SESSION_ENDURING = True SESSION_SAVE = True def __init__(self, session, name): super().__init__(session, name) self.settings = _EditStructureSettings(session, "Structure Modification") self.tool_window = MainToolWindow(self) self.close_previous_bool = self.settings.modify self._build_ui() def _build_ui(self): layout = QGridLayout() self.alchemy_tabs = QTabWidget() #substitute substitute_tab = QWidget() substitute_layout = QGridLayout(substitute_tab) sublabel = QLabel("substituent name:") substitute_layout.addWidget(sublabel, 0, 0, Qt.AlignVCenter) self.subname = QLineEdit() # self.subname.setText("Et") sub_completer = NameCompleter(Substituent.list(), self.subname) self.subname.setCompleter(sub_completer) self.subname.setToolTip("name of substituent in the AaronTools library or your personal library\nseparate names with commas and uncheck 'modify selected structure' to create several structures") substitute_layout.addWidget(self.subname, 0, 1, Qt.AlignVCenter) open_sub_lib = QPushButton("from library...") open_sub_lib.clicked.connect(self.open_sub_selector) substitute_layout.addWidget(open_sub_lib, 0, 2, Qt.AlignTop) substitute_layout.addWidget(QLabel("modify selected structure:"), 1, 0, 1, 1, Qt.AlignVCenter) self.close_previous_sub = QCheckBox() self.close_previous_sub.setToolTip("checked: selected structure will be modified\nunchecked: new model will be created for the modified structure") self.close_previous_sub.setChecked(self.settings.modify) self.close_previous_sub.stateChanged.connect(self.close_previous_change) substitute_layout.addWidget(self.close_previous_sub, 1, 1, 1, 2, Qt.AlignTop) substitute_layout.addWidget(QLabel("relax substituent:"), 2, 0, 1, 1, Qt.AlignVCenter) self.minimize = QCheckBox() self.minimize.setToolTip("spin the added substituents to try to minimize the LJ potential energy") self.minimize.setChecked(self.settings.minimize) substitute_layout.addWidget(self.minimize, 2, 1, 1, 1, Qt.AlignTop) substitute_layout.addWidget(QLabel("guess previous substituent:"), 3, 0, 1, 1, Qt.AlignVCenter) self.guess_old = QCheckBox() self.guess_old.setToolTip("checked: leave the longest connected fragment in the residue\nunchecked: previous substituent must be selected") self.guess_old.setChecked(self.settings.guess) self.guess_old.stateChanged.connect(lambda state, settings=self.settings: settings.__setattr__("guess", True if state == Qt.Checked else False)) substitute_layout.addWidget(self.guess_old, 3, 1, 1, 2, Qt.AlignTop) substitute_layout.addWidget(QLabel("new residue:"), 5, 0, 1, 1, Qt.AlignVCenter) self.new_residue = QCheckBox() self.new_residue.setToolTip("put the new substituent in its own residue instead\nof adding it to the residue of the old substituent") self.new_residue.setChecked(self.settings.new_residue) self.new_residue.stateChanged.connect(lambda state, settings=self.settings: settings.__setattr__("new_residue", True if state == Qt.Checked else False)) substitute_layout.addWidget(self.new_residue, 5, 1, 1, 2, Qt.AlignTop) substitute_layout.addWidget(QLabel("use distance names:"), 4, 0, 1, 1, Qt.AlignVCenter) self.use_greek = QCheckBox() self.use_greek.setChecked(self.settings.use_greek) self.use_greek.setToolTip("indicate distance from point of attachment with atom name") substitute_layout.addWidget(self.use_greek, 4, 1, 1, 1, Qt.AlignTop) substitute_layout.addWidget(QLabel("change residue name:"), 6, 0, 1, 1, Qt.AlignVCenter) self.new_sub_name = QLineEdit() self.new_sub_name.setToolTip("change name of modified residues") self.new_sub_name.setPlaceholderText("leave blank to keep current") substitute_layout.addWidget(self.new_sub_name, 6, 1, 1, 2, Qt.AlignTop) substitute_button = QPushButton("substitute current selection") substitute_button.clicked.connect(self.do_substitute) substitute_layout.addWidget(substitute_button, 7, 0, 1, 3, Qt.AlignTop) self.substitute_button = substitute_button substitute_layout.setRowStretch(0, 0) substitute_layout.setRowStretch(1, 0) substitute_layout.setRowStretch(2, 0) substitute_layout.setRowStretch(3, 0) substitute_layout.setRowStretch(4, 0) substitute_layout.setRowStretch(5, 0) substitute_layout.setRowStretch(6, 0) substitute_layout.setRowStretch(7, 1) #map ligand maplig_tab = QWidget() maplig_layout = QGridLayout(maplig_tab) liglabel = QLabel("ligand name:") maplig_layout.addWidget(liglabel, 0, 0, Qt.AlignVCenter) self.ligname = QLineEdit() lig_completer = NameCompleter(Component.list(), self.ligname) self.ligname.setCompleter(lig_completer) self.ligname.setToolTip("name of ligand in the AaronTools library or your personal library\nseparate names with commas and uncheck 'modify selected structure' to create several structures") maplig_layout.addWidget(self.ligname, 0, 1, Qt.AlignVCenter) open_lig_lib = QPushButton("from library...") open_lig_lib.clicked.connect(self.open_lig_selector) maplig_layout.addWidget(open_lig_lib, 0, 2, Qt.AlignTop) maplig_layout.addWidget(QLabel("modify selected structure:"), 1, 0, 1, 1, Qt.AlignVCenter) self.close_previous_lig = QCheckBox() self.close_previous_lig.setToolTip("checked: selected structure will be modified\nunchecked: new model will be created for the modified structure") self.close_previous_lig.setChecked(self.settings.modify) self.close_previous_lig.stateChanged.connect(self.close_previous_change) maplig_layout.addWidget(self.close_previous_lig, 1, 1, 1, 2, Qt.AlignTop) maplig_button = QPushButton("swap ligand with selected coordinating atoms") maplig_button.clicked.connect(self.do_maplig) maplig_layout.addWidget(maplig_button, 2, 0, 1, 3, Qt.AlignTop) self.maplig_button = maplig_button start_structure_button = QPushButton("place in:") self.lig_model_selector = ModelComboBox(self.session, addNew=True) start_structure_button.clicked.connect(self.do_new_lig) maplig_layout.addWidget(start_structure_button, 3, 0, 1, 1, Qt.AlignTop) maplig_layout.addWidget(self.lig_model_selector, 3, 1, 1, 2, Qt.AlignTop) maplig_layout.setRowStretch(0, 0) maplig_layout.setRowStretch(1, 0) maplig_layout.setRowStretch(2, 0) maplig_layout.setRowStretch(3, 1) #close ring closering_tab = QWidget() closering_layout = QGridLayout(closering_tab) ringlabel = QLabel("ring name:") closering_layout.addWidget(ringlabel, 0, 0, Qt.AlignVCenter) self.ringname = QLineEdit() ring_completer = NameCompleter(Ring.list(), self.ringname) self.ringname.setCompleter(ring_completer) self.ringname.setToolTip("name of ring in the AaronTools library or your personal library\nseparate names with commas and uncheck 'modify selected structure' to create several structures") closering_layout.addWidget(self.ringname, 0, 1, Qt.AlignVCenter) open_ring_lib = QPushButton("from library...") open_ring_lib.clicked.connect(self.open_ring_selector) closering_layout.addWidget(open_ring_lib, 0, 2, Qt.AlignTop) closering_layout.addWidget(QLabel("modify selected structure:"), 1, 0, 1, 1, Qt.AlignVCenter) self.close_previous_ring = QCheckBox() self.close_previous_ring.setToolTip("checked: selected structure will be modified\nunchecked: new model will be created for the modified structure") self.close_previous_ring.setChecked(self.settings.modify) self.close_previous_ring.stateChanged.connect(self.close_previous_change) closering_layout.addWidget(self.close_previous_ring, 1, 1, 1, 2, Qt.AlignTop) closering_layout.addWidget(QLabel("try multiple:"), 2, 0, 1, 1, Qt.AlignVCenter) self.minimize_ring = QCheckBox() self.minimize_ring.setToolTip("try to use other versions of this ring in the library to find the one that fits best") self.minimize_ring.setChecked(self.settings.minimize_ring) closering_layout.addWidget(self.minimize_ring, 2, 1, 1, 2, Qt.AlignTop) closering_layout.addWidget(QLabel("new residue name:"), 3, 0, 1, 1, Qt.AlignVCenter) self.new_ring_name = QLineEdit() self.new_ring_name.setToolTip("change name of modified residues") self.new_ring_name.setPlaceholderText("leave blank to keep current") closering_layout.addWidget(self.new_ring_name, 3, 1, 1, 2, Qt.AlignTop) closering_button = QPushButton("put a ring on current selection") closering_button.clicked.connect(self.do_fusering) closering_layout.addWidget(closering_button, 4, 0, 1, 3, Qt.AlignTop) self.closering_button = closering_button start_structure_button = QPushButton("place in:") self.ring_model_selector = ModelComboBox(self.session, addNew=True) start_structure_button.clicked.connect(self.do_new_ring) closering_layout.addWidget(start_structure_button, 5, 0, 1, 1, Qt.AlignTop) closering_layout.addWidget(self.ring_model_selector, 5, 1, 1, 2, Qt.AlignTop) closering_layout.setRowStretch(0, 0) closering_layout.setRowStretch(1, 0) closering_layout.setRowStretch(2, 0) closering_layout.setRowStretch(3, 0) closering_layout.setRowStretch(4, 0) closering_layout.setRowStretch(5, 1) #change element changeelement_tab = QWidget() changeelement_layout = QFormLayout(changeelement_tab) self.element = QPushButton("C") self.element.setMinimumWidth(int(1.3*self.element.fontMetrics().boundingRect("QQ").width())) self.element.setMaximumWidth(int(1.3*self.element.fontMetrics().boundingRect("QQ").width())) self.element.setMinimumHeight(int(1.5*self.element.fontMetrics().boundingRect("QQ").height())) self.element.setMaximumHeight(int(1.5*self.element.fontMetrics().boundingRect("QQ").height())) ele_color = tuple(list(element_color(ELEMENTS.index("C")))[:-1]) self.element.setStyleSheet( "QPushButton { background: rgb(%i, %i, %i); color: %s; font-weight: bold; }" % ( *ele_color, 'white' if sum( int(x < 130) - int(x > 225) for x in ele_color ) - int(ele_color[1] > 225) + int(ele_color[2] > 200) >= 2 else 'black' ) ) self.element.clicked.connect(self.open_ptable) changeelement_layout.addRow("element:", self.element) self.vsepr = QComboBox() self.vsepr.addItems([ "do not change", # 0 "linear (1 bond)", # 1 "linear (2 bonds)", # 2 "trigonal planar (2 bonds)", # 3 "tetrahedral (2 bonds)", # 4 "trigonal planar", # 5 "tetrahedral (3 bonds)", # 6 "T-shaped", # 7 "trigonal pyramidal", # 8 "tetrahedral", # 9 "sawhorse", #10 "seesaw", #11 "square planar", #12 "trigonal bipyramidal", #13 "square pyramidal", #14 "pentagonal", #15 "octahedral", #16 "hexagonal", #17 "trigonal prismatic", #18 "pentagonal pyramidal", #19 "capped octahedral", #20 "capped trigonal prismatic", #21 "heptagonal", #22 "hexagonal pyramidal", #23 "pentagonal bipyramidal", #24 "biaugmented trigonal prismatic", #25 "cubic", #26 "elongated trigonal bipyramidal", #27 "hexagonal bipyramidal", #28 "heptagonal pyramidal", #29 "octagonal", #30 "square antiprismatic", #31 "trigonal dodecahedral", #32 "capped cube", #33 "capped square antiprismatic", #34 "enneagonal", #35 "heptagonal bipyramidal", #36 "hula-hoop", #37 "triangular cupola", #38 "tridiminished icosahedral", #39 "muffin", #40 "octagonal pyramidal", #41 "tricapped trigonal prismatic", #42 ]) self.vsepr.setCurrentIndex(9) self.vsepr.insertSeparator(33) self.vsepr.insertSeparator(25) self.vsepr.insertSeparator(20) self.vsepr.insertSeparator(16) self.vsepr.insertSeparator(13) self.vsepr.insertSeparator(8) self.vsepr.insertSeparator(5) self.vsepr.insertSeparator(2) self.vsepr.insertSeparator(1) self.vsepr.insertSeparator(0) changeelement_layout.addRow("geometry:", self.vsepr) self.change_bonds = QCheckBox() self.change_bonds.setChecked(self.settings.change_bonds) changeelement_layout.addRow("adjust bond lengths:", self.change_bonds) change_element_button = QPushButton("change selected elements") change_element_button.clicked.connect(self.do_change_element) changeelement_layout.addRow(change_element_button) self.change_element_button = change_element_button start_structure_button = QPushButton("place in:") self.model_selector = ModelComboBox(self.session, addNew=True) start_structure_button.clicked.connect(self.do_new_atom) changeelement_layout.addRow(start_structure_button, self.model_selector) delete_atoms_button = QPushButton("delete selected atoms") delete_atoms_button.clicked.connect(self.delete_atoms) changeelement_layout.addRow(delete_atoms_button) self.alchemy_tabs.addTab(substitute_tab, "substitute") self.alchemy_tabs.addTab(maplig_tab, "swap ligand") self.alchemy_tabs.addTab(closering_tab, "fuse ring") self.alchemy_tabs.addTab(changeelement_tab, "change element") layout.addWidget(self.alchemy_tabs) self.tool_window.ui_area.setLayout(layout) self.tool_window.manage(None) def close_previous_change(self, state): if state == Qt.Checked: self.settings.modify = True for checkbox in [self.close_previous_lig, self.close_previous_sub, self.close_previous_ring]: checkbox.setChecked(True) self.close_previous_bool = True else: self.settings.modify = False for checkbox in [self.close_previous_lig, self.close_previous_sub, self.close_previous_ring]: checkbox.setChecked(False) self.close_previous_bool = False def do_substitute(self): subnames = self.subname.text() new_name = self.new_sub_name.text() use_attached = not self.guess_old.isChecked() minimize = self.minimize.isChecked() new_residue = self.new_residue.isChecked() use_greek = self.use_greek.isChecked() self.settings.minimize = minimize self.settings.use_greek = use_greek if len(new_name.strip()) > 0: run( self.session, "substitute sel substituents %s newName %s guessAttachment %s modify %s minimize %s useRemoteness %s newResidue %s" % ( subnames, new_name, not use_attached, self.close_previous_bool, minimize, use_greek, new_residue, ) ) else: run( self.session, "substitute sel substituents %s guessAttachment %s modify %s minimize %s useRemoteness %s newResidue %s" % ( subnames, not use_attached, self.close_previous_bool, minimize, use_greek, new_residue, ) ) def open_sub_selector(self): self.tool_window.create_child_window("select substituents", window_class=SubstituentSelection, textBox=self.subname) def do_maplig(self): lignames = self.ligname.text() selection = selected_atoms(self.session) if len(selection) < 1: raise RuntimeWarning("nothing selected") models = {} for atom in selection: if atom.structure not in models: models[atom.structure] = [AtomSpec(atom.atomspec)] else: models[atom.structure].append(AtomSpec(atom.atomspec)) first_pass = True new_structures = [] for ligname in lignames.split(','): ligname = ligname.strip() lig = Component(ligname) for model in models: if self.close_previous_bool and first_pass: rescol = ResidueCollection(model) elif self.close_previous_bool and not first_pass: raise RuntimeError("only the first model can be replaced") else: model_copy = model.copy() rescol = ResidueCollection(model_copy) for i, atom in enumerate(model.atoms): rescol.atoms[i].atomspec = atom.atomspec rescol.atoms[i].add_tag(atom.atomspec) rescol.atoms[i].chix_atom = atom target = rescol.find(models[model]) if len(target) % len(lig.key_atoms) == 0: k = 0 ligands = [] while k != len(target): res_lig = ResidueCollection(lig.copy(), comment=lig.comment) res_lig.parse_comment() res_lig = Component(res_lig, key_atoms = ",".join([str(k + 1) for k in res_lig.other["key_atoms"]])) ligands.append(res_lig) k += len(lig.key_atoms) else: raise RuntimeError("number of key atoms no not match: %i now, new ligand has %i" % (len(target), len(lig.key_atoms))) rescol.map_ligand(ligands, target) for center_atom in rescol.center: center_atom.connected = set([]) for atom in rescol.atoms: if atom not in rescol.center: if center_atom.is_connected(atom): atom.connected.add(center_atom) center_atom.connected.add(atom) if self.close_previous_bool: rescol.update_chix(model) else: struc = rescol.get_chimera(self.session) new_structures.append(struc) first_pass = False if not self.close_previous_bool: self.session.models.add(new_structures) def open_lig_selector(self): self.tool_window.create_child_window("select ligands", window_class=LigandSelection, textBox=self.ligname) def do_fusering(self): ring_names = self.ringname.text() new_name = self.new_ring_name.text() minimize_ring = self.minimize_ring.isChecked() self.settings.minimize_ring = minimize_ring if len(new_name.strip()) > 0: run( self.session, "fuseRing sel rings %s newName %s modify %s minimize %s" % ( ring_names, new_name, self.close_previous_bool, minimize_ring, ) ) else: run( self.session, "fuseRing sel rings %s modify %s minimize %s" % ( ring_names, self.close_previous_bool, minimize_ring, ) ) def open_ring_selector(self): self.tool_window.create_child_window("select rings", window_class=RingSelection, textBox=self.ringname) def open_ptable(self): self.tool_window.create_child_window("select element", window_class=_PTable, button=self.element) def display_help(self): """Show the help for this tool in the help viewer.""" from chimerax.core.commands import run run(self.session, 'open %s' % self.help if self.help is not None else "") def do_change_element(self): element = self.element.text() adjust_bonds = self.change_bonds.isChecked() self.settings.change_bonds = adjust_bonds vsepr = self.vsepr.currentText() if vsepr == "do not change": vsepr = False elif vsepr == "linear (1 bond)": vsepr = "linear 1" goal = 1 elif vsepr == "linear (2 bonds)": vsepr = "linear 2" goal = 2 elif vsepr == "trigonal planar (2 bonds)": vsepr = "bent 2 planar" goal = 2 elif vsepr == "tetrahedral (2 bonds)": vsepr = "bent 2 tetrahedral" goal = 2 elif vsepr == "trigonal planar": goal = 3 elif vsepr == "tetrahedral (3 bonds)": vsepr = "bent 3 tetrahedral" goal = 3 else: goal = len(Atom.get_shape(vsepr)) - 1 sel = selected_atoms(self.session) models, _ = guessAttachmentTargets(sel, self.session, allow_adjacent=False) for model in models: conv_res = list(models[model].keys()) for res in models[model]: for target in models[model][res]: for neighbor in target.neighbors: if neighbor.residue not in conv_res: conv_res.append(neighbor.residue) for pbg in self.session.models.list(type=PseudobondGroup): for pbond in pbg.pseudobonds: if target in pbond.atoms and all(atom.structure is model for atom in pbond.atoms): other_atom = pbond.other_atom(target) if other_atom.residue not in conv_res: conv_res.append(other_atom.residue) rescol = ResidueCollection(model, convert_residues=conv_res) for res in models[model]: residue = [resi for resi in rescol.residues if resi.chix_residue is res][0] for target in models[model][res]: targ = rescol.find_exact(AtomSpec(target.atomspec))[0] adjust_hydrogens = vsepr if vsepr is not False: cur_bonds = len(targ.connected) change_Hs = goal - cur_bonds adjust_hydrogens = (change_Hs, vsepr) residue.change_element(targ, element, adjust_bonds=adjust_bonds, adjust_hydrogens=adjust_hydrogens, ) residue.update_chix(res) def do_new_ring(self): rings = self.ringname.text() for ring in rings.split(","): ring = ring.strip() rescol = ResidueCollection(Ring(ring)) model = self.ring_model_selector.currentData() if model is None: chix = rescol.get_chimera(self.session) self.session.models.add([chix]) apply_seqcrow_preset(chix, fallback="Ball-Stick-Endcap") self.ring_model_selector.setCurrentIndex(self.ring_model_selector.count()-1) else: res = model.new_residue("new", "a", len(model.residues)+1) rescol.residues[0].update_chix(res) run(self.session, "select add %s" % " ".join([atom.atomspec for atom in res.atoms])) def do_new_lig(self): ligands = self.ligname.text() for lig in ligands.split(","): lig = lig.strip() rescol = ResidueCollection(Component(lig)) model = self.lig_model_selector.currentData() if model is None: chix = rescol.get_chimera(self.session) self.session.models.add([chix]) apply_seqcrow_preset(chix, fallback="Ball-Stick-Endcap") self.lig_model_selector.setCurrentIndex(self.lig_model_selector.count()-1) else: res = model.new_residue("new", "a", len(model.residues)+1) rescol.residues[0].update_chix(res) run(self.session, "select add %s" % " ".join([atom.atomspec for atom in res.atoms])) def do_new_atom(self): element = self.element.text() adjust_bonds = self.change_bonds.isChecked() self.settings.change_bonds = adjust_bonds vsepr = self.vsepr.currentText() if vsepr == "do not change": vsepr = False elif vsepr == "linear (1 bond)": vsepr = "linear 1" elif vsepr == "linear (2 bonds)": vsepr = "linear 2" elif vsepr == "trigonal planar (2 bonds)": vsepr = "bent 2 planar" elif vsepr == "tetrahedral (2 bonds)": vsepr = "bent 2 tetrahedral" elif vsepr == "tetrahedral (3 bonds)": vsepr = "bent 3 tetrahedral" if vsepr: atoms = Atom.get_shape(vsepr) atoms[0].element = element for atom in atoms[1:]: atom.element = "H" if adjust_bonds: # this works b/c all atoms are 1 angstrom from the center # just multiply by the distance we want expected_dist = RADII[element] + RADII["H"] for atom in atoms[1:]: atom.coords *= expected_dist for atom in atoms[1:]: atoms[0].connected.add(atom) atom.connected.add(atoms[0]) else: atoms = [Atom(element=element, coords=np.zeros(3))] rescol = ResidueCollection(atoms, name="new", refresh_connected=False) model = self.model_selector.currentData() if model is None: chix = rescol.get_chimera(self.session) self.session.models.add([chix]) apply_seqcrow_preset(chix, fallback="Ball-Stick-Endcap") self.model_selector.setCurrentIndex(self.model_selector.count()-1) else: res = model.new_residue("new", "a", len(model.residues)+1) rescol.residues[0].update_chix(res) run(self.session, "select add %s" % " ".join([atom.atomspec for atom in res.atoms])) def delete_atoms(self, *args): atoms = selected_atoms(self.session) for atom in atoms: atom.delete() def delete(self): self.ring_model_selector.deleteLater() self.lig_model_selector.deleteLater() self.model_selector.deleteLater() return super().delete() def close(self): self.ring_model_selector.deleteLater() self.lig_model_selector.deleteLater() self.model_selector.deleteLater() return super().close()