class DocumentTab(QWidget): def __init__(self, parent): self.parent = parent super(DocumentTab, self).__init__(parent) self.name = 'Documents' self.formats = config.document_formats convertQL = QLabel(self.tr('Convert to:')) self.extQCB = QComboBox() final_layout = utils.add_to_layout('h', convertQL, self.extQCB, None) self.setLayout(final_layout) def fill_extension_combobox(self, extraformats): self.extQCB.clear() self.extQCB.addItems(sorted(self.formats + extraformats)) def ok_to_continue(self): """ Check if everything is ok with documenttab to continue conversion. Checks if: - unoconv is missing. Return True if all tests pass, else False. """ if not self.parent.unoconv: QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr('Error!'), self.tr('Unocov is not installed!')) return False return True
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)
class StartSession(preferences.Group): def __init__(self, page): super(StartSession, self).__init__(page) grid = QGridLayout() self.setLayout(grid) def changed(): self.changed.emit() self.combo.setEnabled(self.custom.isChecked()) self.none = QRadioButton(toggled=changed) self.lastused = QRadioButton(toggled=changed) self.custom = QRadioButton(toggled=changed) self.combo = QComboBox(currentIndexChanged=changed) grid.addWidget(self.none, 0, 0, 1, 2) grid.addWidget(self.lastused, 1, 0, 1, 2) grid.addWidget(self.custom, 2, 0, 1, 1) grid.addWidget(self.combo, 2, 1, 1, 1) app.translateUI(self) def translateUI(self): self.setTitle(_("Session to load if Frescobaldi is started without arguments")) self.none.setText(_("Start with no session")) self.lastused.setText(_("Start with last used session")) self.custom.setText(_("Start with session:")) def loadSettings(self): s = QSettings() s.beginGroup("session") startup = s.value("startup", "none", str) if startup == "lastused": self.lastused.setChecked(True) elif startup == "custom": self.custom.setChecked(True) else: self.none.setChecked(True) sessionNames = sessions.sessionNames() self.combo.clear() self.combo.addItems(sessionNames) custom = s.value("custom", "", str) if custom in sessionNames: self.combo.setCurrentIndex(sessionNames.index(custom)) def saveSettings(self): s = QSettings() s.beginGroup("session") s.setValue("custom", self.combo.currentText()) if self.custom.isChecked(): startup = "custom" elif self.lastused.isChecked(): startup = "lastused" else: startup = "none" s.setValue("startup", startup)
class AddPlayerWidget(QWidget): def __init__(self): super(AddPlayerWidget, self).__init__() self.users = {} # self.setWindowTitle('Add Player') self.setStyleSheet(style.style_loader.stylesheet) self.label = QLabel('Enter Name:', self) self.label_widget = QWidget(self) label_layout = QBoxLayout(QBoxLayout.LeftToRight) label_layout.addWidget(self.label) self.label_widget.setLayout(label_layout) self.user_box = QComboBox(self) self.user_box.setFixedWidth(210) self.user_box.setFixedHeight(50) self.user_box_widget = QWidget(self) user_box_layout = QBoxLayout(QBoxLayout.LeftToRight) user_box_layout.addWidget(self.user_box) self.user_box_widget.setLayout(user_box_layout) self.submit_btn = QPushButton('Add Player', self) self.submit_btn.clicked.connect(self.submit) self.submit_btn_widget = QWidget(self) submit_btn_layout = QBoxLayout(QBoxLayout.LeftToRight) submit_btn_layout.addWidget(self.submit_btn) self.submit_btn_widget.setLayout(submit_btn_layout) layout = QFormLayout() layout.addRow(self.label_widget) layout.addRow(self.user_box_widget) layout.addRow(self.submit_btn_widget) self.setLayout(layout) self.show() self.setFixedHeight(self.height()) self.setFixedWidth(self.width()) self.close() def update(self): self.user_box.clear() self.users = um.users() for user in self.users: self.user_box.addItem(user.name + ' (' + str(user.id) + ')') def submit(self): user = self.users[self.user_box.currentIndex()] view.notifier.player_added(user.name, user) self.close()
class AreaOperation(QWidget): # - add objects to an area # - remove objects from an area @update_paths def __init__(self, mode, obj, AS=set(), controller=None): super().__init__() title = 'Add to area' if mode == 'add' else 'Remove from area' self.setWindowTitle(title) values = tuple(map(str, AS)) # list of existing AS self.AS_list = QComboBox() self.AS_list.addItems(values) self.AS_list.activated.connect(self.update_value) # list of areas self.area_list = QComboBox() self.update_value() # confirmation button button_area_operation = QPushButton() button_area_operation.setText('OK') button_area_operation.clicked.connect(lambda: self.area_operation(mode, *obj)) # position in the grid layout = QGridLayout() layout.addWidget(self.AS_list, 0, 0, 1, 2) layout.addWidget(self.area_list, 1, 0, 1, 2) layout.addWidget(button_area_operation, 2, 0, 1, 1) layout.addWidget(cancel_button, 2, 1, 1, 1) self.setLayout(layout) def update_value(self, index): self.area_list.clear() selected_AS = self.network.AS_factory(name=self.AS_list.currentText()) self.area_list.addItems(tuple(map(str, selected_AS.areas))) def area_operation(self, mode, *objects): selected_AS = self.network.AS_factory(name=self.AS_list.currentText()) selected_area = self.area_list.currentText() if mode == 'add': selected_AS.management.add_to_area(selected_area, *objects) else: selected_AS.management.remove_from_area(selected_area, *objects) self.close()
class PreviewForm(QDialog): def __init__(self, parent): super(PreviewForm, self).__init__(parent) self.encodingComboBox = QComboBox() encodingLabel = QLabel("&Encoding:") encodingLabel.setBuddy(self.encodingComboBox) self.textEdit = QTextEdit() self.textEdit.setLineWrapMode(QTextEdit.NoWrap) self.textEdit.setReadOnly(True) buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.encodingComboBox.activated.connect(self.updateTextEdit) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.reject) mainLayout = QGridLayout() mainLayout.addWidget(encodingLabel, 0, 0) mainLayout.addWidget(self.encodingComboBox, 0, 1) mainLayout.addWidget(self.textEdit, 1, 0, 1, 2) mainLayout.addWidget(buttonBox, 2, 0, 1, 2) self.setLayout(mainLayout) self.setWindowTitle("Choose Encoding") self.resize(400, 300) def setCodecList(self, codecs): self.encodingComboBox.clear() for codec in codecs: self.encodingComboBox.addItem(codec_name(codec), codec.mibEnum()) def setEncodedData(self, data): self.encodedData = data self.updateTextEdit() def decodedString(self): return self.decodedStr def updateTextEdit(self): mib = self.encodingComboBox.itemData(self.encodingComboBox.currentIndex()) codec = QTextCodec.codecForMib(mib) data = QTextStream(self.encodedData) data.setAutoDetectUnicode(False) data.setCodec(codec) self.decodedStr = data.readAll() self.textEdit.setPlainText(self.decodedStr)
def update_ComboBox(combobox: QComboBox, init_text: str, texts: List[str]): """ Updates a combo box content using a list of strings. :param combobox: the combobox to be updated :param init_text: the initial updated combo box element :param texts: the list of the texts used to fill the combo box :return: """ combobox.clear() if len(texts) == 0: return if init_text: combobox.addItem(init_text) combobox.addItems(texts)
class ChooseDefaultDict( ChoiceWidget ): def __init__( self, explainer ) : super().__init__( _TR( 'Preference item title line', 'Choose the dictionary for any new book' ), explainer ) self.dcb = QComboBox() self.layout().addWidget(self.dcb) self.dcb.activated[str].connect( self.choice_made ) self.reset() # load the combobox paths.notify_me( self.path_changed ) self.explanation = _TR( 'Preference item details', '''Choose the spell-check dictionary to be used when a book is opened for the first time. If the dictionary that you want is not in the list, you may need to choose the path to the dictionaries folder, above, and click Apply. You can change the dictionary for any book by right-clicking in its Edit panel.''' ) def choice_made( self, dic_tag ) : self.choice = dic_tag def path_changed( self, which ): # some path preference changed; if "dicts" reload the menu if which == "dicts" : self.reload_menu() def reload_menu( self ) : # refresh the combobox with the available tags. dict_dict = dictionaries.get_tag_list() self.dcb.clear() self.dcb.addItems( list( dict_dict.keys() ) ) self.dcb.setCurrentText ( self.choice ) def reset(self) : self.choice = dictionaries.get_default_tag() self.reload_menu() def apply(self): dictionaries.set_default_tag( self.choice )
class Actividad7(QWidget): def __init__(self): super().__init__() self.ventana() def ventana(self): #Etiquetas self.entrada = QLineEdit("Numero de datos", self) self.entrada.move(5,5) self.combo = QComboBox(self) self.combo.move(160,5) x= QLabel("X:", self) x.move(5,40) btn= QPushButton("Calcular", self) btn.move(190,35) y = QLabel("f(X):", self) y.move(5,70) self.entradax = QLineEdit(self) self.entradax.move(35,35) self.entraday = QLineEdit(self) self.entraday.move(35,65) btn2= QPushButton("Borrar Todo", self) btn2.move(190,65) self.valor = QLineEdit("Valor a estimar en",self) self.valor.move(5,95) self.ecuacion= QLabel("Y=",self) self.ecuacion.move(5,130) #Eventos self.entrada.textChanged[str].connect(self.combobox) self.combo.activated[str].connect(self.cambio) self.entradax.textChanged[str].connect(self.x) self.entraday.textChanged[str].connect(self.y) btn.clicked.connect(self.boton) self.entrada.selectionChanged.connect(self.sel1) self.entradax.selectionChanged.connect(self.sel2) self.entraday.selectionChanged.connect(self.sel3) self.valor.selectionChanged.connect(self.sel4) btn2.clicked.connect(self.borrar) #Ventana self.setGeometry(300, 300, 310, 150) self.setWindowTitle("Polinomios de interpolacion de Langrange") self.show() def combobox(self, text): self.combo.clear() self.entradax.clear() self.entraday.clear() if text =='': text='0' for c in range(int(text)): self.combo.addItem(str(c+1)) if len(xl)<= c: xl.append(0.0) yl.append(0.0) if text != "0": self.entradax.setText(str(xl[self.combo.currentIndex()])) self.entraday.setText(str(yl[self.combo.currentIndex()])) def cambio(self, text): self.entradax.setText(str(xl[int(text)-1])) self.entraday.setText(str(yl[int(text)-1])) def x(self, text): if text == "" or text == '-': text= "0" xl[self.combo.currentIndex()]= float(text) def y(self, text): if text == "" or text == '-': text= "0" yl[self.combo.currentIndex()]= float(text) def boton(self): if self.valor.text() == "": #Si el usuario deja en blanco el valor a conocer se conocera que es 0 self.valor.setText("0") datos= int(self.entrada.text()) #datos es el numero de datos ingresados por el usuario cx= float(self.valor.text())#cx sera el valor que el usuario quiera conocer suma=0 #Se declara la sumatoria for c in range(datos): #Este for funciona para movernos en I pro=1 #Se declara la variable producto for c2 in range(datos):#Este for funciona para movernos en J if c2!=c: #Si I es diferente a J se realizara la operacion producto pro*= (cx-xl[c2])/(xl[c]-xl[c2]) #Producto de pro*= yl[c] #Al final de pasar por cada J se multiplica por f(X) en el cual I esta actualmente suma+= pro #pro pasa a ser parte de la Sumatoria self.ecuacion.setText("Y= " + str(suma)) #Al final se imprime la Sumatoria self.ecuacion.adjustSize() def sel1(self): self.entrada.clear() def sel2(self): self.entradax.clear() def sel3(self): self.entraday.clear() def sel4(self): self.valor.clear() def borrar(self): for c in range(len(xl)): xl[c]= 0.0 yl[c]= 0.0 self.sel1() self.sel2() self.sel3() self.sel4()
class Example(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): mainBox = QVBoxLayout() fileBox = QHBoxLayout() menuBox = QHBoxLayout() resBox = QHBoxLayout() self.outEdit = QTextEdit() toolBox = QVBoxLayout() mainBox.addLayout(fileBox) mainBox.addLayout(menuBox) mainBox.addLayout(resBox) resBox.addWidget(self.outEdit) resBox.addLayout(toolBox) openFileBtn = QPushButton('1.选择文件') self.fileNameEdit = QLineEdit() parseFileBtn = QPushButton('2.开始解析') fileBox.addWidget(openFileBtn) fileBox.addWidget(self.fileNameEdit) fileBox.addWidget(parseFileBtn) label1 = QLabel('3.筛选:') levelLabel = QLabel('log级别') self.levelCombo = QComboBox() self.levelCombo.setMinimumWidth(100) modLabel = QLabel('log模块') self.modCombo = QComboBox() self.modCombo.setMinimumWidth(100) funLabel = QLabel('功能') self.funCombo = QComboBox() self.funCombo.setMinimumWidth(100) menuBox.addWidget(label1) menuBox.addWidget(levelLabel) menuBox.addWidget(self.levelCombo) menuBox.addSpacing(15) menuBox.addWidget(modLabel) menuBox.addWidget(self.modCombo) menuBox.addSpacing(15) menuBox.addWidget(funLabel) menuBox.addWidget(self.funCombo) menuBox.addStretch() toolBtn1 = QPushButton('复制') toolBtn2 = QPushButton('保存') toolBtn3 = QPushButton('') toolBtn4 = QPushButton('') self.statusLabel = QLabel('') toolBox.addWidget(toolBtn1) toolBox.addWidget(toolBtn2) # toolBox.addWidget(toolBtn3) # toolBox.addWidget(toolBtn4) toolBox.addStretch() toolBox.addWidget(self.statusLabel) self.setLayout(mainBox) # 按钮连接到槽 openFileBtn.clicked.connect(self.open_file) parseFileBtn.clicked.connect(self.parse_file) self.levelCombo.activated.connect(self.show_lines) self.modCombo.activated.connect(self.show_lines) self.funCombo.activated.connect(self.show_lines) toolBtn1.clicked.connect(self.copy_result) toolBtn2.clicked.connect(self.save_result) self.setGeometry(200, 300, 700, 500) self.setWindowTitle('log解析工具') self.show() def open_file(self): file = QFileDialog.getOpenFileName(self, '选择log文件', '') filename = file[0] self.fileNameEdit.setText(filename) def parse_file(self): self.please_wait() filename = self.fileNameEdit.text() start = time.time() # 计时开始 self.L = plo.Parser(filename) for line_no in range(0,self.L.lines): # 遍历所有log try: self.L.parse_log_level(line_no) # log级别 self.L.parse_log_mod(line_no) # log模块 self.L.parse_log_all_func(line_no) # 其他功能 except Exception as e: print(e) if line_no%1000 == 0 or line_no == self.L.lines - 1: # 每100行和最后一行执行一次刷新,可大大加快解析速度! self.outEdit.setText('解析中,请等待...('+str(line_no)+'/'+str(self.L.lines)+')') QApplication.processEvents() end = time.time() # 计时结束 # log级别 log_levels = self.L.get_levels() self.levelCombo.clear() self.levelCombo.addItem('全部') self.levelCombo.addItems(log_levels.keys()) # log模块 log_mods = self.L.get_mods() self.modCombo.clear() self.modCombo.addItem('全部') self.modCombo.addItems(log_mods.keys()) # log功能 log_funcs = self.L.get_funcs() self.funCombo.clear() self.funCombo.addItem('全部') self.funCombo.addItems(log_funcs.keys()) # 输出结果 print_log = '' print_log += '解析时间:%.2fs\n' % (end-start) print_log += ('各级别log统计结果:\n') for level_name in log_levels.keys(): print_log += (level_name + ': ' + str(len(log_levels.get(level_name, []))) + '\n') print_log += '\n' print_log += ('各模块log统计结果:\n') for mod_name in log_mods.keys(): print_log += (mod_name + ': ' + str(len(log_mods.get(mod_name, []))) + '\n') print_log += '\n' print_log += ('各功能统计结果:\n') for func_name in log_funcs.keys(): print_log += (func_name + ': ' + str(len(log_funcs.get(func_name, []))) + '\n') self.parse_result = print_log # 保存解析结果 self.outEdit.setText(print_log) def show_lines(self): ''' 筛选框操作后,显示结果 ''' selLevel = self.levelCombo.currentText() selMod = self.modCombo.currentText() selFun = self.funCombo.currentText() if(selLevel == '全部' and selMod == '全部' and selFun == '全部'): # 不要显示全部log self.outEdit.setText(self.parse_result) return self.please_wait() if (selLevel != '全部'): resLevel = self.L.get_log_lines(selLevel) if (selMod != '全部'): resMod = self.L.get_log_lines(selMod) if (selFun != '全部'): resFun = self.L.get_log_lines(selFun) # 逐行显示 self.outEdit.clear() lines_num = 0 for i in range(0, self.L.lines): if (selLevel != '全部' and i not in resLevel): # 不满足等级筛选条件 continue if (selMod != '全部' and i not in resMod): # 不满足模块筛选条件 continue if (selFun != '全部' and i not in resFun): # 不满足功能筛选条件 continue # i满足所有筛选条件 self.outEdit.moveCursor(QTextCursor.End) # 使用insertPlainText需保证cursor在末尾 self.outEdit.insertPlainText(self.L.log[i]) lines_num = lines_num + 1 self.show_status('当前' + str(lines_num) + '条') QApplication.processEvents() self.show_status('共' + str(lines_num) + '条') def please_wait(self): self.outEdit.setText('解析中,请等待...') QApplication.processEvents() self.show_status('') def show_status(self, status): self.statusLabel.setText(status) QApplication.processEvents() def copy_result(self): clipboard = QApplication.clipboard() clipboard.setText(self.outEdit.toPlainText()) self.show_status('复制成功') def save_result(self): file = QFileDialog.getSaveFileName(self, '保存log文件', '') filename = file[0] try: with open(filename, 'w+') as f: result = self.outEdit.toPlainText() f.write(result) self.show_status('保存成功') except Exception as e: print(e) self.show_status('保存失败')
class preferences(QWidget): def __init__(self, scale_factor): try: super().__init__() except TypeError: super(self.__class__, self).__init__() # port to python2 self.scale_factor = scale_factor self.config = ConfigParser.RawConfigParser() self.configurations = config_manager() self.configf = self.configurations.configf if os.path.exists(self.configf) is False: print('Config file does not exist!') self.configurations.config_defaults() self.read_defaults() self.initUI() def initUI(self): self.backend() self.codec() self.bitrate() self.samplerates() self.iconcolors() self.notifications() self.searchatlaunch() if platform == 'Linux': self.alsadevice() self.buttons() self.window() def backend(self): """ Backend """ backends_supported = ['node', 'ffmpeg', 'avconv', 'parec', 'gstreamer'] self.backends = [] if platform == 'Darwin': for item in backends_supported: if (is_installed(item, PATH, debug) is True and item != 'avconv' and item != 'gstreamer'): self.backends.append(item) else: for item in backends_supported: if (is_installed(item, PATH, debug) is True and item != 'node' and item != 'gstreamer'): self.backends.append(item) # hardcoded gst-launch-1.0 for gstreamer elif (is_installed('gst-launch-1.0', PATH, debug) is True and item == 'gstreamer'): self.backends.append(item) try: backend_index = self.backends.index(self.backend_conf) except ValueError: # No backend found backend_index = None pass self.backend = QLabel('Select Backend', self) self.backend.move(20 * self.scale_factor, 24 * self.scale_factor) self.qcbackend = QComboBox(self) self.qcbackend.move(180 * self.scale_factor, 20 * self.scale_factor) self.qcbackend.setMinimumContentsLength(7) for item in self.backends: self.qcbackend.addItem(item) if backend_index: self.qcbackend.setCurrentIndex(backend_index) self.qcbackend.activated[str].connect(self.onActivatedbk) def codec(self): """ Codec """ self.codec = QLabel('Audio Coding Format', self) self.codec.move(20 * self.scale_factor, 56 * self.scale_factor) self.qccodec = QComboBox(self) self.qccodec.clear() if self.backend_conf == 'node': self.codecs = ['mp3'] else: self.codecs = [ 'mp3', 'ogg', 'aac', 'wav', 'flac' ] if debug is True: print(self.codecs) codecindex = self.codecs.index(self.codecconf) self.qccodec.move(180 * self.scale_factor, 54 * self.scale_factor) self.qccodec.setMinimumContentsLength(7) for item in self.codecs: self.qccodec.addItem(item) self.qccodec.setCurrentIndex(codecindex) self.qccodec.activated[str].connect(self.onActivatedcc) def bitrate(self): """ Bitrate """ self.bitrate = QLabel('Select Bitrate (kbit/s)', self) self.bitrate.move(20 * self.scale_factor, 88 * self.scale_factor) self.qcbitrate = QComboBox(self) self.qcbitrate.clear() self.qcbitrate.move(180 * self.scale_factor, 88 * self.scale_factor) self.qcbitrate.setMinimumContentsLength(7) if self.codecconf == 'wav': self.bitrates = ['None'] bitrateindex = 0 else: self.bitrates = [ '128', '160', '192', '224', '256', '320', '500' ] bitrateindex = self.bitrates.index(self.bitrateconf) for item in self.bitrates: self.qcbitrate.addItem(item) self.qcbitrate.setCurrentIndex(bitrateindex) self.qcbitrate.activated[str].connect(self.onActivatedbt) def samplerates(self): """ Sample rate """ self.samplerates = [ '192000', '176400', '96000', '88200', '48000', '44100', '32000', '22050' ] sampleratesindex = self.samplerates.index(self.samplerateconf) self.samplerate = QLabel('Sample Rate (Hz)', self) self.samplerate.move(20 * self.scale_factor, 120 * self.scale_factor) self.qcsamplerate = QComboBox(self) self.qcsamplerate.move(180 * self.scale_factor, 120 * self.scale_factor) self.qcsamplerate.setMinimumContentsLength(7) for item in self.samplerates: self.qcsamplerate.addItem(item) self.qcsamplerate.setCurrentIndex(sampleratesindex) self.qcsamplerate.activated[str].connect(self.onActivatedsr) def iconcolors(self): """ Icon colors """ self.colors_list = [ 'black', 'blue', 'white' ] colorsindex = self.colors_list.index(self.searchcolorsconf) self.colors = QLabel('Icon Colors', self) self.colors.move(20 * self.scale_factor, 152 * self.scale_factor) self.qccolors = QComboBox(self) self.qccolors.move(180 * self.scale_factor, 152 * self.scale_factor) self.qccolors.setMinimumContentsLength(7) for item in self.colors_list: self.qccolors.addItem(item) self.qccolors.setCurrentIndex(colorsindex) self.qccolors.activated[str].connect(self.onActivatedcolors) def notifications(self): """ Notifications """ self.notifications_list = [ 'enabled', 'disabled' ] notindex = self.notifications_list.index(self.notifconf) self.notifications = QLabel('Notifications', self) self.notifications.move(20 * self.scale_factor, 184 * self.scale_factor) self.qcnotifications = QComboBox(self) self.qcnotifications.move(180 * self.scale_factor, 184 * self.scale_factor) self.qcnotifications.setMinimumContentsLength(7) for item in self.notifications_list: self.qcnotifications.addItem(item) self.qcnotifications.setCurrentIndex(notindex) self.qcnotifications.activated[str].connect(self.onActivatednotify) def searchatlaunch(self): """ Search at launch """ self.atlaunch_list = [ 'enabled', 'disabled' ] launchindex = self.atlaunch_list.index(self.satlaunchconf) self.atlaunch = QLabel('Search At Launch', self) self.atlaunch.move(20 * self.scale_factor, 214 * self.scale_factor) self.qcatlaunch = QComboBox(self) self.qcatlaunch.move(180 * self.scale_factor, 214 * self.scale_factor) self.qcatlaunch.setMinimumContentsLength(7) for item in self.atlaunch_list: self.qcatlaunch.addItem(item) self.qcatlaunch.setCurrentIndex(launchindex) self.qcatlaunch.activated[str].connect(self.onActivatedatlaunch) def alsadevice(self): """ Set the ALSA Device """ self.alsadevice = QLabel('ALSA Device', self) self.alsadevice.move(20 * self.scale_factor, 244 * self.scale_factor) self.qle = QLineEdit(self) self.qle.move(179 * self.scale_factor, 244 * self.scale_factor) self.qle.setFixedWidth(84*self.scale_factor) self.read_defaults() if self.alsadeviceconf is not None: self.qle.setText(self.alsadeviceconf) self.qle.textChanged[str].connect(self.onActivatedalsadevice) def buttons(self): """ Buttons """ resetbtn = QPushButton("Reset Settings", self) resetbtn.move(10 * self.scale_factor, 274 * self.scale_factor) resetbtn.clicked.connect(self.reset_configuration) faqbtn = QPushButton("FAQ", self) faqbtn.move(138 * self.scale_factor, 274 * self.scale_factor) faqbtn.clicked.connect(lambda: webbrowser.open('https://github.com/muammar/mkchromecast/wiki/FAQ')) donbtn = QPushButton("Donate :)", self) donbtn.move(204 * self.scale_factor, 274 * self.scale_factor) donbtn.clicked.connect(lambda: webbrowser.open('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=RZLF7TDCAXT9Q&lc=US&item_name=mkchromecast¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted')) def window(self): """ Geometry and window's title """ self.setGeometry(300 * self.scale_factor, 300 * self.scale_factor, 300 * self.scale_factor, 200 * self.scale_factor) if platform == 'Darwin': # This is to fix the size of the window self.setFixedSize(310 * self.scale_factor, 320 * self.scale_factor) else: # This is to fix the size of the window self.setFixedSize(282 * self.scale_factor, 320 * self.scale_factor) self.setWindowFlags(QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowMinimizeButtonHint | QtCore.Qt.WindowStaysOnTopHint) self.setWindowTitle('Mkchromecast Preferences') """ Methods """ def reset_configuration(self): self.configurations.write_defaults() self.reset_indexes() def reset_indexes(self): self.read_defaults() """ Indexes of QCombo boxes are reset """ backend_index = self.backends.index(self.backend_conf) codecindex = self.codecs.index(self.codecconf) self.bitrates = [ '128', '160', '192', '224', '256', '320', '500' ] bitrateindex = self.bitrates.index(self.bitrateconf) self.qcbitrate.clear() for item in self.bitrates: self.qcbitrate.addItem(item) sampleratesindex = self.samplerates.index(self.samplerateconf) colorsindex = self.colors_list.index(self.searchcolorsconf) notindex = self.notifications_list.index(self.notifconf) launchindex = self.atlaunch_list.index(self.satlaunchconf) self.qcbackend.setCurrentIndex(backend_index) self.qccodec.setCurrentIndex(codecindex) self.qcbitrate.setCurrentIndex(bitrateindex) self.qcsamplerate.setCurrentIndex(sampleratesindex) self.qccolors.setCurrentIndex(colorsindex) self.qcnotifications.setCurrentIndex(notindex) self.qcatlaunch.setCurrentIndex(launchindex) def onActivatedbk(self, text): self.config.read(self.configf) self.config.set('settings', 'backend', text) self.write_config() self.read_defaults() self.qccodec.clear() if self.backend_conf == 'node': codecs = ['mp3'] self.config.read(self.configf) self.config.set('settings', 'codec', 'mp3') self.write_config() else: codecs = [ 'mp3', 'ogg', 'aac', 'wav', 'flac' ] if debug is True: print('Codecs: %s.' % codecs) codecindex = codecs.index(self.codecconf) self.qccodec.move(180 * self.scale_factor, 54 * self.scale_factor) self.qccodec.setMinimumContentsLength(7) for item in codecs: self.qccodec.addItem(item) self.qccodec.setCurrentIndex(codecindex) self.qccodec.activated[str].connect(self.onActivatedcc) def onActivatedcc(self, text): self.config.read(self.configf) self.config.set('settings', 'codec', text) self.write_config() self.read_defaults() self.qcbitrate.clear() if self.codecconf == 'wav': bitrates = ['None'] bitrateindex = 0 else: self.configurations.chk_config() self.read_defaults() bitrates = [ '128', '160', '192', '224', '256', '320', '500' ] bitrateindex = bitrates.index(self.bitrateconf) self.qcbitrate.move(180 * self.scale_factor, 88 * self.scale_factor) for item in bitrates: self.qcbitrate.addItem(item) self.qcbitrate.setCurrentIndex(bitrateindex) self.qcbitrate.activated[str].connect(self.onActivatedbt) def onActivatedbt(self, text): self.config.read(self.configf) self.config.set('settings', 'bitrate', text) self.write_config() self.read_defaults() def onActivatedsr(self, text): self.config.read(self.configf) self.config.set('settings', 'samplerate', text) self.write_config() self.read_defaults() def onActivatednotify(self, text): self.config.read(self.configf) self.config.set('settings', 'notifications', text) self.write_config() self.read_defaults() def onActivatedcolors(self, text): self.config.read(self.configf) self.config.set('settings', 'colors', text) self.write_config() self.read_defaults() def onActivatedatlaunch(self, text): self.config.read(self.configf) self.config.set('settings', 'searchatlaunch', text) self.write_config() self.read_defaults() def onActivatedalsadevice(self, text): self.config.read(self.configf) if not text: self.config.set('settings', 'alsadevice', None) else: self.config.set('settings', 'alsadevice', text) self.write_config() self.read_defaults() def read_defaults(self): self.backend_conf = ConfigSectionMap('settings')['backend'] self.codecconf = ConfigSectionMap('settings')['codec'] if self.backend_conf == 'node' and self.codecconf != 'mp3': self.config.read(self.configf) self.config.set('settings', 'codec', 'mp3') self.write_config() self.codecconf = ConfigSectionMap('settings')['codec'] self.bitrateconf = ConfigSectionMap('settings')['bitrate'] self.samplerateconf = ConfigSectionMap('settings')['samplerate'] self.notifconf = ConfigSectionMap('settings')['notifications'] self.searchcolorsconf = ConfigSectionMap('settings')['colors'] self.satlaunchconf = ConfigSectionMap('settings')['searchatlaunch'] self.alsadeviceconf = ConfigSectionMap('settings')['alsadevice'] if debug is True: print(self.backend_conf, self.codecconf, self.bitrateconf, self.samplerateconf, self.notifconf, self.satlaunchconf, self.searchcolorsconf, self.alsadeviceconf) def write_config(self): """This method writes to configfile""" with open(self.configf, 'w') as configfile: self.config.write(configfile)
class MazeWalkerWidget(cw.CustomWidget): def __init__(self, parent=None): """ Constructor """ idp_hooks.register_rename_callback(self._rename_hook) cw.CustomWidget.__init__(self) self.name = "Execution Tree" self.parent = parent self.icon = QIcon(Config().icons_path + 'radar-icon.png') # Functionality associated with this widget self.ma = parent.maze_analysis self._createGui() def _createGui(self): self._createLayout() self._createToolBar('Maze') self._createToolBarActions() self._createExecutionTree() # Output Layout self.main_splitter.addWidget(self.ExecutionTreeWG) def _createLayout(self): """ This creates the basic layout: Buttons & Outputs """ # Layouts (This is a common disposition) main_layout = QtWidgets.QHBoxLayout() # Output Layout Inner (QSplitter) self.main_splitter = QSplitter(QtCore.Qt.Horizontal) # Nested layouts main_layout.addWidget(self.main_splitter) self.central_widget.setLayout(main_layout) def _createExecutionTree(self): layout = QtWidgets.QVBoxLayout() self.ExecutionTreeWG = QtWidgets.QWidget() self.ExecutionTreeWG.setLayout(layout) self.filter_qbox = QComboBox() self.filter_qbox.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.filter_qbox.currentIndexChanged.connect(self._tag_filter) self.execution_tree = Maze() maze = self._load_maze_from_idb() if maze is not None: self.execution_tree.init_maze(json.loads(maze)[0], True) for tag in self.execution_tree.tags: self.filter_qbox.addItem(tag) layout.addWidget(self.filter_qbox) layout.addWidget(self.execution_tree) def _createToolBarActions(self): self.addMazeLog = QtWidgets.QAction(QIcon(Config().icons_path + 'add-icon.png'), '&Open Maze Log', self, triggered=self._addMazeLog) self.reloadMazeLog = QtWidgets.QAction(QIcon(Config().icons_path + 'arrow-rotate.png'), '&Reload Maze Log', self, triggered=self._ReloadMazeLog) self.toolbar.addAction(self.addMazeLog) self.toolbar.addAction(self.reloadMazeLog) def _store_maze_in_idb(self, maze): name = "$ com.mazewalker" store = idaapi.netnode(name, 0, True) store.setblob(maze, 0, "N") def _load_maze_from_idb(self): name = "$ com.mazewalker" store = idaapi.netnode(name, 0, True) return store.getblob(0, 'N') def _addMazeLog(self): maze_file = idc.AskFile(0, '*.json', 'Select the Maze...') if maze_file is not None: with open(maze_file, 'r') as fd: maze = fd.read() self._store_maze_in_idb(maze) self.filter_qbox.clear() self.execution_tree.init_maze(json.loads(maze)[0]) for tag in self.execution_tree.tags: self.filter_qbox.addItem(tag) def _ReloadMazeLog(self): self.execution_tree.reload_tree() def _tag_filter(self, index): self.execution_tree.fileter_by_tag( str(self.filter_qbox.itemText(index))) def _rename_execution_tree_node(self, root, new_name, old_name): if root.text(0) == old_name: root.setText(0, new_name) count = root.childCount() for i in range(count): self._rename_execution_tree_node(root.child(i), new_name, old_name) def _rename_hook(self, ea, new_name): if len(new_name) > 0: fname = idc.GetFunctionName(ea) if len(fname) == 0: fname = "0x%x" % ea root = self.execution_tree.invisibleRootItem() self._rename_execution_tree_node(root, new_name, fname) return 1
class Set(QDialog): def __init__(self, father): super().__init__(father, Qt.WindowCloseButtonHint) self.father = father self.setObjectName('set') self.setWindowTitle('设置') self.setWindowIcon(QIcon('image/set.ico')) self.move_pos = [ self.father.desktop_resolving[0] // 2 - 300, self.father.desktop_resolving[1] // 2 - 200 ] self.size_ = [600, 400] self.setGeometry(*self.move_pos, *self.size_) combobox_frame = QFrame(self) api_label = QLabel('接口', combobox_frame) api_label.setProperty('cate', 'combo_label') api_label.setAlignment(Qt.AlignCenter) self.api_choose = QComboBox(self) self.api_choose.setToolTip('选择寻找壁纸的网站') self.api_choose.currentTextChanged.connect( lambda: self.set_change('api')) api_list_view = QListView() api_list_view.entered.connect(self.show_name) self.api_choose.setView(api_list_view) category_label = QLabel('分类', combobox_frame) category_label.setProperty('cate', 'combo_label') category_label.setAlignment(Qt.AlignCenter) self.category_choose = QComboBox(self) self.category_choose.setToolTip('选择壁纸类型') self.category_choose.currentTextChanged.connect( lambda: self.set_change('cate')) category_list_view = QListView() category_list_view.entered.connect(self.show_name) self.category_choose.setView(category_list_view) grid_1 = QGridLayout() grid_1.setContentsMargins(0, 30, 0, 30) grid_1.setSpacing(0) grid_1.addWidget(api_label, 0, 0, 1, 1) grid_1.addWidget(category_label, 0, 1, 1, 1) grid_1.addWidget(self.api_choose, 1, 0, 1, 1) grid_1.addWidget(self.category_choose, 1, 1, 1, 1) combobox_frame.setLayout(grid_1) remain_frame = QFrame(self) switch_label = QLabel('自动切换', remain_frame) switch_label.setProperty('cate', 'indicate_label') self.switch_list = [ "从不", "30秒", "1分钟", "5分钟", "10分钟", "30分钟", "1小时", "2小时", "5小时", "10小时" ] self.true_switch_list = [ 0, 30, 60, 300, 600, 1800, 3600, 7200, 18000, 36000 ] self.switch_slider = QSlider(Qt.Horizontal, self) self.switch_slider.setToolTip('自动切换壁纸') self.switch_slider.setMaximum(9) self.switch_slider.setValue( self.true_switch_list.index(self.father.config['switch'])) self.switch_slider.valueChanged.connect( lambda: self.set_change('switch')) self.switch_show = QLabel( self.switch_list[self.true_switch_list.index( self.father.config['switch'])], remain_frame) size_label = QLabel('大小限制', remain_frame) size_label.setProperty('cate', 'indicate_label') self.size_list = ["不限制", "500K", "1M", "2M", "5M", "10M", "20M"] self.true_size_list = [0, 500, 1000, 2000, 5000, 10000, 20000] self.size_slider = QSlider(Qt.Horizontal, self) self.size_slider.setToolTip('限制图片大小') self.size_slider.setMaximum(6) self.size_slider.setValue( self.true_size_list.index(self.father.config['length'])) self.size_slider.valueChanged.connect(lambda: self.set_change('size')) self.size_show = QLabel( self.size_list[self.true_size_list.index( self.father.config['length'])], remain_frame) self.show_windmill = QCheckBox('桌面显示风车', self) self.show_windmill.setToolTip('桌面显示切换风车') self.show_windmill.setCheckState(self.father.config['show_windmill']) self.show_windmill.stateChanged.connect( lambda: self.set_change('show_windmill')) random_switch_frame = QFrame(self) random_switch_label = QLabel('随机切换', random_switch_frame) random_switch_label.setAlignment(Qt.AlignCenter) random_switch_label.setProperty('cate', 'head_label') self.random_switch = PartFrame(self, self.father, 'random_switch', random_switch_frame) self.random_switch.setToolTip('随机切换壁纸') self.random_switch.set_part([ [ '从不', '顺序切换', 'border-right: 1px solid;border-top-left-radius: 10px;border-top-right-radius: 0;border-bottom-right-radius: 0;border-bottom-left-radius: 10px;' ], [ '一类', '每一次切换都是随机分类(仅分类选项为随机时可用)', 'border-right: 1px solid;border-radius: 0;' ], [ '一页', '每一页的壁纸顺序都被打乱', 'border: 0px solid;border-top-left-radius: 0;border-top-right-radius: 10px;border-bottom-right-radius: 10px;border-bottom-left-radius: 0;' ] ]) random_switch_frame.setFixedSize(122, 57) self.random_switch.move(0, 25) play_what_frame = QFrame(self) play_what_label = QLabel('选壁纸源', play_what_frame) play_what_label.setAlignment(Qt.AlignCenter) play_what_label.setProperty('cate', 'head_label') self.play_what = PartFrame(self, self.father, 'play_what', play_what_frame) self.play_what.setToolTip('选择壁纸源') self.play_what.set_part([ [ '网络', '网络壁纸', 'border-right: 1px solid;border-top-left-radius: 10px;border-top-right-radius: 0;border-bottom-right-radius: 0;border-bottom-left-radius: 10px;' ], ['收藏', '已收藏的壁纸', 'border-right: 1px solid;border-radius: 0;'], [ '本地', '本地壁纸(右键选择文件夹)', 'border-left: 0px solid;border-top-left-radius: 0;border-top-right-radius: 10px;border-bottom-right-radius: 10px;border-bottom-left-radius: 0;' ] ]) play_what_frame.setFixedSize(122, 57) self.play_what.move(0, 25) self.auto_start = QCheckBox('开机自动启动', self) self.auto_start.setToolTip('设置软件开机自启') self.auto_start.setCheckState(self.father.config['auto_start']) self.auto_start.stateChanged.connect( lambda: self.set_change('auto_start')) grid_2 = QGridLayout() grid_2.addWidget(switch_label, 0, 0, 1, 1) grid_2.addWidget(size_label, 1, 0, 1, 1) grid_2.addWidget(self.switch_slider, 0, 1, 1, 2) grid_2.addWidget(self.size_slider, 1, 1, 1, 2) grid_2.addWidget(self.switch_show, 0, 3, 1, 1) grid_2.addWidget(self.size_show, 1, 3, 1, 1) grid_2.addWidget(self.show_windmill, 2, 0, 1, 2) grid_2.addWidget(self.auto_start, 2, 2, 1, 2) grid_2.addWidget(random_switch_frame, 3, 0, 1, 2) grid_2.addWidget(play_what_frame, 3, 2, 1, 2) remain_frame.setLayout(grid_2) right_frame = QFrame(self) self.logo_label = AnimalLabel(self, self.father) self.logo_label.setToolTip('随机选项') self.logo_label.setObjectName('logo') resolution_label = QLabel('分辨率', right_frame) resolution_label.setStyleSheet('QLabel{max-width: 1000px;}') resolution_label.setAlignment(Qt.AlignCenter) resolution_label.setToolTip('依据这个最小分辨率筛选') self.width_edit = QLineEdit(str(self.father.config['resolving'][0]), right_frame) self.width_edit.setMaxLength(5) self.width_edit.setAlignment(Qt.AlignCenter) self.width_edit.editingFinished.connect(self.submit_resolution) self.height_edit = QLineEdit(str(self.father.config['resolving'][1]), right_frame) self.height_edit.setMaxLength(5) self.height_edit.setAlignment(Qt.AlignCenter) self.height_edit.editingFinished.connect(self.submit_resolution) resolution_mid = QLabel('x', right_frame) resolution_mid.setStyleSheet('QLabel{max-width: 1000px;}') resolution_mid.setAlignment(Qt.AlignCenter) clear_button = QPushButton('清空黑名单', right_frame) clear_button.setToolTip('清空不喜欢的图片') clear_button.clicked.connect(self.clear_list) self.update_button = QPushButton('更新接口', right_frame) self.update_button.setToolTip('更新可用网站') self.update_button.clicked.connect(self.check_update) # 状态文字 self.status_label = QLabel('', self) self.status_timer = 0 self.status_label.setFont(QFont('微软雅黑', 14, QFont.Bold)) self.status_label.setStyleSheet( 'QLabel{max-width: 200px;min-width: 200px;color: #A55;}') # GitHub git_btn = GitLabel(self) grid_3 = QGridLayout() grid_3.setRowStretch(3, 2) grid_3.addWidget(self.logo_label, 0, 2, 1, 6) grid_3.addWidget(resolution_label, 1, 0, 2, 2) grid_3.addWidget(self.width_edit, 1, 2, 2, 2) grid_3.addWidget(resolution_mid, 1, 4, 2, 1) grid_3.addWidget(self.height_edit, 1, 5, 2, 2) grid_3.addWidget(clear_button, 3, 2, 2, 3) grid_3.addWidget(self.update_button, 3, 5, 2, 3) grid_3.addWidget(self.status_label, 5, 0, 1, 6) grid_3.addWidget(git_btn, 5, 6, 1, 1) grid_3.setAlignment(Qt.AlignCenter) right_frame.setLayout(grid_3) mid_label_0 = QLabel('', self) mid_label_0.setStyleSheet( 'QLabel{background: qlineargradient(x1: 0, y1: 0,x2: 1,y2: 0, stop: 0 #FF0000, stop: 1 #0000FF);;max-height: 3px;min-height: 3px;max-width: 10000px;}' ) mid_label_1 = QLabel('', self) mid_label_1.setStyleSheet( 'QLabel{background: qlineargradient(x1: 0, y1: 0,x2: 0,y2: 1, stop: 0 #F0F, stop: 1 #FAA);;max-width: 3px;min-width: 3px;max-height: 10000px;}' ) main_grid = QGridLayout() main_grid.setColumnStretch(0, 1) main_grid.setColumnStretch(1, 1) main_grid.setColumnStretch(2, 1) main_grid.setContentsMargins(0, 0, 0, 0) main_grid.setSpacing(0) main_grid.addWidget(combobox_frame, 0, 0, 1, 1) main_grid.addWidget(mid_label_0, 1, 0, 1, 1) main_grid.addWidget(remain_frame, 2, 0, 2, 1) main_grid.addWidget(mid_label_1, 0, 1, 4, 1) main_grid.addWidget(right_frame, 0, 2, 4, 1) self.setLayout(main_grid) self.timer = QTimer() self.interval = 13 self.timer.setInterval(self.interval) self.timer.start() self.timer.timeout.connect(self.rotate) self.remain_cate_random = False self.load_api() def load_api(self): for api in self.father.all_api: pix = QPixmap() if api == '随机': pix.loadFromData( QByteArray.fromBase64( b'iVBORw0KGgoAAAANSUhEUgAAADEAAAAxCAYAAABznEEcAAAJk0lEQVRoge2ZC4yU1RXHf+ebbx7s8lwW1FUR8AUoWqIg1keDUWyqaKk1TYltpUTbao1N2rS2xlhNrCFWrcRaaa2Vttr6SCvah1DEBwq1UKSgBhTBCvJeYd87j+87zb33m5lvl2F3ZwU1qWczOzPf3O/e//+cc8/53xk+sY+JCbeqQXIScDNwDpAqQdMYSKlwrb8m/biv6z1twEPAj4HQByYAi4GGLsO6gz0Y4LvP1R8yzuqAm4AxwJWGxF29EjhUplUQqTz2CmCRB5z5kRCIr9fXNSuP+6whUehl0Idj/SdS8D4WBD6geR8rAhrlRb6627w+jKkORDU53t0COGtMwNQxAeTc+wOuEzPvA0VBewDeHzIFOHd0wLNf7WDuRVkOH6SQNZ2g59vK6XSoUqqvc0fjOvNCwhOumZzn2dntXHt2jlQCFxntNj4yr4sni/mYjR656Fq4/2JVk9bYcyGau7hOvjxnceqWnDCiVvnJ+VkWXtHG9HEFl14V9otc/kS+8VuTC3XGA805oSMv7GoTtjS5x6a9wqZ9QltrRMa0x0Q/CETO8GvgmCHKuHo4ZqgyeqhSX6M2dTRUGgaHjBoakg+UUM0tStoPCVVZuN7nnuUZXt+WcBh8O/sC/+ghyrRRAe2BR8IDTzz7mSAWc0dB2NIsrH5PWLLJY9FGYVtjlIjJPoDPu8XOHqvMHK9MG6OMGaYMSSsShccALRjAquQCJRsIIm4CsSnmoRIyc3yB88a28ttXU9z3Spo9zR6kwS+EkFOho+CAe2KIiO3wHmKJHT8MxtUpsyYG7GoXHn9NmL/KY93WHiKTdzLhslOU66YqZ49SEuJA50LoLBjwYoFbOqr2vSolchL9F1FUhdYc+KJcO7WTSydkuWdFhofXZPDNQMNa7GApyRP7Sox3xC5aJDWiBq6dArMnhdy3UrjteWGfSbV0jEAnnNgAP70w5OIT3KVCNI/avHfADVjPRlwtCLGEHB4D2qyp4qJRxJkQF+H32z32dri65KcSYrOiJomNAtY70SaLRJfESOVDN/mAJHzv08pFJ8C3/yIs3RARycHMU2H+JcqIGufpoFQEnFdRE3FHw0uojbxaQtARiI2SJShF0ga8MDAV8t8mj/tfyfDg6jS5rFvTX79H+NMGn4wP6QQMzQjDB8CQDAxLl+NigASRd8zDRMjY+Hr46xXKVU8Jv18BV58L82dEuW4BSCk9jCU9KZWqlhzsaYH3WoS2vLCnDY6rD5lQb/ZFcWUYlIKWPPz632l+tjzF1kbP7cdUcczN2khAnc1rgWQCBqehboCrIJMOU84bC1OOhAGuGlgyxJSxZyMEC9cLM8ep3UdhrAQ7T7oLm/fBoo2wdLOwbjfsbBX2dkSD2uE75wfcOT3P3qza/pDwQp7Z6HH7CylWvRtVpfgeFBb4NoZeuY7nA2hsg8YW4a0d8PRa4dYkTBwJs05Rrp6s1GXKYS563Hj4ixPcrFqC7vLYTG8ifvuLsHCD0NQSeSARrV0MbxL8hLs0JA3/2Snc+XKaP6zzXY9IUdH8GCO6vI6rKoV1O+CHW4UHVwtzp5ty6YZpdGP33ueKhLs6fxXcsFjY1xIBScfW6WY1vtKah7kvJZn3zwTNbeLu6aGcC7doY3Tc69mKKKOOeeN5cMs0tykrTwymfH93McxbRqU02N8COHN0SHNWeH2LOOC9NVabTtVa0hG67e/YpnTHBfufHIt8b1gC85YAA/t4DE3Ais1RCqR7G1y2vkvxOIgcHDESLjy251suOBYOG1Hd+SBVBH8gGV7BqjtPBK6RfeY4eHGOcv7Yrroubua9Ibnk68qEI9x9vYrGHHzjtIB5MwoMzej+yrVfJDQSfTkH4sghcNclsOhrynF1TutUuiX++uQRjvCcqVEV6YycUQmcQm0arptcYNlVOeacUSAp0fqVLMoO34IMqOxSH4bXwmkNyhfGYQXcyFrKXd0MVy3JlbBrtbafmdemeT5wqfLNycpDrwrPvC283Rj7iqKYqjnoyLt5jEj8+cU5vnxKgVueS7JsU8KNq7CL/REDnaoclHar1w2AhkFw1GBl0uFwwnDl6MFSWslUHJHyuhJ1hpe2CD/4G9w9Q5nS0LXZOdmhnN4ApzcoTbmQtduF1TthaxO89b7r3obUuHq1jbOzoFYVTDky5M+zOnn0tQR3v5xi4w7PldxYDsn1i/KNd0/P13UEnlPXCSERg2iCFIRdZGEkxsSJMeCJN2DOk0JzExxRD499yajWOIFyVIrdu9jBzRXj+UKoRlLZc4SR4+bPpKt1hig1yZDtrfDAqiTzV6bL/UNY4BXTwOl4aMsbnaK0FaC9YK7vn/tGVhgQzVn4/j+Ey/8oNJtcr4XtzXDBQ8IvVjmGFmyMgPlvotkRuPnNOuYYYBRuruA+c6SLFJUwhKZOIwCVG87N8vRXWrnsUzkyCScbPI0OJe4UFfNYlAJxeZHylKSntOVgwRrhjF8JdzxP/JRl+0hnANc8CRf+Tli+xZFOGuKeloCVNqC61AvVRU1jn5dHaYl8U1Y4sT7gNzNbuWlau8Xkd68nxTRJWMAmtVwry4fKul0eT22AR9Z6vLE9ystKTSnqzovXw3ObPT4/Xpk9STlrFAxOldcz3rd7LHJWMe2KwFXLGq3YUAelQna0Cr9cVcMja9PkQsE3gitpzwduI5mbOgpqW/+uVuHNRmH1dmHle8LKbUK+IwJ5ADHWxdKQV3h8jTsNjq2Hc0aFTD3KSPiQ0cOMYnZqdYCvNiNM+przRDwi5qkmqTbCj72W4q7lGd7eGclxD+T4e4PGk0dqnQllS9YdAU3+7W53z2E2coMXpUx/v47XqJQXO3ESRg6CYRllcAYOH6hoQZlxUsCsiQWbsoaUSd9kQnnhHY+5y9Isf8fvXmoX+G/t9qzktiaxuBUlcl883hcrLlxcXGFXM+xqirxiSlMWRteH+KeC5ym1vrKhUbj3lRQPr0mRz1fG4++nLoGK3fRgm1ReN+1DRkJ2F4R7VphvNZLsbYnKaa/nibgdzJ+2qjWFJ9/0uXFJije2eQ5hpuc5zG92PZ8nDjWRbhq+vlbZYxpZEHNxz/twQe8qtv+/q/Vu3ecW2NNaUnV9W18OlE4VBlr7MH45jbu1jw6srmhWOr5VY9VEtS9jnf7yfPe1Wz9y5sNMs4pjSr8j29/sHi1f+IhNqiVAM3C/ado/Apa6Lzw/QjJ9jWxXjNeD/svsiX0gl4BeCXwO0XSX9JJDWGarTckygXdBHgVddPBBfWL/zwb8D/vnGgJlpdTcAAAAAElFTkSuQmCC' )) else: pix.loadFromData( QByteArray.fromBase64(eval('self.father.%s.b64_data' % api))) ico = QIcon(pix) ico.actualSize(QSize(22, 22)) self.api_choose.addItem(ico, api) self.api_choose.setCurrentText(self.father.config['api']) if self.father.config['api'] != '随机': self.father.api = eval('self.father.%s' % self.father.config['api']) self.category_choose.addItems(self.father.api.cate) self.category_choose.setCurrentText(self.father.config['category']) if self.father.config['play_what'] != '网络': self.api_choose.setEnabled(False) self.category_choose.setEnabled(False) else: self.category_choose.addItem('随机') self.category_choose.setCurrentText('随机') def rotate(self): if self.status_timer > 0: self.status_timer -= 1 elif not self.status_label.isHidden() and self.status_timer != -1: self.status_label.setText('') if self.logo_label.add == 0: return elif self.logo_label.add == 1: if self.interval > 2.5: self.interval -= 0.5 self.timer.setInterval(self.interval) else: if self.interval < 15.5: self.interval += 0.5 self.timer.setInterval(self.interval) else: self.logo_label.add = 0 self.logo_label.angle = (self.logo_label.angle - 1) % 360 self.logo_label.update() def set_change(self, what): if not self.father.initializing: if what == 'api': self.father.config['api'] = self.api_choose.currentText() if self.api_choose.currentText() != '随机': # 保持一类随机 if self.father.config['random_switch'] == '一类': self.remain_cate_random = True else: self.remain_cate_random = False # 选择新api exec('self.father.api = self.father.' + self.api_choose.currentText()) self.category_choose.clear() self.category_choose.addItems(self.father.api.cate) else: self.category_choose.clear() self.category_choose.addItem('随机') self.category_choose.setCurrentText('随机') elif what == 'cate': self.father.config[ 'category'] = self.category_choose.currentText() if self.category_choose.currentText( ) != '随机' and self.father.config[ 'random_switch'] == '一类' and not self.remain_cate_random: self.father.config['random_switch'] = '一页' for c in self.random_switch.children(): if c.name == '一页': c.set_active() try: # 选择新的分类 self.father.api.img_set, self.father.api.img_idx = [], 0 except: pass elif what == 'switch': value = self.switch_slider.value() self.switch_show.setText(self.switch_list[value]) self.father.config['switch'] = self.true_switch_list[value] self.father.switch_frame.step_time = 0 elif what == 'size': value = self.size_slider.value() self.size_show.setText(self.size_list[value]) self.father.config['length'] = self.true_size_list[value] elif what == 'show_windmill': self.father.config[ 'show_windmill'] = self.show_windmill.checkState() if self.show_windmill.checkState() == 0: self.father.hide() else: self.father.show() elif what == 'auto_start': if auto_start(int(self.auto_start.checkState()), self.father.my_path): self.father.config[ 'auto_start'] = self.auto_start.checkState() self.father.dump_data('config') def clear_list(self): for api in self.father.data['api']: self.father.data['api'][api]['hate_list'] = [] self.father.dump_data('data') self.status_label.setText('清理完成') self.status_timer = 200 def check_update(self): self.status_label.setText('检查中...') self.status_timer = -1 self.update_button.setEnabled(False) Thread(target=self.check_update_main).start() def check_update_main(self): try: r = ''.join( get('https://github.com/yunyuyuan/invoker/tree/master/pyqt/wallpaper%20switcher/api' ).content.decode().split()) api_list = findall( r'<aclass="js-navigation-open"title="(.*?)\.py"', r) except: dump_log('检查更新' + '--->' + ':失败') self.status_label.setText('检查失败') self.status_timer = 200 return self.not_download = [] for new in api_list: if new not in self.father.all_api and new not in [ '__init__', 'LocalWallpaper_' ]: self.not_download.append(new) # 下载 if self.not_download: self.status_label.setText('%s个更新,下载中-0个' % str(len(self.not_download))) self.status_timer = -1 for api in self.not_download: Thread(target=self.download_api, args=(api, )).start() else: self.status_label.setText('暂无更新') self.status_timer = 200 self.update_button.setEnabled(True) def download_api(self, api, err_count=0): r = get( 'https://raw.githubusercontent.com/yunyuyuan/invoker/master/pyqt/wallpaper%%20switcher/api/%s.py' % api) if r.ok: with open('api/%s.py' % api, 'wb') as fp: fp.write(r.content) fp.close() self.father.data['api'][api] = {} self.father.data['api'][api]['ignore_list'] = [] self.father.data['api'][api]['like_list'] = [] self.father.data['api'][api]['hate_list'] = [] self.father.dump_data('data') lock.acquire() num = int( search('下载中.(\d*)个', self.status_label.text()).group(1)) + 1 self.status_label.setText('%s个更新,下载中-%s个' % (str(len(self.not_download)), num)) self.status_timer = -1 if num == len(self.not_download): self.status_label.setText('下载完成,重启软件生效') self.status_timer = 200 self.update_button.setEnabled(True) lock.release() elif err_count < 5: dump_log('更新api' + '--->' + ':出错') self.download_api(api, err_count + 1) def submit_resolution(self): try: w, h = int(self.width_edit.text()), int(self.height_edit.text()) if 100 <= w <= 10000 and 100 <= h <= 10000: self.father.resolving = [w, h] self.father.config['resolving'] = self.father.resolving self.father.dump_data('config') self.status_label.setText('更新成功!') self.status_timer = 200 else: raise ValueError except ValueError: self.status_label.setText('请输入3-5位数字!') self.status_timer = 200 # 显示选择的api和分类 def show_name(self, idx): self.status_label.setText(idx.data()) self.status_timer = 200
class MusicPreviewWidget(QWidget): def __init__(self, parent=None): super(MusicPreviewWidget, self).__init__(parent) self._lastbuildtime = 10.0 self._running = None self._current = None self._chooserLabel = QLabel() self._chooser = QComboBox(self, activated=self.selectDocument) self._log = log.Log() self._view = popplerview.View() self._progress = widgets.progressbar.TimedProgressBar() self._stack = QStackedLayout() self._top = QWidget() layout = QVBoxLayout() self.setLayout(layout) layout.addWidget(self._top) layout.addLayout(self._stack) layout.addWidget(self._progress) top = QHBoxLayout() top.setContentsMargins(0, 0, 0, 0) top.setSpacing(2) self._top.setLayout(top) top.addWidget(self._chooserLabel) top.addWidget(self._chooser) top.addStretch(1) self._stack.addWidget(self._log) self._stack.addWidget(self._view) self._top.hide() app.aboutToQuit.connect(self.cleanup) app.translateUI(self) def translateUI(self): self._chooserLabel.setText(_("Document:")) def preview(self, text, title=None): """Runs LilyPond on the given text and shows the resulting PDF.""" j = self._running = MusicPreviewJob(text, title) j.done.connect(self._done) self._log.clear() self._log.connectJob(j) j.start() self._progress.start(self._lastbuildtime) def _done(self, success): self._progress.stop(False) pdfs = self._running.resultfiles() self.setDocuments(pdfs) if not pdfs: self._stack.setCurrentWidget(self._log) return self._lastbuildtime = self._running.elapsed_time() self._stack.setCurrentWidget(self._view) if self._current: self._current.cleanup() self._current = self._running # keep the tempdir self._running = None def setDocuments(self, pdfs): """Loads the given PDF path names in the UI.""" self._documents = [popplertools.Document(name) for name in pdfs] self._chooser.clear() self._chooser.addItems([d.name() for d in self._documents]) self._top.setVisible(len(self._documents) > 1) if pdfs: self._chooser.setCurrentIndex(0) self.selectDocument(0) else: self._view.clear() def selectDocument(self, index): doc = self._documents[index].document() if doc: self._view.load(doc) def cleanup(self): if self._running: self._running.abort() self._running.cleanup() self._running = None if self._current: self._current.cleanup() self._current = None self._stack.setCurrentWidget(self._log) self._top.hide() self._view.clear() def print_(self): """Prints the currently displayed document.""" if self._documents: doc = self._documents[self._chooser.currentIndex()] import popplerprint popplerprint.printDocument(doc, self)
class SqliteDbTableEditer(QWidget): #Db=sqlite3.connect("test.db") def __init__(self,dbPath,tblName='',parent=None): self.app=QApplication(sys.argv) self.SqliteDbTypes=['integer','real','text','blob'] self.DbPath,self.CurrentTable=dbPath,tblName #连接数据库 self.Db=sqlite3.connect(self.DbPath) #构建Gui组件 super(SqliteDbTableEditer,self).__init__(parent) self.setWindowTitle('Sqlite数据库表修改器') screen=QDesktopWidget().availableGeometry(0) self.setGeometry(screen.width()/3/2-1, screen.height()/5/2-1, screen.width()*2/3, screen.height()*4/5 ) #lay lay=QVBoxLayout() self.setLayout(lay) #数据库表设置控件 ##layDb layDb=QHBoxLayout() lay.addLayout(layDb) ###lblDb lblDb=QLabel('数据库:') layDb.addWidget(lblDb) ###self.leDb self.leDb=QLineEdit() self.leDb.setText(self.DbPath) layDb.addWidget(self.leDb) ###btnDb btnChangeDb=QPushButton('浏览') btnChangeDb.clicked.connect(self.btnChangeDb_Clicked) layDb.addWidget(btnChangeDb) ###lblTbl lblTbl=QLabel('数据表:') layDb.addWidget(lblTbl) ###self.cbbTbls self.cbbTbls=QComboBox() tbls=list(map(lambda x:x[1], list(filter(lambda x:x[0]=='table', self.Db.execute( 'Select * From sqlite_master' ).fetchall() ) ) ) ) self.cbbTbls.addItems(tbls) if self.CurrentTable!='' : self.cbbTbls.setCurrentIndex(tbls.index(self.CurrentTable)) else: self.CurrentTable=tbls[0] self.makeTableInfo() self.cbbTbls.setCurrentIndex(0) layDb.addWidget(self.cbbTbls) ###lblRename lblRename=QLabel('重命名为:') layDb.addWidget(lblRename) ###self.leRename self.leRename=QLineEdit() self.leRename.setFixedWidth(100) layDb.addWidget(self.leRename) ###btnRename btnRenameTable=QPushButton('重命名') btnRenameTable.clicked.connect(self.btnRenameTable_Clicked) layDb.addWidget(btnRenameTable) ###btnDeleteTable btnDeleteTable=QPushButton('删除表') btnDeleteTable.clicked.connect(self.btnDeleteTable_Clicked) layDb.addWidget(btnDeleteTable) ###btnShow self.btnShow=QPushButton('查看表结构') self.btnShow.clicked.connect(self.btnShow_Clicked) layDb.addWidget(self.btnShow) ###设置TableView控件self.tv,以呈现表数据 self.tv=QTableView() lay.addWidget(self.tv) ###self.model基本初始化 self.model=QSqlTableModel(self,QSqlDatabase.addDatabase('QSQLITE')) self.model.setEditStrategy(QSqlTableModel.OnFieldChange) ###self.tv链接到数据源 self.tv.setModel(self.model) ###self.model数据初始化 self.model.database().setDatabaseName(self.DbPath) self.model.database().open() self.model.setTable(self.CurrentTable) self.model.select() self.cbbTbls.currentIndexChanged.connect(self.changeTable) ##layBtns layBtns=QHBoxLayout() lay.addLayout(layBtns) ###btnAddColumn btnAddColumn=QPushButton('添加列') btnAddColumn.setToolTip('给当前表添加列') btnAddColumn.clicked.connect(self.btnAddColumn_Clicked) layBtns.addWidget(btnAddColumn) ###btnDeleteColumn btnDeleteColumn=QPushButton('删除列') btnDeleteColumn.setToolTip('删除当前表的列') btnDeleteColumn.clicked.connect(self.btnDeleteColumn_Clicked) layBtns.addWidget(btnDeleteColumn) ###btnRenameColumn btnRenameColumn=QPushButton('重命名列') btnRenameColumn.setToolTip('重命名当前表的列') btnRenameColumn.clicked.connect(self.btnRenameColumn_Clicked) layBtns.addWidget(btnRenameColumn) ###btnModifyColumnType btnModifyColumnType=QPushButton('修改列数据类型') btnModifyColumnType.setToolTip('修改当前表的列的数据类型') btnModifyColumnType.clicked.connect(self.btnModifyColumnType_Clicked) layBtns.addWidget(btnModifyColumnType) ###btnModifyColumnConstraint btnModifyColumnConstraint=QPushButton('修改列约束') btnModifyColumnConstraint.setToolTip('修改当前表的列的约束') btnModifyColumnConstraint.clicked.connect( self.btnModifyColumnConstraint_Clicked) layBtns.addWidget(btnModifyColumnConstraint) ###btnOrderColumns btnOrderColumns=QPushButton('调整列顺序') btnOrderColumns.setToolTip('调整当前表的列的顺序') btnOrderColumns.clicked.connect(self.btnOrderColumns_Clicked) layBtns.addWidget(btnOrderColumns) ###btnModifyTableStruct btnModifyTableStruct=QPushButton('修改表结构') btnModifyTableStruct.setToolTip('功能:1.增加列;2.删除列;' +'3.修改列名;4.修改列类型;' +'5.修改列约束;6.调整列顺序' ) btnModifyTableStruct.clicked.connect(self.btnModifyTableStruct_Clicked) layBtns.addWidget(btnModifyTableStruct) ###btnInsertRow btnInsertRow=QPushButton('插入行') btnInsertRow.setToolTip('将在数据表最后增加一行新记录') btnInsertRow.clicked.connect(self.btnInsertRow_Clicked) layBtns.addWidget(btnInsertRow) ###btnDeleteRows btnDeleteRows=QPushButton('删除行') btnDeleteRows.setToolTip('删除所有选中项所在的行') btnDeleteRows.clicked.connect(self.btnDeleteRows_Clicked) layBtns.addWidget(btnDeleteRows) ###btnQuery btnQuery=QPushButton('查询数据') btnQuery.setToolTip('对当前表或数据库进行查询,查询语句将被直接链接到self.model上') btnQuery.clicked.connect(self.btnQuery_Clicked) layBtns.addWidget(btnQuery) self.show() self.app.exec_() def __del__(self): #销毁多余数据库连接 #self.Db.commit() self.Db.close() #---------------------------------------------------------------- def makeTableInfo(self): #table_info=self.Db.execute('pragma table_info(%s)'%self.CurrentTable).fetchall() paragmastr="pragma table_info( '" + self.CurrentTable + "' ) " table_info=self.Db.execute(paragmastr).fetchall() self.columnsCount=len(table_info) self.columnsName=list(map(lambda x:x[1],table_info)) self.columnsType=list(map(lambda x:x[2],table_info)) dbinfo=self.Db.execute('select * from sqlite_master').fetchall() for x in dbinfo: if x[0]=='table' and x[1]==self.CurrentTable: self.sqlStr=x[4] break def DeleteColumn(self,tableName,columnName,tempName=''): if tempName=='': #tempName==''表示直接删除对应的列并提交数据库更改 tempName=tableName+'temp' sqlite_master_sql="select * from sqlite_master" sqlite_master=self.Db.execute(sqlite_master_sql).fetchall() createStr=filter(lambda x:x[0]=='table' and x[1]==tableName, self.Db.execute('select * from sqlite_master').fetchall())[0][4] createStr=','.join(filter(lambda x:x.find(columnName)==-1,createStr.split(','))) newColumns=','.join(map(lambda x:x[1],self.Db.execute('Pragma table_info(%s)'%tableName).fetchall())) #将旧表重命名为临时表名 self.Db.execute("Alter Table %s Rename To %s"%(tableName,tempName)) #新建删除了指定列的数据表 self.Db.execute(createStr) #将旧表的数据导入新表 self.Db.execute('Insert Into %s Select %s From %s'% (tableName,newColumns,tempName)) #删除旧表 self.Db.execute('Drop Table %s'%tempName) #---------------------------------------------------------------- def btnChangeDb_Clicked(self,event): pt=QFileDialog.getOpenFileName( caption='请选择一个sqlite数据库文件:', filter='sqlite数据库文件 (*.db)', directory=os.path.dirname(self.DbPath) ) p=pt[0] if platform.system()=='Windows': p=p.replace('/','\\') if os.path.exists(p): self.DbPath=p self.Db=sqlite3.connect(self.DbPath) tbls=map(lambda x:x[1], filter(lambda x:x[0]=='table', self.Db.execute( 'Select * From sqlite_master' ).fetchall() ) ) self.cbbTbls.currentIndexChanged.disconnect(self.changeTable) self.cbbTbls.clear() self.cbbTbls.addItems(tbls) self.cbbTbls.currentIndexChanged.connect(self.changeTable) self.CurrentTable=tbls[0] self.cbbTbls.setCurrentIndex(0) self.leDb.setText(p) self.model.database().setDatabaseName(self.DbPath) self.model.database().open() self.model.setTable(self.CurrentTable) self.model.select() def changeTable(self,event): if self.CurrentTable!=self.cbbTbls.itemText(event): self.CurrentTable=self.cbbTbls.itemText(event) self.model.setTable(self.CurrentTable) self.model.select() self.makeTableInfo() self.btnShow.setText('查看表结构') def btnDeleteTable_Clicked(self,event): self.Db.execute('Drop Table %s'%self.CurrentTable) for i in range(self.cbbTbls.count()-1,-1,-1): if self.cbbTbls.itemText(i)==self.CurrentTable: self.cbbTbls.removeItem(i) break self.CurrentTable=self.cbbTbls.itemText(0) self.model.setTable(self.CurrentTable) self.model.select() def btnRenameTable_Clicked(self,event): if self.leRename.text()!='': if self.leRename.text()!=self.CurrentTable: try: self.Db.execute('Alter Table %s Rename To %s'% (self.CurrentTable,self.leRename.text()) ) except sqlite3.OperationalError as e: if e.message=='there is already another table or index with this name: %s'%self.leRename.text(): QMessageBox.information(self,'错误', '抱歉,本数据库中以“'+self.leRename.text()+ '”为名称的表或索引已经存在,无法完'+ '成重命名,请重新输入一个名称', '知道了') else: QMessageBox.information(self,'错误', '抱歉,可能是因表名包含非法字符,故'+ '无法完成重命名,请重新输入表名', '知道了') self.leRename.setText('') return self.CurrentTable=self.leRename.text() self.cbbTbls.setItemText(self.cbbTbls.currentIndex(), self.CurrentTable ) self.model.clear() self.model.setQuery(QSqlQuery( 'Select * From %s'%self.CurrentTable)) self.model.select() self.leRename.setText('') else: QMessageBox.information(self,'注意', '抱歉,你还没有输入当前表要修改成的表名\n\n'+ '请先在文本框里输入当前表要重命名成的名字,再点击我', '知道了') def btnShow_Clicked(self,event): if self.btnShow.text()=='查看表结构': self.model.setTable('') self.model.setQuery(QSqlQuery( 'pragma table_info(%s)'%self.CurrentTable)) self.model.select() self.btnShow.setText('查看表数据') else: self.model.setTable(self.CurrentTable) self.model.select() self.btnShow.setText('查看表结构') #---------------------------------------------------------------- def btnInsertRow_Clicked(self,event): self.dlg_InsertRow_Values=[] #self.dlg self.dlg=QDialog() self.dlg.setWindowTitle('插入数据行:') #lay lay=QVBoxLayout() self.dlg.setLayout(lay) #lblprompt lblprompt=QLabel( '请参照创建此表的Sql字符串:\n'+self.sqlStr+ '\n设置各个字段的数据:') lay.addWidget(lblprompt) #layG layG=QGridLayout() lay.addLayout(layG) for i in range(len(self.columnsName)): #lbl lbl=QLabel(self.columnsName[i]+'('+self.columnsType[i]+'):') lbl.setAlignment(Qt.AlignRight) layG.addWidget(lbl,i,0) #le le=QLineEdit() layG.addWidget(le,i,1) if self.columnsType[i].lower() not in self.SqliteDbTypes: #cbb cbb=QComboBox() cbb.addItems(self.SqliteDbTypes) cbb.setCurrentIndex(2) cbb.setToolTip( '此字段的数据类型不是sqlite标准数据'+ '类型,请设置其存储时的使用的sqlite数据类型') layG.addWidget(cbb,i,2) self.dlg_InsertRow_Values.append((le,cbb)) else: self.dlg_InsertRow_Values.append((le,self.columnsType[i])) layG.setColumnStretch(1,1) #layH layH=QHBoxLayout() lay.addLayout(layH) #btnOk btnOk=QPushButton('确定') btnOk.clicked.connect(self.dlg_InsertRow_btnOk_Clicked) layH.addWidget(btnOk) #btnCancel btnCancel=QPushButton('取消') btnCancel.clicked.connect(self.dlg.close) layH.addWidget(btnCancel) self.dlg.show() def dlg_InsertRow_btnOk_Clicked(self,event): sqlStr="Insert Into %s Values("%self.CurrentTable for item in self.dlg_InsertRow_Values: if item[0].text()!='': if type(item[1])==QComboBox: print (item[0].text(),item[1].currentText()) else: print (item[0].text(),item[1]) else: pass def btnDeleteRows_Clicked(self,event): rs=list(map(lambda x:x.row(),self.tv.selectedIndexes())) if len(rs)==0: QMessageBox.information(self,'提醒','请先选中至少一行,再点击此按钮!') return for i in reversed(rs): self.model.removeRows(i,1) self.model.submitAll() def btnQuery_Clicked(self,event): sqltxt,ok=QInputDialog.getText(self,'查询语句设置', '参照创建此表的Sql字符串:\n'+self.sqlStr+ '\n请输入要设置到self.model的查询语句:') if ok: self.model.setTable('') self.model.setQuery(QSqlQuery(sqltxt)) self.model.select() #---------------------------------------------------------------- def btnAddColumn_Clicked(self,event): self.dlgMake_AddColumn() def dlgMake_AddColumn(self,lay=None): if lay is None: self.dlg=QDialog(self) self.dlg.setWindowTitle('添加列:') else: ##self.grpAddColumn self.grpAddColumn=QGroupBox('添加列:') self.grpAddColumn.setCheckable(True) self.grpAddColumn.setChecked(True) lay.addWidget(self.grpAddColumn) ###layAddColumn layAddColumn=QVBoxLayout() if lay is None: self.dlg.setLayout(layAddColumn) else: self.grpAddColumn.setLayout(layAddColumn) ####self.grpAddColumn_ByCmdArgs self.grpAddColumn_ByCmdArgs=QGroupBox('使用参数创建列:') self.grpAddColumn_ByCmdArgs.setCheckable(True) self.grpAddColumn_ByCmdArgs.setChecked(True) self.PreviousChecked=0 self.grpAddColumn_ByCmdArgs.toggled.connect( self.grpAddColumn_ByCmd_toggled) layAddColumn.addWidget(self.grpAddColumn_ByCmdArgs) #####layAddColumn_ByCmdArgs layAddColumn_ByCmdArgs=QHBoxLayout() self.grpAddColumn_ByCmdArgs.setLayout(layAddColumn_ByCmdArgs) ####lblAddColumn_select lblAddColumn_name=QLabel('列名:') layAddColumn_ByCmdArgs.addWidget(lblAddColumn_name) ####self.leAddColumn_name self.leAddColumn_name=QLineEdit() self.leAddColumn_name.setFixedWidth(100) layAddColumn_ByCmdArgs.addWidget(self.leAddColumn_name) ######lblAddColumn_type lblAddColumn_type=QLabel('类型:') layAddColumn_ByCmdArgs.addWidget(lblAddColumn_type) ######self.cbbAddColumn_type self.cbbAddColumn_type=QComboBox() self.cbbAddColumn_type.addItems(self.SqliteDbTypes) self.cbbAddColumn_type.setCurrentIndex(0) self.cbbAddColumn_type.setEditable(True) layAddColumn_ByCmdArgs.addWidget(self.cbbAddColumn_type) ######lblAddColumn_constraint lblAddColumn_constraint=QLabel('约束字符串:') layAddColumn_ByCmdArgs.addWidget(lblAddColumn_constraint) ######self.leAddColumn_constraint self.leAddColumn_constraint=QLineEdit() layAddColumn_ByCmdArgs.addWidget(self.leAddColumn_constraint) ####self.grpAddColumn_ByCmdStr self.grpAddColumn_ByCmdStr=QGroupBox('使用sql字符串创建列:') self.grpAddColumn_ByCmdStr.setCheckable(True) self.grpAddColumn_ByCmdStr.setChecked(False) self.grpAddColumn_ByCmdStr.toggled.connect( self.grpAddColumn_ByCmd_toggled) layAddColumn.addWidget(self.grpAddColumn_ByCmdStr) #####layAddColumn_ByCmdStr layAddColumn_ByCmdStr=QHBoxLayout() self.grpAddColumn_ByCmdStr.setLayout(layAddColumn_ByCmdStr) ######lblAddColumn_cmdstr lblAddColumn_cmdstr=QLabel('用来增加列的部分或完整Sql字符串:') layAddColumn_ByCmdStr.addWidget(lblAddColumn_cmdstr) ######self.leAddColumn_cmdstr self.leAddColumn_cmdstr=QLineEdit() layAddColumn_ByCmdStr.addWidget(self.leAddColumn_cmdstr) if lay is None: self.dlg.show() def grpAddColumn_ByCmd_toggled(self,event): if self.PreviousChecked==0: self.grpAddColumn_ByCmdStr.setChecked(True) self.grpAddColumn_ByCmdArgs.setChecked(False) self.PreviousChecked=1 else: self.grpAddColumn_ByCmdArgs.setChecked(True) self.grpAddColumn_ByCmdStr.setChecked(False) self.PreviousChecked=0 #---------------------------------------------------------------- def btnDeleteColumn_Clicked(self,event): self.dlgMake_DeleteColumn() def dlgMake_DeleteColumn(self,lay=None): if lay is None: self.dlg=QDialog(self) self.dlg.setWindowTitle('删除列:') else: ##self.grpDeleteColumn self.grpDeleteColumn=QGroupBox('删除列:') self.grpDeleteColumn.setCheckable(True) self.grpDeleteColumn.setChecked(False) lay.addWidget(self.grpDeleteColumn) ###layDeleteColumn layDeleteColumn=QHBoxLayout() if lay is None: self.dlg.setLayout(layDeleteColumn) else: self.grpDeleteColumn.setLayout(layDeleteColumn) ###layColumnList layColumnList=QVBoxLayout() layDeleteColumn.addLayout(layColumnList) ####lblDeleteColumn lblDeleteColumn=QLabel('原有的所有列:') layColumnList.addWidget(lblDeleteColumn) ####self.lstColumnList self.lstColumnList=QListWidget() self.lstColumnList.addItems(self.columnsName) self.lstColumnList.setFixedWidth(150) layColumnList.addWidget(self.lstColumnList) ###layDeleteBtns layDeleteBtns=QVBoxLayout() layDeleteColumn.addLayout(layDeleteBtns) ####btnDeleteColumn_Store btnDeleteColumn_Store=QPushButton('>>') btnDeleteColumn_Store.setFixedWidth(50) layDeleteBtns.addWidget(btnDeleteColumn_Store) ####btnDeleteColumn_Unstore btnDeleteColumn_Unstore=QPushButton('<<') btnDeleteColumn_Unstore.setFixedWidth(50) layDeleteBtns.addWidget(btnDeleteColumn_Unstore) ###layColumnsToDelete layColumnsToDelete=QVBoxLayout() layDeleteColumn.addLayout(layColumnsToDelete) ####lblColumnsToDelete lblColumnsToDelete=QLabel('要删除的列:') layColumnsToDelete.addWidget(lblColumnsToDelete) ####self.lstColumnsToDelete self.lstColumnsToDelete=QListWidget() self.lstColumnsToDelete.setFixedWidth(150) layColumnsToDelete.addWidget(self.lstColumnsToDelete) if lay is None: self.dlg.show() #---------------------------------------------------------------- def btnRenameColumn_Clicked(self,event): self.dlgMake_RenameColumn() def dlgMake_RenameColumn(self,lay=None): if lay is None: self.dlg=QDialog(self) self.dlg.setWindowTitle('重命名列:') else: ##self.grpRenameColumn self.grpRenameColumn=QGroupBox('重命名列:') self.grpRenameColumn.setCheckable(True) self.grpRenameColumn.setChecked(False) lay.addWidget(self.grpRenameColumn) ###layRenameColumn layRenameColumn=QHBoxLayout() if lay is None: self.dlg.setLayout(layRenameColumn) else: self.grpRenameColumn.setLayout(layRenameColumn) ####lblRenameColumn_select lblRenameColumn_select=QLabel('选择列:') layRenameColumn.addWidget(lblRenameColumn_select) ####self.cbbRenameColumn_select self.cbbRenameColumn_select=QComboBox() self.cbbRenameColumn_select.addItems(self.columnsName) layRenameColumn.addWidget(self.cbbRenameColumn_select) ####lblRenameColumn_renameto lblRenameColumn_renameto=QLabel('重命名为:') layRenameColumn.addWidget(lblRenameColumn_renameto) ####self.leRenameColumn_renameto self.leRenameColumn_renameto=QLineEdit() self.leRenameColumn_renameto.setFixedWidth(80) layRenameColumn.addWidget(self.leRenameColumn_renameto) ####btnRenameColumn_Store btnRenameColumn_Store=QPushButton('标记 >>') layRenameColumn.addWidget(btnRenameColumn_Store) ####self.cbbRenameColumn_Store self.cbbRenameColumn_Store=QComboBox() layRenameColumn.addWidget(self.cbbRenameColumn_Store,1) if lay is None: self.dlg.show() #---------------------------------------------------------------- def btnModifyColumnType_Clicked(self,event): self.dlgMake_ModifyColumnType() def dlgMake_ModifyColumnType(self,lay=None): if lay is None: self.dlg=QDialog(self) self.dlg.setWindowTitle('修改列数据类型:') else: ##self.grpModifyColumnType self.grpModifyColumnType=QGroupBox('修改列数据类型:') self.grpModifyColumnType.setCheckable(True) self.grpModifyColumnType.setChecked(False) lay.addWidget(self.grpModifyColumnType) ###layModifyColumnType layModifyColumnType=QHBoxLayout() if lay is None: self.dlg.setLayout(layModifyColumnType) else: self.grpModifyColumnType.setLayout(layModifyColumnType) ####lblModifyColumnType_select lblModifyColumnType_select=QLabel('选择列:') layModifyColumnType.addWidget(lblModifyColumnType_select) ####self.cbbModifyColumnType_select self.cbbModifyColumnType_select=QComboBox() self.cbbModifyColumnType_select.addItems(self.columnsName) layModifyColumnType.addWidget(self.cbbModifyColumnType_select) ####lblModifyColumnType_modifyto lblModifyColumnType_modifyto=QLabel('改类型为:') layModifyColumnType.addWidget(lblModifyColumnType_modifyto) ####self.cbbModifyColumnType_modifyto self.cbbModifyColumnType_modifyto=QComboBox() self.cbbModifyColumnType_modifyto.setEditable(True) self.cbbModifyColumnType_modifyto.addItems(self.SqliteDbTypes) self.cbbModifyColumnType_modifyto.setCurrentIndex(2) self.cbbModifyColumnType_modifyto.setFixedWidth(80) layModifyColumnType.addWidget(self.cbbModifyColumnType_modifyto) ####btnModifyColumnType_Store btnModifyColumnType_Store=QPushButton('标记 >>') layModifyColumnType.addWidget(btnModifyColumnType_Store) ####self.cbbModifyColumnType_Store self.cbbModifyColumnType_Store=QComboBox() layModifyColumnType.addWidget(self.cbbModifyColumnType_Store,1) if lay is None: self.dlg.show() #---------------------------------------------------------------- def btnModifyColumnConstraint_Clicked(self,event): self.dlgMake_ModifyColumnConstraint() def dlgMake_ModifyColumnConstraint(self,lay=None): if lay is None: self.dlg=QDialog(self) self.dlg.setWindowTitle('修改列约束:') else: ##self.grpModifyColumnConstraint self.grpModifyColumnConstraint=QGroupBox('修改列约束:') self.grpModifyColumnConstraint.setCheckable(True) self.grpModifyColumnConstraint.setChecked(False) lay.addWidget(self.grpModifyColumnConstraint) ###layModifyColumnConstraint layModifyColumnConstraint=QHBoxLayout() if lay is None: self.dlg.setLayout(layModifyColumnConstraint) else: self.grpModifyColumnConstraint.setLayout(layModifyColumnConstraint) ####lblModifyColumnConstraint_select lblModifyColumnConstraint_select=QLabel('选择列:') layModifyColumnConstraint.addWidget(lblModifyColumnConstraint_select) ####self.cbbModifyColumnConstraint_select self.cbbModifyColumnConstraint_select=QComboBox() self.cbbModifyColumnConstraint_select.addItems(self.columnsName) layModifyColumnConstraint.addWidget(self.cbbModifyColumnConstraint_select) ####lblModifyColumnConstraint_modifyto lblModifyColumnConstraint_modifyto=QLabel('约束改为:') layModifyColumnConstraint.addWidget(lblModifyColumnConstraint_modifyto) ####self.leModifyColumnConstraint_modifyto self.leModifyColumnConstraint_modifyto=QLineEdit() self.leModifyColumnConstraint_modifyto.setFixedWidth(80) layModifyColumnConstraint.addWidget(self.leModifyColumnConstraint_modifyto) ####btnModifyColumnConstraint_Store btnModifyColumnConstraint_Store=QPushButton('标记 >>') layModifyColumnConstraint.addWidget(btnModifyColumnConstraint_Store) ####self.cbbModifyColumnConstraint_Store self.cbbModifyColumnConstraint_Store=QComboBox() layModifyColumnConstraint.addWidget(self.cbbModifyColumnConstraint_Store,1) if lay is None: self.dlg.show() #---------------------------------------------------------------- def btnOrderColumns_Clicked(self,event): self.dlgMake_OrderColumns() def dlgMake_OrderColumns(self,lay=None): if lay is None: self.dlg=QDialog(self) self.dlg.setWindowTitle('调整列顺序:') else: ##self.grpAdjustColumnOrder self.grpAdjustColumnOrder=QGroupBox('调整列顺序:') self.grpAdjustColumnOrder.setCheckable(True) self.grpAdjustColumnOrder.setChecked(False) lay.addWidget(self.grpAdjustColumnOrder) ###layAdjustColumnOrder layAdjustColumnOrder=QVBoxLayout() if lay is None: self.dlg.setLayout(layAdjustColumnOrder) else: self.grpAdjustColumnOrder.setLayout(layAdjustColumnOrder) ####lblAdjustColumnOrder lblAdjustColumnOrder=QLabel('请调整列顺序:') layAdjustColumnOrder.addWidget(lblAdjustColumnOrder) ####self.lstAdjustColumnOrder self.lstAdjustColumnOrder=QListWidget() self.lstAdjustColumnOrder.addItems(self.columnsName) self.lstAdjustColumnOrder.setFixedWidth(150) layAdjustColumnOrder.addWidget(self.lstAdjustColumnOrder) if lay is None: self.dlg.setFixedWidth(175) self.dlg.show() #---------------------------------------------------------------- def btnModifyTableStruct_Clicked(self,event): self.dlg=QDialog(self) self.dlg.setWindowTitle(self.CurrentTable+'表结构修改:') self.dlg.setWindowFlags(Qt.Window| Qt.MSWindowsFixedSizeDialogHint ) #lay lay=QVBoxLayout() self.dlgMake_AddColumn(lay) self.dlgMake_RenameColumn(lay) self.dlgMake_ModifyColumnType(lay) self.dlgMake_ModifyColumnConstraint(lay) #layLists layLists=QHBoxLayout() lay.addLayout(layLists) self.dlgMake_DeleteColumn(layLists) self.dlgMake_OrderColumns(layLists) ##layBtns layBtns=QHBoxLayout() lay.addLayout(layBtns) ##btnOk btnOk=QPushButton('提交修改') btnOk.clicked.connect(self.btnOk_Clicked) layBtns.addWidget(btnOk) ##btnCancel btnCancel=QPushButton('放弃修改') btnCancel.clicked.connect(self.btnCancel_Clicked) layBtns.addWidget(btnCancel) self.dlg.setLayout(lay) self.dlg.open() def btnOk_Clicked(self,event): #do something here self.dlg.close() def btnCancel_Clicked(self,event): self.dlg.close()
class CWidget(QWidget): def __init__(self): super().__init__() self.arr = [] for _ in range(5): c = np.zeros([64, 32]) self.arr.append(c) # for PyQt embedding self.fig = plt.Figure() self.ax = self.fig.add_subplot(111) self.im = self.ax.imshow(self.arr[0], animated=True, vmin=0, vmax=5) self.fig.colorbar(self.im, label='pressure') self.canvas = FigureCanvasQTAgg(self.fig) self.timeInterval = 0.1 self.initUI() def initUI(self): self.connect_status = 0 self.pause_status = 0 self.record_status = 0 self.menu = QVBoxLayout() self.combo_label = QLabel(self) self.combo_label.setText('Port') self.combo_label.setAlignment(Qt.AlignCenter) self.combo_label.setStyleSheet( "QLabel { background-color: #2E3D50;color:#ffffff; border: none; font-weight: regular; font-size: 15pt;font-family: Calibri;}" ) self.combo = QComboBox(self) self.combo.addItem('select') #self.combo.lineEdit.setPlaceholderText("select") self.ports = list(serial.tools.list_ports.comports()) for p in self.ports: self.combo.addItem(p[0]) self.connect_button = QPushButton("Connect") #self.save_button.move(150,50) self.connect_button.setStyleSheet(""" QPushButton { background-color: #2E3D50;color:#ffffff; border: 1px solid white; font-weight: regular; font-size: 15pt;font-family: Calibri;} QPushButton:hover{ background-color: #2E3D50; color:#ffffff;border: 3px solid white; font-weight: bold; font-size: 15pt;font-family: Calibri;} """) self.connect_button.setStyleSheet(""" QPushButton { background-color: #2E3D50;color:#ffffff; border: 1px solid white; font-weight: regular; font-size: 15pt;font-family: Calibri;} QPushButton:hover{ background-color: #2E3D50; color:#ffffff;border: 3px solid white; font-weight: bold; font-size: 15pt;font-family: Calibri;} """) self.connect_button.resize(260, 464) self.sense_label = QLabel(self) self.sense_label.setText('Sensitivity') self.sense_label.setAlignment(Qt.AlignCenter) self.sense_label.setStyleSheet( "QLabel { background-color: #2E3D50;color:#ffffff; border: none; font-weight: regular; font-size: 15pt;font-family: Calibri;}" ) self.threshold_label = QLabel(self) self.threshold_label.setText('Threshold') self.threshold_label.setAlignment(Qt.AlignCenter) self.threshold_label.setStyleSheet( "QLabel { background-color: #2E3D50;color:#ffffff; border: none; font-weight: regular; font-size: 15pt;font-family: Calibri;}" ) self.save_button = QPushButton("Save") #self.save_button.move(150,50) self.save_button.setStyleSheet(""" QPushButton { background-color: #2E3D50;color:#ffffff; border: 1px solid white; font-weight: regular; font-size: 15pt;font-family: Calibri;} QPushButton:hover{ background-color: #2E3D50; color:#ffffff;border: 3px solid white; font-weight: bold; font-size: 15pt;font-family: Calibri;} """) self.save_button.resize(260, 464) # self.logo_button.setStyleSheet("QPushButton{image:url(./image/logo.png); border:0px;}") self.sense_value = QLineEdit("100") self.sense_value.setAlignment(Qt.AlignCenter) self.sense_value.resize(260, 464) #self.option_button.move(150,50) #self.option_button.setStyleSheet("QPushButton { background-color: #2E3D50;color:#ffffff; border: none; font-weight: regular; font-size: 15pt;font-family: Calibri;}") self.sense_slider = QSlider(Qt.Horizontal) self.sense_slider.setRange(1, 100) self.threshold_value = QLineEdit("0") self.threshold_value.setAlignment(Qt.AlignCenter) self.threshold_value.resize(260, 464) self.threshold_slider = QSlider(Qt.Horizontal) self.threshold_slider.setRange(0, 300) self.pause_button = QPushButton("Pause") #self.save_button.move(150,50) self.pause_button.setStyleSheet(""" QPushButton { background-color: #2E3D50;color:#ffffff; border: 1px solid white; font-weight: regular; font-size: 15pt;font-family: Calibri;} QPushButton:hover{ background-color: #2E3D50; color:#ffffff;border: 3px solid white; font-weight: bold; font-size: 15pt;font-family: Calibri;} """) #self.pause_button.resize(260, 464) self.record_button = QPushButton("Record") #self.save_button.move(150,50) self.record_button.setStyleSheet(""" QPushButton { background-color: #2E3D50;color:#ffffff; border: 1px solid white; font-weight: regular; font-size: 15pt;font-family: Calibri;} QPushButton:hover{ background-color: #2E3D50; color:#ffffff;border: 3px solid white; font-weight: bold; font-size: 15pt;font-family: Calibri;} """) self.status_notice = QLineEdit() self.status_notice.setStyleSheet(""" QLineEdit { background-color: #2E3D50;color:#ffffff; border: 0px solid white; font-weight: regular; font-size: 10pt;font-family: Calibri;} """) self.menu.addWidget(self.combo_label) self.menu.addWidget(self.combo) self.menu.addSpacing(5) self.menu.addWidget(self.connect_button) self.menu.addSpacing(20) self.menu.addWidget(self.sense_label) self.menu.addWidget(self.sense_value) self.menu.addWidget(self.sense_slider) self.menu.addWidget(self.threshold_label) self.menu.addWidget(self.threshold_value) self.menu.addWidget(self.threshold_slider) self.menu.addSpacing(50) self.menu.addWidget(self.save_button) self.menu.addSpacing(10) self.menu.addWidget(self.pause_button) self.menu.addSpacing(10) self.menu.addWidget(self.record_button) self.menu.addSpacing(10) self.menu.addWidget(self.status_notice) self.menu.setSpacing(0) self.menu.setContentsMargins(0, 0, 0, 0) #self.menu.addStretch() self.menu.setAlignment(Qt.AlignVCenter) vbox = QHBoxLayout() vbox.setStretchFactor(self.menu, 5) vbox.setStretchFactor(self.canvas, 1) vbox.addLayout(self.menu) vbox.addWidget(self.canvas) self.connect_button.clicked.connect(self.port_connect) self.save_button.clicked.connect(self.save_csv) self.pause_button.clicked.connect(self.pause) self.record_button.clicked.connect(self.record) self.threshold_slider.setValue(0) self.threshold_slider.valueChanged.connect( self.threshold_slider_value_changed) self.threshold_value.textChanged.connect(self.threshold_value_changed) self.sense_slider.setValue(100) self.sense_slider.valueChanged.connect(self.sense_slider_value_changed) self.sense_value.textChanged.connect(self.sense_value_changed) self.combo.activated[str].connect(self.onChanged) #self.combo.highlighted.connect(self.onClicked) self.setLayout(vbox) self.setGeometry(50, 50, 800, 800) # 1~1 중 1번째(1,1,1) 서브 챠트 생성 # self.ax = self.fig.add_subplot(1,1,1) # # 2D line # self.line, = self.ax.plot(self.x, self.y) # 애니메이션 챠트 생성 #self.ani = animation.FuncAnimaXtion(self.fig, self.updatefig, blit=True) #self.canvas.draw() print(self.canvas.size()) self.ani = animation.FuncAnimation(self.fig, self.updatefig, blit=True) self.canvas.draw() self.show() def port_connect(self): try: self.ser = serial.Serial(self.port_num, baudrate=115200, timeout=2.5, parity=serial.PARITY_NONE, bytesize=serial.EIGHTBITS, stopbits=serial.STOPBITS_ONE) self.connect_status = 1 self.status_notice.setText("{} connected".format(self.port_num)) except: try: print(self.port_num) print("port error") except: print("port error") def record(self): if self.record_status == 0: self.record_status = 1 self.record_button.setText("Stop") self.record_button.setStyleSheet(""" QPushButton { background-color: #2E3D50; color:#ffffff;border: 3px solid white; font-weight: bold; font-size: 15pt;font-family: Calibri;} """) self.record_file_name = './data/{}.csv'.format( datetime.datetime.now().strftime("%m-%d-%Y-%H-%M-%S")) self.status_notice.setText("recording") elif self.record_status == 1: self.record_status = 0 self.record_button.setText("Record") self.record_button.setStyleSheet(""" QPushButton { background-color: #2E3D50;color:#ffffff; border: 1px solid white; font-weight: regular; font-size: 15pt;font-family: Calibri;} QPushButton:hover{ background-color: #2E3D50; color:#ffffff;border: 3px solid white; font-weight: bold; font-size: 15pt;font-family: Calibri;} """) self.status_notice.setText("record finished") def pause(self): if self.pause_status == 0: self.pause_status = 1 self.pause_button.setText("Resume") self.pause_button.setStyleSheet(""" QPushButton { background-color: #2E3D50; color:#ffffff;border: 3px solid white; font-weight: bold; font-size: 15pt;font-family: Calibri;} """) self.status_notice.setText("paused") elif self.pause_status == 1: self.pause_status = 0 self.pause_button.setText("Pause") self.pause_button.setStyleSheet(""" QPushButton { background-color: #2E3D50;color:#ffffff; border: 1px solid white; font-weight: regular; font-size: 15pt;font-family: Calibri;} QPushButton:hover{ background-color: #2E3D50; color:#ffffff;border: 3px solid white; font-weight: bold; font-size: 15pt;font-family: Calibri;} """) self.status_notice.setText("resume") def save_csv(self, ): f = open('./data/{}.csv'.format( datetime.datetime.now().strftime("%m-%d-%Y-%H-%M-%S")), 'w', encoding='utf-8', newline='') wr = csv.writer(f) for i in range(64): wr.writerow(self.data[i]) f.close() def onChanged(self, text): #print(text) self.port_num = text def onClicked(self): self.ports = list(serial.tools.list_ports.comports()) self.combo.clear() for p in self.ports: self.combo.addItem(p[0]) def paintEvent(self, event): height = self.size().height() width = self.size().width() painter = QPainter(self) painter.setPen(QPen(QColor(46, 61, 80), 5, Qt.SolidLine)) painter.setBrush(QBrush(QColor(46, 61, 80), Qt.SolidPattern)) #painter.drawRect(0, 0, width-self.canvas.size().width() , height) painter.drawRect(0, 0, width, height) def threshold_value_changed(self): try: if self.threshold_value.text() == '': self.threshold_slider.setValue(1) elif self.threshold_value.text() == '0': self.threshold_slider.setValue(1) else: self.threshold_slider.setValue(int( self.threshold_value.text())) except: self.threshold_slider.setValue(1) def threshold_slider_value_changed(self): self.threshold_value.setText(str(self.threshold_slider.value())) #print(self.threshold_slider.value()) def sense_value_changed(self): try: if self.sense_value.text() == '': self.sense_slider.setValue(1) else: self.sense_slider.setValue(int(self.sense_value.text())) except: self.sense_slider.setValue(0) def sense_slider_value_changed(self): self.sense_value.setText(str(self.sense_slider.value())) #print(self.sense_slider.value()) def closeEvent(self, e): pass def receive_data(self, ): temp = 0 while True: try: data = self.ser.readline().decode("utf-8") #print(data) data = str(data).replace('\r\n', ' ').split(' ')[:-3] data[1:] = list(map(int, data[1:])) data[1:] = np.divide(data[1:], 100) if 'a' in data: data_set = np.array(data[1:]) temp = 1 elif 'b' in data and temp == 1: data_set = np.vstack([data_set, data[1:]]) elif 'c' in data and temp == 1: data_set = np.vstack([data_set, data[1:]]) #print(data_set.shape) if data_set.shape == (64, 32): return data_set else: continue except: continue #else : # print(data) def save_data(self, filename): f = open(filename, 'a', encoding='utf-8', newline='') wr = csv.writer(f) f.write('{}\n'.format( datetime.datetime.now().strftime("%m-%d-%Y-%H-%M-%S"))) for i in range(64): wr.writerow(self.data[i]) if self.record_status == 1: pass elif self.record_status == 0: self.status_notice.setText("saved") def updatefig(self, *args): if self.pause_status == 0: if self.connect_status == 1: self.display_data = self.receive_data() if self.connect_status == 0: self.display_data = np.zeros((64, 32)) self.display_data = self.Sensitivity(self.display_data) self.display_data = self.Threshold(self.display_data) self.data = self.display_data #for test start self.data[19] = self.data[18] #for test end self.im.set_array(self.data) # # print(self.record_status) if self.record_status == 1: self.save_data(self.record_file_name) return self.im, if self.pause_status == 1: self.im.set_array(self.data) if self.record_status == 1: self.save_data(self.record_file_name) return self.im, def Sensitivity(self, data): return np.power(self.sense_slider.value(), data) def Threshold(self, data): data[data <= self.threshold_slider.value() / 100] = 0 return data
class App(QWidget): def __init__(self): #here we initialize the basic parameters for the gui super().__init__() self.prev_text = "" self.title = 'Categorizer' self.col_codes = {} self.left = 10 self.top = 10 self.width = 1200 self.height = 800 self.cur_dir = os.getcwd() self.title_font = QtGui.QFont("Times", 15, QtGui.QFont.Bold) self.base_dir = "" self.initUI() def initUI(self): #We set the basic geometry of the window self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) #Here we set up the button that will allow the user to find their html file of choice button = QPushButton('Find File', self) button.setToolTip( 'This button will allow you to select an html file to process') button.move(150, 700) button.clicked.connect(self.on_click) #This button will allow the user to submit their predetermine color preferences drag_object = CustomLabel('', self) drag_object.move(75, 150) self.button = button self.drag_object = drag_object self.cur_file = "" self.selected_file = QLabel(self) self.selected_file.setText("The selected file is: " + self.cur_file) self.selected_file.setFont(self.title_font) self.selected_file.move(500, 100) self.directory_label = QLabel(self) self.directory_label.setText("Root Directory: " + self.base_dir) self.directory_label.move(500, 40) self.change_dir = QPushButton("Change Directory", self) self.change_dir.setToolTip("Click to change root directory") self.change_dir.move(900 + len(self.directory_label.text()), 40) self.change_dir.clicked.connect(self.change_dir_function) self.combo = QComboBox(self) self.combo.move(500, 200) self.combo.setToolTip( "Choose which folder to add the designated file to") self.combo_hint = QLabel(self) self.combo_hint.setText("Accessible Folders") self.combo_hint.move(500, 170) self.added_folders = AddedFiles("", self) self.add_folder = QPushButton("Add-->", self) self.add_folder.setToolTip( "Press to add the folder to the collection of folders") self.add_folder.move(650, 200) self.add_folder.clicked.connect(self.add_folder_func) self.added_folders_label = QLabel(self) self.added_folders_label.setText("Folders to add file to") self.added_folders_label.move(800, 170) self.add_simlinks = QPushButton("Add Simlinks", self) self.add_simlinks.setToolTip( "Press to add the file to the given directories") self.add_simlinks.move(500, 700) self.add_simlinks.clicked.connect(self.add_simlinks_function) l = QLabel(self) l.setText("Files/Directories") l.move(100, 100) self.show() self.getBaseDir() def add_simlinks_function(self): if self.cur_file == "": QMessageBox.question(self, "Error", 'No file selected', QMessageBox.Ok, QMessageBox.Ok) return folders = [] for i in range(len(self.added_folders.elem)): if self.added_folders.elem[i].text() != '': folders.append(self.added_folders.elem[i].text()) file = self.cur_file file_base = file.split("/")[-1] os.system("mv " + file + " " + self.base_dir + "/.hidden") for folder in folders: print("ln -s " + self.base_dir + "/.hidden/" + file_base + " " + self.base_dir + folder) os.system("ln -s " + self.base_dir + "/.hidden/" + file_base + " " + self.base_dir + folder) QMessageBox.question( self, "Completed", 'The file has been successfully linked. You can find the original file in the hidden folder ' + self.base_dir + "/.hidden", QMessageBox.Ok, QMessageBox.Ok) self.drag_object.update_dir() self.update_combo_box() self.cur_file = "" @pyqtSlot() def add_folder_func(self): self.added_folders.add_element(self.combo.currentText()) @pyqtSlot() def on_click(self): print('Looking for file') location = self.openFileNameDialog() #do stuff def openFileNameDialog(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getOpenFileName( self, "QFileDialog.getOpenFileName()", "", "All Files (*);;Python Files (*.py)", options=options) if fileName: print(fileName) self.cur_file = fileName self.selected_file.setText("The selected file is: " + self.cur_file) self.selected_file.adjustSize() return fileName else: return "Error" def getBaseDir(self): if not os.path.isdir(os.getcwd() + "/.hidden"): self.buildDirPopup() else: self.base_dir = os.getcwd() self.directory_label.setText("Root Directory: " + self.base_dir) self.directory_label.adjustSize() self.drag_object.update_dir() self.change_dir.move(900 + len(self.directory_label.text()), 40) self.update_combo_box() def buildDirPopup(self): self.dirPopup = DirectoryPopup(self) def change_dir_function(self): fileName = str( QFileDialog.getExistingDirectory(self, "QFileDialog.getOpenFileName()")) if fileName: print(fileName) if os.path.isdir(fileName): os.chdir(fileName) self.getBaseDir() def update_combo_box(self): self.combo.clear() if self.base_dir != "": files = self.return_directories(self.base_dir, "") print(files) self.combo.addItems(files) self.adjustSize() def return_directories(self, dir, prefix): files = parse_for_hidden(os.listdir(dir)) deleted = 0 for i in range(len(files)): if os.path.isdir(dir + "/" + files[i - deleted]): files += self.return_directories( dir + "/" + files[i - deleted], files[i - deleted]) files[i - deleted] = prefix + "/" + files[i - deleted] else: del files[i - deleted] deleted += 1 return files
class PictureEditor(QFrame): picture_data: Picture pic_path: str='./' def __init__(self, parent, picture_parameter: dict): QFrame.__init__(self, parent, flags=Qt.FramelessWindowHint) self.buffer = parent.buffer self.picture_parameter = picture_parameter self.picture_label = QLabel() self.resize_multiple = 1 scroll = QScrollArea(self) scroll.setWidget(self.picture_label) scroll.setObjectName('picture') self.name_combo = QComboBox(self) self.index_combo = QComboBox(self) self.palette_combo = QComboBox(self) self.resize_combo = QComboBox(self) self.name_combo.setFixedWidth(120) self.index_combo.setFixedWidth(120) self.palette_combo.setFixedWidth(120) self.resize_combo.setFixedWidth(120) self.name_combo.setItemDelegate(QStyledItemDelegate()) self.index_combo.setItemDelegate(QStyledItemDelegate()) self.palette_combo.setItemDelegate(QStyledItemDelegate()) self.resize_combo.setItemDelegate(QStyledItemDelegate()) self.resize_combo.addItems([f' × {i + 1}' for i in range(4)]) self.name_combo.currentTextChanged[str].connect(self.name_change) self.index_combo.currentIndexChanged.connect(self.refresh_data) self.palette_combo.currentIndexChanged.connect(self.refresh_data) self.resize_combo.currentIndexChanged.connect(self.refresh_data) self.name_combo.addItems(picture_parameter) output_button = QPushButton('導出圖片') input_button = QPushButton('導入圖片') output_button.clicked.connect(self.output_picture) input_button.clicked.connect(self.input_picture) control_layout = QVBoxLayout() control_layout.addWidget(QLabel('選擇圖片'), alignment=Qt.AlignLeft) control_layout.addWidget(self.name_combo, alignment=Qt.AlignRight) control_layout.addWidget(QLabel('選擇編號'), alignment=Qt.AlignLeft) control_layout.addWidget(self.index_combo, alignment=Qt.AlignRight) control_layout.addWidget(QLabel('選擇色板'), alignment=Qt.AlignLeft) control_layout.addWidget(self.palette_combo, alignment=Qt.AlignRight) control_layout.addWidget(QLabel('缩放比例'), alignment=Qt.AlignLeft) control_layout.addWidget(self.resize_combo, alignment=Qt.AlignRight) control_layout.addWidget(output_button, alignment=Qt.AlignRight) control_layout.addWidget(input_button, alignment=Qt.AlignRight) control_layout.addStretch() layout = QHBoxLayout() layout.addLayout(control_layout) layout.addWidget(scroll) self.setLayout(layout) def name_change(self, name: str): picture_setting = DATA_PARAMETER.get('圖片_' + name) self.index_combo.disconnect() self.index_combo.clear() self.index_combo.addItems([f'{i+1:>13d}' for i in range(picture_setting['quantity']['normal_quantity'])]) self.index_combo.currentIndexChanged.connect(self.refresh_data) if self.picture_parameter.get(name): palette_setting = PALETTE_PARAMETER.get('色板_' + self.picture_parameter.get(name)) else: palette_setting = () self.palette_combo.disconnect() self.palette_combo.clear() if palette_setting: self.palette_combo.addItems([f'0x{address:08X}' for address in palette_setting]) self.palette_combo.setEnabled(True) else: self.palette_combo.setEnabled(False) self.palette_combo.currentIndexChanged.connect(self.refresh_data) self.refresh_data() def refresh_data(self): picture_setting = DATA_PARAMETER.get('圖片_' + self.name_combo.currentText()) self.picture_data = Picture(self, **picture_setting) if self.palette_combo.isEnabled(): self.picture_data.palette.set_normal_offset(int(self.palette_combo.currentText(), 16)) self.resize_multiple = self.resize_combo.currentIndex() + 1 self.set_picture() def set_picture(self): picture = self.picture_data.get_data(self.index_combo.currentIndex()) width = self.picture_data.width * self.resize_multiple height = self.picture_data.height * self.resize_multiple self.picture_label.setFixedSize(width, height) self.picture_label.setPixmap(picture.resize((width, height)).toqpixmap()) def output_picture(self): filename = QFileDialog.getSaveFileName(self, '导出图片', self.pic_path, 'BMP图像(*.bmp)')[0] if filename: self.pic_path = filename[0: filename.rfind('/') + 1] if self.index_combo.isEnabled(): picture = self.picture_data.get_data(self.index_combo.currentIndex()) else: picture = self.picture_data.get_data(0) picture.save(filename) def input_picture(self): filename = QFileDialog.getOpenFileName(self, '导入图片', self.pic_path, '*.bmp;;*.png;;*.gif;;*.tif')[0] if filename: self.pic_path = filename[0: filename.rfind('/') + 1] width = self.picture_data.width * self.resize_multiple height = self.picture_data.height * self.resize_multiple picture = Image.open(filename).resize((width, height)) self.picture_data.set_data(self.index_combo.currentIndex(), picture) self.set_picture()
class MnemonicFrame(BaseFrame): def __init__(self, recovered, parent=None): super().__init__(parent) self.label.setText("Mnemonic:") self.mnem_select = QComboBox() prefs = QSettings() prefs.beginGroup("/General") dark_mode = prefs.value("/DarkMode") prefs.endGroup() if dark_mode: self.mnem_select.setStyleSheet("QListView {color: white;}") else: self.mnem_select.setStyleSheet("QListView {color: none;}") self.mnem_select.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) if recovered: self.mnem_select.setEnabled(False) self.layout.addWidget(self.label) self.layout.addWidget(self.mnem_select) self.setLayout(self.layout) self.mnem_list_path = Path( __file__).parents[1] / "res" / "mnemonics.json" # noqa: E501 os.makedirs(os.path.dirname(self.mnem_list_path), exist_ok=True) if not os.path.isfile(self.mnem_list_path): with open(self.mnem_list_path, 'w') as mnem_file: mnem_file.write( '{"mnemonics": ["Modify the mnemonics.json file", "in the res directory", "to change this list"]}' ) # noqa: E501 print('doesn\'t exist') self.cur_mnemonics = None self.load_mnemonics() # Un-comment to allow user to add mnemonics # self.mnem_select.activated.connect(self.mnem_selected) def load_mnemonics(self, active=None): self.mnem_select.clear() with open(self.mnem_list_path, 'r') as mnem_list: try: self.cur_mnemonics = json.load(mnem_list) except Exception: self.new_mnem_file(self.mnem_list_path) # How can we handle this kind of recursive try? self.cur_mnemonics = json.load(mnem_list) self.mnem_select.setPlaceholderText('...') self.mnem_select.addItems(self.cur_mnemonics['mnemonics']) # Un-comment to allow user to add mnemonics # self.mnem_select.addItem('+ Add new') if active: self.mnem_select.setCurrentIndex(self.mnem_select.findText(active)) def add_mnemonic(self, mnemonic): self.cur_mnemonics['mnemonics'].append(mnemonic) self.cur_mnemonics['mnemonics'] = sorted( self.cur_mnemonics['mnemonics'], key=str.casefold) with open(self.mnem_list_path, 'w') as mnen_list: mnen_list.write(json.dumps(self.cur_mnemonics)) @pyqtSlot(int) def mnem_selected(self, index): if index == self.mnem_select.count() - 1: named = False selected = None while not named: selected = QInputDialog.getText(self, 'Add New Mnemonic', 'Mnemonic:') if not selected[1]: return elif not str.strip(selected[0]): QMessageBox.critical( self, "Error", "Mnemonic cannot be blank", ) elif selected[0] in [ self.mnem_select.itemText(i) for i in range(self.mnem_select.count()) ]: QMessageBox.critical( self, "Error", "Mnemonic already exists", ) else: named = True mnemonic = selected[0] self.add_mnemonic(mnemonic) self.load_mnemonics(mnemonic) def new_mnem_file(self, mnem_list_path): default = json.dumps({'mnemonics': ['XXA', 'XXB']}) with open(mnem_list_path, 'w') as mnem_list: mnem_list.write(default)
class DeviceBar(QWidget): """ DeviceBar Signals: onDeviceUpdated() onDeviceSelected(str) # str = id onDeviceChanged(str) # str = id """ onDeviceUpdated = pyqtSignal(str, name="onDeviceUpdated") onDeviceSelected = pyqtSignal(str, name="onDeviceSelected") onDeviceChanged = pyqtSignal(str, name="onDeviceChanged") def __init__(self, parent=None, device_type='usb'): super().__init__(parent=parent) # dont show for local if device_type != 'usb': return self.parent = parent self.wait_for_devtype = device_type self.is_waiting = True self._adb = Adb() if not self._adb.min_required: return self._git = Git() self.setAutoFillBackground(True) self.setStyleSheet( 'background-color: crimson; color: white; font-weight: bold; margin: 0; padding: 10px;' ) self.setup() self._timer = QTimer() self._timer.setInterval(500) self._timer.timeout.connect(self._on_timer) self._timer.start() self._timer_step = 0 frida.get_device_manager().on('added', self._on_device) frida.get_device_manager().on('removed', self._on_device) self.devices_thread = DevicesUpdateThread(self) self.devices_thread.onAddDevice.connect(self.on_add_deviceitem) self.devices_thread.onDevicesUpdated.connect(self._on_devices_finished) self._update_thread = FridaUpdateThread(self) self._update_thread._adb = self._adb self._update_thread.onStatusUpdate.connect(self._update_statuslbl) self._update_thread.onFinished.connect(self._frida_updated) self._update_thread.onError.connect(self._on_download_error) self.updated_frida_version = '' self.updated_frida_assets_url = {} self._device_id = None self._devices = [] remote_frida = self._git.get_frida_version() if remote_frida is None: self.updated_frida_version = '' self.updated_frida_assets_url.clear() else: remote_frida = remote_frida[0] self.updated_frida_version = remote_frida['tag_name'] for asset in remote_frida['assets']: try: name = asset['name'] tag_start = name.index('android-') if name.index('server') >= 0: tag = name[tag_start + 8:-3] self.updated_frida_assets_url[tag] = asset[ 'browser_download_url'] except ValueError: pass def setup(self): """ Setup ui """ h_box = QHBoxLayout() h_box.setContentsMargins(0, 0, 0, 0) self.update_label = QLabel('Waiting for Device') self.update_label.setFixedWidth(self.parent.width()) self.update_label.setOpenExternalLinks(True) self.update_label.setTextFormat(Qt.RichText) self.update_label.setFixedHeight(35) self.update_label.setTextInteractionFlags(Qt.TextBrowserInteraction) self._install_btn = QPushButton('Install Frida', self.update_label) self._install_btn.setStyleSheet('padding: 0; border-color: white;') self._install_btn.setGeometry(self.update_label.width() - 110, 5, 100, 25) self._install_btn.clicked.connect(self._on_install_btn) self._install_btn.setVisible(False) self._start_btn = QPushButton('Start Frida', self.update_label) self._start_btn.setStyleSheet('padding: 0; border-color: white;') self._start_btn.setGeometry(self.update_label.width() - 110, 5, 100, 25) self._start_btn.clicked.connect(self._on_start_btn) self._start_btn.setVisible(False) self._update_btn = QPushButton('Update Frida', self.update_label) self._update_btn.setStyleSheet('padding: 0; border-color: white;') self._update_btn.setGeometry(self.update_label.width() - 110, 5, 100, 25) self._update_btn.clicked.connect(self._on_install_btn) self._update_btn.setVisible(False) self._restart_btn = QPushButton('Restart Frida', self.update_label) self._restart_btn.setStyleSheet('padding: 0; border-color: white;') self._restart_btn.setGeometry(self.update_label.width() - 110, 5, 100, 25) self._restart_btn.clicked.connect(self._on_restart_btn) self._restart_btn.setVisible(False) self._devices_combobox = QComboBox(self.update_label) self._devices_combobox.setStyleSheet( 'padding: 2px 5px; border-color: white;') self._devices_combobox.setGeometry(self.update_label.width() - 320, 5, 200, 25) self._devices_combobox.currentIndexChanged.connect( self._on_device_changed) self._devices_combobox.setVisible(False) h_box.addWidget(self.update_label) self.setLayout(h_box) def on_add_deviceitem(self, device_ident): """ Adds an Item to the DeviceComboBox """ if device_ident['type'] == self.wait_for_devtype: if device_ident['name'] not in self._devices: self._devices.append(device_ident) self._timer_step = -1 self.is_waiting = False def _on_device_changed(self, index): device = None device_id = self._devices_combobox.itemData(index) if device_id: try: device = frida.get_device(device_id) except: return if device: self._device_id = device.id self._check_device(device) self.onDeviceChanged.emit(self._device_id) def _check_device(self, frida_device): self.update_label.setStyleSheet('background-color: crimson;') self._install_btn.setVisible(False) self._update_btn.setVisible(False) self._start_btn.setVisible(False) self._restart_btn.setVisible(False) self._adb.device = frida_device.id self._device_id = frida_device.id if self._adb.available(): self.update_label.setText('Device: ' + frida_device.name) # try getting frida version device_frida = self._adb.get_frida_version() # frida not found show install button if device_frida is None: self._install_btn.setVisible(True) else: # frida is old show update button if self.updated_frida_version != device_frida: self._start_btn.setVisible(True) self._update_btn.setVisible(False) # old frida is running allow use of this version if self._adb.is_frida_running(): self._start_btn.setVisible(False) if self.updated_frida_assets_url: self._update_btn.setVisible(True) self.update_label.setStyleSheet( 'background-color: yellowgreen;') self.onDeviceUpdated.emit(frida_device.id) # frida not running show start button elif device_frida and not self._adb.is_frida_running(): self._start_btn.setVisible(True) # frida is running with last version show restart button elif device_frida and self._adb.is_frida_running(): self.update_label.setStyleSheet( 'background-color: yellowgreen;') self._restart_btn.setVisible(True) self.onDeviceUpdated.emit(frida_device.id) def _on_devices_finished(self): if self._devices: if len(self._devices) > 1: self._devices_combobox.clear() self._devices_combobox.setVisible(True) self.update_label.setText('Please select the Device: ') for device in self._devices: self._devices_combobox.addItem(device['name'], device['id']) else: self._devices_combobox.setVisible(False) try: device = frida.get_device(self._devices[0]['id']) self._check_device(device) except: pass def _on_timer(self): if self._timer_step == -1: self._timer.stop() return if self._timer_step == 0: self.update_label.setText(self.update_label.text() + ' .') self._timer_step = 1 elif self._timer_step == 1: self.update_label.setText(self.update_label.text() + '.') self._timer_step = 2 elif self._timer_step == 2: self.update_label.setText(self.update_label.text() + '.') self._timer_step = 3 else: self.update_label.setText( self.update_label.text()[:-self._timer_step]) self._timer_step = 0 if self.is_waiting and self.devices_thread is not None: if not self.devices_thread.isRunning(): self.devices_thread.start() def _on_download_error(self, text): self._timer_step = -1 self.update_label.setStyleSheet('background-color: crimson;') self.update_label.setText(text) self._install_btn.setVisible(True) self._update_btn.setVisible(False) def _on_device(self): self.update_label.setText('Waiting for Device ...') self._timer_step = 3 self.is_waiting = True self._on_timer() def _on_install_btn(self): # urls are empty if not self.updated_frida_assets_url: return arch = self._adb.get_device_arch() request_url = '' if arch is not None and len(arch) > 1: arch = arch.join(arch.split()) if arch == 'arm64' or arch == 'arm64-v8a': request_url = self.updated_frida_assets_url['arm64'] elif arch == 'armeabi-v7a': request_url = self.updated_frida_assets_url['arm'] else: if arch in self.updated_frida_assets_url: request_url = self.updated_frida_assets_url[arch] try: if self._adb.available() and request_url.index( 'https://') == 0: self._install_btn.setVisible(False) self._update_btn.setVisible(False) if self._update_thread is not None: if not self._update_thread.isRunning(): self._update_thread.frida_update_url = request_url self._update_thread.adb = self._adb self._update_thread.start() except ValueError: # something wrong in .git_cache folder print("request_url not set") def _update_statuslbl(self, text): self._timer.stop() self._timer_step = 0 self._timer.start() self.update_label.setText(text) def _frida_updated(self): #self._timer_step = 3 #self.is_waiting = True self._on_devices_finished() def _on_start_btn(self): if self._adb.available(): self._start_btn.setVisible(False) if self._adb.start_frida(): #self.onDeviceUpdated.emit(self._device_id) self._on_devices_finished() else: self._start_btn.setVisible(True) def _on_restart_btn(self): if self._adb.available(): self._restart_btn.setVisible(False) if self._adb.start_frida(restart=True): self._restart_btn.setVisible(True) #self.onDeviceUpdated.emit(self._device_id) self._on_devices_finished()
class App(QMainWindow): send_to_generator = pyqtSignal(str, tuple, str, str, str) def __init__(self): super().__init__() self.title = "Generator Holzworth" self.left = 30 self.top = 30 self.width = 720 self.height = 500 self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) # get available ports on start self.available_ports = genserialport.list_ports() # combo for choose appropriate port self.port_select = QComboBox(self) self.port_select.addItems(self.available_ports) self.port_select.move(550, 400) self.port_select.adjustSize() # LCDs and labels for frequency, power and phase settings self.lcd_frequency_channel1 = QLCDNumber(self) self.lcd_frequency_channel1.move(20, 30) self.lcd_frequency_channel1.resize(260, 50) self.lcd_frequency_channel1.display(100.0) self.lcd_frequency_channel1.setDigitCount(11) self.channel1_mhz_label = QLabel("MHz", self) self.channel1_mhz_label.move(285, 40) self.channel1_mhz_label.setFont(QFont("Times", 20)) self.lcd_power_channel1 = QLCDNumber(self) self.lcd_power_channel1.move(350, 30) self.lcd_power_channel1.resize(100, 50) self.lcd_power_channel1.display(0.0) ch1_dbm_label = QLabel("dBm", self) ch1_dbm_label.move(455, 40) ch1_dbm_label.setFont(QFont("Times", 20)) self.lcd_phase_channel1 = QLCDNumber(self) self.lcd_phase_channel1.move(525, 30) self.lcd_phase_channel1.resize(100, 50) self.lcd_phase_channel1.display(0.0) ch1_degree_label = QLabel(u"°", self) ch1_degree_label.move(630, 30) ch1_degree_label.setFont(QFont("Times", 20)) # checkbox to choose channel self.label_channel1 = QLabel(u"Kanał 1", self) self.label_channel1.move(20, 5) self.label_channel2 = QLabel(u"Kanał 2", self) self.label_channel2.move(20, 95) self.checkbox_channel1 = QCheckBox(u"Kanał 1", self) self.checkbox_channel1.move(20, 300) self.checkbox_channel2 = QCheckBox(u"Kanał 2", self) self.checkbox_channel2.move(20, 330) #LCDs and labels for second channel self.lcd_frequency_channel2 = QLCDNumber(self) self.lcd_frequency_channel2.move(20, 120) self.lcd_frequency_channel2.resize(260, 50) self.lcd_frequency_channel2.display(100.0) self.lcd_frequency_channel2.setDigitCount(11) self.f2_label = QLabel("MHz", self) self.f2_label.move(285, 130) self.f2_label.setFont(QFont("Times", 20)) self.lcd_power_channel2 = QLCDNumber(self) self.lcd_power_channel2.move(350, 120) self.lcd_power_channel2.resize(100, 50) self.lcd_power_channel2.display(0.0) ch2_dbm_label = QLabel("dBm", self) ch2_dbm_label.move(455, 130) ch2_dbm_label.setFont(QFont("Times", 20)) self.lcd_phase_channel2 = QLCDNumber(self) self.lcd_phase_channel2.move(525, 120) self.lcd_phase_channel2.resize(100, 50) self.lcd_phase_channel2.display(0.0) ch2_degree_label = QLabel(u"°", self) ch2_degree_label.move(630, 120) ch2_degree_label.setFont(QFont("Times", 20)) # textbox to edit to set generator parameters self.textbox_frequency_set = QLineEdit(self) self.textbox_frequency_set.move(20, 220) self.textbox_frequency_set.resize(200, 40) self.textbox_power_set = QLineEdit(self) self.textbox_power_set.move(350, 220) self.textbox_power_set.resize(100, 40) label_frequency = QLabel(u"Częstotliwość", self) label_frequency.move(20, 195) label_frequency.adjustSize() label_power = QLabel("Moc", self) label_power.move(350, 195) label_dbm = QLabel("dBm", self) label_dbm.move(455, 220) label_phase = QLabel(u"Przesunięcie fazy", self) label_phase.move(525, 195) label_phase.adjustSize() self.textbox_phase_set = QLineEdit(self) self.textbox_phase_set.move(525, 220) self.textbox_phase_set.resize(100, 40) label_Hz = QLabel("Hz", self) label_Hz.move(230, 220) # regular expression for settings reg_exp_freq = QRegExp( "[0-9]{0,4}[.]{0,1}[0-9]{0,6}[kMG]" ) # 4 digits before dot, 6 after, must end with k,M or G gen_validator = QRegExpValidator(reg_exp_freq, self.textbox_frequency_set) self.textbox_frequency_set.setValidator(gen_validator) # regex for power settings reg_exp_power = QRegExp("[-]*[0-9]+[.]*[0-9]{2}") gen_validator = QRegExpValidator(reg_exp_power, self.textbox_power_set) self.textbox_power_set.setValidator(gen_validator) # regex for phase settings phase_validator = QRegExpValidator(QRegExp("[0-9]+[.]*[0-9]"), self.textbox_phase_set) self.textbox_phase_set.setValidator(phase_validator) # button for refresh available serial ports self.ports_button = QPushButton(u"Odśwież porty", self) self.ports_button.move(400, 400) self.ports_button.clicked.connect(self.refresh_ports) self.ports_button.adjustSize() # button to set generator self.activate_button = QPushButton("Ustaw", self) self.activate_button.move(300, 400) # thread creation and signals and slots connection self.generator_thread = QThread() self.generator_worker = GeneratorWorker() self.generator_worker.moveToThread(self.generator_thread) self.activate_button.clicked.connect( self.get_user_input_and_send_to_generator) self.send_to_generator.connect( self.generator_worker.send_settings_to_generator) self.generator_worker.set_display.connect(self.show_on_display) self.generator_worker.event_occured.connect(self.show_event) self.generator_thread.start() self.show() def show_on_display(self, setting: str): if setting == "frequency": user_freq_set = self.textbox_frequency_set.text() self.lcd_frequency_channel2.display( user_freq_set[0:len(user_freq_set) - 1]) self.f2_label.setText( GeneratorWorker.freq_dict[user_freq_set[len(user_freq_set) - 1]]) elif setting == "power": self.lcd_power_channel2.display(self.textbox_power_set.text()) elif setting == "phase": self.lcd_phase_channel2.display(self.textbox_phase_set.text()) def show_event(self, message): QMessageBox.about(self, "Komunikat", message) def get_user_input_and_send_to_generator(self): user_freq = self.textbox_frequency_set.text() user_pwr = self.textbox_power_set.text() user_ph = self.textbox_phase_set.text() current_port = str(self.port_select.currentText()) active_channels = (self.checkbox_channel1.isChecked(), self.checkbox_channel2.isChecked()) self.send_to_generator.emit(current_port, active_channels, user_freq, user_pwr, user_ph) def refresh_ports(self): self.port_select.clear() self.port_select.addItems(genserialport.list_ports())
class Window(QMainWindow): """Class for making a GUI for a data anlysis program for single quantum dot spectroscopy. The Class creates a gui with 3 tabs to view several 2d maps of the CCD image, the spectrum of quantum dots and to see histograms of the FWHM and central energy of all the quantum dots in the PL-image. """ def __init__(self): """Initializes global variables and creates the frame of the application.""" super().__init__() self.corr_file_loaded = False self.files_loaded = False self.data_is_available = False self.counter = 0 self.all_files_data = [] self.FWHM_hist_data = [] self.central_energy_hist_data = [] self.titles = [ "Raw data", "No background noise, non-corrected data", "Raw corrected data", "No background noise, corrected data" ] # Setting geometry self.setGeometry(100, 50, 1700, 900) # Setting title self.window = QMainWindow(self) self.setCentralWidget(self.window) self.setWindowTitle("Single Quantum Dot Spectroscopy") # Calling method self.UiComponents() # Showing all the widgets self.show() def UiComponents(self): """Method for creating UI components such as tabs, color maps and sidepanel items. This method specifically includes a color map for 2d maps, 3 tabbed windows (one for 2d maps, one for graphs and one for histograms) and a sidepanel containing options to select files and to fill in measurement settings. """ # Creating a widget object widget = QWidget() # Setting configuration options pg.setConfigOptions(antialias=True) # --- Color map (for 2d maps) --- self.colors = [(68.08602, 1.24287, 84.000825), (64.75342500000001, 67.63977, 135.145665), (41.724374999999995, 120.13891500000001, 142.32774), (34.34646, 167.95218, 132.000495), (121.76352, 209.46821999999997, 81.139725), (253.27824, 231.070035, 36.703680000000006)] self.cmap = pg.ColorMap(pos=np.linspace(0.0, 1.0, 6), color=self.colors) # -------------------------------- # Creating a grid layout and adding plots to grid layout = QHBoxLayout() file_box = QGroupBox("Load Files") settings_box = QGroupBox("Measurement Settings") # --- Tabbed windows --- # Initialize tabs tabwidget = QTabWidget() tabwidget.setMinimumWidth(1200) tabwidget.setMaximumWidth(1201) self.tab1 = QWidget() self.tab2 = QWidget() self.tab3 = QWidget() # Add tabs to tab widget tabwidget.addTab(self.tab1, "2d maps") tabwidget.addTab(self.tab2, "Data fitting") tabwidget.addTab(self.tab3, "Histogram") # Create first tab self.tab1.layout = QGridLayout() self.tab2.layout = QGridLayout() self.tab3.layout = QVBoxLayout() self.tab3.top_layout = QHBoxLayout() self.tab3.bottom_layout = QHBoxLayout() self.tab3.layout.addLayout(self.tab3.top_layout) self.tab3.layout.addLayout(self.tab3.bottom_layout) # Add layouts to tabs self.tab1.setLayout(self.tab1.layout) self.tab2.setLayout(self.tab2.layout) self.tab3.setLayout(self.tab3.layout) # ---------------------- # --- User interface Sidepanel --- # Create sidepanel items self.files_combobox = QComboBox() self.files_combobox.currentIndexChanged.connect(self.update_plots) # Buttons / status updates self.button_groupbox = QGroupBox() self.file_label = QLabel("Select file for analysis") self.open_files_button = QPushButton("Load Files", default=False, autoDefault=False) self.open_files_button.clicked.connect(self.load_files) self.open_corr_file_button = QPushButton("Load Correction File", default=False, autoDefault=False) self.open_corr_file_button.clicked.connect(self.load_corr_file) self.corr_file_status = QLineEdit() self.corr_file_status.setReadOnly(True) self.corr_file_status.setText("No correction file is loaded") self.files_status = QLineEdit() self.files_status.setReadOnly(True) self.files_status.setText("No files loaded") self.run_analysis_button = QPushButton("Run Analysis") self.run_analysis_button.clicked.connect(self.start_analysis) self.pbar = QProgressBar() # Measurement settings user interface self.lower_wavelength_label = QLabel("Lower wavelength (in nm)") self.lower_wavelength_dspinbox = QDoubleSpinBox() self.lower_wavelength_dspinbox.setMaximum(1000000) self.lower_wavelength_dspinbox.setDecimals(8) self.lower_wavelength_dspinbox.setValue(610.00929128) self.upper_wavelength_label = QLabel("Upper wavelength (in nm)") self.upper_wavelength_dspinbox = QDoubleSpinBox() self.upper_wavelength_dspinbox.setMaximum(1000000) self.upper_wavelength_dspinbox.setDecimals(8) self.upper_wavelength_dspinbox.setValue(886.93139111) self.CCD_resolution_label = QLabel( "CCD resolution of data files (x, y)") self.coordinate_label1 = QLabel("(") self.coordinate_label1.setMaximumWidth(5) self.coordinate_label2 = QLabel(",") self.coordinate_label2.setMaximumWidth(5) self.coordinate_label3 = QLabel(")") self.coordinate_label3.setMaximumWidth(5) self.CCD_resolution_x_spinbox = QSpinBox() self.CCD_resolution_x_spinbox.setMaximumWidth(60) self.CCD_resolution_x_spinbox.setMaximum(100000) self.CCD_resolution_x_spinbox.setValue(167) self.CCD_resolution_y_spinbox = QSpinBox() self.CCD_resolution_y_spinbox.setMaximumWidth(60) self.CCD_resolution_y_spinbox.setMaximum(100000) self.CCD_resolution_y_spinbox.setValue(200) self.CCD_resolution_corr_label = QLabel( "CCD resolution of correction files (x, y)") self.coordinate_label4 = QLabel("(") self.coordinate_label4.setMaximumWidth(5) self.coordinate_label5 = QLabel(",") self.coordinate_label5.setMaximumWidth(5) self.coordinate_label6 = QLabel(")") self.coordinate_label6.setMaximumWidth(5) self.CCD_resolution_corr_x_spinbox = QSpinBox() self.CCD_resolution_corr_x_spinbox.setMaximumWidth(60) self.CCD_resolution_corr_x_spinbox.setMaximum(100000) self.CCD_resolution_corr_x_spinbox.setValue(1340) self.CCD_resolution_corr_y_spinbox = QSpinBox() self.CCD_resolution_corr_y_spinbox.setMaximumWidth(60) self.CCD_resolution_corr_y_spinbox.setMaximum(100000) self.CCD_resolution_corr_y_spinbox.setValue(400) # Create sidepanel self.sidepanel = QWidget() self.sidepanel.layout = QVBoxLayout() # general layout self.sidepanel.file_layout = QVBoxLayout( ) # file selection layout (for groupbox) self.sidepanel.select_file_layout = QFormLayout( ) # sublayout for drop down menu self.sidepanel.settings_layout = QVBoxLayout() # settings layout self.sidepanel.settings_layout1 = QFormLayout( ) # sublayout for wavelength settings self.sidepanel.settings_layout2 = QGridLayout( ) # sublayout for CCD settings self.sidepanel.run_analysis_layout = QVBoxLayout( ) # sublayout for analysis button and pbar self.sidepanel.file_layout.addWidget(self.open_corr_file_button) self.sidepanel.file_layout.addWidget(self.corr_file_status) self.sidepanel.file_layout.addWidget(self.open_files_button) self.sidepanel.file_layout.addWidget(self.files_status) self.sidepanel.file_layout.addLayout(self.sidepanel.select_file_layout) file_box.setLayout(self.sidepanel.file_layout) self.sidepanel.layout.addWidget(file_box) self.sidepanel.layout.addSpacing(20) self.sidepanel.layout.addWidget(settings_box) self.sidepanel.layout.addSpacing(20) self.sidepanel.run_analysis_layout.addWidget(self.run_analysis_button) self.sidepanel.layout.addLayout(self.sidepanel.run_analysis_layout) self.sidepanel.select_file_layout.addRow(self.file_label, self.files_combobox) self.sidepanel.settings_layout1.addRow(self.lower_wavelength_label, self.lower_wavelength_dspinbox) self.sidepanel.settings_layout1.addRow(self.upper_wavelength_label, self.upper_wavelength_dspinbox) self.sidepanel.settings_layout2.addWidget(self.CCD_resolution_label, 0, 0) self.sidepanel.settings_layout2.addWidget(self.coordinate_label1, 0, 1) self.sidepanel.settings_layout2.addWidget( self.CCD_resolution_x_spinbox, 0, 2) self.sidepanel.settings_layout2.addWidget(self.coordinate_label2, 0, 3) self.sidepanel.settings_layout2.addWidget( self.CCD_resolution_y_spinbox, 0, 4) self.sidepanel.settings_layout2.addWidget(self.coordinate_label3, 0, 5) self.sidepanel.settings_layout2.addWidget( self.CCD_resolution_corr_label, 1, 0) self.sidepanel.settings_layout2.addWidget(self.coordinate_label4, 1, 1) self.sidepanel.settings_layout2.addWidget( self.CCD_resolution_corr_x_spinbox, 1, 2) self.sidepanel.settings_layout2.addWidget(self.coordinate_label5, 1, 3) self.sidepanel.settings_layout2.addWidget( self.CCD_resolution_corr_y_spinbox, 1, 4) self.sidepanel.settings_layout2.addWidget(self.coordinate_label6, 1, 5) self.sidepanel.settings_layout.addLayout( self.sidepanel.settings_layout1) self.sidepanel.settings_layout.addLayout( self.sidepanel.settings_layout2) settings_box.setLayout(self.sidepanel.settings_layout) self.sidepanel.layout.insertSpacing(0, 5) self.sidepanel.layout.addStretch() self.sidepanel.setLayout(self.sidepanel.layout) # --------------------------------- # Add tab widget and sidepanel to central widget layout.addWidget(tabwidget) layout.addWidget(self.sidepanel) # Stting this layout to the widget widget.setLayout(layout) # Setting this widget as central widget of the main widow self.setCentralWidget(widget) def load_corr_file(self): """Method for loading in the correction file.""" # Dialog window self.meas_corr_curve_file_path, _ = QFileDialog.getOpenFileName( filter="CSV files(*.csv)") if self.meas_corr_curve_file_path != '': # Status box update shortfilename = get_file_name_from_path( self.meas_corr_curve_file_path) self.corr_file_status.setText( f"Succesfully loaded {shortfilename}") self.files_status.setText("No files loaded") self.corr_file_loaded = True else: self.corr_file_status.setText("No correction file is loaded") self.corr_file_loaded = False def load_files(self): """Method for loading in data files.""" # Dialog window self.filenames, _ = QFileDialog.getOpenFileNames( filter="CSV files(*.csv)") # Dropdown menu self.shortfilenames = [] for filename in self.filenames: shortfilename = get_file_name_from_path(filename) self.shortfilenames.append(shortfilename) self.files_combobox.clear() self.files_combobox.addItems(self.shortfilenames) # Update status if len(self.filenames) > 0: self.files_status.setText(f"Succesfully loaded files") self.files_loaded = True else: self.files_status.setText(f"No files loaded") self.files_loaded = False self.clear_plots(self.tab1.layout) self.clear_plots(self.tab2.layout) if self.tab3.top_layout.count() > 1: self.clear_plots(self.tab3.sidepanel_top) self.tab3.top_layout.removeItem(self.tab3.sidepanel_top) self.clear_plots(self.tab3.top_layout) self.clear_plots(self.tab3.sidepanel_bottom) self.tab3.bottom_layout.removeItem(self.tab3.sidepanel_bottom) self.clear_plots(self.tab3.bottom_layout) def get_spinbox_values(self): """Method to retreive the current values of the measurement spinboxes. Returns: All the values in the spinboxes, contained in a tuple. """ self.CCD_width = self.CCD_resolution_x_spinbox.value() self.CCD_height = self.CCD_resolution_y_spinbox.value() self.CCD_width_corr = self.CCD_resolution_corr_x_spinbox.value() self.CCD_height_corr = self.CCD_resolution_corr_y_spinbox.value() self.lower_wavelength = self.lower_wavelength_dspinbox.value() self.upper_wavelength = self.upper_wavelength_dspinbox.value() return self.CCD_width, self.CCD_height, self.CCD_width_corr, self.CCD_height_corr, self.lower_wavelength, self.upper_wavelength def start_analysis(self): """Method for running the analysis on the files. This method starts a worker thread for the data analysis on the data files, and adds a progress bar to the GUI when the data is being analyzed. """ if self.corr_file_loaded == True and self.files_loaded == True: self.CCD_width, self.CCD_height, self.CCD_width_corr, self.CCD_height_corr, self.lower_wavelength, self.upper_wavelength = self.get_spinbox_values( ) self.sidepanel.run_analysis_layout.addWidget(self.pbar) self.thread = QThread() self.worker = Worker() self.worker.moveToThread(self.thread) def start_long_func(): self.all_files_data, self.FWHM_hist_data, self.central_energy_hist_data, = self.worker.run( self.CCD_width, self.CCD_height, self.CCD_width_corr, self.CCD_height_corr, self.lower_wavelength, self.upper_wavelength, self.filenames, self.meas_corr_curve_file_path) self.thread.started.connect(start_long_func) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.thread.finished.connect(self.thread.deleteLater) self.worker.progress.connect(self.report_progress) self.thread.start() self.run_analysis_button.setEnabled(False) self.thread.finished.connect( lambda: self.run_analysis_button.setEnabled(True)) def set_boolean(): self.data_is_available = True def remove_pbar(): self.pbar.setParent(None) self.thread.finished.connect(remove_pbar) self.thread.finished.connect(set_boolean) self.thread.finished.connect(self.update_plots) def update_plots(self): """Method for updating plot widgets. This method creates the plot items for the 2d maps and the QDot graphs. """ if self.data_is_available is True: file_index = self.files_combobox.currentIndex() file_data = self.all_files_data[file_index] self.mapdata = [file_data[i].values for i in range(4)] self.Q_Dot_plot_data = file_data[4] for i in reversed(range(self.tab1.layout.count())): self.tab1.layout.itemAt(i).widget().setParent(None) # Create ticks for x axis tick_strings_lower = floor( file_data[0].reset_index()['index'].loc[0] * 10) / 10 tick_strings_upper = ceil( file_data[0].reset_index()['index'].loc[self.CCD_width - 1] * 10) / 10 tick_strings = np.arange(tick_strings_lower, tick_strings_upper, -0.1) energies = file_data[0].reset_index()['index'].to_numpy() tick_values = [] for E in tick_strings: tick_value = (E - energies[0]) * (self.CCD_width / (energies[-1] - energies[0])) tick_values.append(tick_value) tick_tuples = [] for i in range(len(tick_values)): tick_tuples.append( (float(tick_values[i]), "{:.1f}".format(tick_strings[i]))) for i in reversed(range(self.tab2.layout.count())): self.tab2.layout.itemAt(i).widget().setParent(None) # Create 2d maps image views rows = [1, 1, 4, 4] columns = [1, 2, 1, 2] plots_2dmap = {} axis_2dmap = {} imv_2dmap = {} for i in range(4): axis_2dmap[i] = pg.AxisItem('bottom') axis_2dmap[i].setTicks([tick_tuples]) plots_2dmap[i] = pg.PlotItem( title=self.titles[i], axisItems={"bottom": axis_2dmap[i]}) plots_2dmap[i].setLabel(axis='left', text='Slit position') plots_2dmap[i].setLabel(axis='bottom', text='Energy (eV)') imv_2dmap[i] = pg.ImageView(view=plots_2dmap[i]) imv_2dmap[i].setImage(self.mapdata[i]) imv_2dmap[i].setColorMap(self.cmap) # imv_2dmap[i].ui.histogram.hide() imv_2dmap[i].ui.roiBtn.hide() imv_2dmap[i].ui.menuBtn.hide() # Add plots to layout of tab1 self.tab1.layout.addWidget(imv_2dmap[i], rows[i], columns[i], 3, 1) # Create plot items for each QDot self.Q_Dot_plot_data_arr = self.Q_Dot_plot_data.swapaxes( 'index', 'columns').to_numpy() column_headers = list(self.Q_Dot_plot_data.columns) counter = 1 plots_Qdot = {} axis_Qdot = {} for QdotIndex in range(0, len(self.Q_Dot_plot_data_arr), 2): row = floor((counter - 1) / 3) column = counter - ((row * 3)) - 1 axis_Qdot[QdotIndex / 2] = pg.AxisItem('bottom') axis_Qdot[QdotIndex / 2].setTicks([tick_tuples]) plots_Qdot[QdotIndex / 2] = pg.PlotWidget( title=f"Slit position: {column_headers[QdotIndex]}", axisItems={"bottom": axis_Qdot[QdotIndex / 2]}) plots_Qdot[QdotIndex / 2].addLegend() plots_Qdot[QdotIndex / 2].plot( self.Q_Dot_plot_data_arr[QdotIndex], symbol="o", symbolSize=6, pen=None, name="PL-spectrum") plots_Qdot[QdotIndex / 2].plot( self.Q_Dot_plot_data_arr[QdotIndex + 1], pen=pg.mkPen('r'), name="Optimal gaussian fit") plots_Qdot[QdotIndex / 2].setLabel(axis='left', text='Intensity') plots_Qdot[QdotIndex / 2].setLabel(axis='bottom', text='Energy (eV)') # Add plots to layout of tab2 self.tab2.layout.addWidget(plots_Qdot[QdotIndex / 2], row, column, 1, 1) counter += 1 if self.tab3.top_layout.count() == 0: self.make_histogram() def clear_plots(self, layout): for i in reversed(range(layout.count())): layout.itemAt(i).widget().setParent(None) def make_histogram(self): """Method for creating the FWHM and Central energy histograms.""" # Create sidepanel for top histogram self.tab3.sidepanel_top = QFormLayout(self) self.FWHM_bin_spinbox = QSpinBox() self.FWHM_bin_spinbox.setRange(1, 100) self.FWHM_bin_spinbox.setValue(30) self.FWHM_bin_spinbox.valueChanged.connect(self.update_histograms) self.FWHM_min_spinbox = QDoubleSpinBox() self.FWHM_min_spinbox.setDecimals(2) self.FWHM_min_spinbox.setRange(0.00, 999.99) self.FWHM_min_spinbox.setSingleStep(0.1) self.FWHM_min_spinbox.setValue(0) self.FWHM_min_spinbox.valueChanged.connect(self.update_histograms) self.FWHM_max_spinbox = QDoubleSpinBox() self.FWHM_max_spinbox.setDecimals(2) self.FWHM_max_spinbox.setRange(0.01, 1000.00) self.FWHM_max_spinbox.setSingleStep(0.1) self.FWHM_max_spinbox.setValue(1000.00) self.FWHM_max_spinbox.valueChanged.connect(self.update_histograms) self.tab3.sidepanel_top.addRow(QLabel("Bins:"), self.FWHM_bin_spinbox) self.tab3.sidepanel_top.addRow(QLabel("Minimum FWHM:"), self.FWHM_min_spinbox) self.tab3.sidepanel_top.addRow(QLabel("Maximum FWHM:"), self.FWHM_max_spinbox) # Create histogram for FWHM self.FWHM_hist = pg.PlotWidget(title="FWHM histogram of all QDots") FWHM_bins = self.FWHM_bin_spinbox.value() FWHM_min = self.FWHM_min_spinbox.value() FWHM_max = self.FWHM_max_spinbox.value() x, y, x_new, best_fit = QDot_spectroscopy_Model.histogram( self.FWHM_hist_data, FWHM_bins, FWHM_min, FWHM_max) FWHM_curve = pg.PlotCurveItem(x, y, stepMode=True, fillLevel=0, brush=(0, 0, 255, 80)) FWHM_fit = pg.PlotDataItem(x_new, best_fit, pen=pg.mkPen('r')) self.FWHM_hist.addItem(FWHM_curve) self.FWHM_hist.addItem(FWHM_fit) self.FWHM_hist.setLabel(axis='left', text='Frequency') self.FWHM_hist.setLabel(axis='bottom', text='FWHM (eV)') self.tab3.top_layout.addWidget(self.FWHM_hist) self.tab3.top_layout.addLayout(self.tab3.sidepanel_top) # Create sidepanel for bottom histogram self.tab3.sidepanel_bottom = QFormLayout(self) self.c_energy_bin_spinbox = QSpinBox() self.c_energy_bin_spinbox.setRange(1, 100) self.c_energy_bin_spinbox.setValue(30) self.c_energy_bin_spinbox.valueChanged.connect(self.update_histograms) self.c_energy_min_spinbox = QDoubleSpinBox() self.c_energy_min_spinbox.setDecimals(2) self.c_energy_min_spinbox.setRange(-1000.00, 999.99) self.c_energy_min_spinbox.setSingleStep(0.1) self.c_energy_min_spinbox.setValue(-100) self.c_energy_min_spinbox.valueChanged.connect(self.update_histograms) self.c_energy_max_spinbox = QDoubleSpinBox() self.c_energy_max_spinbox.setDecimals(2) self.c_energy_max_spinbox.setRange(0.01, 1000.00) self.c_energy_max_spinbox.setSingleStep(0.1) self.c_energy_max_spinbox.setValue(1000.00) self.c_energy_max_spinbox.valueChanged.connect(self.update_histograms) self.tab3.sidepanel_bottom.addRow(QLabel("Bins:"), self.c_energy_bin_spinbox) self.tab3.sidepanel_bottom.addRow(QLabel("Minimum central energy:"), self.c_energy_min_spinbox) self.tab3.sidepanel_bottom.addRow(QLabel("Maximum central energy:"), self.c_energy_max_spinbox) # Create histogram for central energies self.c_energy_hist = pg.PlotWidget( title="Central energy histogram of all QDots") c_energy_bins = self.c_energy_bin_spinbox.value() c_energy_min = self.c_energy_min_spinbox.value() c_energy_max = self.c_energy_max_spinbox.value() x, y, x_new, best_fit = QDot_spectroscopy_Model.histogram( self.central_energy_hist_data, c_energy_bins, c_energy_min, c_energy_max) c_energy_curve = pg.PlotCurveItem(x, y, stepMode=True, fillLevel=0, brush=(0, 0, 255, 80)) c_energy_fit = pg.PlotDataItem(x_new, best_fit, pen=pg.mkPen('r')) self.c_energy_hist.addItem(c_energy_curve) self.c_energy_hist.addItem(c_energy_fit) self.c_energy_hist.setLabel(axis='left', text='Frequency') self.c_energy_hist.setLabel(axis='bottom', text='Central energy (eV)') self.tab3.bottom_layout.addWidget(self.c_energy_hist) self.tab3.bottom_layout.addLayout(self.tab3.sidepanel_bottom) def update_histograms(self): """Method for updating histograms based on sidepanel settings.""" self.FWHM_hist.clear() FWHM_bins = self.FWHM_bin_spinbox.value() FWHM_min = self.FWHM_min_spinbox.value() FWHM_max = self.FWHM_max_spinbox.value() x, y, x_new, best_fit = QDot_spectroscopy_Model.histogram( self.FWHM_hist_data, FWHM_bins, FWHM_min, FWHM_max) FWHM_curve = pg.PlotCurveItem(x, y, stepMode=True, fillLevel=0, brush=(0, 0, 255, 80)) FWHM_fit = pg.PlotDataItem(x_new, best_fit, pen=pg.mkPen('r')) self.FWHM_hist.addItem(FWHM_curve) self.FWHM_hist.addItem(FWHM_fit) self.c_energy_hist.clear() c_energy_bins = self.c_energy_bin_spinbox.value() c_energy_min = self.c_energy_min_spinbox.value() c_energy_max = self.c_energy_max_spinbox.value() x, y, x_new, best_fit = QDot_spectroscopy_Model.histogram( self.central_energy_hist_data, c_energy_bins, c_energy_min, c_energy_max) c_energy_curve = pg.PlotCurveItem(x, y, stepMode=True, fillLevel=0, brush=(0, 0, 255, 80)) c_energy_fit = pg.PlotDataItem(x_new, best_fit, pen=pg.mkPen('r')) self.c_energy_hist.addItem(c_energy_curve) self.c_energy_hist.addItem(c_energy_fit) def report_progress(self, n): """Method for updating the progress bar in the GUI.""" self.pbar.setValue(n)
class MusicPreviewWidget(QWidget): def __init__(self, parent=None, showProgress=True, showWaiting=False, progressHidden=False, progressHiddenWhileIdle=True, progressShowFinished=3000, showLog=True): super(MusicPreviewWidget, self).__init__(parent) self._lastbuildtime = 10.0 self._running = None self._current = None self._showLog = showLog if showLog: self._log = log.Log() self._showProgress = showProgress self._chooserLabel = QLabel() self._chooser = QComboBox(self, activated=self.selectDocument) self._view = popplerview.View() self._showWaiting = showWaiting if showWaiting: from widgets.waitingoverlay import Overlay self._waiting = Overlay(self._view) self._waiting.hide() self._stack = QStackedLayout() self._top = QWidget() layout = QVBoxLayout() self.setLayout(layout) layout.addWidget(self._top) layout.addLayout(self._stack) if self._showProgress: self._progress = widgets.progressbar.TimedProgressBar( parent=self, hidden=progressHidden, hideWhileIdle=progressHiddenWhileIdle, showFinished=progressShowFinished) layout.addWidget(self._progress) top = QHBoxLayout() top.setContentsMargins(0, 0, 0, 0) top.setSpacing(2) self._top.setLayout(top) top.addWidget(self._chooserLabel) top.addWidget(self._chooser) top.addStretch(1) if showLog: self._stack.addWidget(self._log) self._stack.addWidget(self._view) self._top.hide() app.aboutToQuit.connect(self.cleanup) app.translateUI(self) def translateUI(self): self._chooserLabel.setText(_("Document:")) def abort_running(self): """Ensures no running job is left behind. This *can* be called by the using dialog/widget.""" j = self._running if j and j.is_running(): if self._showLog: self._log.disconnectJob(j) j.done.disconnect(self._done) j.abort() def preview(self, text, title=None, base_dir=None, temp_dir='', cached=False): """Runs LilyPond on the given text and shows the resulting PDF.""" self.abort_running() if cached: self._running = j = job.lilypond.CachedPreviewJob( text, target_dir=temp_dir, base_dir=base_dir, title=title) if not self._running.needs_compilation(): self._done(None) return else: self._running = j = job.lilypond.VolatileTextJob(text, title=title) j.done.connect(self._done) if self._showLog: self._log.clear() self._log.connectJob(j) self._stack.setCurrentWidget(self._log) if self._showProgress: j.started.connect( lambda: self._progress.start(self._lastbuildtime)) self._progress.start(self._lastbuildtime) if self._showWaiting: self._waiting.start() app.job_queue().add_job(j, 'generic') def _done(self, success): # TODO: Handle failed compilation (= no file to show) if self._showProgress: self._progress.stop() if self._showWaiting: self._waiting.stop() pdfs = self._running.resultfiles() self.setDocuments(pdfs) if not pdfs and self._showLog: self._stack.setCurrentWidget(self._log) return self._lastbuildtime = self._running.elapsed_time() self._stack.setCurrentWidget(self._view) if self._current: self._current.cleanup() self._current = self._running # keep the tempdir self._running = None def setDocuments(self, pdfs): """Loads the given PDF path names in the UI.""" self._documents = [popplertools.Document(name) for name in pdfs] self._chooser.clear() self._chooser.addItems([d.name() for d in self._documents]) self._top.setVisible(len(self._documents) > 1) if pdfs: self._chooser.setCurrentIndex(0) self.selectDocument(0) else: self._view.clear() def selectDocument(self, index): doc = self._documents[index].document() if doc: self._view.load(doc) def cleanup(self): if self._running: self._running.abort() self._running.cleanup() self._running = None if self._current: self._current.cleanup() self._current = None if self._showLog: self._stack.setCurrentWidget(self._log) self._top.hide() self._view.clear() def print_(self): """Prints the currently displayed document.""" if self._documents: doc = self._documents[self._chooser.currentIndex()] import popplerprint popplerprint.printDocument(doc, self)
class MainApp(QWidget): def __init__(self): super(MainApp, self).__init__() self.setGeometry(100, 150, 700, 400) self.setWindowTitle("Bloomberg Stock Checker") self.initUI() def initUI(self): grid = QGridLayout() self.setLayout(grid) self.widgets = [] self.threads = QThreadPool() names = ['Stocks', 'stock_combobox', 'x', 'x', 'x', 'refresh', 'Name', '', 'x', 'x', 'x', 'x', 'Price', '', 'x', 'Currency', '', 'x', 'Open', '', 'Prev Close', '', 'Volume', '', 'Market Cap', '', 'Day Range', '', '52 Week Range', ''] positions = [(y, x) for y in range(5) for x in range(6)] for position, name in zip(positions, names): if name == 'x': continue elif name == '': label = QLabel() label.setText("") grid.addWidget(label, *position) self.widgets.append(label) elif "_combobox" in name: self.combobox = QComboBox() grid.addWidget(self.combobox, *position) elif 'refresh' in name: refreshBtn = QPushButton("Refresh \nData") grid.addWidget(refreshBtn, *position) refreshBtn.clicked.connect(self.refreshBtn_pressed) else: label = QLabel() label.setText(name) grid.addWidget(label, *position) self.widgets.append(label) def refreshBtn_pressed(self): requester = DataRequester(self.combobox, self.add_comboBox_item) self.threads.start(requester) #self.add_comboBox_item(self.combobox) def add_comboBox_item(self): stock_names = read_json() self.combobox.clear() for i in stock_names.keys(): self.combobox.addItem(i) self.combobox.activated[str].connect(self.check_stock) def check_stock(self, name): stock_names = read_json() data = stock_names[name] for i in range(0, len(self.widgets)): if i == 19: pass if self.widgets[i].text() != "": for k, v in data.items(): if k == self.widgets[i].text(): self.widgets[i+1].setText(v)
class AvailableSizes(QDialog): def __init__(self): super(AvailableSizes, self).__init__() self.createCombos() self.createHeader() #self.createMenuBar() self.printOut = QTextEdit() self.printOut.setFont(QFont('Helvetica', 11, QFont.Bold)) self.printOut.setReadOnly(True) mainLayout = QVBoxLayout() #mainLayout.setMenuBar(self.menuBar) mainLayout.addWidget(self.frmHeader) mainLayout.addWidget(self.grpBox) mainLayout.addWidget(self.printOut) #mainLayout.setAlignment(self.frmHeader, Qt.AlignRight) self.setLayout(mainLayout) #self.setWindowTitle("Available Sizes") self.setWindowFlags(Qt.FramelessWindowHint) bgColor = QPalette() bgColor.setColor(self.backgroundRole(), Qt.gray) self.setPalette(bgColor) self.setWindowIcon(QIcon('icon/PS_Icon.png')) self.cbSku.setFocus() def createHeader(self): blk = QPalette() blk.setColor(blk.Foreground, Qt.white) lblTitle = QLabel("Availability Checker") lblTitle.setFont(QFont("Times", 12, QFont.Bold )) lblTitle.setPalette(blk) btnClose = QToolButton() btnClose.setIcon(QIcon("icon\size_exit.png")) btnClose.setAutoRaise(True) btnClose.setIconSize(QSize(25,25)) btnClose.clicked.connect(lambda: self.close()) hbHeader = QHBoxLayout() hbHeader.addWidget(lblTitle) hbHeader.addWidget(btnClose) hbHeader.setContentsMargins(0, 0, 0, 0) self.frmHeader = QFrame() self.frmHeader.setLayout(hbHeader) def createCombos(self): cbFont = QFont("Times", 8, QFont.Bold) designs = self.getDesigns() self.grpBox = QGroupBox() self.grpBox.setFont(QFont('Times', 10, QFont.Bold)) layout = QFormLayout() self.cbSku = QComboBox() self.cbSku.addItem("Designs") self.cbSku.addItems(designs) self.cbSku.setFont(cbFont) self.cbSku.currentIndexChanged.connect(self.skuChanged) self.cbStyle = QComboBox() self.cbStyle.addItem("Styles") self.cbStyle.setFont(cbFont) self.cbStyle.currentIndexChanged.connect(self.styleChanged) layout.addRow(QLabel("Design:"), self.cbSku) layout.addRow(QLabel("Style:"), self.cbStyle) self.grpBox.setLayout(layout) def skuChanged(self): if self.cbStyle.count() > 0: self.cbStyle.clear() self.cbStyle.addItem("Style") self.cbStyle.setCurrentIndex(0) styles = self.getStyles(self.cbSku.currentText()) else: styles = self.getStyles(self.cbSku.currentText()) self.cbStyle.addItems(styles) def styleChanged(self): self.printOut.clear() sizes = self.getSizes(self.cbSku.currentText(), self.cbStyle.currentText()) if self.cbStyle.currentText() != "Styles": for i in sizes: self.printOut.insertPlainText(i + '\n') def createMenuBar(self): self.menuBar = QMenuBar() self.fileMenu = QMenu("&File", self) self.exitAction = self.fileMenu.addAction("E&xit") self.menuBar.addMenu(self.fileMenu) self.exitAction.triggered.connect(self.accept) def getDesigns(self): sd = mysql_db.mysql_connect(self) sd.execute("""SELECT DISTINCT CONCAT(d.sku_code, " - ", d.name) design FROM designs d JOIN packages p on p.design_id = d.id ORDER BY RIGHT(d.sku_code, 3), LEFT(d.sku_code,1)""") ds = sd.fetchall() lsDesigns = [] for i in ds: lsDesigns.append(i[0]) return lsDesigns def getStyles(self, sku): sd = mysql_db.mysql_connect(self) sd.execute("""SELECT DISTINCT g.name FROM garment_styles_ages g JOIN packages p ON p.garment_styles_age_id = g.id JOIN designs d ON d.id = p.design_id WHERE d.sku_code = '""" + sku[:4] + """' ORDER BY g.name""") ds = sd.fetchall() lsStyles = [] for i in ds: lsStyles.append(i[0]) return lsStyles def getSizes(self, sku, style): style = style.replace("'", "\\'") sd = mysql_db.mysql_connect(self) sd.execute(""" SELECT DISTINCT CONCAT(s.name, ' - ', c.name) size FROM sizes s JOIN packages p ON p.size_id = s.id JOIN designs d ON d.id = p.design_id JOIN colors c ON c.id = p.color_id JOIN garment_styles_ages g ON g.id = p.garment_styles_age_id WHERE d.sku_code = '""" + sku[:4] + """' AND g.name = '""" + style + """'""") ds = sd.fetchall() lsSizes = [] for i in ds: lsSizes.append(i[0]) return lsSizes def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.leftClick = True self.offset = event.pos() def mouseMoveEvent(self, event): if self.leftClick == True: x=event.globalX() y=event.globalY() x_w = self.offset.x() y_w = self.offset.y() self.move(x-x_w, y-y_w) def mouseReleaseEvent(self, event): self.leftClick = False
class RangeSelector(QWidget): __LOG: Logger = LogHelper.logger("RangeSelector") def __init__(self, parent=None): super().__init__(parent) self.__init_ui__() def __init_ui__(self): layout = QHBoxLayout() from_layout = QVBoxLayout() from_layout.addWidget(QLabel("From:")) self.__from_select = QComboBox(self) # TODO get ignored for certain styles, like Mac, when not editable # TODO possibly allow editable but make it jump to item instead of adding to list? self.__from_select.setMaxVisibleItems(20) self.__from_select.currentIndexChanged.connect( self.__handle_from_changed) from_layout.addWidget(self.__from_select) layout.addLayout(from_layout) to_layout = QVBoxLayout() to_layout.addWidget(QLabel("To:")) self.__to_select = QComboBox(self) # TODO get ignored for certain styles, like Mac, when not editable # TODO possibly allow editable but make it jump to item instead of adding to list? self.__to_select.setMaxVisibleItems(20) self.__to_select.currentIndexChanged.connect(self.__handle_to_changed) to_layout.addWidget(self.__to_select) layout.addLayout(to_layout) self.setLayout(layout) @pyqtSlot(int) def __handle_from_changed(self, index: int): RangeSelector.__LOG.debug("from index changed to: {0}".format(index)) if self.__to_select.currentIndex() < index: self.__to_select.setCurrentIndex(index) @pyqtSlot(int) def __handle_to_changed(self, index: int): RangeSelector.__LOG.debug("to index changed to: {0}".format(index)) if self.__from_select.currentIndex() > index: self.__from_select.setCurrentIndex(index) def clear(self): self.__from_select.clear() self.__to_select.clear() def from_value(self) -> int: return int(self.__from_select.currentText()) def to_value(self) -> int: return int(self.__to_select.currentText()) def set_range(self, start: int, end: int): if end <= start: raise ValueError("end value must be greater than start") self.__from_select.currentIndexChanged.disconnect( self.__handle_from_changed) self.__to_select.currentIndexChanged.disconnect( self.__handle_to_changed) index = 0 for item in range(start, end): self.__from_select.insertItem(index, str(item)) self.__to_select.insertItem(index, str(item + 1)) index += 1 self.__from_select.setCurrentIndex(0) self.__to_select.setCurrentIndex(end - 2) self.__from_select.currentIndexChanged.connect( self.__handle_from_changed) self.__to_select.currentIndexChanged.connect(self.__handle_to_changed)
class DebugViewer(QWidget): """ Class implementing a widget conatining various debug related views. The individual tabs contain the interpreter shell (optional), the filesystem browser (optional), the two variables viewers (global and local), a breakpoint viewer, a watch expression viewer and the exception logger. Additionally a list of all threads is shown. @signal sourceFile(string, int) emitted to open a source file at a line """ sourceFile = pyqtSignal(str, int) def __init__(self, debugServer, docked, vm, parent=None, embeddedShell=True, embeddedBrowser=True): """ Constructor @param debugServer reference to the debug server object @param docked flag indicating a dock window @param vm reference to the viewmanager object @param parent parent widget (QWidget) @param embeddedShell flag indicating whether the shell should be included. This flag is set to False by those layouts, that have the interpreter shell in a separate window. @param embeddedBrowser flag indicating whether the file browser should be included. This flag is set to False by those layouts, that have the file browser in a separate window or embedded in the project browser instead. """ super(DebugViewer, self).__init__(parent) self.debugServer = debugServer self.debugUI = None self.setWindowIcon(UI.PixmapCache.getIcon("eric.png")) self.__mainLayout = QVBoxLayout() self.__mainLayout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.__mainLayout) self.__tabWidget = E5TabWidget() self.__mainLayout.addWidget(self.__tabWidget) self.embeddedShell = embeddedShell if embeddedShell: from QScintilla.Shell import ShellAssembly # add the interpreter shell self.shellAssembly = ShellAssembly(debugServer, vm, False) self.shell = self.shellAssembly.shell() index = self.__tabWidget.addTab( self.shellAssembly, UI.PixmapCache.getIcon("shell.png"), '') self.__tabWidget.setTabToolTip(index, self.shell.windowTitle()) self.embeddedBrowser = embeddedBrowser if embeddedBrowser: from UI.Browser import Browser # add the browser self.browser = Browser() index = self.__tabWidget.addTab( self.browser, UI.PixmapCache.getIcon("browser.png"), '') self.__tabWidget.setTabToolTip(index, self.browser.windowTitle()) from .VariablesViewer import VariablesViewer # add the global variables viewer self.glvWidget = QWidget() self.glvWidgetVLayout = QVBoxLayout(self.glvWidget) self.glvWidgetVLayout.setContentsMargins(0, 0, 0, 0) self.glvWidgetVLayout.setSpacing(3) self.glvWidget.setLayout(self.glvWidgetVLayout) self.globalsViewer = VariablesViewer(self.glvWidget, True) self.glvWidgetVLayout.addWidget(self.globalsViewer) self.glvWidgetHLayout = QHBoxLayout() self.glvWidgetHLayout.setContentsMargins(3, 3, 3, 3) self.globalsFilterEdit = QLineEdit(self.glvWidget) self.globalsFilterEdit.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Fixed) self.glvWidgetHLayout.addWidget(self.globalsFilterEdit) self.globalsFilterEdit.setToolTip( self.tr("Enter regular expression patterns separated by ';'" " to define variable filters. ")) self.globalsFilterEdit.setWhatsThis( self.tr("Enter regular expression patterns separated by ';'" " to define variable filters. All variables and" " class attributes matched by one of the expressions" " are not shown in the list above.")) self.setGlobalsFilterButton = QPushButton( self.tr('Set'), self.glvWidget) self.glvWidgetHLayout.addWidget(self.setGlobalsFilterButton) self.glvWidgetVLayout.addLayout(self.glvWidgetHLayout) index = self.__tabWidget.addTab( self.glvWidget, UI.PixmapCache.getIcon("globalVariables.png"), '') self.__tabWidget.setTabToolTip(index, self.globalsViewer.windowTitle()) self.setGlobalsFilterButton.clicked.connect( self.__setGlobalsFilter) self.globalsFilterEdit.returnPressed.connect(self.__setGlobalsFilter) # add the local variables viewer self.lvWidget = QWidget() self.lvWidgetVLayout = QVBoxLayout(self.lvWidget) self.lvWidgetVLayout.setContentsMargins(0, 0, 0, 0) self.lvWidgetVLayout.setSpacing(3) self.lvWidget.setLayout(self.lvWidgetVLayout) self.lvWidgetHLayout1 = QHBoxLayout() self.lvWidgetHLayout1.setContentsMargins(3, 3, 3, 3) self.stackComboBox = QComboBox(self.lvWidget) self.stackComboBox.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Fixed) self.lvWidgetHLayout1.addWidget(self.stackComboBox) self.sourceButton = QPushButton(self.tr('Source'), self.lvWidget) self.lvWidgetHLayout1.addWidget(self.sourceButton) self.sourceButton.setEnabled(False) self.lvWidgetVLayout.addLayout(self.lvWidgetHLayout1) self.localsViewer = VariablesViewer(self.lvWidget, False) self.lvWidgetVLayout.addWidget(self.localsViewer) self.lvWidgetHLayout2 = QHBoxLayout() self.lvWidgetHLayout2.setContentsMargins(3, 3, 3, 3) self.localsFilterEdit = QLineEdit(self.lvWidget) self.localsFilterEdit.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Fixed) self.lvWidgetHLayout2.addWidget(self.localsFilterEdit) self.localsFilterEdit.setToolTip( self.tr( "Enter regular expression patterns separated by ';' to define " "variable filters. ")) self.localsFilterEdit.setWhatsThis( self.tr( "Enter regular expression patterns separated by ';' to define " "variable filters. All variables and class attributes matched" " by one of the expressions are not shown in the list above.")) self.setLocalsFilterButton = QPushButton( self.tr('Set'), self.lvWidget) self.lvWidgetHLayout2.addWidget(self.setLocalsFilterButton) self.lvWidgetVLayout.addLayout(self.lvWidgetHLayout2) index = self.__tabWidget.addTab( self.lvWidget, UI.PixmapCache.getIcon("localVariables.png"), '') self.__tabWidget.setTabToolTip(index, self.localsViewer.windowTitle()) self.sourceButton.clicked.connect(self.__showSource) self.stackComboBox.currentIndexChanged[int].connect( self.__frameSelected) self.setLocalsFilterButton.clicked.connect(self.__setLocalsFilter) self.localsFilterEdit.returnPressed.connect(self.__setLocalsFilter) from .CallStackViewer import CallStackViewer # add the call stack viewer self.callStackViewer = CallStackViewer(self.debugServer) index = self.__tabWidget.addTab( self.callStackViewer, UI.PixmapCache.getIcon("step.png"), "") self.__tabWidget.setTabToolTip( index, self.callStackViewer.windowTitle()) self.callStackViewer.sourceFile.connect(self.sourceFile) self.callStackViewer.frameSelected.connect( self.__callStackFrameSelected) from .CallTraceViewer import CallTraceViewer # add the call trace viewer self.callTraceViewer = CallTraceViewer(self.debugServer) index = self.__tabWidget.addTab( self.callTraceViewer, UI.PixmapCache.getIcon("callTrace.png"), "") self.__tabWidget.setTabToolTip( index, self.callTraceViewer.windowTitle()) self.callTraceViewer.sourceFile.connect(self.sourceFile) from .BreakPointViewer import BreakPointViewer # add the breakpoint viewer self.breakpointViewer = BreakPointViewer() self.breakpointViewer.setModel(self.debugServer.getBreakPointModel()) index = self.__tabWidget.addTab( self.breakpointViewer, UI.PixmapCache.getIcon("breakpoints.png"), '') self.__tabWidget.setTabToolTip( index, self.breakpointViewer.windowTitle()) self.breakpointViewer.sourceFile.connect(self.sourceFile) from .WatchPointViewer import WatchPointViewer # add the watch expression viewer self.watchpointViewer = WatchPointViewer() self.watchpointViewer.setModel(self.debugServer.getWatchPointModel()) index = self.__tabWidget.addTab( self.watchpointViewer, UI.PixmapCache.getIcon("watchpoints.png"), '') self.__tabWidget.setTabToolTip( index, self.watchpointViewer.windowTitle()) from .ExceptionLogger import ExceptionLogger # add the exception logger self.exceptionLogger = ExceptionLogger() index = self.__tabWidget.addTab( self.exceptionLogger, UI.PixmapCache.getIcon("exceptions.png"), '') self.__tabWidget.setTabToolTip( index, self.exceptionLogger.windowTitle()) if self.embeddedShell: self.__tabWidget.setCurrentWidget(self.shellAssembly) else: if self.embeddedBrowser: self.__tabWidget.setCurrentWidget(self.browser) else: self.__tabWidget.setCurrentWidget(self.glvWidget) # add the threads viewer self.__mainLayout.addWidget(QLabel(self.tr("Threads:"))) self.__threadList = QTreeWidget() self.__threadList.setHeaderLabels( [self.tr("ID"), self.tr("Name"), self.tr("State"), ""]) self.__threadList.setSortingEnabled(True) self.__mainLayout.addWidget(self.__threadList) self.__doThreadListUpdate = True self.__threadList.currentItemChanged.connect(self.__threadSelected) self.__mainLayout.setStretchFactor(self.__tabWidget, 5) self.__mainLayout.setStretchFactor(self.__threadList, 1) self.currPage = None self.currentStack = None self.framenr = 0 self.debugServer.clientStack.connect(self.handleClientStack) self.__autoViewSource = Preferences.getDebugger("AutoViewSourceCode") self.sourceButton.setVisible(not self.__autoViewSource) def preferencesChanged(self): """ Public slot to handle the preferencesChanged signal. """ self.__autoViewSource = Preferences.getDebugger("AutoViewSourceCode") self.sourceButton.setVisible(not self.__autoViewSource) def setDebugger(self, debugUI): """ Public method to set a reference to the Debug UI. @param debugUI reference to the DebugUI object (DebugUI) """ self.debugUI = debugUI self.debugUI.clientStack.connect(self.handleClientStack) self.callStackViewer.setDebugger(debugUI) def handleResetUI(self): """ Public method to reset the SBVviewer. """ self.globalsViewer.handleResetUI() self.localsViewer.handleResetUI() self.__setGlobalsFilter() self.__setLocalsFilter() self.sourceButton.setEnabled(False) self.currentStack = None self.stackComboBox.clear() self.__threadList.clear() if self.embeddedShell: self.__tabWidget.setCurrentWidget(self.shellAssembly) else: if self.embeddedBrowser: self.__tabWidget.setCurrentWidget(self.browser) else: self.__tabWidget.setCurrentWidget(self.glvWidget) self.breakpointViewer.handleResetUI() def handleRawInput(self): """ Public slot to handle the switch to the shell in raw input mode. """ if self.embeddedShell: self.saveCurrentPage() self.__tabWidget.setCurrentWidget(self.shellAssembly) def initCallStackViewer(self, projectMode): """ Public method to initialize the call stack viewer. @param projectMode flag indicating to enable the project mode (boolean) """ self.callStackViewer.clear() self.callStackViewer.setProjectMode(projectMode) def isCallTraceEnabled(self): """ Public method to get the state of the call trace function. @return flag indicating the state of the call trace function (boolean) """ return self.callTraceViewer.isCallTraceEnabled() def clearCallTrace(self): """ Public method to clear the recorded call trace. """ self.callTraceViewer.clear() def setCallTraceToProjectMode(self, enabled): """ Public slot to set the call trace viewer to project mode. In project mode the call trace info is shown with project relative path names. @param enabled flag indicating to enable the project mode (boolean) """ self.callTraceViewer.setProjectMode(enabled) def showVariables(self, vlist, globals): """ Public method to show the variables in the respective window. @param vlist list of variables to display @param globals flag indicating global/local state """ if globals: self.globalsViewer.showVariables(vlist, self.framenr) else: self.localsViewer.showVariables(vlist, self.framenr) def showVariable(self, vlist, globals): """ Public method to show the variables in the respective window. @param vlist list of variables to display @param globals flag indicating global/local state """ if globals: self.globalsViewer.showVariable(vlist) else: self.localsViewer.showVariable(vlist) def showVariablesTab(self, globals): """ Public method to make a variables tab visible. @param globals flag indicating global/local state """ if globals: self.__tabWidget.setCurrentWidget(self.glvWidget) else: self.__tabWidget.setCurrentWidget(self.lvWidget) def saveCurrentPage(self): """ Public slot to save the current page. """ self.currPage = self.__tabWidget.currentWidget() def restoreCurrentPage(self): """ Public slot to restore the previously saved page. """ if self.currPage is not None: self.__tabWidget.setCurrentWidget(self.currPage) def handleClientStack(self, stack): """ Public slot to show the call stack of the program being debugged. @param stack list of tuples with call stack data (file name, line number, function name, formatted argument/values list) """ block = self.stackComboBox.blockSignals(True) self.framenr = 0 self.stackComboBox.clear() self.currentStack = stack self.sourceButton.setEnabled(len(stack) > 0) for s in stack: # just show base filename to make it readable s = (os.path.basename(s[0]), s[1], s[2]) self.stackComboBox.addItem('{0}:{1}:{2}'.format(*s)) self.stackComboBox.blockSignals(block) def setVariablesFilter(self, globalsFilter, localsFilter): """ Public slot to set the local variables filter. @param globalsFilter filter list for global variable types (list of int) @param localsFilter filter list for local variable types (list of int) """ self.globalsFilter = globalsFilter self.localsFilter = localsFilter def __showSource(self): """ Private slot to handle the source button press to show the selected file. """ index = self.stackComboBox.currentIndex() if index > -1 and self.currentStack: s = self.currentStack[index] self.sourceFile.emit(s[0], int(s[1])) def __frameSelected(self, frmnr): """ Private slot to handle the selection of a new stack frame number. @param frmnr frame number (0 is the current frame) (int) """ self.framenr = frmnr self.debugServer.remoteClientVariables(0, self.localsFilter, frmnr) if self.__autoViewSource: self.__showSource() def __setGlobalsFilter(self): """ Private slot to set the global variable filter. """ filter = self.globalsFilterEdit.text() self.debugServer.remoteClientSetFilter(1, filter) self.debugServer.remoteClientVariables(2, self.globalsFilter) def __setLocalsFilter(self): """ Private slot to set the local variable filter. """ filter = self.localsFilterEdit.text() self.debugServer.remoteClientSetFilter(0, filter) if self.currentStack: self.debugServer.remoteClientVariables( 0, self.localsFilter, self.framenr) def handleDebuggingStarted(self): """ Public slot to handle the start of a debugging session. This slot sets the variables filter expressions. """ self.__setGlobalsFilter() self.__setLocalsFilter() self.showVariablesTab(False) def currentWidget(self): """ Public method to get a reference to the current widget. @return reference to the current widget (QWidget) """ return self.__tabWidget.currentWidget() def setCurrentWidget(self, widget): """ Public slot to set the current page based on the given widget. @param widget reference to the widget (QWidget) """ self.__tabWidget.setCurrentWidget(widget) def showThreadList(self, currentID, threadList): """ Public method to show the thread list. @param currentID id of the current thread (integer) @param threadList list of dictionaries containing the thread data """ citm = None self.__threadList.clear() for thread in threadList: if thread['broken']: state = self.tr("waiting at breakpoint") else: state = self.tr("running") itm = QTreeWidgetItem(self.__threadList, ["{0:d}".format(thread['id']), thread['name'], state]) if thread['id'] == currentID: citm = itm self.__threadList.header().resizeSections(QHeaderView.ResizeToContents) self.__threadList.header().setStretchLastSection(True) if citm: self.__doThreadListUpdate = False self.__threadList.setCurrentItem(citm) self.__doThreadListUpdate = True def __threadSelected(self, current, previous): """ Private slot to handle the selection of a thread in the thread list. @param current reference to the new current item (QTreeWidgetItem) @param previous reference to the previous current item (QTreeWidgetItem) """ if current is not None and self.__doThreadListUpdate: tid = int(current.text(0)) self.debugServer.remoteSetThread(tid) def __callStackFrameSelected(self, frameNo): """ Private slot to handle the selection of a call stack entry of the call stack viewer. @param frameNo frame number (index) of the selected entry (integer) """ if frameNo >= 0: self.stackComboBox.setCurrentIndex(frameNo)
class RadioStationWidget(QDialog): """ """ listen_radio_station_signal = pyqtSignal(str, str) """在线收听""" def __init__(self): super(RadioStationWidget, self).__init__() self.radio_station_type_label = QLabel('电台类别: ') self.radio_station_type_combobox = QComboBox() self.radio_station_type_combobox.currentIndexChanged.connect( self.answer_radio_station_type_combobox_current_index_changed) self.radio_station_type_list = ['通用', '地方'] self.radio_station_id_label = QLabel('电台频道: ') self.radio_station_id_combobox = QComboBox() self.radio_station_id_combobox.currentIndexChanged.connect( self.answer_radio_station_id_combobox_current_index_changed) self.universal_radio_station_id_list = [ "中国交通广播", "环球资讯广播 FM90.5", "中文环球广播", "经典音乐广播 101.8", "哈语广播", "藏语广播", "维语广播", "中国乡村之声", "经济之声", "中国之声", "音乐之声", "中华之声", "神州之声", "华夏之声", "香港之声", "文艺之声", "老年之声", "闽南之音", "南海之声", "客家之声", "海峡飞虹", "轻松调频 FM91.5", "Hit FM FM88.7", ] self.local_radio_station_id_list = [ "北京新闻广播 FM100.6", "北京音乐广播 FM97.4", "北京交通广播 FM103.9", "北京文艺广播 FM87.6", "北京欢乐时光 FM106.5", "北京怀旧金曲 FM107.5", "北京古典音乐 FM98.6", "北京教学广播 FM99.4", "北京长书广播 FM104.3", "北京戏曲曲艺 FM105.1", "北京房山经典音乐 FM96.9", "北京好音乐 FM95.9", "重庆新闻广播 FM96.8", "重庆经济广播 FM101.5", "重庆交通广播 FM95.5", "重庆音乐广播 FM88.1", "重庆都市广播 FM93.8", "重庆文艺广播 FM103.5", "巴渝之声 FM104.5" "南川人民广播电台 FM107.0", "万盛旅游交通广播 FM92.2", "万州交通广播", "福建新闻广播 FM103.6", "福建经济广播 FM96.1", "福建音乐广播 FM91.3", "福建交通广播 FM100.7", "福建东南广播 AM585", "福建私家车广播 FM98.7", "甘肃新闻综合广播 FM96.1", "甘肃都市调频 FM106.6", "甘肃交通广播 FM93.4", "甘肃经济广播 FM93.4", "甘肃农村广播 FM92.2", "兰州新闻综合广播 FM97.3", "兰州交通音乐广播 FM99.5", "兰州生活文艺广播 FM100.8", "广东新闻频道 FM91.4", "广东珠江经济台 FM97.4", "广东音乐之声 FM99.3", "广东城市之声 FM103.6", "广东南方生活广播 FM93.6", "广东羊城交通广播 FM105.2", "广东文体广播 FM107.7", "广东股市广播 FM95.3", "广东优悦广播 FM105.7", "广州新闻电台 FM96.2", "广州汽车音乐电台 FM102.7", "广州交通电台 FM106.1", "东莞音乐广播 FM104", "东莞交通广播", "当涂人民广播电台 FM90.1", ] self.search_result_label = QLabel('获取结果: ') self.audio_result_line_edit = QLineEdit() self.audio_result_line_edit.setReadOnly(True) self.get_audio_btn = QPushButton('获取音频源') self.get_audio_btn.clicked.connect(self.answer_get_audio_btn_clicked) self.copy_audio_btn = QPushButton('复制音频源') self.copy_audio_btn.setDisabled(True) self.copy_audio_btn.clicked.connect(self.answer_copy_audio_btn_clicked) self.listen_audio_btn = QPushButton('在线收听') self.listen_audio_btn.setDisabled(True) self.listen_audio_btn.clicked.connect( self.answer_watch_audio_btn_clicked) self.clean_btn = QPushButton('信息清空') self.clean_btn.clicked.connect(self.answer_clean_btn_clicked) self.init_ui() def init_ui(self): """ :return: """ self.radio_station_type_combobox.addItems(self.radio_station_type_list) self.radio_station_id_combobox.addItems( self.universal_radio_station_id_list) radio_station_type_layout = QHBoxLayout() radio_station_type_layout.setContentsMargins(10, 10, 10, 10) radio_station_type_layout.setSpacing(5) radio_station_type_layout.addWidget(self.radio_station_type_label) radio_station_type_layout.addWidget(self.radio_station_type_combobox) radio_station_type_layout.addStretch() radio_station_id_layout = QHBoxLayout() radio_station_id_layout.setContentsMargins(10, 10, 10, 10) radio_station_id_layout.setSpacing(5) radio_station_id_layout.addWidget(self.radio_station_id_label) radio_station_id_layout.addWidget(self.radio_station_id_combobox) radio_station_id_layout.addStretch() search_result_layout = QHBoxLayout() search_result_layout.setContentsMargins(10, 10, 10, 10) search_result_layout.setSpacing(5) search_result_layout.addWidget(self.search_result_label) search_result_layout.addWidget(self.audio_result_line_edit) search_result_layout.addWidget(self.get_audio_btn) search_result_layout.addWidget(self.copy_audio_btn) search_result_layout.addWidget(self.listen_audio_btn) search_result_layout.addWidget(self.clean_btn) search_result_layout.addStretch() main_layout = QVBoxLayout() main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) main_layout.addLayout(radio_station_type_layout) main_layout.addLayout(radio_station_id_layout) main_layout.addLayout(search_result_layout) self.setLayout(main_layout) self.setWindowTitle("广播电台") self.setWindowIcon(QIcon('./resources/img/[email protected]')) self.setWindowFlags(Qt.WindowCloseButtonHint) def answer_radio_station_type_combobox_current_index_changed(self, index): """ :param index: :return: """ self.radio_station_id_combobox.clear() if index == 0: self.radio_station_id_combobox.addItems( self.universal_radio_station_id_list) else: self.radio_station_id_combobox.addItems( self.local_radio_station_id_list) self.copy_audio_btn.setDisabled(True) self.listen_audio_btn.setDisabled(True) def answer_radio_station_id_combobox_current_index_changed(self, index): """ :param index: :return: """ self.copy_audio_btn.setDisabled(True) self.listen_audio_btn.setDisabled(True) def answer_get_audio_btn_clicked(self): """ :return: """ result = get_real_url_from_radio_station_content( self.radio_station_type_combobox.currentText(), self.radio_station_id_combobox.currentText()) print("search result: ", result) if result: self.audio_result_line_edit.setText(result) self.copy_audio_btn.setDisabled(False) self.listen_audio_btn.setDisabled(False) else: self.copy_audio_btn.setDisabled(True) self.listen_audio_btn.setDisabled(True) _box = PromptBox(2, "获取结果失败!", 1) width, height = get_window_center_point(_box) _box.move(width, height) _box.exec_() def answer_copy_audio_btn_clicked(self): """ :return: """ clipboard = QApplication.clipboard() clipboard.setText(self.audio_result_line_edit.text()) _box = PromptBox(0, "已复制音频源到剪切板!", 1) width, height = get_window_center_point(_box) _box.move(width, height) _box.exec_() def answer_watch_audio_btn_clicked(self): """ :return: """ self.close() self.listen_radio_station_signal.emit( self.audio_result_line_edit.text(), PlayerEnum.MrlTypeRS.value[1]) def answer_clean_btn_clicked(self): """ :return: """ self.radio_station_type_combobox.setCurrentIndex(0) self.radio_station_id_combobox.setCurrentIndex(0) self.audio_result_line_edit.clear() self.copy_audio_btn.setDisabled(True) self.listen_audio_btn.setDisabled(True)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() centralWidget = QWidget() fontLabel = QLabel("Font:") self.fontCombo = QFontComboBox() sizeLabel = QLabel("Size:") self.sizeCombo = QComboBox() styleLabel = QLabel("Style:") self.styleCombo = QComboBox() fontMergingLabel = QLabel("Automatic Font Merging:") self.fontMerging = QCheckBox() self.fontMerging.setChecked(True) self.scrollArea = QScrollArea() self.characterWidget = CharacterWidget() self.scrollArea.setWidget(self.characterWidget) self.findStyles(self.fontCombo.currentFont()) self.findSizes(self.fontCombo.currentFont()) self.lineEdit = QLineEdit() clipboardButton = QPushButton("&To clipboard") self.clipboard = QApplication.clipboard() self.fontCombo.currentFontChanged.connect(self.findStyles) self.fontCombo.activated[str].connect(self.characterWidget.updateFont) self.styleCombo.activated[str].connect(self.characterWidget.updateStyle) self.sizeCombo.currentIndexChanged[str].connect(self.characterWidget.updateSize) self.characterWidget.characterSelected.connect(self.insertCharacter) clipboardButton.clicked.connect(self.updateClipboard) controlsLayout = QHBoxLayout() controlsLayout.addWidget(fontLabel) controlsLayout.addWidget(self.fontCombo, 1) controlsLayout.addWidget(sizeLabel) controlsLayout.addWidget(self.sizeCombo, 1) controlsLayout.addWidget(styleLabel) controlsLayout.addWidget(self.styleCombo, 1) controlsLayout.addWidget(fontMergingLabel) controlsLayout.addWidget(self.fontMerging, 1) controlsLayout.addStretch(1) lineLayout = QHBoxLayout() lineLayout.addWidget(self.lineEdit, 1) lineLayout.addSpacing(12) lineLayout.addWidget(clipboardButton) centralLayout = QVBoxLayout() centralLayout.addLayout(controlsLayout) centralLayout.addWidget(self.scrollArea, 1) centralLayout.addSpacing(4) centralLayout.addLayout(lineLayout) centralWidget.setLayout(centralLayout) self.setCentralWidget(centralWidget) self.setWindowTitle("Character Map") def findStyles(self, font): fontDatabase = QFontDatabase() currentItem = self.styleCombo.currentText() self.styleCombo.clear() for style in fontDatabase.styles(font.family()): self.styleCombo.addItem(style) styleIndex = self.styleCombo.findText(currentItem) if styleIndex == -1: self.styleCombo.setCurrentIndex(0) else: self.styleCombo.setCurrentIndex(styleIndex) def findSizes(self, font): fontDatabase = QFontDatabase() currentSize = self.sizeCombo.currentText() self.sizeCombo.blockSignals(True) self.sizeCombo.clear() if fontDatabase.isSmoothlyScalable(font.family(), fontDatabase.styleString(font)): for size in QFontDatabase.standardSizes(): self.sizeCombo.addItem(str(size)) self.sizeCombo.setEditable(True) else: for size in fontDatabase.smoothSizes(font.family(), fontDatabase.styleString(font)): self.sizeCombo.addItem(str(size)) self.sizeCombo.setEditable(False) self.sizeCombo.blockSignals(False) sizeIndex = self.sizeCombo.findText(currentSize) if sizeIndex == -1: self.sizeCombo.setCurrentIndex(max(0, self.sizeCombo.count() / 3)) else: self.sizeCombo.setCurrentIndex(sizeIndex) def insertCharacter(self, character): self.lineEdit.insert(character) def updateClipboard(self): self.clipboard.setText(self.lineEdit.text(), QClipboard.Clipboard) self.clipboard.setText(self.lineEdit.text(), QClipboard.Selection)
class NewDocument(preferences.Group): def __init__(self, page): super(NewDocument, self).__init__(page) grid = QGridLayout() self.setLayout(grid) def changed(): self.changed.emit() self.combo.setEnabled(self.template.isChecked()) self.emptyDocument = QRadioButton(toggled=changed) self.lilyVersion = QRadioButton(toggled=changed) self.template = QRadioButton(toggled=changed) self.combo = QComboBox(currentIndexChanged=changed) grid.addWidget(self.emptyDocument, 0, 0, 1, 2) grid.addWidget(self.lilyVersion, 1, 0, 1, 2) grid.addWidget(self.template, 2, 0, 1, 1) grid.addWidget(self.combo, 2, 1, 1, 1) self.loadCombo() app.translateUI(self) def translateUI(self): self.setTitle(_("When creating new documents")) self.emptyDocument.setText(_("Create an empty document")) self.lilyVersion.setText(_("Create a document that contains the LilyPond version statement")) self.template.setText(_("Create a document from a template:")) from snippet import snippets for i, name in enumerate(self._names): self.combo.setItemText(i, snippets.title(name)) def loadCombo(self): from snippet import snippets self._names = [name for name in snippets.names() if snippets.get(name).variables.get('template')] self.combo.clear() self.combo.addItems([''] * len(self._names)) def loadSettings(self): s = QSettings() ndoc = s.value("new_document", "empty", str) template = s.value("new_document_template", "", str) if template in self._names: self.combo.setCurrentIndex(self._names.index(template)) if ndoc == "template": self.template.setChecked(True) elif ndoc == "version": self.lilyVersion.setChecked(True) else: self.emptyDocument.setChecked(True) def saveSettings(self): s = QSettings() if self._names and self.template.isChecked(): s.setValue("new_document", "template") s.setValue("new_document_template", self._names[self.combo.currentIndex()]) elif self.lilyVersion.isChecked(): s.setValue("new_document", "version") else: s.setValue("new_document", "empty")
class IterationTable(QWidget): """Widget that handles pipeline iteration. Methods: - add_tag: adds a tag to visualize in the iteration table - emit_iteration_table_updated: emits a signal when the iteration scans have been updated - fill_values: fill values_list depending on the visualized tags - refresh_layout: updates the layout of the widget - remove_tag: removes a tag to visualize in the iteration table - select_iterated_tag: opens a pop-up to let the user select on which tag to iterate - select_visualized_tag: opens a pop-up to let the user select which tag to visualize in the iteration table - update_iterated_tag: updates the widget - update_table: updates the iteration table """ iteration_table_updated = pyqtSignal(list) def __init__(self, project, scan_list, main_window): """ Initialization of the IterationTable widget :param project: current project in the software :param scan_list: list of the selected database files :param main_window: software's main_window """ QWidget.__init__(self) #Necessary for using MIA bricks ProcessMIA.project = project self.project = project if not scan_list: self.scan_list = self.project.session.get_documents_names( COLLECTION_CURRENT) else: self.scan_list = scan_list self.main_window = main_window self.iterated_tag = None # values_list will contain the different values of each selected tag self.values_list = [[], []] # Checkbox to choose to iterate the pipeline or not self.check_box_iterate = QCheckBox("Iterate pipeline") self.check_box_iterate.stateChanged.connect( self.emit_iteration_table_updated) # Label "Iterate over:" self.label_iterate = QLabel("Iterate over:") # Label that displays the name of the selected tag self.iterated_tag_label = QLabel("Select a tag") # Push button to select the tag to iterate self.iterated_tag_push_button = QPushButton("Select") self.iterated_tag_push_button.clicked.connect( self.select_iteration_tag) # QComboBox self.combo_box = QComboBox() self.combo_box.currentIndexChanged.connect(self.update_table) # QTableWidget self.iteration_table = QTableWidget() # Label tag self.label_tags = QLabel("Tags to visualize:") # Each push button will allow the user to visualize a tag in # the iteration browser push_button_tag_1 = QPushButton() push_button_tag_1.setText("SequenceName") push_button_tag_1.clicked.connect( lambda: self.select_visualized_tag(0)) push_button_tag_2 = QPushButton() push_button_tag_2.setText("AcquisitionDate") push_button_tag_2.clicked.connect( lambda: self.select_visualized_tag(1)) # The list of all the push buttons # (the user can add as many as he or she wants) self.push_buttons = [] self.push_buttons.insert(0, push_button_tag_1) self.push_buttons.insert(1, push_button_tag_2) # Labels to add/remove a tag (a push button) self.add_tag_label = ClickableLabel() self.add_tag_label.setObjectName('plus') sources_images_dir = Config().getSourceImageDir() add_tag_picture = QPixmap(os.path.relpath(os.path.join( sources_images_dir, "green_plus.png"))) add_tag_picture = add_tag_picture.scaledToHeight(15) self.add_tag_label.setPixmap(add_tag_picture) self.add_tag_label.clicked.connect(self.add_tag) self.remove_tag_label = ClickableLabel() remove_tag_picture = QPixmap(os.path.relpath(os.path.join( sources_images_dir, "red_minus.png"))) remove_tag_picture = remove_tag_picture.scaledToHeight(20) self.remove_tag_label.setPixmap(remove_tag_picture) self.remove_tag_label.clicked.connect(self.remove_tag) # Layout self.v_layout = QVBoxLayout() self.setLayout(self.v_layout) self.refresh_layout() def add_tag(self): """Add a tag to visualize in the iteration table. Used only for tests """ idx = len(self.push_buttons) push_button = QPushButton() push_button.setText('Tag n°' + str(len(self.push_buttons) + 1)) push_button.clicked.connect(lambda: self.select_visualized_tag(idx)) self.push_buttons.insert(len(self.push_buttons), push_button) self.refresh_layout() def emit_iteration_table_updated(self): """ Emit a signal when the iteration scans have been updated """ if self.check_box_iterate.checkState(): if hasattr(self, 'scans'): self.iteration_table_updated.emit(self.iteration_scans) else: self.iteration_table_updated.emit(self.scan_list) else: self.iteration_table_updated.emit(self.scan_list) def fill_values(self, idx): """ Fill values_list depending on the visualized tags :param idx: """ """ Method that fills the values list when a tag is added or removed. """ tag_name = self.push_buttons[idx].text() values = [] for scan in self.project.session.get_documents_names( COLLECTION_CURRENT): current_value = self.project.session.get_value(COLLECTION_CURRENT, scan, tag_name) if current_value is not None: values.append(current_value) idx_to_fill = len(self.values_list) while len(self.values_list) <= idx: self.values_list.insert(idx_to_fill, []) idx_to_fill += 1 if self.values_list[idx] is not None: self.values_list[idx] = [] for value in values: if value not in self.values_list[idx]: self.values_list[idx].append(value) def refresh_layout(self): """Update the layout of the widget. Called in widget's initialization and when a tag push button is added or removed. """ first_v_layout = QVBoxLayout() first_v_layout.addWidget(self.check_box_iterate) second_v_layout = QVBoxLayout() second_v_layout.addWidget(self.label_iterate) second_v_layout.addWidget(self.iterated_tag_label) third_v_layout = QVBoxLayout() third_v_layout.addWidget(self.iterated_tag_push_button) third_v_layout.addWidget(self.combo_box) top_layout = QHBoxLayout() top_layout.addLayout(first_v_layout) top_layout.addLayout(second_v_layout) top_layout.addLayout(third_v_layout) self.v_layout.addLayout(top_layout) self.v_layout.addWidget(self.iteration_table) self.h_box = QHBoxLayout() self.h_box.setSpacing(10) self.h_box.addWidget(self.label_tags) for tag_label in self.push_buttons: self.h_box.addWidget(tag_label) self.h_box.addWidget(self.add_tag_label) self.h_box.addWidget(self.remove_tag_label) self.h_box.addStretch(1) self.v_layout.addLayout(self.h_box) def remove_tag(self): """Remove a tag to visualize in the iteration table. Used only for tests. """ push_button = self.push_buttons[-1] push_button.deleteLater() push_button = None del self.push_buttons[-1] del self.values_list[-1] self.refresh_layout() def select_iteration_tag(self): """ Open a pop-up to let the user select on which tag to iterate """ ui_select = PopUpSelectTagCountTable( self.project, self.project.session.get_fields_names(COLLECTION_CURRENT), self.iterated_tag) if ui_select.exec_(): self.update_iterated_tag(ui_select.selected_tag) def select_visualized_tag(self, idx): """Open a pop-up to let the user select which tag to visualize in the iteration table :param idx: index of the clicked push button """ popUp = PopUpSelectTagCountTable( self.project, self.project.session.get_fields_names(COLLECTION_CURRENT), self.push_buttons[idx].text()) if popUp.exec_(): self.push_buttons[idx].setText(popUp.selected_tag) self.fill_values(idx) self.update_table() def update_iterated_tag(self, tag_name): """ Update the widget when the iterated tag is modified :param tag_name: name of the iterated tag """ if not self.scan_list: self.scan_list = self.project.session.get_documents_names( COLLECTION_CURRENT) self.iterated_tag_push_button.setText(tag_name) self.iterated_tag = tag_name self.iterated_tag_label.setText(tag_name + ":") # Update combo_box scans_names = self.project.session.get_documents_names( COLLECTION_CURRENT) scans_names = list(set(scans_names).intersection(self.scan_list)) # tag_values_list contains all the values that can take iterated tag self.tag_values_list = [] for scan_name in scans_names: tag_value = self.project.session.get_value(COLLECTION_CURRENT, scan_name, tag_name) if str(tag_value) not in self.tag_values_list: self.tag_values_list.append(str(tag_value)) self.combo_box.clear() self.combo_box.addItems(self.tag_values_list) self.update_table() def update_table(self): """ Update the iteration table """ # Updating the scan list if not self.scan_list: self.scan_list = self.project.session.get_documents_names( COLLECTION_CURRENT) # Clearing the table and preparing its columns self.iteration_table.clear() self.iteration_table.setColumnCount(len(self.push_buttons)) # Headers for idx in range(len(self.push_buttons)): header_name = self.push_buttons[idx].text() if header_name not in self.project.session.get_fields_names( COLLECTION_CURRENT): print("{0} not in the project's tags".format(header_name)) return item = QTableWidgetItem() item.setText(header_name) self.iteration_table.setHorizontalHeaderItem(idx, item) # Searching the database scans that correspond to iterated tag value filter_query = "({" + self.iterated_tag + "} " + "==" + " \"" + \ self.combo_box.currentText() + "\")" scans_list = self.project.session.filter_documents(COLLECTION_CURRENT, filter_query) scans_res = [getattr(document, TAG_FILENAME) for document in scans_list] # Taking the intersection between the found database scans and the # user selection in the data_browser self.iteration_scans = list( set(scans_res).intersection(self.scan_list)) self.iteration_table.setRowCount(len(self.iteration_scans)) # Filling the table cells row = -1 for scan_name in self.iteration_scans: row += 1 for idx in range(len(self.push_buttons)): tag_name = self.push_buttons[idx].text() item = QTableWidgetItem() item.setText(str(self.project.session.get_value( COLLECTION_CURRENT, scan_name, tag_name))) self.iteration_table.setItem(row, idx, item) # This will change the scans list in the current Pipeline Manager tab self.iteration_table_updated.emit(self.iteration_scans)
class Gui(QWidget): def prepareWidgets(self): self.setWindowTitle('Spycer') self.locale = locales.getLocale() main_grid = QGridLayout() main_grid.addWidget(self.init3dWidget(), 0, 0, 20, 5) main_grid.addLayout(self.initRightPanel(), 0, 5, 20, 2) self.bottom_panel = self.initBottomPanel() self.bottom_panel.setEnabled(False) main_grid.addWidget(self.bottom_panel, 20, 0, 2, 7) self.setLayout(main_grid) self.planeActor = gui_utils.createPlaneActorCircle() self.planeTransform = vtk.vtkTransform() self.render.AddActor(self.planeActor) self.stateNothing() self.render.ResetCamera() self.planes = [] self.planesActors = [] self.openedStl = "/home/l1va/Downloads/1_odn2.stl" # TODO: removeme self.loadSTL(self.openedStl) # self.colorizeModel() def init3dWidget(self): widget3d = QVTKRenderWindowInteractor() widget3d.Initialize() widget3d.Start() self.render = vtk.vtkRenderer() self.render.SetBackground(params.BackgroundColor) widget3d.GetRenderWindow().AddRenderer(self.render) self.interactor = widget3d.GetRenderWindow().GetInteractor() self.interactor.GetInteractorStyle().SetCurrentStyleToTrackballCamera() self.axesWidget = gui_utils.createAxes(self.interactor) return widget3d def initRightPanel(self): right_panel = QGridLayout() right_panel.setSpacing(5) right_panel.setColumnStretch(0, 2) # Front-end development at its best self.cur_row = 1 def get_next_row(): self.cur_row += 1 return self.cur_row def get_cur_row(): return self.cur_row thickness_label = QLabel(self.locale.Thickness) self.thickness_value = QLineEdit("0.2") right_panel.addWidget(thickness_label, get_next_row(), 1) right_panel.addWidget(self.thickness_value, get_cur_row(), 2) printSpeed_label = QLabel(self.locale.PrintSpeed) self.printSpeed_value = QLineEdit("50") right_panel.addWidget(printSpeed_label, get_next_row(), 1) right_panel.addWidget(self.printSpeed_value, get_cur_row(), 2) printSpeedLayer1_label = QLabel(self.locale.PrintSpeedLayer1) self.printSpeedLayer1_value = QLineEdit("50") right_panel.addWidget(printSpeedLayer1_label, get_next_row(), 1) right_panel.addWidget(self.printSpeedLayer1_value, get_cur_row(), 2) printSpeedWall_label = QLabel(self.locale.PrintSpeedWall) self.printSpeedWall_value = QLineEdit("50") right_panel.addWidget(printSpeedWall_label, get_next_row(), 1) right_panel.addWidget(self.printSpeedWall_value, get_cur_row(), 2) extruderTemp_label = QLabel(self.locale.ExtruderTemp) self.extruderTemp_value = QLineEdit("200") right_panel.addWidget(extruderTemp_label, get_next_row(), 1) right_panel.addWidget(self.extruderTemp_value, get_cur_row(), 2) bedTemp_label = QLabel(self.locale.BedTemp) self.bedTemp_value = QLineEdit("60") right_panel.addWidget(bedTemp_label, get_next_row(), 1) right_panel.addWidget(self.bedTemp_value, get_cur_row(), 2) fillDensity_label = QLabel(self.locale.FillDensity) self.fillDensity_value = QLineEdit("20") right_panel.addWidget(fillDensity_label, get_next_row(), 1) right_panel.addWidget(self.fillDensity_value, get_cur_row(), 2) wallThickness_label = QLabel(self.locale.WallThickness) self.wallThickness_value = QLineEdit("0.8") right_panel.addWidget(wallThickness_label, get_next_row(), 1) right_panel.addWidget(self.wallThickness_value, get_cur_row(), 2) nozzle_label = QLabel(self.locale.Nozzle) self.nozzle_value = QLineEdit("0.4") right_panel.addWidget(nozzle_label, get_next_row(), 1) right_panel.addWidget(self.nozzle_value, get_cur_row(), 2) filling_type_label = QLabel(self.locale.FillingType) right_panel.addWidget(filling_type_label, get_next_row(), 1) # todo fix displaying shifting (feature is below) right_panel.addWidget(self.nozzle_value, get_cur_row(), 2) filling_type_valuesW = QWidget() self.filling_type_values = QComboBox(filling_type_valuesW) self.filling_type_values.addItems(self.locale.FillingTypeValues) right_panel.addWidget(filling_type_valuesW, get_cur_row(), 2) self.fanOffLayer1_box = QCheckBox(self.locale.FanOffLayer1) right_panel.addWidget(self.fanOffLayer1_box, get_next_row(), 1) self.modelSwitch_box = QCheckBox(self.locale.ShowStl) self.modelSwitch_box.stateChanged.connect(self.switchModels) right_panel.addWidget(self.modelSwitch_box, get_next_row(), 1) self.slider_label = QLabel(self.locale.LayersCount) self.layersNumber_label = QLabel() right_panel.addWidget(self.slider_label, get_next_row(), 1) right_panel.addWidget(self.layersNumber_label, get_cur_row(), 2) self.pictureSlider = QSlider() self.pictureSlider.setOrientation(QtCore.Qt.Horizontal) self.pictureSlider.setMinimum(1) self.pictureSlider.setValue(1) self.pictureSlider.valueChanged.connect(self.changeLayerView) right_panel.addWidget(self.pictureSlider, get_next_row(), 1, 1, 2) self.xPosition_value = QLineEdit("0") right_panel.addWidget(self.xPosition_value, get_next_row(), 1) self.yPosition_value = QLineEdit("0") right_panel.addWidget(self.yPosition_value, get_cur_row(), 2) self.zPosition_value = QLineEdit("0") right_panel.addWidget(self.zPosition_value, get_next_row(), 1) self.move_button = QPushButton(self.locale.MoveModel) self.move_button.clicked.connect(self.moveModel) right_panel.addWidget(self.move_button, get_cur_row(), 2, 1, 1) loadModel_button = QPushButton(self.locale.OpenModel) loadModel_button.clicked.connect(self.openFile) right_panel.addWidget(loadModel_button, get_next_row(), 1, 1, 1) self.editPlanes_button = QPushButton("Редактировать") # TODO: locales self.editPlanes_button.clicked.connect(lambda: self.loadSTL(self.openedStl)) right_panel.addWidget(self.editPlanes_button, get_cur_row(), 2, 1, 1) self.slice3a_button = QPushButton(self.locale.Slice3Axes) self.slice3a_button.clicked.connect(lambda: self.sliceSTL("3axes")) right_panel.addWidget(self.slice3a_button, get_next_row(), 1, 1, 1) self.sliceVip_button = QPushButton(self.locale.SliceVip) self.sliceVip_button.clicked.connect(lambda: self.sliceSTL("vip")) right_panel.addWidget(self.sliceVip_button, get_cur_row(), 2, 1, 1) self.saveGCode_button = QPushButton(self.locale.SaveGCode) self.saveGCode_button.clicked.connect(self.saveGCodeFile) right_panel.addWidget(self.saveGCode_button, get_next_row(), 1, 1, 1) self.analyzeModel_button = QPushButton("Анализировать") # TODO: locales self.analyzeModel_button.clicked.connect(self.analyzeModel) right_panel.addWidget(self.analyzeModel_button, get_cur_row(), 2, 1, 1) self.colorizeAngle_value = QLineEdit("30") right_panel.addWidget(self.colorizeAngle_value, get_next_row(), 1) self.colorModel_button = QPushButton(self.locale.ColorModel) self.colorModel_button.clicked.connect(self.colorizeModel) right_panel.addWidget(self.colorModel_button, get_cur_row(), 2, 1, 1) return right_panel def initBottomPanel(self): bottom_layout = QGridLayout() bottom_layout.setSpacing(5) bottom_layout.setColumnStretch(7, 1) self.addPlane_button = QPushButton("Добавить") self.addPlane_button.clicked.connect(self.addPlane) bottom_layout.addWidget(self.addPlane_button, 1, 0) comboW = QWidget() self.combo = QComboBox(comboW) self.combo.currentIndexChanged.connect(self.changeComboSelect) bottom_layout.addWidget(comboW, 0, 0, 1, 2) self.removePlane_button = QPushButton("Удалить") self.removePlane_button.clicked.connect(self.removePlane) bottom_layout.addWidget(self.removePlane_button, 2, 0) self.tilted_checkbox = QCheckBox(self.locale.Tilted) self.tilted_checkbox.stateChanged.connect(self.applyPlaneChange) bottom_layout.addWidget(self.tilted_checkbox, 0, 3) x_label = QLabel("X:") # TODO: to locales bottom_layout.addWidget(x_label, 0, 4) self.x_value = QLineEdit("3.0951") self.x_value.editingFinished.connect(self.applyEditsChange) bottom_layout.addWidget(self.x_value, 0, 5) y_label = QLabel("Y:") # TODO: to locales bottom_layout.addWidget(y_label, 1, 4) self.y_value = QLineEdit("5.5910") self.y_value.editingFinished.connect(self.applyEditsChange) bottom_layout.addWidget(self.y_value, 1, 5) z_label = QLabel("Z:") # TODO: to locales bottom_layout.addWidget(z_label, 2, 4) self.z_value = QLineEdit("89.5414") self.z_value.editingFinished.connect(self.applyEditsChange) bottom_layout.addWidget(self.z_value, 2, 5) rotated_label = QLabel("Повёрнута:") # TODO: to locales bottom_layout.addWidget(rotated_label, 3, 4) self.rotated_value = QLineEdit("31.0245") self.rotated_value.editingFinished.connect(self.applyEditsChange) bottom_layout.addWidget(self.rotated_value, 3, 5) self.xSlider = QSlider() self.xSlider.setOrientation(QtCore.Qt.Horizontal) self.xSlider.setMinimum(-100) self.xSlider.setMaximum(100) self.xSlider.setValue(1) self.xSlider.valueChanged.connect(self.applyPlaneChange) bottom_layout.addWidget(self.xSlider, 0, 6, 1, 2) self.ySlider = QSlider() self.ySlider.setOrientation(QtCore.Qt.Horizontal) self.ySlider.setMinimum(-100) self.ySlider.setMaximum(100) self.ySlider.setValue(1) self.ySlider.valueChanged.connect(self.applyPlaneChange) bottom_layout.addWidget(self.ySlider, 1, 6, 1, 2) self.zSlider = QSlider() self.zSlider.setOrientation(QtCore.Qt.Horizontal) self.zSlider.setMinimum(0) self.zSlider.setMaximum(200) self.zSlider.setValue(1) self.zSlider.valueChanged.connect(self.applyPlaneChange) bottom_layout.addWidget(self.zSlider, 2, 6, 1, 2) self.rotSlider = QSlider() self.rotSlider.setOrientation(QtCore.Qt.Horizontal) self.rotSlider.setMinimum(-180) self.rotSlider.setMaximum(180) self.rotSlider.setValue(0) self.rotSlider.valueChanged.connect(self.applyPlaneChange) bottom_layout.addWidget(self.rotSlider, 3, 6, 1, 2) # self.applyPlane_button = QPushButton("Применить") # TODO: # self.applyPlane_button.clicked.connect(self.applyPlaneChange) # bottom_layout.addWidget(self.applyPlane_button, 2, 2) bottom_panel = QWidget() bottom_panel.setLayout(bottom_layout) return bottom_panel def applyEditsChange(self): self.xSlider.setValue(float(self.x_value.text())) self.ySlider.setValue(float(self.y_value.text())) self.zSlider.setValue(float(self.z_value.text())) self.rotSlider.setValue(float(self.rotated_value.text())) def applyPlaneChange(self): self.x_value.setText(str(self.xSlider.value())) self.y_value.setText(str(self.ySlider.value())) self.z_value.setText(str(self.zSlider.value())) self.rotated_value.setText(str(self.rotSlider.value())) center = [float(self.xSlider.value()), float(self.ySlider.value()), float(self.zSlider.value())] ind = self.combo.currentIndex() if ind == -1: return self.planes[ind] = gui_utils.Plane(self.tilted_checkbox.isChecked(), float(self.rotSlider.value()), center) self.drawPlanes() def addPlane(self): if len(self.planes)==0: self.planes.append(gui_utils.Plane(True, 0, [10,10,10])) else: path = [self.planes[-1].x, self.planes[-1].y, self.planes[-1].z + 10] self.planes.append(gui_utils.Plane(False, 0, path)) self.loadPlanes() def removePlane(self): ind = self.combo.currentIndex() if ind == -1: return del self.planes[ind] self.loadPlanes() def changeComboSelect(self): ind = self.combo.currentIndex() if ind==-1: return plane = self.planes[ind] self.tilted_checkbox.setChecked(plane.tilted) self.rotated_value.setText(str(plane.rot)) self.x_value.setText(str(plane.x)) self.y_value.setText(str(plane.y)) self.z_value.setText(str(plane.z)) self.xSlider.setValue(plane.x) self.ySlider.setValue(plane.y) self.zSlider.setValue(plane.z) self.rotSlider.setValue(plane.rot) self.planesActors[ind].GetProperty().SetColor(params.LastLayerColor) self.reloadScene() def loadPlanes(self): #if len(self.planes) == 0: # self.bottom_panel.setEnabled(False) # return #self.bottom_panel.setEnabled(True) self.combo.clear() for i in range(len(self.planes)): self.combo.addItem("Плоскость " + str(i + 1)) self.changeComboSelect() self.drawPlanes() def drawPlanes(self): # TODO: optimize for p in self.planesActors: self.render.RemoveActor(p) self.planesActors = [] for p in self.planes: # rot = self.rotations[self.lays2rots[-1]] act = gui_utils.createPlaneActorCircleByCenterAndRot([p.x, p.y, p.z], -60 if p.tilted else 0, p.rot) # act = utils.createPlaneActorCircleByCenterAndRot([p.x, p.y, p.z], 0,0) # print("tilted" if p.tilted else "NOT") self.planesActors.append(act) self.render.AddActor(act) ind = self.combo.currentIndex() if ind != -1: self.planesActors[ind].GetProperty().SetColor(params.LastLayerColor) # print("was draw planes: ",len(self.planes)) self.reloadScene() def stateNothing(self): self.modelSwitch_box.setEnabled(False) self.modelSwitch_box.setChecked(False) self.slider_label.setEnabled(False) self.layersNumber_label.setEnabled(False) self.layersNumber_label.setText(" ") self.currLayerNumber = 0 self.pictureSlider.setEnabled(False) self.pictureSlider.setSliderPosition(0) self.move_button.setEnabled(False) self.slice3a_button.setEnabled(False) self.colorModel_button.setEnabled(False) self.editPlanes_button.setEnabled(False) # self.slice5aProfile_button.setEnabled(False) # self.slice5a_button.setEnabled(False) self.sliceVip_button.setEnabled(False) self.saveGCode_button.setEnabled(False) self.state = NothingState def stateGcode(self, layers_count): self.modelSwitch_box.setEnabled(False) self.modelSwitch_box.setChecked(False) self.slider_label.setEnabled(True) self.layersNumber_label.setEnabled(True) self.layersNumber_label.setText(str(layers_count)) self.currLayerNumber = layers_count self.pictureSlider.setEnabled(True) self.pictureSlider.setMaximum(layers_count) self.pictureSlider.setSliderPosition(layers_count) self.move_button.setEnabled(False) self.slice3a_button.setEnabled(False) self.colorModel_button.setEnabled(False) self.editPlanes_button.setEnabled(True) # self.slice5aProfile_button.setEnabled(False) # self.slice5a_button.setEnabled(False) self.sliceVip_button.setEnabled(False) self.saveGCode_button.setEnabled(True) self.state = GCodeState def stateStl(self): self.modelSwitch_box.setEnabled(False) self.modelSwitch_box.setChecked(False) self.slider_label.setEnabled(False) self.layersNumber_label.setEnabled(False) self.layersNumber_label.setText(" ") self.currLayerNumber = 0 self.pictureSlider.setEnabled(False) self.pictureSlider.setSliderPosition(0) self.move_button.setEnabled(True) self.slice3a_button.setEnabled(True) self.colorModel_button.setEnabled(True) self.editPlanes_button.setEnabled(False) # self.slice5aProfile_button.setEnabled(True) # self.slice5a_button.setEnabled(True) self.sliceVip_button.setEnabled(True) self.saveGCode_button.setEnabled(False) self.state = StlState def stateBoth(self, layers_count): self.modelSwitch_box.setEnabled(True) self.modelSwitch_box.setChecked(False) self.slider_label.setEnabled(True) self.layersNumber_label.setEnabled(True) self.layersNumber_label.setText(str(layers_count)) self.currLayerNumber = layers_count self.pictureSlider.setEnabled(True) self.pictureSlider.setMaximum(layers_count) self.pictureSlider.setSliderPosition(layers_count) self.move_button.setEnabled(True) self.slice3a_button.setEnabled(True) self.colorModel_button.setEnabled(True) self.editPlanes_button.setEnabled(True) # self.slice5aProfile_button.setEnabled(True) # self.slice5a_button.setEnabled(True) self.sliceVip_button.setEnabled(True) self.saveGCode_button.setEnabled(True) self.state = BothState def moveModel(self): self.stlTranslation = [float(self.xPosition_value.text()), float(self.yPosition_value.text()), float(self.zPosition_value.text())] print(self.stlTranslation) transform = vtk.vtkTransform() transform.Translate(self.stlTranslation[0], self.stlTranslation[1], self.stlTranslation[2]) self.stlActor.SetUserTransform(transform) self.reloadScene() def loadGCode(self, filename, addStl): gode = gcode.readGCode(filename) self.gode = gode blocks = gui_utils.makeBlocks(gode.layers) self.actors = gui_utils.wrapWithActors(blocks, gode.rotations, gode.lays2rots) self.clearScene() self.render.AddActor(self.planeActor) if addStl: self.render.AddActor(self.stlActor) self.rotatePlane(gode.rotations[-1]) for actor in self.actors: self.render.AddActor(actor) #self.loadPlanes() self.bottom_panel.setEnabled(False) if addStl: self.stateBoth(len(self.actors)) else: self.stateGcode(len(self.actors)) self.openedGCode = filename self.render.ResetCamera() self.reloadScene() def loadSTL(self, filename, method=gui_utils.createStlActorInOrigin): self.stlActor, self.stlTranslation, self.stlBounds = method(filename) # self.xSlider.setMinimum(self.stlBounds[0]) # self.xSlider.setMaximum(self.stlBounds[1]) # self.ySlider.setMinimum(self.stlBounds[2]) # self.ySlider.setMaximum(self.stlBounds[3]) # self.zSlider.setMinimum(self.stlBounds[4]) # self.zSlider.setMaximum(self.stlBounds[5]) # print(self.stlTranslation) self.xPosition_value.setText(str(self.stlTranslation[0])[:10]) self.yPosition_value.setText(str(self.stlTranslation[1])[:10]) self.zPosition_value.setText(str(self.stlTranslation[2])[:10]) self.clearScene() self.render.AddActor(self.planeActor) self.render.AddActor(self.stlActor) self.bottom_panel.setEnabled(True) self.loadPlanes() self.stateStl() self.openedStl = filename self.render.ResetCamera() self.reloadScene() def changeLayerView(self): newSliderValue = self.pictureSlider.value() self.actors[newSliderValue - 1].GetProperty().SetColor(params.LastLayerColor) self.actors[self.currLayerNumber - 1].GetProperty().SetColor(params.LayerColor) self.layersNumber_label.setText(str(newSliderValue)) if newSliderValue < self.currLayerNumber: for layer in range(newSliderValue, self.currLayerNumber): self.actors[layer].VisibilityOff() else: for layer in range(self.currLayerNumber, newSliderValue): self.actors[layer].VisibilityOn() if self.gode.lays2rots[newSliderValue - 1] != self.gode.lays2rots[self.currLayerNumber - 1]: currRotation = self.gode.rotations[self.gode.lays2rots[newSliderValue - 1]] for block in range(newSliderValue): transform = vtk.vtkTransform() transform.PostMultiply() transform.RotateX(-self.gode.rotations[self.gode.lays2rots[block]].x_rot) transform.PostMultiply() transform.RotateZ(-self.gode.rotations[self.gode.lays2rots[block]].z_rot) transform.PostMultiply() transform.RotateZ(currRotation.z_rot) transform.PostMultiply() transform.RotateX(currRotation.x_rot) self.actors[block].SetUserTransform(transform) self.rotatePlane(currRotation) for i in range(len(self.planes)): self.rotateAnyPlane(self.planesActors[i], self.planes[i], currRotation) self.currLayerNumber = newSliderValue self.reloadScene() def rotatePlane(self, rotation): transform = vtk.vtkTransform() transform.PostMultiply() transform.RotateZ(rotation.z_rot) transform.PostMultiply() transform.RotateX(rotation.x_rot) self.planeActor.SetUserTransform(transform) self.planeTransform = transform def rotateAnyPlane(self, planeActor, plane, rotation): transform = vtk.vtkTransform() transform.PostMultiply() transform.RotateX(-60 if plane.tilted else 0) transform.PostMultiply() transform.RotateZ(plane.rot) transform.Translate(plane.x, plane.y, plane.z - 0.1) transform.PostMultiply() transform.RotateZ(rotation.z_rot) transform.PostMultiply() transform.RotateX(rotation.x_rot) planeActor.SetUserTransform(transform) def sliceSTL(self, slicing_type): values = { "stl": format_path(self.openedStl), "gcode": params.OutputGCode, "originx": self.stlTranslation[0], "originy": self.stlTranslation[1], "originz": self.stlTranslation[2], "rotcx": params.RotationCenter[0], "rotcy": params.RotationCenter[1], "rotcz": params.RotationCenter[2], "thickness": self.thickness_value.text(), "wall_thickness": self.wallThickness_value.text(), "fill_density": self.fillDensity_value.text(), "bed_temperature": self.bedTemp_value.text(), "extruder_temperature": self.extruderTemp_value.text(), "print_speed": self.printSpeed_value.text(), "print_speed_layer1": self.printSpeedLayer1_value.text(), "print_speed_wall": self.printSpeedWall_value.text(), "nozzle": self.nozzle_value.text(), "filling_type": locales.getLocaleByLang("en").FillingTypeValues[self.filling_type_values.currentIndex()], "slicing_type": slicing_type, "planes_file": params.PlanesFile, } self.savePlanesToFile() cmd = params.SliceCommand.format(**values) if self.fanOffLayer1_box.isChecked(): cmd += " --fan_off_layer1" print(cmd) subprocess.check_output(str.split(cmd)) self.stlActor.VisibilityOff() self.loadGCode(params.OutputGCode, True) def savePlanesToFile(self): with open(params.PlanesFile, 'w') as out: for p in self.planes: out.write(p.toFile() + '\n') def colorizeModel(self): values = { "stl": format_path(self.openedStl), "out": params.ColorizeResult, "angle": self.colorizeAngle_value.text(), } cmd = params.ColorizeStlCommand.format(**values) subprocess.check_output(str.split(cmd)) self.loadSTL(self.openedStl, method=gui_utils.createStlActorInOriginWithColorize) def analyzeModel(self): values = { "stl": format_path(self.openedStl), "angle": self.colorizeAngle_value.text(), "out": params.AnalyzeResult, "originx": self.stlTranslation[0], "originy": self.stlTranslation[1], "originz": self.stlTranslation[2], "rotcx": params.RotationCenter[0], "rotcy": params.RotationCenter[1], "rotcz": params.RotationCenter[2], } cmd = params.AnalyzeStlCommand.format(**values) subprocess.check_output(str.split(cmd)) self.planes = gui_utils.read_planes() self.bottom_panel.setEnabled(True) # self.openedStl = "cuttedSTL.stl" self.loadSTL(self.openedStl, method=gui_utils.createStlActorInOrigin) def clearScene(self): self.render.RemoveAllViewProps() def reloadScene(self): self.render.Modified() self.interactor.Render() def switchModels(self, state): if state == QtCore.Qt.Checked: for actor in self.actors: actor.VisibilityOff() self.stlActor.VisibilityOn() else: for layer in range(self.pictureSlider.value()): self.actors[layer].VisibilityOn() self.stlActor.VisibilityOff() self.reloadScene() def openFile(self): try: filename = str( QFileDialog.getOpenFileName(None, self.locale.OpenModel, "/home/l1va/Downloads/5axes_3d_printer/test", "STL (*.stl)")[0]) # TODO: fix path if filename != "": self.planes = [] fileExt = os.path.splitext(filename)[1].upper() filename = str(Path(filename)) if fileExt == ".STL": self.loadSTL(filename) elif fileExt == ".GCODE": self.loadGCode(filename, False) else: print("This file format isn't supported:", fileExt) except IOError as e: print("Error during file opening:", e) def saveGCodeFile(self): try: name = str(QFileDialog.getSaveFileName(None, self.locale.SaveGCode, "", "Gcode (*.gcode)")[0]) if name != "": if not name.endswith(".gcode"): name += ".gcode" copy2(self.openedGCode, name) except IOError as e: print("Error during file saving:", e)
class NewDocument(preferences.Group): def __init__(self, page): super(NewDocument, self).__init__(page) grid = QGridLayout() self.setLayout(grid) def changed(): self.changed.emit() self.combo.setEnabled(self.template.isChecked()) self.emptyDocument = QRadioButton(toggled=changed) self.lilyVersion = QRadioButton(toggled=changed) self.template = QRadioButton(toggled=changed) self.combo = QComboBox(currentIndexChanged=changed) grid.addWidget(self.emptyDocument, 0, 0, 1, 2) grid.addWidget(self.lilyVersion, 1, 0, 1, 2) grid.addWidget(self.template, 2, 0, 1, 1) grid.addWidget(self.combo, 2, 1, 1, 1) self.loadCombo() app.translateUI(self) def translateUI(self): self.setTitle(_("When creating new documents")) self.emptyDocument.setText(_("Create an empty document")) self.lilyVersion.setText(_("Create a document that contains the LilyPond version statement")) self.template.setText(_("Create a document from a template:")) from snippet import snippets for i, name in enumerate(self._names): self.combo.setItemText(i, snippets.title(name)) def loadCombo(self): from snippet import snippets self._names = [name for name in snippets.names() if snippets.get(name).variables.get('template')] self.combo.clear() self.combo.addItems([''] * len(self._names)) def loadSettings(self): s = QSettings() ndoc = s.value("new_document", "empty", str) template = s.value("new_document_template", "", str) if template in self._names: self.combo.setCurrentIndex(self._names.index(template)) if ndoc == "template": self.template.setChecked(True) elif ndoc == "version": self.lilyVersion.setChecked(True) else: self.emptyDocument.setChecked(True) def saveSettings(self): s = QSettings() if self._names and self.template.isChecked(): s.setValue("new_document", "template") s.setValue("new_document_template", self._names[self.combo.currentIndex()]) elif self.lilyVersion.isChecked(): s.setValue("new_document", "version") else: s.setValue("new_document", "empty")
class EditorAssembly(QWidget): """ Class implementing the editor assembly widget containing the navigation combos and the editor widget. """ def __init__(self, dbs, fn=None, vm=None, filetype="", editor=None, tv=None): """ Constructor @param dbs reference to the debug server object @param fn name of the file to be opened (string). If it is None, a new (empty) editor is opened @param vm reference to the view manager object (ViewManager.ViewManager) @param filetype type of the source file (string) @param editor reference to an Editor object, if this is a cloned view @param tv reference to the task viewer object """ super(EditorAssembly, self).__init__() self.__layout = QGridLayout(self) self.__layout.setContentsMargins(0, 0, 0, 0) self.__layout.setSpacing(1) self.__globalsCombo = QComboBox() self.__membersCombo = QComboBox() from .Editor import Editor self.__editor = Editor(dbs, fn, vm, filetype, editor, tv) self.__layout.addWidget(self.__globalsCombo, 0, 0) self.__layout.addWidget(self.__membersCombo, 0, 1) self.__layout.addWidget(self.__editor, 1, 0, 1, -1) self.__module = None self.__globalsCombo.activated[int].connect(self.__globalsActivated) self.__membersCombo.activated[int].connect(self.__membersActivated) self.__editor.cursorLineChanged.connect(self.__editorCursorLineChanged) self.__parseTimer = QTimer(self) self.__parseTimer.setSingleShot(True) self.__parseTimer.setInterval(5 * 1000) self.__parseTimer.timeout.connect(self.__parseEditor) self.__editor.textChanged.connect(self.__resetParseTimer) self.__editor.refreshed.connect(self.__resetParseTimer) self.__selectedGlobal = "" self.__selectedMember = "" self.__globalsBoundaries = {} self.__membersBoundaries = {} QTimer.singleShot(0, self.__parseEditor) def shutdownTimer(self): """ Public method to stop and disconnect the timer. """ self.__parseTimer.stop() self.__parseTimer.timeout.disconnect(self.__parseEditor) self.__editor.textChanged.disconnect(self.__resetParseTimer) self.__editor.refreshed.disconnect(self.__resetParseTimer) def getEditor(self): """ Public method to get the reference to the editor widget. @return reference to the editor widget (Editor) """ return self.__editor def __globalsActivated(self, index, moveCursor=True): """ Private method to jump to the line of the selected global entry and to populate the members combo box. @param index index of the selected entry (integer) @keyparam moveCursor flag indicating to move the editor cursor (boolean) """ # step 1: go to the line of the selected entry lineno = self.__globalsCombo.itemData(index) if lineno is not None: if moveCursor: txt = self.__editor.text(lineno - 1).rstrip() pos = len(txt.replace(txt.strip(), "")) self.__editor.gotoLine( lineno, pos if pos == 0 else pos + 1, True) self.__editor.setFocus() # step 2: populate the members combo, if the entry is a class self.__membersCombo.clear() self.__membersBoundaries = {} self.__membersCombo.addItem("") memberIndex = 0 entryName = self.__globalsCombo.itemText(index) if self.__module: if entryName in self.__module.classes: entry = self.__module.classes[entryName] elif entryName in self.__module.modules: entry = self.__module.modules[entryName] # step 2.0: add module classes items = {} for cl in entry.classes.values(): if cl.isPrivate(): icon = UI.PixmapCache.getIcon("class_private.png") elif cl.isProtected(): icon = UI.PixmapCache.getIcon( "class_protected.png") else: icon = UI.PixmapCache.getIcon("class.png") items[cl.name] = (icon, cl.lineno, cl.endlineno) for key in sorted(items.keys()): itm = items[key] self.__membersCombo.addItem(itm[0], key, itm[1]) memberIndex += 1 self.__membersBoundaries[(itm[1], itm[2])] = \ memberIndex else: return # step 2.1: add class methods from Utilities.ModuleParser import Function items = {} for meth in entry.methods.values(): if meth.modifier == Function.Static: icon = UI.PixmapCache.getIcon("method_static.png") elif meth.modifier == Function.Class: icon = UI.PixmapCache.getIcon("method_class.png") elif meth.isPrivate(): icon = UI.PixmapCache.getIcon("method_private.png") elif meth.isProtected(): icon = UI.PixmapCache.getIcon("method_protected.png") else: icon = UI.PixmapCache.getIcon("method.png") items[meth.name] = (icon, meth.lineno, meth.endlineno) for key in sorted(items.keys()): itm = items[key] self.__membersCombo.addItem(itm[0], key, itm[1]) memberIndex += 1 self.__membersBoundaries[(itm[1], itm[2])] = memberIndex # step 2.2: add class instance attributes items = {} for attr in entry.attributes.values(): if attr.isPrivate(): icon = UI.PixmapCache.getIcon("attribute_private.png") elif attr.isProtected(): icon = UI.PixmapCache.getIcon( "attribute_protected.png") else: icon = UI.PixmapCache.getIcon("attribute.png") items[attr.name] = (icon, attr.lineno) for key in sorted(items.keys()): itm = items[key] self.__membersCombo.addItem(itm[0], key, itm[1]) # step 2.3: add class attributes items = {} icon = UI.PixmapCache.getIcon("attribute_class.png") for glob in entry.globals.values(): items[glob.name] = (icon, glob.lineno) for key in sorted(items.keys()): itm = items[key] self.__membersCombo.addItem(itm[0], key, itm[1]) def __membersActivated(self, index, moveCursor=True): """ Private method to jump to the line of the selected members entry. @param index index of the selected entry (integer) @keyparam moveCursor flag indicating to move the editor cursor (boolean) """ lineno = self.__membersCombo.itemData(index) if lineno is not None and moveCursor: txt = self.__editor.text(lineno - 1).rstrip() pos = len(txt.replace(txt.strip(), "")) self.__editor.gotoLine(lineno, pos if pos == 0 else pos + 1, True) self.__editor.setFocus() def __resetParseTimer(self): """ Private slot to reset the parse timer. """ self.__parseTimer.stop() self.__parseTimer.start() def __parseEditor(self): """ Private method to parse the editor source and repopulate the globals combo. """ from Utilities.ModuleParser import Module, getTypeFromTypeName self.__module = None sourceType = getTypeFromTypeName(self.__editor.determineFileType()) if sourceType != -1: src = self.__editor.text() if src: fn = self.__editor.getFileName() if fn is None: fn = "" self.__module = Module("", fn, sourceType) self.__module.scan(src) # remember the current selections self.__selectedGlobal = self.__globalsCombo.currentText() self.__selectedMember = self.__membersCombo.currentText() self.__globalsCombo.clear() self.__membersCombo.clear() self.__globalsBoundaries = {} self.__membersBoundaries = {} self.__globalsCombo.addItem("") index = 0 # step 1: add modules items = {} for module in self.__module.modules.values(): items[module.name] = (UI.PixmapCache.getIcon("module.png"), module.lineno, module.endlineno) for key in sorted(items.keys()): itm = items[key] self.__globalsCombo.addItem(itm[0], key, itm[1]) index += 1 self.__globalsBoundaries[(itm[1], itm[2])] = index # step 2: add classes items = {} for cl in self.__module.classes.values(): if cl.isPrivate(): icon = UI.PixmapCache.getIcon("class_private.png") elif cl.isProtected(): icon = UI.PixmapCache.getIcon("class_protected.png") else: icon = UI.PixmapCache.getIcon("class.png") items[cl.name] = (icon, cl.lineno, cl.endlineno) for key in sorted(items.keys()): itm = items[key] self.__globalsCombo.addItem(itm[0], key, itm[1]) index += 1 self.__globalsBoundaries[(itm[1], itm[2])] = index # step 3: add functions items = {} for func in self.__module.functions.values(): if func.isPrivate(): icon = UI.PixmapCache.getIcon("method_private.png") elif func.isProtected(): icon = UI.PixmapCache.getIcon("method_protected.png") else: icon = UI.PixmapCache.getIcon("method.png") items[func.name] = (icon, func.lineno, func.endlineno) for key in sorted(items.keys()): itm = items[key] self.__globalsCombo.addItem(itm[0], key, itm[1]) index += 1 self.__globalsBoundaries[(itm[1], itm[2])] = index # step 4: add attributes items = {} for glob in self.__module.globals.values(): if glob.isPrivate(): icon = UI.PixmapCache.getIcon("attribute_private.png") elif glob.isProtected(): icon = UI.PixmapCache.getIcon( "attribute_protected.png") else: icon = UI.PixmapCache.getIcon("attribute.png") items[glob.name] = (icon, glob.lineno) for key in sorted(items.keys()): itm = items[key] self.__globalsCombo.addItem(itm[0], key, itm[1]) # reset the currently selected entries without moving the # text cursor index = self.__globalsCombo.findText(self.__selectedGlobal) if index != -1: self.__globalsCombo.setCurrentIndex(index) self.__globalsActivated(index, moveCursor=False) index = self.__membersCombo.findText(self.__selectedMember) if index != -1: self.__membersCombo.setCurrentIndex(index) self.__membersActivated(index, moveCursor=False) def __editorCursorLineChanged(self, lineno): """ Private slot handling a line change of the cursor of the editor. @param lineno line number of the cursor (integer) """ lineno += 1 # cursor position is zero based, code info one based # step 1: search in the globals for (lower, upper), index in self.__globalsBoundaries.items(): if upper == -1: upper = 1000000 # it is the last line if lower <= lineno <= upper: break else: index = 0 self.__globalsCombo.setCurrentIndex(index) self.__globalsActivated(index, moveCursor=False) # step 2: search in members for (lower, upper), index in self.__membersBoundaries.items(): if upper == -1: upper = 1000000 # it is the last line if lower <= lineno <= upper: break else: index = 0 self.__membersCombo.setCurrentIndex(index) self.__membersActivated(index, moveCursor=False)
class Browser(QWidget): """LilyPond documentation browser widget.""" def __init__(self, dockwidget): super(Browser, self).__init__(dockwidget) layout = QVBoxLayout(spacing=0) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.toolbar = tb = QToolBar() self.webview = QWebView(contextMenuPolicy=Qt.CustomContextMenu) self.chooser = QComboBox(sizeAdjustPolicy=QComboBox.AdjustToContents) self.search = SearchEntry(maximumWidth=200) layout.addWidget(self.toolbar) layout.addWidget(self.webview) ac = dockwidget.actionCollection ac.help_back.triggered.connect(self.webview.back) ac.help_forward.triggered.connect(self.webview.forward) ac.help_home.triggered.connect(self.showHomePage) ac.help_print.triggered.connect(self.slotPrint) self.webview.page().setNetworkAccessManager(lilydoc.network.accessmanager()) self.webview.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks) self.webview.page().linkClicked.connect(self.openUrl) self.webview.page().setForwardUnsupportedContent(True) self.webview.page().unsupportedContent.connect(self.slotUnsupported) self.webview.urlChanged.connect(self.slotUrlChanged) self.webview.customContextMenuRequested.connect(self.slotShowContextMenu) tb.addAction(ac.help_back) tb.addAction(ac.help_forward) tb.addSeparator() tb.addAction(ac.help_home) tb.addAction(ac.help_print) tb.addSeparator() tb.addWidget(self.chooser) tb.addWidget(self.search) self.chooser.activated[int].connect(self.showHomePage) self.search.textEdited.connect(self.slotSearchChanged) self.search.returnPressed.connect(self.slotSearchReturnPressed) dockwidget.mainwindow().iconSizeChanged.connect(self.updateToolBarSettings) dockwidget.mainwindow().toolButtonStyleChanged.connect(self.updateToolBarSettings) app.settingsChanged.connect(self.readSettings) self.readSettings() self.loadDocumentation() self.showInitialPage() app.settingsChanged.connect(self.loadDocumentation) app.translateUI(self) def readSettings(self): s = QSettings() s.beginGroup("documentation") ws = self.webview.page().settings() family = s.value("fontfamily", self.font().family(), str) size = s.value("fontsize", 16, int) ws.setFontFamily(QWebSettings.StandardFont, family) ws.setFontSize(QWebSettings.DefaultFontSize, size) fixed = textformats.formatData('editor').font ws.setFontFamily(QWebSettings.FixedFont, fixed.family()) ws.setFontSize(QWebSettings.DefaultFixedFontSize, fixed.pointSizeF() * 96 / 72) def keyPressEvent(self, ev): if ev.text() == "/": self.search.setFocus() else: super(Browser, self).keyPressEvent(ev) def translateUI(self): try: self.search.setPlaceholderText(_("Search...")) except AttributeError: pass # not in Qt 4.6 def showInitialPage(self): """Shows the preferred start page. If a local documentation instance already has a suitable version, just loads it. Otherwise connects to the allLoaded signal, that is emitted when all the documentation instances have loaded their version information and then shows the start page (if another page wasn't yet loaded). """ if self.webview.url().isEmpty(): docs = lilydoc.manager.docs() version = lilypondinfo.preferred().version() index = -1 if version: for num, doc in enumerate(docs): if doc.version() is not None and doc.version() >= version: index = num # a suitable documentation is found break if index == -1: # nothing found (or LilyPond version not available), # wait for loading or show the most recent version if not lilydoc.manager.loaded(): lilydoc.manager.allLoaded.connect(self.showInitialPage) return index = len(docs) - 1 self.chooser.setCurrentIndex(index) self.showHomePage() def loadDocumentation(self): """Puts the available documentation instances in the combobox.""" i = self.chooser.currentIndex() self.chooser.clear() for doc in lilydoc.manager.docs(): v = doc.versionString() if doc.isLocal(): t = _("(local)") else: t = _("({hostname})").format(hostname=doc.url().host()) self.chooser.addItem("{0} {1}".format(v or _("<unknown>"), t)) self.chooser.setCurrentIndex(i) if not lilydoc.manager.loaded(): lilydoc.manager.allLoaded.connect(self.loadDocumentation, -1) return def updateToolBarSettings(self): mainwin = self.parentWidget().mainwindow() self.toolbar.setIconSize(mainwin.iconSize()) self.toolbar.setToolButtonStyle(mainwin.toolButtonStyle()) def showManual(self): """Invoked when the user presses F1.""" self.slotHomeFrescobaldi() # TEMP def slotUrlChanged(self): ac = self.parentWidget().actionCollection ac.help_back.setEnabled(self.webview.history().canGoBack()) ac.help_forward.setEnabled(self.webview.history().canGoForward()) def openUrl(self, url): if url.path().endswith(('.ily', '.lyi', '.ly')): self.sourceViewer().showReply(lilydoc.network.get(url)) else: self.webview.load(url) def slotUnsupported(self, reply): helpers.openUrl(reply.url()) def slotSearchChanged(self): text = self.search.text() if not text.startswith(':'): self.webview.page().findText(text, QWebPage.FindWrapsAroundDocument) def slotSearchReturnPressed(self): text = self.search.text() if not text.startswith(':'): self.slotSearchChanged() else: pass # TODO: implement full doc search def sourceViewer(self): try: return self._sourceviewer except AttributeError: from . import sourceviewer self._sourceviewer = sourceviewer.SourceViewer(self) return self._sourceviewer def showHomePage(self): """Shows the homepage of the LilyPond documentation.""" i = self.chooser.currentIndex() if i < 0: i = 0 doc = lilydoc.manager.docs()[i] url = doc.home() if doc.isLocal(): path = url.toLocalFile() langs = lilydoc.network.langs() if langs: for lang in langs: if os.path.exists(path + '.' + lang + '.html'): path += '.' + lang break url = QUrl.fromLocalFile(path + '.html') self.webview.load(url) def slotPrint(self): printer = QPrinter() dlg = QPrintDialog(printer, self) dlg.setWindowTitle(app.caption(_("Print"))) if dlg.exec_(): self.webview.print_(printer) def slotShowContextMenu(self, pos): hit = self.webview.page().currentFrame().hitTestContent(pos) menu = QMenu() if hit.linkUrl().isValid(): a = self.webview.pageAction(QWebPage.CopyLinkToClipboard) a.setIcon(icons.get("edit-copy")) a.setText(_("Copy &Link")) menu.addAction(a) menu.addSeparator() a = menu.addAction(icons.get("window-new"), _("Open Link in &New Window")) a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))(hit.linkUrl())) else: if hit.isContentSelected(): a = self.webview.pageAction(QWebPage.Copy) a.setIcon(icons.get("edit-copy")) a.setText(_("&Copy")) menu.addAction(a) menu.addSeparator() a = menu.addAction(icons.get("window-new"), _("Open Document in &New Window")) a.triggered.connect((lambda url: lambda: self.slotNewWindow(url))(self.webview.url())) if menu.actions(): menu.exec_(self.webview.mapToGlobal(pos)) def slotNewWindow(self, url): helpers.openUrl(url)
class LedgerAuthDialog(QDialog): def __init__(self, handler, data): '''Ask user for 2nd factor authentication. Support text, security card and paired mobile methods. Use last method from settings, but support new pairing and downgrade. ''' QDialog.__init__(self, handler.top_level_window()) self.handler = handler self.txdata = data self.idxs = self.txdata['keycardData'] if self.txdata['confirmationType'] > 1 else '' self.setMinimumWidth(650) self.setWindowTitle(_("Ledger Wallet Authentication")) self.cfg = copy.deepcopy(self.handler.win.wallet.get_keystore().cfg) self.dongle = self.handler.win.wallet.get_keystore().get_client().dongle self.ws = None self.pin = '' self.devmode = self.getDevice2FAMode() if self.devmode == 0x11 or self.txdata['confirmationType'] == 1: self.cfg['mode'] = 0 vbox = QVBoxLayout() self.setLayout(vbox) def on_change_mode(idx): if idx < 2 and self.ws: self.ws.stop() self.ws = None self.cfg['mode'] = 0 if self.devmode == 0x11 else idx if idx > 0 else 1 if self.cfg['mode'] > 1 and self.cfg['pair'] and not self.ws: self.req_validation() if self.cfg['mode'] > 0: self.handler.win.wallet.get_keystore().cfg = self.cfg self.handler.win.wallet.save_keystore() self.update_dlg() def add_pairing(): self.do_pairing() def return_pin(): self.pin = self.pintxt.text() if self.txdata['confirmationType'] == 1 else self.cardtxt.text() if self.cfg['mode'] == 1: self.pin = ''.join(chr(int(str(i),16)) for i in self.pin) self.accept() self.modebox = QWidget() modelayout = QHBoxLayout() self.modebox.setLayout(modelayout) modelayout.addWidget(QLabel(_("Method:"))) self.modes = QComboBox() modelayout.addWidget(self.modes, 2) self.addPair = QPushButton(_("Pair")) self.addPair.setMaximumWidth(60) modelayout.addWidget(self.addPair) modelayout.addStretch(1) self.modebox.setMaximumHeight(50) vbox.addWidget(self.modebox) self.populate_modes() self.modes.currentIndexChanged.connect(on_change_mode) self.addPair.clicked.connect(add_pairing) self.helpmsg = QTextEdit() self.helpmsg.setStyleSheet("QTextEdit { background-color: lightgray; }") self.helpmsg.setReadOnly(True) vbox.addWidget(self.helpmsg) self.pinbox = QWidget() pinlayout = QHBoxLayout() self.pinbox.setLayout(pinlayout) self.pintxt = QLineEdit() self.pintxt.setEchoMode(2) self.pintxt.setMaxLength(4) self.pintxt.returnPressed.connect(return_pin) pinlayout.addWidget(QLabel(_("Enter PIN:"))) pinlayout.addWidget(self.pintxt) pinlayout.addWidget(QLabel(_("NOT DEVICE PIN - see above"))) pinlayout.addStretch(1) self.pinbox.setVisible(self.cfg['mode'] == 0) vbox.addWidget(self.pinbox) self.cardbox = QWidget() card = QVBoxLayout() self.cardbox.setLayout(card) self.addrtext = QTextEdit() self.addrtext.setStyleSheet("QTextEdit { color:blue; background-color:lightgray; padding:15px 10px; border:none; font-size:20pt; font-family:monospace; }") self.addrtext.setReadOnly(True) self.addrtext.setMaximumHeight(130) card.addWidget(self.addrtext) def pin_changed(s): if len(s) < len(self.idxs): i = self.idxs[len(s)] addr = self.txdata['address'] if not constants.net.TESTNET: text = addr[:i] + '<u><b>' + addr[i:i+1] + '</u></b>' + addr[i+1:] else: # pin needs to be created from mainnet address addr_mainnet = bitcoin.script_to_address(bitcoin.address_to_script(addr), net=constants.BitcoinMainnet) addr_mainnet = addr_mainnet[:i] + '<u><b>' + addr_mainnet[i:i+1] + '</u></b>' + addr_mainnet[i+1:] text = str(addr) + '\n' + str(addr_mainnet) self.addrtext.setHtml(str(text)) else: self.addrtext.setHtml(_("Press Enter")) pin_changed('') cardpin = QHBoxLayout() cardpin.addWidget(QLabel(_("Enter PIN:"))) self.cardtxt = QLineEdit() self.cardtxt.setEchoMode(2) self.cardtxt.setMaxLength(len(self.idxs)) self.cardtxt.textChanged.connect(pin_changed) self.cardtxt.returnPressed.connect(return_pin) cardpin.addWidget(self.cardtxt) cardpin.addWidget(QLabel(_("NOT DEVICE PIN - see above"))) cardpin.addStretch(1) card.addLayout(cardpin) self.cardbox.setVisible(self.cfg['mode'] == 1) vbox.addWidget(self.cardbox) self.pairbox = QWidget() pairlayout = QVBoxLayout() self.pairbox.setLayout(pairlayout) pairhelp = QTextEdit(helpTxt[5]) pairhelp.setStyleSheet("QTextEdit { background-color: lightgray; }") pairhelp.setReadOnly(True) pairlayout.addWidget(pairhelp, 1) self.pairqr = QRCodeWidget() pairlayout.addWidget(self.pairqr, 4) self.pairbox.setVisible(False) vbox.addWidget(self.pairbox) self.update_dlg() if self.cfg['mode'] > 1 and not self.ws: self.req_validation() def populate_modes(self): self.modes.blockSignals(True) self.modes.clear() self.modes.addItem(_("Summary Text PIN (requires dongle replugging)") if self.txdata['confirmationType'] == 1 else _("Summary Text PIN is Disabled")) if self.txdata['confirmationType'] > 1: self.modes.addItem(_("Security Card Challenge")) if not self.cfg['pair']: self.modes.addItem(_("Mobile - Not paired")) else: self.modes.addItem(_("Mobile - {}").format(self.cfg['pair'][1])) self.modes.blockSignals(False) def update_dlg(self): self.modes.setCurrentIndex(self.cfg['mode']) self.modebox.setVisible(True) self.addPair.setText(_("Pair") if not self.cfg['pair'] else _("Re-Pair")) self.addPair.setVisible(self.txdata['confirmationType'] > 2) self.helpmsg.setText(helpTxt[self.cfg['mode'] if self.cfg['mode'] < 2 else 2 if self.cfg['pair'] else 4]) self.helpmsg.setMinimumHeight(180 if self.txdata['confirmationType'] == 1 else 100) self.pairbox.setVisible(False) self.helpmsg.setVisible(True) self.pinbox.setVisible(self.cfg['mode'] == 0) self.cardbox.setVisible(self.cfg['mode'] == 1) self.pintxt.setFocus(True) if self.cfg['mode'] == 0 else self.cardtxt.setFocus(True) self.setMaximumHeight(400) def do_pairing(self): rng = os.urandom(16) pairID = (hexlify(rng) + hexlify(hashlib.sha256(rng).digest()[0:1])).decode('utf-8') self.pairqr.setData(pairID) self.modebox.setVisible(False) self.helpmsg.setVisible(False) self.pinbox.setVisible(False) self.cardbox.setVisible(False) self.pairbox.setVisible(True) self.pairqr.setMinimumSize(300,300) if self.ws: self.ws.stop() self.ws = LedgerWebSocket(self, pairID) self.ws.pairing_done.connect(self.pairing_done) self.ws.start() def pairing_done(self, data): if data is not None: self.cfg['pair'] = [ data['pairid'], data['name'], data['platform'] ] self.cfg['mode'] = 2 self.handler.win.wallet.get_keystore().cfg = self.cfg self.handler.win.wallet.save_keystore() self.pin = 'paired' self.accept() def req_validation(self): if self.cfg['pair'] and 'secureScreenData' in self.txdata: if self.ws: self.ws.stop() self.ws = LedgerWebSocket(self, self.cfg['pair'][0], self.txdata) self.ws.req_updated.connect(self.req_updated) self.ws.start() def req_updated(self, pin): if pin == 'accepted': self.helpmsg.setText(helpTxt[3]) else: self.pin = str(pin) self.accept() def getDevice2FAMode(self): apdu = [0xe0, 0x24, 0x01, 0x00, 0x00, 0x01] # get 2fa mode try: mode = self.dongle.exchange( bytearray(apdu) ) return mode except BTChipException as e: debug_msg('Device getMode Failed') return 0x11 def closeEvent(self, evnt): debug_msg("CLOSE - Stop WS") if self.ws: self.ws.stop() if self.pairbox.isVisible(): evnt.ignore() self.update_dlg()
class H5PlotGUI(QDialog): """The main GUI for H5Plot. From here the SolSets, SolTabs and antennas to plot are selected. """ def __init__(self, h5file, logging_instance, parent=None): super(H5PlotGUI, self).__init__(parent) self.logger = logging_instance self.figures = [] self.h5parm = lh5.h5parm(h5file) self.solset_labels = self.h5parm.getSolsetNames() self.solset = self.h5parm.getSolset('sol000') self.soltab_labels = self.solset.getSoltabNames() self.soltab = self.solset.getSoltab(self.soltab_labels[0]) self.stations = self.soltab.getValues()[1]['ant'] self.refant = 'CS001HBA0' self.wrapphase = True self.stcache = SoltabCache(self.soltab.getValues(), self.soltab.getAxesNames()) rvals, raxes = reorder_soltab(self.soltab) self.stcache.update(rvals, raxes) self.move(300, 300) self.setWindowTitle('H5Plot') self.solset_label = QLabel('SolSet: ') self.solset_picker = QComboBox() for l in self.solset_labels: self.solset_picker.addItem(l) self.solset_picker.activated.connect(self._solset_picker_event) self.soltab_label_y = QLabel('Plot ') self.soltab_label_x = QLabel(' vs ') self.soltab_picker = QComboBox() for l in self.soltab_labels: self.soltab_picker.addItem(l) self.soltab_picker.activated.connect(self._soltab_picker_event) self.axis_picker = QComboBox() self.axis_picker.addItems(['time', 'freq']) self.axis_picker.activated.connect(self._axis_picker_event) self.axis = 'time' self.refant_label = QLabel('Ref. Ant. ') self.refant_picker = QComboBox() self.refant_picker.addItems(self.stations) self.refant_picker.activated.connect(self._refant_picker_event) self.phasewrap_box = QCheckBox('Wrap Phases') self.phasewrap_box.setChecked(True) self.phasewrap_box.setEnabled(False) self.phasewrap_box.stateChanged.connect(self._phasewrap_event) self.plot_button = QPushButton('Plot') self.plot_button.clicked.connect(self._plot_button_event) self.station_picker = QListWidget() self.station_picker.addItems(self.stations) self.station_picker.setCurrentRow(0) plot_layout = QGridLayout() plot_layout.addWidget(self.soltab_label_y, 0, 0) plot_layout.addWidget(self.soltab_picker, 0, 1) plot_layout.addWidget(self.soltab_label_x, 0, 2) plot_layout.addWidget(self.axis_picker, 0, 3) plot_layout.addWidget(self.refant_label, 1, 0) plot_layout.addWidget(self.refant_picker, 1, 1) plot_layout.addWidget(self.phasewrap_box, 1, 3) layout = QFormLayout(self) layout.addRow(self.solset_label, self.solset_picker) layout.addRow(plot_layout) layout.addRow(self.plot_button) layout.addRow(self.station_picker) def _axis_picker_event(self): """Callback function for when the x-axis is changed. Sets the `axis` attribute to the selected axis """ self.logger.debug('Axis changed to: ' + self.axis_picker.currentText()) self.axis = self.axis_picker.currentText() def closeEvent(self, event): self.logger.info('Closing all open figures before exiting.') plt.close('all' ) event.accept() def _refant_picker_event(self): self.logger.debug('Reference antenna changed to: ' + self.refant_picker.currentText()) self.refant = self.refant_picker.currentText() def _solset_picker_event(self): """Callback function for when the SolSet is changed. Sets the `solset` attribute. """ self.logger.debug('Solset changed to: ' + self.solset_picker.currentText()) self.solset = self.h5parm.getSolset(self.solset_picker.currentText()) self.soltab_labels = self.solset.getSoltabNames() self.soltab_picker.clear() for l in self.soltab_labels: self.soltab_picker.addItem(l) self._soltab_picker_event() def _soltab_picker_event(self): """Callback function for when the SolTab is changed. Sets the `soltab` attribute. """ self.logger.debug('Soltab changed to: ' + self.soltab_picker.currentText()) self.soltab = self.solset.getSoltab(self.soltab_picker.currentText()) rvals, raxes = reorder_soltab(self.soltab) self.stcache.update(rvals, raxes) def _phasewrap_event(self): self.logger.debug('Phase wrapping changed to ' + str(self.phasewrap_box.isChecked())) self.wrapphase = self.phasewrap_box.isChecked() def _plot_button_event(self): """Callback function for when the plot button is pressed. Calls the `plot` function subsecquently. """ self.logger.debug('Plotting button pressed.') self.plot(labels=(self.axis, self.soltab.name)) def plot(self, labels=('x-axis', 'y-axis'), limits=([None, None], [None, None])): self.logger.info('Plotting ' + self.soltab.name + ' vs ' + self.axis + \ ' for ' + self.solset.name) antenna = self.station_picker.currentRow() refantenna = self.refant_picker.currentIndex() # Values have shape (timestamps, frequencies, antennas, polarizations, directions). values = self.stcache.values[0] if (('rotationmeasure' in self.soltab.name) or ('RMextract' in self.soltab.name) or ('clock' in self.soltab.name)) and (self.axis == 'freq'): self.logger.warning('Rotation Measure does not support frequency axis! Switch to time instead.') return else: x_axis = self.stcache.values[1][self.axis] st_type = self.soltab.getType() print(st_type) fig = plt.figure() ax = fig.add_subplot(111) ax.set_title(self.stations[antenna]) if self.axis == 'time': if 'rotationmeasure' in self.soltab.name: y_axis = values[:, antenna] ax.plot(x_axis, y_axis) elif ('pol' in self.stcache.axes) and ('dir' in self.stcache.axes): if st_type == 'phase': ax.set_ylim(-np.pi, np.pi) # Plot phase-like quantities w.r.t. to a reference antenna. y_axis = values[:, 0, antenna, :, 0] - values[:, 0, refantenna, :, 0] if self.wrapphase: y_axis = wrap_phase(y_axis) elif (st_type == 'clock') or (st_type == 'rotationmeasure'): y_axis = values[:, antenna] else: y_axis = values[:, 0, antenna, :, 0] for i,y in enumerate(y_axis): ax.plot(x_axis, y[:,i], 'h', label=self.stcache.values[1]['pol'][i]) elif 'pol' in self.stcache.axes: if st_type == 'phase': ax.set_ylim(-np.pi, np.pi) # Plot phase-like quantities w.r.t. to a reference antenna. y_axis = values[:, 0, antenna, :] - values[:, 0, refantenna, :] if self.wrapphase: y_axis = wrap_phase(y_axis) elif (st_type == 'clock') or (st_type == 'rotationmeasure'): y_axis = values[:, antenna] else: y_axis = values[:, 0, antenna, :] for i in range(y_axis.shape[1]): ax.plot(x_axis, y_axis[:, i], 'h', label=self.stcache.values[1]['pol'][i]) elif 'dir' in self.stcache.axes: if st_type == 'phase': ax.set_ylim(-np.pi, np.pi) # Plot phase-like quantities w.r.t. to a reference antenna. y_axis = values[:, 0, antenna, 0] - values[:, 0, refantenna, 0] if self.wrapphase: y_axis = wrap_phase(y_axis) elif (st_type == 'clock') or (st_type == 'rotationmeasure'): y_axis = values[:, antenna] else: y_axis = values[:, 0, antenna, 0] ax.plot(x_axis, y_axis[:, i], 'h') elif ('pol' not in self.stcache.axes) and ('dir' not in self.stcache.axes): if (st_type == 'clock') or (st_type == 'rotationmeasure'): y_axis = values[:, antenna] else: y_axis = values[:, 0, antenna] ax.plot(x_axis, y_axis) elif self.axis == 'freq': if ('rotationmeasure' in self.soltab.name) or ('clock' in self.soltab.name): self.logger.warning('Rotation Measure does not support frequency axis! Switch to time instead.') if ('pol' in self.stcache.axes) and ('dir' in self.stcache.axes): if st_type == 'phase': ax.set_ylim(-np.pi, np.pi) # Plot phase-like quantities w.r.t. to a reference antenna. y_axis = values[0, :, antenna, :, 0] - values[0, :, refantenna, :, 0] if self.wrapphase: y_axis = wrap_phase(y_axis) else: y_axis = values[0, :, antenna, :, 0] for i,y in enumerate(y_axis): ax.plot(x_axis, y[:,i]) elif 'pol' in self.stcache.axes: if st_type == 'phase': ax.set_ylim(-np.pi, np.pi) # Plot phase-like quantities w.r.t. to a reference antenna. y_axis = values[0, :, antenna, :] - values[0, :, refantenna, :] if self.wrapphase: y_axis = wrap_phase(y_axis) else: y_axis = values[0, :, antenna, :] for i in range(y_axis.shape[1]): ax.plot(x_axis, y_axis[:, i], 'h', label=self.stcache.values[1]['pol'][i]) elif 'dir' in self.stcache.axes: if st_type == 'phase': ax.set_ylim(-np.pi, np.pi) # Plot phase-like quantities w.r.t. to a reference antenna. y_axis = values[0, :, antenna, 0] - values[0, :, refantenna, 0] if self.wrapphase: y_axis = wrap_phase(y_axis) else: y_axis = values[0, :, antenna, 0] elif ('pol' not in self.stcache.axes) and ('dir' not in self.stcache.axes): y_axis = values[0, :, antenna] ax.plot(x_axis, y_axis) ax.set(xlabel=self.axis, ylabel=labels[1], xlim=limits[0], ylim=limits[1]) if ax.get_legend_handles_labels()[1]: ax.legend() self.figures.append(fig) fig.show()
class SvgView(QWidget): def __init__(self, dockwidget): super(SvgView, self).__init__(dockwidget) self._document = None self._setting_zoom = False self.view = view.View(self) self.pageLabel = QLabel() self.pageCombo = QComboBox(sizeAdjustPolicy=QComboBox.AdjustToContents) layout = QVBoxLayout(spacing=0) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) hbox = QHBoxLayout(spacing=0) hbox.addWidget(self.pageLabel) hbox.addWidget(self.pageCombo) self.zoomInButton = QToolButton(autoRaise=True) self.zoomOutButton = QToolButton(autoRaise=True) self.zoomOriginalButton = QToolButton(autoRaise=True) self.zoomNumber = QSpinBox(minimum=10, maximum=1000, suffix="%") ac = dockwidget.actionCollection self.zoomInButton.setDefaultAction(ac.svg_zoom_in) self.zoomOutButton.setDefaultAction(ac.svg_zoom_out) self.zoomOriginalButton.setDefaultAction(ac.svg_zoom_original) hbox.addWidget(self.zoomInButton) hbox.addWidget(self.zoomNumber) hbox.addWidget(self.zoomOutButton) hbox.addWidget(self.zoomOriginalButton) self.resetButton = QPushButton("reload", self) self.resetButton.clicked.connect(self.reLoadDoc) hbox.addWidget(self.resetButton) self.saveButton = QPushButton("save edits", self) self.saveButton.clicked.connect(self.callSave) hbox.addWidget(self.saveButton) hbox.addStretch(1) layout.addLayout(hbox) layout.addWidget(self.view) app.jobFinished.connect(self.initSvg) app.documentClosed.connect(self.slotDocumentClosed) app.documentLoaded.connect(self.initSvg) self.pageCombo.currentIndexChanged.connect(self.changePage) self.zoomNumber.valueChanged.connect(self.slotZoomNumberChanged) self.view.zoomFactorChanged.connect(self.slotViewZoomChanged) dockwidget.mainwindow().currentDocumentChanged.connect(self.initSvg) self.zoomNumber.setValue(100) doc = dockwidget.mainwindow().currentDocument() if doc: self.initSvg(doc) app.translateUI(self) def translateUI(self): self.pageLabel.setText(_("Page:")) def mainwindow(self): return self.parent().mainwindow() def initSvg(self, doc): """Opens first page of score after compilation""" if doc == self.mainwindow().currentDocument(): files = svgfiles.SvgFiles.instance(doc) model = files.model() # forces update if files: self._document = doc with qutil.signalsBlocked(self.pageCombo): self.pageCombo.setModel(model) self.pageCombo.setCurrentIndex(files.current) self.view.load(files.url(files.current)) def reLoadDoc(self): """Reloads current document.""" if self._document: self.initSvg(self._document) def callSave(self): """Call save function""" self.view.evalSave() def getCurrent(self): files = svgfiles.SvgFiles.instance(self._document) return files.filename(files.current) def slotZoomNumberChanged(self, value): self._setting_zoom = True self.view.setZoomFactor(value / 100.0) self._setting_zoom = False def slotViewZoomChanged(self): if not self._setting_zoom: self.zoomNumber.setValue(int(self.view.zoomFactor() * 100)) def changePage(self, page_index): """change page of score""" doc = self._document if doc: files = svgfiles.SvgFiles.instance(doc) if files: files.current = page_index svg = files.url(page_index) self.view.load(svg) def slotDocumentClosed(self, doc): if doc == self._document: self._document = None if self.pageCombo.model(): self.pageCombo.model().deleteLater() self.pageCombo.clear() self.pageCombo.update() # otherwise it doesn't redraw self.view.clear()
class InputTab(SerafinInputTab): def __init__(self, parent): super().__init__(parent) self.old_options = ('1', '') self.data = None self.mesh = None self.polylines = [] self.var_IDs = [] self._initWidgets() # some instance attributes will be set there self._setLayout() self._bindEvents() self.setMinimumWidth(800) def _initWidgets(self): # create the button open Polygon self.btnOpenPolyline = QPushButton('Load\nSections', self, icon=self.style().standardIcon(QStyle.SP_DialogOpenButton)) self.btnOpenPolyline.setToolTip('<b>Open</b> a .i2s or .shp file') self.btnOpenPolyline.setFixedSize(105, 50) self.btnOpenPolyline.setEnabled(False) # create some text fields displaying the IO files info self.polygonNameBox = QPlainTextEdit() self.polygonNameBox.setReadOnly(True) self.polygonNameBox.setFixedHeight(50) self.csvNameBox = QLineEdit() self.csvNameBox.setReadOnly(True) self.csvNameBox.setFixedHeight(30) # create some widgets for flux options self.fluxBox = QComboBox() self.fluxBox.setFixedSize(400, 30) self.timeSampling = QLineEdit('1') self.timeSampling.setFixedWidth(50) # create the submit button self.btnSubmit = QPushButton('Submit\n(to .csv)', self, icon=self.style().standardIcon(QStyle.SP_DialogSaveButton)) self.btnSubmit.setFixedSize(105, 50) self.btnSubmit.setEnabled(False) def _bindEvents(self): self.btnOpen.clicked.connect(self.btnOpenSerafinEvent) self.btnOpenPolyline.clicked.connect(self.btnOpenPolylineEvent) self.btnSubmit.clicked.connect(self.btnSubmitEvent) self.timeSampling.editingFinished.connect(self._checkSamplingFrequency) def _setLayout(self): mainLayout = QVBoxLayout() mainLayout.addItem(QSpacerItem(10, 10)) mainLayout.setSpacing(15) mainLayout.addLayout(self.input_layout) mainLayout.addItem(QSpacerItem(10, 20)) hlayout = QHBoxLayout() hlayout.addItem(QSpacerItem(30, 1)) hlayout.addWidget(self.btnOpenPolyline) hlayout.addWidget(self.polygonNameBox) mainLayout.addLayout(hlayout) mainLayout.addItem(QSpacerItem(10, 10)) mainLayout.addStretch() glayout = QGridLayout() glayout.addWidget(QLabel(' Select the flux to compute'), 1, 1) glayout.addWidget(self.fluxBox, 1, 2) hlayout = QHBoxLayout() hlayout.addWidget(QLabel('Time sampling frequency')) hlayout.addWidget(self.timeSampling) hlayout.setAlignment(self.timeSampling, Qt.AlignLeft) hlayout.addStretch() glayout.addLayout(hlayout, 2, 2) glayout.setAlignment(Qt.AlignLeft) glayout.setSpacing(10) mainLayout.addLayout(glayout) hlayout = QHBoxLayout() hlayout.addItem(QSpacerItem(30, 1)) hlayout.addWidget(self.btnSubmit) hlayout.addWidget(self.csvNameBox) mainLayout.addLayout(hlayout) mainLayout.addStretch() mainLayout.addItem(QSpacerItem(10, 15)) mainLayout.addWidget(QLabel(' Message logs')) mainLayout.addWidget(self.logTextBox.widget) self.setLayout(mainLayout) def _reinitInput(self): self.reset() self.data = None self.csvNameBox.clear() self.mesh = None self.csvNameBox.clear() self.old_options = (self.timeSampling.text(), self.fluxBox.currentText()) self.btnOpenPolyline.setEnabled(False) self.timeSampling.setText('1') self.fluxBox.clear() self.btnSubmit.setEnabled(False) def _resetDefaultOptions(self): sampling_frequency, flux_type = self.old_options if int(sampling_frequency) <= len(self.data.time): self.timeSampling.setText(sampling_frequency) for i in range(self.fluxBox.count()): text = self.fluxBox.itemText(i) if text == flux_type: self.fluxBox.setCurrentIndex(i) self.btnSubmit.setEnabled(True) break def _addFluxOptions(self, header): for possible_flux in PossibleFluxComputation(header.var_IDs, header.var_names): self.fluxBox.addItem(possible_flux) return self.fluxBox.count() > 0 def _checkSamplingFrequency(self): try: sampling_frequency = int(self.timeSampling.text()) except ValueError: QMessageBox.critical(self, 'Error', 'The sampling frequency must be a number!', QMessageBox.Ok) self.timeSampling.setText('1') return if sampling_frequency < 1 or sampling_frequency > len(self.data.time): QMessageBox.critical(self, 'Error', 'The sampling frequency must be in the range [1; nbFrames]!', QMessageBox.Ok) self.timeSampling.setText('1') return def _getFluxSection(self): selection = self.fluxBox.currentText() var_IDs = PossibleFluxComputation.get_variables(selection) flux_type = PossibleFluxComputation.get_flux_type(var_IDs) return flux_type, var_IDs, selection def btnOpenSerafinEvent(self): canceled, filename = super().open_event() if canceled: return self._reinitInput() success, data = self.read_2d(filename) if not success: return flux_added = self._addFluxOptions(data.header) if not flux_added: QMessageBox.critical(self, 'Error', 'No flux is computable from this file.', QMessageBox.Ok) self.summaryTextBox.clear() return # record the mesh for future visualization and calculations self.parent.inDialog() meshLoader = LoadMeshDialog('flux', data.header) self.mesh = meshLoader.run() self.parent.outDialog() if meshLoader.thread.canceled: self.fluxBox.clear() self.polygonNameBox.clear() self.summaryTextBox.clear() return self.data = data self._resetDefaultOptions() self.btnOpenPolyline.setEnabled(True) self.parent.imageTab.reset() self.parent.tab.setTabEnabled(1, False) def btnOpenPolylineEvent(self): success, filename, polylines = open_polylines() if not success: return self.polylines = polylines logging.info('Finished reading the polyline file %s' % filename) self.polygonNameBox.clear() self.polygonNameBox.appendPlainText(filename + '\n' + 'The file contains {} open polyline{}.'.format( len(self.polylines), 's' if len(self.polylines) > 1 else '')) self.csvNameBox.clear() self.btnSubmit.setEnabled(True) self.parent.imageTab.reset() self.parent.tab.setTabEnabled(1, False) def btnSubmitEvent(self): canceled, filename = save_dialog('CSV') if canceled: return self.csvNameBox.setText(filename) sampling_frequency = int(self.timeSampling.text()) flux_type, self.var_IDs, flux_title = self._getFluxSection() self.parent.tab.setTabEnabled(1, False) logging.info('Writing the output to %s' % filename) self.parent.inDialog() # initialize the progress bar progressBar = OutputProgressDialog() # do the calculations names = [poly.id for poly in self.polylines] try: with Serafin.Read(self.data.filename, self.data.language) as input_stream: input_stream.header = self.data.header input_stream.time = self.data.time calculator = FluxCalculatorThread(flux_type, self.var_IDs, input_stream, names, self.polylines, sampling_frequency, self.mesh, self.parent.csv_separator, self.parent.fmt_float) progressBar.setValue(5) QApplication.processEvents() with open(filename, 'w') as f2: progressBar.connectToThread(calculator) calculator.write_csv(f2) except (Serafin.SerafinRequestError, Serafin.SerafinValidationError) as e: QMessageBox.critical(None, 'Serafin Error', e.message, QMessageBox.Ok, QMessageBox.Ok) return if not calculator.canceled: progressBar.outputFinished() progressBar.exec_() self.parent.outDialog() if calculator.canceled: self.csvNameBox.clear() return # unlock the image viewer self.parent.imageTab.getData(flux_title) self.parent.tab.setTabEnabled(1, True)
class ToneGenerator(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) super().__init__(parent) # start new thread that constantly polls MIDI input self.create_MIDI() # create GUI (windows, slider, etc...) self.create_UI(parent) format = QAudioFormat() self.create_AUDIO(format) self.generator = Flute(format, self) self.generator.start() self.output.start(self.generator) def create_AUDIO(self, format): format.setChannelCount(AUDIO_CHANS) format.setSampleRate(SAMPLE_RATE) format.setSampleSize(SAMPLE_SIZE) format.setCodec("audio/pcm") format.setByteOrder( QAudioFormat.LittleEndian ) format.setSampleType( QAudioFormat.SignedInt ) self.output = QAudioOutput(format, self) output_buffer_size = \ int(2*SAMPLE_RATE \ *CTRL_INTERVAL/1000) self.output.setBufferSize( output_buffer_size ) def create_MIDI(self): # Create the port reader object self.midiListener = MidiPortReader() # Create a thread which will read it self.listenerThread = QThread() # Take the object and move it # to the new thread (it isn't running yet) self.midiListener.moveToThread(self.listenerThread) # Tell Qt the function to call # when it starts the thread self.listenerThread.started.connect(self.midiListener.listener) # connect pyqtSignals to slots in ToneGenerator self.midiListener.newNoteFrequency.connect(self.on_newNoteFrequency) self.midiListener.newNoteVelocity.connect(self.on_newNoteVelocity) self.midiListener.portClosed.connect(self.on_portClosed) # Fingers in ears, eyes tight shut... self.listenerThread.start() # Good grief, IT WORKS! def create_UI(self, parent): # Create a slider to fine tune freq and two buttons #self.octaveBox = QSlider(Qt.Horizontal) #self.octaveBox.setMinimum(-100) #self.octaveBox.setMaximum(100) self.octaveBox = QSpinBox() self.octaveBox.setRange(-5,5) self.octaveLabel = QLabel("Octave: ") self.quitButton = QPushButton(self.tr('&Quit')) # create dropdown menu so user can choose midi device in use (populate list from data from midi listener object) self.MIDIMenu = QComboBox() self.MIDIMenu.addItems(self.midiListener.getMIDIDevices()) # create ADSR sliders self.aSlider = QSlider(Qt.Vertical) self.aSlider.setMinimum(1) self.aSlider.setMaximum(50) self.aSlider.setSliderPosition(1) self.dSlider = QSlider(Qt.Vertical) self.dSlider.setMinimum(1) self.dSlider.setMaximum(50) self.dSlider.setSliderPosition(8) self.sSlider = QSlider(Qt.Vertical) self.sSlider.setMinimum(1) self.sSlider.setMaximum(100) self.sSlider.setSliderPosition(80) self.rSlider = QSlider(Qt.Vertical) self.rSlider.setMinimum(1) self.rSlider.setMaximum(100) self.rSlider.setSliderPosition(50) # No parent: we're going to add this # to vLayout. hLayout1 = QHBoxLayout() hLayout1.addWidget(self.octaveLabel) hLayout1.addWidget(self.octaveBox) hLayout2 = QHBoxLayout() hLayout2.addWidget(self.aSlider) hLayout2.addWidget(self.dSlider) hLayout2.addWidget(self.sSlider) hLayout2.addWidget(self.rSlider) hLayout3 = QHBoxLayout() hLayout3.addWidget(self.MIDIMenu) hLayout3.addWidget(self.quitButton) # parent = self: this is the # "top level" layout vLayout = QVBoxLayout(self) vLayout.addLayout(hLayout1) vLayout.addLayout(hLayout2) vLayout.addLayout(hLayout3) # connect qt object signals to slots self.quitButton.clicked.connect(self.quitClicked) self.octaveBox.valueChanged.connect(self.changeOctave) self.aSlider.valueChanged.connect(self.changeADSRParam) self.dSlider.valueChanged.connect(self.changeADSRParam) self.sSlider.valueChanged.connect(self.changeADSRParam) self.rSlider.valueChanged.connect(self.changeADSRParam) self.MIDIMenu.currentIndexChanged[str].connect(self.changeMIDIDevice) # this isn't a @pyqtSlot(), the text is passed directly to the function def changeMIDIDevice(self, dev): self.midiListener.setMIDIDevice(dev) @pyqtSlot() def quitClicked(self): self.close() @pyqtSlot() def changeOctave(self): #scale slider value to freq and pass to subclass to update filter self.generator.setOctave(self.octaveBox.value()) @pyqtSlot(float) def on_newNoteFrequency(self, freq): # change value of filter cutoff so it sounds like we're playing a different note self.generator.updateFilter(freq) @pyqtSlot(int) def on_newNoteVelocity(self, value): # note_off message doesn't work with shit USB keyboards, so we simulate a note_off message with the velocity if value != 0: self.generator.playNote() else: self.generator.stopNote() @pyqtSlot() def on_portClosed(self): # when port has closed, clear drop down menu and rescan for MIDI devices self.MIDIMenu.clear() self.MIDIMenu.addItems(self.midiListener.getMIDIDevices()) @pyqtSlot() def changeADSRParam(self): self.generator.updateADSR(self.aSlider.value()/10, self.dSlider.value()/10, self.sSlider.value()/100, self.rSlider.value()/10)
class MainView(base, form): def __init__(self, pipeline, parent=None): super(base, self).__init__(parent) self.setupUi(self) self.pipeline = pipeline self.pip_widgets = [] self.default_pips = [] self.draw_ui() self.connect_ui() def register_observers(self): pass def connect_ui(self): """ This function connects the ui using signals from the ui elements and its method counterparts. """ self.input_btn.clicked.connect(self.set_input_url) self.output_btn.clicked.connect(self.set_output_url) self.save_btn.clicked.connect(self.save_pipeline) self.load_favorite_pipelines() self.fav_pips_combo_box.activated.connect(self.select_default_pip) self.run_btn.clicked.connect(self.run) self.delete_btn.clicked.connect(self.trash_pipeline) self.add_btn.clicked.connect(lambda: self.add_pipe_entry_new()) def draw_ui(self): """ This function draws all additional UI elements. If you want the application to display any additional things like a button you can either add it in the QtDesigner or declare it here. """ # *TODO* Create these ones with Qt Designer and put them into select_cat_alg_vbox_layout. I failed self.ComboxCategories = QComboBox() self.stackedWidgetComboxesAlgorithms = QStackedWidget() self.select_cat_alg_vbox_layout.addWidget(self.ComboxCategories) self.select_cat_alg_vbox_layout.addWidget(self.stackedWidgetComboxesAlgorithms) self.ComboxCategories.hide() """ This function is concerned with drawing all non static elements into the GUI. """ """self.set_pip_title("A. Junius2") self.set_preset(["A.Junius", "test", "test", "test"]) self.add_pip_entry("../assets/images/P.png", "Preprocessing - adaptive trehsold watershed") self.add_pip_entry("../assets/images/P.png", "Preprocessing - adaptive trehsold watershed") self.add_pip_entry("../assets/images/P.png", "Preprocessing - adaptive trehsold watershed") self.add_pip_entry("../assets/images/P.png", "Preprocessing - adaptive trehsold watershed") self.add_pip_entry("../assets/images/P.png", "Preprocessing - adaptive trehsold watershed") self.add_pip_entry("../assets/images/P.png", "Preprocessing - adaptive trehsold watershed") self.add_pip_entry("../assets/images/P.png", "Preprocessing - adaptive trehsold watershed") self.add_cat_image("../assets/images/seg_fav.jpeg", "Preprocessing") self.add_cat_image("../assets/images/wing.jpeg", "Preprocessing") self.add_cat_image("../assets/images/wing.jpeg", "Preprocessing") self.add_cat_image("../assets/images/wing.jpeg", "Preprocessing") self.add_cat_image("../assets/images/wing.jpeg", "Preprocessing") self.add_cat_image("../assets/images/wing.jpeg", "Preprocessing") self.add_cat_image("../assets/images/wing.jpeg", "Preprocessing") self.main_image_label.setPixmap(QtGui.QPixmap("wing.jpeg")) category_combo_box = ComboBoxWidget("type") category_combo_box.add_item("Preprocessing", "../assets/images/P.png") category_combo_box.add_item("Segmentation", "../assets/images/S.png") category_combo_box.add_item("Graph Detection", "../assets/images/D.png") category_combo_box.add_item("Graph Filtering", "../assets/images/F.png") alg_combo_box = ComboBoxWidget("algorithm") alg_combo_box.add_item("Otsus") alg_combo_box.add_item("Guo Hall") alg_combo_box.add_item("Adaptive Treshold") slider_1 = SliderWidget("slider1das", 0, 10, 1, 4, True) slider_2 = SliderWidget("slider1", 0, 10, 2, 4, False) slider_3 = SliderWidget("sliderböadsad", 0, 10, 1, 4, True) slider_4 = SliderWidget("sliderböadsad", 0, 10, 1, 4, True) slider_5 = SliderWidget("sliderböadsad", 0, 10, 1, 4, True) checkbox_1 = CheckBoxWidget("checkbox1", True) self.setting_widget_vbox_layout.addWidget(category_combo_box) self.setting_widget_vbox_layout.addWidget(alg_combo_box) self.setting_widget_vbox_layout.addWidget(slider_1) self.setting_widget_vbox_layout.addWidget(slider_2) self.setting_widget_vbox_layout.addWidget(slider_3) self.setting_widget_vbox_layout.addWidget(slider_4) self.setting_widget_vbox_layout.addWidget(slider_5) self.setting_widget_vbox_layout.addWidget(checkbox_1) self.setting_widget_vbox_layout.setAlignment(Qt.AlignTop)""" def set_pip_title(self, title): """ Sets the title of the current selected pipeline in the ui. Args: | *title*: the title of the pipeline | *label_ref*: the reference to the label. """ self.current_pip_label.setText(title) def load_dark_theme(self, application): """ This function is called to load the white theme with all its icons for the buttons and the css file. Args: application: the cureent app instance """ # load buttons pixmap_icon = QtGui.QPixmap("./assets/images/add_white.png") q_icon = QtGui.QIcon(pixmap_icon) self.add_btn.setIcon(q_icon) pixmap_icon = QtGui.QPixmap("./assets/images/trash_white.png") q_icon = QtGui.QIcon(pixmap_icon) self.delete_btn.setIcon(q_icon) pixmap_icon = QtGui.QPixmap("./assets/images/diskette_white.png") q_icon = QtGui.QIcon(pixmap_icon) self.save_btn.setIcon(q_icon) pixmap_icon = QtGui.QPixmap("./assets/images/up-arrow_white.png") q_icon = QtGui.QIcon(pixmap_icon) self.input_btn.setIcon(q_icon) pixmap_icon = QtGui.QPixmap("./assets/images/folder_white.png") q_icon = QtGui.QIcon(pixmap_icon) self.output_btn.setIcon(q_icon) @pyqtSlot(int) def select_default_pip(self, index): """ This is the slot for the Pipeline combobox in the ui Args: index: index of the option currently selected """ # delete current pipeline self.trash_pipeline() # get url and name name, url = self.default_pips[index - 1] # parse the json in the model self.pipeline.load_pipeline_json(url) print("PARSER" + str(self.pipeline.executed_cats[0].active_algorithm)) print("PARSER" + str(self.pipeline.executed_cats[1].active_algorithm)) # set the title self.set_pip_title(name) # Create an entry in the pipeline widget for every step in the pipeline for i in range(0, len(self.pipeline.executed_cats)): self.add_pipe_entry_new(i) self.scroll_down_pip() """for widget in alg_widgets: self.setting_widget_vbox_layout.addWidget(widget)""" def trash_pipeline(self): """ This method clears the complete pipeline while users clicked the trash button. """ # remove all entries in the pipeline list while self.pip_widget_vbox_layout.count(): child = self.pip_widget_vbox_layout.takeAt(0) child.widget().deleteLater() while self.stackedWidget_Settings.currentWidget() is not None: self.stackedWidget_Settings.removeWidget(self.stackedWidget_Settings.currentWidget()) self.settings_collapsable.setTitle("") # remove the pipeline name self.set_pip_title("") # remove all entries int the executed_cats of the model pipeline del self.pipeline.executed_cats[:] # remove all widgets del self.pip_widgets[:] # remove category algorith dropdown self.remove_cat_alg_dropdown() # remove all entries from the pipeline model del self.pipeline.executed_cats[:] @pyqtSlot() def run(self): """ This method runs the the pipeline by calling the process methode in pipeline """ self.pipeline.process() @pyqtSlot() def set_input_url(self): """ This method sets the url for the input image in the pipeline. """ url = QtWidgets.QFileDialog.getOpenFileNames() if url[0]: print(url[0]) print(url[0][0]) self.lineEdit.setText(url[0][0]) self.pipeline.set_input(url[0][0]) @pyqtSlot() def set_output_url(self): """ This method sets the url for the output folder in the pipeline. Args: url: the url to the output folder a user selected in the ui """ url = QtWidgets.QFileDialog.getExistingDirectory() if url: print(url) print(url) self.custom_line_edit.setText(url) self.pipeline.set_output_dir(url) def load_favorite_pipelines(self): """ Scans the directory for default pipelines to display all available items """ self.fav_pips_combo_box.addItem("Please Select") # scan the directory for default pipelines for file in os.listdir("./_default_pipelines"): if file.endswith(".json"): name = file.split(".")[0] url = os.path.abspath("./_default_pipelines" + "/" + file) self.default_pips.append([name, url]) self.fav_pips_combo_box.addItem(name) @pyqtSlot() def save_pipeline(self): """ Saves the pipeline as a json at the users file system. """ url = str(QtWidgets.QFileDialog.getSaveFileName()[0]) split_list = url.split("/") name = split_list[len(split_list) - 1].split(".")[0] del split_list[len(split_list) - 1] url = url.replace(name, "") self.pipeline.save_pipeline_json(name, url) @pyqtSlot(int) def remove_pip_entry(self, pipe_entry_widget, settings_widget, cat=None): """ Removes the pip entry at the given position in the ui Args: pipeline_index (object): settings_widget: position: position at which the pip entry gets removed """ # remove pipeline entry widget from ui self.pip_widget_vbox_layout.removeWidget(pipe_entry_widget) pipe_entry_widget.deleteLater() # remove it settings widgets from ui if settings_widget is not None: if self.stackedWidget_Settings.currentWidget() == settings_widget: self.stackedWidget_Settings.hide() self.remove_cat_alg_dropdown() self.settings_collapsable.setTitle("Settings") self.stackedWidget_Settings.removeWidget(settings_widget) # remove in model if cat is not None: print("Remove entry at pos " + str(self.pipeline.get_index(cat)) + " " + str(cat)) self.pipeline.delete_category(self.pipeline.get_index(cat)) def change_pip_entry_alg(self, position, new_category, new_algorithm, pipe_entry_widget, settings_widget): """ Changes the selected algorithm of the pipeline entry at the position. Afterwards create all widgets for this algorithm instance Args: position: the position of the pipeline entry algorithm: the selected algorithm for this category """ print("Position to be changed:" + str(position)) print("Pipeline length: " + str(len(self.pipeline.executed_cats))) old_cat = self.pipeline.executed_cats[position] old_alg = old_cat.active_algorithm print("Old Cat found in pipeline: " + str(old_cat)) print("Old Alg: found in pipeline:" + str(old_alg)) print("New Category given:" + str(new_category)) print("New Algorithm given:" + str(new_algorithm)) # set in model self.pipeline.change_category(new_category, position) self.pipeline.change_algorithm(new_algorithm, position) new_cat = self.pipeline.executed_cats[position] new_alg = new_cat.active_algorithm # change settings widgets self.remove_pip_entry(pipe_entry_widget, settings_widget) (new_pipe_entry_widget, new_settings_widget) = self.add_pipe_entry_new(position) self.stackedWidget_Settings.show() self.stackedWidget_Settings.setCurrentIndex(position) self.settings_collapsable.setTitle(new_alg.get_name() + " Settings") self.remove_cat_alg_dropdown() self.create_cat_alg_dropdown(position, new_pipe_entry_widget, new_settings_widget) self.set_cat_alg_dropdown(new_cat, new_alg) print("New Cat found in pipeline: " + str(new_cat)) print("New Alg found in pipeline: " + str(new_alg)) def load_settings_widgets_from_pipeline_groupbox(self, position): """ Extracts all widgets from a single algorithm and returns a QBoxLayout Args: alg: the alg instance we extract from Returns: a QBoxLayout containing all widgets for this particular alg. """ alg = self.pipeline.executed_cats[position].active_algorithm print("alg " + str(alg)) print("cat " + str(self.pipeline.executed_cats[position])) empty_flag = True groupOfSliders = QGroupBox() sp = QSizePolicy() sp.setVerticalPolicy(QSizePolicy.Preferred) # groupOfSliders.setSizePolicy(sp) groupOfSliderssLayout = QBoxLayout(QBoxLayout.TopToBottom) groupOfSliderssLayout.setContentsMargins(0, -0, -0, 0) groupOfSliderssLayout.setAlignment(Qt.AlignTop) groupOfSliderssLayout.setSpacing(0) print("Build Slider @ "+ str(position)) # create integer sliders for slider in alg.integer_sliders: empty_flag = False print("slider.value " + str(slider.value)) print("slider " + str(slider)) #print(alg.get_name() + ": add slider (int).") groupOfSliderssLayout.addWidget( SliderWidget(slider.name, slider.lower, slider.upper, slider.step_size, slider.value, slider.set_value, False)) # create float sliders for slider in alg.float_sliders: empty_flag = False #print(alg.get_name() + ": add slider (float).") groupOfSliderssLayout.addWidget( SliderWidget(slider.name, slider.lower, slider.upper, slider.step_size, slider.value, slider.set_value, True), 0, Qt.AlignTop) # create checkboxes for checkbox in alg.checkboxes: empty_flag = False #print(alg.get_name() + ": add checkbox.") groupOfSliderssLayout.addWidget(CheckBoxWidget(checkbox.name, checkbox.value, checkbox.set_value), 0, Qt.AlignTop) # create dropdowns for combobox in alg.drop_downs: empty_flag = False #print(alg.get_name() + ": add combobox.") groupOfSliderssLayout.addWidget( ComboBoxWidget(combobox.name, combobox.options, combobox.set_value, combobox.value), 0, Qt.AlignTop) if empty_flag: label = QLabel() label.setText("This algorithm has no Settings.") groupOfSliderssLayout.addWidget(label, 0, Qt.AlignHCenter) groupOfSliders.setLayout(groupOfSliderssLayout) return groupOfSliders def create_cat_alg_dropdown(self, cat_position, pipe_entry_widget, settings_widget): """ Args: last_cat (object): """ layout = self.select_cat_alg_vbox_layout cat = self.pipeline.executed_cats[cat_position] last_cat = None # Show only allowed categories in dropdown if len(self.pipeline.executed_cats) > 1: last_cat = self.pipeline.executed_cats[cat_position - 1] # Combobox for selecting Category self.ComboxCategories.show() self.ComboxCategories.setFixedHeight(30) self.ComboxCategories.addItem("<Please Select Category>") self.stackedWidgetComboxesAlgorithms = QStackedWidget() self.stackedWidgetComboxesAlgorithms.setFixedHeight(30) self.stackedWidgetComboxesAlgorithms.hide() def setCurrentIndexCat(index): #print("Set Cat") if self.ComboxCategories.currentIndex() == 0: self.stackedWidgetComboxesAlgorithms.hide() else: self.stackedWidgetComboxesAlgorithms.show() self.stackedWidgetComboxesAlgorithms.setCurrentIndex(index - 1) for category_name in self.pipeline.report_available_cats(last_cat): # Add Category to combobox self.ComboxCategories.addItem(category_name) tmp1 = QComboBox() tmp1.addItem("<Please Select Algorithm>") tmp1.setFixedHeight(30) category = self.pipeline.get_category(category_name) #self.current_index = -1 def setCurrentIndexAlg(index): if self.ComboxCategories.currentIndex() == 0 or self.stackedWidgetComboxesAlgorithms.currentWidget().currentIndex() == 0: pass else: #self.current_index != index: self.change_pip_entry_alg(self.pipeline.get_index(cat), self.ComboxCategories.currentText(), self.stackedWidgetComboxesAlgorithms.currentWidget().currentText(), pipe_entry_widget, settings_widget) #self.current_index = index tmp1.activated.connect(setCurrentIndexAlg) for algorithm_name in self.pipeline.get_all_algorithm_list(category): tmp1.addItem(algorithm_name) self.stackedWidgetComboxesAlgorithms.addWidget(tmp1) layout.addWidget(self.ComboxCategories) layout.addWidget(self.stackedWidgetComboxesAlgorithms) self.ComboxCategories.activated.connect(setCurrentIndexCat) def set_cat_alg_dropdown(self, category, algorithm): indexC = self.ComboxCategories.findText(category.get_name()) #print("IndexC " + str(indexC)) self.ComboxCategories.setCurrentIndex(indexC) self.stackedWidgetComboxesAlgorithms.show() self.stackedWidgetComboxesAlgorithms.setCurrentIndex(indexC - 1) indexA = self.stackedWidgetComboxesAlgorithms.currentWidget().findText(algorithm.get_name()) #print("IndexA " + str(indexA)) self.stackedWidgetComboxesAlgorithms.currentWidget().setCurrentIndex(indexA) def remove_cat_alg_dropdown(self): """ Returns: object: """ self.ComboxCategories.clear() while self.stackedWidgetComboxesAlgorithms.currentWidget() is not None: self.stackedWidgetComboxesAlgorithms.removeWidget(self.stackedWidgetComboxesAlgorithms.currentWidget()) while self.select_cat_alg_vbox_layout.count(): child = self.select_cat_alg_vbox_layout.takeAt(0) child.widget().hide() def scroll_down_pip(self): self.pip_scroll.verticalScrollBar().setSliderPosition(self.pip_scroll.verticalScrollBar().maximum()) def add_pipe_entry_new(self, position=None): """ Creates a entry in the ui pipeline with a given position in pipeline. It also creates the corresponding settings widget. """ # create an widget that displays the pip entry in the ui and connect the remove button pip_main_widget = QWidget() pip_main_widget.setFixedHeight(70) pip_main_widget.setFixedWidth(300) pip_main_layout = QHBoxLayout() pip_main_widget.setLayout(pip_main_layout) new_marker = False if position is None: position = len(self.pipeline.executed_cats) cat = self.pipeline.new_category(position) label = "<Click to specify new step>" icon = None new_marker = True else: cat = self.pipeline.executed_cats[position] alg = cat.active_algorithm label = alg.get_name() icon = cat.get_icon() new_marker = False pixmap = QPixmap(icon) pixmap_scaled_keeping_aspec = pixmap.scaled(30, 30, QtCore.Qt.KeepAspectRatio) pixmap_label = QtWidgets.QLabel() pixmap_label.setPixmap(pixmap_scaled_keeping_aspec) pip_up_down = QWidget() pip_up_down.setFixedHeight(70) pip_up_down_layout = QVBoxLayout() pip_up_down.setLayout(pip_up_down_layout) up_btn = QToolButton() dw_btn = QToolButton() up_btn.setArrowType(Qt.UpArrow) up_btn.setFixedHeight(25) dw_btn.setArrowType(Qt.DownArrow) dw_btn.setFixedHeight(25) pip_up_down_layout.addWidget(up_btn) pip_up_down_layout.addWidget(dw_btn) string_label = QLabel() string_label.setText(label) string_label.setFixedWidth(210) btn = QtWidgets.QPushButton() btn.setFixedSize(20, 20) pixmap_icon = QtGui.QPixmap("./assets/images/delete_x_white.png") q_icon = QtGui.QIcon(pixmap_icon) btn.setIcon(q_icon) pip_main_layout.addWidget(pip_up_down, Qt.AlignVCenter) pip_main_layout.addWidget(pixmap_label, Qt.AlignVCenter) pip_main_layout.addWidget(string_label, Qt.AlignLeft) pip_main_layout.addWidget(btn, Qt.AlignVCenter) self.pip_widget_vbox_layout.insertWidget(position, pip_main_widget) # Create the corresponding settings widget and connect it self.settings_collapsable.setTitle("Settings") self.stackedWidget_Settings.hide() settings_main_widget = None if not new_marker: settings_main_widget = self.load_settings_widgets_from_pipeline_groupbox(position) self.stackedWidget_Settings.insertWidget(position, settings_main_widget) def show_settings(): # Set background color while widget is selected. Doesn't work because of theme? *TODO* p = pip_main_widget.palette() p.setColor(pip_main_widget.backgroundRole(), Qt.red) pip_main_widget.setPalette(p) if not new_marker: self.stackedWidget_Settings.show() self.stackedWidget_Settings.setCurrentIndex(self.pipeline.get_index(cat)) self.settings_collapsable.setTitle(alg.get_name() + " Settings") else: self.stackedWidget_Settings.hide() # Create drop down for cats and algs self.remove_cat_alg_dropdown() self.create_cat_alg_dropdown(self.pipeline.get_index(cat), pip_main_widget, settings_main_widget) if not new_marker: self.set_cat_alg_dropdown(cat, alg) # Connect Button to remove step from pipeline def delete_button_clicked(): self.remove_cat_alg_dropdown() self.remove_pip_entry(pip_main_widget, settings_main_widget, cat) self.clickable(pixmap_label).connect(show_settings) self.clickable(string_label).connect(show_settings) btn.clicked.connect(delete_button_clicked) return (pip_main_widget, settings_main_widget) def add_pip_entry_empty(self): """ Creates an blank entry in the ui pipeline since the user still needs to specify a type and an algorithm of the category. It also creates the corresponding settings widget. """ # create an widget that displays the pip entry in the ui and connect the remove button pip_main_widget = QWidget() pip_main_widget.setFixedHeight(70) pip_main_widget.setFixedWidth(300) pip_main_layout = QHBoxLayout() pip_main_widget.setLayout(pip_main_layout) label = "<Click to specify new step>" icon = None pixmap = QPixmap(icon) pixmap_scaled_keeping_aspec = pixmap.scaled(30, 30, QtCore.Qt.KeepAspectRatio) pixmap_label = QtWidgets.QLabel() pixmap_label.setPixmap(pixmap_scaled_keeping_aspec) pip_up_down = QWidget() pip_up_down.setFixedHeight(70) pip_up_down_layout = QVBoxLayout() pip_up_down.setLayout(pip_up_down_layout) up_btn = QToolButton() dw_btn = QToolButton() up_btn.setArrowType(Qt.UpArrow) up_btn.setFixedHeight(25) dw_btn.setArrowType(Qt.DownArrow) dw_btn.setFixedHeight(25) pip_up_down_layout.addWidget(up_btn) pip_up_down_layout.addWidget(dw_btn) string_label = QLabel() string_label.setText(label) string_label.setFixedWidth(210) btn = QtWidgets.QPushButton() btn.setFixedSize(20, 20) pixmap_icon = QtGui.QPixmap("./assets/images/delete_x_white.png") q_icon = QtGui.QIcon(pixmap_icon) btn.setIcon(q_icon) pip_main_layout.addWidget(pip_up_down, Qt.AlignVCenter) pip_main_layout.addWidget(pixmap_label, Qt.AlignVCenter) pip_main_layout.addWidget(string_label, Qt.AlignLeft) pip_main_layout.addWidget(btn, Qt.AlignVCenter) cat_position = len(self.pipeline.executed_cats) self.pip_widget_vbox_layout.insertWidget(cat_position, pip_main_widget) index = self.pip_widget_vbox_layout.indexOf(pip_main_widget) #print(index) # Create the corresponding empty settings widget and connect it # settings = self.load_widgets_from_cat_groupbox(cat_position) *TODO* EMPTY self.settings_collapsable.setTitle("Settings") self.stackedWidget_Settings.hide() # Add new step to pipeline new_category = self.pipeline.new_category(cat_position) print("Create new entry " + str(new_category)) print("Pipeline length: " + str(len(self.pipeline.executed_cats)) + ".") settings_main_widget = None # Connect pipeline entry with corresponding settings widget def show_settings(): #print("click") self.stackedWidget_Settings.show() self.remove_cat_alg_dropdown() # Create drop down for cats and algs self.create_cat_alg_dropdown(self.pipeline.get_index(new_category), pip_main_widget, settings_main_widget) self.stackedWidget_Settings.hide() # Connect Button to remove step from pipeline def delete_button_clicked(): self.remove_cat_alg_dropdown() self.remove_pip_entry(pip_main_widget, settings_main_widget, new_category) self.clickable(pixmap_label).connect(show_settings) self.clickable(string_label).connect(show_settings) btn.clicked.connect(delete_button_clicked) self.scroll_down_pip() def add_pip_entry(self, cat_position): """ Creates a entry in the ui pipeline with a given position in pipeline. It also creates the corresponding settings widget. """ # create an widget that displays the pip entry in the ui and connect the remove button pip_main_widget = QWidget() pip_main_widget.setFixedHeight(70) pip_main_widget.setFixedWidth(300) pip_main_layout = QHBoxLayout() pip_main_widget.setLayout(pip_main_layout) cat = self.pipeline.executed_cats[cat_position] alg = cat.active_algorithm label = alg.get_name() icon = cat.get_icon() pixmap = QPixmap(icon) pixmap_scaled_keeping_aspec = pixmap.scaled(30, 30, QtCore.Qt.KeepAspectRatio) pixmap_label = QtWidgets.QLabel() pixmap_label.setPixmap(pixmap_scaled_keeping_aspec) pip_up_down = QWidget() pip_up_down.setFixedHeight(70) pip_up_down_layout = QVBoxLayout() pip_up_down.setLayout(pip_up_down_layout) up_btn = QToolButton() dw_btn = QToolButton() up_btn.setArrowType(Qt.UpArrow) up_btn.setFixedHeight(25) dw_btn.setArrowType(Qt.DownArrow) dw_btn.setFixedHeight(25) pip_up_down_layout.addWidget(up_btn) pip_up_down_layout.addWidget(dw_btn) string_label = QLabel() string_label.setText(label) string_label.setFixedWidth(210) btn = QtWidgets.QPushButton() btn.setFixedSize(20, 20) pixmap_icon = QtGui.QPixmap("./assets/images/delete_x_white.png") q_icon = QtGui.QIcon(pixmap_icon) btn.setIcon(q_icon) pip_main_layout.addWidget(pip_up_down, Qt.AlignVCenter) pip_main_layout.addWidget(pixmap_label, Qt.AlignVCenter) pip_main_layout.addWidget(string_label, Qt.AlignLeft) pip_main_layout.addWidget(btn, Qt.AlignVCenter) self.pip_widget_vbox_layout.insertWidget(cat_position, pip_main_widget) index = self.pip_widget_vbox_layout.indexOf(pip_main_widget) #print(index) # Create the corresponding settings widget and connect it settings_main_widget = self.load_settings_widgets_from_pipeline_groupbox(cat_position) self.settings_collapsable.setTitle("Settings") self.stackedWidget_Settings.hide() self.stackedWidget_Settings.insertWidget(cat_position, settings_main_widget) #print("Read from pipeline entry " + str(cat)) #print("Pipeline length: " + str(len(self.pipeline.executed_cats)) + ".") def show_settings(): # Set background color while widget is selected. Doesn't work because of theme? *TODO* p = pip_main_widget.palette() p.setColor(pip_main_widget.backgroundRole(), Qt.red) pip_main_widget.setPalette(p) self.stackedWidget_Settings.show() self.stackedWidget_Settings.setCurrentIndex(self.pipeline.get_index(cat)) self.settings_collapsable.setTitle(alg.get_name() + " Settings") self.remove_cat_alg_dropdown() # Create drop down for cats and algs self.create_cat_alg_dropdown(self.pipeline.get_index(cat), pip_main_widget, settings_main_widget) #print(cat) #print(alg) self.set_cat_alg_dropdown(cat, alg) # Connect Button to remove step from pipeline def delete_button_clicked(): self.remove_pip_entry(pip_main_widget, settings_main_widget, cat) self.clickable(pixmap_label).connect(show_settings) self.clickable(string_label).connect(show_settings) btn.clicked.connect(delete_button_clicked) return (pip_main_widget, settings_main_widget) # https://wiki.python.org/moin/PyQt/Making%20non-clickable%20widgets%20clickable def clickable(self, widget): """ Convert any widget to a clickable widget. """ class Filter(QObject): clicked = pyqtSignal() def eventFilter(self, obj, event): if obj == widget: if event.type() == QEvent.MouseButtonPress: if obj.rect().contains(event.pos()): self.clicked.emit() # The developer can opt for .emit(obj) to get the object within the slot. return True return False filter = Filter(widget) widget.installEventFilter(filter) return filter.clicked
class HeapPluginForm(PluginForm): def __init__(self): super(HeapPluginForm, self).__init__() self.parent = None self.config_path = None self.config = None self.tracer = None self.heap = None self.cur_arena = None # default: main_arena self.ptr_size = get_arch_ptrsize() def OnCreate(self, form): self.parent = self.FormToPyQtWidget(form) self.setup_gui() self.init_heap() self.populate_gui() def setup_gui(self): self.chunk_widget = ChunkWidget(self) self.tracer_tab = TracerWidget(self) self.arena_widget = ArenaWidget(self) self.bins_widget = BinsWidget(self) self.tcache_widget = TcacheWidget(self) self.magic_widget = MagicWidget(self) self.config_widget = ConfigWidget(self) self.tabs = QTabWidget() self.tabs.addTab(self.tracer_tab, "Tracer") self.tabs.addTab(self.arena_widget, "Arena") self.tabs.addTab(self.bins_widget, "Bins") self.tabs.addTab(self.tcache_widget, "Tcache") self.tabs.addTab(self.magic_widget, "Magic") self.tabs.addTab(self.config_widget, "Config") self.btn_reload = QPushButton("Reload info") icon = QtGui.QIcon(os.path.normpath(ICONS_DIR + '/refresh.png')) self.btn_reload.setIcon(icon) self.btn_reload.setFixedWidth(120) self.btn_reload.setEnabled(False) self.btn_reload.clicked.connect(self.reload_gui_info) self.cb_arenas = QComboBox() self.cb_arenas.setFixedWidth(150) self.cb_arenas.currentIndexChanged[int].connect(self.cb_arenas_changed) hbox_arenas = QHBoxLayout() hbox_arenas.addWidget(QLabel('Switch arena: ')) hbox_arenas.addWidget(self.cb_arenas) hbox_arenas.setContentsMargins(0, 0, 0, 0) self.arenas_widget = QWidget() self.arenas_widget.setLayout(hbox_arenas) self.arenas_widget.setVisible(False) self.txt_warning = QLabel() self.txt_warning.setStyleSheet("font-weight: bold; color: red") self.txt_warning.setVisible(False) hbox_top = QHBoxLayout() hbox_top.addWidget(self.btn_reload) hbox_top.addWidget(self.arenas_widget) hbox_top.addWidget(self.txt_warning) hbox_top.setContentsMargins(0, 0, 0, 0) hbox_top.addStretch(1) vbox_left_panel = QVBoxLayout() vbox_left_panel.addLayout(hbox_top) vbox_left_panel.addWidget(self.tabs) vbox_left_panel.setContentsMargins(0, 0, 0, 0) left_panel = QWidget() left_panel.setLayout(vbox_left_panel) self.splitter = QSplitter(QtCore.Qt.Horizontal) self.splitter.addWidget(left_panel) self.splitter.addWidget(self.chunk_widget) self.splitter.setStretchFactor(0, 1) main_layout = QVBoxLayout() main_layout.addWidget(self.splitter) self.parent.setLayout(main_layout) def populate_gui(self): self.magic_widget.populate_libc_offsets() self.reload_gui_info() def reload_gui_info(self, from_arena_cb=False): if not self.heap: return if not self.heap.get_heap_base(): self.show_warning('Heap not initialized') return self.hide_warning() self.arenas_widget.setVisible(True) if not from_arena_cb: self.populate_arenas() self.arena_widget.populate_table() self.tcache_widget.populate_table() self.bins_widget.populate_tables() def init_heap(self): try: self.config_path = CONFIG_PATH self.config = HeapConfig(self.config_path) self.config_widget.load_config() except Exception as e: self.config = None self.show_warning('Please, update the config file') warning(str(e)) return if not self.config.offsets: arch_bits = self.ptr_size * 8 self.show_warning('Config: Libc offsets for %d bits not found.' % arch_bits) return try: current_libc_version = get_libc_version() if self.config.libc_version == current_libc_version or current_libc_version == None: self.heap = Heap(self.config) self.btn_reload.setEnabled(True) self.tabs.setTabEnabled(3, self.heap.tcache_enabled) else: self.show_warning('Config: glibc version mismatched: %s != %s' % \ (str(self.config.libc_version), str(current_libc_version))) except AttributeError: self.show_warning('Invalid config file content') def populate_arenas(self): old_arena = self.cur_arena self.cb_arenas.clear() for addr, arena in self.heap.arenas(): if addr == self.heap.main_arena_addr: self.cb_arenas.addItem("main_arena", None) else: self.cb_arenas.addItem("0x%x" % addr, addr) idx = self.cb_arenas.findData(old_arena) if idx != -1: self.cb_arenas.setCurrentIndex(idx) def show_warning(self, txt): self.txt_warning.setText(txt) self.txt_warning.setVisible(True) def hide_warning(self): self.txt_warning.setVisible(False) def cb_arenas_changed(self, idx): self.cur_arena = self.cb_arenas.itemData(idx) self.reload_gui_info(True) def show_chunk_info(self, address): self.chunk_widget.show_chunk(address) def Show(self): return PluginForm.Show(self, PLUGNAME, options=(PluginForm.FORM_TAB | PluginForm.FORM_CLOSE_LATER)) def OnClose(self, form): if self.tracer: self.tracer.unhook() log("Tracer disabled") log("Form closed")
class MainWindow(QMainWindow, Ui_MainWindow): """ classdocs """ def __init__(self, app): """ Init :param sakia.core.app.Application app: application :type: sakia.core.app.Application """ # Set up the user interface from Designer. super().__init__() self.app = app self.initialized = False self.password_asker = None self.import_dialog = None super().setupUi(self) QApplication.setWindowIcon(QIcon(":/icons/sakia_logo")) self.app.version_requested.connect(self.latest_version_requested) self.status_label = QLabel("", self) self.status_label.setTextFormat(Qt.RichText) self.statusbar.addPermanentWidget(self.status_label, 1) self.label_time = QLabel("", self) self.statusbar.addPermanentWidget(self.label_time) self.combo_referential = QComboBox(self) self.combo_referential.setEnabled(False) self.combo_referential.currentIndexChanged.connect(self.referential_changed) self.statusbar.addPermanentWidget(self.combo_referential) self.homescreen = HomeScreenWidget(self.app, self.status_label) self.homescreen.frame_communities.community_tile_clicked.connect(self.change_community) self.homescreen.toolbutton_new_account.clicked.connect(self.open_add_account_dialog) self.homescreen.toolbutton_new_account.addAction(self.action_add_account) self.homescreen.toolbutton_new_account.addAction(self.action_import) self.homescreen.button_add_community.clicked.connect(self.action_open_add_community) self.homescreen.button_disconnect.clicked.connect(lambda :self.action_change_account("")) self.centralWidget().layout().addWidget(self.homescreen) self.homescreen.toolbutton_connect.setMenu(self.menu_change_account) self.community_view = CommunityWidget(self.app, self.status_label) self.community_view.button_home.clicked.connect(lambda: self.change_community(None)) self.community_view.button_certification.clicked.connect(self.open_certification_dialog) self.community_view.button_send_money.clicked.connect(self.open_transfer_money_dialog) self.centralWidget().layout().addWidget(self.community_view) def startup(self): self.update_time() # FIXME : Need python 3.5 self.app.get_last_version() if self.app.preferences['maximized']: self.showMaximized() else: self.show() if self.app.current_account: self.password_asker = PasswordAskerDialog(self.app.current_account) self.community_view.change_account(self.app.current_account, self.password_asker) self.refresh() @asyncify @asyncio.coroutine def open_add_account_dialog(self, checked=False): dialog = ProcessConfigureAccount(self.app, None) result = yield from dialog.async_exec() if result == QDialog.Accepted: self.action_change_account(self.app.current_account.name) @asyncify @asyncio.coroutine def open_configure_account_dialog(self, checked=False): dialog = ProcessConfigureAccount(self.app, self.app.current_account) result = yield from dialog.async_exec() if result == QDialog.Accepted: if self.app.current_account: self.action_change_account(self.app.current_account.name) else: self.refresh() @pyqtSlot(str) def display_error(self, error): QMessageBox.critical(self, ":(", error, QMessageBox.Ok) @pyqtSlot(str) def referential_changed(self, index): if self.app.current_account: self.app.current_account.set_display_referential(index) if self.community_view: self.community_view.referential_changed() self.homescreen.referential_changed() @pyqtSlot() def update_time(self): dateTime = QDateTime.currentDateTime() self.label_time.setText("{0}".format(QLocale.toString( QLocale(), QDateTime.currentDateTime(), QLocale.dateTimeFormat(QLocale(), QLocale.NarrowFormat) ))) timer = QTimer() timer.timeout.connect(self.update_time) timer.start(1000) @pyqtSlot() def delete_contact(self): contact = self.sender().data() self.app.current_account.contacts.remove(contact) self.refresh_contacts() @pyqtSlot() def edit_contact(self): index = self.sender().data() dialog = ConfigureContactDialog(self.app.current_account, self, None, index) result = dialog.exec_() if result == QDialog.Accepted: self.window().refresh_contacts() def action_change_account(self, account_name): self.app.change_current_account(self.app.get_account(account_name)) self.password_asker = PasswordAskerDialog(self.app.current_account) self.community_view.change_account(self.app.current_account, self.password_asker) self.refresh() @pyqtSlot() def action_open_add_community(self): dialog = ProcessConfigureCommunity(self.app, self.app.current_account, None, self.password_asker) if dialog.exec_() == QDialog.Accepted: self.app.save(self.app.current_account) dialog.community.start_coroutines() self.homescreen.refresh() def open_transfer_money_dialog(self): dialog = TransferMoneyDialog(self.app, self.app.current_account, self.password_asker, self.community_view.community, None) if dialog.exec_() == QDialog.Accepted: self.community_view.tab_history.table_history.model().sourceModel().refresh_transfers() def open_certification_dialog(self): dialog = CertificationDialog(self.app, self.app.current_account, self.password_asker) dialog.exec_() def open_add_contact_dialog(self): dialog = ConfigureContactDialog(self.app.current_account, self) result = dialog.exec_() if result == QDialog.Accepted: self.window().refresh_contacts() def open_preferences_dialog(self): dialog = PreferencesDialog(self.app) result = dialog.exec_() def open_about_popup(self): """ Open about popup window """ aboutDialog = QDialog(self) aboutUi = Ui_AboutPopup() aboutUi.setupUi(aboutDialog) latest = self.app.available_version version_info = "" version_url = "" if not latest[0]: version_info = self.tr("Latest release : {version}") \ .format(version=latest[1]) version_url = latest[2] new_version_text = """ <p><b>{version_info}</b></p> <p><a href="{version_url}">{link_text}</a></p> """.format(version_info=version_info, version_url=version_url, link_text=self.tr("Download link")) else: new_version_text = "" text = self.tr(""" <h1>sakia</h1> <p>Python/Qt uCoin client</p> <p>Version : {:}</p> {new_version_text} <p>License : GPLv3</p> <p><b>Authors</b></p> <p>inso</p> <p>vit</p> <p>Moul</p> <p>canercandan</p> """).format(__version__, new_version_text=new_version_text) aboutUi.label.setText(text) aboutDialog.show() @pyqtSlot() def latest_version_requested(self): latest = self.app.available_version logging.debug("Latest version requested") if not latest[0]: version_info = self.tr("Please get the latest release {version}") \ .format(version=latest[1]) version_url = latest[2] if self.app.preferences['notifications']: toast.display("sakia", """{version_info}""".format( version_info=version_info, version_url=version_url)) @pyqtSlot(Community) def change_community(self, community): if community: self.homescreen.hide() self.community_view.show() else: self.community_view.hide() self.homescreen.show() self.community_view.change_community(community) def refresh_accounts(self): self.menu_change_account.clear() for account_name in sorted(self.app.accounts.keys()): action = QAction(account_name, self) action.triggered.connect(lambda checked, account_name=account_name: self.action_change_account(account_name)) self.menu_change_account.addAction(action) def refresh_contacts(self): self.menu_contacts_list.clear() if self.app.current_account: for index, contact in enumerate(self.app.current_account.contacts): contact_menu = self.menu_contacts_list.addMenu(contact['name']) edit_action = contact_menu.addAction(self.tr("Edit")) edit_action.triggered.connect(self.edit_contact) edit_action.setData(index) delete_action = contact_menu.addAction(self.tr("Delete")) delete_action.setData(contact) delete_action.triggered.connect(self.delete_contact) def refresh(self): """ Refresh main window When the selected account changes, all the widgets in the window have to be refreshed """ logging.debug("Refresh started") self.refresh_accounts() self.community_view.hide() self.homescreen.show() self.homescreen.refresh() if self.app.current_account is None: self.setWindowTitle(self.tr("sakia {0}").format(__version__)) self.action_add_a_contact.setEnabled(False) self.actionCertification.setEnabled(False) self.actionTransfer_money.setEnabled(False) self.action_configure_parameters.setEnabled(False) self.action_set_as_default.setEnabled(False) self.menu_contacts_list.setEnabled(False) self.combo_referential.setEnabled(False) self.status_label.setText(self.tr("")) self.password_asker = None else: self.password_asker = PasswordAskerDialog(self.app.current_account) self.combo_referential.blockSignals(True) self.combo_referential.clear() for ref in money.Referentials: self.combo_referential.addItem(ref.translated_name()) self.combo_referential.setEnabled(True) self.combo_referential.blockSignals(False) logging.debug(self.app.preferences) self.combo_referential.setCurrentIndex(self.app.preferences['ref']) self.action_add_a_contact.setEnabled(True) self.actionCertification.setEnabled(True) self.actionTransfer_money.setEnabled(True) self.menu_contacts_list.setEnabled(True) self.action_configure_parameters.setEnabled(True) self.setWindowTitle(self.tr("sakia {0} - Account : {1}").format(__version__, self.app.current_account.name)) self.refresh_contacts() def import_account(self): self.import_dialog = ImportAccountDialog(self.app, self) self.import_dialog.accepted.connect(self.import_account_accepted) self.import_dialog.exec_() def import_account_accepted(self): # open account after import self.action_change_account(self.import_dialog.edit_name.text()) def export_account(self): # Testable way of using a QFileDialog export_dialog = QFileDialog(self) export_dialog.setObjectName('ExportFileDialog') export_dialog.setWindowTitle(self.tr("Export an account")) export_dialog.setNameFilter(self.tr("All account files (*.acc)")) export_dialog.setLabelText(QFileDialog.Accept, self.tr('Export')) export_dialog.setOption(QFileDialog.DontUseNativeDialog, True) export_dialog.accepted.connect(self.export_account_accepted) export_dialog.show() def export_account_accepted(self): export_dialog = self.sender() selected_file = export_dialog.selectedFiles() if selected_file: if selected_file[0][-4:] == ".acc": path = selected_file[0] else: path = selected_file[0] + ".acc" self.app.export_account(path, self.app.current_account) def closeEvent(self, event): self.app.stop() super().closeEvent(event) def changeEvent(self, event): """ Intercepte LanguageChange event to translate UI :param QEvent QEvent: Event :return: """ if event.type() == QEvent.LanguageChange: self.retranslateUi(self) self.refresh() return super(MainWindow, self).changeEvent(event)
class MainWindow(QMainWindow): """Show the main window of SCCT.""" EXIT_CODE_REBOOT = -123 def __init__(self, controller, app, showChangelog): """Init the main window.""" try: super().__init__() self._save = True self.tlock = TriggerLock() self.controller = controller self.game_list = {} with self.tlock: self.createFormMatchDataBox() self.createTabs() self.createHorizontalGroupBox() self.createBackgroundTasksBox() self.createMenuBar() mainLayout = QVBoxLayout() mainLayout.addWidget(self.tabs, 0) mainLayout.addWidget(self.fromMatchDataBox, 1) mainLayout.addWidget(self.backgroundTasksBox, 0) mainLayout.addWidget(self.horizontalGroupBox, 0) self.setWindowTitle( "WarCraft III – Meta Plays Casting Tool v{}".format( hwctool.__version__)) self.window = QWidget() self.window.setLayout(mainLayout) self.setCentralWidget(self.window) # self.size self.statusBar() self.leds = dict() for scope in self.controller.websocketThread.get_primary_scopes(): self.leds[scope] = LedIndicator(self) for key, led in self.leds.items(): self.controller.toogleLEDs(0, key, self) self.statusBar().addPermanentWidget(led) self.app = app self.controller.setView(self) self.controller.refreshButtonStatus() self.processEvents() self.settings = QSettings(ClientConfig.APP_NAME, ClientConfig.COMPANY_NAME) self.restoreGeometry( self.settings.value("geometry", self.saveGeometry())) self.restoreState( self.settings.value("windowState", self.saveState())) self.mysubwindows = dict() self.show() self.raise_() if showChangelog: self.openChangelog() except Exception as e: module_logger.exception("message") # def showAbout(self): # """Show subwindow with about info.""" # html = markdown2.markdown_path( # hwctool.settings.getResFile("about.md")) # html = html.replace("%VERSION%", hwctool.__version__) # if(not hwctool.__new_version__): # new_version = _("Halo Wars Casting Tool is up to date.") # else: # new_version = _("The new version {} is available!").format( # hwctool.__latest_version__) # html = html.replace('%NEW_VERSION%', new_version) # # use self as parent here # QMessageBox.about( # self, _("Halo Wars Casting Tool - About"), html) def closeEvent(self, event): """Close and clean up window.""" try: try: for name, window in self.mysubwindows.items(): if (window and window.isVisible()): window.close() finally: self.settings.setValue("geometry", self.saveGeometry()) self.settings.setValue("windowState", self.saveState()) self.controller.cleanUp(self._save) QMainWindow.closeEvent(self, event) # event.accept() except Exception as e: module_logger.exception("message") def updateGame(self, title): """updates game played""" self.setWindowTitle("{} – Meta Plays Casting Tool v{}".format( title, hwctool.__version__)) #change title hwctool.settings.races = hwctool.settings.game_races[ title] #update races hwctool.settings.current_game = title #update current game #uncheck, check for item in self.game_list.keys(): self.game_list[item].setChecked(False) self.game_list[title].setChecked(True) #updates dropdown menu for players max_no_sets = hwctool.settings.max_no_sets for player_idx in range(max_no_sets): for team_idx in range(2): self.cb_race[team_idx][player_idx].clear() for race in hwctool.settings.races: self.cb_race[team_idx][player_idx].addItem(race) #update styles self.openStyleDialog() def createMenuBar(self): """Create the menu bar.""" try: menubar = self.menuBar() # BROWSER SOURCES self.createBrowserSrcMenu() #SETTINGS settingsMenu = menubar.addMenu(_('Settings')) # apiAct = QAction(QIcon(hwctool.settings.getResFile( # 'browser.png')), _('Browser Sources'), self) # apiAct.setToolTip( # _('Edit Settings for all Browser Sources')) # apiAct.triggered.connect(self.openBrowserSourcesDialog) # settingsMenu.addAction(apiAct) apiAct = QAction(QIcon(hwctool.settings.getResFile('twitch.png')), _('Twitch'), self) apiAct.setToolTip( _('Edit Intro-Settings and API-Settings' ' for Twitch')) apiAct.triggered.connect(self.openApiDialog) settingsMenu.addAction(apiAct) # styleAct = QAction(QIcon(hwctool.settings.getResFile( # 'pantone.png')), _('Styles'), self) # styleAct.setToolTip('') # styleAct.triggered.connect(self.openStyleDialog) # settingsMenu.addAction(styleAct) apiAct = QAction(QIcon(hwctool.settings.getResFile('browser.png')), _('Intro settings'), self) apiAct.setToolTip(_('Edit Settings for all Browser Sources')) apiAct.triggered.connect(self.openBrowserSourcesDialog) settingsMenu.addAction(apiAct) styleAct = QAction( QIcon(hwctool.settings.getResFile('pantone.png')), _('Source styles'), self) styleAct.setToolTip('') styleAct.triggered.connect(self.openStyleDialog) settingsMenu.addAction(styleAct) ProfileMenu(self, self.controller) infoMenu = menubar.addMenu(_('Info && Links')) myAct = QAction(QIcon(hwctool.settings.getResFile('folder.png')), _('Open log folder'), self) myAct.triggered.connect(lambda: os.startfile( hwctool.settings.getAbsPath(hwctool.settings.getLogDir()))) infoMenu.addAction(myAct) infoMenu.addSeparator() websiteAct = QAction( QIcon(hwctool.settings.getResFile('github.ico')), 'Github - Meta Plays Casting Tool', self) websiteAct.triggered.connect(lambda: self.controller.openURL( "https://github.com/FluffyMaguro/MetaPlaysCastingTool/")) infoMenu.addAction(websiteAct) ixAct = QAction(QIcon(hwctool.settings.getResFile('icon.png')), 'Meta Plays (website)', self) ixAct.triggered.connect( lambda: self.controller.openURL("https://meta-plays.com/")) infoMenu.addAction(ixAct) websiteAct = QAction( QIcon(hwctool.settings.getResFile('favicon.jpg')), 'Maguro.one (website)', self) websiteAct.triggered.connect( lambda: self.controller.openURL("https://www.maguro.one/")) infoMenu.addAction(websiteAct) infoMenu.addSeparator() websiteAct = QAction( QIcon(hwctool.settings.getResFile('hwct.ico')), 'StarCraft Casting Tool - Docs', self) websiteAct.triggered.connect(lambda: self.controller.openURL( "https://teampheenix.github.io/StarCraft-Casting-Tool/")) infoMenu.addAction(websiteAct) myAct = QAction(QIcon(hwctool.settings.getResFile('patreon.png')), _('StarCraft Casting Tool - Patreon'), self) myAct.triggered.connect(lambda: self.controller.openURL( "https://www.patreon.com/StarCraftCastingTool")) infoMenu.addAction(myAct) myAct = QAction(QIcon(hwctool.settings.getResFile('donate.ico')), _('StarCraft Casting Tool - PayPal'), self) myAct.triggered.connect(lambda: self.controller.openURL( "https://paypal.me/StarCraftCastingTool")) infoMenu.addAction(myAct) #Choose the game gameMenu = menubar.addMenu(_('Game')) icon_dict = { 'StarCraft II': 'SC2.png', 'WarCraft III': 'WC3.png', 'Age of Empires IV': 'AOEIV.png', 'Age of Empires Online': 'AOEO.png', 'Age of Mythology': 'AOM.png', 'Halo Wars 2': 'HW.png', 'SpellForce 3': 'SF3.png' } for game in hwctool.settings.game_races: if game in icon_dict: myAct = QAction(QIcon( hwctool.settings.getResFile(icon_dict[game])), _(game), self, checkable=True) else: myAct = QAction(QIcon( hwctool.settings.getResFile('loading.png')), _(game), self, checkable=True) myAct.triggered.connect(partial(self.updateGame, game)) gameMenu.addAction(myAct) self.game_list[game] = myAct except Exception as e: module_logger.exception("message") def createBrowserSrcMenu(self): menubar = self.menuBar() main_menu = menubar.addMenu(_('Browser Sources')) srcs = [] srcs.append({ 'name': _('Intro'), 'file': 'intro.html', 'settings': lambda: self.openBrowserSourcesDialog('intro') }) srcs.append({'name': _('Score'), 'file': 'score.html'}) act = QAction(QIcon(hwctool.settings.getResFile('folder.png')), _('Open Folder'), self) act.triggered.connect(lambda: os.startfile( hwctool.settings.getAbsPath(hwctool.settings.casting_html_dir))) main_menu.addAction(act) main_menu.addSeparator() for src in srcs: myMenu = QMenu(src['name'], self) sub = src.get('sub', False) if sub: for icon in sub: mySubMenu = QMenu(icon['name'], self) icon['file'] = os.path.join( hwctool.settings.casting_html_dir, icon['file']) act = QAction( QIcon(hwctool.settings.getResFile('html.png')), _('Open in Browser'), self) act.triggered.connect( lambda x, file=icon['file']: self.controller.openURL( hwctool.settings.getAbsPath(file))) mySubMenu.addAction(act) act = QAction( QIcon(hwctool.settings.getResFile('copy.png')), _('Copy URL to Clipboard'), self) act.triggered.connect( lambda x, file=icon['file']: QApplication.clipboard( ).setText(hwctool.settings.getAbsPath(file))) mySubMenu.addAction(act) if icon.get('settings', None) is not None: act = QAction( QIcon(hwctool.settings.getResFile('browser.png')), _('Settings'), self) act.triggered.connect(icon['settings']) mySubMenu.addAction(act) myMenu.addMenu(mySubMenu) else: src['file'] = os.path.join(hwctool.settings.casting_html_dir, src['file']) act = QAction(QIcon(hwctool.settings.getResFile('html.png')), _('Open in Browser'), self) act.triggered.connect( lambda x, file=src['file']: self.controller.openURL( hwctool.settings.getAbsPath(file))) myMenu.addAction(act) act = QAction(QIcon(hwctool.settings.getResFile('copy.png')), _('Copy URL to Clipboard'), self) act.triggered.connect( lambda x, file=src['file']: QApplication.clipboard( ).setText(hwctool.settings.getAbsPath(file))) myMenu.addAction(act) if src.get('settings', None) is not None: act = QAction( QIcon(hwctool.settings.getResFile('browser.png')), _('Settings'), self) act.triggered.connect(src['settings']) myMenu.addAction(act) main_menu.addMenu(myMenu) main_menu.addSeparator() # apiAct = QAction(QIcon(hwctool.settings.getResFile( # 'browser.png')), _('Settings'), self) # apiAct.setToolTip( # _('Edit Settings for all Browser Sources')) # apiAct.triggered.connect(self.openBrowserSourcesDialog) # main_menu.addAction(apiAct) # styleAct = QAction(QIcon(hwctool.settings.getResFile( # 'pantone.png')), _('Styles'), self) # styleAct.setToolTip('') # styleAct.triggered.connect(self.openStyleDialog) # main_menu.addAction(styleAct) def openApiDialog(self): """Open subwindow with connection settings.""" self.mysubwindows['connections'] = SubwindowConnections() self.mysubwindows['connections'].createWindow(self) self.mysubwindows['connections'].show() def openStyleDialog(self): """Open subwindow with style settings.""" self.mysubwindows['styles'] = SubwindowStyles() self.mysubwindows['styles'].createWindow(self) self.mysubwindows['styles'].show() def openBrowserSourcesDialog(self, tab=''): """Open subwindow with browser sources settings.""" self.mysubwindows['browser'] = SubwindowBrowserSources() self.mysubwindows['browser'].createWindow(self, tab) self.mysubwindows['browser'].show() def openReadme(self): """Open subwindow with readme viewer.""" self.mysubwindows['readme'] = SubwindowMarkdown() self.mysubwindows['readme'].createWindow( self, _("Readme"), hwctool.settings.getResFile('readme.ico'), hwctool.settings.getResFile("../README.md")) self.mysubwindows['readme'].show() def openChangelog(self): """Open subwindow with readme viewer.""" self.mysubwindows['changelog'] = SubwindowMarkdown() self.mysubwindows['changelog'].createWindow( self, "Halo Wars Casting Tool " + _("Changelog"), hwctool.settings.getResFile("changelog.png"), hwctool.settings.getResFile("../CHANGELOG.md")) self.mysubwindows['changelog'].show() def changeLanguage(self, language): """Change the language.""" hwctool.settings.config.parser.set("SCT", "language", language) self.restart() def createTabs(self): """Create tabs in main window.""" try: # Initialize tab screen self.tabs = QTabWidget() self.tab2 = QWidget() # self.tabs.resize(300,200) # Add tabs self.tabs.addTab(self.tab2, _("Custom Match")) # Create second tab self.tab2.layout = QVBoxLayout() container = QHBoxLayout() label = QLabel() label.setMinimumWidth(self.labelWidth) container.addWidget(label, 0) label = QLabel(_("Match Format:")) label.setMinimumWidth(80) container.addWidget(label, 0) container.addWidget(QLabel(_("Best of")), 0) self.cb_bestof = QComboBox() for idx in range(0, hwctool.settings.max_no_sets): self.cb_bestof.addItem(str(idx + 1)) self.cb_bestof.setCurrentIndex(3) string = _('"Best of 6/4": First, a Bo5/3 is played and the' ' ace map gets extended to a Bo3 if needed;' ' Best of 2: Bo3 with only two maps played.') self.cb_bestof.setToolTip(string) self.cb_bestof.setMaximumWidth(40) self.cb_bestof.currentIndexChanged.connect(self.changeBestOf) container.addWidget(self.cb_bestof, 0) container.addWidget(QLabel(_(" but at least")), 0) self.cb_minSets = QComboBox() self.cb_minSets.setToolTip( _('Minimum number of maps played (even if the match' ' is decided already)')) self.cb_minSets.setMaximumWidth(40) container.addWidget(self.cb_minSets, 0) container.addWidget(QLabel(" " + _("maps") + " "), 0) self.cb_minSets.currentIndexChanged.connect( lambda idx: self.highlightApplyCustom()) ###### APPLY BUTTON label = QLabel("") container.addWidget(label, 1) self.applycustom_is_highlighted = False self.pb_applycustom = QToolButton() action = QAction(_("Apply Format")) action.triggered.connect(self.applycustom_click) self.pb_applycustom.setDefaultAction(action) self.pb_applycustom.setFixedWidth(100) container.addWidget(self.pb_applycustom, 0) self.defaultButtonPalette = self.pb_applycustom.palette() self.tab2.layout.addLayout(container) ###### RESET BUTTON label = QLabel("") container.addWidget(label, 1) self.pb_resetdata = QPushButton(_("Reset Match Data")) self.pb_resetdata.setFixedWidth(100) self.pb_resetdata.clicked.connect(self.resetdata_click) container.addWidget(self.pb_resetdata, 0) self.tab2.layout.addLayout(container) self.tab2.setLayout(self.tab2.layout) ###### SPACING container.insertSpacing(-1, 100) ########## REMOVED CUSTOM URL # container = QHBoxLayout() # label = QLabel() # label.setMinimumWidth(self.labelWidth) # container.addWidget(label, 0) # label = QLabel(_("Match-URL:")) # label.setMinimumWidth(80) # container.addWidget(label, 0) self.le_url_custom = MonitoredLineEdit() # self.le_url_custom.setAlignment(Qt.AlignCenter) # self.le_url_custom.setToolTip( # _('Optionally specify the Match-URL,' # ' e.g., for Nightbot commands')) # self.le_url_custom.setPlaceholderText( # _("Specify the Match-URL of your Custom Match")) # completer = QCompleter( # ["http://"], self.le_url_custom) # completer.setCaseSensitivity(Qt.CaseInsensitive) # completer.setCompletionMode( # QCompleter.UnfilteredPopupCompletion) # completer.setWrapAround(True) # self.le_url_custom.setCompleter(completer) # self.le_url_custom.setMinimumWidth(360) # self.le_url_custom.textModified.connect(self.highlightApplyCustom) # container.addWidget(self.le_url_custom, 11) except Exception as e: module_logger.exception("message") def changeBestOf(self, bestof): """Change the minimum sets combo box on change of BoX.""" bestof = bestof + 1 self.cb_minSets.clear() self.highlightApplyCustom() for idx in range(0, bestof): self.cb_minSets.addItem(str(idx + 1)) if bestof == 2: self.cb_minSets.setCurrentIndex(1) else: self.cb_minSets.setCurrentIndex(int((bestof - 1) / 2)) def updatePlayerCompleters(self): """Refresh the completer for the player line edits.""" list = ["TBD"] + self.controller.historyManager.getPlayerList() for player_idx in range(self.max_no_sets): for team_idx in range(2): completer = QCompleter(list, self.le_player[team_idx][player_idx]) completer.setCaseSensitivity(Qt.CaseInsensitive) completer.setCompletionMode(QCompleter.InlineCompletion) completer.setWrapAround(True) self.le_player[team_idx][player_idx].setCompleter(completer) def createFormMatchDataBox(self): """Create the froms for the match data.""" try: self.max_no_sets = hwctool.settings.max_no_sets self.scoreWidth = 35 self.raceWidth = 100 self.labelWidth = 25 self.mimumLineEditWidth = 130 self.fromMatchDataBox = QGroupBox(_("Match Data")) layout2 = QVBoxLayout() self.le_league = MonitoredLineEdit() self.le_league.setText("League TBD") self.le_league.setAlignment(Qt.AlignCenter) self.le_league.setPlaceholderText("League TBD") self.le_league.textModified.connect(self.league_changed) policy = QSizePolicy() policy.setHorizontalStretch(3) policy.setHorizontalPolicy(QSizePolicy.Expanding) policy.setVerticalStretch(1) policy.setVerticalPolicy(QSizePolicy.Fixed) self.le_league.setSizePolicy(policy) self.le_player = [[ MonitoredLineEdit() for x in range(self.max_no_sets) ] for y in range(2)] self.cb_race = [[QComboBox() for x in range(self.max_no_sets)] for y in range(2)] self.sl_score = [ QSlider(Qt.Horizontal) for y in range(self.max_no_sets) ] self.label_set = [ QLabel('#{}'.format(y + 1), self) for y in range(self.max_no_sets) ] self.setContainer = [ QHBoxLayout() for y in range(self.max_no_sets) ] container = QGridLayout() button = QPushButton() pixmap = QIcon(hwctool.settings.getResFile('update.png')) button.setIcon(pixmap) button.clicked.connect(lambda: self.controller.swapTeams()) button.setFixedWidth(self.labelWidth) button.setToolTip(_("Swap players.")) container.addWidget(button, 0, 0, 1, 1) label = QLabel(_("League:")) label.setAlignment(Qt.AlignCenter) label.setFixedWidth(self.raceWidth) container.addWidget(label, 0, 1, 1, 1) container.addWidget(self.le_league, 0, 2, 1, 3) label = QLabel("") label.setFixedWidth(self.raceWidth) container.addWidget(label, 0, 5, 1, 1) layout2.addLayout(container) for player_idx in range(self.max_no_sets): for team_idx in range(2): self.cb_race[team_idx][player_idx].\ currentIndexChanged.connect( lambda idx, t=team_idx, p=player_idx: self.race_changed(t, p)) self.le_player[team_idx][player_idx].textModified.connect( lambda t=team_idx, p=player_idx: self.player_changed( t, p)) self.le_player[team_idx][player_idx].setText("TBD") self.le_player[team_idx][player_idx].setAlignment( Qt.AlignCenter) self.le_player[team_idx][player_idx].setPlaceholderText( _("Player {} of team {}").format( player_idx + 1, team_idx + 1)) self.le_player[team_idx][player_idx].setMinimumWidth( self.mimumLineEditWidth) for race in hwctool.settings.races: self.cb_race[team_idx][player_idx].addItem(race) self.cb_race[team_idx][player_idx].setFixedWidth( self.raceWidth) self.sl_score[player_idx].setMinimum(-1) self.sl_score[player_idx].setMaximum(1) self.sl_score[player_idx].setValue(0) self.sl_score[player_idx].setTickPosition( QSlider.TicksBothSides) self.sl_score[player_idx].setTickInterval(1) self.sl_score[player_idx].setTracking(False) self.sl_score[player_idx].valueChanged.connect( lambda x, player_idx=player_idx: self.sl_changed( player_idx, x)) self.sl_score[player_idx].setToolTip(_('Set the score')) self.sl_score[player_idx].setFixedWidth(self.scoreWidth) self.setContainer[player_idx] = QHBoxLayout() # self.label_set[player_idx].setText("#" + str(player_idx + 1)) self.label_set[player_idx].setAlignment(Qt.AlignCenter) self.label_set[player_idx].setFixedWidth(self.labelWidth) self.setContainer[player_idx].addWidget( self.label_set[player_idx], 0) self.setContainer[player_idx].addWidget( self.cb_race[0][player_idx], 0) self.setContainer[player_idx].addWidget( self.le_player[0][player_idx], 4) self.setContainer[player_idx].addWidget( self.sl_score[player_idx], 0) self.setContainer[player_idx].addWidget( self.le_player[1][player_idx], 4) self.setContainer[player_idx].addWidget( self.cb_race[1][player_idx], 0) layout2.addLayout(self.setContainer[player_idx]) layout2.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.fromMatchDataBox.setLayout(layout2) self.updatePlayerCompleters() except Exception as e: module_logger.exception("message") def createHorizontalGroupBox(self): """Create horizontal group box for tasks.""" try: self.horizontalGroupBox = QGroupBox(_("Tasks")) layout = QHBoxLayout() self.pb_twitchupdate = QPushButton(_("Update Twitch Title")) self.pb_twitchupdate.clicked.connect(self.updatetwitch_click) # self.pb_nightbotupdate = QPushButton( # _("Update Nightbot")) # self.pb_nightbotupdate.clicked.connect(self.updatenightbot_click) self.pb_resetscore = QPushButton(_("Reset Score")) self.pb_resetscore.clicked.connect(self.resetscore_click) layout.addWidget(self.pb_twitchupdate) # layout.addWidget(self.pb_nightbotupdate) layout.addWidget(self.pb_resetscore) self.horizontalGroupBox.setLayout(layout) except Exception as e: module_logger.exception("message") def createBackgroundTasksBox(self): """Create group box for background tasks.""" try: self.backgroundTasksBox = QGroupBox(_("Background Tasks")) self.cb_autoTwitch = QCheckBox(_("Auto Twitch Update")) self.cb_autoTwitch.setChecked(False) self.cb_autoTwitch.stateChanged.connect(self.autoTwitch_change) # self.cb_autoNightbot = QCheckBox( # _("Auto Nightbot Update")) # self.cb_autoNightbot.setChecked(False) # self.cb_autoNightbot.stateChanged.connect( # self.autoNightbot_change) layout = QGridLayout() layout.addWidget(self.cb_autoTwitch, 0, 0) # layout.addWidget(self.cb_autoNightbot, 0, 1) self.backgroundTasksBox.setLayout(layout) except Exception as e: module_logger.exception("message") def autoTwitch_change(self): """Handle change of auto twitch check box.""" try: if (self.cb_autoTwitch.isChecked()): self.controller.autoRequestsThread.activateTask('twitch') else: self.controller.autoRequestsThread.deactivateTask('twitch') except Exception as e: module_logger.exception("message") # def autoNightbot_change(self): # """Handle change of auto twitch check box.""" # try: # if(self.cb_autoNightbot.isChecked()): # self.controller.autoRequestsThread.activateTask('nightbot') # else: # self.controller.autoRequestsThread.deactivateTask('nightbot') # except Exception as e: # module_logger.exception("message") def autoUpdate_change(self): """Handle change of auto score update check box.""" try: if (self.cb_autoUpdate.isChecked()): self.controller.runSC2ApiThread("updateScore") else: self.controller.stopSC2ApiThread("updateScore") except Exception as e: module_logger.exception("message") def autoToggleScore_change(self): """Handle change of toggle score check box.""" try: if (self.cb_autoToggleScore.isChecked()): self.controller.runSC2ApiThread("toggleScore") else: self.controller.stopSC2ApiThread("toggleScore") except Exception as e: module_logger.exception("message") def autoToggleProduction_change(self): """Handle change of toggle production tab check box.""" try: if (self.cb_autoToggleProduction.isChecked()): self.controller.runSC2ApiThread("toggleProduction") else: self.controller.stopSC2ApiThread("toggleProduction") except Exception as e: module_logger.exception("message") def applyCustomFormat(self, format): """Handle click to apply custom format.""" QApplication.setOverrideCursor(Qt.WaitCursor) try: with self.tlock: self.controller.matchData.applyCustomFormat(format) self.controller.updateForms() self.resizeWindow() self.highlightApplyCustom(False) except Exception as e: module_logger.exception("message") finally: QApplication.restoreOverrideCursor() def applycustom_click(self): """Handle click to apply custom match.""" QApplication.setOverrideCursor(Qt.WaitCursor) try: with self.tlock: self.statusBar().showMessage(_('Applying Custom Match...')) msg = self.controller.applyCustom( int(self.cb_bestof.currentText()), False, True, int(self.cb_minSets.currentText()), self.le_url_custom.text().strip()) self.statusBar().showMessage(msg) self.highlightApplyCustom(False) except Exception as e: module_logger.exception("message") finally: QApplication.restoreOverrideCursor() def resetdata_click(self): """Handle click to reset the data.""" QApplication.setOverrideCursor(Qt.WaitCursor) try: with self.tlock: msg = self.controller.resetData() self.statusBar().showMessage(msg) except Exception as e: module_logger.exception("message") finally: QApplication.restoreOverrideCursor() def openBrowser_click(self): """Handle request to open URL in browser.""" try: url = self.le_url.text() self.controller.openURL(url) except Exception as e: module_logger.exception("message") # def updatenightbot_click(self): # """Handle click to change nightbot command.""" # try: # self.statusBar().showMessage(_('Updating Nightbot Command...')) # msg = self.controller.updateNightbotCommand() # self.statusBar().showMessage(msg) # except Exception as e: # module_logger.exception("message") def updatetwitch_click(self): """Handle click to change twitch title.""" try: self.statusBar().showMessage(_('Updating Twitch Title...')) msg = self.controller.updateTwitchTitle() self.statusBar().showMessage(msg) except Exception as e: module_logger.exception("message") def resetscore_click(self, myteam=False): """Handle click to reset the score.""" try: self.statusBar().showMessage(_('Resetting Score...')) with self.tlock: for set_idx in range(self.max_no_sets): self.sl_score[set_idx].setValue(0) self.controller.matchData.setMapScore(set_idx, 0, overwrite=True) if myteam: self.sl_team.setValue(0) self.controller.matchData.setMyTeam(0) if not self.controller.resetWarning(): self.statusBar().showMessage('') except Exception as e: module_logger.exception("message") def setScore(self, idx, score, allkill=True): """Handle change of the score.""" try: if (self.sl_score[idx].value() == 0): self.statusBar().showMessage(_('Updating Score...')) with self.tlock: self.sl_score[idx].setValue(score) self.controller.matchData.setMapScore(idx, score, True) if not self.controller.resetWarning(): self.statusBar().showMessage('') return True else: return False except Exception as e: module_logger.exception("message") def league_changed(self): if not self.tlock.trigger(): return self.controller.matchData.setLeague(self.le_league.text()) def sl_changed(self, set_idx, value): """Handle a new score value.""" try: if self.tlock.trigger(): if set_idx == -1: self.controller.matchData.setMyTeam(value) else: self.controller.matchData.setMapScore(set_idx, value, True) except Exception as e: module_logger.exception("message") def player_changed(self, team_idx, player_idx): """Handle a change of player names.""" if not self.tlock.trigger(): return try: player = self.le_player[team_idx][player_idx].text().strip() race = self.cb_race[team_idx][player_idx].currentText() if (player_idx == 0 and self.controller.matchData.getSolo()): for p_idx in range(1, self.max_no_sets): self.le_player[team_idx][p_idx].setText(player) self.player_changed(team_idx, p_idx) self.controller.historyManager.insertPlayer(player, race) self.controller.matchData.setPlayer( team_idx, player_idx, self.le_player[team_idx][player_idx].text()) if race == "Random": new_race = self.controller.historyManager.getRace(player) if new_race != "Random": index = self.cb_race[team_idx][player_idx].findText( new_race, Qt.MatchFixedString) if index >= 0: self.cb_race[team_idx][player_idx].setCurrentIndex( index) elif player.lower() == "tbd": self.cb_race[team_idx][player_idx].setCurrentIndex(0) self.updatePlayerCompleters() except Exception as e: module_logger.exception("message") def race_changed(self, team_idx, player_idx): """Handle a change of player names.""" if not self.tlock.trigger(): return player = self.le_player[team_idx][player_idx].text().strip() race = self.cb_race[team_idx][player_idx].currentText() self.controller.historyManager.insertPlayer(player, race) self.controller.matchData.setRace( team_idx, player_idx, self.cb_race[team_idx][player_idx].currentText()) try: if (player_idx == 0 and self.controller.matchData.getSolo()): race = self.cb_race[team_idx][0].currentText() for player_idx in range(1, self.max_no_sets): index = self.cb_race[team_idx][player_idx].findText( race, Qt.MatchFixedString) if index >= 0: self.cb_race[team_idx][player_idx].setCurrentIndex( index) except Exception as e: module_logger.exception("message") def highlightApplyCustom(self, highlight=True, force=False): if not force and not self.tlock.trigger(): return try: if self.applycustom_is_highlighted == highlight: return highlight except AttributeError: return False if highlight: myPalette = self.pb_applycustom.palette() myPalette.setColor(QPalette.Background, Qt.darkRed) myPalette.setColor(QPalette.ButtonText, Qt.darkRed) self.pb_applycustom.setPalette(myPalette) else: self.pb_applycustom.setPalette(self.defaultButtonPalette) self.applycustom_is_highlighted = highlight return highlight def resizeWindow(self): """Resize the window height to size hint.""" if (not self.isMaximized()): self.processEvents() self.resize(self.width(), self.sizeHint().height()) def processEvents(self): """Process ten PyQt5 events.""" for i in range(0, 10): self.app.processEvents() def restart(self, save=True): """Restart the main window.""" self._save = save self.close() self.app.exit(self.EXIT_CODE_REBOOT)
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 Spectrum(QWidget): """Plot the power spectrum for a specified channel. Attributes ---------- parent : instance of QMainWindow the main window. x_limit : tuple or list 2 values specifying the limit on x-axis y_limit : tuple or list 2 values specifying the limit on y-axis log : bool log-transform the data or not idx_chan : instance of QComboBox the element with the list of channel names. idx_x_min : instance of QLineEdit value with min x value idx_x_max : instance of QLineEdit value with max x value idx_y_min : instance of QLineEdit value with min y value idx_y_max : instance of QLineEdit value with max y value idx_log : instance of QCheckBox widget that defines if log should be used or not idx_fig : instance of QGraphicsView the view with the power spectrum scene : instance of QGraphicsScene the scene with GraphicsItems Notes ----- If data contains NaN, it doesn't create any spectrum (feature or bug?). """ def __init__(self, parent): super().__init__() self.parent = parent self.config = ConfigSpectrum(self.display_window) self.selected_chan = None self.idx_chan = None self.idx_fig = None self.scene = None self.create() def create(self): """Create empty scene for power spectrum.""" self.idx_chan = QComboBox() self.idx_chan.activated.connect(self.display_window) self.idx_fig = QGraphicsView(self) self.idx_fig.scale(1, -1) layout = QVBoxLayout() layout.addWidget(self.idx_chan) layout.addWidget(self.idx_fig) self.setLayout(layout) self.resizeEvent(None) def show_channame(self, chan_name): self.selected_chan = self.idx_chan.currentIndex() self.idx_chan.clear() self.idx_chan.addItem(chan_name) self.idx_chan.setCurrentIndex(0) def update(self): """Add channel names to the combobox.""" self.idx_chan.clear() for chan_name in self.parent.traces.chan: self.idx_chan.addItem(chan_name) if self.selected_chan is not None: self.idx_chan.setCurrentIndex(self.selected_chan) self.selected_chan = None def display_window(self): """Read the channel name from QComboBox and plot its spectrum. This function is necessary it reads the data and it sends it to self.display. When the user selects a smaller chunk of data from the visible traces, then we don't need to call this function. """ if self.idx_chan.count() == 0: self.update() chan_name = self.idx_chan.currentText() lg.debug('Power spectrum for channel ' + chan_name) if chan_name: trial = 0 data = self.parent.traces.data(trial=trial, chan=chan_name) self.display(data) else: self.scene.clear() def display(self, data): """Make graphicsitem for spectrum figure. Parameters ---------- data : ndarray 1D vector containing the data only This function can be called by self.display_window (which reads the data for the selected channel) or by the mouse-events functions in traces (which read chunks of data from the user-made selection). """ value = self.config.value self.scene = QGraphicsScene(value['x_min'], value['y_min'], value['x_max'] - value['x_min'], value['y_max'] - value['y_min']) self.idx_fig.setScene(self.scene) self.add_grid() self.resizeEvent(None) s_freq = self.parent.traces.data.s_freq f, Pxx = welch(data, fs=s_freq, nperseg=int(min( (s_freq, len(data))))) # force int freq_limit = (value['x_min'] <= f) & (f <= value['x_max']) if self.config.value['log']: Pxx_to_plot = log(Pxx[freq_limit]) else: Pxx_to_plot = Pxx[freq_limit] self.scene.addPath(Path(f[freq_limit], Pxx_to_plot), QPen(QColor(LINE_COLOR), LINE_WIDTH)) def add_grid(self): """Add axis and ticks to figure. Notes ----- I know that visvis and pyqtgraphs can do this in much simpler way, but those packages create too large a padding around the figure and this is pretty fast. """ value = self.config.value # X-AXIS # x-bottom self.scene.addLine(value['x_min'], value['y_min'], value['x_min'], value['y_max'], QPen(QColor(LINE_COLOR), LINE_WIDTH)) # at y = 0, dashed self.scene.addLine(value['x_min'], 0, value['x_max'], 0, QPen(QColor(LINE_COLOR), LINE_WIDTH, Qt.DashLine)) # ticks on y-axis y_high = int(floor(value['y_max'])) y_low = int(ceil(value['y_min'])) x_length = (value['x_max'] - value['x_min']) / value['x_tick'] for y in range(y_low, y_high): self.scene.addLine(value['x_min'], y, value['x_min'] + x_length, y, QPen(QColor(LINE_COLOR), LINE_WIDTH)) # Y-AXIS # left axis self.scene.addLine(value['x_min'], value['y_min'], value['x_max'], value['y_min'], QPen(QColor(LINE_COLOR), LINE_WIDTH)) # larger ticks on x-axis every 10 Hz x_high = int(floor(value['x_max'])) x_low = int(ceil(value['x_min'])) y_length = (value['y_max'] - value['y_min']) / value['y_tick'] for x in range(x_low, x_high, 10): self.scene.addLine(x, value['y_min'], x, value['y_min'] + y_length, QPen(QColor(LINE_COLOR), LINE_WIDTH)) # smaller ticks on x-axis every 10 Hz y_length = (value['y_max'] - value['y_min']) / value['y_tick'] / 2 for x in range(x_low, x_high, 5): self.scene.addLine(x, value['y_min'], x, value['y_min'] + y_length, QPen(QColor(LINE_COLOR), LINE_WIDTH)) def resizeEvent(self, event): """Fit the whole scene in view. Parameters ---------- event : instance of Qt.Event not important """ value = self.config.value self.idx_fig.fitInView(value['x_min'], value['y_min'], value['x_max'] - value['x_min'], value['y_max'] - value['y_min']) def reset(self): """Reset widget as new""" self.idx_chan.clear() if self.scene is not None: self.scene.clear() self.scene = None
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.parts = [] self.blocks = [] self.centralBlock = [0, 0, 0, 1] self.resolution = 16 self.createGUI() self.createMenu() self.connectSlots() self.project_file = "" self.current_block = 0 self.block_count = 0 def createGUI(self): self.widget = QWidget(self) self.gvMain = MainView(self, 0, self.blocks) self.views = {key: XYZview(self, self.blocks, key) for key in ('xy', 'yz', 'zx')} self.cbSelectBox = QComboBox(self) self.pbAddBox = QPushButton("Add Box", self) self.pbDeleteBox = QPushButton("Delete selected box", self) self.slScale = QSlider(self) self.slScale.setOrientation(Qt.Horizontal) self.slScale.setRange(2, 15) self.slScale.setValue(5) self.slResolution = QSlider(self) self.slResolution.setOrientation(Qt.Horizontal) self.slResolution.setRange(1, 6) # resolution is 2**this_value self.slResolution.setValue(4) # 2**4 is 16 -- initial resolution self.turn_buttons = {'x': QPushButton("Turn around X axis", self), 'y': QPushButton("Turn around Y axis", self), 'z': QPushButton("Turn around Z axis", self)} self.swap_buttons = {'xy': QPushButton("Swap X and Y", self), 'yz': QPushButton("Swap Y and Z", self), 'zx': QPushButton("Swap Z and X", self)} self.grLayout = QGridLayout() self.grLayout.addWidget(QLabel("Main view"), 0, 0) self.grLayout.addWidget(self.gvMain, 1, 0) self.grLayout.addWidget(QLabel("Y view"), 0, 1) self.grLayout.addWidget(self.views['zx'], 1, 1) self.vbRightLayout = QVBoxLayout() self.vbRightLayout.addWidget(QLabel("Select box")) self.vbRightLayout.addWidget(self.cbSelectBox) self.vbRightLayout.addWidget(self.pbAddBox) self.vbRightLayout.addWidget(self.pbDeleteBox) self.vbRightLayout.addWidget(QLabel("Scale")) self.vbRightLayout.addWidget(self.slScale) self.vbRightLayout.addWidget(QLabel("Resolution")) self.vbRightLayout.addWidget(self.slResolution) self.vbRightLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) for button in self.swap_buttons.values(): self.vbRightLayout.addWidget(button) for button in self.turn_buttons.values(): self.vbRightLayout.addWidget(button) self.hbMainLayout = QHBoxLayout() self.hbMainLayout.addLayout(self.grLayout, 10) self.hbMainLayout.addLayout(self.vbRightLayout, 1) self.grLayout.addWidget(QLabel("X view"), 2, 0) self.grLayout.addWidget(self.views['yz'], 3, 0) self.grLayout.addWidget(QLabel("Z view"), 2, 1) self.grLayout.addWidget(self.views['xy'], 3, 1) self.widget.setLayout(self.hbMainLayout) self.setCentralWidget(self.widget) self.setWindowTitle("Nodebox editor") self.resize(1000, 600) def createMenu(self): self.menuBar = QMenuBar() self.fileMenu = self.menuBar.addMenu("&File") self.helpMenu = self.menuBar.addMenu("&Help") self.aNewProject = self.fileMenu.addAction("Start new project") self.aOpen = self.fileMenu.addAction("Open") self.aSave = self.fileMenu.addAction("Save as...") self.aExport = self.fileMenu.addAction("Export as...") self.fileMenu.addSeparator() self.aExitApp = self.fileMenu.addAction("Exit") self.setMenuBar(self.menuBar) def addBox(self): self.blocks.append(Block([-8, -8, -8, 1], [8, 8, 8, 1])) self.block_count += 1 # BTW, we will not decrease this value self.cbSelectBox.addItems(["Block" + str(self.block_count)]) self.cbSelectBox.setCurrentIndex(self.cbSelectBox.count()-1) self.update() self.current_block = self.blocks[self.cbSelectBox.currentIndex()] self.sendCurrentBlock(self.current_block) def deleteBox(self): if self.cbSelectBox.count() != 0: idx = self.cbSelectBox.currentIndex() del self.blocks[idx] self.cbSelectBox.removeItem(idx) if self.cbSelectBox.count() != 0: self.cbSelectBox.setCurrentIndex(0) self.current_block = self.blocks[0] self.sendCurrentBlock(self.current_block) else: self.current_block = 0; self.sendCurrentBlock(0) self.update() def connectSlots(self): self.aExitApp.triggered.connect(lambda: sys.exit(0)) self.aExport.triggered.connect(self.actionExport) self.aSave.triggered.connect(self.actionSave) self.aNewProject.triggered.connect(self.actionNewProject) self.pbAddBox.clicked.connect(self.addBox) self.pbDeleteBox.clicked.connect(self.deleteBox) self.cbSelectBox.activated.connect(self.cbSwitch) self.slScale.valueChanged.connect(self.slScaleChange) self.slResolution.valueChanged.connect(self.slResolutionChange) self.aOpen.triggered.connect(self.actionOpen) for (key, button) in self.turn_buttons.items(): button.clicked.connect(partial(self.turn, key)) for (key, button) in self.swap_buttons.items(): button.clicked.connect(partial(self.swap, key)) def actionNewProject(self): self.blocks.clear() self.current_block = 0 self.cbSelectBox.clear() self.sendCurrentBlock(0) self.block_count = 0 self.update() def actionExport(self): if using_qt5: export_as = QFileDialog.getSaveFileName(self, "Export as...")[0] else: export_as = QFileDialog.getSaveFileName(self, "Export as...") create_code = codegen.codegen(self, "mynode", self.blocks, self.resolution) if export_as != "": create_code.writeToFile(export_as) def actionSave(self): if using_qt5: save_as = QFileDialog.getSaveFileName(self, "Save as...")[0] else: save_as = QFileDialog.getSaveFileName(self, "Save as...") if save_as != "": output_file = open(save_as, "w+") for b in self.blocks: output_file.write(" ".join([ str(b.p1()[0]), str(b.p1()[2]), str(b.p1()[1]), str(b.p2()[0]), str(b.p2()[2]), str(b.p2()[1])]) + "\n") output_file.close() def sendCurrentBlock(self, block): for view in self.views.values(): view.set_current_block(block) def sendScale(self, scale): for view in self.views.values(): view.set_scale(scale) self.gvMain.scale = scale def sendResolution(self, resolution): for view in self.views.values(): view.set_resolution(resolution) self.gvMain.resolution = resolution self.resolution = resolution def actionOpen(self): if using_qt5: open_from = QFileDialog.getOpenFileName(self, "Open file")[0] else: open_from = QFileDialog.getOpenFileName(self, "Open file") input_file = open(open_from, "r") self.blocks.clear() self.sendCurrentBlock(0) self.cbSelectBox.clear() for line in input_file: t = [int(token) for token in line.split(" ")] self.blocks.append(Block([t[0], t[2], t[1], 1], [t[3], t[5], t[4], 1])) self.cbSelectBox.addItems(["Block" + str(len(self.blocks))]) input_file.close() self.update() def cbSwitch(self): self.current_block = self.blocks[self.cbSelectBox.currentIndex()] self.sendCurrentBlock(self.current_block) self.update() def slScaleChange(self): self.sendScale(self.slScale.value()) self.update() def slResolutionChange(self): self.sendResolution(2**self.slResolution.value()) self.update() def swap(self, coords): for b in self.blocks: b.swap(coords) self.update() def turn(self, coord): for b in self.blocks: b.turn(coord) self.update()
class App(QWidget): def __init__(self): super().__init__() self.title = "Science Fact Generator" # location of window self.left = 100 self.top = 100 # dimenssions of window self.width = 800 self.height = 800 # function that initalizes the window self.initUI() self.data = webscraper.webscraper() # print(self.data.genFactList(1,1)) # function to initalize the content of our window def initUI(self): # window frame attributes self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) # Generate button button = QPushButton('Generate', self) button.setToolTip('generate fun fact') button.setFixedSize(100, 100) button.move(100, 300) # calls onClick function when the button has been pressed # The button click (signal) is connected to the action (slot). # the method onClick will be called if the signal emits. button.clicked.connect(self.onClick) # Month Combo Box comboBox = QComboBox(self) comboBox.move(100, 100) comboBox.addItem("January") comboBox.addItem("Febuary") comboBox.addItem("March") comboBox.addItem("April") comboBox.addItem("May") comboBox.addItem("June") comboBox.addItem("July") comboBox.addItem("August") comboBox.addItem("September") comboBox.addItem("October") comboBox.addItem("November") comboBox.addItem("December") comboBox.activated[str].connect(self.monthSelected) self.dayComboBox = QComboBox(self) self.dayComboBox.move(250, 100) maxday = monthrange(2012, 1)[1] days = [str(x) for x in range(1, maxday)] self.dayComboBox.addItems(days) self.show() # slot for button click @pyqtSlot() def onClick(self): date = self.calendar.selectedDate() print(date.month(), date.day(), date.year()) print(self.data.factList) def monthSelected(self, month): self.dayComboBox.clear() maxday = monthrange(2012, self.monthToInt(month))[1] days = [str(x) for x in range(1, maxday)] self.dayComboBox.clear() self.dayComboBox.addItems(days) print(month) # returns integer version of coresponding month def monthToInt(self, month): if month == "January": return 1 elif month == "Febuary": return 2 elif month == "March": return 3 elif month == "April": return 4 elif month == "May": return 5 elif month == "June": return 6 elif month == "July": return 7 elif month == "August": return 8 elif month == "September": return 9 elif month == "October": return 10 elif month == "November": return 11 else: return 12
class Example(QWidget): def __init__(self): super().__init__() self.ventana() def ventana(self): #Planteamiento de etiquetas self.inp= QLineEdit("Numero de datos", self) self.inp.move(5,5) self.x= QLineEdit(self) self.x.move(5,50) self.y= QLineEdit(self) self.y.move(160,50) lbl= QLabel("x", self) lbl.move(5, 30) lbl2= QLabel("y", self) lbl2.move(160, 30) self.lbl3= QLabel(self) self.lbl3.move(5,75) self.inp2=QLineEdit("Conocer X en",self) self.inp2.move(5,100) self.lbl4= QLabel("y=...", self) self.lbl4.move(160,100) self.com= QComboBox(self) self.com.move(160,5) but= QPushButton("Calcular", self) but.move(5,130) #Eventos self.com.activated[str].connect(self.onAc) self.inp.textChanged[str].connect(self.combo) self.x.textChanged[str].connect(self.lx) self.y.textChanged[str].connect(self.ly) self.inp.selectionChanged.connect(self.bor) self.x.selectionChanged.connect(self.bor2) self.y.selectionChanged.connect(self.bor3) self.inp2.selectionChanged.connect(self.bor4) but.clicked.connect(self.boton) #Ventana self.setGeometry(300, 300, 350, 160) self.setWindowTitle('Regresion Lineal') self.show() #Metodos de los eventos def boton(self): sp=0 ss=0 ym= 0 xm= 0 b1=0 b0=0 te= int(self.inp.text()) for c in range(te): ym+= yl[c] xm+= xl[c] c=0 ym/=te xm/=te for c in range(te): sp+= (xl[c]-xm)*(yl[c]-ym) ss+= (xl[c]-xm)**2 b1= sp/ss b0= ym-(b1*xm) if self.inp2.text() == '': self.inp2.setText("0") cp= float(self.inp2.text()) r= b0+(b1*cp) self.lbl4.setText("y="+str(r)) self.lbl4.adjustSize() self.lbl3.setText("y="+str(b0)+"+("+str(b1)+"x)") self.lbl3.adjustSize() def bor(self): self.inp.clear() def bor2(self): self.x.clear() def bor3(self): self.y.clear() def bor4(self): self.inp2.clear() def combo(self, text): self.com.clear() if text =='': text='0' for c in range(int(text)): self.com.addItem(str(c+1)) if len(xl)<= c: xl.append(0) yl.append(0) def lx(self, text): if text == "": text= "0" xl[(self.com.currentIndex())]= float(text) def ly(self, text): if text == "": text= "0" yl[(self.com.currentIndex())]= float(text) def onAc(self, text): if self.x.text()== " ": xl[int(text)-1]= 0 if self.y.text()== " ": yl[int(text)-1]= 0 self.x.setText(str(xl[int(text)-1])) self.y.setText(str(yl[int(text)-1]))
class ScopeGroupBox(QGroupBox): """Define QGroupBox for icon scope.""" dataModified = pyqtSignal() def __init__(self, name='', options=list(), scope='all', parent=None): """Init lineedit.""" super().__init__(name, parent) layout = QFormLayout() self.bt_dynamic = QRadioButton(_("Dynamic:")) self.bt_dynamic.toggled.connect(lambda: self.btnstate('dynamic')) self.bt_dynamic.setMinimumWidth(120) self.scope_box = QComboBox() found = False idx = 0 for key, item in options.items(): self.scope_box.addItem(item, key) if key == scope: self.scope_box.setCurrentIndex(idx) self.bt_dynamic.setChecked(True) found = True idx = idx + 1 layout.addRow(self.bt_dynamic, self.scope_box) self.bt_static = QRadioButton(_("Static:")) self.bt_static.toggled.connect(lambda: self.btnstate('static')) self.bt_static.setMinimumWidth(120) container = QHBoxLayout() self.label1 = QLabel(_('From')) container.addWidget(self.label1) self.cb_lower = QComboBox() for set_idx in range(0, scctool.settings.max_no_sets): self.cb_lower.addItem(_('Map {}').format(set_idx + 1), set_idx) self.cb_lower.currentIndexChanged.connect(self.adjustRangeUpper) container.addWidget(self.cb_lower, 0) self.label2 = QLabel(_('to')) self.label2.setAlignment(Qt.AlignCenter) container.addWidget(self.label2, 0) self.cb_upper = QComboBox() for set_idx in range(0, scctool.settings.max_no_sets): self.cb_upper.addItem(_('Map {}').format(set_idx + 1), set_idx) container.addWidget(self.cb_upper, 0) layout.addRow(self.bt_static, container) if not found: m = re.match(r'^(\d+)-(\d+)$', scope) if m and int(m.group(1)) <= int(m.group(2)): self.bt_static.setChecked(True) self.cb_upper.setCurrentIndex(int(m.group(2)) - 1) self.cb_lower.setCurrentIndex(int(m.group(1)) - 1) self.setLayout(layout) self.btnstate('dynamic') self.btnstate('static') self.bt_dynamic.toggled.connect(self.triggerSignal) self.bt_static.toggled.connect(self.triggerSignal) self.cb_upper.currentIndexChanged.connect(self.triggerSignal) self.cb_lower.currentIndexChanged.connect(self.triggerSignal) self.scope_box.currentIndexChanged.connect(self.triggerSignal) def btnstate(self, b): if b == 'dynamic': self.scope_box.setEnabled(self.bt_dynamic.isChecked()) elif b == 'static': self.cb_lower.setEnabled(self.bt_static.isChecked()) self.cb_upper.setEnabled(self.bt_static.isChecked()) self.label1.setEnabled(self.bt_static.isChecked()) self.label2.setEnabled(self.bt_static.isChecked()) def adjustRangeUpper(self, lower): current_idx = self.cb_upper.itemData(self.cb_upper.currentIndex()) self.cb_upper.clear() rg = range(lower, scctool.settings.max_no_sets) if current_idx not in rg: current_idx = lower idx = 0 for set_idx in rg: self.cb_upper.addItem(_('Map {}').format(set_idx + 1), set_idx) if set_idx == current_idx: self.cb_upper.setCurrentIndex(idx) idx = idx + 1 def getScope(self): if self.bt_dynamic.isChecked(): return self.scope_box.itemData(self.scope_box.currentIndex()) else: lower = int(self.cb_lower.itemData( self.cb_lower.currentIndex())) + 1 upper = int(self.cb_upper.itemData( self.cb_upper.currentIndex())) + 1 return '{}-{}'.format(lower, upper) def triggerSignal(self): self.dataModified.emit()
class ErgebnissListe(QWidget): template = "<tr><td>Eintrag von </td><td>{: >20}</td><td>in der Disziplin {:<15} </td><td>{}erfolgreich {}</td></tr>" def __init__(self,parent=None): super(ErgebnissListe, self).__init__(parent) self.auswahlAlter = QComboBox() self.auswahlAlter.addItem("Bitte auswählen") for i in range(3,18): self.auswahlAlter.addItem("{} Jahre / Jahrgang {}".format(i, date.today().year-i)) self.auswahlAlter.activated.connect(self.auswahlKlasse) self.auswahlAlter.activated.connect(self.waehleDisziplinen) self.auswahlGeschlecht = QComboBox() self.auswahlGeschlecht.addItem("Bitte auswählen") self.auswahlGeschlecht.addItem("Männlich") self.auswahlGeschlecht.addItem("Weiblich") self.auswahlGeschlecht.activated.connect(self.auswahlKlasse) self.auswahlGeschlecht.activated.connect(self.waehleDisziplinen) self.auswahlDisziplin = QComboBox() self.auswahlDisziplin.addItem("Bitte auswählen") for i in getDisziplin(10): self.auswahlDisziplin.addItem(i) self.auswahlDisziplin.activated.connect(self.auswahlKlasse) self.mainLayout = QGridLayout() self.mainLayout.addWidget(QLabel("Alter:"), 0, 0) self.mainLayout.addWidget(self.auswahlAlter, 0, 1, 1, 3) self.mainLayout.addWidget(QLabel("Geschlecht:"), 1, 0) self.mainLayout.addWidget(self.auswahlGeschlecht, 1, 1, 1, 3) self.mainLayout.addWidget(QLabel("Disziplin:"), 2, 0) self.mainLayout.addWidget(self.auswahlDisziplin, 2, 1, 1, 3) self._speichern = QPushButton("Speichern") self._speichern.clicked.connect(self.speichern) self.setLayout(self.mainLayout) self._sportler = [] self.update() def waehleDisziplinen(self): self.auswahlDisziplin.clear() self.auswahlDisziplin.addItem("Bitte auswählen") for i in getDisziplin(self.auswahlAlter.currentIndex()+2): self.auswahlDisziplin.addItem(i) def auswahlKlasse(self): if self.auswahlAlter.currentIndex() == 0: return False elif self.auswahlGeschlecht.currentIndex() == 0: return False elif self.auswahlDisziplin.currentIndex() == 0: return False self.clearAuswahl() disziplin = self.auswahlDisziplin.currentIndex()-1 if self.auswahlDisziplin.currentText() is "-": return for sportler in QueryTool().queryAndFetch("SELECT ID, Name, Vorname FROM LG_NGD WHERE WieAlt = ? AND Geschlecht = ?", self.auswahlAlter.currentIndex()+2, bool(self.auswahlGeschlecht.currentIndex()-1)): self._sportler += [sportler[0]] name = "{} {}".format(sportler[2],sportler[1]) #UID, Name for werte in reversed(QueryTool().queryAndFetch("SELECT Wert1, Wert2, Wert3 FROM LG_NGD_Ergebnisse WHERE UID = ? " "AND Typ = ? UNION SELECT 0, 0, 0", sportler[0], disziplin)): row = self.mainLayout.rowCount() self.mainLayout.addWidget(QLabel(name), row, 0) for i in range(0,felderzahl[disziplin]): el = QDoubleSpinBox() el.setMaximum(99999) el.setValue(werte[i]) el.setSuffix(" "+einheiten[disziplin]) el.setSingleStep(0.01) self.mainLayout.addWidget(el, row, i+1, 1, 3/felderzahl[disziplin]) break self._speichern = QPushButton("Speichern") self._speichern.clicked.connect(self.speichern) self.mainLayout.addWidget(self._speichern, self.mainLayout.rowCount(), 0, 1, 4) def speichern(self): row = self.mainLayout.rowCount()-len(self._sportler)-1 disziplin = self.auswahlDisziplin.currentIndex()-1 ausgabe = "<table>" for UID in self._sportler: werte = ["0","0","0"] for col in range(1, 1+felderzahl[disziplin]): item = self.mainLayout.itemAtPosition(row, col) text = "0" try: if type(item.widget()) is not type(QDoubleSpinBox()): raise TypeError("No LineEdit") text = item.widget().value() except TypeError: text = "0" except AttributeError: text = "0" werte[col-1]=text data = QueryTool().queryAndFetch("SELECT * FROM LG_NGD_Ergebnisse WHERE UID = ? AND Typ = ?",UID,disziplin) ergebnisse = None typ = None if len(data) is not 0: ergebniss = QueryTool().update("LG_NGD_Ergebnisse", data[0][0], Wert1=werte[0], Wert2=werte[1], Wert3=werte[2]) typ = "aktualisiert" else: ergebniss = QueryTool().insert("LG_NGD_Ergebnisse", UID=UID, Typ=disziplin, Wert1=werte[0], Wert2=werte[1], Wert3=werte[2]) typ = "eingetragen" username = self.mainLayout.itemAtPosition(row, 0) if type(username.widget()) is not type(QLabel()): username = "" else: username = username.widget().text() ausgabe += self.template.format(username, list(getDisziplin(self.auswahlAlter.currentIndex()+2))[disziplin], "nicht " if ergebniss is None else "", typ) row += 1 ausgabe += "</table>" QMessageBox.information(self, "Eintragungsstatus", ausgabe) def clearAuswahl(self): for w in self.iterWidgets(True): w[0].setParent(None) self._sportler=[] def iterWidgets(self,allWidgets = False)->QWidget: for row in range(3, self.mainLayout.rowCount()-(1 if not allWidgets else 0)): for col in range(self.mainLayout.columnCount()): item = self.mainLayout.itemAtPosition(row, col) if item is not None and item.widget() is not None: yield (item.widget(), row, col) else: break def update(self): if not self.auswahlKlasse(): return
class ImageTab(QWidget): def __init__(self, parent): super(ImageTab, self).__init__(parent) self.parent = parent self.name = 'Images' self.formats = config.image_formats self.extra_img = config.image_extra_formats validator = QRegExpValidator(QRegExp(r'^[1-9]\d*'), self) converttoQL = QLabel(self.tr('Convert to:')) self.extQCB = QComboBox() commandQL = QLabel(self.tr('Extra options:')) self.commandQLE = QLineEdit() hlayout2 = utils.add_to_layout( 'h', converttoQL, self.extQCB, commandQL, self.commandQLE) sizeQL = QLabel( '<html><p align="center">' + self.tr('Image Size:') + '</p></html>') self.widthQLE = utils.create_LineEdit((50, 16777215), validator, 4) self.heightQLE = utils.create_LineEdit((50, 16777215), validator, 4) label = QLabel('<html><p align="center">x</p></html>') label.setMaximumWidth(25) hlayout1 = utils.add_to_layout('h', self.widthQLE, label,self.heightQLE) sizelayout = utils.add_to_layout('v', sizeQL, hlayout1) self.imgaspectQChB = QCheckBox(self.tr("Maintain aspect ratio")) self.autocropQChB = QCheckBox(self.tr("Auto-crop")) vlayout = utils.add_to_layout('v', self.imgaspectQChB,self.autocropQChB) rotateQL = QLabel( "<html><div align='center'>" + self.tr("Rotate") + ":</div><br>(" + self.tr("degrees - clockwise") + ")</html>") self.rotateQLE = utils.create_LineEdit((100, 16777215), validator, 3) self.vflipQChB = QCheckBox(self.tr('Vertical flip')) self.hflipQChB = QCheckBox(self.tr('Horizontal flip')) vlayout2 = utils.add_to_layout('v', self.vflipQChB, self.hflipQChB) hlayout3 = utils.add_to_layout( 'h', sizelayout, vlayout, rotateQL, self.rotateQLE, vlayout2, None) final_layout = utils.add_to_layout('v', hlayout2, hlayout3) self.setLayout(final_layout) def clear(self): """Clear self.widthQLE and self.heightQLE.""" self.widthQLE.clear() self.heightQLE.clear() self.commandQLE.clear() self.rotateQLE.clear() self.imgaspectQChB.setChecked(False) self.autocropQChB.setChecked(False) self.vflipQChB.setChecked(False) self.hflipQChB.setChecked(False) def fill_extension_combobox(self, extraformats): self.extQCB.clear() self.extQCB.addItems(sorted(self.formats + extraformats)) def ok_to_continue(self): """ Check if everything is ok with imagetab to continue conversion. Check if: - ImageMagick is missing. - Either none or both size lineEdits are active at a time. Return True if all tests pass, else False. """ width = self.widthQLE.text() height = self.heightQLE.text() if not self.parent.imagemagick: QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr( 'Error!'), self.tr('ImageMagick is not installed!')) return False if (width and not height) or (not width and height): QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr( 'Error!'), self.tr('The size LineEdit may not be empty.')) if width and not height: self.heightQLE.setFocus() else: self.widthQLE.setFocus() return False return True def set_default_command(self): """Set the default value to self.commandQLE.""" self.clear() self.commandQLE.setText(self.parent.default_command_image)
class comics_project_details_editor(QDialog): configGroup = "ComicsProjectManagementTools" """ Initialise the editor. @param projectUrl - The directory to which all paths are relative. """ def __init__(self, projectUrl=str()): super().__init__() self.projectUrl = projectUrl layout = QFormLayout() self.setLayout(layout) self.setWindowTitle(i18n("Comic Project Settings")) buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) self.lnProjectName = QLineEdit() self.lnProjectConcept = QLineEdit() self.cmb_defaultTemplate = QComboBox() self.pagesLocation = path_select( question=i18n("Where should the pages go?"), projectUrl=self.projectUrl) self.exportLocation = path_select( question=i18n("Where should the export go?"), projectUrl=self.projectUrl) self.templateLocation = path_select( question=i18n("Where are the templates?"), projectUrl=self.projectUrl) self.keyLocation = path_select( question=i18n("Where are the extra auto-completion keys located?")) self.keyLocation.setToolTip( i18n( "The location for extra autocompletion keys in the meta-data editor. Point this at a folder containing key_characters/key_format/key_genre/key_rating/key_author_roles/key_other with inside txt files(csv for tating) containing the extra auto-completion keys, each on a new line. This path is stored in the krita configuration, and not the project configuration." )) self.templateLocation.locationChanged.connect(self.refill_templates) layout.addRow(i18n("Project Name:"), self.lnProjectName) layout.addRow(i18n("Project Concept:"), self.lnProjectConcept) layout.addRow(i18n("Pages Folder:"), self.pagesLocation) layout.addRow(i18n("Export Folder:"), self.exportLocation) layout.addRow(i18n("Template Folder:"), self.templateLocation) layout.addRow(i18n("Default Template:"), self.cmb_defaultTemplate) layout.addRow(i18n("Extra Keys Folder:"), self.keyLocation) self.layout().addWidget(buttons) """ Fill the templates doc with the kra files found in the templates directory. Might want to extend this to other files as well, as they basically get resaved anyway... """ def refill_templates(self): self.cmb_defaultTemplate.clear() templateLocation = os.path.join(self.projectUrl, self.templateLocation.getLocation()) for entry in os.scandir(templateLocation): if entry.name.endswith('.kra') and entry.is_file(): name = os.path.relpath(entry.path, templateLocation) self.cmb_defaultTemplate.addItem(name) """ Load the UI values from the config dictionary given. """ def setConfig(self, config, projectUrl): self.projectUrl = projectUrl if "projectName" in config.keys(): self.lnProjectName.setText(config["projectName"]) if "concept" in config.keys(): self.lnProjectConcept.setText(config["concept"]) if "pagesLocation" in config.keys(): self.pagesLocation.setLocation(config["pagesLocation"]) if "exportLocation" in config.keys(): self.exportLocation.setLocation(config["exportLocation"]) if "templateLocation" in config.keys(): self.templateLocation.setLocation(config["templateLocation"]) self.refill_templates() self.keyLocation.setLocation( Application.readSetting(self.configGroup, "extraKeysLocation", str())) """ Store the GUI values into the config dictionary given. @return the config diactionary filled with new values. """ def getConfig(self, config): config["projectName"] = self.lnProjectName.text() config["concept"] = self.lnProjectConcept.text() config["pagesLocation"] = self.pagesLocation.getLocation() config["exportLocation"] = self.exportLocation.getLocation() config["templateLocation"] = self.templateLocation.getLocation() config["singlePageTemplate"] = os.path.join( self.templateLocation.getLocation(), self.cmb_defaultTemplate.currentText()) Application.writeSetting(self.configGroup, "extraKeysLocation", self.keyLocation.getLocation()) return config
class myClass(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setWindowTitle("下拉列表控件QComboBox") self.setGeometry(700, 300, 600, 500) myframe1 = QFrame(self) myframe1.move(50, 50) lbl_1 = QLabel("省", myframe1) lbl_1.move(0, 3) comBox1 = QComboBox(myframe1) comBox1.move(30, 0) # 传递字符串类型 comBox1.activated[str].connect(self.myActived) # 选择以后可以进行信号处理 # 省份 comBox1.addItem("选择省份") comBox1.addItem("广西") comBox1.addItem("广东") comBox1.addItem("福建") comBox1.addItem("北京") # 市级 lbl_2 = QLabel("市", myframe1) lbl_2.move(170, 3) self.comBox2 = QComboBox(myframe1) self.comBox2.move(200, 0) self.comBox2.activated[str].connect(self.myActived2) self.show() def myActived(self, strName): # 每次选择之前先清空 self.comBox2.clear() print(strName) if strName == "广西": self.comBox2.addItem("南宁") self.comBox2.addItem("贵港") self.comBox2.addItem("柳州") self.comBox2.addItem("桂林") self.comBox2.addItem("玉林") self.comBox2.addItem("防城港") self.comBox2.addItem("平果") elif strName == "广东": self.comBox2.addItem("广州") self.comBox2.addItem("深圳") self.comBox2.addItem("东莞") self.comBox2.addItem("珠海") self.comBox2.addItem("中山") self.comBox2.addItem("佛山") self.comBox2.addItem("惠州") elif strName == "福建": self.comBox2.addItem("厦门") self.comBox2.addItem("泉州") elif strName == "北京": self.comBox2.addItem("朝阳") self.comBox2.addItem("一环") self.comBox2.addItem("二环") elif strName == "选择省份": self.comBox2.clear() def myActived2(self, strName): print(strName)
class LedgerAuthDialog(QDialog): def __init__(self, handler, data): '''Ask user for 2nd factor authentication. Support text and security card methods. Use last method from settings, but support downgrade. ''' QDialog.__init__(self, handler.top_level_window()) self.handler = handler self.txdata = data self.idxs = self.txdata[ 'keycardData'] if self.txdata['confirmationType'] > 1 else '' self.setMinimumWidth(650) self.setWindowTitle(_("Ledger Wallet Authentication")) self.cfg = copy.deepcopy(self.handler.win.wallet.get_keystore().cfg) self.dongle = self.handler.win.wallet.get_keystore().get_client( ).dongle self.pin = '' self.devmode = self.getDevice2FAMode() if self.devmode == 0x11 or self.txdata['confirmationType'] == 1: self.cfg['mode'] = 0 vbox = QVBoxLayout() self.setLayout(vbox) def on_change_mode(idx): self.cfg[ 'mode'] = 0 if self.devmode == 0x11 else idx if idx > 0 else 1 if self.cfg['mode'] > 0: self.handler.win.wallet.get_keystore().cfg = self.cfg self.handler.win.wallet.save_keystore() self.update_dlg() def return_pin(): self.pin = self.pintxt.text( ) if self.txdata['confirmationType'] == 1 else self.cardtxt.text() if self.cfg['mode'] == 1: self.pin = ''.join(chr(int(str(i), 16)) for i in self.pin) self.accept() self.modebox = QWidget() modelayout = QHBoxLayout() self.modebox.setLayout(modelayout) modelayout.addWidget(QLabel(_("Method:"))) self.modes = QComboBox() modelayout.addWidget(self.modes, 2) modelayout.addStretch(1) self.modebox.setMaximumHeight(50) vbox.addWidget(self.modebox) self.populate_modes() self.modes.currentIndexChanged.connect(on_change_mode) self.helpmsg = QTextEdit() self.helpmsg.setStyleSheet( "QTextEdit { color:black; background-color: lightgray; }") self.helpmsg.setReadOnly(True) vbox.addWidget(self.helpmsg) self.pinbox = QWidget() pinlayout = QHBoxLayout() self.pinbox.setLayout(pinlayout) self.pintxt = QLineEdit() self.pintxt.setEchoMode(2) self.pintxt.setMaxLength(4) self.pintxt.returnPressed.connect(return_pin) pinlayout.addWidget(QLabel(_("Enter PIN:"))) pinlayout.addWidget(self.pintxt) pinlayout.addWidget(QLabel(_("NOT DEVICE PIN - see above"))) pinlayout.addStretch(1) self.pinbox.setVisible(self.cfg['mode'] == 0) vbox.addWidget(self.pinbox) self.cardbox = QWidget() card = QVBoxLayout() self.cardbox.setLayout(card) self.addrtext = QTextEdit() self.addrtext.setStyleSheet(''' QTextEdit { color:blue; background-color:lightgray; padding:15px 10px; border:none; font-size:20pt; font-family: "Courier New", monospace; } ''') self.addrtext.setReadOnly(True) self.addrtext.setMaximumHeight(130) card.addWidget(self.addrtext) def pin_changed(s): if len(s) < len(self.idxs): i = self.idxs[len(s)] addr = self.txdata['address'] if not constants.net.TESTNET: text = addr[:i] + '<u><b>' + addr[ i:i + 1] + '</u></b>' + addr[i + 1:] else: # pin needs to be created from mainnet address addr_mainnet = bitcoin.script_to_address( bitcoin.address_to_script(addr), net=constants.QtumMainnet) addr_mainnet = addr_mainnet[:i] + '<u><b>' + addr_mainnet[ i:i + 1] + '</u></b>' + addr_mainnet[i + 1:] text = str(addr) + '\n' + str(addr_mainnet) self.addrtext.setHtml(str(text)) else: self.addrtext.setHtml(_("Press Enter")) pin_changed('') cardpin = QHBoxLayout() cardpin.addWidget(QLabel(_("Enter PIN:"))) self.cardtxt = QLineEdit() self.cardtxt.setEchoMode(2) self.cardtxt.setMaxLength(len(self.idxs)) self.cardtxt.textChanged.connect(pin_changed) self.cardtxt.returnPressed.connect(return_pin) cardpin.addWidget(self.cardtxt) cardpin.addWidget(QLabel(_("NOT DEVICE PIN - see above"))) cardpin.addStretch(1) card.addLayout(cardpin) self.cardbox.setVisible(self.cfg['mode'] == 1) vbox.addWidget(self.cardbox) self.update_dlg() def populate_modes(self): self.modes.blockSignals(True) self.modes.clear() self.modes.addItem( _("Summary Text PIN (requires dongle replugging)" ) if self.txdata['confirmationType'] == 1 else _("Summary Text PIN is Disabled")) if self.txdata['confirmationType'] > 1: self.modes.addItem(_("Security Card Challenge")) self.modes.blockSignals(False) def update_dlg(self): self.modes.setCurrentIndex(self.cfg['mode']) self.modebox.setVisible(True) self.helpmsg.setText(helpTxt[self.cfg['mode']]) self.helpmsg.setMinimumHeight(180 if self.txdata['confirmationType'] == 1 else 100) self.helpmsg.setVisible(True) self.pinbox.setVisible(self.cfg['mode'] == 0) self.cardbox.setVisible(self.cfg['mode'] == 1) self.pintxt.setFocus( True) if self.cfg['mode'] == 0 else self.cardtxt.setFocus(True) self.setMaximumHeight(400) def getDevice2FAMode(self): apdu = [0xe0, 0x24, 0x01, 0x00, 0x00, 0x01] # get 2fa mode try: mode = self.dongle.exchange(bytearray(apdu)) return mode except BTChipException as e: _logger.debug('Device getMode Failed') return 0x11
class SimTab(QWidget): def __init__(self, main_app): super().__init__() self.main_app = main_app self.oengus = main_app.oengus self.main_params = self.oengus.MainParamDict self.sim_selected = self.oengus.sims[0] self.build_ui() def build_ui(self): min_width = 150 max_width = 200 layout = QGridLayout() self.setLayout(layout) #### # # Build up the sim settings tab # # Choose Sim: | ComboBox | # Choose shock finder: | ComboBox | # #### layout.addWidget(QLabel('Choose sim'), 0, 0) self.sim_combo = QComboBox(self) self.update_sim_list() self.sim_combo.currentIndexChanged.connect(self.sim_selection_changed) layout.addWidget(self.sim_combo, 0, 1) layout.addWidget(QLabel('Choose Shock Finder'), 1, 0) self.shock_combo = QComboBox(self) self.update_shock_opts() self.shock_combo.currentIndexChanged.connect(self.shock_finder_changed) layout.addWidget(self.shock_combo, 1, 1) #### # # prtl stride: # | QLineEdit | | x | average 1D | # #### sim_ind = self.sim_selected.sim_num sim_params = self.main_params['sim_params'][sim_ind] layout.addWidget(QLabel('Prtl Stride'), 2, 0) self.prtl_stride_edit = QLineEdit(self) self.prtl_stride_edit.setText(str(sim_params['PrtlStride'])) self.prtl_stride_edit.setMaximumWidth(max_width) self.prtl_stride_edit.setMinimumWidth(min_width) self.prtl_stride_edit.returnPressed.connect(self.stride_changed) layout.addWidget(self.prtl_stride_edit, 2, 1) self.average1D_cb = QCheckBox("Average1D") self.average1D_cb.setChecked(sim_params['Average1D']) self.average1D_cb.stateChanged.connect(self.avg_changed) layout.addWidget(self.average1D_cb, 3, 0) # radio buttons to choose plane. row = QHBoxLayout() row.addWidget(QLabel('Choose 2D-plane:')) self.slice_radio_btns = [] radiobutton = QRadioButton("x-y") radiobutton.plane = 0 radiobutton.toggled.connect(self.radio_clicked) self.slice_radio_btns.append(radiobutton) row.addWidget(radiobutton) radiobutton = QRadioButton("x-z") radiobutton.plane = 1 radiobutton.toggled.connect(self.radio_clicked) self.slice_radio_btns.append(radiobutton) row.addWidget(radiobutton) radiobutton = QRadioButton("y-z") radiobutton.plane = 2 radiobutton.toggled.connect(self.radio_clicked) self.slice_radio_btns.append(radiobutton) row.addWidget(radiobutton) layout.addLayout(row, 4, 0, 1, 2) # Now do the sliders self.sliders_dict = {} for i, ax in enumerate(['x', 'y', 'z']): row = QHBoxLayout() sld_obj = {} sld_obj['label'] = QLabel(self) sld_obj['sld'] = QSlider(Qt.Horizontal, self) sld_obj['sld'].ax = ax # update the text box whenever sld is change sld_obj['sld'].valueChanged.connect(self.scale_handler) # only update the plot when the user releases the mouse sld_obj['sld'].mouseReleaseEvent = partial(self.update_slice_val, ax) # self.sld.setRange(self.param.minimum, self.param.maximum) sld_obj['sld'].setFocusPolicy(Qt.NoFocus) sld_obj['sld'].setPageStep(1) row.addWidget(QLabel(f'{ax}-slice')) row.addWidget(sld_obj['sld']) row.addWidget(sld_obj['label']) self.sliders_dict[ax] = sld_obj layout.addLayout(row, 5 + i, 0, 1, 2) self.update_slice_widgets() def scale_handler(self, e): # if changing the scale will change the value of the parameter, do so sld = self.sender() ax = self.sim_selected.get_data(data_class='axes', attribute=sld.ax)['data'] self.sliders_dict[sld.ax]['label'].setText( f'{round(ax[int(sld.value())], 2)}') def update_slice_val(self, ax_name, e): sim_ind = self.sim_selected.sim_num sim_params = self.main_params['sim_params'][sim_ind] sld = self.sliders_dict[ax_name]['sld'] ax = self.sim_selected.get_data(data_class='axes', attribute=ax_name)['data'] next_sld_val = float(sld.value()) / (len(ax) - 1.0) if next_sld_val != sim_params[f'{ax_name}Slice']: sim_params[f'{ax_name}Slice'] = next_sld_val if not sim_params['Average1D']: for i in range(self.oengus.MainParamDict['NumOfRows']): for j in range(self.oengus.MainParamDict['NumOfCols']): self.oengus.SubPlotList[i][j].save_axes_pos() self.oengus.SubPlotList[i][j].refresh() self.oengus.SubPlotList[i][j].load_axes_pos() self.oengus.canvas.draw() def update_slice_widgets(self): sim_ind = self.sim_selected.sim_num sim_params = self.main_params['sim_params'][sim_ind] for btn in self.slice_radio_btns: btn.setChecked(btn.plane == sim_params['2DSlicePlane']) x_ax = self.sim_selected.get_data(data_class='axes', attribute='x')['data'] y_ax = self.sim_selected.get_data(data_class='axes', attribute='y')['data'] z_ax = self.sim_selected.get_data(data_class='axes', attribute='z')['data'] self.slice_radio_btns[1].setEnabled(len(z_ax) > 1) self.slice_radio_btns[2].setEnabled( # Fals (len(y_ax) > 1) and (len(z_ax) > 1)) # enable or disable sliders # for key in ['edit', 'sld']: self.sliders_dict['x']['sld'].setEnabled( sim_params['2DSlicePlane'] == 2 and (len(x_ax) > 1)) self.sliders_dict['y']['sld'].setEnabled( (sim_params['2DSlicePlane'] != 2) and (len(y_ax) > 1)) self.sliders_dict['z']['sld'].setEnabled((len(z_ax) > 1)) self.update_slider_vals() def update_slider_vals(self): for key in ['x', 'y', 'z']: ax = self.sim_selected.get_data(data_class='axes', attribute=key)['data'] if len(ax) > 1: self.sliders_dict[key]['sld'].setRange(0, len(ax) - 1) self.sliders_dict[key]['sld'].setValue( self.oengus.calc_slices(key, self.sim_selected)) def radio_clicked(self): # If the shared axes are changed, we have to call the link # handler on every subplot radioButton = self.sender() sim_ind = self.sim_selected.sim_num sim_params = self.main_params['sim_params'][sim_ind] if radioButton.isChecked(): if sim_params['2DSlicePlane'] != radioButton.plane: sim_params['2DSlicePlane'] = radioButton.plane self.update_slice_widgets() self.oengus.figure.clf() self.oengus.create_graphs() self.oengus.canvas.draw() def avg_changed(self): ind = self.sim_selected.sim_num sim_params = self.main_params['sim_params'][ind] if sim_params['Average1D'] != self.average1D_cb.isChecked(): sim_params['Average1D'] = self.average1D_cb.isChecked() for i in range(self.oengus.MainParamDict['NumOfRows']): for j in range(self.oengus.MainParamDict['NumOfCols']): self.oengus.SubPlotList[i][j].save_axes_pos() self.oengus.SubPlotList[i][j].refresh() self.oengus.SubPlotList[i][j].load_axes_pos() self.oengus.canvas.draw() def stride_changed(self): # Note here that Tkinter passes an event object to SkipSizeChange() if not self.ignoreChange: ind = self.sim_selected.sim_num sim_params = self.main_params['sim_params'][ind] try: sim_params['PrtlStride'] = int(self.prtl_stride_edit.text()) self.sim_selected.xtra_stride = sim_params['PrtlStride'] for i in range(self.oengus.MainParamDict['NumOfRows']): for j in range(self.oengus.MainParamDict['NumOfCols']): self.oengus.SubPlotList[i][j].save_axes_pos() self.oengus.SubPlotList[i][j].refresh() self.oengus.SubPlotList[i][j].load_axes_pos() self.oengus.canvas.draw() except ValueError: self.prtl_stride_edit.setText(str(sim_params['PrtlStride'])) def update_sim_list(self): self.ignoreChange = True self.sim_combo.clear() for name in self.oengus.sim_names: self.sim_combo.addItem(name) index = self.sim_combo.findText(self.sim_selected.name) if index >= 0: self.sim_combo.setCurrentIndex(index) self.ignoreChange = False def sim_selection_changed(self): if not self.ignoreChange: if self.sim_combo.currentText() != self.sim_selected.name: try: ind = self.oengus.sim_names.index( self.sim_combo.currentText()) except ValueError: ind = 0 self.sim_selected = self.oengus.sims[ind] sim_params = self.oengus.MainParamDict['sim_params'][ind] self.prtl_stride_edit.setText(str(sim_params['PrtlStride'])) self.average1D_cb.setChecked(sim_params['Average1D']) self.update_shock_opts() self.update_slice_widgets() def update_shock_opts(self): self.ignoreChange = True self.shock_combo.clear() avail_opts = self.sim_selected.get_available_quantities() for method_name in avail_opts['shock_finders']: self.shock_combo.addItem(method_name) sim_params = self.oengus.MainParamDict['sim_params'][ self.sim_selected.sim_num] index = self.shock_combo.findText(sim_params['shock_method']) self.ignoreChange = False if index >= 0: self.shock_combo.setCurrentIndex(index) else: self.shock_combo.setCurrentIndex(0) def shock_finder_changed(self, *args): if not self.ignoreChange: combo_name = self.shock_combo.currentText() sim_params = self.oengus.MainParamDict['sim_params'][ self.sim_selected.sim_num] if sim_params['shock_method'] != combo_name: sim_params['shock_method'] = combo_name # self.shock_finder_var.set(self.sim_selected.shock_finder_name) # update shock lines for i in range(self.oengus.MainParamDict['NumOfRows']): for j in range(self.oengus.MainParamDict['NumOfCols']): self.oengus.SubPlotList[i][j].save_axes_pos() self.oengus.SubPlotList[i][j].refresh() self.oengus.SubPlotList[i][j].load_axes_pos() self.oengus.canvas.draw()
class DirectoriesDialog(QMainWindow): def __init__(self, app, **kwargs): super().__init__(None, **kwargs) self.app = app self.lastAddedFolder = platform.INITIAL_FOLDER_IN_DIALOGS self.recentFolders = Recent(self.app, 'recentFolders') self._setupUi() self._updateScanTypeList() self.directoriesModel = DirectoriesModel(self.app.model.directory_tree, view=self.treeView) self.directoriesDelegate = DirectoriesDelegate() self.treeView.setItemDelegate(self.directoriesDelegate) self._setupColumns() self.app.recentResults.addMenu(self.menuLoadRecent) self.app.recentResults.addMenu(self.menuRecentResults) self.recentFolders.addMenu(self.menuRecentFolders) self._updateAddButton() self._updateRemoveButton() self._updateLoadResultsButton() self._updateActionsState() self._setupBindings() def _setupBindings(self): self.appModeRadioBox.itemSelected.connect(self.appModeButtonSelected) self.showPreferencesButton.clicked.connect(self.app.actionPreferences.trigger) self.scanButton.clicked.connect(self.scanButtonClicked) self.loadResultsButton.clicked.connect(self.actionLoadResults.trigger) self.addFolderButton.clicked.connect(self.actionAddFolder.trigger) self.removeFolderButton.clicked.connect(self.removeFolderButtonClicked) self.treeView.selectionModel().selectionChanged.connect(self.selectionChanged) self.app.recentResults.itemsChanged.connect(self._updateLoadResultsButton) self.recentFolders.itemsChanged.connect(self._updateAddButton) self.recentFolders.mustOpenItem.connect(self.app.model.add_directory) self.directoriesModel.foldersAdded.connect(self.directoriesModelAddedFolders) self.app.willSavePrefs.connect(self.appWillSavePrefs) def _setupActions(self): # (name, shortcut, icon, desc, func) ACTIONS = [ ('actionLoadResults', 'Ctrl+L', '', tr("Load Results..."), self.loadResultsTriggered), ('actionShowResultsWindow', '', '', tr("Results Window"), self.app.showResultsWindow), ('actionAddFolder', '', '', tr("Add Folder..."), self.addFolderTriggered), ] createActions(ACTIONS, self) def _setupMenu(self): self.menubar = QMenuBar(self) self.menubar.setGeometry(QRect(0, 0, 42, 22)) self.menuFile = QMenu(self.menubar) self.menuFile.setTitle(tr("File")) self.menuView = QMenu(self.menubar) self.menuView.setTitle(tr("View")) self.menuHelp = QMenu(self.menubar) self.menuHelp.setTitle(tr("Help")) self.menuLoadRecent = QMenu(self.menuFile) self.menuLoadRecent.setTitle(tr("Load Recent Results")) self.setMenuBar(self.menubar) self.menuFile.addAction(self.actionLoadResults) self.menuFile.addAction(self.menuLoadRecent.menuAction()) self.menuFile.addSeparator() self.menuFile.addAction(self.app.actionClearPictureCache) self.menuFile.addSeparator() self.menuFile.addAction(self.app.actionQuit) self.menuView.addAction(self.app.actionPreferences) self.menuView.addAction(self.actionShowResultsWindow) self.menuView.addAction(self.app.actionIgnoreList) self.menuHelp.addAction(self.app.actionShowHelp) self.menuHelp.addAction(self.app.actionOpenDebugLog) self.menuHelp.addAction(self.app.actionAbout) self.menubar.addAction(self.menuFile.menuAction()) self.menubar.addAction(self.menuView.menuAction()) self.menubar.addAction(self.menuHelp.menuAction()) # Recent folders menu self.menuRecentFolders = QMenu() self.menuRecentFolders.addAction(self.actionAddFolder) self.menuRecentFolders.addSeparator() # Recent results menu self.menuRecentResults = QMenu() self.menuRecentResults.addAction(self.actionLoadResults) self.menuRecentResults.addSeparator() def _setupUi(self): self.setWindowTitle(self.app.NAME) self.resize(420, 338) self.centralwidget = QWidget(self) self.verticalLayout = QVBoxLayout(self.centralwidget) hl = QHBoxLayout() label = QLabel(tr("Application Mode:"), self) label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) hl.addWidget(label) self.appModeRadioBox = RadioBox( self, items=[tr("Standard"), tr("Music"), tr("Picture")], spread=False ) hl.addWidget(self.appModeRadioBox) self.verticalLayout.addLayout(hl) hl = QHBoxLayout() hl.setAlignment(Qt.AlignLeft) label = QLabel(tr("Scan Type:"), self) label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) hl.addWidget(label) self.scanTypeComboBox = QComboBox(self) self.scanTypeComboBox.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)) self.scanTypeComboBox.setMaximumWidth(400) hl.addWidget(self.scanTypeComboBox) self.showPreferencesButton = QPushButton(tr("More Options"), self.centralwidget) self.showPreferencesButton.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) hl.addWidget(self.showPreferencesButton) self.verticalLayout.addLayout(hl) self.promptLabel = QLabel(tr("Select folders to scan and press \"Scan\"."), self.centralwidget) self.verticalLayout.addWidget(self.promptLabel) self.treeView = QTreeView(self.centralwidget) self.treeView.setSelectionMode(QAbstractItemView.ExtendedSelection) self.treeView.setSelectionBehavior(QAbstractItemView.SelectRows) self.treeView.setAcceptDrops(True) triggers = QAbstractItemView.DoubleClicked | QAbstractItemView.EditKeyPressed\ | QAbstractItemView.SelectedClicked self.treeView.setEditTriggers(triggers) self.treeView.setDragDropOverwriteMode(True) self.treeView.setDragDropMode(QAbstractItemView.DropOnly) self.treeView.setUniformRowHeights(True) self.verticalLayout.addWidget(self.treeView) self.horizontalLayout = QHBoxLayout() self.removeFolderButton = QPushButton(self.centralwidget) self.removeFolderButton.setIcon(QIcon(QPixmap(":/minus"))) self.removeFolderButton.setShortcut("Del") self.horizontalLayout.addWidget(self.removeFolderButton) self.addFolderButton = QPushButton(self.centralwidget) self.addFolderButton.setIcon(QIcon(QPixmap(":/plus"))) self.horizontalLayout.addWidget(self.addFolderButton) spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem1) self.loadResultsButton = QPushButton(self.centralwidget) self.loadResultsButton.setText(tr("Load Results")) self.horizontalLayout.addWidget(self.loadResultsButton) self.scanButton = QPushButton(self.centralwidget) self.scanButton.setText(tr("Scan")) self.scanButton.setDefault(True) self.horizontalLayout.addWidget(self.scanButton) self.verticalLayout.addLayout(self.horizontalLayout) self.setCentralWidget(self.centralwidget) self._setupActions() self._setupMenu() if self.app.prefs.directoriesWindowRect is not None: self.setGeometry(self.app.prefs.directoriesWindowRect) else: moveToScreenCenter(self) def _setupColumns(self): header = self.treeView.header() header.setStretchLastSection(False) header.setSectionResizeMode(0, QHeaderView.Stretch) header.setSectionResizeMode(1, QHeaderView.Fixed) header.resizeSection(1, 100) def _updateActionsState(self): self.actionShowResultsWindow.setEnabled(self.app.resultWindow is not None) def _updateAddButton(self): if self.recentFolders.isEmpty(): self.addFolderButton.setMenu(None) else: self.addFolderButton.setMenu(self.menuRecentFolders) def _updateRemoveButton(self): indexes = self.treeView.selectedIndexes() if not indexes: self.removeFolderButton.setEnabled(False) return self.removeFolderButton.setEnabled(True) def _updateLoadResultsButton(self): if self.app.recentResults.isEmpty(): self.loadResultsButton.setMenu(None) else: self.loadResultsButton.setMenu(self.menuRecentResults) def _updateScanTypeList(self): try: self.scanTypeComboBox.currentIndexChanged[int].disconnect(self.scanTypeChanged) except TypeError: # Not connected, ignore pass self.scanTypeComboBox.clear() scan_options = self.app.model.SCANNER_CLASS.get_scan_options() for scan_option in scan_options: self.scanTypeComboBox.addItem(scan_option.label) SCAN_TYPE_ORDER = [so.scan_type for so in scan_options] selected_scan_type = self.app.prefs.get_scan_type(self.app.model.app_mode) scan_type_index = SCAN_TYPE_ORDER.index(selected_scan_type) self.scanTypeComboBox.setCurrentIndex(scan_type_index) self.scanTypeComboBox.currentIndexChanged[int].connect(self.scanTypeChanged) self.app._update_options() #--- QWidget overrides def closeEvent(self, event): event.accept() if self.app.model.results.is_modified: title = tr("Unsaved results") msg = tr("You have unsaved results, do you really want to quit?") if not self.app.confirm(title, msg): event.ignore() if event.isAccepted(): QApplication.quit() #--- Events def addFolderTriggered(self): title = tr("Select a folder to add to the scanning list") flags = QFileDialog.ShowDirsOnly dirpath = str(QFileDialog.getExistingDirectory(self, title, self.lastAddedFolder, flags)) if not dirpath: return self.lastAddedFolder = dirpath self.app.model.add_directory(dirpath) self.recentFolders.insertItem(dirpath) def appModeButtonSelected(self, index): if index == 2: mode = AppMode.Picture elif index == 1: mode = AppMode.Music else: mode = AppMode.Standard self.app.model.app_mode = mode self._updateScanTypeList() def appWillSavePrefs(self): self.app.prefs.directoriesWindowRect = self.geometry() def directoriesModelAddedFolders(self, folders): for folder in folders: self.recentFolders.insertItem(folder) def loadResultsTriggered(self): title = tr("Select a results file to load") files = ';;'.join([tr("dupeGuru Results (*.dupeguru)"), tr("All Files (*.*)")]) destination = QFileDialog.getOpenFileName(self, title, '', files) if destination: self.app.model.load_from(destination) self.app.recentResults.insertItem(destination) def removeFolderButtonClicked(self): self.directoriesModel.model.remove_selected() def scanButtonClicked(self): if self.app.model.results.is_modified: title = tr("Start a new scan") msg = tr("You have unsaved results, do you really want to continue?") if not self.app.confirm(title, msg): return self.app.model.start_scanning() def scanTypeChanged(self, index): scan_options = self.app.model.SCANNER_CLASS.get_scan_options() self.app.prefs.set_scan_type(self.app.model.app_mode, scan_options[index].scan_type) self.app._update_options() def selectionChanged(self, selected, deselected): self._updateRemoveButton()
class tb_optical_model(QWidget): def __init__(self): QWidget.__init__(self) self.dump_dir = os.path.join(get_sim_path(), "light_dump") self.layout = QVBoxLayout() label = QLabel(_("Optical model") + ":") self.layout.addWidget(label) self.cb = QComboBox() self.cb.activated.connect(self.on_cb_model_changed) self.layout.addWidget(self.cb) self.update() self.setLayout(self.layout) self.show() def get_text(self): out = self.cb.currentText() out = out.split(" ")[0] return out def file_name_set_start(self, start): self.start = start def file_name_set_end(self, end): self.end = end def find_models(self): ret = [] path = get_plugins_path() for file in glob.glob(os.path.join(path, "*")): file_name = os.path.basename(file) if file_name.startswith("light_"): if file_name.endswith(".dll") or file_name.endswith(".so"): ret.append(os.path.basename(file_name[6:]).split(".")[0]) return ret def on_cb_model_changed(self): cb_text = self.cb.currentText() inp_update_token_value("light.inp", "#light_model", cb_text) def update(self): self.cb.blockSignals(True) self.cb.clear() models = self.find_models() if len(models) == 0: error_dlg( self, _("I can't find any optical plugins, I think the model is not installed properly." )) return for i in range(0, len(models)): self.cb.addItem(models[i]) used_model = inp_get_token_value( os.path.join(get_sim_path(), "light.inp"), "#light_model") print(models, used_model) if models.count(used_model) == 0: used_model = "exp" inp_update_token_value(os.path.join(get_sim_path(), "light.inp"), "#light_model", "exp") self.cb.setCurrentIndex(self.cb.findText(used_model)) else: self.cb.setCurrentIndex(self.cb.findText(used_model)) self.cb.blockSignals(False)
class SearchWindow(QWidget): # Find all objects which property fits a given value # ------------- # ComboBox: list of all subtypes of objects # ComboBox: list of all properties of the subtype # CheckBox: whether the search is regex-based or not # LineEdit: value # PushButton: confirmation # ------------- def __init__(self, controller): super().__init__() self.controller = controller self.setWindowTitle('Search window') self.setMinimumSize(300, 200) self.subtypes_list = QComboBox() self.subtypes_list.addItems(name_to_obj) self.subtypes_list.activated.connect(self.update_properties) self.property_list = QComboBox() self.checkbox_regex = QCheckBox('Regex search') self.entry_search = QLineEdit() button_OK = QPushButton() button_OK.setText('OK') button_OK.clicked.connect(self.search) # position in the grid layout = QGridLayout() layout.addWidget(self.subtypes_list, 0, 0, 1, 2) layout.addWidget(self.property_list, 1, 0, 1, 2) layout.addWidget(self.checkbox_regex, 2, 0, 1, 1) layout.addWidget(self.entry_search, 3, 0, 1, 1) layout.addWidget(button_OK, 4, 0, 1, 1) self.setLayout(layout) # update property with first value of the list self.update_properties() def update_properties(self): subtype = self.subtypes_list.currentText() properties = object_properties[name_to_obj[subtype]] properties = tuple(p.pretty_name for p in properties) self.property_list.clear() self.property_list.addItems(properties) @update_paths def search(self, _): self.view.scene.clearSelection() subtype = name_to_obj[self.subtypes_list.currentText()] property = pretty_name_to_class[self.property_list.currentText()] type = subtype_to_type[subtype] input = self.entry_search.text() for obj in self.network.ftr(type, subtype): value = getattr(obj, property.name) if not self.checkbox_regex.isChecked(): converted_input = self.network.objectizer(property.name, input) if value == converted_input: obj.gobject[self.view].setSelected(True) else: if re.search(str(input), str(value)): obj.gobject[self.view].setSelected(True)
class QVisaUnitSelector(QWidget): def __init__(self, config): # Inherits QWidget QWidget.__init__(self) self._base = collections.OrderedDict({"G" : 1e9, "M" : 1e6, "k" : 1e3, "": 1, "m" : 1e-3, "u" : 1e-6, "n" : 1e-9 }) # QVisaUnitSelector configuration dictionary example # { # "unit" : "V", # "min" : "u", # "max" : "", # "label" : "Voltage (V)", # "limit" : 1.0, # "signed" : True, # "default" : [100, "m"] # } self.config = config # If not generating a unitless value _gen_unit_range if self.config['unit'] not in ['__INT__', '__DOUBLE__']: self._gen_unit_range() # Generate the widget self.setLayout(self._gen_unit_selector()) # Generate unit range based on user input def _gen_unit_range(self): # Initialise self._units, _append = {}, False # Loop through orderedDict (decending magnitude) for _k,_v in list(self._base.items()): if _k == self.config["max"]: _append = True if _k == self.config["min"]: self._units[ str(_k) + str( self.config["unit"]) ] = _v break if _append: self._units[ str(_k) + str( self.config["unit"]) ] = _v # Function to update spinbox range on unit maximum def _update_unit_selector(self): # If we are working with physical units if self.unit_select is not None: # This if is needed so clear() in update does not trigger this method if self.unit_select.currentText() != "": # Calculate unit limit in updated units _limit = ( self.config["limit"][0] * self._base[self.config["limit"][1]] ) / float( self._units[self.unit_select.currentText()] ) # Calculate ratio between previous and current units _ratio = float( self._units[ self._selected ] ) / float( self._units[ self.unit_select.currentText() ] ) # Calculate value in updated units _value = self.unit_value.value() * _ratio # Taking into account signed/unsigned input set maximum and minimum if self.config["signed"] == True: self.unit_value.setMaximum( 1.0 * _limit ) self.unit_value.setMinimum( -1.0 * _limit ) self.unit_value.setValue( _value ) # Set minimum takeing into account signed/unsigned input else: self.unit_value.setMaximum( 1.0 * _limit ) self.unit_value.setMinimum( 0.0 ) self.unit_value.setValue( _value ) # Cache new value for next ratio calculation self._selected = self.unit_select.currentText() # Otherwise ints or doubles else: if self.config['unit'] == "__DOUBLE__": self.unit_value.setMaximum(self.config["limit"][0] ) if self.config["signed"] == True: self.unit_value.setMinimum(self.config["limit"][0] ) else: self.unit_value.setMinimum( 0.0 ) if self.config['unit'] == "__INT__": self.unit_value.setMaximum( int( self.config["limit"][0] ) ) if self.config["signed"] == True: self.unit_value.setMinimum( int( self.config["limit"][0] ) ) else: self.unit_value.setMinimum( 0 ) # Generate unit selector def _gen_unit_selector(self): # Unit selection box self.unit_layout = QHBoxLayout() self.unit_layout.setContentsMargins(0,0,0,0) # Generate unit box (double value) if self.config['unit'] == "__DOUBLE__": # Unit select first (see below) self.unit_select = None self._selected = None # Unit value Spinbox self.unit_value = QDoubleSpinBox() self.unit_value.setDecimals(3) self.unit_value.setSingleStep(0.1) self._update_unit_selector() self.unit_value.setValue(self.config["default"][0]) self.unit_value.setFixedWidth(200) # Generate unit box (int value) elif self.config['unit'] == "__INT__": # Unit select first (see below) self.unit_select = None self._selected = None # Unit value Spinbox self.unit_value = QSpinBox() self.unit_value.setFixedWidth(200) self.unit_value.setValue(int(self.config["default"][0])) self._update_unit_selector() # for limits on init # General case (physical units) else: # Unit selection combobox: needs to be first so self.unit_select # exists on _update_unit_limits call self.unit_select = QComboBox() self.unit_select.setFixedWidth(80) self.unit_select.addItems( list(self._units.keys()) ) self.unit_select.setCurrentText(self.config["default"][1] + self.config["unit"]) self.unit_select.currentTextChanged.connect(self._update_unit_selector) # Cache current value of base self._selected = self.unit_select.currentText() # Unit value Spinbox self.unit_value = QDoubleSpinBox() self.unit_value.setDecimals(3) self.unit_value.setSingleStep(0.1) self._update_unit_selector() # for limits on init self.unit_value.setValue(self.config["default"][0]) self.unit_value.setFixedWidth(200) # Add widgets to hbox self.unit_label=QLabel(self.config["label"]) # Pack this last # Pack units self.unit_layout.addWidget(self.unit_value) if self.unit_select is not None: self.unit_layout.addWidget(self.unit_select) self.unit_layout.addWidget(self.unit_label) self.unit_layout.setContentsMargins(0,0,0,0) # Return layout return self.unit_layout # Method to re-render widget with new configuration def update_config(self, _config): # Update configuration and generate units self.config = _config self._gen_unit_range() # Clear combobox and add new unit values if self.unit_select is not None: self.unit_select.clear() self.unit_select.addItems( list(self._units.keys()) ) # Call _update_unit_limits for new limits # (it should be called on add_items) self._update_unit_limits() # Update default value self.unit_value.setValue(self.config["default"][0]) if self.config["default"] == 2: self.unit_select.setCurrentText(self.config["default"][1] + self.config["unit"]) # Set label text self.unit_label.setText(self.config["label"]) # Wrapper for value method def value(self): if self.unit_select is not None: return float( self._units[ self.unit_select.currentText() ] * self.unit_value.value() ) else: return self.unit_value.value() # Wrapper method for setEnabled def setEnabled(self, _bool): self.unit_value.setEnabled(_bool) self.unit_select.setEnabled(_bool)