class ParamSpinBox(QAbstractSpinBox): # signals valueChanged = pyqtSignal(float) def __init__(self, parent): QAbstractSpinBox.__init__(self, parent) self.fName = "" self.fMinimum = 0.0 self.fMaximum = 1.0 self.fDefault = 0.0 self.fValue = None self.fStep = 0.01 self.fStepSmall = 0.0001 self.fStepLarge = 0.1 self.fIsReadOnly = False self.fScalePoints = None self.fUseScalePoints = False self.fBar = ParamProgressBar(self) self.fBar.setContextMenuPolicy(Qt.NoContextMenu) #self.fBar.show() self.fBox = None self.lineEdit().hide() self.customContextMenuRequested.connect(self.slot_showCustomMenu) self.fBar.valueChanged.connect(self.slot_progressBarValueChanged) QTimer.singleShot(0, self.slot_updateProgressBarGeometry) def setDefault(self, value): value = geFixedValue(self.fName, value, self.fMinimum, self.fMaximum) self.fDefault = value def setMinimum(self, value): self.fMinimum = value self.fBar.setMinimum(value) def setMaximum(self, value): self.fMaximum = value self.fBar.setMaximum(value) def setValue(self, value): value = geFixedValue(self.fName, value, self.fMinimum, self.fMaximum) if self.fValue == value: return False self.fValue = value self.fBar.setValue(value) if self.fUseScalePoints: self._setScalePointValue(value) self.valueChanged.emit(value) self.update() return True def setStep(self, value): if value == 0.0: self.fStep = 0.001 else: self.fStep = value if self.fStepSmall > value: self.fStepSmall = value if self.fStepLarge < value: self.fStepLarge = value self.fBar.fIsInteger = bool(self.fStepSmall == 1.0) def setStepSmall(self, value): if value == 0.0: self.fStepSmall = 0.0001 elif value > self.fStep: self.fStepSmall = self.fStep else: self.fStepSmall = value self.fBar.fIsInteger = bool(self.fStepSmall == 1.0) def setStepLarge(self, value): if value == 0.0: self.fStepLarge = 0.1 elif value < self.fStep: self.fStepLarge = self.fStep else: self.fStepLarge = value def setLabel(self, label): self.fBar.setLabel(label) def setName(self, name): self.fName = name self.fBar.setName(name) def setTextCallback(self, textCall): self.fBar.setTextCall(textCall) def setReadOnly(self, yesNo): self.fIsReadOnly = yesNo self.setButtonSymbols(QAbstractSpinBox.UpDownArrows if yesNo else QAbstractSpinBox.NoButtons) QAbstractSpinBox.setReadOnly(self, yesNo) # FIXME use change event def setEnabled(self, yesNo): self.fBar.setEnabled(yesNo) QAbstractSpinBox.setEnabled(self, yesNo) def setScalePoints(self, scalePoints, useScalePoints): if len(scalePoints) == 0: self.fScalePoints = None self.fUseScalePoints = False return self.fScalePoints = scalePoints self.fUseScalePoints = useScalePoints if not useScalePoints: return # Hide ProgressBar and create a ComboBox self.fBar.close() self.fBox = QComboBox(self) self.fBox.setContextMenuPolicy(Qt.NoContextMenu) #self.fBox.show() self.slot_updateProgressBarGeometry() # Add items, sorted boxItemValues = [] for scalePoint in scalePoints: value = scalePoint['value'] if self.fStep == 1.0: label = "%i - %s" % (int(value), scalePoint['label']) else: label = "%f - %s" % (value, scalePoint['label']) if len(boxItemValues) == 0: self.fBox.addItem(label) boxItemValues.append(value) else: if value < boxItemValues[0]: self.fBox.insertItem(0, label) boxItemValues.insert(0, value) elif value > boxItemValues[-1]: self.fBox.addItem(label) boxItemValues.append(value) else: for index in range(len(boxItemValues)): if value >= boxItemValues[index]: self.fBox.insertItem(index+1, label) boxItemValues.insert(index+1, value) break if self.fValue is not None: self._setScalePointValue(self.fValue) self.fBox.currentIndexChanged['QString'].connect(self.slot_comboBoxIndexChanged) def stepBy(self, steps): if steps == 0 or self.fValue is None: return value = self.fValue + (self.fStep * steps) if value < self.fMinimum: value = self.fMinimum elif value > self.fMaximum: value = self.fMaximum self.setValue(value) def stepEnabled(self): if self.fIsReadOnly or self.fValue is None: return QAbstractSpinBox.StepNone if self.fValue <= self.fMinimum: return QAbstractSpinBox.StepUpEnabled if self.fValue >= self.fMaximum: return QAbstractSpinBox.StepDownEnabled return (QAbstractSpinBox.StepUpEnabled | QAbstractSpinBox.StepDownEnabled) def updateAll(self): self.update() self.fBar.update() if self.fBox is not None: self.fBox.update() def resizeEvent(self, event): QAbstractSpinBox.resizeEvent(self, event) self.slot_updateProgressBarGeometry() @pyqtSlot(str) def slot_comboBoxIndexChanged(self, boxText): if self.fIsReadOnly: return value = float(boxText.split(" - ", 1)[0]) lastScaleValue = self.fScalePoints[-1]['value'] if value == lastScaleValue: value = self.fMaximum self.setValue(value) @pyqtSlot(float) def slot_progressBarValueChanged(self, value): if self.fIsReadOnly: return if value <= self.fMinimum: realValue = self.fMinimum elif value >= self.fMaximum: realValue = self.fMaximum else: curStep = int((value - self.fMinimum) / self.fStep + 0.5) realValue = self.fMinimum + (self.fStep * curStep) if realValue < self.fMinimum: realValue = self.fMinimum elif realValue > self.fMaximum: realValue = self.fMaximum self.setValue(realValue) @pyqtSlot() def slot_showCustomMenu(self): clipboard = QApplication.instance().clipboard() pasteText = clipboard.text() pasteValue = None if pasteText: try: pasteValue = float(pasteText) except: pass menu = QMenu(self) actReset = menu.addAction(self.tr("Reset (%f)" % self.fDefault)) actRandom = menu.addAction(self.tr("Random")) menu.addSeparator() actCopy = menu.addAction(self.tr("Copy (%f)" % self.fValue)) if pasteValue is None: actPaste = menu.addAction(self.tr("Paste")) actPaste.setEnabled(False) else: actPaste = menu.addAction(self.tr("Paste (%f)" % pasteValue)) menu.addSeparator() actSet = menu.addAction(self.tr("Set value...")) if self.fIsReadOnly: actReset.setEnabled(False) actRandom.setEnabled(False) actPaste.setEnabled(False) actSet.setEnabled(False) actSel = menu.exec_(QCursor.pos()) if actSel == actReset: self.setValue(self.fDefault) elif actSel == actRandom: value = random() * (self.fMaximum - self.fMinimum) + self.fMinimum self.setValue(value) elif actSel == actCopy: clipboard.setText("%f" % self.fValue) elif actSel == actPaste: self.setValue(pasteValue) elif actSel == actSet: dialog = CustomInputDialog(self, self.fName, self.fValue, self.fMinimum, self.fMaximum, self.fStep, self.fScalePoints) if dialog.exec_(): value = dialog.returnValue() self.setValue(value) @pyqtSlot() def slot_updateProgressBarGeometry(self): self.fBar.setGeometry(self.lineEdit().geometry()) if self.fUseScalePoints: self.fBox.setGeometry(self.lineEdit().geometry()) def _getNearestScalePoint(self, realValue): finalValue = 0.0 for i in range(len(self.fScalePoints)): scaleValue = self.fScalePoints[i]["value"] if i == 0: finalValue = scaleValue else: srange1 = abs(realValue - scaleValue) srange2 = abs(realValue - finalValue) if srange2 > srange1: finalValue = scaleValue return finalValue def _setScalePointValue(self, value): value = self._getNearestScalePoint(value) for i in range(self.fBox.count()): if float(self.fBox.itemText(i).split(" - ", 1)[0]) == value: self.fBox.setCurrentIndex(i) break
def move_combo(direction: str, combo: QComboBox): current_index = combo.currentIndex() if direction == 'left': if current_index == 0: combo.setCurrentIndex(combo.count() - 1) else: combo.setCurrentIndex(current_index - 1) if direction == 'right': if current_index == combo.count() - 1: combo.setCurrentIndex(0) else: combo.setCurrentIndex(current_index + 1)
def get_elements_from_combobox(combobox: QComboBox) -> List[str]: """ Returns all elements from combobox provided in a list. :param combobox: Combobox to get list of elements from. :return: List of elements from combobox. """ return [combobox.itemText(i) for i in range(combobox.count())]
def _create_control_select(self, device, zone, option): """ Prepares and returns a dropdown for changing options. """ params = option["parameters"] current_index = 0 combo = QComboBox() combo.setIconSize(QSize(16, 16)) for i, param in enumerate(params): icon_path = common.get_icon("params", param["id"]) combo.addItem(param["label"]) if icon_path: combo.setItemIcon(combo.count() - 1, QIcon(icon_path)) if param["active"] is True: current_index = i i = i + 1 combo.setCurrentIndex(current_index) def _current_index_changed(index): param = params[index] self._event_set_option(device, zone, option["id"], param["data"]) combo.currentIndexChanged.connect(_current_index_changed) return [combo]
def append_to_combobox(cbox: QComboBox): current = cbox.currentText() completions = set(cbox.itemText(i) for i in range(cbox.count())) completions.add(current) cbox.clear() cbox.addItems(completions) cbox.setCurrentIndex(cbox.findText(current))
class NewContactDialog(QDialog): def __init__(self, users): super().__init__() self.setWindowTitle("New Contact") self.users = QComboBox() self.users.addItems(users) self.users.currentTextChanged.connect(self.userSelected) self.current = [self.users.itemText(i) for i in range(self.users.count())][0] self.addBtn = QPushButton() self.addBtn.setText('Add') self.addBtn.clicked.connect(self.addContact) self.layout = QVBoxLayout() self.layout.addWidget(self.users) self.layout.addWidget(self.addBtn) self.setLayout(self.layout) def addContact(self): self.close() def userSelected(self, value): self.current = value
class QComboBoxDemo(QWidget): def __init__(self): super(QComboBoxDemo, self).__init__() self.initUI() def initUI(self): self.setWindowTitle('QComboBoxDemo') self.resize(300, 280) layout = QVBoxLayout() self.label = QLabel('请选择语言...') self.cb = QComboBox() self.cb.addItem('C') self.cb.addItem('C++') self.cb.addItems(['Java', 'Python']) self.cb.currentIndexChanged.connect(self.SelectionChanged) layout.addWidget(self.label) layout.addWidget(self.cb) self.setLayout(layout) def SelectionChanged(self, i): self.label.setText(self.cb.currentText()) self.label.adjustSize() self.label.setFont(QFont('Arial', 20)) for item in range(self.cb.count()): print('Item:' + str(item) + ',' + self.cb.itemText(item)) print('CurrentIndex:' + str(i) + ',SelecctionChanged:' + self.cb.itemText(i))
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 comboBoxDemo(QWidget): def __init__(self): super(comboBoxDemo, self).__init__() self.initUI() def initUI(self): self.setWindowTitle('下拉列表框测试') self.label = QLabel('请选择您最喜欢的春节晚会节目') layout = QHBoxLayout() # 使用水平布局 self.cb = QComboBox() # 实例化一个下拉列表框 self.cb.addItems(['相声', '小品', '歌曲', '舞蹈']) # 添加下拉列表中的选项 self.cb.currentIndexChanged.connect( self.selectionChange) # 信号绑定,并传递所选的索引Index # 控件使用水平布局 layout.addWidget(self.label) layout.addWidget(self.cb) self.setLayout(layout) def selectionChange(self, i): "这是一个函数文档,下面的for循环及那个cb下拉列表框中的项都打印出来" for count in range(self.cb.count()): print('item' + str(count) + '=' + self.cb.itemText(count)) # 打印目前选中的 print('current index', i, 'selection changed', self.cb.currentText())
def needs_update(self, cb: QComboBox, new_data: list): if self.debug == True: print(new_data) if cb.count() <= 0: cb.addItems(new_data) else: self.update(cb, new_data)
class SerialChooser(QWidget): def __init__(self, master): super().__init__(master) grid = QGridLayout() self.comboBox = QComboBox(self) self.comboBox.addItem(DEFAULT_ROBOT_SERIAL_PORT) self.comboBox.setEditable(True) grid.addWidget(self.comboBox, 0, 0) self.setLayout(grid) def setEntries(self, entries): for i in range(self.comboBox.count()): self.comboBox.removeItem(i) self.comboBox.addItems(entries) def getEntry(self): strList = self.comboBox.currentText().split() if len(strList) > 0: return strList[0] else: return "" def markBlank(self): self.comboBox.setStyleSheet("") def markWrong(self): self.comboBox.setStyleSheet("""QComboBox { background-color: rgb(249, 83, 83) }""") def markConnected(self): self.comboBox.setStyleSheet("""QComboBox { background-color: rgb(203, 230, 163) }""")
def __init__(self, main_form, edit_these, new_item, title): QMainWindow.__init__(self, main_form) self.helper = HelpHandler(self) self.help_topic = "swmm/src/src/groundwaterfloweditordialog.htm" self._main_form = main_form self.project = main_form.project self.new_item = new_item self.refresh_column = -1 self.setupUi(self) self.setWindowTitle(title) self.cmdOK.clicked.connect(self.cmdOK_Clicked) self.cmdCancel.clicked.connect(self.cmdCancel_Clicked) self.backend = PropertyEditorBackend(self.tblGeneric, self.lblNotes, main_form, edit_these, new_item) for column in range(0, self.tblGeneric.columnCount()): # for aquifers, show available aquifers aquifer_section = main_form.project.find_section("AQUIFERS") aquifer_list = aquifer_section.value[0:] combobox = QComboBox() combobox.addItem('') selected_index = 0 for value in aquifer_list: combobox.addItem(value.name) if edit_these[column].aquifer == value.name: selected_index = int(combobox.count()) - 1 combobox.setCurrentIndex(selected_index) self.tblGeneric.setCellWidget(1, column, combobox) # also set special text plus button cells self.set_lateral_equation(column) self.set_deep_equation(column) self.installEventFilter(self)
class MainWin(QWidget): def __init__(self, parent=None): super(MainWin, self).__init__(parent) layout = QVBoxLayout() self.cb = QComboBox() self.cb.addItem('C') self.cb.addItem('C++') self.cb.addItems(['Java', 'C#', 'Python']) self.cb.currentIndexChanged.connect(self.selectionchange) layout.addWidget(self.cb) self.lb = QLabel('') layout.addWidget(self.lb) self.setLayout(layout) self.resize(300, 90) self.setWindowTitle('ComboBox') def selectionchange(self, idx): self.lb.setText(self.cb.currentText()) print('Items in the list are: ') for i in range(self.cb.count()): print('item {} = {}'.format(i, self.cb.itemText(i))) print('Current index', idx, 'selection changed', self.cb.currentText())
class QComboBoxDemo(QWidget): def __init__(self): super(QComboBoxDemo, self).__init__() self.v_layout = QVBoxLayout() self.label = QLabel('请选择编程语言') self.comboBox = QComboBox() self.initUI() def initUI(self): self.setWindowTitle('下拉列表控件') self.comboBox.addItem('C++') self.comboBox.addItem('C') self.comboBox.addItem('Python') self.comboBox.addItems(['Java', 'C#', 'R']) self.comboBox.currentIndexChanged.connect(self.selection_change) self.v_layout.addWidget(self.label) self.v_layout.addWidget(self.comboBox) self.setLayout(self.v_layout) def selection_change(self, index): self.label.setText(self.comboBox.currentText()) # self.label.adjustSize() for count in range(self.comboBox.count()): print('item {} = {}'.format(count, self.comboBox.itemText(count))) print('current index {}, selection changed {}'.format( index, self.comboBox.currentText()))
class RosIPSetupWidget(QGroupBox): def __init__(self, parent=None): QGroupBox.__init__(self, "ros ip", parent) l = QVBoxLayout() self.setLayout(l) self.ip = QLineEdit("") self.comboip = QComboBox() for k, v in ip4_addresses().items(): self.comboip.addItem(k+': '+v, v) self.comboip.addItem("other...", "") self.comboip.currentIndexChanged.connect(self.comboip_currentIndexChanged) l.addWidget(self.comboip) l.addWidget(self.ip) def comboipChangeIndex(self, index): self.comboip.setCurrentIndex(index) self.comboip_currentIndexChanged(index) def comboip_currentIndexChanged(self, index): if index == self.comboip.count() - 1: self.ip.setEnabled(True) else: self.ip.setEnabled(False) value = self.comboip.itemData(index) if not isinstance(value, basestring): value = value.toString() #then it should be a QVariant self.ip.setText(value) def setData(self, data): ip = data["ROS_IP"] self.ip.setText("{0}".format(ip)) idx = self.comboip.findData(ip) if idx < 0: self.comboip.setItemData(self.comboip.count()-1, ip) self.comboipChangeIndex(self.comboip.count()-1) else: self.comboipChangeIndex(idx) def getData(self, data): data["ROS_IP"] = str(self.ip.text())
def get_style_combo_box(self): combo_box = QComboBox() combo_box.addItems(QStyleFactory.keys()) combo_box.activated[str].connect(self.change_style) all_items = [combo_box.itemText(i) for i in range(combo_box.count())] idx = all_items.index('Fusion') combo_box.setCurrentIndex(idx) return combo_box
def addToCombo(self, combo: QComboBox, data): print(data, combo) if data: if 'id' in data.keys() and 'name' in data.keys(): item = "{id} - {name}".format(**data) #QComboBox.itemText items = [combo.itemText(i) for i in range(combo.count())] if item not in items: combo.addItem(item)
def __init__(self, main_form, edit_these, new_item): self.help_topic = "swmm/src/src/pumpproperties.htm" self._main_form = main_form self.project = main_form.project self.refresh_column = -1 self.project_section = self.project.pumps if self.project_section and \ isinstance(self.project_section.value, list) and \ len(self.project_section.value) > 0 and \ isinstance(self.project_section.value[0], self.SECTION_TYPE): if edit_these: # Edit only specified item(s) in section if isinstance(edit_these[0], str): # Translate list from names to objects edit_names = edit_these edit_objects = [item for item in self.project_section.value if item.name in edit_these] edit_these = edit_objects else: # Edit all items in section edit_these = [] edit_these.extend(self.project_section.value) frmGenericPropertyEditor.__init__(self, main_form, self.project_section, edit_these, new_item, "SWMM " + self.SECTION_TYPE.__name__ + " Editor") for column in range(0, self.tblGeneric.columnCount()): # for curves, show available curves curves_section = self.project.find_section("CURVES") curves_list = curves_section.value[0:] combobox = QComboBox() combobox.addItem('*') selected_index = 0 for curve in curves_list: if curve.curve_type in [CurveType.PUMP1, CurveType.PUMP2, CurveType.PUMP3, CurveType.PUMP4]: combobox.addItem(curve.name) if len(edit_these) > 0: if edit_these[column].pump_curve == curve.name: selected_index = int(combobox.count())-1 combobox.setCurrentIndex(selected_index) self.tblGeneric.setCellWidget(5, column, combobox) # for initial status, show on/off combobox = QComboBox() combobox.addItem('OFF') combobox.addItem('ON') combobox.setCurrentIndex(1) if len(edit_these) > 0: if edit_these[column].initial_status == 'OFF': combobox.setCurrentIndex(0) self.tblGeneric.setCellWidget(6, column, combobox) if (main_form.program_settings.value("Geometry/" + "frmPumps_geometry") and main_form.program_settings.value("Geometry/" + "frmPumps_state")): self.restoreGeometry(main_form.program_settings.value("Geometry/" + "frmPumps_geometry", self.geometry(), type=QtCore.QByteArray)) self.restoreState(main_form.program_settings.value("Geometry/" + "frmPumps_state", self.windowState(), type=QtCore.QByteArray)) self.installEventFilter(self)
def setFieldNames(note_field_input: QComboBox, new_text): # clear out old options for index in range(note_field_input.count()): note_field_input.removeItem(0) for note_type in note_types: if note_type["name"] == new_text: for field in note_type["flds"]: note_field_input.addItem(field["name"])
def __init__(self, main_form, edit_these, new_item): self.help_topic = "swmm/src/src/outletproperties.htm" self._main_form = main_form self.project = main_form.project self.refresh_column = -1 self.project_section = self.project.outlets if self.project_section and \ isinstance(self.project_section.value, list) and \ len(self.project_section.value) > 0 and \ isinstance(self.project_section.value[0], self.SECTION_TYPE): if edit_these: # Edit only specified item(s) in section if isinstance(edit_these[0], str): # Translate list from names to objects edit_names = edit_these edit_objects = [ item for item in self.project_section.value if item.name in edit_these ] edit_these = edit_objects else: # Edit all items in section edit_these = [] edit_these.extend(self.project_section.value) frmGenericPropertyEditor.__init__( self, main_form, self.project_section, edit_these, new_item, "SWMM " + self.SECTION_TYPE.__name__ + " Editor") for column in range(0, self.tblGeneric.columnCount()): # for flapgate, show true/false combobox = QComboBox() combobox.addItem('True') combobox.addItem('False') combobox.setCurrentIndex(1) if len(edit_these) > 0: if edit_these[column].flap_gate == 'True' or edit_these[ column].flap_gate == True: combobox.setCurrentIndex(0) self.tblGeneric.setCellWidget(6, column, combobox) # tabular curve name curves_section = self.project.find_section("CURVES") curves_list = curves_section.value[0:] combobox = QComboBox() combobox.addItem('*') selected_index = 0 for value in curves_list: if value.curve_type == CurveType.RATING: combobox.addItem(value.name) if len(edit_these) > 0: if edit_these[column].rating_curve == value.name: selected_index = int(combobox.count()) - 1 combobox.setCurrentIndex(selected_index) self.tblGeneric.setCellWidget(10, column, combobox) self.installEventFilter(self)
def __init__(self, main_form, edit_these, new_item): self.help_topic = "swmm/src/src/aquifereditordialog.htm" frmGenericPropertyEditor.__init__( self, main_form, main_form.project.aquifers, edit_these, new_item, "SWMM " + self.SECTION_TYPE.__name__ + " Editor") self.project_section = main_form.project.aquifers if self.project_section and \ isinstance(self.project_section.value, list) and \ len(self.project_section.value) > 0 and \ isinstance(self.project_section.value[0], self.SECTION_TYPE): if edit_these: # Edit only specified item(s) in section if isinstance(edit_these[0], str): # Translate list from names to objects edit_names = edit_these edit_objects = [ item for item in self.project_section.value if item.name in edit_these ] edit_these = edit_objects else: # Edit all items in section edit_these = [] edit_these.extend(self.project_section.value) self.pattern_section = main_form.project.patterns pattern_list = self.pattern_section.value[0:] for column in range(0, self.tblGeneric.columnCount()): # for patterns, show available patterns combobox = QComboBox() combobox.addItem('') selected_index = 0 for value in pattern_list: combobox.addItem(value.name) if edit_these[column].upper_evaporation_pattern == value.name: selected_index = int(combobox.count()) - 1 combobox.setCurrentIndex(selected_index) self.tblGeneric.setCellWidget(13, column, combobox) self._main_form = main_form if (main_form.program_settings.value("Geometry/" + "frmAquifers_geometry") and main_form.program_settings.value("Geometry/" + "frmAquifers_state")): self.restoreGeometry( main_form.program_settings.value("Geometry/" + "frmAquifers_geometry", self.geometry(), type=QtCore.QByteArray)) self.restoreState( main_form.program_settings.value("Geometry/" + "frmAquifers_state", self.windowState(), type=QtCore.QByteArray))
def IterComboBox(self, direction: int, CMBX: QtWidgets.QComboBox): # Tested """ Iters and loads the corresponding for all the DB that have been declared for Apollo :Args: direction: int Direction for the list to iter in (Forward/Backward) CMBX: QtWidgets.QComboBox Combobox with all the DB names. """ Index = CMBX.currentIndex() + (direction) if Index == CMBX.count(): Index = 0 elif Index < 0: Index = CMBX.count() - 1 else: pass CMBX.setCurrentIndex(Index)
def PopulateCMBX(self, CMBX: QtWidgets.QComboBox, Data=None): # Tested """ Populates the CMBX with the data provided :Args: CMBX: QtWidgets.QComboBox Combobox with all the DB names. Data: list[str, str, str] data to fill in the combobox """ if Data == None: DBnames = self.UI.DB_Monitored.keys() else: DBnames = Data [CMBX.removeItem(item) for item in range(CMBX.count())] CMBXitems = [CMBX.itemText(item) for item in range(CMBX.count())] for Name in DBnames: if Name not in CMBXitems: CMBX.addItem(Name)
def addItem(combo: QComboBox, db_manager, data: dict, check=False) -> int: """добавление элемента""" display_key = combo.model().display if check: index = findItem(combo, data[display_key]) if index >= 0: return index table_class = getattr(combo.model(), 'TableClass') new_id = db_manager.createRecord(table_class, data) data.update({'ID': new_id}) combo.addItem(data[display_key], data) return combo.count() - 1
def __genSelectionEntry(self, key, setting): newItem = QTreeWidgetItem(self.__ui.settingsTree, [key]) selectionWidget = QComboBox(self.__ui.settingsTree) selectionWidget.setProperty("key", key) for val in setting["values"]: selectionWidget.addItem(str(val), val) if setting["value"] == val: selectionWidget.setCurrentIndex(selectionWidget.count() - 1) self.__ui.settingsTree.setItemWidget(newItem, 1, selectionWidget) selectionWidget.currentIndexChanged[int].connect(self.__valueChangedIndex) return newItem
def __init__(self, session, edit_these, new_item): self.help_topic = "epanet/src/src/Rese0029.htm" self.session = session self.project = session.project self.refresh_column = -1 self.project_section = self.project.reservoirs if self.project_section and \ isinstance(self.project_section.value, list) and \ len(self.project_section.value) > 0 and \ isinstance(self.project_section.value[0], self.SECTION_TYPE): if edit_these: # Edit only specified item(s) in section if isinstance(edit_these[0], str): # Translate list from names to objects edit_names = edit_these edit_objects = [ item for item in self.project_section.value if item.name in edit_these ] edit_these = edit_objects else: # Edit all items in section edit_these = [] edit_these.extend(self.project_section.value) frmGenericPropertyEditor.__init__(self, session, session.project.reservoirs, edit_these, new_item, "EPANET Reservoir Editor") for column in range(0, self.tblGeneric.columnCount()): # for pattern, show available patterns pattern_list = self.project.patterns.value combobox = QComboBox() combobox.addItem('') selected_index = 0 for value in pattern_list: combobox.addItem(value.name) if edit_these[column].head_pattern_name == value.name: selected_index = int(combobox.count()) - 1 combobox.setCurrentIndex(selected_index) self.tblGeneric.setCellWidget(6, column, combobox) # set coordinates # coordinate_section = self.project.find_section("COORDINATES") # if coordinate_section.value[edit_these[column].name]: # value = coordinate_section.value[edit_these[column].name].x # self.tblGeneric.setItem(1, column, QTableWidgetItem(value)) # value = coordinate_section.value[edit_these[column].name].y # self.tblGeneric.setItem(2, column, QTableWidgetItem(value)) # also set special text plus button cells self.set_quality_cell(column) self.installEventFilter(self)
def set_combo_text(self, combo: QtWidgets.QComboBox, text: str) -> None: """Convenience function to update set the current text of a combobox. Parameters ---------- combo: PyQt5.QtWidgets.QComboBox The combobox to modify text: str The item to use""" items = list(map(combo.itemText, range(combo.count()))) if text in items: combo.setCurrentIndex(items.index(text))
def createEditor(self, parent, option, index): editor = QComboBox(parent) editor.addItem("Unknown (und)", None) editor.insertSeparator(editor.count()) common_langs = ["eng", "deu", "ita", "spa", "fra", "por", "nld", "swe", "nor", "fin", "pol", "ron", "rus", "tur", "vie", "kor", "arz", "pes", "hin", "zho", "jpn"] for key in common_langs: lang = LANGUAGES[key] editor.addItem(f"{lang} ({key})", key) editor.insertSeparator(editor.count()) for key, lang in sorted(LANGUAGES.items(), key=lambda item: item[1]): if key in common_langs: continue editor.addItem(f"{lang} ({key})", key) return editor
def display_ports(ports: typing.List[QtSerialPort.QSerialPortInfo], combo: QComboBox) -> typing.Dict[str, str]: known_keys = set() remove_indices = [] was_empty = combo.count() == 0 def make_description(p: QtSerialPort.QSerialPortInfo) -> str: out = f'{p.portName()}: {p.manufacturer() or "Unknown vendor"} - {p.description() or "Unknown product"}' if p.serialNumber().strip(): out += ' #' + str(p.serialNumber()) return out description_location_mapping = {} description_icon_mapping = {} for x in ports: desc = make_description(x) icon = _get_port_icon(x) description_location_mapping[desc] = x.systemLocation() if icon: description_icon_mapping[desc] = icon # Marking known and scheduling for removal for idx in itertools.count(): tx = combo.itemText(idx) if not tx: break known_keys.add(tx) if tx not in description_location_mapping: _logger.debug('Removing port %r', tx) remove_indices.append(idx) # Removing - starting from the last item in order to retain indexes for idx in remove_indices[::-1]: combo.removeItem(idx) # Adding new items - starting from the last item in order to retain the final order for key in list(description_location_mapping.keys())[::-1]: if key not in known_keys: _logger.debug('Adding port %r', key) try: combo.insertItem(0, description_icon_mapping[key], key) except KeyError: combo.insertItem(0, key) # Updating selection if was_empty: combo.setCurrentIndex(0) return description_location_mapping
class LateralPanel(QWidget): def __init__(self, explorer): super(LateralPanel, self).__init__() vbox = QVBoxLayout(self) vbox.setContentsMargins(0, 0, 0, 0) vbox.addWidget(explorer) hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) self.labelText = "Ln: %s, Col: %s" self.labelCursorPosition = QLabel(_translate("LateralPanel", self.labelText % (0, 0))) hbox.addWidget(self.labelCursorPosition) self.combo = QComboBox() ui_tools.ComboBoxButton(self.combo, self.combo.clear, self.style().standardPixmap(self.style().SP_TrashIcon)) self.combo.setToolTip(_translate("LateralPanel", "Select the item from the Paste " "Historial list.\nYou can Copy items into this list with: " "%s\nor Paste them using: %s") % (resources.get_shortcut("History-Copy").toString( QKeySequence.NativeText), resources.get_shortcut("History-Paste").toString( QKeySequence.NativeText))) self.combo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) hbox.addWidget(self.combo) vbox.addLayout(hbox) def update_line_col(self, line, col): self.labelCursorPosition.setText(_translate("LateralPanel", self.labelText % (line, col))) def add_new_copy(self, copy): self.combo.insertItem(0, copy) self.combo.setCurrentIndex(0) if self.combo.count() > settings.COPY_HISTORY_BUFFER: self.combo.removeItem(self.combo.count() - 1) def get_paste(self): return self.combo.currentText()
class SelectSpeciesDialog(QDialog): def __init__(self, species, parent=None): super(SelectSpeciesDialog, self).__init__(parent=parent) self.setWindowTitle('Select Species') layout = QGridLayout(self) label = QLabel('species shown in pictures:', self) self.species_combo = QComboBox(self) self.species_combo.setMinimumWidth(300) for s in species: self.species_combo.addItem(s) add_species_button = QPushButton('New', self) def add_species(): name, ok = QInputDialog.getText(self, 'Add Species', 'name of species:') if name and ok: # does species already exist? index = self.species_combo.findText(name, QtCore.Qt.MatchFixedString) if index >= 0: self.species_combo.setCurrentIndex(index) self.species_combo.addItem(name) self.species_combo.setCurrentIndex( self.species_combo.count() - 1 ) add_species_button.pressed.connect(add_species) spacer = QSpacerItem(20, 10, QSizePolicy.Fixed) buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self) def check_selection(): if len(self.species_combo.currentText()) > 0: self.accept() buttons.accepted.connect(check_selection) buttons.rejected.connect(self.reject) layout.addWidget(label, 0, 0) layout.addWidget(self.species_combo, 1, 0) layout.addWidget(add_species_button, 1, 1) layout.addItem(spacer, 2, 0) layout.addWidget(buttons, 3, 0) # static method to create the dialog and return (date, time, accepted) @staticmethod def get_species(species, parent = None): dialog = SelectSpeciesDialog(species, parent) result = dialog.exec_() selection = dialog.species_combo.currentText() return selection, result == QDialog.Accepted
def __init__(self, main_form, edit_these, new_item): self.help_topic = "swmm/src/src/storageunitproperties.htm" self._main_form = main_form self.project = main_form.project self.refresh_column = -1 self.project_section = self.project.storage self.new_item = new_item if self.project_section and \ isinstance(self.project_section.value, list) and \ len(self.project_section.value) > 0 and \ isinstance(self.project_section.value[0], self.SECTION_TYPE): if edit_these: # Edit only specified item(s) in section if isinstance(edit_these[0], str): # Translate list from names to objects edit_names = edit_these edit_objects = [ item for item in self.project_section.value if item.name in edit_these ] edit_these = edit_objects else: # Edit all items in section edit_these = [] edit_these.extend(self.project_section.value) frmGenericPropertyEditor.__init__(self, main_form, self.project.storage, edit_these, new_item, "SWMM Storage Units Editor") for column in range(0, self.tblGeneric.columnCount()): combobox = QComboBox() combobox.addItem('') selected_index = 0 for value in self.project.curves.value: if value.curve_type == CurveType.STORAGE: combobox.addItem(value.name) if edit_these[column].storage_curve == value.name: selected_index = int(combobox.count()) - 1 combobox.setCurrentIndex(selected_index) self.tblGeneric.setCellWidget(17, column, combobox) # also set special text plus button cells self.set_seepage_loss_cell(column) self.set_inflow_cell(column) self.set_treatment_cell(column) self.installEventFilter(self)
def __init__(self, main_form, edit_these, new_item): self.help_topic = "swmm/src/src/flowdividerproperties.htm" self._main_form = main_form self.project = main_form.project self.refresh_column = -1 self.project_section = self.project.dividers if self.project_section and \ isinstance(self.project_section.value, list) and \ len(self.project_section.value) > 0 and \ isinstance(self.project_section.value[0], self.SECTION_TYPE): if edit_these: # Edit only specified item(s) in section if isinstance(edit_these[0], str): # Translate list from names to objects edit_names = edit_these edit_objects = [item for item in self.project_section.value if item.name in edit_these] edit_these = edit_objects else: # Edit all items in section edit_these = [] edit_these.extend(self.project_section.value) frmGenericPropertyEditor.__init__(self, main_form, self.project_section, edit_these, new_item, "SWMM Dividers Editor") for column in range(0, self.tblGeneric.columnCount()): # for curves, show available curves curves_section = self.project.find_section("CURVES") curves_list = curves_section.value[0:] combobox = QComboBox() combobox.addItem('') selected_index = 0 for value in curves_list: if value.curve_type == CurveType.DIVERSION: combobox.addItem(value.name) if edit_these[column].divider_curve == value.name: selected_index = int(combobox.count())-1 combobox.setCurrentIndex(selected_index) self.tblGeneric.setCellWidget(15, column, combobox) # also set special text plus button cells self.set_inflow_cell(column) self.set_treatment_cell(column) if (main_form.program_settings.value("Geometry/" + "frmDividers_geometry") and main_form.program_settings.value("Geometry/" + "frmDividers_state")): self.restoreGeometry(main_form.program_settings.value("Geometry/" + "frmDividers_geometry", self.geometry(), type=QtCore.QByteArray)) self.restoreState(main_form.program_settings.value("Geometry/" + "frmDividers_state", self.windowState(), type=QtCore.QByteArray)) self.installEventFilter(self)
class LateralPanel(QWidget): splitEditor = pyqtSignal('QObject*', 'QObject*', bool) closeSplit = pyqtSignal(QWidget) def __init__(self, parent=None): super(LateralPanel, self).__init__(parent) self.has_component = False self.vbox = QVBoxLayout(self) self.vbox.setContentsMargins(0, 0, 0, 0) hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 5, 5) self.combo = QComboBox() ui_tools.ComboBoxButton(self.combo, self.combo.clear, self.style().standardPixmap(self.style().SP_TrashIcon)) self.combo.setToolTip(self.tr("Select the item from the Paste " "History list.\nYou can Copy items into this list with: " "%s\nor Paste them using: %s") % (resources.get_shortcut("History-Copy").toString( QKeySequence.NativeText), resources.get_shortcut("History-Paste").toString( QKeySequence.NativeText))) self.combo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) hbox.addWidget(self.combo) self.vbox.addLayout(hbox) def add_component(self, widget): self.vbox.insertWidget(0, widget) self.has_component = True def add_new_copy(self, copy): self.combo.insertItem(0, copy) self.combo.setCurrentIndex(0) if self.combo.count() > settings.COPY_HISTORY_BUFFER: self.combo.removeItem(self.combo.count() - 1) def get_paste(self): return self.combo.currentText()
class tb_pulse_load_type(QWidget): changed = pyqtSignal() def __init__(self,index): self.index=index QWidget.__init__(self) layout=QHBoxLayout() label=QLabel() label.setText(_("Load type:")) layout.addWidget(label) self.sim_mode = QComboBox(self) self.sim_mode.setEditable(True) layout.addWidget(self.sim_mode) self.setLayout(layout) self.sim_mode.addItem("open_circuit") self.sim_mode.addItem("load") self.sim_mode.addItem("ideal_diode_ideal_load") lines=[] inp_load_file(lines,os.path.join(get_inp_file_path(),"pulse"+str(self.index)+".inp")) token=inp_get_token_value("pulse"+str(self.index)+".inp", "#pulse_sim_mode") all_items = [self.sim_mode.itemText(i) for i in range(self.sim_mode.count())] for i in range(0,len(all_items)): if all_items[i] == token: self.sim_mode.setCurrentIndex(i) self.sim_mode.currentIndexChanged.connect(self.call_back_sim_mode_changed) def call_back_sim_mode_changed(self): mode=self.sim_mode.currentText() inp_update_token_value("pulse"+str(self.index)+".inp", "#pulse_sim_mode", mode,1) self.changed.emit()
class LabelComboBox(QWidget): def __init__(self, label='', items = {'UJ object reference value': 'Name to show'}): super(LabelComboBox, self).__init__() self.label = QLabel() self.label.setText(label) self.items = items self.combo_box = QComboBox() self.combo_box.insertItems(0, self.items.values()) self.layout = QHBoxLayout() self.layout.setContentsMargins(0,0,0,0) self.layout.addWidget(self.label) self.layout.addWidget(self.combo_box, stretch = 1) def reset_items(self, items = {'UJ object reference value': 'Name to show'}): while self.combo_box.count() != 0: self.combo_box.removeItem(0) self.items = items self.combo_box.addItems(self.items.values()) def show(self): self.combo_box.show() self.label.show() def hide(self): self.combo_box.hide() self.label.hide() def set_text(self, text): if text in self.items.values(): self.combo_box.setCurrentText(text) if text in self.items.keys(): self.combo_box.setCurrentText(self.items[text]) def text(self): return self.combo_box.currentText()
class NetworkSettingsPanel(SettingsPanel): def __init__(self, parent=None): super(NetworkSettingsPanel, self).__init__(parent) # Checkbox to toggle DNS prefetching. self.dnsPrefetchingToggle = QCheckBox(tr("Enable DNS &prefetching"), self) self.layout().addWidget(self.dnsPrefetchingToggle) # Checkbox to toggle XSS auditing. self.xssAuditingToggle = QCheckBox(tr("Enable X&SS auditing"), self) self.layout().addWidget(self.xssAuditingToggle) # Proxy label. proxyLabel = QLabel(tr("<b>Proxy configuration</b>")) self.layout().addWidget(proxyLabel) # Type row. typeRow = custom_widgets.Row(self) self.layout().addWidget(typeRow) # Create a nice label. typeLabel = QLabel(tr("Type:"), self) typeRow.addWidget(typeLabel) # Combo box to select proxy type. self.proxySelect = QComboBox(self) self.proxySelect.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.proxySelect.addItem("None") self.proxySelect.addItem('Socks5') self.proxySelect.addItem('Http') typeRow.addWidget(self.proxySelect) # Hostname and port row. self.hostNamePortRow = custom_widgets.Row() self.layout().addWidget(self.hostNamePortRow) # Hostname row. self.hostNameRow = custom_widgets.LineEditRow(tr("Hostname:"), self) self.hostNameEntry = self.hostNameRow.lineEdit self.hostNamePortRow.addWidget(self.hostNameRow) # Port row. self.portRow = custom_widgets.SpinBoxRow(tr("Port:"), self) self.portRow.expander.hide() self.portEntry = self.portRow.spinBox self.portEntry.setMaximum(99999) self.hostNamePortRow.addWidget(self.portRow) # User row. self.userRow = custom_widgets.LineEditRow(tr("User:"******"Password:"******"proxy/Hostname"))) self.userEntry.setText(str(settings.settings.value("proxy/User"))) self.passwordEntry.setText(str(settings.settings.value("proxy/Password"))) self.xssAuditingToggle.setChecked(settings.setting_to_bool("network/XSSAuditingEnabled")) self.dnsPrefetchingToggle.setChecked(settings.setting_to_bool("network/DnsPrefetchingEnabled")) port = settings.setting_to_int("proxy/Port") if port == "None": port = str(settings.default_port) self.portEntry.setValue(port) for index in range(0, self.proxySelect.count()): if self.proxySelect.itemText(index) == settings.settings.value("proxy/Type"): self.proxySelect.setCurrentIndex(index) break def saveSettings(self): settings.settings.setValue("proxy/Hostname", self.hostNameEntry.text()) proxyType = self.proxySelect.currentText() if proxyType == "None": proxyType = "No" settings.settings.setValue("network/XSSAuditingEnabled", self.xssAuditingToggle.isChecked()) settings.settings.setValue("network/DnsPrefetchingEnabled", self.dnsPrefetchingToggle.isChecked()) settings.settings.setValue("proxy/Type", proxyType) settings.settings.setValue("proxy/Port", self.portEntry.value()) settings.settings.setValue("proxy/User", self.userEntry.text()) settings.settings.setValue("proxy/Password", self.passwordEntry.text()) common.applyWebSettings() settings.settings.sync()
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 MainWindow(QMainWindow): """Main window.""" def __init__(self, parent=None): """Init class.""" super(MainWindow, self).__init__() # self.statusBar().showMessage(__doc__.strip().capitalize()) self.setWindowTitle(__doc__.strip().capitalize()) self.setMinimumSize(600, 200) self.setMaximumSize(800, 400) self.resize(self.minimumSize()) self.setWindowIcon(QIcon.fromTheme("preferences-system")) self.center() QShortcut("Ctrl+q", self, activated=lambda: self.close()) self.menuBar().addMenu("&File").addAction("Exit", exit) windowMenu = self.menuBar().addMenu("&Window") windowMenu.addAction("Minimize", lambda: self.showMinimized()) windowMenu.addAction("Maximize", lambda: self.showMaximized()) windowMenu.addAction("FullScreen", lambda: self.showFullScreen()) windowMenu.addAction("Restore", lambda: self.showNormal()) windowMenu.addAction("Center", lambda: self.center()) windowMenu.addAction("Top-Left", lambda: self.move(0, 0)) windowMenu.addAction("To Mouse", lambda: self.move_to_mouse_position()) windowMenu.addSeparator() windowMenu.addAction( "Increase size", lambda: self.resize(self.size().width() * 1.4, self.size().height() * 1.4)) windowMenu.addAction("Decrease size", lambda: self.resize( self.size().width() // 1.4, self.size().height() // 1.4)) windowMenu.addAction("Minimum size", lambda: self.resize(self.minimumSize())) windowMenu.addAction("Maximum size", lambda: self.resize(self.maximumSize())) windowMenu.addAction("Horizontal Wide", lambda: self.resize( self.maximumSize().width(), self.minimumSize().height())) windowMenu.addAction("Vertical Tall", lambda: self.resize( self.minimumSize().width(), self.maximumSize().height())) windowMenu.addSeparator() windowMenu.addAction("Disable Resize", lambda: self.setFixedSize(self.size())) windowMenu.addAction("Set Interface Font...", lambda: self.setFont(QFontDialog.getFont()[0])) helpMenu = self.menuBar().addMenu("&Help") helpMenu.addAction("About Qt 5", lambda: QMessageBox.aboutQt(self)) helpMenu.addAction("About Python 3", lambda: open_new_tab('https://www.python.org')) helpMenu.addAction("About" + __doc__, lambda: QMessageBox.about(self, __doc__, HELP)) helpMenu.addSeparator() helpMenu.addAction( "Keyboard Shortcut", lambda: QMessageBox.information(self, __doc__, "<b>Quit = CTRL+Q")) helpMenu.addAction("View Source Code", lambda: call('xdg-open ' + __file__, shell=True)) helpMenu.addAction("View GitHub Repo", lambda: open_new_tab(__url__)) helpMenu.addAction("Check Updates", lambda: Downloader(self)) container = QWidget() container_layout = QVBoxLayout(container) self.setCentralWidget(container) # widgets group0, group1 = QGroupBox("Message to QR Code"), QGroupBox("Options") container_layout.addWidget(group0) container_layout.addWidget(group1) # message self.message = QLineEdit() self.message.setPlaceholderText("{} type a message!".format(getuser())) self.message.setToolTip("Message Text to encode as QR Code Image") QHBoxLayout(group0).addWidget(self.message) # options self.background, self.foreground = QComboBox(), QComboBox() self.qrcodesize, self.qrerrorlvl = QSpinBox(), QSpinBox() self.background.setToolTip("Background Color") self.foreground.setToolTip("Foreground Color") self.qrcodesize.setToolTip("QR Code Size") self.qrerrorlvl.setToolTip("QR Code Error Tolerance Level") self.background.addItems(STANDARD_NAMED_COLORS) self.foreground.addItems(STANDARD_NAMED_COLORS) self.foreground.setCurrentIndex(randint(0, self.background.count())) self.qrcodesize.setRange(2, 20) self.qrcodesize.setValue(2) self.qrcodesize.setSingleStep(2) self.qrerrorlvl.setRange(0, 3) self.qrerrorlvl.setValue(1) self.qrerrorlvl.setSingleStep(1) opt_layout = QHBoxLayout(group1) opt_layout.addWidget(QLabel("<b>Background")) opt_layout.addWidget(self.background) opt_layout.addWidget(QLabel("<b>Foreground")) opt_layout.addWidget(self.foreground) opt_layout.addWidget(QLabel("<b>Size")) opt_layout.addWidget(self.qrcodesize) opt_layout.addWidget(QLabel("<b>Error Tolerance")) opt_layout.addWidget(self.qrerrorlvl) self.bt = QDialogButtonBox(self) self.bt.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Close) self.bt.rejected.connect(exit) self.bt.accepted.connect(self.run) container_layout.addWidget(self.bt) def run(self): """Run the main method and create QR Code.""" global BACKGROUND_COLOR, FOREGROUND_COLOR global QRCODE_SIZE, ERRORCORRECT_LVL if not len(self.message.text().strip()): return BACKGROUND_COLOR = str(self.background.currentText()).strip().lower() FOREGROUND_COLOR = str(self.foreground.currentText()).strip().lower() ERRORCORRECT_LVL = abs(self.qrerrorlvl.value()) QRCODE_SIZE = abs(self.qrcodesize.value()) qr = QRCode(QRCODE_SIZE, ERRORCORRECT_LVL) qr.addData(str(self.message.text()).strip().encode('ASCII', 'ignore')) qr.make() im = qr.makeImage() im.show() self.showMinimized() def center(self): """Center Window on the Current Screen,with Multi-Monitor support.""" window_geometry = self.frameGeometry() mousepointer_position = QApplication.desktop().cursor().pos() screen = QApplication.desktop().screenNumber(mousepointer_position) centerPoint = QApplication.desktop().screenGeometry(screen).center() window_geometry.moveCenter(centerPoint) self.move(window_geometry.topLeft()) def move_to_mouse_position(self): """Center the Window on the Current Mouse position.""" window_geometry = self.frameGeometry() window_geometry.moveCenter(QApplication.desktop().cursor().pos()) self.move(window_geometry.topLeft()) def closeEvent(self, event): """Ask to Quit.""" the_conditional_is_true = QMessageBox.question( self, __doc__.title(), 'Quit ?.', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == QMessageBox.Yes event.accept() if the_conditional_is_true else event.ignore()
class Settings_Net(QWidget): def __init__(self, parent: QWidget): super(Settings_Net, self).__init__(parent) self._layout = QVBoxLayout() self.setLayout(self._layout) # construct layout min_width = 150 self.user_agents = dict() self.user_agents["chrome_win7_x64"] = ( "Chrome 41, Windows 7 x64", "Mozilla/5.0 (Windows NT 6.1; WOW64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/41.0.2227.0 Safari/537.36", ) self.user_agents["chrome_linux_64"] = ( "Chrome 41, Linux x86_64", "Mozilla/5.0 (X11; Linux x86_64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/41.0.2227.0 Safari/537.36", ) self.user_agents["chrome_android"] = ( "Chrome 47, Android 4.3 Galaxy-S3", "Mozilla/5.0 (Linux; Android 4.3; GT-I9300 Build/JSS15J) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/47.0.2526.83 Mobile Safari/537.36", ) self.user_agents["firefox_win32"] = ( "Firefox 40, Windows 7 32-bit", "Mozilla/5.0 (Windows NT 6.1; rv:40.0) " "Gecko/20100101 Firefox/40.1", ) self.user_agents["firefox_android"] = ( "Firefox, Android 4.3 Galaxy-S3", "Mozilla/5.0 (Android 4.3; Mobile; rv:43.0) " "Gecko/43.0 Firefox/43.0", ) self.user_agents["edge_win10"] = ( "Microsoft Edge, Windows 10 x64", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/42.0.2311.135 Safari/537.36 Edge/12.246", ) # server URL self._l_surl = QHBoxLayout() self._l_ua = QHBoxLayout() self._lbl_surl = QLabel(self.tr("Server URL:"), self) self._lbl_surl.setMinimumWidth(min_width) self._le_surl = QLineEdit(self) self._l_surl.addWidget(self._lbl_surl) self._l_surl.addWidget(self._le_surl) self._layout.addLayout(self._l_surl) # emulate browser combo box self._l_eb = QHBoxLayout() self._lbl_eb = QLabel(self.tr("Emulate browser:"), self) self._lbl_eb.setMinimumWidth(min_width) self._cb_eb = QComboBox(self) self._cb_eb.setEditable(False) self._cb_eb.setInsertPolicy(QComboBox.InsertAtBottom) ua_keylist = [i for i in self.user_agents.keys()] ua_keylist.sort() for key_id in ua_keylist: b_tuple = self.user_agents[key_id] display_string = b_tuple[0] self._cb_eb.addItem(display_string, QVariant(str(key_id))) self._cb_eb.addItem(self.tr("<Custom>"), QVariant("custom")) self._l_eb.addWidget(self._lbl_eb) self._l_eb.addWidget(self._cb_eb) self._layout.addLayout(self._l_eb) # custom user-agent string self._lbl_ua = QLabel(self.tr("User-agent string:"), self) self._lbl_ua.setMinimumWidth(min_width) self._le_ua = QLineEdit(self) self._l_ua.addWidget(self._lbl_ua) self._l_ua.addWidget(self._le_ua) self._layout.addLayout(self._l_ua) # proxy settings self._l_proxy = QHBoxLayout() self._lbl_proxy = QLabel(self.tr("Proxy type:"), self) self._lbl_proxy.setMinimumWidth(min_width) self._cb_proxy = QComboBox(self) self._cb_proxy.setEditable(False) self._cb_proxy.addItem(self.tr("No proxy"), QVariant("none")) self._cb_proxy.addItem(self.tr("HTTP proxy"), QVariant("http")) self._cb_proxy.addItem(self.tr("SOCKS5 proxy"), QVariant("socks5")) self._l_proxy.addWidget(self._lbl_proxy) self._l_proxy.addWidget(self._cb_proxy) self._layout.addLayout(self._l_proxy) self._l_proxy_s = QHBoxLayout() self._lbl_proxy_s = QLabel(self.tr("Proxy addr:port:"), self) self._lbl_proxy_s.setMinimumWidth(min_width) self._le_proxy_addr = QLineEdit(self) self._l_proxy_s.addWidget(self._lbl_proxy_s) self._l_proxy_s.addWidget(self._le_proxy_addr) self._layout.addLayout(self._l_proxy_s) # all connections self._cb_eb.currentIndexChanged.connect(self.on_cb_eb_current_index_changed) self._cb_proxy.currentIndexChanged.connect(self.on_cb_proxy_current_index_changed) # finalize self._layout.addStretch() @pyqtSlot(int) def on_cb_eb_current_index_changed(self, index: int): key_id = str(self._cb_eb.currentData(Qt.UserRole)) if key_id == "custom": self._le_ua.setEnabled(True) return self._le_ua.setEnabled(False) if key_id in self.user_agents: b_tuple = self.user_agents[key_id] ua_str = b_tuple[1] self._le_ua.setText(ua_str) @pyqtSlot(int) def on_cb_proxy_current_index_changed(self, index: int): if index == 0: self._le_proxy_addr.setEnabled(False) else: self._le_proxy_addr.setEnabled(True) def ua_select(self, key_id: str): cnt = self._cb_eb.count() for i in range(cnt): item_key_id = str(self._cb_eb.itemData(i, Qt.UserRole)) if item_key_id == key_id: self._cb_eb.setCurrentIndex(i) break def load_from_config(self, cfg: configparser.ConfigParser): # defaults xnova_url = "uni4.xnova.su" user_agent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0" user_agent_id = "custom" proxy = "" if "net" in cfg: xnova_url = cfg["net"]["xnova_url"] user_agent = cfg["net"]["user_agent"] user_agent_id = cfg["net"]["user_agent_id"] proxy = cfg["net"]["proxy"] self._le_surl.setText(xnova_url) self._le_surl.setEnabled(False) # cannot be edited by user, for safety! # deal with user-agent self._le_ua.setText(user_agent) if user_agent_id == "custom": self._le_ua.setEnabled(True) else: self._le_ua.setEnabled(False) self.ua_select(user_agent_id) # deal with proxy if proxy == "": self._le_proxy_addr.setText("") self._cb_proxy.setCurrentIndex(0) self._le_proxy_addr.setEnabled(False) elif proxy.startswith("http://"): self._cb_proxy.setCurrentIndex(1) proxy_addr = proxy[7:] self._le_proxy_addr.setText(proxy_addr) self._le_proxy_addr.setEnabled(True) elif proxy.startswith("socks5://"): self._cb_proxy.setCurrentIndex(2) proxy_addr = proxy[9:] self._le_proxy_addr.setText(proxy_addr) self._le_proxy_addr.setEnabled(True) else: raise ValueError("Invalid proxy setting: " + proxy) def save_to_config(self, cfg: configparser.ConfigParser): # ensure there is a 'net' section if "net" not in cfg: cfg.add_section("net") # skip server url # deal with user-agent user_agent_id = "" user_agent = "" idx = self._cb_eb.currentIndex() if idx >= 0: user_agent_id = str(self._cb_eb.itemData(idx, Qt.UserRole)) cfg["net"]["user_agent_id"] = user_agent_id user_agent = self._le_ua.text().strip() if user_agent != "": cfg["net"]["user_agent"] = user_agent # deal with proxy idx = self._cb_proxy.currentIndex() proxy_addr = self._le_proxy_addr.text().strip() if idx == 0: cfg["net"]["proxy"] = "" elif idx == 1: cfg["net"]["proxy"] = "http://" + proxy_addr elif idx == 2: cfg["net"]["proxy"] = "socks5://" + proxy_addr logger.debug("Saved network config")
class LayoutSelect(QDialog): def __init__(self, parent=None): super().__init__(parent) self.filepath = '' self.layouts = {} self.setWindowModality(Qt.ApplicationModal) self.setWindowTitle('Layout selection') self.setMaximumSize(675, 300) self.setMinimumSize(675, 300) self.resize(675, 300) self.setLayout(QGridLayout(self)) self.layout().setContentsMargins(5, 5, 5, 5) self.layoutBox = QComboBox(self) self.layout().addWidget(self.layoutBox, 0, 0) self.layButton = QPushButton(self) self.layButton.setText('Select layout') self.layout().addWidget(self.layButton, 0, 1) self.fileButton = QPushButton(self) self.fileButton.setText('Open file') self.layout().addWidget(self.fileButton, 0, 2) self.layout().setColumnStretch(0, 3) self.layout().setColumnStretch(1, 2) self.layout().setColumnStretch(2, 1) line = QFrame(self) line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.layout().addWidget(line, 1, 0, 1, 3) self.description = QTextBrowser(self) self.layout().addWidget(self.description, 2, 0, 1, 3) for layout_class in layouts.get_layouts(): self.layoutBox.addItem(layout_class.NAME) self.layouts[layout_class.NAME] = (layout_class, layout_class.DESCRIPTION) if self.layoutBox.count() == 0: raise Exception('No layout installed!') self.show_description(self.layoutBox.currentText()) self.layoutBox.currentTextChanged.connect(self.show_description) self.layButton.clicked.connect(self.accept) self.fileButton.clicked.connect(self.open_file) def selected(self): return self.layouts[self.layoutBox.currentText()][0] def show_description(self, layout_name): self.description.setHtml('<center><h2>' + layout_name + '</h2></center><br>' + self.layouts[layout_name][1]) def open_file(self): path, _ = QFileDialog.getOpenFileName(self, filter='*.lsp', directory=os.getenv('HOME')) self.filepath = path self.accept() def closeEvent(self, e): e.ignore()
class PyMultiPageWidget(QWidget): currentIndexChanged = pyqtSignal(int) pageTitleChanged = pyqtSignal(str) def __init__(self, parent=None): super(PyMultiPageWidget, self).__init__(parent) self.comboBox = QComboBox() # MAGIC # It is important that the combo box has an object name beginning # with '__qt__passive_', otherwise, it is inactive in the form editor # of the designer and you can't change the current page via the # combo box. # MAGIC self.comboBox.setObjectName('__qt__passive_comboBox') self.stackWidget = QStackedWidget() self.comboBox.activated.connect(self.setCurrentIndex) self.layout = QVBoxLayout() self.layout.addWidget(self.comboBox) self.layout.addWidget(self.stackWidget) self.setLayout(self.layout) def sizeHint(self): return QSize(200, 150) def count(self): return self.stackWidget.count() def widget(self, index): return self.stackWidget.widget(index) @pyqtSlot(QWidget) def addPage(self, page): self.insertPage(self.count(), page) @pyqtSlot(int, QWidget) def insertPage(self, index, page): page.setParent(self.stackWidget) self.stackWidget.insertWidget(index, page) title = page.windowTitle() if title == "": title = "Page %d" % (self.comboBox.count() + 1) page.setWindowTitle(title) self.comboBox.insertItem(index, title) @pyqtSlot(int) def removePage(self, index): widget = self.stackWidget.widget(index) self.stackWidget.removeWidget(widget) self.comboBox.removeItem(index) def getPageTitle(self): return self.stackWidget.currentWidget().windowTitle() @pyqtSlot(str) def setPageTitle(self, newTitle): self.comboBox.setItemText(self.getCurrentIndex(), newTitle) self.stackWidget.currentWidget().setWindowTitle(newTitle) self.pageTitleChanged.emit(newTitle) def getCurrentIndex(self): return self.stackWidget.currentIndex() @pyqtSlot(int) def setCurrentIndex(self, index): if index != self.getCurrentIndex(): self.stackWidget.setCurrentIndex(index) self.comboBox.setCurrentIndex(index) self.currentIndexChanged.emit(index) pageTitle = pyqtProperty(str, fget=getPageTitle, fset=setPageTitle, stored=False) currentIndex = pyqtProperty(int, fget=getCurrentIndex, fset=setCurrentIndex)
class ClearHistoryDialog(QDialog): def __init__(self, parent=None): super(ClearHistoryDialog, self).__init__(parent) self.setWindowFlags(Qt.Dialog) self.setWindowTitle(tr("Clear Data")) closeWindowAction = QAction(self) closeWindowAction.setShortcuts(["Esc", "Ctrl+W", "Ctrl+Shift+Del"]) closeWindowAction.triggered.connect(self.close) self.addAction(closeWindowAction) self.layout = QVBoxLayout() self.setLayout(self.layout) label = QLabel(tr("What to clear:"), self) self.layout.addWidget(label) self.dataType = QComboBox(self) self.dataType.addItem(tr("History")) self.dataType.addItem(tr("Cookies")) self.dataType.addItem(tr("Memory Caches")) self.dataType.addItem(tr("Persistent Storage")) self.dataType.addItem(tr("Everything")) self.layout.addWidget(self.dataType) self.toolBar = QToolBar(self) self.toolBar.setStyleSheet(common.blank_toolbar) self.toolBar.setMovable(False) self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu) self.layout.addWidget(self.toolBar) self.clearHistoryButton = QPushButton(tr("Clear"), self) self.clearHistoryButton.clicked.connect(self.clearHistory) self.toolBar.addWidget(self.clearHistoryButton) self.closeButton = QPushButton(tr("Close"), self) self.closeButton.clicked.connect(self.close) self.toolBar.addWidget(self.closeButton) def display(self): self.show() self.activateWindow() def clearHistory(self): clear_everything = (self.dataType.currentIndex() == self.dataType.count()-1) if self.dataType.currentIndex() == 0 or clear_everything: data.clearHistory() if self.dataType.currentIndex() == 1 or clear_everything: data.clearCookies() if self.dataType.currentIndex() == 2 or clear_everything: QWebSettings.globalSettings().clearMemoryCaches() if self.dataType.currentIndex() == 3 or clear_everything: QWebSettings.globalSettings().setIconDatabasePath("") QWebSettings.globalSettings().setLocalStoragePath("") QWebSettings.globalSettings().setOfflineStoragePath("") QWebSettings.globalSettings().setOfflineWebApplicationCachePath("") for subpath in ("WebpageIcons.db", "LocalStorage", "Databases",): path = os.path.abspath(os.path.join(settings.settings_folder, subpath)) if os.path.isfile(path): try: os.remove(path) except: pass elif os.path.isdir(path): if sys.platform.startswith("win"): args = ["rmdir", "/s", "/q", "\"" + path + "\""] try: os.system(" ".join(args)) except: pass else: try: subprocess.Popen(["rm", "-rf", path]) except: pass QWebSettings.globalSettings().enablePersistentStorage(settings.settings_folder)
class MeteoSettings(QDialog): applied_signal = pyqtSignal() def __init__(self, accurate_url, appid, parent=None): super(MeteoSettings, self).__init__(parent) self.layout = QVBoxLayout() self.accurate_url = accurate_url self.appid = appid self.settings = QSettings() self.set_city = self.settings.value("City") or "?" locale = QLocale.system().name() locale_long = ["pt_BR", "zh_CN", "zh_TW"] if locale not in locale_long: locale = locale[:2] self.interval_set = self.settings.value("Interval") or "30" self.temp_tray_color = self.settings.value("TrayColor") or "" # -----Cities comboBox------------------------ self.first = True self.clear_combo = False self.city_list_before = [] self.citylist = [] self.city_combo = QComboBox() if self.set_city != "?": self.add_cities_incombo() self.city_combo.currentIndexChanged.connect(self.city_default) self.city_title = QLabel(self.tr("City")) self.city_button = QPushButton() self.city_button.setIcon(QIcon(":/configure")) self.city_button.setToolTip(self.tr("Click to edit the cities list")) self.city_button.clicked.connect(self.edit_cities_list) # ------Language------------------------------ self.language_label = QLabel(self.tr("Language")) self.language_combo = QComboBox() self.language_combo.setToolTip( QCoreApplication.translate( "Tooltip", "The application has to be restared to apply the language setting", "Settings dialogue" ) ) self.language_dico = { "bg": self.tr("Bulgarian"), "ca": self.tr("Catalan"), "cs": self.tr("Czech"), "da": self.tr("Danish"), "de": self.tr("German"), "el": self.tr("Greek"), "en": self.tr("English"), "es": self.tr("Spanish"), "fi": self.tr("Finnish"), "fr": self.tr("French"), "he": self.tr("Hebrew"), "hr": self.tr("Croatian"), "hu": self.tr("Hungarian"), "it": self.tr("Italian"), "ja": self.tr("Japanese"), "lt": self.tr("Lithuanian"), "nb": self.tr("Norwegian (Bokmaal)"), "nl": self.tr("Dutch"), "pl": self.tr("Polish"), "pt": self.tr("Portuguese"), "pt_BR": self.tr("Brazil Portuguese"), "ro": self.tr("Romanian"), "ru": self.tr("Russian"), "sk": self.tr("Slovak"), "sv": self.tr("Swedish"), "tr": self.tr("Turkish"), "uk": self.tr("Ukrainian"), "zh_TW": self.tr("Chinese Traditional"), "zh_CN": self.tr("Chinese Simplified"), } lang_list = sorted(self.language_dico.values()) # English as fallback language if locale not in self.language_dico: locale = "en" self.setLanguage = self.settings.value("Language") or locale self.language_combo.addItems(lang_list) self.language_combo.setCurrentIndex(self.language_combo.findText(self.language_dico[self.setLanguage])) self.language_combo.currentIndexChanged.connect(self.language) self.lang_changed = False # Unit system self.units_changed = False self.temp_unit = self.settings.value("Unit") if self.temp_unit is None or self.temp_unit == "": self.temp_unit = "metric" self.units_changed = True self.units_label = QLabel(self.tr("Temperature unit")) self.units_combo = QComboBox() self.units_dico = {"metric": "°C", "imperial": "°F", " ": "°K"} units_list = sorted(self.units_dico.values()) self.units_combo.addItems(units_list) self.units_combo.setCurrentIndex(self.units_combo.findText(self.units_dico[self.temp_unit])) self.units_combo.currentIndexChanged.connect(self.units) # Decimal in trayicon self.temp_decimal_label = QLabel( QCoreApplication.translate( "If the temperature will be shown with a decimal or rounded in tray icon", "Temperature accuracy in system tray", "Settings dialogue", ) ) self.temp_decimal_combo = QComboBox() temp_decimal_combo_dico = {"False": "0°", "True": "0.1°"} temp_decimal_combo_list = [temp_decimal_combo_dico["False"], temp_decimal_combo_dico["True"]] self.temp_decimal_combo.addItems(temp_decimal_combo_list) temp_decimal_bool_str = self.settings.value("Decimal") or "False" self.temp_decimal_combo.setCurrentIndex( self.temp_decimal_combo.findText(temp_decimal_combo_dico[temp_decimal_bool_str]) ) self.temp_decimal_combo.currentIndexChanged.connect(self.temp_decimal) self.temp_decimal_changed = False # Interval of updates self.interval_label = QLabel(self.tr("Update interval")) self.interval_min = QLabel(self.tr("minutes")) self.interval_combo = QComboBox() self.interval_list = ["15", "30", "45", "60", "90", "120"] self.interval_combo.addItems(self.interval_list) self.interval_combo.setCurrentIndex( self.interval_combo.findText(self.interval_list[self.interval_list.index(self.interval_set)]) ) self.interval_combo.currentIndexChanged.connect(self.interval) self.interval_changed = False # OK Cancel Apply Buttons self.buttonLayout = QHBoxLayout() self.buttonLayout.addStretch() self.buttonBox = QDialogButtonBox() self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Apply | QDialogButtonBox.Cancel) self.buttonBox.setContentsMargins(0, 30, 0, 0) self.buttonLayout.addWidget(self.buttonBox) self.buttonBox.button(QDialogButtonBox.Apply).clicked.connect(self.apply_settings) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(False) # Autostart self.autostart_label = QLabel(self.tr("Launch at startup")) self.autostart_checkbox = QCheckBox() autostart_bool = self.settings.value("Autostart") or "False" autostart_bool = eval(autostart_bool) self.autostart_checkbox.setChecked(autostart_bool) self.autostart_checkbox.stateChanged.connect(self.autostart) self.autostart_changed = False # Tray temp° color self.temp_colorLabel = QLabel(self.tr("Font colour in the tray")) self.temp_colorButton = QPushButton() self.temp_colorButton.setStyleSheet("QWidget {{ background-color: {0} }}".format(self.temp_tray_color)) self.temp_colorButton.setMaximumSize(QSize(44, 24)) self.temp_colorButton.clicked.connect(self.color_chooser) self.temp_color_resetButton = QPushButton(self.tr("Reset")) self.temp_color_resetButton.setToolTip(self.tr("Reset font colour to system default")) self.temp_color_resetButton.clicked.connect(self.color_reset) # Display notifications self.notifier_label = QLabel(self.tr("Notification on weather update")) self.notifier_checkbox = QCheckBox() notifier_bool = self.settings.value("Notifications") or "True" notifier_bool = eval(notifier_bool) self.notifier_checkbox.setChecked(notifier_bool) self.notifier_checkbox.stateChanged.connect(self.notifier) self.notifier_changed = False # Icon & Temp self.tray_icon_temp_label = QLabel( QCoreApplication.translate( "Settings dialogue", "System tray icon", """Setting to choose the type of the icon on the tray (only icon, only text, icon&text""", ) ) self.tray_icon_combo = QComboBox() tray_icon_temp = QCoreApplication.translate( "Settings dialogue", "Icon & temperature", "Setting to choose the type of the icon on the tray" ) tray_icon = QCoreApplication.translate( "Settings dialogue", "Icon", "Setting to choose the type of the icon on the tray" ) tray_temp = QCoreApplication.translate( "Settings dialogue", "Temperature", "Setting to choose the type of the icon on the tray" ) self.tray_dico = {"icon&temp": tray_icon_temp, "icon": tray_icon, "temp": tray_temp} set_tray_icon = self.settings.value("TrayType") or "icon&temp" tray_icon_list = sorted(self.tray_dico.values()) self.tray_icon_combo.addItems(tray_icon_list) self.tray_icon_combo.setCurrentIndex(self.tray_icon_combo.findText(self.tray_dico[set_tray_icon])) self.tray_icon_combo.currentIndexChanged.connect(self.tray) self.tray_changed = False # Font size fontsize = self.settings.value("FontSize") or "18" self.fontsize_label = QLabel( QCoreApplication.translate( "Settings dialog", "Font size in tray", "Setting for the font size of the temperature in the tray icon" ) ) self.fontsize_spinbox = QSpinBox() self.fontsize_spinbox.setRange(12, 32) self.fontsize_spinbox.setValue(int(fontsize)) if fontsize is None or fontsize == "": self.settings.setValue("FontSize", "18") self.fontsize_changed = False self.fontsize_spinbox.valueChanged.connect(self.fontsize_change) # Proxy self.proxy_label = QLabel(QCoreApplication.translate("Checkbox", "Connection by proxy", "Settings dialogue")) self.proxy_chbox = QCheckBox() proxy_bool = self.settings.value("Proxy") or "False" self.proxy_bool = eval(proxy_bool) self.proxy_chbox.setChecked(self.proxy_bool) self.proxy_chbox.stateChanged.connect(self.proxy) self.proxy_changed = False self.proxy_button = QPushButton( QCoreApplication.translate("Label of button to open the proxy dialogue", "Settings", "Settings dialogue") ) self.proxy_button.clicked.connect(self.proxy_settings) self.proxy_button.setEnabled(self.proxy_bool) # Openweathermap key self.owmkey_label = QLabel( QCoreApplication.translate( "The key that user can generate in his OpenWeatherMap profile", "OpenWeatherMap key", "Settings dialogue", ) ) self.owmkey_create = QLabel( QCoreApplication.translate( "Link to create a profile in OpenWeatherMap", '<a href="http://home.openweathermap.org/users/sign_up">Create key</a>', "Settings dialogue", ) ) self.owmkey_create.setOpenExternalLinks(True) apikey = self.settings.value("APPID") or "" self.owmkey_text = QLineEdit() self.owmkey_text.setText(apikey) self.owmkey_text.textChanged.connect(self.apikey_changed) # ---------- self.panel = QGridLayout() self.panel.addWidget(self.city_title, 0, 0) self.panel.addWidget(self.city_combo, 0, 1) self.panel.addWidget(self.city_button, 0, 2) self.panel.addWidget(self.language_label, 1, 0) self.panel.addWidget(self.language_combo, 1, 1) self.panel.addWidget(self.units_label, 2, 0) self.panel.addWidget(self.units_combo, 2, 1) self.panel.addWidget(self.temp_decimal_label, 3, 0) self.panel.addWidget(self.temp_decimal_combo, 3, 1) self.panel.addWidget(self.interval_label, 4, 0) self.panel.addWidget(self.interval_combo, 4, 1) self.panel.addWidget(self.interval_min, 4, 2) self.panel.addWidget(self.autostart_label, 5, 0) self.panel.addWidget(self.autostart_checkbox, 5, 1) self.panel.addWidget(self.temp_colorLabel, 6, 0) self.panel.addWidget(self.temp_colorButton, 6, 1) self.panel.addWidget(self.temp_color_resetButton, 6, 2) self.panel.addWidget(self.notifier_label, 7, 0) self.panel.addWidget(self.notifier_checkbox, 7, 1) self.panel.addWidget(self.tray_icon_temp_label, 8, 0) self.panel.addWidget(self.tray_icon_combo, 8, 1) self.panel.addWidget(self.fontsize_label, 9, 0) self.panel.addWidget(self.fontsize_spinbox, 9, 1) self.panel.addWidget(self.proxy_label, 10, 0) self.panel.addWidget(self.proxy_chbox, 10, 1) self.panel.addWidget(self.proxy_button, 10, 2) self.panel.addWidget(self.owmkey_label, 11, 0) self.panel.addWidget(self.owmkey_text, 11, 1) self.panel.addWidget(self.owmkey_create, 11, 2) self.layout.addLayout(self.panel) self.layout.addLayout(self.buttonLayout) self.statusbar = QLabel() self.layout.addWidget(self.statusbar) self.nokey_message = QCoreApplication.translate( "Warning message after pressing Ok", "Please enter your OpenWeatherMap key", "Settings dialogue" ) self.nocity_message = QCoreApplication.translate( "Warning message after pressing OK", "Please add a city", "Settings dialogue" ) self.setLayout(self.layout) self.setWindowTitle(self.tr("Meteo-qt Configuration")) def units(self): self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) self.units_changed = True def language(self): self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) self.lang_changed = True def city_default(self): allitems = [self.city_combo.itemText(i) for i in range(self.city_combo.count())] city_name = self.city_combo.currentText() citytosave = city_name.split("_") if len(citytosave) < 3: return self.id_before = citytosave[2] self.city_before = citytosave[0] self.country_before = citytosave[1] self.city_list_before = allitems[:] self.city_list_before.pop(self.city_list_before.index(city_name)) self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) def interval(self): self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) self.interval_changed = True def edit_cities_list(self): apikey = self.owmkey_text.text() apiid = "&APPID=" + apikey if apikey == "": self.statusbar.setText(self.nokey_message) return dialog = citylistdlg.CityListDlg(self.citylist, self.accurate_url, apiid, self) dialog.citieslist_signal.connect(self.cities_list) dialog.exec_() def cities_list(self, cit_list): if len(cit_list) > 0: citytosave = cit_list[0].split("_") self.id_before = citytosave[2] self.city_before = citytosave[0] self.country_before = citytosave[1] if len(cit_list) > 1: self.city_list_before = cit_list[1:] else: self.city_list_before = str("") else: self.id_before = "" self.city_before = "" self.country_before = "" self.city_list_before = [] self.clear_combo = True self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) self.first = False self.add_cities_incombo() def autostart(self, state): self.autostart_state = state self.autostart_changed = True self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) def autostart_apply(self): dir_auto = "/.config/autostart/" d_file = "meteo-qt.desktop" home = os.getenv("HOME") total_path = home + dir_auto + d_file if self.autostart_state == 2: desktop_file = [ "[Desktop Entry]\n", "Exec=meteo-qt\n", "Name=meteo-qt\n", "Type=Application\n", "Version=1.0\n", "X-LXQt-Need-Tray=true\n", ] if not os.path.exists(home + dir_auto): os.system("mkdir -p {}".format(os.path.dirname(total_path))) with open(total_path, "w") as out_file: out_file.writelines(desktop_file) self.settings.setValue("Autostart", "True") logging.debug("Write desktop file in ~/.config/autostart") elif self.autostart_state == 0: if os.path.exists(total_path): os.remove(total_path) self.settings.setValue("Autostart", "False") logging.debug("Remove desktop file from ~/.config/autostart") else: return def color_chooser(self): col = QColorDialog.getColor() if col.isValid(): self.temp_colorButton.setStyleSheet("QWidget {{ background-color: {0} }}".format(col.name())) # focus to next elem to show immediatley the colour # in the button (in some DEs) self.temp_color_resetButton.setFocus() self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) self.color_before = col.name() else: logging.debug("Invalid color:" + str(col)) def color_reset(self): self.temp_colorButton.setStyleSheet("QWidget { background-color: }") self.color_before = "" self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) def notifier(self, state): self.notifier_state = state self.notifier_changed = True self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) def notifier_apply(self): if self.notifier_state == 2: self.settings.setValue("Notifications", "True") logging.debug("Write: Notifications = True") elif self.notifier_state == 0: self.settings.setValue("Notifications", "False") logging.debug("Write: Notifications = False") def temp_decimal(self, state): self.temp_decimal_state = state self.temp_decimal_changed = True self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) def tray(self): self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) self.tray_changed = True def tray_apply(self): tray = self.tray_icon_combo.currentText() self.settings.setValue("Tray", tray) logging.debug("Write >" + "Tray >" + str(tray)) settray = [key for key, value in self.tray_dico.items() if value == tray] self.settings.setValue("TrayType", settray[0]) def fontsize_change(self, size): self.fontsize_changed = True self.fontsize_value = size self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) def fontsize_apply(self): logging.debug("Apply fontsize: " + str(self.fontsize_value)) self.settings.setValue("FontSize", str(self.fontsize_value)) def proxy(self, state): self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) if state == 2: self.proxy_bool = True self.proxy_button.setEnabled(True) else: self.proxy_bool = False self.proxy_button.setEnabled(False) def proxy_settings(self): dialog = proxydlg.Proxy(self) dialog.exec_() def apikey_changed(self): self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True) def apply_settings(self): self.accepted() def accepted(self): apikey = self.owmkey_text.text() city_name = self.city_combo.currentText() if apikey == "": self.statusbar.setText(self.nokey_message) return else: self.statusbar.setText("") self.settings.setValue("APPID", str(self.owmkey_text.text())) if city_name == "": self.statusbar.setText(self.nocity_message) return else: self.statusbar.setText("") self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(False) if hasattr(self, "id_before"): self.settings.setValue("ID", self.id_before) logging.debug("write " + "ID" + str(self.id_before)) if hasattr(self, "city_before"): self.settings.setValue("City", self.city_before) logging.debug("write " + "City" + str(self.city_before)) if hasattr(self, "country_before"): self.settings.setValue("Country", self.country_before) logging.debug("write " + "Country" + str(self.country_before)) if hasattr(self, "city_list_before"): self.settings.setValue("CityList", str(self.city_list_before)) logging.debug("write " + "CityList" + str(self.city_list_before)) if hasattr(self, "color_before"): self.settings.setValue("TrayColor", self.color_before) if self.color_before == "": self.color_before = "None" logging.debug("Write font color for temp in tray: {0}".format(self.color_before)) if self.autostart_changed: self.autostart_apply() if self.interval_changed: time = self.interval_combo.currentText() self.settings.setValue("Interval", time) logging.debug("Write " + "Interval " + str(time)) if self.lang_changed: lang = self.language_combo.currentText() setlang = [key for key, value in self.language_dico.items() if value == lang] self.settings.setValue("Language", setlang[0]) logging.debug("Write " + "Language " + str(setlang[0])) if self.units_changed: unit = self.units_combo.currentText() setUnit = [key for key, value in self.units_dico.items() if value == unit] self.settings.setValue("Unit", setUnit[0]) logging.debug("Write " + "Unit " + str(setUnit[0])) if self.temp_decimal_changed: decimal = self.temp_decimal_combo.currentText() decimal_bool_str = "False" if decimal == "0.1°": decimal_bool_str = "True" self.settings.setValue("Decimal", decimal_bool_str) logging.debug("Write: Decimal in tray icon = " + decimal_bool_str) if self.notifier_changed: self.notifier_apply() if self.tray_changed: self.tray_apply() if self.fontsize_changed: self.fontsize_apply() proxy_url = self.settings.value("Proxy_url") or "" if proxy_url == "": self.proxy_bool = False self.settings.setValue("Proxy", str(self.proxy_bool)) self.applied_signal.emit() def accept(self): self.accepted() apikey = self.owmkey_text.text() city_name = self.city_combo.currentText() if apikey == "": self.statusbar.setText(self.nokey_message) return if city_name == "": self.statusbar.setText(self.nocity_message) return QDialog.accept(self) def add_cities_incombo(self): list_cities = "" self.city_combo.clear() if self.clear_combo: return if self.first: list_cities = self.settings.value("CityList") if list_cities is not None: self.city_list_before = list_cities[:] self.citylist = [self.set_city + "_" + self.settings.value("Country") + "_" + self.settings.value("ID")] else: self.citylist = [self.city_before + "_" + self.country_before + "_" + self.id_before] list_cities = self.city_list_before[:] if list_cities is None: list_cities = [] if list_cities != "" and list_cities is not None: if type(list_cities) is str: list_cities = eval(list_cities) self.citylist = self.citylist + list_cities duplicate = [] for i in self.citylist: if i not in duplicate: duplicate.append(i) self.citylist = duplicate[:] self.city_combo.addItems(self.citylist) if len(list_cities) > 0: maxi = len(max(list_cities, key=len)) self.city_combo.setMinimumSize(maxi * 8, 23)
class CSVOptionsWindow(QWidget): def __init__(self, mainwindow): QWidget.__init__(self, mainwindow, Qt.Window) self._setupUi() self.doc = mainwindow.doc self.model = mainwindow.model.csv_options self.tableModel = CSVOptionsTableModel(self.model, self.tableView) self.model.view = self self.encodingComboBox.addItems(SUPPORTED_ENCODINGS) self.cancelButton.clicked.connect(self.hide) self.continueButton.clicked.connect(self.model.continue_import) self.targetComboBox.currentIndexChanged.connect(self.targetIndexChanged) self.layoutComboBox.currentIndexChanged.connect(self.layoutIndexChanged) self.rescanButton.clicked.connect(self.rescanClicked) def _setupUi(self): self.setWindowTitle(tr("CSV Options")) self.resize(526, 369) self.verticalLayout = QVBoxLayout(self) msg = tr( "Specify which CSV columns correspond to which transaction fields. You must also " "uncheck the \"Import\" column for lines that don\'t represent a transaction " "(header, footer, comments)." ) self.label = QLabel(msg) self.label.setWordWrap(True) self.verticalLayout.addWidget(self.label) self.gridLayout = QGridLayout() self.label_2 = QLabel(tr("Layout:")) self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1) self.layoutComboBox = QComboBox(self) self.layoutComboBox.setMinimumSize(QtCore.QSize(160, 0)) self.gridLayout.addWidget(self.layoutComboBox, 0, 1, 1, 1) self.label_4 = QLabel(tr("Delimiter:")) self.gridLayout.addWidget(self.label_4, 0, 3, 1, 1) self.fieldSeparatorEdit = QLineEdit(self) self.fieldSeparatorEdit.setMaximumSize(QtCore.QSize(30, 16777215)) self.gridLayout.addWidget(self.fieldSeparatorEdit, 0, 4, 1, 1) self.targetComboBox = QComboBox(self) self.gridLayout.addWidget(self.targetComboBox, 1, 1, 1, 1) self.label_3 = QLabel(tr("Target:")) self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1) self.encodingComboBox = QComboBox(self) self.gridLayout.addWidget(self.encodingComboBox, 1, 4, 1, 1) spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem, 2, 2, 1, 1) self.horizontalLayout_2 = QHBoxLayout() self.horizontalLayout_2.setSpacing(0) spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem1) self.rescanButton = QPushButton(tr("Rescan")) sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.rescanButton.sizePolicy().hasHeightForWidth()) self.rescanButton.setSizePolicy(sizePolicy) self.horizontalLayout_2.addWidget(self.rescanButton) self.gridLayout.addLayout(self.horizontalLayout_2, 2, 3, 1, 2) self.label_5 = QLabel(tr("Encoding:")) self.gridLayout.addWidget(self.label_5, 1, 3, 1, 1) self.verticalLayout.addLayout(self.gridLayout) self.tableView = QTableView(self) self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.setShowGrid(False) self.tableView.horizontalHeader().setHighlightSections(False) self.tableView.verticalHeader().setVisible(False) self.tableView.verticalHeader().setDefaultSectionSize(18) self.verticalLayout.addWidget(self.tableView) self.horizontalLayout = QHBoxLayout() spacerItem2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem2) self.cancelButton = QPushButton(tr("Cancel")) self.cancelButton.setShortcut("Esc") self.horizontalLayout.addWidget(self.cancelButton) self.continueButton = QPushButton(tr("Continue Import")) self.continueButton.setDefault(True) self.horizontalLayout.addWidget(self.continueButton) self.verticalLayout.addLayout(self.horizontalLayout) # --- Private def _newLayout(self): title = tr("New Layout") msg = tr("Choose a name for your new layout:") name, ok = QInputDialog.getText(self, title, msg) if ok and name: self.model.new_layout(name) def _renameLayout(self): title = tr("Rename Layout") msg = tr("Choose a name for your layout:") name, ok = QInputDialog.getText(self, title, msg) if ok and name: self.model.rename_selected_layout(name) # --- Event Handling def layoutIndexChanged(self, index): # This one is a little complicated. We want to only be able to select the layouts. If # anything else is clicked, we revert back to the old index. If the item has user data, # it means that an action has to be performed. if index < 0: return elif index < len(self.model.layout_names): layout_name = None if index == 0 else str(self.layoutComboBox.itemText(index)) self.model.select_layout(layout_name) else: self.layoutComboBox.setCurrentIndex(self.layoutComboBox.findText(self.model.layout.name)) data = str(self.layoutComboBox.itemData(index)) if data == NEW_LAYOUT: self._newLayout() elif data == RENAME_LAYOUT: self._renameLayout() elif data == DELETE_LAYOUT: self.model.delete_selected_layout() def rescanClicked(self): self.model.encoding_index = self.encodingComboBox.currentIndex() self.model.field_separator = str(self.fieldSeparatorEdit.text()) self.model.rescan() def targetIndexChanged(self, index): self.model.selected_target_index = index # --- model --> view # hide() is called from the model, but is already covered by QWidget def refresh_columns(self): self.tableModel.beginResetModel() self.tableModel.endResetModel() def refresh_columns_name(self): self.tableModel.refreshColumnsName() def refresh_layout_menu(self): self.layoutComboBox.currentIndexChanged.disconnect(self.layoutIndexChanged) self.layoutComboBox.clear() self.layoutComboBox.addItems(self.model.layout_names) self.layoutComboBox.insertSeparator(self.layoutComboBox.count()) self.layoutComboBox.addItem(tr("New Layout..."), NEW_LAYOUT) self.layoutComboBox.addItem(tr("Rename Selected Layout..."), RENAME_LAYOUT) self.layoutComboBox.addItem(tr("Delete Selected Layout"), DELETE_LAYOUT) self.layoutComboBox.setCurrentIndex(self.layoutComboBox.findText(self.model.layout.name)) self.layoutComboBox.currentIndexChanged.connect(self.layoutIndexChanged) def refresh_lines(self): self.tableModel.beginResetModel() self.tableModel.endResetModel() self.fieldSeparatorEdit.setText(self.model.field_separator) def refresh_targets(self): self.targetComboBox.currentIndexChanged.disconnect(self.targetIndexChanged) self.targetComboBox.clear() self.targetComboBox.addItems(self.model.target_account_names) self.targetComboBox.currentIndexChanged.connect(self.targetIndexChanged) def show(self): # For non-modal dialogs, show() is not enough to bring the window at the forefront, we have # to call raise() as well QWidget.show(self) self.raise_() def show_message(self, msg): title = "Warning" QMessageBox.warning(self, title, msg)
class Example(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): self.resize(800, 600) centralWidget = QWidget(self) grid = QGridLayout(centralWidget) grid.setSpacing(10) self.listOfDiscipline = QComboBox(centralWidget) grid.addWidget(self.listOfDiscipline, 0, 0, 1, 1) textIn = QLabel(centralWidget) textIn.setText('Входные компетенции') grid.addWidget(textIn, 1, 0, 1, 1) self.tableIn = QTableView(centralWidget) grid.addWidget(self.tableIn, 2, 0, 1, 1) textOut = QLabel(centralWidget) textOut.setText('Выходные компетенции') grid.addWidget(textOut, 3, 0, 1, 1) self.tableOut = QTableView(centralWidget) grid.addWidget(self.tableOut, 4, 0, 1, 1) self.setCentralWidget(centralWidget) openFile = QAction('Открыть базу данных', self) openFile.setShortcut('Ctrl+O') openFile.setStatusTip('Открыть базу данных комптенций') openFile.triggered.connect(self.MainFunc) exitWindow = QAction('Выход', self) exitWindow.setStatusTip('Завершение программы') exitWindow.triggered.connect(self.close) saveFile_one = QAction('Сохранить дисциплину', self) saveFile_one.setShortcut('Ctrl+S') saveFile_one.setStatusTip('Сохранить одну дисциплину в формате xlsx') saveFile_one.triggered.connect(self.save_one) saveFile_all = QAction('Сохранить все дисциплины', self) saveFile_all.setShortcut('Ctrl+A') saveFile_all.setStatusTip('Сохранить все дисциплины в формате xlsx') saveFile_all.triggered.connect(self.save_all) menubar = self.menuBar() fileMenu = menubar.addMenu('&Файл') fileMenu.addAction(openFile) fileSaveMenu = fileMenu.addMenu('&Дисциплины') fileSaveMenu.addAction(saveFile_one) fileSaveMenu.addAction(saveFile_all) fileMenu.addAction(fileSaveMenu.menuAction()) fileMenu.addSeparator() fileMenu.addAction(exitWindow) self.nameFileOpen = '' self.statusBar() self.setWindowTitle('Формирование компетенций') self.show() def MainFunc(self): """ Основная функция :return: """ self.nameFileOpen = self.showDialog() self.listOfDiscipline.activated[str].connect(self.comboPrint) def comboPrint(self, displ): self.formInComp(displ, self.nameFileOpen, 'table') def showDialog(self): """ Открытие базы данных :return: """ fname = QFileDialog.getOpenFileName(self, 'Открыть базу данных', '/', 'DataBase(*.sqlite)')[0] self.displ = self.listDB(fname) return fname def listDB(self, namebd): """ Получение списка таблиц базы данных :param nameDB: :return: """ cache = [] db = sqlite3.connect(namebd) cur = db.cursor() k = cur.execute('SELECT * FROM sqlite_master WHERE type = "table"') for j in k: if j[1] != 'sqlite_stat1' and j[1] != 'ОК' and j[1] != 'ОПК': cache.append(j[1]) cur.close() db.close() self.listOfDiscipline.addItems(cache) return cache def formInComp(self, displ, namebd, type): """ Формирование входящих компетенций на основе выходящих :param list, namebd: :return: """ self.cacheIn = [] self.cacheOut = [] self.cacheInDisp = [] rowIn = 0 rowOut = 0 db = sqlite3.connect(namebd) cur = db.cursor() k = cur.execute('SELECT * FROM ' + displ) for line in k: inDisp = self.procInDisp(line[6]) if str(line[0]).find('К') != -1: rowOut = rowOut + 1 self.cacheOut.append(line) if inDisp != '': self.cacheInDisp.append(inDisp) for dis in self.cacheInDisp: if dis in self.displ: k = cur.execute('SELECT * FROM ' + dis) for line in k: if (line[0] != '') and (line[0] != '\t'): self.cacheIn.append(line) rowIn = rowIn + 1 self.cacheIn.sort() self.cacheOut.sort() if type == 'table': self.createTable('out', rowOut, self.cacheOut) self.createTable('in', rowIn, self.cacheIn) else: return self.cacheIn, self.cacheOut cur.close() db.close() def procInDisp(self, disp): """ Обработка входящих дисциплин для применения в SQL запросах :param disp: :return: """ m = disp m = m.strip() m = m.replace(' ', '_') m = m.replace(' ', '') m = m.replace(' ', '') m = m.replace('-', '_') m = m.replace('.', '') m = m.replace('«', '') m = m.replace('»', '') m = m.replace(',', '') m = m.capitalize() return m def createTable(self, type_table, rows, list_of_komp): """ Создание и заполнение таблицы :param type_table: :param row: :param list_komp: :param list_desc: :return: """ if type_table == 'out': model = QStandardItemModel(rows, 2) list_horizontal = ['Код компетенции', 'Описание компетенции'] model.setHorizontalHeaderLabels(list_horizontal) self.tableOut.setModel(model) self.tableOut.setColumnWidth(0, 110) self.tableOut.setColumnWidth(1, self.tableOut.width() - 130) for row in range(rows): for column in range(2): index = model.index(row, column, QModelIndex()) model.setData(index, str(list_of_komp[row][column]).strip()) else: model = QStandardItemModel(rows, 2) list_horizontal = ['Код компетенции', 'Описание компетенции'] model.setHorizontalHeaderLabels(list_horizontal) self.tableIn.setModel(model) self.tableIn.setColumnWidth(0, 110) self.tableIn.setColumnWidth(1, self.tableIn.width() - 130) for row in range(rows): for column in range(2): index = model.index(row, column, QModelIndex()) model.setData(index, str(list_of_komp[row][column]).strip()) def save_one(self): wb = openpyxl.Workbook() ws = wb.active ws.title = str(self.listOfDiscipline.currentText())[:20] ws.append(['Входящие компетенции']) for line in self.cacheIn: ws.append([line[0].strip(), line[1].strip()]) ws.append(['Выходящие компетенции']) for line in self.cacheOut: ws.append([line[0].strip(), line[1].strip()]) wb.save(self.listOfDiscipline.currentText() + '.xlsx') def save_all(self): count_displ = self.listOfDiscipline.count() wb = openpyxl.Workbook() ws = wb.active ws.title = 'Дисциплины' ws['A1'] = 'Сохранениые дисциплины' for count in range(count_displ): ws.append([str(self.listOfDiscipline.itemText(count))]) for count in range(count_displ): inDis, outDis = self.formInComp(self.listOfDiscipline.itemText(count), self.nameFileOpen, ' ') ws = wb.create_sheet(self.listOfDiscipline.itemText(count)[:20]) ws.append(['Входящие компетенции']) for line in inDis: ws.append([line[0].strip(), line[1].strip()]) ws.append(['Выходящие компетенции']) for line in outDis: ws.append([line[0].strip(), line[1].strip()]) wb.save('Все дисциплины.xlsx')
class Interface(QWidget): """Interface widget class.""" def __init__(self, parent): super(Interface, self).__init__() self._preferences, vbox = parent, QVBoxLayout(self) self.toolbar_settings = settings.TOOLBAR_ITEMS groupBoxExplorer = QGroupBox( translations.TR_PREFERENCES_INTERFACE_EXPLORER_PANEL) group_theme = QGroupBox( translations.TR_PREFERENCES_THEME) group_hdpi = QGroupBox(translations.TR_PREFERENCES_SCREEN_RESOLUTION) # groupBoxToolbar = QGroupBox( # translations.TR_PREFERENCES_INTERFACE_TOOLBAR_CUSTOMIZATION) groupBoxLang = QGroupBox( translations.TR_PREFERENCES_INTERFACE_LANGUAGE) # Explorers vboxExplorer = QVBoxLayout(groupBoxExplorer) self._checkProjectExplorer = QCheckBox( translations.TR_PREFERENCES_SHOW_EXPLORER) self._checkSymbols = QCheckBox( translations.TR_PREFERENCES_SHOW_SYMBOLS) self._checkWebInspetor = QCheckBox( translations.TR_PREFERENCES_SHOW_WEB_INSPECTOR) self._checkFileErrors = QCheckBox( translations.TR_PREFERENCES_SHOW_FILE_ERRORS) self._checkMigrationTips = QCheckBox( translations.TR_PREFERENCES_SHOW_MIGRATION) vboxExplorer.addWidget(self._checkProjectExplorer) vboxExplorer.addWidget(self._checkSymbols) vboxExplorer.addWidget(self._checkWebInspetor) vboxExplorer.addWidget(self._checkFileErrors) vboxExplorer.addWidget(self._checkMigrationTips) # Theme vbox_theme = QVBoxLayout(group_theme) hbox = QHBoxLayout() hbox.addWidget(QLabel(translations.TR_PREFERENCES_NINJA_THEME)) self._combobox_themes = QComboBox() # self._combobox_themes.addItems(theme.available_theme_names()) self._combobox_themes.setCurrentText(settings.NINJA_SKIN) hbox.addWidget(self._combobox_themes) vbox_theme.addLayout(hbox) vbox_theme.addWidget( QLabel(translations.TR_PREFERENCES_REQUIRES_RESTART)) # HDPI hbox = QHBoxLayout(group_hdpi) self._combo_resolution = QComboBox() self._combo_resolution.addItems([ translations.TR_PREFERENCES_SCREEN_NORMAL, translations.TR_PREFERENCES_SCREEN_AUTO_HDPI, translations.TR_PREFERENCES_SCREEN_CUSTOM_HDPI ]) self._combo_resolution.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Fixed) hbox.addWidget(self._combo_resolution) self._line_custom_hdpi = QLineEdit() self._line_custom_hdpi.setPlaceholderText("1.5") hbox.addWidget(self._line_custom_hdpi) #GUI - Toolbar #vbox_toolbar = QVBoxLayout(groupBoxToolbar) #hbox_select_items = QHBoxLayout() #label_toolbar = QLabel(translations.TR_PREFERENCES_TOOLBAR_ITEMS) #label_toolbar.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) #hbox_select_items.addWidget(label_toolbar) #self._comboToolbarItems = QComboBox() #self._load_combo_data(self._comboToolbarItems) #self._btnItemAdd = QPushButton(QIcon(":img/add"), '') #self._btnItemAdd.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) #self._btnItemAdd.setIconSize(QSize(16, 16)) #self._btnItemRemove = QPushButton(QIcon(':img/delete'), '') #self._btnItemRemove.setIconSize(QSize(16, 16)) #self._btnDefaultItems = QPushButton( #translations.TR_PREFERENCES_TOOLBAR_DEFAULT) #self._btnDefaultItems.setSizePolicy(QSizePolicy.Fixed, #QSizePolicy.Fixed) #self._btnItemRemove.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) #hbox_select_items.addWidget(self._comboToolbarItems) #hbox_select_items.addWidget(self._btnItemAdd) #hbox_select_items.addWidget(self._btnItemRemove) #hbox_select_items.addWidget(self._btnDefaultItems) #vbox_toolbar.addLayout(hbox_select_items) #self._toolbar_items = QToolBar() #self._toolbar_items.setObjectName("custom") #self._toolbar_items.setToolButtonStyle(Qt.ToolButtonIconOnly) #self._load_toolbar() #vbox_toolbar.addWidget(self._toolbar_items) #vbox_toolbar.addWidget(QLabel( #translations.TR_PREFERENCES_TOOLBAR_CONFIG_HELP)) # Language vboxLanguage = QVBoxLayout(groupBoxLang) vboxLanguage.addWidget(QLabel( translations.TR_PREFERENCES_SELECT_LANGUAGE)) self._comboLang = QComboBox() self._comboLang.setEnabled(False) vboxLanguage.addWidget(self._comboLang) vboxLanguage.addWidget(QLabel( translations.TR_PREFERENCES_REQUIRES_RESTART)) # Load Languages self._load_langs() # Settings self._checkProjectExplorer.setChecked( settings.SHOW_PROJECT_EXPLORER) self._checkSymbols.setChecked(settings.SHOW_SYMBOLS_LIST) self._checkWebInspetor.setChecked(settings.SHOW_WEB_INSPECTOR) self._checkFileErrors.setChecked(settings.SHOW_ERRORS_LIST) self._checkMigrationTips.setChecked(settings.SHOW_MIGRATION_LIST) self._line_custom_hdpi.setText(settings.CUSTOM_SCREEN_RESOLUTION) index = 0 if settings.HDPI: index = 1 elif settings.CUSTOM_SCREEN_RESOLUTION: index = 2 self._combo_resolution.setCurrentIndex(index) vbox.addWidget(groupBoxExplorer) vbox.addWidget(group_theme) vbox.addWidget(group_hdpi) # vbox.addWidget(groupBoxToolbar) vbox.addWidget(groupBoxLang) vbox.addStretch(1) # Signals # self.connect(self._btnItemAdd, SIGNAL("clicked()"), # # self.toolbar_item_added) # self.connect(self._btnItemRemove, SIGNAL("clicked()"), # # self.toolbar_item_removed) # self.connect(self._btnDefaultItems, SIGNAL("clicked()"), # # self.toolbar_items_default) self._combo_resolution.currentIndexChanged.connect( self._on_resolution_changed) self._preferences.savePreferences.connect(self.save) def _on_resolution_changed(self, index): enabled = False if index == 2: enabled = True self._line_custom_hdpi.setEnabled(enabled) #def toolbar_item_added(self): #data = self._comboToolbarItems.itemData( #self._comboToolbarItems.currentIndex()) #if data not in self.toolbar_settings or data == 'separator': #selected = self.actionGroup.checkedAction() #if selected is None: #self.toolbar_settings.append(data) #else: #dataAction = selected.data() #self.toolbar_settings.insert( #self.toolbar_settings.index(dataAction) + 1, data) #self._load_toolbar() ## def toolbar_item_removed(self): #data = self._comboToolbarItems.itemData( #self._comboToolbarItems.currentIndex()) #if data in self.toolbar_settings and data != 'separator': #self.toolbar_settings.pop(self.toolbar_settings.index(data)) #self._load_toolbar() #elif data == 'separator': #self.toolbar_settings.reverse() #self.toolbar_settings.pop(self.toolbar_settings.index(data)) #self.toolbar_settings.reverse() #self._load_toolbar() ## def toolbar_items_default(self): #self.toolbar_settings = settings.TOOLBAR_ITEMS_DEFAULT #self._load_toolbar() ## def _load_combo_data(self, combo): #self.toolbar_items = { #'separator': [QIcon(':img/separator'), 'Add Separtor'], #'new-file': [QIcon(resources.IMAGES['new']), self.tr('New File')], #'new-project': [QIcon(resources.IMAGES['newProj']), #self.tr('New Project')], #'save-file': [QIcon(resources.IMAGES['save']), #self.tr('Save File')], #'save-as': [QIcon(resources.IMAGES['saveAs']), self.tr('Save As')], #'save-all': [QIcon(resources.IMAGES['saveAll']), #self.tr('Save All')], #'save-project': [QIcon(resources.IMAGES['saveAll']), #self.tr('Save Project')], #'reload-file': [QIcon(resources.IMAGES['reload-file']), #self.tr('Reload File')], #'open-file': [QIcon(resources.IMAGES['open']), #self.tr('Open File')], #'open-project': [QIcon(resources.IMAGES['openProj']), #self.tr('Open Project')], #'activate-profile': [QIcon(resources.IMAGES['activate-profile']), #self.tr('Activate Profile')], #'deactivate-profile': #[QIcon(resources.IMAGES['deactivate-profile']), #self.tr('Deactivate Profile')], #'print-file': [QIcon(resources.IMAGES['print']), #self.tr('Print File')], #'close-file': #[self.style().standardIcon(QStyle.SP_DialogCloseButton), #self.tr('Close File')], #'close-projects': #[self.style().standardIcon(QStyle.SP_DialogCloseButton), #self.tr('Close Projects')], #'undo': [QIcon(resources.IMAGES['undo']), self.tr('Undo')], #'redo': [QIcon(resources.IMAGES['redo']), self.tr('Redo')], #'cut': [QIcon(resources.IMAGES['cut']), self.tr('Cut')], #'copy': [QIcon(resources.IMAGES['copy']), self.tr('Copy')], #'paste': [QIcon(resources.IMAGES['paste']), self.tr('Paste')], #'find': [QIcon(resources.IMAGES['find']), self.tr('Find')], #'find-replace': [QIcon(resources.IMAGES['findReplace']), #self.tr('Find/Replace')], #'find-files': [QIcon(resources.IMAGES['find']), #self.tr('Find In files')], #'code-locator': [QIcon(resources.IMAGES['locator']), #self.tr('Code Locator')], #'splith': [QIcon(resources.IMAGES['splitH']), #self.tr('Split Horizontally')], #'splitv': [QIcon(resources.IMAGES['splitV']), #self.tr('Split Vertically')], #'follow-mode': [QIcon(resources.IMAGES['follow']), #self.tr('Follow Mode')], #'zoom-in': [QIcon(resources.IMAGES['zoom-in']), self.tr('Zoom In')], #'zoom-out': [QIcon(resources.IMAGES['zoom-out']), #self.tr('Zoom Out')], #'indent-more': [QIcon(resources.IMAGES['indent-more']), #self.tr('Indent More')], #'indent-less': [QIcon(resources.IMAGES['indent-less']), #self.tr('Indent Less')], #'comment': [QIcon(resources.IMAGES['comment-code']), #self.tr('Comment')], #'uncomment': [QIcon(resources.IMAGES['uncomment-code']), #self.tr('Uncomment')], #'go-to-definition': [QIcon(resources.IMAGES['go-to-definition']), #self.tr('Go To Definition')], #'insert-import': [QIcon(resources.IMAGES['insert-import']), #self.tr('Insert Import')], #'run-project': [QIcon(resources.IMAGES['play']), 'Run Project'], #'run-file': [QIcon(resources.IMAGES['file-run']), 'Run File'], #'stop': [QIcon(resources.IMAGES['stop']), 'Stop'], #'preview-web': [QIcon(resources.IMAGES['preview-web']), #self.tr('Preview Web')]} #for item in self.toolbar_items: #combo.addItem(self.toolbar_items[item][0], #self.toolbar_items[item][1], item) #combo.model().sort(0) ## def _load_toolbar(self): #pass ##self._toolbar_items.clear() ##self.actionGroup = QActionGroup(self) ##self.actionGroup.setExclusive(True) ##for item in self.toolbar_settings: ##if item == 'separator': ##self._toolbar_items.addSeparator() ##else: ##action = self._toolbar_items.addAction( ##self.toolbar_items[item][0], self.toolbar_items[item][1]) ##action.setData(item) ##action.setCheckable(True) ##self.actionGroup.addAction(action) def _load_langs(self): langs = file_manager.get_files_from_folder( resources.LANGS, '.qm') self._languages = ['English'] + \ [file_manager.get_module_name(lang) for lang in langs] self._comboLang.addItems(self._languages) if(self._comboLang.count() > 1): self._comboLang.setEnabled(True) if settings.LANGUAGE: index = self._comboLang.findText(settings.LANGUAGE) else: index = 0 self._comboLang.setCurrentIndex(index) def save(self): qsettings = IDE.ninja_settings() qsettings.beginGroup("ide") qsettings.beginGroup("interface") ninja_theme = self._combobox_themes.currentText() settings.NINJA_SKIN = ninja_theme qsettings.setValue("skin", settings.NINJA_SKIN) settings.SHOW_PROJECT_EXPLORER = self._checkProjectExplorer.isChecked() qsettings.setValue("showProjectExplorer", settings.SHOW_PROJECT_EXPLORER) settings.SHOW_SYMBOLS_LIST = self._checkSymbols.isChecked() qsettings.setValue("showSymbolsList", settings.SHOW_SYMBOLS_LIST) if self._line_custom_hdpi.isEnabled(): screen_resolution = self._line_custom_hdpi.text().strip() settings.CUSTOM_SCREEN_RESOLUTION = screen_resolution else: settings.HDPI = bool(self._combo_resolution.currentIndex()) qsettings.setValue("autoHdpi", settings.HDPI) settings.CUSTOM_SCREEN_RESOLUTION = "" qsettings.setValue("customScreenResolution", settings.CUSTOM_SCREEN_RESOLUTION) qsettings.endGroup() qsettings.endGroup()
class fullScreenEditor(QWidget): def __init__(self, index, parent=None): QWidget.__init__(self, parent) self._background = None self._index = index self._theme = findThemePath(settings.fullScreenTheme) self._themeDatas = loadThemeDatas(self._theme) self.setMouseTracking(True) self._geometries = {} # Text editor self.editor = MDEditView(self, index=index, spellcheck=settings.spellcheck, highlighting=True, dict=settings.dict) self.editor.setFrameStyle(QFrame.NoFrame) self.editor.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.editor.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.editor.installEventFilter(self) self.editor.setMouseTracking(True) self.editor.setVerticalScrollBar(myScrollBar()) self.scrollBar = self.editor.verticalScrollBar() self.scrollBar.setParent(self) # Top Panel self.topPanel = myPanel(parent=self) # self.topPanel.layout().addStretch(1) # Spell checking if enchant: self.btnSpellCheck = QPushButton(self) self.btnSpellCheck.setFlat(True) self.btnSpellCheck.setIcon(QIcon.fromTheme("tools-check-spelling")) self.btnSpellCheck.setCheckable(True) self.btnSpellCheck.setChecked(self.editor.spellcheck) self.btnSpellCheck.toggled.connect(self.editor.toggleSpellcheck) else: self.btnSpellCheck = None # Navigation Buttons self.btnPrevious = QPushButton(self) self.btnPrevious.setFlat(True) self.btnPrevious.setIcon(QIcon.fromTheme("arrow-left")) self.btnPrevious.clicked.connect(self.switchPreviousItem) self.btnNext = QPushButton(self) self.btnNext.setFlat(True) self.btnNext.setIcon(QIcon.fromTheme("arrow-right")) self.btnNext.clicked.connect(self.switchNextItem) self.btnNew = QPushButton(self) self.btnNew.setFlat(True) self.btnNew.setIcon(QIcon.fromTheme("document-new")) self.btnNew.clicked.connect(self.createNewText) # Path and New Text Buttons self.wPath = myPath(self) # Close self.btnClose = QPushButton(self) self.btnClose.setIcon(qApp.style().standardIcon(QStyle.SP_DialogCloseButton)) self.btnClose.clicked.connect(self.close) self.btnClose.setFlat(True) # Top panel Layout if self.btnSpellCheck: self.topPanel.layout().addWidget(self.btnSpellCheck) self.topPanel.layout().addSpacing(15) self.topPanel.layout().addWidget(self.btnPrevious) self.topPanel.layout().addWidget(self.btnNext) self.topPanel.layout().addWidget(self.btnNew) self.topPanel.layout().addStretch(1) self.topPanel.layout().addWidget(self.wPath) self.topPanel.layout().addStretch(1) self.topPanel.layout().addWidget(self.btnClose) self.updateTopBar() # Left Panel self._locked = False self.leftPanel = myPanel(vertical=True, parent=self) self.locker = locker(self) self.locker.lockChanged.connect(self.setLocked) self.leftPanel.layout().addWidget(self.locker) # Bottom Panel self.bottomPanel = myPanel(parent=self) self.bottomPanel.layout().addSpacing(24) self.lstThemes = QComboBox(self) self.lstThemes.setAttribute(Qt.WA_TranslucentBackground) paths = allPaths("resources/themes") for p in paths: lst = [i for i in os.listdir(p) if os.path.splitext(i)[1] == ".theme"] for t in lst: themeIni = os.path.join(p, t) name = loadThemeDatas(themeIni)["Name"] # self.lstThemes.addItem(os.path.splitext(t)[0]) self.lstThemes.addItem(name) self.lstThemes.setItemData(self.lstThemes.count()-1, os.path.splitext(t)[0]) self.lstThemes.setCurrentIndex(self.lstThemes.findData(settings.fullScreenTheme)) # self.lstThemes.setCurrentText(settings.fullScreenTheme) self.lstThemes.currentTextChanged.connect(self.setTheme) self.lstThemes.setMaximumSize(QSize(300, QFontMetrics(qApp.font()).height())) themeLabel = QLabel(self.tr("Theme:"), self) self.bottomPanel.layout().addWidget(themeLabel) self.bottomPanel.layout().addWidget(self.lstThemes) self.bottomPanel.layout().addStretch(1) self.lblProgress = QLabel(self) self.lblProgress.setMaximumSize(QSize(200, 14)) self.lblProgress.setMinimumSize(QSize(100, 14)) self.lblWC = QLabel(self) self.lblClock = myClockLabel(self) self.bottomPanel.layout().addWidget(self.lblWC) self.bottomPanel.layout().addWidget(self.lblProgress) self.bottomPanel.layout().addSpacing(15) self.bottomPanel.layout().addWidget(self.lblClock) self.updateStatusBar() self.bottomPanel.layout().addSpacing(24) # Add Widget Settings if self.btnSpellCheck: self.topPanel.addWidgetSetting(self.tr("Spellcheck"), 'top-spellcheck', (self.btnSpellCheck, )) self.topPanel.addWidgetSetting(self.tr("Navigation"), 'top-navigation', (self.btnPrevious, self.btnNext)) self.topPanel.addWidgetSetting(self.tr("New Text"), 'top-new-doc', (self.btnNew, )) self.topPanel.addWidgetSetting(self.tr("Title"), 'top-title', (self.wPath, )) self.topPanel.addSetting(self.tr("Title: Show Full Path"), 'title-show-full-path', True) self.topPanel.setSettingCallback('title-show-full-path', lambda var, val: self.updateTopBar()) self.bottomPanel.addWidgetSetting(self.tr("Theme selector"), 'bottom-theme', (self.lstThemes, themeLabel)) self.bottomPanel.addWidgetSetting(self.tr("Word count"), 'bottom-wc', (self.lblWC, )) self.bottomPanel.addWidgetSetting(self.tr("Progress"), 'bottom-progress', (self.lblProgress, )) self.bottomPanel.addSetting(self.tr("Progress: Auto Show/Hide"), 'progress-auto-show', True) self.bottomPanel.addWidgetSetting(self.tr("Clock"), 'bottom-clock', (self.lblClock, )) self.bottomPanel.addSetting(self.tr("Clock: Show Seconds"), 'clock-show-seconds', True) self.bottomPanel.setAutoHideVariable('autohide-bottom') self.topPanel.setAutoHideVariable('autohide-top') self.leftPanel.setAutoHideVariable('autohide-left') # Connection self._index.model().dataChanged.connect(self.dataChanged) # self.updateTheme() self.showFullScreen() # self.showMaximized() # self.show() def __del__(self): # print("Leaving fullScreenEditor via Destructor event", flush=True) self.showNormal() self.close() def setLocked(self, val): self._locked = val self.btnClose.setVisible(not val) def setTheme(self, themeName): themeName = self.lstThemes.currentData() settings.fullScreenTheme = themeName self._theme = findThemePath(themeName) self._themeDatas = loadThemeDatas(self._theme) self.updateTheme() def updateTheme(self): # Reinit stored geometries for hiding widgets self._geometries = {} rect = self.geometry() self._background = generateTheme(self._themeDatas, rect) setThemeEditorDatas(self.editor, self._themeDatas, self._background, rect) # Colors if self._themeDatas["Foreground/Color"] == self._themeDatas["Background/Color"] or \ self._themeDatas["Foreground/Opacity"] < 5: self._fgcolor = QColor(self._themeDatas["Text/Color"]) self._bgcolor = QColor(self._themeDatas["Background/Color"]) else: self._bgcolor = QColor(self._themeDatas["Foreground/Color"]) self._bgcolor.setAlpha(self._themeDatas["Foreground/Opacity"] * 255 / 100) self._fgcolor = QColor(self._themeDatas["Text/Color"]) if self._themeDatas["Text/Color"] == self._themeDatas["Foreground/Color"]: self._fgcolor = QColor(self._themeDatas["Background/Color"]) # ScrollBar r = self.editor.geometry() w = qApp.style().pixelMetric(QStyle.PM_ScrollBarExtent) r.setWidth(w) r.moveRight(rect.right() - rect.left()) self.scrollBar.setGeometry(r) # self.scrollBar.setVisible(False) self.hideWidget(self.scrollBar) p = self.scrollBar.palette() b = QBrush(self._background.copy(self.scrollBar.geometry())) p.setBrush(QPalette.Base, b) self.scrollBar.setPalette(p) self.scrollBar.setColor(self._bgcolor) # Left Panel r = self.locker.geometry() r.moveTopLeft(QPoint( 0, self.geometry().height() / 2 - r.height() / 2 )) self.leftPanel.setGeometry(r) self.hideWidget(self.leftPanel) self.leftPanel.setColor(self._bgcolor) # Top / Bottom Panels r = QRect(0, 0, 0, 24) r.setWidth(rect.width()) # r.moveLeft(rect.center().x() - r.width() / 2) self.topPanel.setGeometry(r) # self.topPanel.setVisible(False) self.hideWidget(self.topPanel) r.moveBottom(rect.bottom() - rect.top()) self.bottomPanel.setGeometry(r) # self.bottomPanel.setVisible(False) self.hideWidget(self.bottomPanel) self.topPanel.setColor(self._bgcolor) self.bottomPanel.setColor(self._bgcolor) # Lst theme # p = self.lstThemes.palette() p = self.palette() p.setBrush(QPalette.Button, self._bgcolor) p.setBrush(QPalette.ButtonText, self._fgcolor) p.setBrush(QPalette.WindowText, self._fgcolor) for panel in (self.bottomPanel, self.topPanel, self.leftPanel): for i in range(panel.layout().count()): item = panel.layout().itemAt(i) if item.widget(): item.widget().setPalette(p) # self.lstThemes.setPalette(p) # self.lblWC.setPalette(p) self.update() self.editor.centerCursor() def paintEvent(self, event): if self._background: painter = QPainter(self) painter.setClipRegion(event.region()) painter.drawPixmap(event.rect(), self._background, event.rect()) painter.end() def resizeEvent(self, event): self.updateTheme() def keyPressEvent(self, event): if event.key() in [Qt.Key_Escape, Qt.Key_F11] and \ not self._locked: # print("Leaving fullScreenEditor via keyPressEvent", flush=True) self.showNormal() self.close() elif (event.modifiers() & Qt.AltModifier) and \ event.key() in [Qt.Key_PageUp, Qt.Key_PageDown, Qt.Key_Left, Qt.Key_Right]: if event.key() in [Qt.Key_PageUp, Qt.Key_Left]: success = self.switchPreviousItem() if event.key() in [Qt.Key_PageDown, Qt.Key_Right]: success = self.switchNextItem() if not success: QWidget.keyPressEvent(self, event) else: QWidget.keyPressEvent(self, event) def mouseMoveEvent(self, event): r = self.geometry() for w in [self.scrollBar, self.topPanel, self.bottomPanel, self.leftPanel]: # w.setVisible(w.geometry().contains(event.pos())) if self._geometries[w].contains(event.pos()): self.showWidget(w) else: self.hideWidget(w) def hideWidget(self, widget): if widget not in self._geometries: self._geometries[widget] = widget.geometry() if hasattr(widget, "_autoHide") and not widget._autoHide: return # Hides widget in the bottom right corner widget.move(self.geometry().bottomRight() + QPoint(1, 1)) def showWidget(self, widget): if widget in self._geometries: widget.move(self._geometries[widget].topLeft()) def eventFilter(self, obj, event): if obj == self.editor and event.type() == QEvent.Enter: for w in [self.scrollBar, self.topPanel, self.bottomPanel, self.leftPanel]: # w.setVisible(False) self.hideWidget(w) return QWidget.eventFilter(self, obj, event) def dataChanged(self, topLeft, bottomRight): # This is called sometimes after self has been destroyed. Don't know why. if not self or not self._index: return if topLeft.row() <= self._index.row() <= bottomRight.row(): self.updateStatusBar() def updateTopBar(self): item = self._index.internalPointer() previousItem = self.previousTextItem(item) nextItem = self.nextTextItem(item) self.btnPrevious.setEnabled(previousItem is not None) self.btnNext.setEnabled(nextItem is not None) self.wPath.setItem(item) def updateStatusBar(self): if self._index: item = self._index.internalPointer() wc = item.data(Outline.wordCount) goal = item.data(Outline.goal) pg = item.data(Outline.goalPercentage) if goal: if settings.fullscreenSettings.get("progress-auto-show", True): self.lblProgress.show() self.lblWC.setText(self.tr("{} words / {}").format(wc, goal)) else: if settings.fullscreenSettings.get("progress-auto-show", True): self.lblProgress.hide() self.lblWC.setText(self.tr("{} words").format(wc)) pg = 0 rect = self.lblProgress.geometry() rect = QRect(QPoint(0, 0), rect.size()) self.px = QPixmap(rect.size()) self.px.fill(Qt.transparent) p = QPainter(self.px) drawProgress(p, rect, pg, 2) p.end() self.lblProgress.setPixmap(self.px) self.locker.setWordCount(wc) # If there's a goal, then we update the locker target's number of word accordingly # (also if there is a word count, we deduce it. if goal and not self.locker.isLocked(): if wc and goal - wc > 0: self.locker.spnWordTarget.setValue(goal - wc) elif not wc: self.locker.spnWordTarget.setValue(goal) def setCurrentModelIndex(self, index): self._index = index self.editor.setCurrentModelIndex(index) self.updateTopBar() self.updateStatusBar() def switchPreviousItem(self): item = self._index.internalPointer() previousItem = self.previousTextItem(item) if previousItem: self.setCurrentModelIndex(previousItem.index()) return True return False def switchNextItem(self): item = self._index.internalPointer() nextItem = self.nextTextItem(item) if nextItem: self.setCurrentModelIndex(nextItem.index()) return True return False def switchToItem(self, item): item = self.firstTextItem(item) if item: self.setCurrentModelIndex(item.index()) def createNewText(self): item = self._index.internalPointer() newItem = outlineItem(title=qApp.translate("outlineBasics", "New"), _type=settings.defaultTextType) self._index.model().insertItem(newItem, item.row() + 1, item.parent().index()) self.setCurrentModelIndex(newItem.index()) def previousModelItem(self, item): parent = item.parent() if not parent: # Root has no sibling return None row = parent.childItems.index(item) if row > 0: return parent.child(row - 1) return self.previousModelItem(parent) def nextModelItem(self, item): parent = item.parent() if not parent: # Root has no sibling return None row = parent.childItems.index(item) if row + 1 < parent.childCount(): return parent.child(row + 1) return self.nextModelItem(parent) def previousTextItem(self, item): previous = self.previousModelItem(item) while previous: last = self.lastTextItem(previous) if last: return last previous = self.previousModelItem(previous) return None def nextTextItem(self, item): if item.isFolder() and item.childCount() > 0: next = item.child(0) else: next = self.nextModelItem(item) while next: first = self.firstTextItem(next) if first: return first next = self.nextModelItem(next) return None def firstTextItem(self, item): if item.isText(): return item for child in item.children(): first = self.firstTextItem(child) if first: return first return None def lastTextItem(self, item): if item.isText(): return item for child in reversed(item.children()): last = self.lastTextItem(child) if last: return last return None
class NBCopy(QWidget): def __init__(self, debug): super().__init__() # get all mounted drives self.drives = get_usb_drives() # set state variables self.debug = debug self.source = None self.destination = None self.initUI() def initUI(self): """Draw the UI.""" QToolTip.setFont(QFont('SansSerif', 12)) grid = QGridLayout() self.setLayout(grid) lbl_source = QLabel('Source:', self) lbl_source.setAlignment(Qt.AlignCenter) lbl_destination = QLabel('Destination:', self) lbl_destination.setAlignment(Qt.AlignCenter) self.cmb_source = QComboBox(self) self.populate_cmb_source() self.cmb_source.activated.connect(self.source_activated) self.cmb_source.setToolTip("Select either a source USB device " "or a source 'nb' backup directory") self.cmb_destination = QComboBox(self) self.populate_cmb_destination() self.cmb_destination.activated.connect(self.destination_activated) self.cmb_destination.setToolTip('Select a destination USB device') self.lbl_status = QLabel('', self) self.lbl_status.setAlignment(Qt.AlignLeft) self.btn_copy = QPushButton('Copy', self) # self.btn_copy.setFixedWidth(80) self.btn_copy.setFixedWidth(self.btn_copy.width()) self.btn_copy.clicked.connect(self.start_copy) self.btn_copy.setEnabled(False) hbox = QHBoxLayout() hbox.addWidget(self.lbl_status, Qt.AlignLeft) hbox.addStretch(1) hbox.addWidget(self.btn_copy, Qt.AlignRight) hbox.maximumSize() grid.addWidget(lbl_source, 0, 0, Qt.AlignRight) grid.addWidget(self.cmb_source, 0, 1) grid.addWidget(lbl_destination, 1, 0, Qt.AlignRight) grid.addWidget(self.cmb_destination, 1, 1) grid.addLayout(hbox, 2, 1) grid.setColumnStretch(0, 0) grid.setColumnStretch(1, 1) self.setWindowTitle('%s %s' % (ProgName, ProgVersion)) self.setMinimumWidth(MinimumWidth) self.show() self.setFixedHeight(self.height()) def populate_cmb_source(self): """Fill the source combobox with choices.""" # remove current items while self.cmb_source.count(): self.cmb_source.removeItem(0) # fill combobox with new items self.cmb_source.addItem(SelectDirString) for path in self.drives: self.cmb_source.addItem(path) for path in SourcePaths: self.cmb_source.addItem(path) def populate_cmb_destination(self): """Fill the destination combobox with choices.""" # remove current items while self.cmb_destination.count(): self.cmb_destination.removeItem(0) self.cmb_destination.addItem(SelectDestDrive) for path in self.drives: self.cmb_destination.addItem(path) def source_activated(self): """User chooses source device/directory.""" # get source path from combobox source = self.cmb_source.currentText() if source == SelectDirString: # user wants to source from a directory, choose with a file dialog dirname = QFileDialog.getExistingDirectory(self, 'Select a source directory:', osp.expanduser('~'), QFileDialog.ShowDirsOnly) self.source = dirname if dirname not in SourcePaths: SourcePaths.append(dirname) self.populate_cmb_source() index = self.cmb_source.findText(dirname, Qt.MatchFixedString) if index >= 0: self.cmb_source.setCurrentIndex(index) else: self.source = source # check that source is good if self.source: if not self.good_source(self.source): self.warn("Path '%s' is a bad source" % self.source) self.source = None self.check_copy_disabled() def destination_activated(self): self.destination = self.cmb_destination.currentText() # check with user if destination correct if not self.good_destination(self.destination): self.warn("Path '%s' is a bad destination" % self.destination) self.destination = None index = self.cmb_destination.findText(self.destination, Qt.MatchFixedString) if index >= 0: self.cmb_destination.setCurrentIndex(index) self.check_copy_disabled() def start_copy(self): """Start the actual copy. Two threads do the formatting/copying, a control thread and a worker thread. This function starts the control thread which manages the worker thread. The control thread signals this (GUI) thread with two message types: Status Finished """ # disable the 'Copy' button while doing this self.btn_copy.setEnabled(False) # start the thread to do the work self.threadCopy = CopyThread(log, self.source, self.destination) self.threadCopy.copy_done.connect(self.copy_thread_finished) self.threadCopy.status.connect(self.copy_thread_status) self.threadCopy.start() log('Copy thread started') def copy_thread_status(self, status): """Receive a status signal from the copy thread.""" log('Thread.status=%s' % status) self.lbl_status.setText(status) def copy_thread_finished(self, new_destination): log("Writing '%s' into file '%s'" % (IdFileString, osp.join(new_destination, IdFile))) with open(osp.join(new_destination, IdFile), 'w') as fd: fd.write(IdFileString) self.warn("Finished copying to\n'%s'." % new_destination) # reset comboboxes for another possible copy self.cmb_source.setCurrentIndex(0) self.cmb_destination.setCurrentIndex(0) # reset source & destination ready for next try # this enables the 'Copy' button self.source = None self.destination = None self.check_copy_disabled() # clear the status display self.lbl_status.setText('') def check_copy_disabled(self): """Copy button only enabled if both src&dest defined.""" state = bool(self.source and self.destination) self.btn_copy.setEnabled(state) def good_source(self, source): """Check that a given source path is a valid source. This mainly consists of checking that the '.diskid' file exists in the root directory and gas the right contents. """ # we need the .diskid file with correct contents diskid_file = osp.join(source, IdFile) if not osp.isfile(diskid_file): log('%s is not a file!?' % diskid_file) return False with open(diskid_file, 'r') as fd: line = fd.read() if line != IdFileString: log("File %s doesn't contain '%s' but '%s'" % (diskid_file, IdFileString, line)) return False return True def good_destination(self, destination): """Check that a given destination path is a valid destination.""" return True def exec_cmd(self, cmd): """Execute command and return output and exit code.""" # args = shlex.split(cmd) # process = Popen(args, stdout=PIPE) process = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT) (output, err) = process.communicate() exit_code = process.wait() output = output.decode("utf-8") return (output, exit_code) def warn(self, msg): log(msg) QMessageBox.information(self, '%s %s' % (ProgName, ProgVersion), msg, QMessageBox.Ok, QMessageBox.Ok)
class PlayerControls(QWidget): play = pyqtSignal() pause = pyqtSignal() stop = pyqtSignal() next = pyqtSignal() previous = pyqtSignal() changeVolume = pyqtSignal(int) changeMuting = pyqtSignal(bool) changeRate = pyqtSignal(float) def __init__(self, parent=None): super(PlayerControls, self).__init__(parent) self.playerState = QMediaPlayer.StoppedState self.playerMuted = False self.playButton = QToolButton(clicked=self.playClicked) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.stopButton = QToolButton(clicked=self.stop) self.stopButton.setIcon(self.style().standardIcon(QStyle.SP_MediaStop)) self.stopButton.setEnabled(False) self.nextButton = QToolButton(clicked=self.next) self.nextButton.setIcon( self.style().standardIcon(QStyle.SP_MediaSkipForward)) self.previousButton = QToolButton(clicked=self.previous) self.previousButton.setIcon( self.style().standardIcon(QStyle.SP_MediaSkipBackward)) self.muteButton = QToolButton(clicked=self.muteClicked) self.muteButton.setIcon( self.style().standardIcon(QStyle.SP_MediaVolume)) self.volumeSlider = QSlider(Qt.Horizontal, sliderMoved=self.changeVolume) self.volumeSlider.setRange(0, 100) self.rateBox = QComboBox(activated=self.updateRate) self.rateBox.addItem("0.5x", 0.5) self.rateBox.addItem("1.0x", 1.0) self.rateBox.addItem("2.0x", 2.0) self.rateBox.setCurrentIndex(1) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.stopButton) layout.addWidget(self.previousButton) layout.addWidget(self.playButton) layout.addWidget(self.nextButton) layout.addWidget(self.muteButton) layout.addWidget(self.volumeSlider) layout.addWidget(self.rateBox) self.setLayout(layout) def state(self): return self.playerState def setState(self,state): if state != self.playerState: self.playerState = state if state == QMediaPlayer.StoppedState: self.stopButton.setEnabled(False) self.playButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPlay)) elif state == QMediaPlayer.PlayingState: self.stopButton.setEnabled(True) self.playButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPause)) elif state == QMediaPlayer.PausedState: self.stopButton.setEnabled(True) self.playButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPlay)) def volume(self): return self.volumeSlider.value() def setVolume(self, volume): self.volumeSlider.setValue(volume) def isMuted(self): return self.playerMuted def setMuted(self, muted): if muted != self.playerMuted: self.playerMuted = muted self.muteButton.setIcon( self.style().standardIcon( QStyle.SP_MediaVolumeMuted if muted else QStyle.SP_MediaVolume)) def playClicked(self): if self.playerState in (QMediaPlayer.StoppedState, QMediaPlayer.PausedState): self.play.emit() elif self.playerState == QMediaPlayer.PlayingState: self.pause.emit() def muteClicked(self): self.changeMuting.emit(not self.playerMuted) def playbackRate(self): return self.rateBox.itemData(self.rateBox.currentIndex()) def setPlaybackRate(self, rate): for i in range(self.rateBox.count()): if qFuzzyCompare(rate, self.rateBox.itemData(i)): self.rateBox.setCurrentIndex(i) return self.rateBox.addItem("%dx" % rate, rate) self.rateBox.setCurrentIndex(self.rateBox.count() - 1) def updateRate(self): self.changeRate.emit(self.playbackRate())
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 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.info('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__() 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 ProjectTreeColumn(QDialog): # Signalsnproject = dockWidget = pyqtSignal('PyQt_PyObject') undockWidget = pyqtSignal() changeTitle = pyqtSignal('PyQt_PyObject', 'QString') updateLocator = pyqtSignal() activeProjectChanged = pyqtSignal() def __init__(self, parent=None): super(ProjectTreeColumn, self).__init__(parent) vbox = QVBoxLayout(self) vbox.setSizeConstraint(QVBoxLayout.SetDefaultConstraint) vbox.setContentsMargins(0, 0, 0, 0) vbox.setSpacing(0) self._buttons = [] frame = QFrame() frame.setObjectName("actionbar") box = QVBoxLayout(frame) box.setContentsMargins(1, 1, 1, 1) box.setSpacing(0) self._combo_project = QComboBox() self._combo_project.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Fixed) self._combo_project.setSizeAdjustPolicy( QComboBox.AdjustToMinimumContentsLengthWithIcon) self._combo_project.setObjectName("combo_projects") box.addWidget(self._combo_project) vbox.addWidget(frame) self._combo_project.setContextMenuPolicy(Qt.CustomContextMenu) self._projects_area = QStackedLayout() logger.debug("This is the projects area") vbox.addLayout(self._projects_area) # Empty widget self._empty_proj = QLabel(translations.TR_NO_PROJECTS) self._empty_proj.setAlignment(Qt.AlignCenter) self._empty_proj.setAutoFillBackground(True) self._empty_proj.setBackgroundRole(QPalette.Base) self._projects_area.addWidget(self._empty_proj) self._projects_area.setCurrentWidget(self._empty_proj) self.projects = [] self._combo_project.activated.connect( self._change_current_project) self._combo_project.customContextMenuRequested[ 'const QPoint&'].connect(self.context_menu_for_root) connections = ( { "target": "main_container", "signal_name": "addToProject", "slot": self._add_file_to_project }, { "target": "main_container", "signal_name": "showFileInExplorer", "slot": self._show_file_in_explorer }, ) IDE.register_service('projects_explorer', self) IDE.register_signals('projects_explorer', connections) ExplorerContainer.register_tab(translations.TR_TAB_PROJECTS, self) # FIXME: Should have a ninja settings object that stores tree state # FIXME: Or bettter, application data object # TODO: check this: # self.connect(ide, SIGNAL("goingDown()"), # self.tree_projects.shutdown) # def close_project_signal(): # self.emit(SIGNAL("updateLocator()")) def install_tab(self): ide = IDE.get_service('ide') ui_tools.install_shortcuts(self, actions.PROJECTS_TREE_ACTIONS, ide) ide.goingDown.connect(self._on_ide_going_down) def _on_ide_going_down(self): """Save some settings before close""" if self.current_tree is None: return ds = IDE.data_settings() show_filesize = not bool(self.current_tree.isColumnHidden(1)) ds.setValue("projectsExplorer/showFileSize", show_filesize) def load_session_projects(self, projects): for project in projects: if os.path.exists(project): self._open_project_folder(project) def open_project_folder(self, folderName=None): if settings.WORKSPACE: directory = settings.WORKSPACE else: directory = os.path.expanduser("~") if folderName is None: folderName = QFileDialog.getExistingDirectory( self, translations.TR_OPEN_PROJECT_DIRECTORY, directory) logger.debug("Choosing Foldername") if folderName: if not file_manager.folder_exists(folderName): QMessageBox.information( self, translations.TR_PROJECT_NONEXIST_TITLE, translations.TR_PROJECT_NONEXIST % folderName) return logger.debug("Opening %s" % folderName) for p in self.projects: if p.project.path == folderName: QMessageBox.information( self, translations.TR_PROJECT_PATH_ALREADY_EXIST_TITLE, translations.TR_PROJECT_PATH_ALREADY_EXIST % folderName) return self._open_project_folder(folderName) def _open_project_folder(self, folderName): ninjaide = IDE.get_service("ide") # TODO: handle exception when .nja file is empty project = NProject(folderName) qfsm = ninjaide.filesystem.open_project(project) if qfsm: self.add_project(project) self.save_recent_projects(folderName) # FIXME: show editor area? # main_container = IDE.get_service('main_container') # if main_container: # main_container.show_editor_area() if len(self.projects) > 1: title = "%s (%s)" % ( translations.TR_TAB_PROJECTS, len(self.projects)) else: title = translations.TR_TAB_PROJECTS self.changeTitle.emit(self, title) def _add_file_to_project(self, path): """Add the file for 'path' in the project the user choose here.""" if self._projects_area.count() > 0: path_project = [self.current_project] _add_to_project = add_to_project.AddToProject(path_project, self) _add_to_project.exec_() if not _add_to_project.path_selected: return main_container = IDE.get_service('main_container') if not main_container: return editorWidget = main_container.get_current_editor() if not editorWidget.file_path: name = QInputDialog.getText( None, translations.TR_ADD_FILE_TO_PROJECT, translations.TR_FILENAME + ": ")[0] if not name: QMessageBox.information( self, translations.TR_INVALID_FILENAME, translations.TR_INVALID_FILENAME_ENTER_A_FILENAME) return else: name = file_manager.get_basename(editorWidget.file_path) new_path = file_manager.create_path( _add_to_project.path_selected, name) ide_srv = IDE.get_service("ide") old_file = ide_srv.get_or_create_nfile(path) new_file = old_file.save(editorWidget.text(), new_path) # FIXME: Make this file replace the original in the open tab else: pass # Message about no project def _show_file_in_explorer(self, path): '''Iterate through the list of available projects and show the current file in the explorer view for the first project that contains it (i.e. if the same file is included in multiple open projects, the path will be expanded for the first project only). Note: This slot is connected to the main container's "showFileInExplorer(QString)" signal.''' central = IDE.get_service('central_container') if central and not central.is_lateral_panel_visible(): return for project in self.projects: index = project.model().index(path) if index.isValid(): # This highlights the index in the tree for us project.scrollTo(index, QAbstractItemView.EnsureVisible) project.setCurrentIndex(index) break def add_project(self, project): if project not in self.projects: self._combo_project.addItem(project.name) tooltip = utils.path_with_tilde_homepath(project.path) self._combo_project.setToolTip(tooltip) index = self._combo_project.count() - 1 self._combo_project.setItemData(index, project) ptree = TreeProjectsWidget(project) self._projects_area.addWidget(ptree) ptree.closeProject['PyQt_PyObject'].connect(self._close_project) pmodel = project.model ptree.setModel(pmodel) pindex = pmodel.index(pmodel.rootPath()) ptree.setRootIndex(pindex) self.projects.append(ptree) self._projects_area.setCurrentWidget(ptree) # Can be empty widget self._combo_project.setCurrentIndex(index) # FIXME: improve? # if len(self.projects) == 1: # self._combo_project.currentIndexChanged[int].connect( # self._change_current_project) def _close_project(self, widget): """Close the project related to the tree widget.""" index = self._combo_project.currentIndex() self.projects.remove(widget) # index + 1 is necessary because the widget # with index 0 is the empty widget self._projects_area.takeAt(index + 1) self._combo_project.removeItem(index) index = self._combo_project.currentIndex() self._projects_area.setCurrentIndex(index + 1) ninjaide = IDE.get_service('ide') ninjaide.filesystem.close_project(widget.project.path) widget.deleteLater() if len(self.projects) > 1: title = "%s (%s)" % ( translations.TR_TAB_PROJECTS, len(self.projects)) else: title = translations.TR_TAB_PROJECTS self.changeTitle.emit(self, title) self.updateLocator.emit() def _change_current_project(self, index): nproject = self._combo_project.itemData(index) ninjaide = IDE.get_service("ide") projects = ninjaide.get_projects() for project in projects.values(): if project == nproject: nproject.is_current = True else: project.is_current = False self._projects_area.setCurrentIndex(index + 1) self.activeProjectChanged.emit() def close_opened_projects(self): for project in reversed(self.projects): self._close_project(project) def save_project(self): """Save all the opened files that belongs to the actual project.""" if self.current_project is not None: path = self.current_project.path main_container = IDE.get_service('main_container') if path and main_container: main_container.save_project(path) def create_new_project(self): wizard = new_project_manager.NewProjectManager(self) wizard.show() @property def current_project(self): project = None if self._projects_area.count() > 0 and self.current_tree is not None: project = self.current_tree.project return project @property def current_tree(self): tree = None widget = self._projects_area.currentWidget() if isinstance(widget, TreeProjectsWidget): tree = widget return tree def set_current_item(self, path): if self.current_project is not None: self.current_tree.set_current_item(path) def save_recent_projects(self, folder): settings = IDE.data_settings() recent_project_list = settings.value('recentProjects', {}) # if already exist on the list update the date time projectProperties = json_manager.read_ninja_project(folder) name = projectProperties.get('name', '') description = projectProperties.get('description', '') if not name: name = file_manager.get_basename(folder) if not description: description = translations.TR_NO_DESCRIPTION if folder in recent_project_list: properties = recent_project_list[folder] properties["lastopen"] = QDateTime.currentDateTime() properties["name"] = name properties["description"] = description recent_project_list[folder] = properties else: recent_project_list[folder] = { "name": name, "description": description, "isFavorite": False, "lastopen": QDateTime.currentDateTime()} # if the length of the project list it's high that 10 then delete # the most old # TODO: add the length of available projects to setting if len(recent_project_list) > MAX_RECENT_PROJECTS: del recent_project_list[self.find_most_old_open( recent_project_list)] settings.setValue('recentProjects', recent_project_list) def find_most_old_open(self, recent_project_list): listFounder = [] for recent_project_path, content in list(recent_project_list.items()): listFounder.append((recent_project_path, int( content["lastopen"].toString("yyyyMMddHHmmzzz")))) listFounder = sorted(listFounder, key=lambda date: listFounder[1], reverse=True) # sort by date last used return listFounder[0][0] def reject(self): if self.parent() is None: self.dockWidget.emit(self) def closeEvent(self, event): self.dockWidget.emit(self) event.ignore() def context_menu_for_root(self): menu = QMenu(self) if self.current_tree is None: # No projects return path = self.current_tree.project.path # Reset index self.current_tree.setCurrentIndex(QModelIndex()) action_add_file = menu.addAction(QIcon(":img/new"), translations.TR_ADD_NEW_FILE) action_add_folder = menu.addAction(QIcon( ":img/openProj"), translations.TR_ADD_NEW_FOLDER) action_create_init = menu.addAction(translations.TR_CREATE_INIT) menu.addSeparator() action_run_project = menu.addAction(translations.TR_RUN_PROJECT) action_properties = menu.addAction(translations.TR_PROJECT_PROPERTIES) action_show_file_size = menu.addAction(translations.TR_SHOW_FILESIZE) menu.addSeparator() action_close = menu.addAction(translations.TR_CLOSE_PROJECT) # Connections action_add_file.triggered.connect( lambda: self.current_tree._add_new_file(path)) action_add_folder.triggered.connect( lambda: self.current_tree._add_new_folder(path)) action_create_init.triggered.connect(self.current_tree._create_init) action_run_project.triggered.connect( self.current_tree._execute_project) action_properties.triggered.connect( self.current_tree.open_project_properties) action_close.triggered.connect(self.current_tree._close_project) action_show_file_size.triggered.connect( self.current_tree.show_filesize_info) # menu for the project for m in self.current_tree.extra_menus_by_scope['project']: if isinstance(m, QMenu): menu.addSeparator() menu.addMenu(m) # show the menu! menu.exec_(QCursor.pos())
class fullScreenEditor(QWidget): def __init__(self, index, parent=None): QWidget.__init__(self, parent) self._background = None self._index = index self._theme = findThemePath(settings.fullScreenTheme) self._themeDatas = loadThemeDatas(self._theme) self.setMouseTracking(True) self._geometries = {} # Text editor self.editor = textEditView(self, index=index, spellcheck=settings.spellcheck, highlighting=True, dict=settings.dict) self.editor.setFrameStyle(QFrame.NoFrame) self.editor.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.editor.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.editor.installEventFilter(self) self.editor.setMouseTracking(True) self.editor.setVerticalScrollBar(myScrollBar()) self.scrollBar = self.editor.verticalScrollBar() self.scrollBar.setParent(self) # Top Panel self.topPanel = myPanel(parent=self) # self.topPanel.layout().addStretch(1) # Spell checking if enchant: self.btnSpellCheck = QPushButton(self) self.btnSpellCheck.setFlat(True) self.btnSpellCheck.setIcon(QIcon.fromTheme("tools-check-spelling")) self.btnSpellCheck.setCheckable(True) self.btnSpellCheck.setChecked(self.editor.spellcheck) self.btnSpellCheck.toggled.connect(self.editor.toggleSpellcheck) self.topPanel.layout().addWidget(self.btnSpellCheck) self.topPanel.layout().addStretch(1) # Formatting self.textFormat = textFormat(self) self.topPanel.layout().addWidget(self.textFormat) self.topPanel.layout().addStretch(1) self.btnClose = QPushButton(self) self.btnClose.setIcon(qApp.style().standardIcon(QStyle.SP_DialogCloseButton)) self.btnClose.clicked.connect(self.close) self.btnClose.setFlat(True) self.topPanel.layout().addWidget(self.btnClose) # Left Panel self._locked = False self.leftPanel = myPanel(vertical=True, parent=self) self.locker = locker(self) self.locker.lockChanged.connect(self.setLocked) self.leftPanel.layout().addWidget(self.locker) # Bottom Panel self.bottomPanel = myPanel(parent=self) self.bottomPanel.layout().addSpacing(24) self.lstThemes = QComboBox(self) self.lstThemes.setAttribute(Qt.WA_TranslucentBackground) paths = allPaths("resources/themes") for p in paths: lst = [i for i in os.listdir(p) if os.path.splitext(i)[1] == ".theme"] for t in lst: themeIni = os.path.join(p, t) name = loadThemeDatas(themeIni)["Name"] # self.lstThemes.addItem(os.path.splitext(t)[0]) self.lstThemes.addItem(name) self.lstThemes.setItemData(self.lstThemes.count()-1, os.path.splitext(t)[0]) self.lstThemes.setCurrentIndex(self.lstThemes.findData(settings.fullScreenTheme)) # self.lstThemes.setCurrentText(settings.fullScreenTheme) self.lstThemes.currentTextChanged.connect(self.setTheme) self.lstThemes.setMaximumSize(QSize(300, QFontMetrics(qApp.font()).height())) self.bottomPanel.layout().addWidget(QLabel(self.tr("Theme:"), self)) self.bottomPanel.layout().addWidget(self.lstThemes) self.bottomPanel.layout().addStretch(1) self.lblProgress = QLabel(self) self.lblProgress.setMaximumSize(QSize(200, 14)) self.lblProgress.setMinimumSize(QSize(100, 14)) self.lblWC = QLabel(self) self.bottomPanel.layout().addWidget(self.lblWC) self.bottomPanel.layout().addWidget(self.lblProgress) self.updateStatusBar() self.bottomPanel.layout().addSpacing(24) # Connection self._index.model().dataChanged.connect(self.dataChanged) # self.updateTheme() self.showFullScreen() # self.showMaximized() # self.show() def setLocked(self, val): self._locked = val self.btnClose.setVisible(not val) def setTheme(self, themeName): themeName = self.lstThemes.currentData() settings.fullScreenTheme = themeName self._theme = findThemePath(themeName) self._themeDatas = loadThemeDatas(self._theme) self.updateTheme() def updateTheme(self): # Reinit stored geometries for hiding widgets self._geometries = {} rect = self.geometry() self._background = generateTheme(self._themeDatas, rect) setThemeEditorDatas(self.editor, self._themeDatas, self._background, rect) # Colors if self._themeDatas["Foreground/Color"] == self._themeDatas["Background/Color"] or \ self._themeDatas["Foreground/Opacity"] < 5: self._bgcolor = QColor(self._themeDatas["Text/Color"]) self._fgcolor = QColor(self._themeDatas["Background/Color"]) else: self._bgcolor = QColor(self._themeDatas["Foreground/Color"]) self._bgcolor.setAlpha(self._themeDatas["Foreground/Opacity"] * 255 / 100) self._fgcolor = QColor(self._themeDatas["Text/Color"]) if self._themeDatas["Text/Color"] == self._themeDatas["Foreground/Color"]: self._fgcolor = QColor(self._themeDatas["Background/Color"]) # ScrollBar r = self.editor.geometry() w = qApp.style().pixelMetric(QStyle.PM_ScrollBarExtent) r.setWidth(w) r.moveRight(rect.right() - rect.left()) self.scrollBar.setGeometry(r) # self.scrollBar.setVisible(False) self.hideWidget(self.scrollBar) p = self.scrollBar.palette() b = QBrush(self._background.copy(self.scrollBar.geometry())) p.setBrush(QPalette.Base, b) self.scrollBar.setPalette(p) self.scrollBar.setColor(self._bgcolor) # Left Panel r = self.locker.geometry() r.moveTopLeft(QPoint( 0, self.geometry().height() / 2 - r.height() / 2 )) self.leftPanel.setGeometry(r) self.hideWidget(self.leftPanel) self.leftPanel.setColor(self._bgcolor) # Top / Bottom Panels r = QRect(0, 0, 0, 24) r.setWidth(rect.width()) # r.moveLeft(rect.center().x() - r.width() / 2) self.topPanel.setGeometry(r) # self.topPanel.setVisible(False) self.hideWidget(self.topPanel) r.moveBottom(rect.bottom() - rect.top()) self.bottomPanel.setGeometry(r) # self.bottomPanel.setVisible(False) self.hideWidget(self.bottomPanel) self.topPanel.setColor(self._bgcolor) self.bottomPanel.setColor(self._bgcolor) # Lst theme # p = self.lstThemes.palette() p = self.palette() p.setBrush(QPalette.Button, self._bgcolor) p.setBrush(QPalette.ButtonText, self._fgcolor) p.setBrush(QPalette.WindowText, self._fgcolor) for panel in (self.bottomPanel, self.topPanel): for i in range(panel.layout().count()): item = panel.layout().itemAt(i) if item.widget(): item.widget().setPalette(p) # self.lstThemes.setPalette(p) # self.lblWC.setPalette(p) self.update() def paintEvent(self, event): if self._background: painter = QPainter(self) painter.setClipRegion(event.region()) painter.drawPixmap(event.rect(), self._background, event.rect()) painter.end() def resizeEvent(self, event): self.updateTheme() def keyPressEvent(self, event): if event.key() in [Qt.Key_Escape, Qt.Key_F11] and \ not self._locked: self.close() else: QWidget.keyPressEvent(self, event) def mouseMoveEvent(self, event): r = self.geometry() for w in [self.scrollBar, self.topPanel, self.bottomPanel, self.leftPanel]: # w.setVisible(w.geometry().contains(event.pos())) if self._geometries[w].contains(event.pos()): self.showWidget(w) else: self.hideWidget(w) def hideWidget(self, widget): if widget not in self._geometries: self._geometries[widget] = widget.geometry() widget.move(self.geometry().bottomRight()) def showWidget(self, widget): if widget in self._geometries: widget.move(self._geometries[widget].topLeft()) def eventFilter(self, obj, event): if obj == self.editor and event.type() == QEvent.Enter: for w in [self.scrollBar, self.topPanel, self.bottomPanel, self.leftPanel]: # w.setVisible(False) self.hideWidget(w) return QWidget.eventFilter(self, obj, event) def dataChanged(self, topLeft, bottomRight): if not self._index: return if topLeft.row() <= self._index.row() <= bottomRight.row(): self.updateStatusBar() def updateStatusBar(self): if self._index: item = self._index.internalPointer() wc = item.data(Outline.wordCount.value) goal = item.data(Outline.goal.value) pg = item.data(Outline.goalPercentage.value) if goal: rect = self.lblProgress.geometry() rect = QRect(QPoint(0, 0), rect.size()) self.px = QPixmap(rect.size()) self.px.fill(Qt.transparent) p = QPainter(self.px) drawProgress(p, rect, pg, 2) p.end() self.lblProgress.setPixmap(self.px) self.lblWC.setText(self.tr("{} words / {}").format(wc, goal)) else: self.lblProgress.hide() self.lblWC.setText(self.tr("{} words").format(wc)) self.locker.setWordCount(wc) # If there's a goal, then we update the locker target's number of word accordingly # (also if there is a word count, we deduce it. if goal and not self.locker.isLocked(): if wc and goal - wc > 0: self.locker.spnWordTarget.setValue(goal - wc) elif not wc: self.locker.spnWordTarget.setValue(goal)
class MainWindow(QMainWindow): """The main GUI application.""" def __init__(self, config): """Initializer for the GUI widgets. Pass in an instance of Config class, so that it may interact with the config.""" super().__init__() self.config = config self.setWindowTitle("Livestreamer GUI v{}".format(APPVERSION)) self.setup_systray() self.setup_menu() self.setup_geometry() self.livestreamer_thread = None self.thread_exit_grace_time = 10000 # How long a thread can take to exit in milliseconds self.timestamp_format = self.config.get_config_value("timestamp-format") self.setup_control_widgets() self.update_colors() # Load all streaming-related data self.selections = {"streamer": None, "channel": None} self.load_streamers() self.load_channels(self.streamer_input.currentText()) # Do the first configuration, if the application was run for the first time self.do_init_config() # Finally show the window and the system tray icon, if it should be shown self.show() self.close_override = False self.show_hide_systray() self.check_and_do_database_migration() def do_init_config(self): do_config = self.config.get_config_value("is-configured") if do_config == 0: self.menu_cmd_configure() self.config.set_config_value("is-configured", 1) self.insertText("Using config database version '{}'".format(self.config.get_config_value("db-version"))) def setup_systray(self): if not self.config.get_config_value("enable-systray-icon"): self.systray = None return self.systray = QSystemTrayIcon(self) self.systray.activated.connect(self.systray_activated) main_menu = QMenu(self) quit_action = QAction("&Quit", self) quit_action.triggered.connect(self.on_close_override) main_menu.addAction(quit_action) self.systray.setContextMenu(main_menu) def systray_activated(self, reason): if reason == QSystemTrayIcon.Trigger: if self.isVisible(): self.hide() else: self.showNormal() def check_and_do_database_migration(self): current_version = self.config.get_config_value("db-version") if self.config.is_migration_needed(): self.insertText("Detected pending config database upgrade to version '{}'. Awaiting user input...".format(DBVERSION)) message = "You are using an older version of the application config database.\n\nWould you like to upgrade the database now? Your existing config database will be backed up." upgrade_is_mandatory = current_version < MANDATORY_DBVERSION if upgrade_is_mandatory: message = message + "\n\nWARNING: Your config database is not compatible with this version of Livestreamer GUI. UPDATE IS MANDATORY! If you cancel the update, the application will exit." reply = QMessageBox.question(self, "Pending config database upgrade", message, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if reply == QMessageBox.Yes: self.insertText("Backing up config database...") backup = self.config.make_database_backup() self.insertText("Current config database backed up to '{}'".format(backup)) self.insertText("Config database update initialized...") self.update() self.config.execute_migration() new_version = self.config.get_config_value("db-version") self.insertText("Config database update from version '{}' to '{}' finished.".format(current_version, new_version)) elif reply == QMessageBox.No and upgrade_is_mandatory: QtCore.QTimer.singleShot(500, self.on_close_override) # self.on_close_override() # Calling this in an __init__()-called method doesn't seem to work... else: self.insertText("Config database update cancelled. No changes were made.") def setup_menu(self): config_action = QAction("&Configure...", self) config_action.triggered.connect(self.menu_cmd_configure) quit_action = QAction("&Quit", self) quit_action.setShortcut("Ctrl+Q") quit_action.triggered.connect(self.on_close_override) menu = self.menuBar() file_menu = menu.addMenu("&File") file_menu.addAction(config_action) file_menu.addSeparator() file_menu.addAction(quit_action) def setup_geometry(self): width = self.config.get_config_value("root-width") height = self.config.get_config_value("root-height") topleft = QApplication.desktop().availableGeometry().topLeft() if self.config.get_config_value("remember-window-position"): xoffset = self.config.get_config_value("root-xoffset") yoffset = self.config.get_config_value("root-yoffset") topleft.setX(self.config.get_config_value("root-xoffset")) topleft.setY(self.config.get_config_value("root-yoffset")) self.resize(width, height) self.setMinimumSize(500, 300) self.move(topleft) # Center the window # center_point = QApplication.desktop().availableGeometry().center() # frame_geometry = self.frameGeometry() # frame_geometry.moveCenter(center_point) # self.move(frame_geometry.topLeft()) def setup_control_widgets(self): self.cwidget = QWidget(self) self.setCentralWidget(self.cwidget) layout = QGridLayout(self.cwidget) self.cwidget.setLayout(layout) fg_fav = self.config.get_config_value("button-foreground-favorite") fg_edit = self.config.get_config_value("button-foreground-edit") fg_add = self.config.get_config_value("button-foreground-add") fg_delete = self.config.get_config_value("button-foreground-delete") control_button_width = 30 control_button_font_style = "QPushButton { font-family: Arial, sans-serif; font-size: 16px }" column = 0 label_streamer_input = QLabel("Streamer", self.cwidget) layout.addWidget(label_streamer_input, 0, column) label_channel_input = QLabel("Channel", self.cwidget) layout.addWidget(label_channel_input, 1, column) label_quality_input = QLabel("Stream quality", self.cwidget) layout.addWidget(label_quality_input, 2, column) column += 1 self.streamer_input = QComboBox(self.cwidget) self.streamer_input.setEnabled(False) self.streamer_input.currentIndexChanged.connect(self.on_streamer_select) layout.addWidget(self.streamer_input, 0, column) self.channel_input = QComboBox(self.cwidget) self.channel_input.setEnabled(False) self.channel_input.currentIndexChanged.connect(self.on_channel_select) layout.addWidget(self.channel_input, 1, column) self.quality_input = QComboBox(self.cwidget) self.quality_input.addItem("(auto-refresh is disabled; please refresh manually)") self.quality_input.setEnabled(False) layout.addWidget(self.quality_input, 2, column) layout.setColumnStretch(column, 5) column += 1 self.fav_streamer_button = QPushButton("\u2764", self.cwidget) self.fav_streamer_button.setMaximumWidth(control_button_width) self.fav_streamer_button.setStyleSheet(":enabled {{ color: {0} }} {1}".format(fg_fav, control_button_font_style)) self.fav_streamer_button.setEnabled(False) self.fav_streamer_button.setToolTip("Set the selected streamer as your most favorite streamer") self.fav_streamer_button.clicked.connect(self.cmd_set_favorite_streamer) layout.addWidget(self.fav_streamer_button, 0, column) self.fav_channel_button = QPushButton("\u2764", self.cwidget) self.fav_channel_button.setMaximumWidth(control_button_width) self.fav_channel_button.setStyleSheet(':enabled {{ color: {0} }} {1}'.format(fg_fav, control_button_font_style)) self.fav_channel_button.setEnabled(False) self.fav_channel_button.setToolTip("Set the selected channel as your most favorite channel") self.fav_channel_button.clicked.connect(self.cmd_set_favorite_channel) layout.addWidget(self.fav_channel_button, 1, column) self.clear_quality_cache_button = QPushButton("Refresh streams", self.cwidget) self.clear_quality_cache_button.setEnabled(False) self.clear_quality_cache_button.clicked.connect(self.cmd_refresh_quality_cache) layout.addWidget(self.clear_quality_cache_button, 2, column, 1, 4) column += 1 self.edit_streamer_button = QPushButton("\u270E", self.cwidget) self.edit_streamer_button.setMaximumWidth(control_button_width) self.edit_streamer_button.setStyleSheet(":enabled {{ color: {0} }} {1}".format(fg_edit, control_button_font_style)) self.edit_streamer_button.setEnabled(False) self.edit_streamer_button.setToolTip("Edit data about the selected streamer") self.edit_streamer_button.clicked.connect(self.cmd_edit_streamer) layout.addWidget(self.edit_streamer_button, 0, column) self.edit_channel_button = QPushButton("\u270E", self.cwidget) self.edit_channel_button.setMaximumWidth(control_button_width) self.edit_channel_button.setStyleSheet(":enabled {{ color: {0} }} {1}".format(fg_edit, control_button_font_style)) self.edit_channel_button.setToolTip("Edit data about the selected channel") self.edit_channel_button.clicked.connect(self.cmd_edit_channel) layout.addWidget(self.edit_channel_button, 1, column) column += 1 self.add_streamer_button = QPushButton("\u271A", self.cwidget) self.add_streamer_button.setMaximumWidth(control_button_width) self.add_streamer_button.setStyleSheet(":enabled {{ color: {0} }} {1}".format(fg_add, control_button_font_style)) self.add_streamer_button.setEnabled(False) self.add_streamer_button.setToolTip("Add a new streamer") self.add_streamer_button.clicked.connect(self.cmd_add_streamer) layout.addWidget(self.add_streamer_button, 0, column) self.add_channel_button = QPushButton("\u271A", self.cwidget) self.add_channel_button.setMaximumWidth(control_button_width) self.add_channel_button.setStyleSheet(":enabled {{ color: {0} }} {1}".format(fg_add, control_button_font_style)) self.add_channel_button.setToolTip("Add a new channel") self.add_channel_button.clicked.connect(self.cmd_add_channel) layout.addWidget(self.add_channel_button, 1, column) column += 1 self.delete_streamer_button = QPushButton("\u2716", self.cwidget) self.delete_streamer_button.setMaximumWidth(control_button_width) self.delete_streamer_button.setStyleSheet(":enabled {{ color: {0} }} {1}".format(fg_delete, control_button_font_style)) self.delete_streamer_button.setEnabled(False) self.delete_streamer_button.setToolTip("Remove the selected streamer permanently") self.delete_streamer_button.clicked.connect(self.cmd_delete_streamer) layout.addWidget(self.delete_streamer_button, 0, column) self.delete_channel_button = QPushButton("\u2716", self.cwidget) self.delete_channel_button.setMaximumWidth(control_button_width) self.delete_channel_button.setStyleSheet(":enabled {{ color: {0} }} {1}".format(fg_delete, control_button_font_style)) self.delete_channel_button.setToolTip("Remove the selected channel permanently") self.delete_channel_button.clicked.connect(self.cmd_delete_channel) layout.addWidget(self.delete_channel_button, 1, column) # Add button for running livestreamer at the fourth row self.run_livestreamer_button = QPushButton("Run Livestreamer", self.cwidget) self.run_livestreamer_button.setEnabled(False) self.run_livestreamer_button.clicked.connect(self.run_livestreamer) layout.addWidget(self.run_livestreamer_button, 3, 0) self.log_widget = QTextEdit(self.cwidget) layout.addWidget(self.log_widget, 4, 0, 1, column+1) self.log_widget.setAcceptRichText(False) self.log_widget.setReadOnly(True) self.log_widget.setTabChangesFocus(True) def set_window_icon(self): """Sets the root window's icon, which is also shown in the taskbar.""" streamer = self.config.get_streamer(self.streamer_input.currentText()) icon = QIcon(os.path.join(IMAGESROOT, streamer["icon"])) self.setWindowIcon(icon) if self.systray is not None: self.systray.setIcon(icon) def closeEvent(self, event): """When the QWidget is closed, QCloseEvent is triggered, and this method catches and handles it.""" if not self.close_override and self.put_to_systray("close"): event.ignore() return if self.livestreamer_thread is not None and self.livestreamer_thread.keep_running: reply = QMessageBox.question(self, "Really quit Livestreamer GUI?", "Livestreamer is still running. Quitting will close it and the opened player.\n\nQuit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: # Terminate the child process, else it'll keep running even after this application is closed if self.livestreamer_thread is not None: self.livestreamer_thread.term_process() self.livestreamer_thread.wait(self.thread_exit_grace_time) self.update() event.accept() else: event.ignore() # Explicitly hide the icon, if it remains visible after the application closes if self.systray is not None: self.systray.hide() # Remember the position of the window self.remember_window_position() event.accept() def changeEvent(self, event): if type(event) is not QWindowStateChangeEvent: return # It's one of the window state change events (normal, minimize, maximize, fullscreen, active) if self.isMinimized(): self.put_to_systray("minimize") def remember_window_position(self): if self.config.get_config_value("remember-window-position"): point = self.frameGeometry().topLeft() self.config.set_config_value("root-xoffset", point.x()) self.config.set_config_value("root-yoffset", point.y()) self.insertText("Window position saved.") def show_hide_systray(self): if self.systray is None: self.setup_systray() if self.systray is None: return if self.config.get_config_value("enable-systray-icon"): self.systray.show() else: self.systray.hide() def put_to_systray(self, event): if event == "minimize": config_value = "minimize-to-systray" elif event == "close": config_value = "close-to-systray" else: return False if self.systray is not None and self.config.get_config_value(config_value) and self.isVisible(): self.hide() return True return False def menu_cmd_configure(self): streamer = self.config.get_streamer(self.streamer_input.currentText()) dialog = AppConfigDialog(self, self.config, streamer_icon=os.path.join(IMAGESROOT, streamer["icon"])) dialog.exec() if dialog.result() == QDialog.Accepted: self.show_hide_systray() self.update_colors() dialog.close() dialog = None def cmd_set_favorite_streamer(self): raise NotImplementedException() # self.fav_streamer_button.setEnabled(False) # self.config.set_favorite_streamer(self.streamer_input.setCurrentText()) # self.insertText("Favorited streamer '{}'.".format(self.streamer_input.setCurrentText())) def cmd_edit_streamer(self): raise NotImplementedException() def cmd_add_streamer(self): raise NotImplementedException() def cmd_delete_streamer(self): raise NotImplementedException() def cmd_set_favorite_channel(self): self.fav_channel_button.setEnabled(False) self.config.set_favorite_channel(self.streamer_input.currentText(), self.channel_input.currentText()) self.insertText("Favorited channel '{}'.".format(self.channel_input.currentText())) def cmd_edit_channel(self): streamer = self.config.get_streamer(self.streamer_input.currentText()) streamer_icon = os.path.join(IMAGESROOT, streamer["icon"]) channel_data = self.config.get_streamer_channel(streamer["name"], self.channel_input.currentText()) dialog = AddEditChannelsDialog(self, self.config, title="Edit the channel", streamer_icon=streamer_icon, streamer=streamer, channel_data=channel_data) dialog.exec() result = dialog.result_data dialog.close() dialog = None if result is not None: self.insertText("Updated channel name '{old_name}' => '{new_name}, URL '{old_url}' => '{new_url}'".format(old_name=channel_data["name"], new_name=result["name"], old_url=channel_data["url"], new_url=result["url"])) self.load_channels(streamer["name"]) # Set the active channel to the previously selected (due to possible name change and sorting) self.channel_input.setCurrentIndex(self.channel_input.findText(result["name"])) def cmd_add_channel(self): streamer = self.config.get_streamer(self.streamer_input.currentText()) streamer_icon = os.path.join(IMAGESROOT, streamer["icon"]) dialog = AddEditChannelsDialog(self, self.config, title="Add a channel", streamer_icon=streamer_icon, streamer=streamer) dialog.exec() result = dialog.result_data dialog.close() dialog = None if result is not None: self.insertText("Added channel '{}' with URL '{}'".format(result["name"], result["url"])) self.load_channels(streamer["name"]) def cmd_delete_channel(self): channel = self.config.get_streamer_channel(self.streamer_input.currentText(), self.channel_input.currentText()) reply = QMessageBox.question(self, "Delete channel", "Are you sure you want to remove the channel?\nName: {}\nURL: {}".format(channel["name"], channel["url"]), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self.config.delete_channel(self.streamer_input.currentText(), channel["name"]) self.insertText("Removed channel '{}' with URL '{}'".format(channel["name"], channel["url"])) self.load_channels(self.streamer_input.currentText()) def cmd_refresh_quality_cache(self): self.insertText("Refreshing cache for channel '{}'.".format(self.channel_input.currentText())) self.clear_quality_cache_button.setEnabled(False) self.clear_quality_cache_button.repaint() # Loading streams seems to block repainting of the GUI, so force a repaint here self.config.clean_quality_cache(self.streamer_input.currentText(), self.channel_input.currentText(), True) self.load_streams(True) self.clear_quality_cache_button.setEnabled(True) def on_close_override(self): self.close_override = True self.close() def on_streamer_select(self, event): # If the previously selected item is selected again, don't do anything if self.selections["streamer"] == self.streamer_input.currentText(): return self.selections["streamer"] = self.streamer_input.currentText() streamer = self.config.get_streamer(self.streamer_input.currentText()) self.set_window_icon() if streamer["favorite"]: self.fav_streamer_button.setEnabled(False) else: self.fav_streamer_button.setEnabled(True) def on_channel_select(self, event): # If the previously selected item is selected again, don't do anything if self.selections["channel"] == self.channel_input.currentText() or not self.channel_input.currentText(): return self.selections["channel"] = self.channel_input.currentText() channel = self.config.get_streamer_channel(self.streamer_input.currentText(), self.channel_input.currentText()) if channel and channel["favorite"]: self.fav_channel_button.setEnabled(False) else: self.fav_channel_button.setEnabled(True) self.load_streams() self.channel_input.setFocus(True) def load_streamers(self): streamers = self.config.get_streamers() favorite_streamer_index = 0 streamer_list = [] for index, streamer in enumerate(streamers): streamer_list.append(streamer["name"]) if streamer["favorite"]: favorite_streamer_index = index self.streamer_input.clear() self.streamer_input.addItems(streamer_list) if len(streamer_list) != 0: self.streamer_input.setCurrentIndex(favorite_streamer_index) self.selections["streamer"] = self.streamer_input.currentText() self.fav_streamer_button.setEnabled(False) def load_channels(self, streamer_name): channels = self.config.get_streamer_channels(streamer_name) self.channel_input.clear() favorite_channel = None channel_list = [] self.fav_channel_button.setEnabled(False) for index, channel in enumerate(channels): channel_list.append(channel["name"]) if channel["favorite"]: favorite_channel = channel["name"] self.channel_input.addItems(sorted(channel_list)) if len(channel_list) == 0: self.channel_input.addItem("(no channels exist for this streamer)") self.fav_channel_button.setEnabled(False) self.edit_channel_button.setEnabled(False) self.delete_channel_button.setEnabled(False) self.clear_quality_cache_button.setEnabled(False) self.channel_input.setEnabled(False) else: self.edit_channel_button.setEnabled(True) self.delete_channel_button.setEnabled(True) self.clear_quality_cache_button.setEnabled(True) self.channel_input.setEnabled(True) if favorite_channel is None: self.channel_input.setCurrentIndex(0) self.fav_channel_button.setEnabled(True) else: self.channel_input.setCurrentIndex(self.channel_input.findText(favorite_channel)) self.selections["channel"] = self.channel_input.currentText() def display_loaded_streams(self, streams, skip_caching=False): self.quality_input.clear() if len(streams) == 0: self.quality_input.addItem("(channel is currently not streaming)") else: self.run_livestreamer_button.setEnabled(True) self.clear_quality_cache_button.setEnabled(True) self.quality_input.addItems(sorted(streams)) self.quality_input.setCurrentIndex(0) self.quality_input.setEnabled(True) if not skip_caching: self.insertText("Cleaning any cached streams for channel '{}'...".format(self.channel_input.currentText())) self.config.clean_quality_cache(self.streamer_input.currentText(), self.channel_input.currentText()) self.insertText("Adding probed streams for channel '{}' to cache...".format(self.channel_input.currentText())) self.config.add_quality_to_cache(self.streamer_input.currentText(), self.channel_input.currentText(), streams) self.insertText("Done.") def load_streams(self, force_refresh=False): self.quality_input.clear() self.run_livestreamer_button.setEnabled(False) self.channel_input.setEnabled(False) self.quality_input.setEnabled(False) if self.channel_input.count() == 0: return streams = self.config.get_quality_from_cache(self.streamer_input.currentText(), self.channel_input.currentText()) if len(streams) > 0: self.display_loaded_streams(streams, True) self.insertText("Loaded streams for channel '{}' from cache.".format(self.channel_input.currentText())) else: self.insertText("No cached channel streams found for channel '{}'".format(self.channel_input.currentText())) if not force_refresh and self.config.get_config_value('auto-refresh-quality') == 0: self.quality_input.addItem("(auto-refresh is disabled; please refresh manually)") self.quality_input.setEnabled(False) else: stream_url = self.get_streamer_url() if stream_url is None: self.insertText("Failed to form a complete streamer URL (missing streamer/channel/stream)!") return self.probe_for_streams(stream_url) self.channel_input.setEnabled(True) def probe_for_streams(self, stream_url): self.insertText("Probing streamer's channel for live streams: {}".format(stream_url)) livestreamer = self.config.get_config_value("livestreamer-path") if livestreamer is None or livestreamer.strip() == "" or not os.path.isfile(livestreamer): self.insertText("Livestreamer path is not configured or file doesn't exist!") return command_format = self.config.get_config_value("probe-command-format") command = command_format.format(livestreamer=livestreamer, url=stream_url) self.livestreamer_thread = LivestreamerWorker(shlex.split(command)) self.livestreamer_thread.statusMessage.connect(self.parse_probed_streams, False) self.livestreamer_thread.start() self.livestreamer_thread.wait(self.thread_exit_grace_time) def parse_probed_streams(self, event): streams = [] message = event.message.lower() if "no streams found on this url" in message: self.insertText("No streams found. The channel is probably not streaming.") else: pos = message.find("available streams:") if pos == -1: return if "(best, worst)" in message: message = message.replace("(best, worst)", "(best and worst)") elif "(worst, best)" in message: message = message.replace("(worst, best)", "(worst and best)") qualities = message[pos+18:].split(",") for item in qualities: streams.append(item.strip()) left_parenthesis = item.find("(") if left_parenthesis == -1: continue if item.find("worst", left_parenthesis) >= left_parenthesis: streams.append("worst") if item.find("best", left_parenthesis) >= left_parenthesis: streams.append("best") streams.sort() self.insertText("Found {} stream(s): {}".format(len(streams), ", ".join(streams))) self.display_loaded_streams(streams) def get_streamer_url(self): streamer = self.config.get_streamer(self.streamer_input.currentText()) if streamer is None: self.insertText("No streamer selected!") return if streamer["url"] is None or streamer["url"].strip() == "": self.insertText("Invalid streamer URL!") return if self.channel_input.count() == 0: self.insertText("No channels exist!") return channel = self.config.get_streamer_channel(streamer["name"], self.channel_input.currentText()) return urljoin(streamer["url"], channel["url"]) def run_livestreamer(self): if self.livestreamer_thread is not None: if self.livestreamer_thread.isRunning(): self.insertText("Livestreamer should still be running!") return else: self.livestreamer_thread.wait(self.thread_exit_grace_time) self.livestreamer_thread = None self.update() if self.livestreamer_thread is None: livestreamer = self.config.get_config_value("livestreamer-path") if livestreamer is None or livestreamer.strip() == "" or not os.path.isfile(livestreamer): self.insertText("Livestreamer path is not configured or file doesn't exist!") return player = self.config.get_config_value("player-path") if player is None or player.strip() == "" or not os.path.isfile(player): self.insertText("Player path is not configured or file doesn't exist!") return stream_url = self.get_streamer_url() if stream_url is None: self.insertText("Failed to form a complete streamer URL (missing streamer/channel/stream)!") return command_format = self.config.get_config_value("command-format") quality = self.quality_input.currentText() if "(" in quality: quality = quality[:quality.find("(")].strip() command = command_format.format(livestreamer=livestreamer, player=player, url=stream_url, quality=quality) self.livestreamer_thread = LivestreamerWorker(shlex.split(command)) self.insertText("Starting Livestreamer thread.") self.livestreamer_thread.finished.connect(self.handle_livestreamer_thread_finished_signal) self.livestreamer_thread.statusMessage.connect(self.handle_livestreamer_thread_message_signal) self.livestreamer_thread.start() @QtCore.pyqtSlot(object) def handle_livestreamer_thread_message_signal(self, event): self.insertText(event.message, event.add_newline, event.add_timestamp) def handle_livestreamer_thread_finished_signal(self): self.livestreamer_thread = None def update_colors(self): foreground_color = self.config.get_config_value("foreground-color") background_color = self.config.get_config_value("background-color") self.cwidget.setStyleSheet("QWidget QLabel {{ color: {0} }} .QWidget {{ background-color: {1} }}".format(foreground_color, background_color)) self.cwidget.update() def insertText(self, msg, add_newline=True, timestamp=True): """Helper method for outputting text to the text box.""" text = "" if timestamp and self.timestamp_format is not None: timestamp = format(datetime.now().strftime(self.timestamp_format)) text = "{} ".format(timestamp) text += msg self.log_widget.moveCursor(QTextCursor.End) self.log_widget.insertPlainText(text) if add_newline: self.log_widget.insertPlainText("\n") self.log_widget.update()
class SchemeSelector(QWidget): currentChanged = pyqtSignal() changed = pyqtSignal() def __init__(self, parent=None): super(SchemeSelector, self).__init__(parent) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.label = QLabel() self.scheme = QComboBox() self.menuButton = QPushButton(flat=True) menu = QMenu(self.menuButton) self.menuButton.setMenu(menu) layout.addWidget(self.label) layout.addWidget(self.scheme) layout.addWidget(self.menuButton) layout.addStretch(1) # action generator def act(slot, icon=None): a = QAction(self, triggered=slot) self.addAction(a) icon and a.setIcon(icons.get(icon)) return a # add action a = self.addAction_ = act(self.slotAdd, 'list-add') menu.addAction(a) # remove action a = self.removeAction = act(self.slotRemove, 'list-remove') menu.addAction(a) # rename action a = self.renameAction = act(self.slotRename, 'document-edit') menu.addAction(a) menu.addSeparator() # import action a = self.importAction = act(self.slotImport, 'document-open') menu.addAction(a) # export action a = self.exportAction = act(self.slotExport, 'document-save-as') menu.addAction(a) self.scheme.currentIndexChanged.connect(self.slotSchemeChanged) app.translateUI(self) def translateUI(self): self.label.setText(_("Scheme:")) self.menuButton.setText(_("&Menu")) self.addAction_.setText(_("&Add...")) self.removeAction.setText(_("&Remove")) self.renameAction.setText(_("Re&name...")) self.importAction.setText(_("&Import...")) self.exportAction.setText(_("&Export...")) def slotSchemeChanged(self, index): """Called when the Scheme combobox is changed by the user.""" self.disableDefault(self.scheme.itemData(index) == 'default') self.currentChanged.emit() self.changed.emit() def disableDefault(self, val): self.removeAction.setDisabled(val) self.renameAction.setDisabled(val) def schemes(self): """Returns the list with internal names of currently available schemes.""" return [self.scheme.itemData(i) for i in range(self.scheme.count())] def currentScheme(self): """Returns the internal name of the currently selected scheme""" return self.scheme.itemData(self.scheme.currentIndex()) def insertSchemeItem(self, name, scheme): for i in range(1, self.scheme.count()): n = self.scheme.itemText(i) if n.lower() > name.lower(): self.scheme.insertItem(i, name, scheme) break else: self.scheme.addItem(name, scheme) def addScheme(self, name): num, key = 1, 'user1' while key in self.schemes() or key in self._schemesToRemove: num += 1 key = 'user{0}'.format(num) self.insertSchemeItem(name, key) self.scheme.setCurrentIndex(self.scheme.findData(key)) return key def slotAdd(self): name, ok = QInputDialog.getText(self, app.caption(_("Add Scheme")), _("Please enter a name for the new scheme:")) if ok: self.addScheme(name) def slotRemove(self): index = self.scheme.currentIndex() scheme = self.scheme.itemData(index) if scheme == 'default': return # default can not be removed self._schemesToRemove.add(scheme) self.scheme.removeItem(index) def slotRename(self): index = self.scheme.currentIndex() name = self.scheme.itemText(index) scheme = self.scheme.itemData(index) newName, ok = QInputDialog.getText(self, _("Rename"), _("New name:"), text=name) if ok: self.scheme.blockSignals(True) self.scheme.removeItem(index) self.insertSchemeItem(newName, scheme) self.scheme.setCurrentIndex(self.scheme.findData(scheme)) self.scheme.blockSignals(False) self.changed.emit() def slotImport(self): filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files")) caption = app.caption(_("dialog title", "Import color theme")) filename = QFileDialog.getOpenFileName(self, caption, QDir.homePath(), filetypes)[0] if filename: self.parent().import_(filename) def slotExport(self): name = self.scheme.currentText() filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files")) caption = app.caption(_("dialog title", "Export {name}").format(name=name)) path = os.path.join(QDir.homePath(), name+'.xml') filename = QFileDialog.getSaveFileName(self, caption, path, filetypes)[0] if filename: if os.path.splitext(filename)[1] != '.xml': filename += '.xml' self.parent().export(name, filename) def loadSettings(self, currentKey, namesGroup): # don't mark schemes for removal anymore self._schemesToRemove = set() s = QSettings() cur = s.value(currentKey, "default", str) # load the names for the shortcut schemes s.beginGroup(namesGroup) block = self.scheme.blockSignals(True) self.scheme.clear() self.scheme.addItem(_("Default"), "default") lst = [(s.value(key, key, str), key) for key in s.childKeys()] for name, key in sorted(lst, key=lambda f: f[0].lower()): self.scheme.addItem(name, key) # find out index index = self.scheme.findData(cur) self.disableDefault(cur == 'default') self.scheme.setCurrentIndex(index) self.scheme.blockSignals(block) self.currentChanged.emit() def saveSettings(self, currentKey, namesGroup, removePrefix=None): # first save new scheme names s = QSettings() s.beginGroup(namesGroup) for i in range(self.scheme.count()): if self.scheme.itemData(i) != 'default': s.setValue(self.scheme.itemData(i), self.scheme.itemText(i)) for scheme in self._schemesToRemove: s.remove(scheme) s.endGroup() if removePrefix: for scheme in self._schemesToRemove: s.remove("{0}/{1}".format(removePrefix, scheme)) # then save current scheme = self.currentScheme() s.setValue(currentKey, scheme) # clean up self._schemesToRemove = set()
class LoginScreen(QWidget): """ The login screen lets the user select a user profile or create a new one. """ login_successful = pyqtSignal(str, UserProfile, name="login_successful") def __init__(self, *args, **kwargs): """ Load the user profiles and create the login controls. """ super().__init__(*args, **kwargs) # Load the user profile collection. try: self.user_profile_collection = UserProfileCollection.from_dict(global_settings["users"]) except KeyError: self.user_profile_collection = UserProfileCollection() # Create and set the widget layout. layout = QVBoxLayout() layout.setAlignment(Qt.AlignCenter) self.setLayout(layout) # Fill the select-user combobox with the loaded profile names. self.select_user_combobox = QComboBox() layout.addWidget(self.select_user_combobox) self.select_user_combobox.addItem("") names = self.user_profile_collection.names() names = [(name.lower(), name) for name in names] # convert to lower case for sorting for _, name in sorted(names): self.select_user_combobox.addItem(name) # Add the login button. self.login_btn = QPushButton(text="Login", enabled=False) layout.addWidget(self.login_btn) # Add the create-user link. txt = QLabel(text="<a href='#'>Create new user</a>") layout.addWidget(txt) txt.setContextMenuPolicy(Qt.PreventContextMenu) # Connect signals and slots. This must be done after initializing all class members. self.select_user_combobox.currentIndexChanged.connect(self.on_selection_changed) self.login_btn.clicked.connect(self.on_login) txt.linkActivated.connect(self.on_show_create_user_dialog) @pyqtSlot(int, name="on_selection_changed") @log_exceptions def on_selection_changed(self, i): """ Disable the login button if no username is selected, enable it otherwise. :param i: The current selected index in the selection combobox. """ self.login_btn.setEnabled(i != 0) @pyqtSlot(name="on_login") @log_exceptions def on_login(self): """ If something is selected in the select-user combobox, the login_successful is emitted. """ if self.select_user_combobox.currentIndex() != 0: name = self.select_user_combobox.currentText() profile = self.user_profile_collection[name] self.login_successful.emit(name, profile) else: logging.warning("LoginScreen.on_login(): Tried to login without selecting a user.") @pyqtSlot(name="on_show_create_user_dialog") @log_exceptions def on_show_create_user_dialog(self): """ Show the dialog to create a new user. """ names = self.user_profile_collection.names() db_locations = self.user_profile_collection.db_locations() w = CreateUserDialog(names, db_locations, parent=self) w.setAttribute(Qt.WA_DeleteOnClose, True) w.accepted.connect(self.on_create_user) w.show() @pyqtSlot(dict, name="on_create_user") @log_exceptions def on_create_user(self, data): """ Add the user to the profile collection. """ try: name = data.pop("display_name") profile = UserProfile() for key, value in data.items(): profile[key] = value # Add the profile to the collection. self.user_profile_collection[name] = profile # Add the new name to the combobox while keeping the alphabetical order. for i in range(self.select_user_combobox.count()): if name.lower() < self.select_user_combobox.itemText(i).lower(): self.select_user_combobox.insertItem(i, name) break else: self.select_user_combobox.addItem(name) self.select_user_combobox.setCurrentText(name) # Save the created user. global_settings["users"] = self.user_profile_collection except (KeyError, IndexError, OSError) as ex: logging.warning(str(ex))
class LanguageSelectWidget(QWidget): language_changed = pyqtSignal(str) def __init__(self, lyrics_path, current_language, *args, **kwargs): super(LanguageSelectWidget, self).__init__(*args, **kwargs) self.lyrics_path = QStandardPaths.locate(QStandardPaths.AppDataLocation, lyrics_path, QStandardPaths.LocateDirectory) self.current_language = current_language layout = QVBoxLayout() layout.setSpacing(5) layout.setContentsMargins(0, 0, 0, 0) languages = [] try: for filename in os.listdir(self.lyrics_path): if filename != "timing" and os.path.isdir(os.path.join(self.lyrics_path, filename)): languages.append(filename) except FileNotFoundError: pass self.languages_combo_box = QComboBox() self.languages_combo_box.addItems(sorted(languages) + [self.tr("New Language...")]) self.languages_combo_box.currentTextChanged.connect(self._language_changed) self._select_current_language() layout.addWidget(self.languages_combo_box) self.edit_button = QPushButton(text=self.tr("Edit Language..."), clicked=self._edit_current_language) layout.addWidget(self.edit_button) self.setLayout(layout) self.import_lyrics_wizard = ImportLyricsWizard(lyrics_path, accepted=self._wizard_done, rejected=self._wizard_aborted, ) self._editing_language = False if not languages: self.import_lyrics_wizard.open() def _language_changed(self, name): if name == self.tr("New Language..."): self.import_lyrics_wizard.open() else: self.current_language = name self.language_changed.emit(name) def _wizard_done(self): languages = [self.languages_combo_box.itemText(i) for i in range(self.languages_combo_box.count() - 1)] if self._editing_language: self._editing_language = False old_index = languages.index(self.current_language) self.languages_combo_box.removeItem(old_index) languages.pop(old_index) new_language = self.import_lyrics_wizard.language print("new", new_language) languages.append(new_language) languages.sort() index = languages.index(new_language) self.languages_combo_box.insertItem(index, new_language) self.languages_combo_box.setCurrentIndex(index) def _wizard_aborted(self): self._select_current_language() def _select_current_language(self): languages = [self.languages_combo_box.itemText(i) for i in range(self.languages_combo_box.count() - 1)] if languages: self.languages_combo_box.setCurrentIndex(languages.index(self.current_language)) def _edit_current_language(self): self._editing_language = True self.import_lyrics_wizard.open() self.import_lyrics_wizard.edit_language(self.current_language)
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