class ActionsPane(QWidget): def __init__(self): super().__init__() self.group = QButtonGroup() self.group.setExclusive(False) self.scope_widget = ActionsScope() self.action_buttons = QVBoxLayout() self.big_red_button = QPushButton("Automate !!!", clicked=self.automate) self.big_red_button.setStyleSheet("QPushButton { background-color : red}") self.layout = QVBoxLayout() self.setLayout(self.layout) self.layout.addWidget(self.scope_widget) self.layout.addLayout(self.action_buttons) self.layout.addStretch() self.layout.addWidget(self.big_red_button) def registerAction(self, action): button = ActionButton(action) self.group.addButton(button.checkbox) self.action_buttons.addWidget(button) def getCheckedActions(self): return [btn.parent().action for btn in self.group.buttons() if btn.isChecked()] def automate(self, event): for action in self.getCheckedActions(): action.on_triggered()
def __init__(self, parent = None): super(StrokeStyleWidget, self).__init__(parent) self.setupUi(self) capGroup = QButtonGroup(self) capGroup.addButton(self.squareCapButton, Qt.SquareCap) capGroup.addButton(self.roundCapButton, Qt.RoundCap) capGroup.addButton(self.flatCapButton, Qt.FlatCap) capGroup.setExclusive(True) capGroup.buttonClicked[int].connect(self.capStyleChanged) joinGroup = QButtonGroup(self) joinGroup.addButton(self.roundJoinButton, Qt.RoundJoin) joinGroup.addButton(self.miterJoinButton, Qt.MiterJoin) joinGroup.addButton(self.bevelJoinButton, Qt.BevelJoin) joinGroup.setExclusive(True) joinGroup.buttonClicked[int].connect(self.joinStyleChanged) self.widthSpinner.valueChanged.connect(self.strokeWidthChanged)
class OptionsWidget(QWidget): progress = pyqtSignal(int) def __init__(self, conf, parent=None): QWidget.__init__(self, parent) self._conf = conf self._projects = [] for project in self._conf.projects: self._projects += [ProjectWidgets(project)] gLayout = QGridLayout() column = 0 for iproject in range(len(self._projects)): column += self._projects[iproject].addToLayout(column, gLayout) toolsGroup = QGroupBox('Projects && Tools') toolsGroup.setLayout(gLayout) scrollToolsGroup = QScrollArea() scrollToolsGroup.setMinimumHeight(350) #scrollToolsGroup.setVerticalScrollBarPolicy( Qt.ScrollBarAlwaysOn ) scrollToolsGroup.setWidget(toolsGroup) self._buildMode = QComboBox() self._buildMode.addItems(('Release', 'Debug')) #self._svnUpdate = QCheckBox( 'SVN Update' ) #self._svnStatus = QCheckBox( 'SVN Status' ) self._make = QCheckBox('Build') self._enableDoc = QCheckBox('Build Documentation') self._devtoolset2 = QCheckBox('Build with devtoolset 2') self._qt5 = QCheckBox('Build with Qt 5 (Qt 4 default)') self._noCache = QCheckBox('Remove previous CMake cache') self._rmBuild = QCheckBox('Cleanup Build Directory') self._verbose = QCheckBox('Display Compiler Commands') self._threads = QComboBox() for j in range(16): self._threads.addItem('-j%d' % (j + 1), j + 1) self._commandGroup = QButtonGroup() self._commandGroup.setExclusive(True) #self._commandGroup.addButton( self._svnUpdate ) #self._commandGroup.addButton( self._svnStatus ) self._commandGroup.addButton(self._make) vLayout = QVBoxLayout() #vLayout.addWidget( self._svnUpdate ) #vLayout.addWidget( self._svnStatus ) vLayout.addWidget(self._make) vLayout.addStretch() commandGroup = QGroupBox('Command') commandGroup.setLayout(vLayout) vLayout = QVBoxLayout() vLayout.addWidget(self._buildMode) vLayout.addWidget(self._enableDoc) vLayout.addWidget(self._devtoolset2) vLayout.addWidget(self._qt5) vLayout.addWidget(self._noCache) vLayout.addWidget(self._rmBuild) vLayout.addStretch() optionsGroup = QGroupBox('Command Options') optionsGroup.setLayout(vLayout) vLayout = QVBoxLayout() vLayout.addWidget(self._threads) vLayout.addWidget(self._verbose) vLayout.addStretch() miscGroup = QGroupBox('Misc. Options') miscGroup.setLayout(vLayout) hLayout = QHBoxLayout() hLayout.addWidget(commandGroup) hLayout.addWidget(optionsGroup) hLayout.addWidget(miscGroup) commands = QWidget() commands.setLayout(hLayout) vLayout = QVBoxLayout() vLayout.addWidget(commands) vLayout.addWidget(scrollToolsGroup) vLayout.addStretch() self.setLayout(vLayout) self.readSettings() return def _getProjects(self): return self._projects def _getBuildMode(self): return self._buildMode.currentText() def _getThreads(self): return self._threads.currentText() #def _getSvnUpdate ( self ): return self._svnUpdate.isChecked() #def _getSvnStatus ( self ): return self._svnStatus.isChecked() def _getMake(self): return self._make.isChecked() def _getEnableDoc(self): return self._enableDoc.isChecked() def _getDevtoolset2(self): return self._devtoolset2.isChecked() def _getQt5(self): return self._qt5.isChecked() def _getNoCache(self): return self._noCache.isChecked() def _getRmBuild(self): return self._rmBuild.isChecked() def _getVerbose(self): return self._verbose.isChecked() projects = property(_getProjects) buildMode = property(_getBuildMode) threads = property(_getThreads) #svnUpdate = property( _getSvnUpdate ) #svnStatus = property( _getSvnStatus ) make = property(_getMake) enableDoc = property(_getEnableDoc) devtoolset2 = property(_getDevtoolset2) qt5 = property(_getQt5) noCache = property(_getNoCache) rmBuild = property(_getRmBuild) verbose = property(_getVerbose) def readSettings(self): settings = QSettings() #self._svnUpdate .setChecked( settings.value('builder/svnUpdate').toBool() ) #self._svnStatus .setChecked( settings.value('builder/svnStatus').toBool() ) self._make.setChecked(settings.value('builder/make').toBool()) self._enableDoc.setChecked( settings.value('builder/enableDoc').toBool()) self._devtoolset2.setChecked( settings.value('builder/devtoolset2').toBool()) self._qt5.setChecked(settings.value('builder/qt5').toBool()) self._noCache.setChecked(settings.value('builder/noCache').toBool()) self._rmBuild.setChecked(settings.value('builder/rmBuild').toBool()) self._verbose.setChecked(settings.value('builder/verbose').toBool()) buildModeName = settings.value('builder/buildMode').toString() index = self._buildMode.findText(buildModeName) if index >= 0: self._buildMode.setCurrentIndex(index) threads = settings.value('builder/threads').toString() index = self._threads.findText(threads) if index >= 0: self._threads.setCurrentIndex(index) for project in self._projects: project.readFromSettings() return def saveSettings(self): settings = QSettings() #settings.setValue('builder/svnUpdate' , self._svnUpdate .isChecked() ) #settings.setValue('builder/svnStatus' , self._svnStatus .isChecked() ) settings.setValue('builder/make', self._make.isChecked()) settings.setValue('builder/enableDoc', self._enableDoc.isChecked()) settings.setValue('builder/devtoolset2', self._devtoolset2.isChecked()) settings.setValue('builder/qt5', self._qt5.isChecked()) settings.setValue('builder/buildMode', self._buildMode.currentText()) settings.setValue('builder/noCache', self._noCache.isChecked()) settings.setValue('builder/rmBuild', self._rmBuild.isChecked()) settings.setValue('builder/verbose', self._verbose.isChecked()) settings.setValue('builder/threads', self._threads.currentText()) for project in self._projects: project.saveToSettings() return
class QgsComposerArrowWidget(Ui_QgsComposerArrowWidgetBase): def __init__(self, parent, arrow): Ui_QgsComposerArrowWidgetBase.__init__(self, parent) self.mArrow = arrow self.mRadioButtonGroup = QButtonGroup(self) self.mRadioButtonGroup.addButton(self.mDefaultMarkerRadioButton) self.mRadioButtonGroup.addButton(self.mNoMarkerRadioButton) self.mRadioButtonGroup.addButton(self.mSvgMarkerRadioButton) self.mRadioButtonGroup.setExclusive(True) # //disable the svg related gui elements by default self.on_mSvgMarkerRadioButton_toggled(False) # //add widget for general composer item properties itemPropertiesWidget = QgsComposerItemWidget(self, self.mArrow) self.mainLayout.addWidget(itemPropertiesWidget) self.mArrowHeadOutlineColorButton.setColorDialogTitle( QString("Select arrow head outline color")) self.mArrowHeadOutlineColorButton.setAllowAlpha(True) self.mArrowHeadOutlineColorButton.setContext("composer") self.mArrowHeadOutlineColorButton.setNoColorString( QString("Transparent outline")) self.mArrowHeadOutlineColorButton.setShowNoColor(True) self.mArrowHeadFillColorButton.setColorDialogTitle( QString("Select arrow head fill color")) self.mArrowHeadFillColorButton.setAllowAlpha(True) self.mArrowHeadFillColorButton.setContext("composer") self.mArrowHeadFillColorButton.setNoColorString( QString("Transparent fill")) self.mArrowHeadFillColorButton.setShowNoColor(True) self.setGuiElementValues() if (arrow): self.connect(arrow, SIGNAL("itemChanged()"), self.setGuiElementValues) self.connect(self.mArrowHeadWidthSpinBox, SIGNAL("valueChanged(double)"), self.on_mArrowHeadWidthSpinBox_valueChanged) self.timeEnd = 0 self.timeStart = 0 def on_mOutlineWidthSpinBox_valueChanged(self, d): if (not self.mArrow): return self.mArrow.beginCommand(QString("Arrow head outline width"), QgsComposerMergeCommand.ArrowOutlineWidth) self.mArrow.setArrowHeadOutlineWidth(self.mOutlineWidthSpinBox.value()) self.mArrow.update() self.mArrow.endCommand() def on_mArrowHeadWidthSpinBox_valueChanged(self, d): if (not self.mArrow): return self.mArrow.beginCommand(QString("Arrowhead width"), QgsComposerMergeCommand.ArrowHeadWidth) self.mArrow.setArrowHeadWidth(self.mArrowHeadWidthSpinBox.value()) self.mArrow.update() self.mArrow.endCommand() def on_mArrowHeadFillColorButton_colorChanged(self, newColor): if (not self.mArrow): return self.mArrow.beginCommand(QString("Arrow head fill color")) self.mArrow.setArrowHeadFillColor(newColor) self.mArrow.update() self.mArrow.endCommand() def on_mArrowHeadOutlineColorButton_colorChanged(self, newColor): if (not self.mArrow): return self.mArrow.beginCommand(QString("Arrow head outline color")) self.mArrow.setArrowHeadOutlineColor(newColor) self.mArrow.update() self.mArrow.endCommand() def blockAllSignals(self, block): self.mLineStyleButton.blockSignals(block) self.mArrowHeadFillColorButton.blockSignals(block) self.mArrowHeadOutlineColorButton.blockSignals(block) self.mOutlineWidthSpinBox.blockSignals(block) self.mArrowHeadWidthSpinBox.blockSignals(block) self.mDefaultMarkerRadioButton.blockSignals(block) self.mNoMarkerRadioButton.blockSignals(block) self.mSvgMarkerRadioButton.blockSignals(block) self.mStartMarkerLineEdit.blockSignals(block) self.mStartMarkerToolButton.blockSignals(block) self.mEndMarkerLineEdit.blockSignals(block) self.mEndMarkerToolButton.blockSignals(block) def setGuiElementValues(self): if (not self.mArrow): return self.blockAllSignals(True) self.mArrowHeadFillColorButton.setColor( self.mArrow.arrowHeadFillColor()) self.mArrowHeadOutlineColorButton.setColor( self.mArrow.arrowHeadOutlineColor()) self.mOutlineWidthSpinBox.setValue(self.mArrow.arrowHeadOutlineWidth()) self.mArrowHeadWidthSpinBox.setValue(self.mArrow.arrowHeadWidth()) mode = self.mArrow.markerMode() if (mode == QgsComposerArrow.DefaultMarker): self.mDefaultMarkerRadioButton.setChecked(True) elif (mode == QgsComposerArrow.NoMarker): self.mNoMarkerRadioButton.setChecked(True) else: # //svg marker: self.mSvgMarkerRadioButton.setChecked(True) self.enableSvgInputElements(True) self.mStartMarkerLineEdit.setText(self.mArrow.startMarker()) self.mEndMarkerLineEdit.setText(self.mArrow.endMarker()) self.updateLineSymbolMarker() self.blockAllSignals(False) def enableSvgInputElements(self, enable): self.mStartMarkerLineEdit.setEnabled(enable) self.mStartMarkerToolButton.setEnabled(enable) self.mEndMarkerLineEdit.setEnabled(enable) self.mEndMarkerToolButton.setEnabled(enable) def on_mDefaultMarkerRadioButton_toggled(self, toggled): if (self.mArrow and toggled): self.mArrow.beginCommand(QString("Arrow marker changed")) self.mArrow.setMarkerMode(QgsComposerArrow.DefaultMarker) self.mArrow.update() self.mArrow.endCommand() def on_mNoMarkerRadioButton_toggled(self, toggled): if (self.mArrow and toggled): self.mArrow.beginCommand(QString("Arrow marker changed")) self.mArrow.setMarkerMode(QgsComposerArrow.NoMarker) self.mArrow.update() self.mArrow.endCommand() def on_mSvgMarkerRadioButton_toggled(self, toggled): self.enableSvgInputElements(toggled) if (self.mArrow and toggled): self.mArrow.beginCommand(QString("Arrow marker changed")) self.mArrow.setMarkerMode(QgsComposerArrow.SVGMarker) self.mArrow.update() self.mArrow.endCommand() def on_mStartMarkerLineEdit_textChanged(self, text): if (self.mArrow): self.mArrow.beginCommand(QString("Arrow start marker")) fi = QFileInfo(text) if (fi.exists() and fi.isFile()): self.mArrow.setStartMarker(text) else: self.mArrow.setStartMarker("") self.mArrow.update() self.mArrow.endCommand() def on_mEndMarkerLineEdit_textChanged(self, text): if (self.mArrow): self.mArrow.beginCommand(QString("Arrow end marker")) fi = QFileInfo(text) if (fi.exists() and fi.isFile()): self.mArrow.setEndMarker(text) else: self.mArrow.setEndMarker("") self.mArrow.update() self.mArrow.endCommand() def on_mStartMarkerToolButton_clicked(self): if self.timeStart != 0: self.timeEnd = time.time() print self.timeEnd if self.timeEnd - self.timeStart <= 2: self.timeStart = 0 return s = QSettings() openDir = QString() if (not self.mStartMarkerLineEdit.text().isEmpty()): fi = QFileInfo(self.mStartMarkerLineEdit.text()) openDir = fi.dir().absolutePath() if (openDir.isEmpty()): openDir = s.value("/UI/lastComposerMarkerDir", QDir.homePath()).toString() svgFileName = QFileDialog.getOpenFileName( self, QString("Start marker svg file"), openDir) if (not svgFileName.isNull()): fileInfo = QFileInfo(svgFileName) s.setValue("/UI/lastComposerMarkerDir", fileInfo.absolutePath()) self.mArrow.beginCommand(QString("Arrow start marker")) self.mStartMarkerLineEdit.setText(svgFileName) self.mArrow.endCommand() self.timeStart = time.time() def on_mEndMarkerToolButton_clicked(self): if self.timeStart != 0: self.timeEnd = time.time() print self.timeEnd if self.timeEnd - self.timeStart <= 2: self.timeStart = 0 return s = QSettings() openDir = QString() if (not self.mEndMarkerLineEdit.text().isEmpty()): fi = QFileInfo(self.mEndMarkerLineEdit.text()) openDir = fi.dir().absolutePath() if (openDir.isEmpty()): openDir = s.value("/UI/lastComposerMarkerDir", QDir.homePath()).toString() svgFileName = QFileDialog.getOpenFileName( self, QString("End marker svg file"), openDir) if (not svgFileName.isNull()): fileInfo = QFileInfo(svgFileName) s.setValue("/UI/lastComposerMarkerDir", fileInfo.absolutePath()) self.mArrow.beginCommand(QString("Arrow end marker")) self.mEndMarkerLineEdit.setText(svgFileName) self.mArrow.endCommand() self.timeStart = time.time() def on_mLineStyleButton_clicked(self): if self.timeStart != 0: self.timeEnd = time.time() print self.timeEnd if self.timeEnd - self.timeStart <= 2: self.timeStart = 0 return if (not self.mArrow): return newSymbol = self.mArrow.lineSymbol().clone() d = QgsSymbolV2SelectorDialog(newSymbol, QgsStyleV2.defaultStyle(), None, self) d.setExpressionContext(self.mArrow.createExpressionContext()) if (d.exec_() == QDialog.Accepted): self.mArrow.beginCommand(QString("Arrow line style changed")) self.mArrow.setLineSymbol(newSymbol) self.updateLineSymbolMarker() self.mArrow.endCommand() self.mArrow.update() else: pass # delete newSymbol; self.timeStart = time.time() def updateLineSymbolMarker(self): if (not self.mArrow): return icon = QgsSymbolLayerV2Utils.symbolPreviewIcon( self.mArrow.lineSymbol(), self.mLineStyleButton.iconSize()) self.mLineStyleButton.setIcon(icon)
class OptionWidget(EditorWidget): widgettype = 'Option Row' def __init__(self, *args, **kwargs): super(OptionWidget, self).__init__(*args, **kwargs) self._bindvalue = None self.group = QButtonGroup() self.group.buttonClicked.connect(self.emitvaluechanged) def createWidget(self, parent=None): widget = QWidget(parent) return widget def _buildfromlist(self, listconfig, multiselect): def chunks(l, n): """ Yield successive n-sized chunks from l. """ for i in xrange(0, len(l), n): yield l[i:i+n] items = listconfig['items'] wrap = self.config.get('wrap', 0) showcolor = self.config.get('always_color', False) if wrap > 0: rows = list(chunks(items, wrap)) else: rows = [items] for rowcount, row in enumerate(rows): for column, item in enumerate(row): parts = item.split(';') data = parts[0] try: desc = parts[1] except IndexError: desc = data button = QPushButton() button.setCheckable(multiselect) self.group.setExclusive(not multiselect) icon = QIcon() try: path = parts[2] if path.startswith("#"): # Colour the button with the hex value. # If show color is enabled we always show the color regardless of selection. print showcolor if not showcolor: style = """ QPushButton::checked {{ border: 3px solid rgb(137, 175, 255); background-color: {colour}; }}""".format(colour=path) else: style = """ QPushButton::checked {{ border: 3px solid rgb(137, 175, 255); }} QPushButton {{ background-color: {colour}; }}""".format(colour=path) button.setStyleSheet(style) elif path.endswith("_icon"): icon = QIcon(":/icons/{}".format(path)) else: icon = QIcon(path) except: icon = QIcon() button.setCheckable(True) button.setText(desc) button.setProperty("value", data) button.setIcon(icon) button.setIconSize(QSize(24, 24)) if isinstance(self.widget.layout(), QBoxLayout): self.widget.layout().addWidget(button) else: self.widget.layout().addWidget(button, rowcount, column) self.group.addButton(button) def initWidget(self, widget, config): if not widget.layout(): widget.setLayout(QGridLayout()) widget.layout().setContentsMargins(0, 0, 0, 0) def updatefromconfig(self): super(OptionWidget, self).updatefromconfig() for button in self.group.buttons(): self.group.removeButton(button) self.widget.layout().removeWidget(button) button.deleteLater() button.setParent(None) listconfig = self.config['list'] multiselect = self.config.get('multi', False) self._buildfromlist(listconfig, multiselect) super(OptionWidget, self).endupdatefromconfig() def validate(self, *args): button = self.group.checkedButton() if button: return True return False @property def buttons(self): return self.group.buttons() @property def nullvalues(self): return ['NULL'] @property def multioption(self): return self.config.get('multi', False) def setvalue(self, value): def set_button(setvalue): for button in self.group.buttons(): buttonvalue = button.property("value") if (setvalue is None and buttonvalue in self.nullvalues) or buttonvalue == str(setvalue): button.setChecked(True) self.emitvaluechanged() return if value in self.nullvalues: value = None if self.multioption and value: values = value.split(';') else: values = [value] for value in values: set_button(value) def value(self): def _returnvalue(): if self.multioption: _values = [] checked = [button for button in self.group.buttons() if button.isChecked()] for button in checked: value = button.property("value") _values.append(value) if not _values: return None return ";".join(_values) else: checked = self.group.checkedButton() if not checked: return None value = checked.property("value") return value returnvalue = _returnvalue() if returnvalue in self.nullvalues: returnvalue = None return returnvalue
class OptionWidget(EditorWidget): widgettype = 'Option Row' def __init__(self, *args): super(OptionWidget, self).__init__(*args) self._bindvalue = None self.group = QButtonGroup() self.group.setExclusive(True) self.group.buttonClicked.connect(self.emitvaluechanged) def createWidget(self, parent): widget = QWidget(parent) return widget def _buildfromlist(self, listconfig): items = listconfig['items'] for item in items: parts = item.split(';') data = parts[0] try: desc = parts[1] except IndexError: desc = data button = QPushButton() icon = QIcon() try: path = parts[2] if path.startswith("#"): # Colour the button with the hex value style = """ QPushButton:checked {{ border: 3px solid rgb(137, 175, 255); background-color: {colour}; }}""".format(colour=path) button.setStyleSheet(style) elif path.endswith("_icon"): icon = QIcon(":/icons/{}".format(path)) else: icon = QIcon(path) except: icon = QIcon() button.setCheckable(True) button.setText(desc) button.setProperty("value", data) button.setIcon(icon) button.setIconSize(QSize(24, 24)) self.widget.layout().addWidget(button) self.group.addButton(button) def initWidget(self, widget): if not widget.layout(): widget.setLayout(QHBoxLayout()) widget.layout().setContentsMargins(0, 0, 0, 0) def updatefromconfig(self): super(OptionWidget, self).updatefromconfig() for button in self.group.buttons(): self.group.removeButton(button) self.widget.layout().removeWidget(button) button.deleteLater() button.setParent(None) listconfig = self.config['list'] self._buildfromlist(listconfig) super(OptionWidget, self).endupdatefromconfig() def validate(self, *args): button = self.group.checkedButton() if button: return True return False @property def nullvalues(self): return ['NULL'] def setvalue(self, value): if value in self.nullvalues: value = None for button in self.group.buttons(): buttonvalue = button.property("value") if (value is None and buttonvalue in self.nullvalues) or buttonvalue == str(value): button.setChecked(True) self.emitvaluechanged() return def value(self): button = self.group.checkedButton() if not button: return None value = button.property("value") if value in self.nullvalues: value = None return value
class AudioVideoTab(QWidget): def __init__(self, parent): super(AudioVideoTab, self).__init__(parent) self.parent = parent self.name = "AudioVideo" self.defaultStr = self.tr("Default") self.DisableStream = self.tr("Disable") self.formats = config.video_formats frequency_values = [self.defaultStr] + config.video_frequency_values bitrate_values = [self.defaultStr] + config.video_bitrate_values rotation_options = [ self.tr("None"), "90 " + self.tr("clockwise"), "90 " + self.tr("clockwise") + " + " + self.tr("vertical flip"), "90 " + self.tr("counter clockwise"), "90 " + self.tr("counter clockwise") + " + " + self.tr("vertical flip"), "180", self.tr("horizontal flip"), self.tr("vertical flip"), ] digits_validator = QRegExpValidator(QRegExp(r"[1-9]\d*"), self) digits_validator_wzero = QRegExpValidator(QRegExp(r"\d*"), self) digits_validator_minus = QRegExpValidator(QRegExp(r"(-1|[1-9]\d*)"), self) time_validator = QRegExpValidator(QRegExp(r"\d{1,2}:\d{1,2}:\d{1,2}\.\d+"), self) converttoQL = QLabel(self.tr("Convert to:")) self.extQCB = QComboBox() self.extQCB.setMinimumWidth(100) vidcodecQL = QLabel("Video codec:") self.vidcodecQCB = QComboBox() self.vidcodecQCB.setMinimumWidth(110) audcodecQL = QLabel("Audio codec:") self.audcodecQCB = QComboBox() self.audcodecQCB.setMinimumWidth(110) hlayout1 = utils.add_to_layout( "h", converttoQL, self.extQCB, QSpacerItem(180, 20), vidcodecQL, self.vidcodecQCB, audcodecQL, self.audcodecQCB, ) commandQL = QLabel(self.tr("Command:")) self.commandQLE = QLineEdit() self.presetQPB = QPushButton(self.tr("Preset")) self.defaultQPB = QPushButton(self.defaultStr) hlayout2 = utils.add_to_layout("h", commandQL, self.commandQLE, self.presetQPB, self.defaultQPB) sizeQL = QLabel(self.tr("Video Size:")) aspectQL = QLabel(self.tr("Aspect:")) frameQL = QLabel(self.tr("Frame Rate (fps):")) bitrateQL = QLabel(self.tr("Video Bitrate (kbps):")) self.widthQLE = utils.create_LineEdit((70, 16777215), digits_validator_minus, 4) self.heightQLE = utils.create_LineEdit((70, 16777215), digits_validator_minus, 4) label = QLabel('<html><p align="center">x</p></html>') layout1 = utils.add_to_layout("h", self.widthQLE, label, self.heightQLE) self.aspect1QLE = utils.create_LineEdit((50, 16777215), digits_validator, 2) self.aspect2QLE = utils.create_LineEdit((50, 16777215), digits_validator, 2) label = QLabel('<html><p align="center">:</p></html>') layout2 = utils.add_to_layout("h", self.aspect1QLE, label, self.aspect2QLE) self.frameQLE = utils.create_LineEdit((120, 16777215), digits_validator, 4) self.bitrateQLE = utils.create_LineEdit((130, 16777215), digits_validator, 6) labels = [sizeQL, aspectQL, frameQL, bitrateQL] widgets = [layout1, layout2, self.frameQLE, self.bitrateQLE] self.preserveaspectQChB = QCheckBox(self.tr("Preserve aspect ratio")) self.preservesizeQChB = QCheckBox(self.tr("Preserve video size")) preserve_layout = utils.add_to_layout("v", self.preserveaspectQChB, self.preservesizeQChB) videosettings_layout = QHBoxLayout() for a, b in zip(labels, widgets): a.setText('<html><p align="center">{0}</p></html>'.format(a.text())) layout = utils.add_to_layout("v", a, b) videosettings_layout.addLayout(layout) if a == aspectQL: # add vidaspectCB in layout after aspectQL videosettings_layout.addLayout(preserve_layout) freqQL = QLabel(self.tr("Frequency (Hz):")) chanQL = QLabel(self.tr("Audio Channels:")) bitrateQL = QLabel(self.tr("Audio Bitrate (kbps):")) threadsQL = QLabel(self.tr("Threads:")) self.freqQCB = QComboBox() self.freqQCB.addItems(frequency_values) self.chan1QRB = QRadioButton("1") self.chan1QRB.setMaximumSize(QSize(51, 16777215)) self.chan2QRB = QRadioButton("2") self.chan2QRB.setMaximumSize(QSize(51, 16777215)) self.group = QButtonGroup() self.group.addButton(self.chan1QRB) self.group.addButton(self.chan2QRB) spcr1 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum) spcr2 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum) chanlayout = utils.add_to_layout("h", spcr1, self.chan1QRB, self.chan2QRB, spcr2) self.audbitrateQCB = QComboBox() self.audbitrateQCB.addItems(bitrate_values) self.threadsQLE = utils.create_LineEdit((50, 16777215), digits_validator_wzero, 1) labels = [freqQL, bitrateQL, chanQL, threadsQL] widgets = [self.freqQCB, self.audbitrateQCB, chanlayout, self.threadsQLE] audiosettings_layout = QHBoxLayout() for a, b in zip(labels, widgets): a.setText('<html><p align="center">{0}</p></html>'.format(a.text())) layout = utils.add_to_layout("v", a, b) audiosettings_layout.addLayout(layout) time_format = " (hh:mm:ss):" beginQL = QLabel(self.tr("Split file. Begin time") + time_format) self.beginQLE = utils.create_LineEdit(None, time_validator, None) durationQL = QLabel(self.tr("Duration") + time_format) self.durationQLE = utils.create_LineEdit(None, time_validator, None) hlayout4 = utils.add_to_layout("h", beginQL, self.beginQLE, durationQL, self.durationQLE) embedQL = QLabel(self.tr("Embed subtitle:")) self.embedQLE = QLineEdit() self.embedQTB = QToolButton() self.embedQTB.setText("...") rotateQL = QLabel(self.tr("Rotate:")) self.rotateQCB = QComboBox() self.rotateQCB.addItems(rotation_options) hlayout5 = utils.add_to_layout("h", rotateQL, self.rotateQCB, embedQL, self.embedQLE, self.embedQTB) hidden_layout = utils.add_to_layout("v", videosettings_layout, audiosettings_layout, hlayout4, hlayout5) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.moreQPB = QPushButton(QApplication.translate("Tab", "More")) self.moreQPB.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.moreQPB.setCheckable(True) hlayout3 = utils.add_to_layout("h", line, self.moreQPB) self.frame = QFrame() self.frame.setLayout(hidden_layout) self.frame.hide() final_layout = utils.add_to_layout("v", hlayout1, hlayout2, hlayout3, self.frame) self.setLayout(final_layout) self.presetQPB.clicked.connect(self.choose_preset) self.defaultQPB.clicked.connect(self.set_default_command) self.embedQTB.clicked.connect(self.open_subtitle_file) self.moreQPB.toggled.connect(self.frame.setVisible) self.moreQPB.toggled.connect(lambda: QTimer.singleShot(100, self.resize_parent)) self.widthQLE.textChanged.connect(self.command_update_size) self.heightQLE.textChanged.connect(self.command_update_size) self.aspect1QLE.textChanged.connect(self.command_update_aspect) self.aspect2QLE.textChanged.connect(self.command_update_aspect) self.frameQLE.textChanged.connect(self.command_update_frames) self.bitrateQLE.textChanged.connect(self.command_update_vidbitrate) self.threadsQLE.textChanged.connect(self.command_update_threads) self.beginQLE.textChanged.connect(self.command_update_begin_time) self.durationQLE.textChanged.connect(self.command_update_duration) self.embedQLE.textChanged.connect(self.command_update_subtitles) self.vidcodecQCB.currentIndexChanged.connect(self.command_update_vcodec) self.audcodecQCB.currentIndexChanged.connect(self.command_update_acodec) self.freqQCB.currentIndexChanged.connect(self.command_update_frequency) self.rotateQCB.currentIndexChanged.connect(self.command_update_rotation) self.audbitrateQCB.currentIndexChanged.connect(self.command_update_audbitrate) self.chan1QRB.clicked.connect(lambda: self.command_update_channels("1")) self.chan2QRB.clicked.connect(lambda: self.command_update_channels("2")) self.preserveaspectQChB.toggled.connect(self.command_update_preserve_aspect) self.preservesizeQChB.toggled.connect(self.command_update_preserve_size) def resize_parent(self): """Give MainWindow its default size.""" self.parent.setMinimumSize(self.parent.sizeHint()) self.parent.resize(self.parent.sizeHint()) def clear(self): """Clear all values of graphical widgets.""" lines = [ self.commandQLE, self.widthQLE, self.heightQLE, self.aspect1QLE, self.aspect2QLE, self.frameQLE, self.bitrateQLE, self.threadsQLE, self.beginQLE, self.embedQLE, self.durationQLE, ] for i in lines: i.clear() self.vidcodecQCB.setCurrentIndex(0) self.audcodecQCB.setCurrentIndex(0) self.freqQCB.setCurrentIndex(0) self.audbitrateQCB.setCurrentIndex(0) self.rotateQCB.setCurrentIndex(0) self.preserveaspectQChB.setChecked(False) self.preservesizeQChB.setChecked(False) self.group.setExclusive(False) self.chan1QRB.setChecked(False) self.chan2QRB.setChecked(False) self.group.setExclusive(True) # setExclusive(False) in order to be able to uncheck checkboxes and # then setExclusive(True) so only one radio button can be set def fill_video_comboboxes(self, vcodecs, acodecs, extraformats): vcodecs = [i for i in vcodecs.split("\n")] if vcodecs else [] acodecs = [i for i in acodecs.split("\n")] if acodecs else [] extraformats = [i for i in extraformats.split("\n")] if extraformats else [] self.vidcodecQCB.currentIndexChanged.disconnect() self.audcodecQCB.currentIndexChanged.disconnect() self.vidcodecQCB.clear() self.audcodecQCB.clear() self.extQCB.clear() self.vidcodecQCB.addItems([self.defaultStr, self.DisableStream] + vcodecs) self.audcodecQCB.addItems([self.defaultStr, self.DisableStream] + acodecs) self.extQCB.addItems(sorted(self.formats + extraformats)) self.vidcodecQCB.currentIndexChanged.connect(self.command_update_vcodec) self.audcodecQCB.currentIndexChanged.connect(self.command_update_acodec) def ok_to_continue(self): """ Check if everything is ok with audiovideotab to continue conversion. Check if: - Either ffmpeg or avconv are installed. Return True if all tests pass, else False. """ if self.parent.vidconverter is None: QMessageBox.warning( self, "FF Multi Converter - " + self.tr("Error!"), self.tr( "Neither ffmpeg nor libav are installed." "\nYou will not be able to convert audio/video files until you" " install one of them." ), ) return False return True def open_subtitle_file(self): """ Get the filename using standard QtDialog and update embedQLE's text. """ fname = QFileDialog.getOpenFileName( self, "FF Multi Converter - " + self.tr("Choose File"), config.home, "Subtitles (*.srt *.sub *.ssa *.ass)" ) if fname: self.embedQLE.setText(fname) def set_default_command(self): """Set the default value to self.commandQLE.""" self.clear() self.commandQLE.setText(self.parent.default_command) def choose_preset(self): """ Open the presets dialog and update self.commandQLE, and self.extQCB and with the appropriate values. """ dialog = presets_dlgs.ShowPresets(choose=True) if dialog.exec_() and dialog.the_command is not None: self.clear() self.commandQLE.setText(dialog.the_command) self.commandQLE.home(False) find = self.extQCB.findText(dialog.the_extension) if find >= 0: self.extQCB.setCurrentIndex(find) def command_update_size(self): command = self.commandQLE.text() text1 = self.widthQLE.text() text2 = self.heightQLE.text() if not (text1 == "-1" or text2 == "-1"): self.preserveaspectQChB.setChecked(False) if (text1 or text2) and not (text1 and text2) or (text1 == "-" or text2 == "-"): return regex = r"(\s+|^)-s(:v){0,1}\s+\d+x\d+(\s+|$)" if re.search(regex, command): command = re.sub(regex, "", command) regex = r"(,*\s*){0,1}(scale=-?\d+:-?\d+)(\s*,*\s*){0,1}" _filter = "scale={0}:{1}".format(text1, text2) if text1 and text2 else "" self.commandQLE.setText(utils.update_cmdline_text(command, _filter, regex, bool(text1 and text2), 0, 2)) def command_update_preserve_size(self): checked = self.preservesizeQChB.isChecked() self.widthQLE.setEnabled(not checked) self.heightQLE.setEnabled(not checked) if checked: self.widthQLE.clear() self.heightQLE.clear() # command_update_size() is triggered here command = self.commandQLE.text() regex = r"(\s+|^)-s\s+\d+x\d+(\s+|$)" command = re.sub(" +", " ", re.sub(regex, " ", command)).strip() self.commandQLE.setText(command) def command_update_aspect(self): command = self.commandQLE.text() text1 = self.aspect1QLE.text() text2 = self.aspect2QLE.text() if (text1 or text2) and not (text1 and text2): return regex = r"(\s+|^)-aspect\s+\d+:\d+(\s+|$)" s = " -aspect {0}:{1} ".format(text1, text2) if text1 and text2 else " " if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(" +", " ", command).strip() self.commandQLE.setText(command) def command_update_preserve_aspect(self): command = self.commandQLE.text() checked = self.preserveaspectQChB.isChecked() self.aspect1QLE.setEnabled(not checked) self.aspect2QLE.setEnabled(not checked) if checked: self.aspect1QLE.clear() self.aspect2QLE.clear() # self.command_update_aspect() is triggered here regex = r"(,*\s*){0,1}(scale=(-?\d+):(-?\d+))(\s*,*\s*){0,1}" search = re.search(regex, command) if search: width = search.groups()[2] height = search.groups()[3] if not (width == "-1" or height == "-1"): s = "scale=-1:{0}".format(height) command = re.sub(regex, r"\1{0}\5".format(s), command) self.widthQLE.setText("-1") self.heightQLE.setText(height) regex = r"(\s+|^)-aspect\s+\d+:\d+(\s+|$)" command = re.sub(" +", " ", re.sub(regex, " ", command)).strip() self.commandQLE.setText(command) def command_update_frames(self): command = self.commandQLE.text() text = self.frameQLE.text() regex = r"(\s+|^)-r\s+\d+(\s+|$)" s = " -r {0} ".format(text) if text else " " if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(" +", " ", command).strip() self.commandQLE.setText(command) def command_update_vidbitrate(self): command = self.commandQLE.text() text = self.bitrateQLE.text() regex = r"(\s+|^)-b(:v){0,1}\s+\d+[kKmM](\s+|$)" s = " -b:v {0}k ".format(text) if text else " " if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub("-sameq", "", command) command = re.sub(" +", " ", command).strip() self.commandQLE.setText(command) def command_update_frequency(self): command = self.commandQLE.text() text = self.freqQCB.currentText() regex = r"(\s+|^)-ar\s+\d+(\s+|$)" s = " -ar {0} ".format(text) if self.freqQCB.currentIndex() != 0 else " " if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(" +", " ", command).strip() self.commandQLE.setText(command) def command_update_audbitrate(self): command = self.commandQLE.text() text = self.audbitrateQCB.currentText() regex = r"(\s+|^)-(ab|b:a)\s+\d+[kKmM](\s+|$)" if self.audbitrateQCB.currentIndex() != 0: s = " -b:a {0}k ".format(text) else: s = " " if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(" +", " ", command).strip() self.commandQLE.setText(command) def command_update_channels(self, channel): command = self.commandQLE.text() regex = r"(\s+|^)-ac\s+\d+(\s+|$)" s = " -ac {0} ".format(channel) if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(" +", " ", command).strip() self.commandQLE.setText(command) def command_update_threads(self): command = self.commandQLE.text() text = self.threadsQLE.text() regex = r"(\s+|^)-threads\s+\d+(\s+|$)" s = " -threads {0} ".format(text) if text else " " if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(" +", " ", command).strip() self.commandQLE.setText(command) def command_update_begin_time(self): command = self.commandQLE.text() text = self.beginQLE.text() regex = r"(\s+|^)-ss\s+\S+(\s+|$)" s = " -ss {0} ".format(text) if text else " " if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(" +", " ", command).strip() self.commandQLE.setText(command) def command_update_duration(self): command = self.commandQLE.text() text = self.durationQLE.text() regex = r"(\s+|^)-t\s+\S+(\s+|$)" s = " -t {0} ".format(text) if text else " " if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(" +", " ", command).strip() self.commandQLE.setText(command) def command_update_vcodec(self): command = self.commandQLE.text() text = self.vidcodecQCB.currentText() regex = r"(\s+|^)-(vcodec|c:v)\s+\S+(\s+|$)" regex_vn = r"(\s+|^)-vn(\s+|$)" if self.vidcodecQCB.currentIndex() == 1: s = " -vn ".format(text) elif self.vidcodecQCB.currentIndex() == 0: s = " " else: s = " -vcodec {0} ".format(text) if re.search(regex, command): command = re.sub(regex, s, command) elif re.search(regex_vn, command): command = re.sub(regex_vn, s, command) else: command += s command = re.sub(" +", " ", command).strip() self.commandQLE.setText(command) def command_update_acodec(self): command = self.commandQLE.text() text = self.audcodecQCB.currentText() regex = r"(\s+|^)-(acodec|c:a)\s+\S+(\s+|$)" regex_an = r"(\s+|^)-an(\s+|$)" if self.audcodecQCB.currentIndex() == 1: s = " -an ".format(text) elif self.audcodecQCB.currentIndex() == 0: s = " " else: s = " -acodec {0} ".format(text) if re.search(regex, command): command = re.sub(regex, s, command) elif re.search(regex_an, command): command = re.sub(regex_an, s, command) else: command += s command = re.sub(" +", " ", command).strip() self.commandQLE.setText(command) def command_update_subtitles(self): command = self.commandQLE.text() regex = r"(,*\s*){0,1}(subtitles=\'.*\')(\s*,*\s*){0,1}" text = self.embedQLE.text() _filter = "subtitles='{0}'".format(text) if text else "" self.commandQLE.setText(utils.update_cmdline_text(command, _filter, regex, bool(text), 0, 2)) def command_update_rotation(self): command = self.commandQLE.text() regex = r"(,*\s*){0,1}(transpose=\d(,\s*transpose=\d)*|vflip|hflip)(\s*,*\s*){0,1}" rotate = self.rotateQCB.currentIndex() if rotate == 0: # none _filter = "" elif rotate == 1: # 90 clockwise _filter = "transpose=1" elif rotate == 2: # 90 clockwise + vertical flip _filter = "transpose=3" elif rotate == 3: # 90 counter clockwise _filter = "transpose=2" elif rotate == 4: # 90 counter clockwise + vertical flip _filter = "transpose=0" elif rotate == 5: # 180 _filter = "transpose=2,transpose=2" elif rotate == 6: # horizontal flip _filter = "hflip" elif rotate == 7: # vertical flip _filter = "vflip" self.commandQLE.setText(utils.update_cmdline_text(command, _filter, regex, bool(rotate != 0), 0, 3))
class PlotWidget(QtGui.QWidget, plot_widget_class): """Wrapper widget for PyQtGraph adding some extra buttons""" def __init__(self, parent=None, fps=100, title="", *args): super(PlotWidget, self).__init__(*args) self.setupUi(self) # Limit the plot update to 10Hz self._ts = time() self._delay = 0.1 # Check if we could import PyQtGraph, if not then stop here if not _pyqtgraph_found: self.can_enable = False return else: self.can_enable = True self._items = {} self._last_item = 0 self.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding)) self.setMinimumSize(self.minimumSizeHint()) self.parent = parent pg.setConfigOption('background', 'w') pg.setConfigOption('foreground', 'k') self._plot_widget = pg.PlotWidget() self._plot_widget.hideButtons() self._plot_widget.setLabel('bottom', "Time", "ms") self._plot_widget.addLegend() self._plot_widget.getViewBox().disableAutoRange(ViewBox.XAxis) self._plot_widget.getViewBox().sigRangeChangedManually.connect( self._manual_range_change) self._plot_widget.getViewBox().setMouseEnabled(x=False, y=True) self._plot_widget.getViewBox().setMouseMode(ViewBox.PanMode) self.plotLayout.addWidget(self._plot_widget) #self.saveToFile.clicked.connect(self.saveToFileSignal) self._x_min = 0 self._x_max = 500 self._enable_auto_y.setChecked(True) self._enable_samples_x.setChecked(True) self._last_ts = None self._dtime = None self._x_range = (float(self._range_x_min.text()), float(self._range_x_max.text())) self._nbr_samples = int(self._nbr_of_samples_x.text()) self._nbr_of_samples_x.valueChanged.connect(self._nbr_samples_changed) self._range_y_min.valueChanged.connect(self._y_range_changed) self._range_y_max.valueChanged.connect(self._y_range_changed) self._y_btn_group = QButtonGroup() self._y_btn_group.addButton(self._enable_auto_y) self._y_btn_group.addButton(self._enable_range_y) self._y_btn_group.setExclusive(True) self._y_btn_group.buttonClicked.connect(self._y_mode_change) self._x_btn_group = QButtonGroup() self._x_btn_group.addButton(self._enable_range_x) self._x_btn_group.addButton(self._enable_samples_x) self._x_btn_group.addButton(self._enable_seconds_x) self._x_btn_group.addButton(self._enable_manual_x) self._x_btn_group.setExclusive(True) self._x_btn_group.buttonClicked.connect(self._x_mode_change) self._draw_graph = True self._auto_redraw.stateChanged.connect(self._auto_redraw_change) def _auto_redraw_change(self, state): """Callback from the auto redraw checkbox""" if state == 0: self._draw_graph = False else: self._draw_graph = True def _x_mode_change(self, box): """Callback when user changes the X-axis mode""" if box == self._enable_range_x: logger.info("Enable range x") self._x_range = (float(self._range_x_min.text()), float(self._range_x_max.text())) else: self._range_x_min.setEnabled(False) self._range_x_max.setEnabled(False) def _y_mode_change(self, box): """Callback when user changes the Y-axis mode""" if box == self._enable_range_y: self._range_y_min.setEnabled(True) self._range_y_max.setEnabled(True) y_range = (float(self._range_y_min.value()), float(self._range_y_max.value())) self._plot_widget.getViewBox().setRange(yRange=y_range) else: self._range_y_min.setEnabled(False) self._range_y_max.setEnabled(False) if box == self._enable_auto_y: self._plot_widget.getViewBox().enableAutoRange(ViewBox.YAxis) def _manual_range_change(self, obj): """Callback from pyqtplot when users changes the range of the plot using the mouse""" [[x_min, x_max], [y_min, y_max]] = self._plot_widget.getViewBox().viewRange() self._range_y_min.setValue(y_min) self._range_y_max.setValue(y_max) self._range_y_min.setEnabled(True) self._range_y_max.setEnabled(True) self._enable_range_y.setChecked(True) def _y_range_changed(self, val): """Callback when user changes Y range manually""" _y_range = (float(self._range_y_min.value()), float(self._range_y_max.value())) self._plot_widget.getViewBox().setRange(yRange=_y_range, padding=0) def _nbr_samples_changed(self, val): """Callback when user changes the number of samples to be shown""" self._nbr_samples = val def set_title(self, title): """ Set the title of the plot. title - the new title """ self._plot_widget.setTitle(title) def add_curve(self, title, pen='r'): """ Add a new curve to the plot. title - the name of the data pen - color of curve (using r for red and so on..) """ self._items[title] = PlotItemWrapper( self._plot_widget.plot(name=title, pen=pen)) def add_data(self, data, ts): """ Add new data to the plot. data - dictionary sent from logging layer containing variable/value pairs ts - timestamp of the data in ms """ if not self._last_ts: self._last_ts = ts elif not self._last_ts: self._dtime = ts - self._last_ts self._last_ts = ts x_min_limit = 0 x_max_limit = 0 # We are adding new datasets, calculate what we should show. if self._enable_samples_x.isChecked(): x_min_limit = max(0, self._last_item - self._nbr_samples) x_max_limit = max(self._last_item, self._nbr_samples) for name in self._items: self._items[name].add_point(data[name], ts) if self._draw_graph and time() > self._ts + self._delay: [self._x_min, self._x_max ] = self._items[name].show_data(x_min_limit, x_max_limit) if time() > self._ts + self._delay: self._ts = time() if self._enable_samples_x.isChecked( ) and self._dtime and self._last_item < self._nbr_samples: self._x_max = self._x_min + self._nbr_samples * self._dtime self._last_item = self._last_item + 1 self._plot_widget.getViewBox().setRange(xRange=(self._x_min, self._x_max)) def removeAllDatasets(self): """Reset the plot by removing all the datasets""" for item in self._items: self._plot_widget.removeItem(self._items[item]) self._plot_widget.plotItem.legend.items = [] self._items = {} self._last_item = 0 self._last_ts = None self._dtime = None self._plot_widget.clear()
class DefaultSelectParameterWidget(SelectParameterWidget): """Widget class for Default Select Parameter.""" def __init__(self, parameter, parent=None): """Constructor :param parameter: A DefaultSelectParameter object. :type parameter: DefaultSelectParameter """ super(DefaultSelectParameterWidget, self).__init__(parameter, parent) self.default_layout = QHBoxLayout() self.radio_button_layout = QHBoxLayout() self.radio_button_widget = QWidget() self.default_label = QLabel(tr('Default')) # Create radio button group self.default_input_button_group = QButtonGroup() # Define string enabler for radio button self.radio_button_enabler = self.input.itemData(0, Qt.UserRole) for i in range(len(self._parameter.default_labels)): if '%s' in self._parameter.default_labels[i]: label = (self._parameter.default_labels[i] % self._parameter.default_values[i]) else: label = self._parameter.default_labels[i] radio_button = QRadioButton(label) self.radio_button_layout.addWidget(radio_button) self.default_input_button_group.addButton(radio_button, i) if self._parameter.default_value == \ self._parameter.default_values[i]: radio_button.setChecked(True) # Create double spin box for custom value self.custom_value = QDoubleSpinBox() if self._parameter.default_values[-1]: self.custom_value.setValue(self._parameter.default_values[-1]) has_min = False if self._parameter.minimum is not None: has_min = True self.custom_value.setMinimum(self._parameter.minimum) has_max = False if self._parameter.maximum is not None: has_max = True self.custom_value.setMaximum(self._parameter.maximum) if has_min and has_max: step = (self._parameter.maximum - self._parameter.minimum) / 100.0 self.custom_value.setSingleStep(step) self.radio_button_layout.addWidget(self.custom_value) self.toggle_custom_value() # Reset the layout self.input_layout.setParent(None) self.help_layout.setParent(None) self.label.setParent(None) self.inner_input_layout.setParent(None) self.input_layout = QGridLayout() self.input_layout.setSpacing(0) self.input_layout.addWidget(self.label, 0, 0) self.input_layout.addLayout(self.inner_input_layout, 0, 1) self.input_layout.addWidget(self.default_label, 1, 0) self.input_layout.addLayout(self.radio_button_layout, 1, 1) self.main_layout.addLayout(self.input_layout) self.main_layout.addLayout(self.help_layout) # check every added combobox, it could have been toggled by # the existing keyword self.toggle_input() # Connect # noinspection PyUnresolvedReferences self.input.currentIndexChanged.connect(self.toggle_input) self.default_input_button_group.buttonClicked.connect( self.toggle_custom_value) def raise_invalid_type_exception(self): message = 'Expecting element type of %s' % ( self._parameter.element_type.__name__) err = ValueError(message) return err def get_parameter(self): """Obtain list parameter object from the current widget state. :returns: A DefaultSelectParameter from the current state of widget. """ current_index = self.input.currentIndex() selected_value = self.input.itemData(current_index, Qt.UserRole) if hasattr(selected_value, 'toPyObject'): selected_value = selected_value.toPyObject() try: self._parameter.value = selected_value except ValueError: err = self.raise_invalid_type_exception() raise err radio_button_checked_id = self.default_input_button_group.checkedId() # No radio button checked, then default value = None if radio_button_checked_id == -1: self._parameter.default = None # The last radio button (custom) is checked, get the value from the # line edit elif (radio_button_checked_id == len(self._parameter.default_values) - 1): self._parameter.default_values[radio_button_checked_id] \ = self.custom_value.value() self._parameter.default = self.custom_value.value() else: self._parameter.default = self._parameter.default_values[ radio_button_checked_id] return self._parameter def set_default(self, default): """Set default value by item's string. :param default: The default. :type default: str, int :returns: True if success, else False. :rtype: bool """ # Find index of choice try: default_index = self._parameter.default_values.index(default) self.default_input_button_group.button(default_index).setChecked( True) except ValueError: last_index = len(self._parameter.default_values) - 1 self.default_input_button_group.button(last_index).setChecked(True) self.custom_value.setValue(default) self.toggle_custom_value() def toggle_custom_value(self): radio_button_checked_id = self.default_input_button_group.checkedId() if (radio_button_checked_id == len(self._parameter.default_values) - 1): self.custom_value.setDisabled(False) else: self.custom_value.setDisabled(True) def toggle_input(self): """Change behaviour of radio button based on input.""" current_index = self.input.currentIndex() # If current input is not a radio button enabler, disable radio button. if self.input.itemData(current_index, Qt.UserRole) != (self.radio_button_enabler): self.disable_radio_button() # Otherwise, enable radio button. else: self.enable_radio_button() def set_selected_radio_button(self): """Set selected radio button to 'Do not report'.""" dont_use_button = self.default_input_button_group.button( len(self._parameter.default_values) - 2) dont_use_button.setChecked(True) def disable_radio_button(self): """Disable radio button group and custom value input area.""" checked = self.default_input_button_group.checkedButton() if checked: self.default_input_button_group.setExclusive(False) checked.setChecked(False) self.default_input_button_group.setExclusive(True) for button in self.default_input_button_group.buttons(): button.setDisabled(True) self.custom_value.setDisabled(True) def enable_radio_button(self): """Enable radio button and custom value input area then set selected radio button to 'Do not report'. """ for button in self.default_input_button_group.buttons(): button.setEnabled(True) self.set_selected_radio_button() self.custom_value.setEnabled(True)
class BrowserPage(QWidget): def __init__(self, base): QWidget.__init__(self) current_browser = base.core.get_default_browser() description = QLabel(i18n.get("web_browser_tab_description")) description.setWordWrap(True) self.command = QLineEdit() self.default_browser = RadioButton(i18n.get("use_default_browser"), self) self.default_browser.selected.connect(self.__on_defaul_selected) self.custom_browser = RadioButton(i18n.get("set_custom_browser"), self) self.custom_browser.selected.connect(self.__on_custom_selected) custom_label = QLabel(i18n.get("command")) self.open_button = QPushButton(i18n.get("open")) self.test_button = QPushButton(i18n.get("test")) self.test_button.clicked.connect(self.__on_test) command_box = QHBoxLayout() command_box.setSpacing(5) command_box.addWidget(custom_label) command_box.addWidget(self.command, 1) # command_box.addWidget(self.open_button) command_box.addWidget(self.test_button) self.button_group = QButtonGroup() self.button_group.addButton(self.default_browser.radiobutton) self.button_group.addButton(self.custom_browser.radiobutton) self.button_group.setExclusive(True) vbox = QVBoxLayout() vbox.setSpacing(0) vbox.setContentsMargins(5, 5, 5, 0) vbox.addWidget(description) vbox.addSpacing(15) vbox.addWidget(self.default_browser) vbox.addSpacing(10) vbox.addWidget(self.custom_browser) vbox.addLayout(command_box) vbox.addStretch(1) self.setLayout(vbox) if current_browser == "": self.default_browser.set_value(True) self.command.setText("") self.__on_defaul_selected() else: self.custom_browser.set_value(True) self.command.setText(current_browser) self.__on_custom_selected() def __on_test(self): cmd = str(self.command.text()) if cmd != "": subprocess.Popen([cmd, "http://turpial.org.ve/"]) def __on_defaul_selected(self): self.open_button.setEnabled(False) self.test_button.setEnabled(False) self.command.setEnabled(False) def __on_custom_selected(self): self.open_button.setEnabled(True) self.test_button.setEnabled(True) self.command.setEnabled(True) def get_config(self): if self.default_browser.get_value(): cmd = "" else: cmd = str(self.command.text()) return {"cmd": cmd}
class ControlPanel(QFrame): def __init__(self, parent=None): QFrame.__init__(self, parent) self.setFrameShape(spec.FRAME_SHAPE) self.setAutoFillBackground(True) self.palette().setColor(self.backgroundRole(), spec.POV_COLOR) self.label = QuitterLabel("pksampler", self) self.label.setScaledContents(True) font = self.label.font() font.setPointSize(40) font.setFamily("Lucida Grande") self.label.palette().setColor(QPalette.WindowText, QColor(60, 60, 80)) self.mapper = midi.InputWidget(parent=self) self.mapper.setMinimumHeight(50) self.mapper.setMinimumWidth(100) self.send1Slot = slots.EffectSlot(self) self.send1Slot.frame_color = SLOT_COLOR self.send2Slot = slots.EffectSlot(self) self.send2Slot.frame_color = SLOT_COLOR self.modeGroup = QButtonGroup(self) self.modeGroup.setExclusive(True) self.modeButtons = [] for mode in ("select", "play", "delete"): button = pk.widgets.Button(self) button.setText(mode) button.setCheckable(True) setattr(self, mode + "Button", button) self.modeGroup.addButton(button) self.modeButtons.append(button) self.clickButton = pk.widgets.Button(self, color="green") self.clickButton.setText("click") self.clickButton.setCheckable(True) QObject.connect(self.send1Slot, SIGNAL("selected(QWidget *)"), self, SIGNAL("selected(QWidget *)")) QObject.connect(self.send2Slot, SIGNAL("selected(QWidget *)"), self, SIGNAL("selected(QWidget *)")) QObject.connect(self.send1Slot, SIGNAL("added(QWidget *, QWidget *)"), self.setSend) QObject.connect(self.send1Slot, SIGNAL("deleted(QWidget *, QWidget *)"), self, SIGNAL("unsetSend1()")) QObject.connect(self.send2Slot, SIGNAL("added(QWidget *, QWidget *)"), self.setSend) QObject.connect(self.send1Slot, SIGNAL("deleted(QWidget *, QWidget *)"), self, SIGNAL("unsetSend2()")) Layout = QHBoxLayout(self) Layout.addWidget(self.label) Layout.addWidget(self.mapper) # Layout.addStretch(20) Layout.addWidget(self.send1Slot) Layout.addWidget(self.send2Slot) # pk.widgets.utils.h_centered(Layout, self.send1Slot) # pk.widgets.utils.h_centered(Layout, self.send2Slot) # ModeLayout = QGridLayout() ModeLayout = QHBoxLayout() Layout.addLayout(ModeLayout) for index, button in enumerate(self.modeButtons): # ModeLayout.addWidget(button, index % 2, index / 2) ModeLayout.addWidget(button) # pk.widgets.utils.h_centered(Layout, button) Layout.addStretch(1) # Layout.addWidget(self.clickButton) pk.widgets.utils.h_centered(Layout, self.clickButton) def setSend(self, part, slot): if slot == self.send1Slot: self.emit(SIGNAL("setSend1(QWidget *)"), part) if slot == self.send2Slot: self.emit(SIGNAL("setSend2(QWidget *)"), part)
class ApplicationWindow(QMainWindow): def __init__(self): super(ApplicationWindow, self).__init__() self._init_ui() self._set_defaults() def _init_ui(self): # Styles self.setStyleSheet("""QRadioButton { max-width: 40px; }""") bold_font = QFont() bold_font.setBold(True) title_label = QLabel(self) title_label.setText("PyPass3") title_label.move(10, 0) title_label.setMinimumSize(300, 20) title_label.setFont(bold_font) length_label = QLabel(self) length_label.setText("Length") length_label.move(192, 185) length_label.setMinimumSize(200, 20) length_label.setFont(bold_font) main_label = QLabel(self) main_label.setText("Make robust secrets with random characters,\n" "words, or numbers. Or choose number of dice\n" "and rolls for words type passphrase. Defaults\n" "to 5 dice and 5 rolls.\n") main_label.setMinimumSize(280, 100) main_label.move(10, 15) type_label = QLabel(self) type_label.setText("Secret type") type_label.move(10, 87) type_label.setFont(bold_font) dice_label = QLabel(self) dice_label.setText("Number of dice") dice_label.move(10, 138) dice_label.setMinimumSize(280, 20) dice_label.setFont(bold_font) rolls_label = QLabel(self) rolls_label.setText("Number of rolls") rolls_label.move(10, 190) rolls_label.setMinimumSize(280, 20) rolls_label.setFont(bold_font) self.textbox = QTextEdit(self) self.textbox.setMinimumSize(280, 100) self.textbox.move(10, 245) self.textbox.setFontFamily("Courier New") self.length_textline = QLineEdit(self) self.length_textline.setMinimumSize(100, 20) self.length_textline.move(190, 210) min_width = 125 # max_width = 150 # Add Generate button generate_btn = QPushButton('Generate', self) generate_btn.setToolTip('Click to generate secret') # generate_btn.clicked.connect(on_click) generate_btn.clicked.connect(self._on_click) generate_btn.move(10, 355) generate_btn.setMinimumWidth(min_width) # Add Quit button quit_btn = QPushButton('Quit', self) quit_btn.setToolTip('Quit this application') quit_btn.clicked.connect(exit) quit_btn.move(165, 355) quit_btn.setMinimumWidth(min_width) # Add Copy button copy_btn = QPushButton('Copy', self) copy_btn.setToolTip('Copy your secret') copy_btn.clicked.connect(self._copy_textbox) copy_btn.move(250, 320) copy_btn.setMaximumWidth(35) copy_btn.setMaximumHeight(20) copy_btn.setStyleSheet('font-size: 11px;') # Add Help button help_btn = QPushButton('Help', self) help_btn.setToolTip('Get help about this application') help_btn.clicked.connect(self._open_help) help_btn.move(240, 80) help_btn.setMaximumWidth(35) help_btn.setMaximumHeight(20) help_btn.setStyleSheet('font-size: 11px;') hr1 = QFrame(self) hr1.setFrameShape(QFrame.HLine) hr1.move(10, 125) hr1.setMinimumWidth(280) hr1.setStyleSheet("color: #d0d0d0;") hr2 = QFrame(self) hr2.setFrameShape(QFrame.HLine) hr2.move(10, 175) hr2.setMinimumWidth(100) hr2.setStyleSheet("color: #d0d0d0;") # Add secret type radio buttons self.words_radio_btn = QRadioButton('words', self) self.words_radio_btn.move(10, 110) self.words_radio_btn.clicked.connect(self._set_word_defaults) self.words_radio_btn.setStyleSheet('max-width: 80px;') self.mixed_radio_btn = QRadioButton('mixed', self) self.mixed_radio_btn.move(90, 110) self.mixed_radio_btn.clicked.connect(self._disabled_unused) self.mixed_radio_btn.setStyleSheet('max-width: 80px;') self.numbers_radio_btn = QRadioButton('numbers', self) self.numbers_radio_btn.move(170, 110) self.numbers_radio_btn.clicked.connect(self._disabled_unused) self.numbers_radio_btn.setStyleSheet('max-width: 100px;') # Add dice roll radio buttons self.num_dice4 = QRadioButton('4', self) self.num_dice4.move(10, 160) self.num_dice5 = QRadioButton('5', self) self.num_dice5.move(60, 160) self.num_rolls3 = QRadioButton('3', self) self.num_rolls3.move(10, 212) self.num_rolls4 = QRadioButton('4', self) self.num_rolls4.move(60, 212) self.num_rolls5 = QRadioButton('5', self) self.num_rolls5.move(110, 212) self.radio_type_group = QButtonGroup(self) self.radio_type_group.addButton(self.words_radio_btn) self.radio_type_group.addButton(self.mixed_radio_btn) self.radio_type_group.addButton(self.numbers_radio_btn) self.radio_dice_group = QButtonGroup(self) self.radio_dice_group.addButton(self.num_dice4) self.radio_dice_group.addButton(self.num_dice5) self.radio_rolls_group = QButtonGroup(self) self.radio_rolls_group.addButton(self.num_rolls3) self.radio_rolls_group.addButton(self.num_rolls4) self.radio_rolls_group.addButton(self.num_rolls5) self.setGeometry(100, 100, 300, 400) self.setWindowTitle('Password Generator') self.setWindowIcon(QIcon('../images/lock_icon_bkgrd.png')) def _set_defaults(self): self.words_radio_btn.setChecked(True) self.num_dice5.setChecked(True) self.num_rolls5.setChecked(True) self.length_textline.setText('') def _run_generate(self): logging.info('[{0}]\n{1}'.format(utils.get_timestamp(), self._get_args())) return generate_secret(int(self._get_args()['number_rolls']), int(self._get_args()['number_dice']), int(self._get_args()['how_many']), str(self._get_args()['output_type']), int(self._get_args()['password_length'])) # def generate_secret(number_rolls: int = 5, number_dice: int = 5, # how_many: int = 1, output_type: str = 'words', # password_length: int = 20) # output_type=self._get_args()['output_type'], # password_length=int(self._get_args()['password_length']), # number_dice=int(self._get_args()['number_dice']), # number_rolls=int(self._get_args()['number_rolls']) def _on_click(self): self.textbox.setFontFamily("Courier New") return self.textbox.setText(self._run_generate()) def _get_args(self): args = {'password_length': 20, 'how_many': 1} # Type if self.numbers_radio_btn.isChecked(): args['output_type'] = self.numbers_radio_btn.text() elif self.mixed_radio_btn.isChecked(): args['output_type'] = self.mixed_radio_btn.text() else: args['output_type'] = self.words_radio_btn.text() # Length if self.length_textline.text(): args['password_length'] = self.length_textline.text() # Dice if self.num_dice4.isChecked(): args['number_dice'] = self.num_dice4.text() else: args['number_dice'] = self.num_dice5.text() # Rolls if self.num_rolls3.isChecked(): args['number_rolls'] = self.num_rolls3.text() elif self.num_rolls4.isChecked(): args['number_rolls'] = self.num_rolls4.text() else: args['number_rolls'] = self.num_rolls5.text() return args def _disabled_unused(self): tmp_text = self.length_textline.text() if tmp_text: self.length_textline.setText(tmp_text) else: self.length_textline.setText('20') self.radio_dice_group.setExclusive(False) self.radio_rolls_group.setExclusive(False) self.num_dice4.setChecked(False) self.num_dice4.setCheckable(False) self.num_dice4.setEnabled(False) self.num_dice5.setChecked(False) self.num_dice5.setCheckable(False) self.num_dice5.setEnabled(False) self.num_rolls3.setChecked(False) self.num_rolls3.setCheckable(False) self.num_rolls3.setEnabled(False) self.num_rolls4.setChecked(False) self.num_rolls4.setCheckable(False) self.num_rolls4.setEnabled(False) self.num_rolls5.setChecked(False) self.num_rolls5.setCheckable(False) self.num_rolls5.setEnabled(False) self.radio_dice_group.setExclusive(True) self.radio_rolls_group.setExclusive(True) def _set_word_defaults(self): self.length_textline.setText('') self.num_dice4.setCheckable(True) self.num_dice4.setEnabled(True) self.num_dice5.setCheckable(True) self.num_dice5.setEnabled(True) self.num_rolls3.setCheckable(True) self.num_rolls3.setEnabled(True) self.num_rolls4.setCheckable(True) self.num_rolls4.setEnabled(True) self.num_rolls5.setCheckable(True) self.num_rolls5.setEnabled(True) self.num_dice5.setChecked(True) self.num_rolls5.setChecked(True) def _copy_textbox(self): self.textbox.selectAll() self.textbox.copy() def _open_help(self): message = QMessageBox(self) with open('../assets/help/_main.txt', 'r') as help_text: message.setText(help_text.read()) message.setIcon(QMessageBox.Question) with open('../assets/help/_inform.txt', 'r') as help_inform: message.setInformativeText(help_inform.read()) message.setWindowTitle('PyPass3 Help') message.setStandardButtons(QMessageBox.Close) message.exec_()
class AuthenticationFrontend(ScrollArea): COMPONENT = 'auth_cert' LABEL = tr('Authentication server') REQUIREMENTS = ('auth_cert',) ICON = ':/icons/auth_protocol.png' def __init__(self, client, parent): self.__loading = True ScrollArea.__init__(self) self.mainwindow = parent self.client = client self.modified = False self.qauthcertobject = QAuthCertObject.getInstance() frame = QFrame(self) layout = QVBoxLayout(frame) layout.addWidget(QLabel('<H1>%s</H1>' % tr('Authentication server') )) head_box = QGroupBox(tr("How the authentication server handles certificates")) head = QFormLayout(head_box) self.strictCheckBox = QCheckBox() head.addRow(QLabel(tr("Strict mode (check the client's certificate against the installed CA)")), self.strictCheckBox) self.connect(self.strictCheckBox, SIGNAL('toggled(bool)'), self.setStrict) self.cl_auth_box = QGroupBox(tr("Client authentication with a certificate is")) cl_auth = QVBoxLayout(self.cl_auth_box) self.auth_by_cert = QButtonGroup() self.auth_by_cert.setExclusive(True) self.mainwindow.writeAccessNeeded(self.strictCheckBox) labels = [tr('forbidden'), tr('allowed'), tr('mandatory')] for index, label_button in enumerate(labels): button = QRadioButton(label_button) self.auth_by_cert.addButton(button, index) cl_auth.addWidget(button) self.mainwindow.writeAccessNeeded(button) self.auth_by_cert.button(0).setChecked(Qt.Checked) self.connect(self.auth_by_cert, SIGNAL('buttonClicked(int)'), self.auth_by_cert_modified) # Captive portal # -------------- self.portal_groupbox = QGroupBox(tr("Captive portal")) self.portal_groupbox.setLayout(QVBoxLayout()) # Enabled checkbox: self.portal_checkbox = QCheckBox(tr("Enable captive portal")) self.connect(self.portal_checkbox, SIGNAL('toggled(bool)'), self.setPortalEnabled) # List of networks redirected to the captive portal: self.portal_nets_groupbox = QGroupBox( tr("Networks handled by the captive portal")) self.portal_nets_groupbox.setLayout(QVBoxLayout()) self.portal_nets_edit = NetworkListEdit() self.connect(self.portal_nets_edit, SIGNAL('textChanged()'), self.setPortalNets) self.portal_nets_groupbox.layout().addWidget(self.portal_nets_edit) # Pack the widgets: for widget in (self.portal_checkbox, self.portal_nets_groupbox): self.portal_groupbox.layout().addWidget(widget) self.mainwindow.writeAccessNeeded(self.portal_checkbox) self.mainwindow.writeAccessNeeded(self.portal_nets_edit) if not EDENWALL: self.portal_groupbox.setVisible(False) # authentication server self.pki_widget = PkiEmbedWidget(self.client, self, 'auth_cert', PkiEmbedWidget.SHOW_ALL|PkiEmbedWidget.CRL_OPTIONAL, self.setModified) self.mainwindow.writeAccessNeeded(self.pki_widget) layout.addWidget(head_box) layout.addWidget(self.cl_auth_box) layout.addWidget(self.portal_groupbox) layout.addWidget(self.pki_widget) layout.addStretch() self.setWidget(frame) self.setWidgetResizable(True) self.resetConf() self.__loading = False def setModified(self, isModified=True, message=""): if self.__loading: return if isModified: self.modified = True self.mainwindow.setModified(self, True) if message: self.mainwindow.addToInfoArea(message) else: self.modified = False def setModifiedCallback(self, *unused): self.setModified() def isModified(self): return self.modified def saveConf(self, message): self.qauthcertobject.auth_cert.auth_by_cert = self.auth_by_cert.checkedId() conf = self.pki_widget.getConfig() self.qauthcertobject.auth_cert.setSSLDict(conf) serialized = self.qauthcertobject.auth_cert.serialize(downgrade=True) self.client.call('auth_cert', 'setAuthCertConfig', serialized, message) def resetConf(self): auth_cert_loaded = self._reset_helper( 'auth_cert', 'getAuthCertConfig', self.qauthcertobject, tr("Authentication interface enabled"), tr("Authentication disabled: backend not loaded") ) self.setModified(False) remote = self.qauthcertobject.auth_cert.getReceivedSerialVersion() if remote < 3: self.mainwindow.addWarningMessage(tr('Captive portal configuration disabled: this frontend and your appliance software versions are not compatible.')) enable_portal = ( auth_cert_loaded and EDENWALL and remote >= 3 ) self.portal_groupbox.setVisible(enable_portal) if not auth_cert_loaded: return self.strictCheckBox.setChecked(self.qauthcertobject.auth_cert.strict) if not self.qauthcertobject.auth_cert.auth_by_cert: self.qauthcertobject.auth_cert.auth_by_cert = 0 self.auth_by_cert.button( self.qauthcertobject.auth_cert.auth_by_cert).setChecked(True) # Captive portal: self.portal_checkbox.setChecked( self.qauthcertobject.auth_cert.portal_enabled) self.portal_nets_edit.setIpAddrs( self.qauthcertobject.auth_cert.portal_nets) # Certificate (PKI): pki_conf = self.qauthcertobject.auth_cert.getSSLDict() self.pki_widget.setConfig(pki_conf) def error(self, message): self.mainwindow.addToInfoArea(message, category=COLOR_ERROR) def auth_by_cert_modified(self, idbox): button_name = self.auth_by_cert.button(idbox).text() info = tr("Certificates - Authentication with client certificate : '%s'") % button_name self.setModified(message=info) def setPortalEnabled(self, value): if value != self.qauthcertobject.auth_cert.portal_enabled: self.qauthcertobject.auth_cert.setPortalEnabled(value) self.setModified() def setPortalNets(self): if self.portal_nets_edit.isValid(): self.qauthcertobject.auth_cert.setPortalNets( self.portal_nets_edit.value()) self.setModified() def setStrict(self, value): if value != self.qauthcertobject.auth_cert.strict: self.qauthcertobject.auth_cert.setStrict(value) self.setModified() self.cl_auth_box.setEnabled(value) def isValid(self): cert_validity = self.pki_widget.validate() if cert_validity is not None: self.error_message = '<br/>' + cert_validity + '<br/>' self.mainwindow.addToInfoArea(cert_validity, category=COLOR_ERROR) return False return True def onApplyFinished(self): self.pki_widget.feed()
def createLabelAndList(labelText): widget, label = _createLabelInWidget(labelText, QGridLayout) buttonGroup = QButtonGroup(widget) buttonGroup.setObjectName('buttonGroup') buttonGroup.setExclusive(False) return (widget, label, buttonGroup)
class BrowserPage(QWidget): def __init__(self, base): QWidget.__init__(self) current_browser = base.core.get_default_browser() description = QLabel(i18n.get('web_browser_tab_description')) description.setWordWrap(True) self.command = QLineEdit() self.default_browser = RadioButton(i18n.get('use_default_browser'), self) self.default_browser.selected.connect(self.__on_defaul_selected) self.custom_browser = RadioButton(i18n.get('set_custom_browser'), self) self.custom_browser.selected.connect(self.__on_custom_selected) custom_label = QLabel(i18n.get('command')) self.open_button = QPushButton(i18n.get('open')) self.test_button = QPushButton(i18n.get('test')) self.test_button.clicked.connect(self.__on_test) command_box = QHBoxLayout() command_box.setSpacing(5) command_box.addWidget(custom_label) command_box.addWidget(self.command, 1) #command_box.addWidget(self.open_button) command_box.addWidget(self.test_button) self.button_group = QButtonGroup() self.button_group.addButton(self.default_browser.radiobutton) self.button_group.addButton(self.custom_browser.radiobutton) self.button_group.setExclusive(True) vbox = QVBoxLayout() vbox.setSpacing(0) vbox.setContentsMargins(5, 5, 5, 0) vbox.addWidget(description) vbox.addSpacing(15) vbox.addWidget(self.default_browser) vbox.addSpacing(10) vbox.addWidget(self.custom_browser) vbox.addLayout(command_box) vbox.addStretch(1) self.setLayout(vbox) if current_browser == '': self.default_browser.set_value(True) self.command.setText('') self.__on_defaul_selected() else: self.custom_browser.set_value(True) self.command.setText(current_browser) self.__on_custom_selected() def __on_test(self): cmd = str(self.command.text()) if cmd != '': subprocess.Popen([cmd, 'http://turpial.org.ve/']) def __on_defaul_selected(self): self.open_button.setEnabled(False) self.test_button.setEnabled(False) self.command.setEnabled(False) def __on_custom_selected(self): self.open_button.setEnabled(True) self.test_button.setEnabled(True) self.command.setEnabled(True) def get_config(self): if self.default_browser.get_value(): cmd = '' else: cmd = str(self.command.text()) return {'cmd': cmd}
def create_rows(self, layout): u"""Build the rows of the dialog box""" play_button_group = QButtonGroup(self) old_play_button_group = QButtonGroup(self) for num, entry in enumerate(self.entries_list, 3): tt_text = self.build_text_help_label(entry) ico_label = QLabel('', self) ico_label.setToolTip(tt_text) if entry.icon: ico_label.setPixmap(QPixmap.fromImage(entry.icon)) layout.addWidget(ico_label, num, 0) tt_label = QLabel(entry.display_word, self) tt_label.setToolTip(tt_text) layout.addWidget(tt_label, num, 1) if self.hide_text: tt_label.hide() # Play button. t_play_button = QPushButton(self) play_button_group.addButton(t_play_button, num - 3) t_play_button.setToolTip(self.play_help) t_play_button.setIcon(QIcon(os.path.join(icons_dir, 'play.png'))) layout.addWidget(t_play_button, num, self.play_column) if self.note[entry.audio_field_name]: t_play_old_button = QPushButton(self) old_play_button_group.addButton(t_play_old_button, num - 3) t_play_old_button.setIcon( QIcon(os.path.join(icons_dir, 'play.png'))) if not self.hide_text: t_play_old_button.setToolTip( self.note[entry.audio_field_name]) else: t_play_old_button.setToolTip(self.play_old_help_short) layout.addWidget(t_play_old_button, num, self.play_old_column) else: dummy_label = QLabel('', self) dummy_label.setToolTip(self.play_old_empty_line_help) layout.addWidget(dummy_label, num, self.play_old_column) # The group where we later look what to do: t_button_group = QButtonGroup(self) t_button_group.setExclusive(True) # Now the four buttons t_add_button = QPushButton(self) t_add_button.setCheckable(True) t_add_button.setFlat(True) t_add_button.setToolTip(self.add_help_text_short) t_add_button.setIcon(QIcon(os.path.join(icons_dir, 'add.png'))) layout.addWidget(t_add_button, num, self.add_column) t_button_group.addButton(t_add_button, Action.Add) t_keep_button = QPushButton(self) t_keep_button.setCheckable(True) t_keep_button.setFlat(True) t_keep_button.setToolTip(self.keep_help_text_short) t_keep_button.setIcon(QIcon(os.path.join(icons_dir, 'keep.png'))) layout.addWidget(t_keep_button, num, self.keep_column) t_button_group.addButton(t_keep_button, Action.Keep) t_delete_button = QPushButton(self) t_delete_button.setCheckable(True) t_delete_button.setFlat(True) t_delete_button.setToolTip(self.delete_help_text_short) t_delete_button.setIcon( QIcon(os.path.join(icons_dir, 'delete.png'))) layout.addWidget(t_delete_button, num, self.delete_column) t_button_group.addButton(t_delete_button, Action.Delete) t_blacklist_button = QPushButton(self) t_blacklist_button.setCheckable(True) t_blacklist_button.setFlat(True) t_blacklist_button.setToolTip(self.blacklist_help_text_short) t_blacklist_button.setIcon( QIcon(os.path.join(icons_dir, 'blacklist.png'))) if entry.entry_hash: layout.addWidget( t_blacklist_button, num, self.blacklist_column) else: t_blacklist_button.hide() dummy_label_bl = QLabel('', self) dummy_label_bl.setToolTip(self.blacklist_empty_line_help) layout.addWidget(dummy_label_bl, num, self.blacklist_column) t_button_group.button(entry.action).setChecked(True) # New: check a button based on how good the downloader is. t_button_group.addButton(t_blacklist_button, Action.Blacklist) self.buttons_groups.append(t_button_group) play_button_group.buttonClicked.connect( lambda button: play( self.entries_list[play_button_group.id(button)].file_path)) # N.B.: anki.sound.play() plays files from anywhere, not just # from the colection.media folder. We should be good, # here. (This behaviour may be a security risk, idk.) old_play_button_group.buttonClicked.connect( lambda button: playFromText( self.note[ self.entries_list[ old_play_button_group.id(button)].audio_field_name]))
class AudioVideoTab(QWidget): def __init__(self, parent): super(AudioVideoTab, self).__init__(parent) self.parent = parent self.name = 'AudioVideo' self.defaultStr = self.tr('Default') self.DisableStream = self.tr('Disable') self.formats = config.video_formats frequency_values = [self.defaultStr] + config.video_frequency_values bitrate_values = [self.defaultStr] + config.video_bitrate_values rotation_options = [ self.tr('None'), '90 ' + self.tr('clockwise'), '90 ' + self.tr('clockwise') + ' + ' + self.tr('vertical flip'), '90 ' + self.tr('counter clockwise'), '90 ' + self.tr('counter clockwise') + ' + ' + self.tr('vertical flip'), '180', self.tr('horizontal flip'), self.tr('vertical flip') ] digits_validator = QRegExpValidator(QRegExp(r'[1-9]\d*'), self) digits_validator_wzero = QRegExpValidator(QRegExp(r'\d*'), self) digits_validator_minus = QRegExpValidator(QRegExp(r'(-1|[1-9]\d*)'), self) time_validator = QRegExpValidator( QRegExp(r'\d{1,2}:\d{1,2}:\d{1,2}\.\d+'), self) converttoQL = QLabel(self.tr('Convert to:')) self.extQCB = QComboBox() self.extQCB.setMinimumWidth(100) vidcodecQL = QLabel('Video codec:') self.vidcodecQCB = QComboBox() self.vidcodecQCB.setMinimumWidth(110) audcodecQL = QLabel('Audio codec:') self.audcodecQCB = QComboBox() self.audcodecQCB.setMinimumWidth(110) hlayout1 = utils.add_to_layout('h', converttoQL, self.extQCB, QSpacerItem(180, 20), vidcodecQL, self.vidcodecQCB, audcodecQL, self.audcodecQCB) commandQL = QLabel(self.tr('Command:')) self.commandQLE = QLineEdit() self.presetQPB = QPushButton(self.tr('Preset')) self.defaultQPB = QPushButton(self.defaultStr) hlayout2 = utils.add_to_layout('h', commandQL, self.commandQLE, self.presetQPB, self.defaultQPB) sizeQL = QLabel(self.tr('Video Size:')) aspectQL = QLabel(self.tr('Aspect:')) frameQL = QLabel(self.tr('Frame Rate (fps):')) bitrateQL = QLabel(self.tr('Video Bitrate (kbps):')) self.widthQLE = utils.create_LineEdit((70, 16777215), digits_validator_minus, 4) self.heightQLE = utils.create_LineEdit((70, 16777215), digits_validator_minus, 4) label = QLabel('<html><p align="center">x</p></html>') layout1 = utils.add_to_layout('h', self.widthQLE, label, self.heightQLE) self.aspect1QLE = utils.create_LineEdit((50, 16777215), digits_validator, 2) self.aspect2QLE = utils.create_LineEdit((50, 16777215), digits_validator, 2) label = QLabel('<html><p align="center">:</p></html>') layout2 = utils.add_to_layout('h', self.aspect1QLE, label, self.aspect2QLE) self.frameQLE = utils.create_LineEdit((120, 16777215), digits_validator, 4) self.bitrateQLE = utils.create_LineEdit((130, 16777215), digits_validator, 6) labels = [sizeQL, aspectQL, frameQL, bitrateQL] widgets = [layout1, layout2, self.frameQLE, self.bitrateQLE] self.preserveaspectQChB = QCheckBox(self.tr("Preserve aspect ratio")) self.preservesizeQChB = QCheckBox(self.tr("Preserve video size")) preserve_layout = utils.add_to_layout('v', self.preserveaspectQChB, self.preservesizeQChB) videosettings_layout = QHBoxLayout() for a, b in zip(labels, widgets): a.setText('<html><p align="center">{0}</p></html>'.format( a.text())) layout = utils.add_to_layout('v', a, b) videosettings_layout.addLayout(layout) if a == aspectQL: # add vidaspectCB in layout after aspectQL videosettings_layout.addLayout(preserve_layout) freqQL = QLabel(self.tr('Frequency (Hz):')) chanQL = QLabel(self.tr('Audio Channels:')) bitrateQL = QLabel(self.tr('Audio Bitrate (kbps):')) threadsQL = QLabel(self.tr('Threads:')) self.freqQCB = QComboBox() self.freqQCB.addItems(frequency_values) self.chan1QRB = QRadioButton('1') self.chan1QRB.setMaximumSize(QSize(51, 16777215)) self.chan2QRB = QRadioButton('2') self.chan2QRB.setMaximumSize(QSize(51, 16777215)) self.group = QButtonGroup() self.group.addButton(self.chan1QRB) self.group.addButton(self.chan2QRB) spcr1 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum) spcr2 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum) chanlayout = utils.add_to_layout('h', spcr1, self.chan1QRB, self.chan2QRB, spcr2) self.audbitrateQCB = QComboBox() self.audbitrateQCB.addItems(bitrate_values) self.threadsQLE = utils.create_LineEdit((50, 16777215), digits_validator_wzero, 1) labels = [freqQL, bitrateQL, chanQL, threadsQL] widgets = [ self.freqQCB, self.audbitrateQCB, chanlayout, self.threadsQLE ] audiosettings_layout = QHBoxLayout() for a, b in zip(labels, widgets): a.setText('<html><p align="center">{0}</p></html>'.format( a.text())) layout = utils.add_to_layout('v', a, b) audiosettings_layout.addLayout(layout) time_format = " (hh:mm:ss):" beginQL = QLabel(self.tr("Split file. Begin time") + time_format) self.beginQLE = utils.create_LineEdit(None, time_validator, None) durationQL = QLabel(self.tr("Duration") + time_format) self.durationQLE = utils.create_LineEdit(None, time_validator, None) hlayout4 = utils.add_to_layout('h', beginQL, self.beginQLE, durationQL, self.durationQLE) embedQL = QLabel(self.tr("Embed subtitle:")) self.embedQLE = QLineEdit() self.embedQTB = QToolButton() self.embedQTB.setText("...") rotateQL = QLabel(self.tr("Rotate:")) self.rotateQCB = QComboBox() self.rotateQCB.addItems(rotation_options) hlayout5 = utils.add_to_layout('h', rotateQL, self.rotateQCB, embedQL, self.embedQLE, self.embedQTB) hidden_layout = utils.add_to_layout('v', videosettings_layout, audiosettings_layout, hlayout4, hlayout5) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.moreQPB = QPushButton(QApplication.translate('Tab', 'More')) self.moreQPB.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.moreQPB.setCheckable(True) hlayout3 = utils.add_to_layout('h', line, self.moreQPB) self.frame = QFrame() self.frame.setLayout(hidden_layout) self.frame.hide() final_layout = utils.add_to_layout('v', hlayout1, hlayout2, hlayout3, self.frame) self.setLayout(final_layout) self.presetQPB.clicked.connect(self.choose_preset) self.defaultQPB.clicked.connect(self.set_default_command) self.embedQTB.clicked.connect(self.open_subtitle_file) self.moreQPB.toggled.connect(self.frame.setVisible) self.moreQPB.toggled.connect( lambda: QTimer.singleShot(100, self.resize_parent)) self.widthQLE.textChanged.connect(self.command_update_size) self.heightQLE.textChanged.connect(self.command_update_size) self.aspect1QLE.textChanged.connect(self.command_update_aspect) self.aspect2QLE.textChanged.connect(self.command_update_aspect) self.frameQLE.textChanged.connect(self.command_update_frames) self.bitrateQLE.textChanged.connect(self.command_update_vidbitrate) self.threadsQLE.textChanged.connect(self.command_update_threads) self.beginQLE.textChanged.connect(self.command_update_begin_time) self.durationQLE.textChanged.connect(self.command_update_duration) self.embedQLE.textChanged.connect(self.command_update_subtitles) self.vidcodecQCB.currentIndexChanged.connect( self.command_update_vcodec) self.audcodecQCB.currentIndexChanged.connect( self.command_update_acodec) self.freqQCB.currentIndexChanged.connect(self.command_update_frequency) self.rotateQCB.currentIndexChanged.connect( self.command_update_rotation) self.audbitrateQCB.currentIndexChanged.connect( self.command_update_audbitrate) self.chan1QRB.clicked.connect( lambda: self.command_update_channels('1')) self.chan2QRB.clicked.connect( lambda: self.command_update_channels('2')) self.preserveaspectQChB.toggled.connect( self.command_update_preserve_aspect) self.preservesizeQChB.toggled.connect( self.command_update_preserve_size) def resize_parent(self): """Give MainWindow its default size.""" self.parent.setMinimumSize(self.parent.sizeHint()) self.parent.resize(self.parent.sizeHint()) def clear(self): """Clear all values of graphical widgets.""" lines = [ self.commandQLE, self.widthQLE, self.heightQLE, self.aspect1QLE, self.aspect2QLE, self.frameQLE, self.bitrateQLE, self.threadsQLE, self.beginQLE, self.embedQLE, self.durationQLE ] for i in lines: i.clear() self.vidcodecQCB.setCurrentIndex(0) self.audcodecQCB.setCurrentIndex(0) self.freqQCB.setCurrentIndex(0) self.audbitrateQCB.setCurrentIndex(0) self.rotateQCB.setCurrentIndex(0) self.preserveaspectQChB.setChecked(False) self.preservesizeQChB.setChecked(False) self.group.setExclusive(False) self.chan1QRB.setChecked(False) self.chan2QRB.setChecked(False) self.group.setExclusive(True) # setExclusive(False) in order to be able to uncheck checkboxes and # then setExclusive(True) so only one radio button can be set def fill_video_comboboxes(self, vcodecs, acodecs, extraformats): vcodecs = [i for i in vcodecs.split("\n")] if vcodecs else [] acodecs = [i for i in acodecs.split("\n")] if acodecs else [] extraformats = [i for i in extraformats.split("\n") ] if extraformats else [] self.vidcodecQCB.currentIndexChanged.disconnect() self.audcodecQCB.currentIndexChanged.disconnect() self.vidcodecQCB.clear() self.audcodecQCB.clear() self.extQCB.clear() self.vidcodecQCB.addItems([self.defaultStr, self.DisableStream] + vcodecs) self.audcodecQCB.addItems([self.defaultStr, self.DisableStream] + acodecs) self.extQCB.addItems(sorted(self.formats + extraformats)) self.vidcodecQCB.currentIndexChanged.connect( self.command_update_vcodec) self.audcodecQCB.currentIndexChanged.connect( self.command_update_acodec) def ok_to_continue(self): """ Check if everything is ok with audiovideotab to continue conversion. Check if: - Either ffmpeg or avconv are installed. Return True if all tests pass, else False. """ if self.parent.vidconverter is None: QMessageBox.warning( self, 'FF Multi Converter - ' + self.tr('Error!'), self. tr('Neither ffmpeg nor libav are installed.' '\nYou will not be able to convert audio/video files until you' ' install one of them.')) return False return True def open_subtitle_file(self): """ Get the filename using standard QtDialog and update embedQLE's text. """ fname = QFileDialog.getOpenFileName( self, 'FF Multi Converter - ' + self.tr('Choose File'), config.home, 'Subtitles (*.srt *.sub *.ssa *.ass)') if fname: self.embedQLE.setText(fname) def set_default_command(self): """Set the default value to self.commandQLE.""" self.clear() self.commandQLE.setText(self.parent.default_command) def choose_preset(self): """ Open the presets dialog and update self.commandQLE, and self.extQCB and with the appropriate values. """ dialog = presets_dlgs.ShowPresets(choose=True) if dialog.exec_() and dialog.the_command is not None: self.clear() self.commandQLE.setText(dialog.the_command) self.commandQLE.home(False) find = self.extQCB.findText(dialog.the_extension) if find >= 0: self.extQCB.setCurrentIndex(find) def command_update_size(self): command = self.commandQLE.text() text1 = self.widthQLE.text() text2 = self.heightQLE.text() if not (text1 == '-1' or text2 == '-1'): self.preserveaspectQChB.setChecked(False) if (text1 or text2) and not (text1 and text2) or (text1 == '-' or text2 == '-'): return regex = r'(\s+|^)-s(:v){0,1}\s+\d+x\d+(\s+|$)' if re.search(regex, command): command = re.sub(regex, '', command) regex = r'(,*\s*){0,1}(scale=-?\d+:-?\d+)(\s*,*\s*){0,1}' _filter = "scale={0}:{1}".format(text1, text2) if text1 and text2 else '' self.commandQLE.setText( utils.update_cmdline_text(command, _filter, regex, bool(text1 and text2), 0, 2)) def command_update_preserve_size(self): checked = self.preservesizeQChB.isChecked() self.widthQLE.setEnabled(not checked) self.heightQLE.setEnabled(not checked) if checked: self.widthQLE.clear() self.heightQLE.clear() # command_update_size() is triggered here command = self.commandQLE.text() regex = r'(\s+|^)-s\s+\d+x\d+(\s+|$)' command = re.sub(' +', ' ', re.sub(regex, ' ', command)).strip() self.commandQLE.setText(command) def command_update_aspect(self): command = self.commandQLE.text() text1 = self.aspect1QLE.text() text2 = self.aspect2QLE.text() if (text1 or text2) and not (text1 and text2): return regex = r'(\s+|^)-aspect\s+\d+:\d+(\s+|$)' s = ' -aspect {0}:{1} '.format(text1, text2) if text1 and text2 else ' ' if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(' +', ' ', command).strip() self.commandQLE.setText(command) def command_update_preserve_aspect(self): command = self.commandQLE.text() checked = self.preserveaspectQChB.isChecked() self.aspect1QLE.setEnabled(not checked) self.aspect2QLE.setEnabled(not checked) if checked: self.aspect1QLE.clear() self.aspect2QLE.clear() # self.command_update_aspect() is triggered here regex = r'(,*\s*){0,1}(scale=(-?\d+):(-?\d+))(\s*,*\s*){0,1}' search = re.search(regex, command) if search: width = search.groups()[2] height = search.groups()[3] if not (width == '-1' or height == '-1'): s = "scale=-1:{0}".format(height) command = re.sub(regex, r'\1{0}\5'.format(s), command) self.widthQLE.setText('-1') self.heightQLE.setText(height) regex = r'(\s+|^)-aspect\s+\d+:\d+(\s+|$)' command = re.sub(' +', ' ', re.sub(regex, ' ', command)).strip() self.commandQLE.setText(command) def command_update_frames(self): command = self.commandQLE.text() text = self.frameQLE.text() regex = r'(\s+|^)-r\s+\d+(\s+|$)' s = ' -r {0} '.format(text) if text else ' ' if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(' +', ' ', command).strip() self.commandQLE.setText(command) def command_update_vidbitrate(self): command = self.commandQLE.text() text = self.bitrateQLE.text() regex = r'(\s+|^)-b(:v){0,1}\s+\d+[kKmM](\s+|$)' s = ' -b:v {0}k '.format(text) if text else ' ' if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub('-sameq', '', command) command = re.sub(' +', ' ', command).strip() self.commandQLE.setText(command) def command_update_frequency(self): command = self.commandQLE.text() text = self.freqQCB.currentText() regex = r'(\s+|^)-ar\s+\d+(\s+|$)' s = ' -ar {0} '.format( text) if self.freqQCB.currentIndex() != 0 else ' ' if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(' +', ' ', command).strip() self.commandQLE.setText(command) def command_update_audbitrate(self): command = self.commandQLE.text() text = self.audbitrateQCB.currentText() regex = r'(\s+|^)-(ab|b:a)\s+\d+[kKmM](\s+|$)' if self.audbitrateQCB.currentIndex() != 0: s = ' -b:a {0}k '.format(text) else: s = ' ' if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(' +', ' ', command).strip() self.commandQLE.setText(command) def command_update_channels(self, channel): command = self.commandQLE.text() regex = r'(\s+|^)-ac\s+\d+(\s+|$)' s = ' -ac {0} '.format(channel) if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(' +', ' ', command).strip() self.commandQLE.setText(command) def command_update_threads(self): command = self.commandQLE.text() text = self.threadsQLE.text() regex = r'(\s+|^)-threads\s+\d+(\s+|$)' s = ' -threads {0} '.format(text) if text else ' ' if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(' +', ' ', command).strip() self.commandQLE.setText(command) def command_update_begin_time(self): command = self.commandQLE.text() text = self.beginQLE.text() regex = r'(\s+|^)-ss\s+\S+(\s+|$)' s = ' -ss {0} '.format(text) if text else ' ' if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(' +', ' ', command).strip() self.commandQLE.setText(command) def command_update_duration(self): command = self.commandQLE.text() text = self.durationQLE.text() regex = r'(\s+|^)-t\s+\S+(\s+|$)' s = ' -t {0} '.format(text) if text else ' ' if re.search(regex, command): command = re.sub(regex, s, command) else: command += s command = re.sub(' +', ' ', command).strip() self.commandQLE.setText(command) def command_update_vcodec(self): command = self.commandQLE.text() text = self.vidcodecQCB.currentText() regex = r'(\s+|^)-(vcodec|c:v)\s+\S+(\s+|$)' regex_vn = r'(\s+|^)-vn(\s+|$)' if self.vidcodecQCB.currentIndex() == 1: s = ' -vn '.format(text) elif self.vidcodecQCB.currentIndex() == 0: s = ' ' else: s = ' -vcodec {0} '.format(text) if re.search(regex, command): command = re.sub(regex, s, command) elif re.search(regex_vn, command): command = re.sub(regex_vn, s, command) else: command += s command = re.sub(' +', ' ', command).strip() self.commandQLE.setText(command) def command_update_acodec(self): command = self.commandQLE.text() text = self.audcodecQCB.currentText() regex = r'(\s+|^)-(acodec|c:a)\s+\S+(\s+|$)' regex_an = r'(\s+|^)-an(\s+|$)' if self.audcodecQCB.currentIndex() == 1: s = ' -an '.format(text) elif self.audcodecQCB.currentIndex() == 0: s = ' ' else: s = ' -acodec {0} '.format(text) if re.search(regex, command): command = re.sub(regex, s, command) elif re.search(regex_an, command): command = re.sub(regex_an, s, command) else: command += s command = re.sub(' +', ' ', command).strip() self.commandQLE.setText(command) def command_update_subtitles(self): command = self.commandQLE.text() regex = r'(,*\s*){0,1}(subtitles=\'.*\')(\s*,*\s*){0,1}' text = self.embedQLE.text() _filter = "subtitles='{0}'".format(text) if text else '' self.commandQLE.setText( utils.update_cmdline_text(command, _filter, regex, bool(text), 0, 2)) def command_update_rotation(self): command = self.commandQLE.text() regex = r'(,*\s*){0,1}(transpose=\d(,\s*transpose=\d)*|vflip|hflip)(\s*,*\s*){0,1}' rotate = self.rotateQCB.currentIndex() if rotate == 0: # none _filter = '' elif rotate == 1: # 90 clockwise _filter = 'transpose=1' elif rotate == 2: # 90 clockwise + vertical flip _filter = 'transpose=3' elif rotate == 3: # 90 counter clockwise _filter = 'transpose=2' elif rotate == 4: # 90 counter clockwise + vertical flip _filter = 'transpose=0' elif rotate == 5: # 180 _filter = 'transpose=2,transpose=2' elif rotate == 6: # horizontal flip _filter = 'hflip' elif rotate == 7: # vertical flip _filter = 'vflip' self.commandQLE.setText( utils.update_cmdline_text(command, _filter, regex, bool(rotate != 0), 0, 3))
class QtSubsetBrowserClient(QMainWindow, core.client.Client): """ QT class to edit subset colors """ def __init__(self, data, parent=None): core.client.Client.__init__(self, data) QMainWindow.__init__(self, parent) self.setWindowTitle("Subset Selection") self.subset_widgets = {} self.create_main_frame() def register_to_hub(self, hub): core.client.Client.register_to_hub(self, hub) hub.subscribe(self, msg.ActiveSubsetUpdateMessage, handler=self._update_active_subset, filter=lambda x: \ x.sender.is_compatible(self.data)) def _update_active_subset(self, message): subset = message.sender widget = self.subset_widgets[subset] if not widget['check'].isChecked(): widget['check'].toggle() def _add_subset(self, message): """ Add a new subset to the panel """ s = message.sender width = 50 height = 50 pm = QPixmap(width, height) color = mpl_to_qt4_color(s.style.color) pm.fill(color) icon = QIcon(pm) layer = QHBoxLayout() check = QCheckBox("") check.setChecked(False) self.connect(check, SIGNAL('stateChanged(int)'), self.on_check) widget = QPushButton(icon, "") self.connect(widget, SIGNAL('clicked()'), self.on_push) layer.addWidget(check) layer.addWidget(widget) self.layout.addLayout(layer) self.subset_widgets[s] = {'layer':layer, 'widget':widget, 'check':check, 'pixmap':pm} # make sure buttons are exclusive self.check_group.addButton(check) def _remove_subset(self, message): pass def _update_all(self, message): pass def _update_subset(self, message): """ When a subset is updated, sync its color on the browser """ subset = message.sender color = mpl_to_qt4_color(subset.style.color) pm = self.subset_widgets[subset]['pixmap'] pm.fill(color) icon = QIcon(pm) self.subset_widgets[subset]['widget'].setIcon(icon) def on_check(self): """ When a checkbox is pressed, update the active subset """ source = self.sender() for key in self.subset_widgets: check = self.subset_widgets[key]['check'] if check is source: self.data.set_active_subset(key) def on_push(self): """ When a subset color button is pushed, update the color """ source = self.sender() for key in self.subset_widgets: button = self.subset_widgets[key]['widget'] if button == source: dialog = QColorDialog() initial = mpl_to_qt4_color(key.style.color) color = dialog.getColor(initial = initial) key.style.color = qt4_to_mpl_color(color) def create_main_frame(self): """ Create the main UI """ self.main_frame = QWidget() self.layout = QVBoxLayout() for s in self.data.subsets: self._add_subset(core.message.SubsetAddMessage(s)) self.main_frame.setLayout(self.layout) self.setCentralWidget(self.main_frame) self.check_group = QButtonGroup() self.check_group.setExclusive(True)
class DateTimePickerDialog(QDialog): """ A custom date picker with a time and date picker """ def __init__(self, mode="DateTime"): QDialog.__init__(self) # Set up the user interface from Designer. self.ui = Ui_datatimerpicker() self.ui.setupUi(self) self.mode = mode self.group = QButtonGroup() self.group.setExclusive(True) self.group.addButton(self.ui.ambutton) self.group.addButton(self.ui.pmbutton) self.ui.ambutton.toggled.connect(self.isDirty) self.ui.pmbutton.toggled.connect(self.isDirty) self.ui.datepicker.selectionChanged.connect(self.isDirty) self.ui.hourpicker.itemSelectionChanged.connect(self.isDirty) self.ui.minutepicker.itemSelectionChanged.connect(self.isDirty) self.ui.buttonBox.accepted.connect(self.accept) self.ui.buttonBox.rejected.connect(self.reject) self.ui.setasnowbutton.pressed.connect(self.setAsNow) self.setWindowFlags(Qt.Dialog | Qt.CustomizeWindowHint) if mode == "Date": self.ui.timesection.hide() self.ui.setasnowbutton.setText("Set as current date") elif mode == "Time": self.ui.datepicker.hide() self.ui.setasnowbutton.setText("Set as current time") def isDirty(self, *args): date = self.getSelectedDate() time = self.getSelectedTime() datetime = QDateTime(date, time) if self.mode == "Date": value = datetime.toString("ddd d MMM yyyy") elif self.mode == "Time": value = datetime.toString("h:m ap") else: value = datetime.toString("ddd d MMM yyyy 'at' h:m ap") self.ui.label.setText(value) def setDateTime(self, datetime): """ Set the picker to datatime datetime - The QDateTime with the value to set. """ self.setTime(datetime.time()) self.setDate(datetime.date()) def setAsNow(self): """ Set the current date and time on the picker as now. """ now = QDateTime.currentDateTime() self.setDateTime(now) def setTime(self, time): """ Set just the time part of the picker """ hour = time.hour() if hour > 12: hour = hour - 12 if hour == 0: hour = hour + 12 minute = time.minute() minute = int(round(minute / 5.0) * 5.0) amap = time.toString("AP") log("Hour %s Minute %s" % (hour, minute)) try: houritems = self.ui.hourpicker.findItems(str(hour), Qt.MatchFixedString) self.ui.hourpicker.setCurrentItem(houritems[0]) except IndexError: log("Can't find hour") try: minuteitems = self.ui.minutepicker.findItems( str(minute), Qt.MatchFixedString) self.ui.minutepicker.setCurrentItem(minuteitems[0]) except IndexError: log("Can't find minute") if amap == "PM": self.ui.pmbutton.toggle() def setDate(self, date): """ Set just the date part of the picker """ self.ui.datepicker.setSelectedDate(date) def getSelectedTime(self): """ Returns the currently selected data and time """ try: hour = self.ui.hourpicker.currentItem().text() except AttributeError: hour = "" try: minute = self.ui.minutepicker.currentItem().text() except AttributeError: minute = "" zone = self.ui.ambutton.isChecked() and "AM" or "PM" return QTime.fromString("%s%s%s" % (hour, minute, zone), "hmAP") def getSelectedDate(self): """ Returns just the date part of the picker """ return self.ui.datepicker.selectedDate()
class AudioVideoTab(QWidget): def __init__(self, parent): super(AudioVideoTab, self).__init__(parent) self.parent = parent self.name = 'AudioVideo' self.formats = ['3gp', 'aac', 'ac3', 'afc', 'aiff', 'amr', 'asf', 'au', 'avi', 'dvd', 'flac', 'flv', 'mka', 'mkv', 'mmf', 'mov', 'mp3', 'mp4', 'mpg', 'ogg', 'ogv', 'psp', 'rm', 'spx', 'vob', 'wav', 'webm', 'wma', 'wmv'] self.extra_formats = ['aifc', 'm2t', 'm4a', 'm4v', 'mp2', 'mpeg', 'ra', 'ts'] nochange = self.tr('No Change') frequency_values = [nochange, '22050', '44100', '48000'] bitrate_values = [nochange, '32', '96', '112', '128', '160', '192', '256', '320'] pattern = QRegExp(r'^[1-9]\d*') validator = QRegExpValidator(pattern, self) converttoLabel = QLabel(self.tr('Convert to:')) self.extComboBox = QComboBox() self.extComboBox.addItems(self.formats + [self.tr('Other')]) self.extComboBox.setMinimumWidth(130) self.extLineEdit = QLineEdit() self.extLineEdit.setMaximumWidth(85) self.extLineEdit.setEnabled(False) hlayout1 = pyqttools.add_to_layout(QHBoxLayout(), converttoLabel, None, self.extComboBox, self.extLineEdit) commandLabel = QLabel(self.tr('Command:')) self.commandLineEdit = QLineEdit() self.presetButton = QPushButton(self.tr('Preset')) self.defaultButton = QPushButton(self.tr('Default')) hlayout2 = pyqttools.add_to_layout(QHBoxLayout(), commandLabel, self.commandLineEdit, self.presetButton, self.defaultButton) sizeLabel = QLabel(self.tr('Video Size:')) aspectLabel = QLabel(self.tr('Aspect:')) frameLabel = QLabel(self.tr('Frame Rate (fps):')) bitrateLabel = QLabel(self.tr('Video Bitrate (kbps):')) self.widthLineEdit = pyqttools.create_LineEdit((50, 16777215), validator, 4) self.heightLineEdit = pyqttools.create_LineEdit((50, 16777215), validator,4) label = QLabel('x') layout1 = pyqttools.add_to_layout(QHBoxLayout(), self.widthLineEdit, label, self.heightLineEdit) self.aspect1LineEdit = pyqttools.create_LineEdit((35, 16777215), validator,2) self.aspect2LineEdit = pyqttools.create_LineEdit((35, 16777215), validator,2) label = QLabel(':') layout2 = pyqttools.add_to_layout(QHBoxLayout(), self.aspect1LineEdit, label, self.aspect2LineEdit) self.frameLineEdit = pyqttools.create_LineEdit(None, validator, 4) self.bitrateLineEdit = pyqttools.create_LineEdit(None, validator, 6) labels = [sizeLabel, aspectLabel, frameLabel, bitrateLabel] widgets = [layout1, layout2, self.frameLineEdit, self.bitrateLineEdit] videosettings_layout = QHBoxLayout() for a, b in zip(labels, widgets): text = a.text() a.setText('<html><p align="center">{0}</p></html>'.format(text)) layout = pyqttools.add_to_layout(QVBoxLayout(), a, b) videosettings_layout.addLayout(layout) freqLabel = QLabel(self.tr('Frequency (Hz):')) chanLabel = QLabel(self.tr('Channels:')) bitrateLabel = QLabel(self.tr('Audio Bitrate (kbps):')) self.freqComboBox = QComboBox() self.freqComboBox.addItems(frequency_values) self.chan1RadioButton = QRadioButton('1') self.chan1RadioButton.setMaximumSize(QSize(51, 16777215)) self.chan2RadioButton = QRadioButton('2') self.chan2RadioButton.setMaximumSize(QSize(51, 16777215)) self.group = QButtonGroup() self.group.addButton(self.chan1RadioButton) self.group.addButton(self.chan2RadioButton) spcr1 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum) spcr2 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum) chanlayout = pyqttools.add_to_layout(QHBoxLayout(), spcr1, self.chan1RadioButton, self.chan2RadioButton, spcr2) self.audio_bitrateComboBox = QComboBox() self.audio_bitrateComboBox.addItems(bitrate_values) labels = [freqLabel, chanLabel, bitrateLabel] widgets = [self.freqComboBox, chanlayout, self.audio_bitrateComboBox] audiosettings_layout = QHBoxLayout() for a, b in zip(labels, widgets): text = a.text() a.setText('<html><p align="center">{0}</p></html>'.format(text)) layout = pyqttools.add_to_layout(QVBoxLayout(), a, b) audiosettings_layout.addLayout(layout) hidden_layout = pyqttools.add_to_layout(QVBoxLayout(), videosettings_layout, audiosettings_layout) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.moreButton = QPushButton(QApplication.translate('Tab', 'More')) self.moreButton.setSizePolicy(QSizePolicy(QSizePolicy.Fixed)) self.moreButton.setCheckable(True) hlayout3 = pyqttools.add_to_layout(QHBoxLayout(), line, self.moreButton) self.frame = QFrame() self.frame.setLayout(hidden_layout) self.frame.hide() final_layout = pyqttools.add_to_layout(QVBoxLayout(), hlayout1, hlayout2, hlayout3, self.frame) self.setLayout(final_layout) self.presetButton.clicked.connect(self.choose_preset) self.defaultButton.clicked.connect(self.set_default_command) self.moreButton.toggled.connect(self.frame.setVisible) self.moreButton.toggled.connect(self.resize_parent) self.extComboBox.currentIndexChanged.connect( lambda: self.extLineEdit.setEnabled( self.extComboBox.currentIndex() == len(self.formats))) self.widthLineEdit.textChanged.connect( lambda: self.command_elements_change('size')) self.heightLineEdit.textChanged.connect( lambda: self.command_elements_change('size')) self.aspect1LineEdit.textChanged.connect( lambda: self.command_elements_change('aspect')) self.aspect2LineEdit.textChanged.connect( lambda: self.command_elements_change('aspect')) self.frameLineEdit.textChanged.connect( lambda: self.command_elements_change('frames')) self.bitrateLineEdit.textChanged.connect( lambda: self.command_elements_change('video_bitrate')) self.freqComboBox.currentIndexChanged.connect( lambda: self.command_elements_change('frequency')) self.audio_bitrateComboBox.currentIndexChanged.connect( lambda: self.command_elements_change('audio_bitrate')) self.chan1RadioButton.clicked.connect( lambda: self.command_elements_change('channels1')) self.chan2RadioButton.clicked.connect( lambda: self.command_elements_change('channels2')) def resize_parent(self): """Resize MainWindow.""" height = MAIN_FIXED_HEIGHT if self.frame.isVisible() else MAIN_HEIGHT self.parent.setMinimumSize(MAIN_WIDTH, height) self.parent.resize(MAIN_WIDTH, height) def clear(self): """Clear all values of graphical widgets.""" lines = [self.commandLineEdit, self.widthLineEdit, self.heightLineEdit, self.aspect1LineEdit, self.aspect2LineEdit, self.frameLineEdit, self.bitrateLineEdit, self.extLineEdit] for i in lines: i.clear() self.freqComboBox.setCurrentIndex(0) self.audio_bitrateComboBox.setCurrentIndex(0) self.group.setExclusive(False) self.chan1RadioButton.setChecked(False) self.chan2RadioButton.setChecked(False) self.group.setExclusive(True) # setExclusive(False) in order to be able to uncheck checkboxes and # then setExclusive(True) so only one radio button can be set def ok_to_continue(self): """ Check if everything is ok with audiovideotab to continue conversion. Check if: - Either ffmpeg or avconv are installed. - Desired extension is valid. - self.commandLineEdit is empty. Return True if all tests pass, else False. """ if not self.parent.ffmpeg and not self.parent.avconv: QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr( 'Error!'), self.tr('Neither ffmpeg nor avconv are installed.' '\nYou will not be able to convert audio/video files until you' ' install one of them.')) return False if self.extLineEdit.isEnabled(): text = str(self.extLineEdit.text()).strip() if len(text.split()) != 1 or text[0] == '.': QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr( 'Error!'), self.tr('Extension must be one word and must ' 'not start with a dot.')) self.extLineEdit.selectAll() self.extLineEdit.setFocus() return False if not self.commandLineEdit.text(): QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr( 'Error!'), self.tr('The command LineEdit may not be empty.')) self.commandLineEdit.setFocus() return False return True def set_default_command(self): """Set the default value to self.commandLineEdit.""" self.clear() self.commandLineEdit.setText(self.parent.default_command) def choose_preset(self): """ Open the presets dialog and update self.commandLineEdit, self.extComboBox and self.extLineEdit with the appropriate values. """ dialog = presets_dlgs.ShowPresets() if dialog.exec_() and dialog.the_command is not None: self.commandLineEdit.setText(dialog.the_command) self.commandLineEdit.home(False) find = self.extComboBox.findText(dialog.the_extension) if find >= 0: self.extComboBox.setCurrentIndex(find) else: self.extComboBox.setCurrentIndex(len(self.formats)) self.extLineEdit.setText(dialog.the_extension) def remove_consecutive_spaces(self, string): """Remove any consecutive spaces from a string and return it.""" temp = string string = '' for i in temp.split(): if i: string += i + ' ' return string[:-1] def command_elements_change(self, widget): """Fill self.commandLineEdit with the appropriate command parameters.""" command = str(self.commandLineEdit.text()) if widget == 'size': text1 = self.widthLineEdit.text() text2 = self.heightLineEdit.text() if (text1 or text2) and not (text1 and text2): return f = re.sub(r'^.*(-s\s+\d+x\d+).*$', r'\1', command) if re.match(r'^.*(-s\s+\d+x\d+).*$', f): command = command.replace(f, '').strip() if text1 and text2: command += ' -s {0}x{1}'.format(text1, text2) elif widget == 'aspect': text1 = self.aspect1LineEdit.text() text2 = self.aspect2LineEdit.text() if (text1 or text2) and not (text1 and text2): return f = re.sub(r'^.*(-aspect\s+\d+:\d+).*$', r'\1', command) if re.match(r'^.*(-aspect\s+\d+:\d+).*$', f): command = command.replace(f, '').strip() if text1 and text2: command += ' -aspect {0}:{1}'.format(text1, text2) elif widget == 'frames': text = self.frameLineEdit.text() f = re.sub(r'^.*(-r\s+\d+).*$', r'\1', command) if re.match(r'^.*(-r\s+\d+).*$', f): command = command.replace(f, '').strip() if text: command += ' -r {0}'.format(text) elif widget == 'video_bitrate': text = self.bitrateLineEdit.text() f = re.sub(r'^.*(-b\s+\d+k).*$', r'\1', command) if re.match(r'^.*(-b\s+\d+k).*$', f): command = command.replace(f, '') if text: command += ' -b {0}k'.format(text) command = command.replace('-sameq', '').strip() elif widget == 'frequency': text = self.freqComboBox.currentText() f = re.sub(r'^.*(-ar\s+\d+).*$', r'\1', command) if re.match(r'^.*(-ar\s+\d+).*$', f): command = command.replace(f, '').strip() if text != 'No Change': command += ' -ar {0}'.format(text) elif widget == 'audio_bitrate': text = self.audio_bitrateComboBox.currentText() f = re.sub(r'^.*(-ab\s+\d+k).*$', r'\1', command) if re.match(r'^.*(-ab\s+\d+k).*$', f): command = command.replace(f, '').strip() if text != 'No Change': command += ' -ab {0}k'.format(text) elif widget in ('channels1', 'channels2'): text = self.chan1RadioButton.text() if widget == 'channels1' \ else self.chan2RadioButton.text() f = re.sub(r'^.*(-ac\s+\d+).*$', r'\1', command) if re.match(r'^.*(-ac\s+\d+).*$', f): command = command.replace(f, '').strip() command += ' -ac {0}'.format(text) self.commandLineEdit.clear() self.commandLineEdit.setText(self.remove_consecutive_spaces(command))
class OptionWidget(EditorWidget): widgettype = 'Option Row' def __init__(self, *args): super(OptionWidget, self).__init__(*args) self._bindvalue = None self.group = QButtonGroup() self.group.setExclusive(True) self.group.buttonClicked.connect(self.emitvaluechanged) def createWidget(self, parent): widget = QWidget(parent) widget.setLayout(QHBoxLayout()) widget.layout().setContentsMargins(0, 0, 0, 0) return widget def _buildfromlist(self, listconfig): items = listconfig['items'] for item in items: parts = item.split(';') data = parts[0] try: desc = parts[1] except IndexError: desc = data try: path = parts[2] if path.endswith("_icon"): icon = QIcon(":/icons/{}".format(path)) else: icon = QIcon(path) except: icon = QIcon() button = QPushButton() button.setCheckable(True) button.setText(desc) button.setProperty("value", data) button.setIcon(icon) button.setIconSize(QSize(24, 24)) self.widget.layout().addWidget(button) self.group.addButton(button) def initWidget(self, widget): pass def updatefromconfig(self): super(OptionWidget, self).updatefromconfig() listconfig = self.config['list'] self._buildfromlist(listconfig) super(OptionWidget, self).endupdatefromconfig() def validate(self, *args): button = self.group.checkedButton() if button: return True return False def setvalue(self, value): for button in self.group.buttons(): if button.property("value") == str(value): button.setChecked(True) return def value(self): button = self.group.checkedButton() if not button: return None return button.property("value")
class AudioVideoTab(QWidget): def __init__(self, parent): super(AudioVideoTab, self).__init__(parent) self.parent = parent self.name = 'AudioVideo' self.formats = [ '3gp', 'aac', 'ac3', 'afc', 'aiff', 'amr', 'asf', 'au', 'avi', 'dvd', 'flac', 'flv', 'mka', 'mkv', 'mmf', 'mov', 'mp3', 'mp4', 'mpg', 'ogg', 'ogv', 'psp', 'rm', 'spx', 'vob', 'wav', 'webm', 'wma', 'wmv' ] self.extra_formats = [ 'aifc', 'm2t', 'm4a', 'm4v', 'mp2', 'mpeg', 'ra', 'ts' ] nochange = self.tr('No Change') frequency_values = [nochange, '22050', '44100', '48000'] bitrate_values = [ nochange, '32', '96', '112', '128', '160', '192', '256', '320' ] pattern = QRegExp(r'^[1-9]\d*') validator = QRegExpValidator(pattern, self) converttoLabel = QLabel(self.tr('Convert to:')) self.extComboBox = QComboBox() self.extComboBox.addItems(self.formats + [self.tr('Other')]) self.extComboBox.setMinimumWidth(130) self.extLineEdit = QLineEdit() self.extLineEdit.setMaximumWidth(85) self.extLineEdit.setEnabled(False) hlayout1 = pyqttools.add_to_layout(QHBoxLayout(), converttoLabel, None, self.extComboBox, self.extLineEdit) commandLabel = QLabel(self.tr('Command:')) self.commandLineEdit = QLineEdit() self.presetButton = QPushButton(self.tr('Preset')) self.defaultButton = QPushButton(self.tr('Default')) hlayout2 = pyqttools.add_to_layout(QHBoxLayout(), commandLabel, self.commandLineEdit, self.presetButton, self.defaultButton) sizeLabel = QLabel(self.tr('Video Size:')) aspectLabel = QLabel(self.tr('Aspect:')) frameLabel = QLabel(self.tr('Frame Rate (fps):')) bitrateLabel = QLabel(self.tr('Video Bitrate (kbps):')) self.widthLineEdit = pyqttools.create_LineEdit((50, 16777215), validator, 4) self.heightLineEdit = pyqttools.create_LineEdit((50, 16777215), validator, 4) label = QLabel('x') layout1 = pyqttools.add_to_layout(QHBoxLayout(), self.widthLineEdit, label, self.heightLineEdit) self.aspect1LineEdit = pyqttools.create_LineEdit((35, 16777215), validator, 2) self.aspect2LineEdit = pyqttools.create_LineEdit((35, 16777215), validator, 2) label = QLabel(':') layout2 = pyqttools.add_to_layout(QHBoxLayout(), self.aspect1LineEdit, label, self.aspect2LineEdit) self.frameLineEdit = pyqttools.create_LineEdit(None, validator, 4) self.bitrateLineEdit = pyqttools.create_LineEdit(None, validator, 6) labels = [sizeLabel, aspectLabel, frameLabel, bitrateLabel] widgets = [layout1, layout2, self.frameLineEdit, self.bitrateLineEdit] videosettings_layout = QHBoxLayout() for a, b in zip(labels, widgets): text = a.text() a.setText('<html><p align="center">{0}</p></html>'.format(text)) layout = pyqttools.add_to_layout(QVBoxLayout(), a, b) videosettings_layout.addLayout(layout) freqLabel = QLabel(self.tr('Frequency (Hz):')) chanLabel = QLabel(self.tr('Channels:')) bitrateLabel = QLabel(self.tr('Audio Bitrate (kbps):')) self.freqComboBox = QComboBox() self.freqComboBox.addItems(frequency_values) self.chan1RadioButton = QRadioButton('1') self.chan1RadioButton.setMaximumSize(QSize(51, 16777215)) self.chan2RadioButton = QRadioButton('2') self.chan2RadioButton.setMaximumSize(QSize(51, 16777215)) self.group = QButtonGroup() self.group.addButton(self.chan1RadioButton) self.group.addButton(self.chan2RadioButton) spcr1 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum) spcr2 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum) chanlayout = pyqttools.add_to_layout(QHBoxLayout(), spcr1, self.chan1RadioButton, self.chan2RadioButton, spcr2) self.audio_bitrateComboBox = QComboBox() self.audio_bitrateComboBox.addItems(bitrate_values) labels = [freqLabel, chanLabel, bitrateLabel] widgets = [self.freqComboBox, chanlayout, self.audio_bitrateComboBox] audiosettings_layout = QHBoxLayout() for a, b in zip(labels, widgets): text = a.text() a.setText('<html><p align="center">{0}</p></html>'.format(text)) layout = pyqttools.add_to_layout(QVBoxLayout(), a, b) audiosettings_layout.addLayout(layout) hidden_layout = pyqttools.add_to_layout(QVBoxLayout(), videosettings_layout, audiosettings_layout) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.moreButton = QPushButton(QApplication.translate('Tab', 'More')) self.moreButton.setSizePolicy(QSizePolicy(QSizePolicy.Fixed)) self.moreButton.setCheckable(True) hlayout3 = pyqttools.add_to_layout(QHBoxLayout(), line, self.moreButton) self.frame = QFrame() self.frame.setLayout(hidden_layout) self.frame.hide() final_layout = pyqttools.add_to_layout(QVBoxLayout(), hlayout1, hlayout2, hlayout3, self.frame) self.setLayout(final_layout) self.presetButton.clicked.connect(self.choose_preset) self.defaultButton.clicked.connect(self.set_default_command) self.moreButton.toggled.connect(self.frame.setVisible) self.moreButton.toggled.connect(self.resize_parent) self.extComboBox.currentIndexChanged.connect( lambda: self.extLineEdit.setEnabled(self.extComboBox.currentIndex( ) == len(self.formats))) self.widthLineEdit.textChanged.connect( lambda: self.command_elements_change('size')) self.heightLineEdit.textChanged.connect( lambda: self.command_elements_change('size')) self.aspect1LineEdit.textChanged.connect( lambda: self.command_elements_change('aspect')) self.aspect2LineEdit.textChanged.connect( lambda: self.command_elements_change('aspect')) self.frameLineEdit.textChanged.connect( lambda: self.command_elements_change('frames')) self.bitrateLineEdit.textChanged.connect( lambda: self.command_elements_change('video_bitrate')) self.freqComboBox.currentIndexChanged.connect( lambda: self.command_elements_change('frequency')) self.audio_bitrateComboBox.currentIndexChanged.connect( lambda: self.command_elements_change('audio_bitrate')) self.chan1RadioButton.clicked.connect( lambda: self.command_elements_change('channels1')) self.chan2RadioButton.clicked.connect( lambda: self.command_elements_change('channels2')) def resize_parent(self): """Resize MainWindow.""" height = MAIN_FIXED_HEIGHT if self.frame.isVisible() else MAIN_HEIGHT self.parent.setMinimumSize(MAIN_WIDTH, height) self.parent.resize(MAIN_WIDTH, height) def clear(self): """Clear all values of graphical widgets.""" lines = [ self.commandLineEdit, self.widthLineEdit, self.heightLineEdit, self.aspect1LineEdit, self.aspect2LineEdit, self.frameLineEdit, self.bitrateLineEdit, self.extLineEdit ] for i in lines: i.clear() self.freqComboBox.setCurrentIndex(0) self.audio_bitrateComboBox.setCurrentIndex(0) self.group.setExclusive(False) self.chan1RadioButton.setChecked(False) self.chan2RadioButton.setChecked(False) self.group.setExclusive(True) # setExclusive(False) in order to be able to uncheck checkboxes and # then setExclusive(True) so only one radio button can be set def ok_to_continue(self): """ Check if everything is ok with audiovideotab to continue conversion. Check if: - Either ffmpeg or avconv are installed. - Desired extension is valid. - self.commandLineEdit is empty. Return True if all tests pass, else False. """ if not self.parent.ffmpeg and not self.parent.avconv: QMessageBox.warning( self, 'FF Multi Converter - ' + self.tr('Error!'), self. tr('Neither ffmpeg nor avconv are installed.' '\nYou will not be able to convert audio/video files until you' ' install one of them.')) return False if self.extLineEdit.isEnabled(): text = str(self.extLineEdit.text()).strip() if len(text.split()) != 1 or text[0] == '.': QMessageBox.warning( self, 'FF Multi Converter - ' + self.tr('Error!'), self.tr('Extension must be one word and must ' 'not start with a dot.')) self.extLineEdit.selectAll() self.extLineEdit.setFocus() return False if not self.commandLineEdit.text(): QMessageBox.warning( self, 'FF Multi Converter - ' + self.tr('Error!'), self.tr('The command LineEdit may not be empty.')) self.commandLineEdit.setFocus() return False return True def set_default_command(self): """Set the default value to self.commandLineEdit.""" self.clear() self.commandLineEdit.setText(self.parent.default_command) def choose_preset(self): """ Open the presets dialog and update self.commandLineEdit, self.extComboBox and self.extLineEdit with the appropriate values. """ dialog = presets_dlgs.ShowPresets() if dialog.exec_() and dialog.the_command is not None: self.commandLineEdit.setText(dialog.the_command) self.commandLineEdit.home(False) find = self.extComboBox.findText(dialog.the_extension) if find >= 0: self.extComboBox.setCurrentIndex(find) else: self.extComboBox.setCurrentIndex(len(self.formats)) self.extLineEdit.setText(dialog.the_extension) def remove_consecutive_spaces(self, string): """Remove any consecutive spaces from a string and return it.""" temp = string string = '' for i in temp.split(): if i: string += i + ' ' return string[:-1] def command_elements_change(self, widget): """Fill self.commandLineEdit with the appropriate command parameters.""" command = str(self.commandLineEdit.text()) if widget == 'size': text1 = self.widthLineEdit.text() text2 = self.heightLineEdit.text() if (text1 or text2) and not (text1 and text2): return f = re.sub(r'^.*(-s\s+\d+x\d+).*$', r'\1', command) if re.match(r'^.*(-s\s+\d+x\d+).*$', f): command = command.replace(f, '').strip() if text1 and text2: command += ' -s {0}x{1}'.format(text1, text2) elif widget == 'aspect': text1 = self.aspect1LineEdit.text() text2 = self.aspect2LineEdit.text() if (text1 or text2) and not (text1 and text2): return f = re.sub(r'^.*(-aspect\s+\d+:\d+).*$', r'\1', command) if re.match(r'^.*(-aspect\s+\d+:\d+).*$', f): command = command.replace(f, '').strip() if text1 and text2: command += ' -aspect {0}:{1}'.format(text1, text2) elif widget == 'frames': text = self.frameLineEdit.text() f = re.sub(r'^.*(-r\s+\d+).*$', r'\1', command) if re.match(r'^.*(-r\s+\d+).*$', f): command = command.replace(f, '').strip() if text: command += ' -r {0}'.format(text) elif widget == 'video_bitrate': text = self.bitrateLineEdit.text() f = re.sub(r'^.*(-b\s+\d+k).*$', r'\1', command) if re.match(r'^.*(-b\s+\d+k).*$', f): command = command.replace(f, '') if text: command += ' -b {0}k'.format(text) command = command.replace('-sameq', '').strip() elif widget == 'frequency': text = self.freqComboBox.currentText() f = re.sub(r'^.*(-ar\s+\d+).*$', r'\1', command) if re.match(r'^.*(-ar\s+\d+).*$', f): command = command.replace(f, '').strip() if text != 'No Change': command += ' -ar {0}'.format(text) elif widget == 'audio_bitrate': text = self.audio_bitrateComboBox.currentText() f = re.sub(r'^.*(-ab\s+\d+k).*$', r'\1', command) if re.match(r'^.*(-ab\s+\d+k).*$', f): command = command.replace(f, '').strip() if text != 'No Change': command += ' -ab {0}k'.format(text) elif widget in ('channels1', 'channels2'): text = self.chan1RadioButton.text() if widget == 'channels1' \ else self.chan2RadioButton.text() f = re.sub(r'^.*(-ac\s+\d+).*$', r'\1', command) if re.match(r'^.*(-ac\s+\d+).*$', f): command = command.replace(f, '').strip() command += ' -ac {0}'.format(text) self.commandLineEdit.clear() self.commandLineEdit.setText(self.remove_consecutive_spaces(command))
class DateTimePickerDialog(QDialog): """ A custom date picker with a time and date picker """ def __init__(self, mode="DateTime"): QDialog.__init__(self) # Set up the user interface from Designer. self.ui = Ui_datatimerpicker() self.ui.setupUi(self) self.group = QButtonGroup() self.group.setExclusive(True) self.group.addButton(self.ui.ambutton) self.group.addButton(self.ui.pmbutton) self.ui.ambutton.toggled.connect(self.isDirty) self.ui.pmbutton.toggled.connect(self.isDirty) self.ui.datepicker.selectionChanged.connect(self.isDirty) self.ui.hourpicker.itemSelectionChanged.connect(self.isDirty) self.ui.minutepicker.itemSelectionChanged.connect(self.isDirty) self.ui.buttonBox.accepted.connect(self.accept) self.ui.buttonBox.rejected.connect(self.reject) self.ui.setasnowbutton.pressed.connect(self.setAsNow) self.setWindowFlags(Qt.Dialog | Qt.CustomizeWindowHint) if mode == "Date": self.ui.hourpicker.hide() self.ui.minutepicker.hide() self.ui.ampmbutton.hide() elif mode == "Time": self.ui.datepicker.hide() def isDirty(self, *args): date = self.getSelectedDate() time = self.getSelectedTime() datetime = QDateTime(date, time) value = datetime.toString("ddd d MMM yyyy 'at' h:m ap") self.ui.label.setText(value) def setDateTime(self, datetime): """ Set the picker to datatime datetime - The QDateTime with the value to set. """ self.setTime(datetime.time()) self.setDate(datetime.date()) def setAsNow(self): """ Set the current date and time on the picker as now. """ now = QDateTime.currentDateTime() self.setDateTime(now) def setTime(self, time): """ Set just the time part of the picker """ hour = time.hour() if hour > 12: hour = hour - 12 if hour == 0: hour = hour + 12 minute = time.minute() minute = int(round(minute / 5.0) * 5.0) amap = time.toString("AP") log("Hour %s Minute %s" % (hour, minute)) try: houritems = self.ui.hourpicker.findItems(str(hour), Qt.MatchFixedString) self.ui.hourpicker.setCurrentItem(houritems[0]) except IndexError: log("Can't find hour") try: minuteitems = self.ui.minutepicker.findItems(str(minute), Qt.MatchFixedString) self.ui.minutepicker.setCurrentItem(minuteitems[0]) except IndexError: log("Can't find minute") if amap == "PM": self.ui.pmbutton.toggle() def setDate(self, date): """ Set just the date part of the picker """ self.ui.datepicker.setSelectedDate(date) def getSelectedTime(self): """ Returns the currently selected data and time """ try: hour = self.ui.hourpicker.currentItem().text() except AttributeError: hour = "" try: minute = self.ui.minutepicker.currentItem().text() except AttributeError: minute = "" zone = self.ui.ambutton.isChecked() and "AM" or "PM" return QTime.fromString("%s%s%s" % (hour, minute, zone), "hmAP") def getSelectedDate(self): """ Returns just the date part of the picker """ return self.ui.datepicker.selectedDate()
def __init__(self, parent, item): Ui_QgsComposerItemWidgetBase.__init__(self, parent, item) # self.setupUi( self ) self.mItem = item self.mFreezeXPosSpin = False self.mFreezeYPosSpin = False self.mFreezeWidthSpin = False self.mFreezeHeightSpin = False self.mFreezePageSpin = False #make button exclusive buttonGroup = QButtonGroup(self) buttonGroup.addButton(self.mUpperLeftCheckBox) buttonGroup.addButton(self.mUpperMiddleCheckBox) buttonGroup.addButton(self.mUpperRightCheckBox) buttonGroup.addButton(self.mMiddleLeftCheckBox) buttonGroup.addButton(self.mMiddleCheckBox) buttonGroup.addButton(self.mMiddleRightCheckBox) buttonGroup.addButton(self.mLowerLeftCheckBox) buttonGroup.addButton(self.mLowerMiddleCheckBox) buttonGroup.addButton(self.mLowerRightCheckBox) buttonGroup.setExclusive(True) # self.mXLineEdit.setValidator( QDoubleValidator( 0 ) ) # self.mYLineEdit.setValidator( QDoubleValidator( 0 ) ) # self.mWidthLineEdit.setValidator( QDoubleValidator( 0 ) ) # self.mHeightLineEdit.setValidator( QDoubleValidator( 0 ) ) self.setValuesForGuiElements() self.connect(self.mItem.composition(), SIGNAL("paperSizeChanged()"), self.setValuesForGuiPositionElements) self.connect(self.mItem, SIGNAL("sizeChanged()"), self.setValuesForGuiPositionElements) self.connect(self.mItem, SIGNAL("itemChanged()"), self.setValuesForGuiNonPositionElements) self.connect(self.mTransparencySlider, SIGNAL("valueChanged( int )"), self.mTransparencySpnBx, SLOT("setValue( int )")) self.updateVariables() self.connect(self.mVariableEditor, SIGNAL("scopeChanged()"), self.variablesChanged) # listen out for variable edits # QgsApplication* app = qobject_cast<QgsApplication*>( QgsApplication.instance() ); # if ( app ) # { # self.connect( app, SIGNAL( settingsChanged() ), this, SLOT( updateVariables() ) ); # } # self.connect( QgsProject.instance(), SIGNAL( variablesChanged() ), this, SLOT( updateVariables() ) ); if (self.mItem.composition()): self.connect(self.mItem.composition(), SIGNAL("variablesChanged()"), self.updateVariables) #self.connect atlas signals to data defined buttons atlas = self.atlasComposition() if (atlas): #repopulate data defined buttons if atlas layer changes self.connect(atlas, SIGNAL("coverageLayerChanged( QgsVectorLayer* )"), self.populateDataDefinedButtons) self.connect(atlas, SIGNAL("toggled( bool )"), self.populateDataDefinedButtons) #self.connect data defined buttons self.connect(self.mXPositionDDBtn, SIGNAL("dataDefinedChanged( const QString& )"), self.updateDataDefinedProperty) self.connect(self.mXPositionDDBtn, SIGNAL("dataDefinedActivated( bool )"), self.updateDataDefinedProperty) self.connect(self.mYPositionDDBtn, SIGNAL("dataDefinedChanged( const QString& )"), self.updateDataDefinedProperty) self.connect(self.mYPositionDDBtn, SIGNAL("dataDefinedActivated( bool )"), self.updateDataDefinedProperty) self.connect(self.mWidthDDBtn, SIGNAL("dataDefinedChanged( const QString& )"), self.updateDataDefinedProperty) self.connect(self.mWidthDDBtn, SIGNAL("dataDefinedActivated( bool )"), self.updateDataDefinedProperty) self.connect(self.mHeightDDBtn, SIGNAL("dataDefinedChanged( const QString& )"), self.updateDataDefinedProperty) self.connect(self.mHeightDDBtn, SIGNAL("dataDefinedActivated( bool )"), self.updateDataDefinedProperty) self.connect(self.mItemRotationDDBtn, SIGNAL("dataDefinedChanged( const QString& )"), self.updateDataDefinedProperty) self.connect(self.mItemRotationDDBtn, SIGNAL("dataDefinedActivated( bool )"), self.updateDataDefinedProperty) self.connect(self.mTransparencyDDBtn, SIGNAL("dataDefinedChanged( const QString& )"), self.updateDataDefinedProperty) self.connect(self.mTransparencyDDBtn, SIGNAL("dataDefinedActivated( bool )"), self.updateDataDefinedProperty) self.connect(self.mBlendModeDDBtn, SIGNAL("dataDefinedChanged( const QString& )"), self.updateDataDefinedProperty) self.connect(self.mBlendModeDDBtn, SIGNAL("dataDefinedActivated( bool )"), self.updateDataDefinedProperty) self.connect(self.mExcludePrintsDDBtn, SIGNAL("dataDefinedChanged( const QString& )"), self.updateDataDefinedProperty) self.connect(self.mExcludePrintsDDBtn, SIGNAL("dataDefinedActivated( bool )"), self.updateDataDefinedProperty) #content in QgsComposerItemWidget.h file self.mFrameColorButton.colorChanged.connect( self.on_mFrameColorButton_colorChanged) self.mBackgroundColorButton.clicked.connect( self.on_mBackgroundColorButton_clicked) self.mBackgroundColorButton.colorChanged.connect( self.on_mBackgroundColorButton_colorChanged) self.connect(self.mOutlineWidthSpinBox, SIGNAL("valueChanged( double )"), self.on_mOutlineWidthSpinBox_valueChanged) self.mFrameGroupBox.toggled.connect(self.on_mFrameGroupBox_toggled) self.mFrameJoinStyleCombo.currentIndexChanged.connect( self.on_mFrameJoinStyleCombo_currentIndexChanged) self.mBackgroundGroupBox.toggled.connect( self.on_mBackgroundGroupBox_toggled) self.mItemIdLineEdit.editingFinished.connect( self.on_mItemIdLineEdit_editingFinished) self.mPageSpinBox.valueChanged.connect( self.on_mPageSpinBox_valueChanged) self.mXPosSpin.valueChanged.connect(self.on_mXPosSpin_valueChanged) self.mYPosSpin.valueChanged.connect(self.on_mYPosSpin_valueChanged) self.mWidthSpin.valueChanged.connect(self.on_mWidthSpin_valueChanged) self.mHeightSpin.valueChanged.connect(self.on_mHeightSpin_valueChanged) self.mUpperLeftCheckBox.stateChanged.connect( self.on_mUpperLeftCheckBox_stateChanged) self.mUpperMiddleCheckBox.stateChanged.connect( self.on_mUpperMiddleCheckBox_stateChanged) self.mUpperRightCheckBox.stateChanged.connect( self.on_mUpperRightCheckBox_stateChanged) self.mMiddleLeftCheckBox.stateChanged.connect( self.on_mMiddleLeftCheckBox_stateChanged) self.mMiddleCheckBox.stateChanged.connect( self.on_mMiddleCheckBox_stateChanged) self.mMiddleRightCheckBox.stateChanged.connect( self.on_mMiddleRightCheckBox_stateChanged) self.mLowerLeftCheckBox.stateChanged.connect( self.on_mLowerLeftCheckBox_stateChanged) self.mLowerMiddleCheckBox.stateChanged.connect( self.on_mLowerMiddleCheckBox_stateChanged) self.mLowerRightCheckBox.stateChanged.connect( self.on_mLowerRightCheckBox_stateChanged) self.mBlendModeCombo.currentIndexChanged.connect( self.on_mBlendModeCombo_currentIndexChanged) self.mTransparencySpnBx.valueChanged.connect( self.on_mTransparencySpnBx_valueChanged) self.connect(self.mItemRotationSpinBox, SIGNAL("valueChanged( double )"), self.on_mItemRotationSpinBox_valueChanged) self.mExcludeFromPrintsCheckBox.toggled.connect( self.on_mExcludeFromPrintsCheckBox_toggled)
def create_rows(self, layout, sarea): u"""Build the rows of the dialog box""" play_button_group = QButtonGroup(sarea) old_play_button_group = QButtonGroup(sarea) for num, entry in enumerate(self.entries_list, 2): tt_text = self.build_text_help_label(entry) ico_label = QLabel('', sarea) ico_label.setToolTip(tt_text) if entry.icon: ico_label.setPixmap(QPixmap.fromImage(entry.icon)) layout.addWidget(ico_label, num, 0) tt_label = QLabel(entry.display_word, sarea) tt_label.setToolTip(tt_text) layout.addWidget(tt_label, num, 1) if self.hide_text: tt_label.hide() # Play button. t_play_button = QPushButton(sarea) play_button_group.addButton(t_play_button, num-2) t_play_button.setToolTip(self.play_help) t_play_button.setIcon(QIcon(os.path.join(icons_dir, 'play.png'))) layout.addWidget(t_play_button, num, self.play_column) if self.note[entry.audio_field_name]: t_play_old_button = QPushButton(sarea) old_play_button_group.addButton(t_play_old_button, num-2) t_play_old_button.setIcon( QIcon(os.path.join(icons_dir, 'play.png'))) if not self.hide_text: t_play_old_button.setToolTip( self.note[entry.audio_field_name]) else: t_play_old_button.setToolTip(self.play_old_help_short) layout.addWidget(t_play_old_button, num, self.play_old_column) else: dummy_label = QLabel('', sarea) dummy_label.setToolTip(self.play_old_empty_line_help) layout.addWidget(dummy_label, num, self.play_old_column) # The group where we later look what to do: t_button_group = QButtonGroup(sarea) t_button_group.setExclusive(True) # Now the four buttons t_add_button = QPushButton(sarea) t_add_button.setCheckable(True) t_add_button.setFlat(True) t_add_button.setToolTip(self.add_help_text_short) t_add_button.setIcon(QIcon(os.path.join(icons_dir, 'add.png'))) layout.addWidget(t_add_button, num, self.add_column) t_button_group.addButton(t_add_button, Action.Add) t_keep_button = QPushButton(sarea) t_keep_button.setCheckable(True) t_keep_button.setFlat(True) t_keep_button.setToolTip(self.keep_help_text_short) t_keep_button.setIcon(QIcon(os.path.join(icons_dir, 'keep.png'))) layout.addWidget(t_keep_button, num, self.keep_column) t_button_group.addButton(t_keep_button, Action.Keep) t_delete_button = QPushButton(sarea) t_delete_button.setCheckable(True) t_delete_button.setFlat(True) t_delete_button.setToolTip(self.delete_help_text_short) t_delete_button.setIcon( QIcon(os.path.join(icons_dir, 'delete.png'))) layout.addWidget(t_delete_button, num, self.delete_column) t_button_group.addButton(t_delete_button, Action.Delete) t_blacklist_button = QPushButton(sarea) t_blacklist_button.setCheckable(True) t_blacklist_button.setFlat(True) t_blacklist_button.setToolTip(self.blacklist_help_text_short) t_blacklist_button.setIcon( QIcon(os.path.join(icons_dir, 'blacklist.png'))) if entry.entry_hash: layout.addWidget( t_blacklist_button, num, self.blacklist_column) else: t_blacklist_button.hide() dummy_label_bl = QLabel('', sarea) dummy_label_bl.setToolTip(self.blacklist_empty_line_help) layout.addWidget(dummy_label_bl, num, self.blacklist_column) t_button_group.button(entry.action).setChecked(True) # New: check a button based on how good the downloader is. t_button_group.addButton(t_blacklist_button, Action.Blacklist) self.buttons_groups.append(t_button_group) play_button_group.buttonClicked.connect( lambda button: play( self.entries_list[play_button_group.id(button)].file_path)) # N.B.: anki.sound.play() plays files from anywhere, not just # from the colection.media folder. We should be good, # here. (This behaviour may be a security risk, idk.) old_play_button_group.buttonClicked.connect( lambda button: playFromText( self.note[ self.entries_list[ old_play_button_group.id(button)].audio_field_name]))
class DefaultSelectParameterWidget(SelectParameterWidget): """Widget class for Default Select Parameter.""" def __init__(self, parameter, parent=None): """Constructor :param parameter: A DefaultSelectParameter object. :type parameter: DefaultSelectParameter """ super(DefaultSelectParameterWidget, self).__init__(parameter, parent) self.default_layout = QHBoxLayout() self.radio_button_layout = QHBoxLayout() self.radio_button_widget = QWidget() self.default_label = QLabel(tr('Default')) # Create radio button group self.default_input_button_group = QButtonGroup() # Define string enabler for radio button self.radio_button_enabler = self.input.itemData(0, Qt.UserRole) for i in range(len(self._parameter.default_labels)): if '%s' in self._parameter.default_labels[i]: label = ( self._parameter.default_labels[i] % self._parameter.default_values[i]) else: label = self._parameter.default_labels[i] radio_button = QRadioButton(label) self.radio_button_layout.addWidget(radio_button) self.default_input_button_group.addButton(radio_button, i) if self._parameter.default_value == \ self._parameter.default_values[i]: radio_button.setChecked(True) # Create double spin box for custom value self.custom_value = QDoubleSpinBox() if self._parameter.default_values[-1]: self.custom_value.setValue(self._parameter.default_values[-1]) has_min = False if self._parameter.minimum is not None: has_min = True self.custom_value.setMinimum(self._parameter.minimum) has_max = False if self._parameter.maximum is not None: has_max = True self.custom_value.setMaximum(self._parameter.maximum) if has_min and has_max: step = (self._parameter.maximum - self._parameter.minimum) / 100.0 self.custom_value.setSingleStep(step) self.radio_button_layout.addWidget(self.custom_value) self.toggle_custom_value() # Reset the layout self.input_layout.setParent(None) self.help_layout.setParent(None) self.label.setParent(None) self.inner_input_layout.setParent(None) self.input_layout = QGridLayout() self.input_layout.setSpacing(0) self.input_layout.addWidget(self.label, 0, 0) self.input_layout.addLayout(self.inner_input_layout, 0, 1) self.input_layout.addWidget(self.default_label, 1, 0) self.input_layout.addLayout(self.radio_button_layout, 1, 1) self.main_layout.addLayout(self.input_layout) self.main_layout.addLayout(self.help_layout) # check every added combobox, it could have been toggled by # the existing keyword self.toggle_input() # Connect # noinspection PyUnresolvedReferences self.input.currentIndexChanged.connect(self.toggle_input) self.default_input_button_group.buttonClicked.connect( self.toggle_custom_value) def raise_invalid_type_exception(self): message = 'Expecting element type of %s' % ( self._parameter.element_type.__name__) err = ValueError(message) return err def get_parameter(self): """Obtain list parameter object from the current widget state. :returns: A DefaultSelectParameter from the current state of widget. """ current_index = self.input.currentIndex() selected_value = self.input.itemData(current_index, Qt.UserRole) if hasattr(selected_value, 'toPyObject'): selected_value = selected_value.toPyObject() try: self._parameter.value = selected_value except ValueError: err = self.raise_invalid_type_exception() raise err radio_button_checked_id = self.default_input_button_group.checkedId() # No radio button checked, then default value = None if radio_button_checked_id == -1: self._parameter.default = None # The last radio button (custom) is checked, get the value from the # line edit elif (radio_button_checked_id == len(self._parameter.default_values) - 1): self._parameter.default_values[radio_button_checked_id] \ = self.custom_value.value() self._parameter.default = self.custom_value.value() else: self._parameter.default = self._parameter.default_values[ radio_button_checked_id] return self._parameter def set_default(self, default): """Set default value by item's string. :param default: The default. :type default: str, int :returns: True if success, else False. :rtype: bool """ # Find index of choice try: default_index = self._parameter.default_values.index(default) self.default_input_button_group.button(default_index).setChecked( True) except ValueError: last_index = len(self._parameter.default_values) - 1 self.default_input_button_group.button(last_index).setChecked( True) self.custom_value.setValue(default) self.toggle_custom_value() def toggle_custom_value(self): radio_button_checked_id = self.default_input_button_group.checkedId() if (radio_button_checked_id == len(self._parameter.default_values) - 1): self.custom_value.setDisabled(False) else: self.custom_value.setDisabled(True) def toggle_input(self): """Change behaviour of radio button based on input.""" current_index = self.input.currentIndex() # If current input is not a radio button enabler, disable radio button. if self.input.itemData(current_index, Qt.UserRole) != ( self.radio_button_enabler): self.disable_radio_button() # Otherwise, enable radio button. else: self.enable_radio_button() def set_selected_radio_button(self): """Set selected radio button to 'Do not report'.""" dont_use_button = self.default_input_button_group.button( len(self._parameter.default_values) - 2) dont_use_button.setChecked(True) def disable_radio_button(self): """Disable radio button group and custom value input area.""" checked = self.default_input_button_group.checkedButton() if checked: self.default_input_button_group.setExclusive(False) checked.setChecked(False) self.default_input_button_group.setExclusive(True) for button in self.default_input_button_group.buttons(): button.setDisabled(True) self.custom_value.setDisabled(True) def enable_radio_button(self): """Enable radio button and custom value input area then set selected radio button to 'Do not report'. """ for button in self.default_input_button_group.buttons(): button.setEnabled(True) self.set_selected_radio_button() self.custom_value.setEnabled(True)
class OptionWidget(EditorWidget): widgettype = 'Option Row' def __init__(self, *args): super(OptionWidget, self).__init__(*args) self._bindvalue = None self.group = QButtonGroup() self.group.setExclusive(True) self.group.buttonClicked.connect(self.emitvaluechanged) def createWidget(self, parent): widget = QWidget(parent) widget.setLayout(QHBoxLayout()) widget.layout().setContentsMargins(0,0,0,0) return widget def _buildfromlist(self, listconfig): items = listconfig['items'] for item in items: parts = item.split(';') data = parts[0] try: desc = parts[1] except IndexError: desc = data try: path = parts[2] if path.endswith("_icon"): icon = QIcon(":/icons/{}".format(path)) else: icon = QIcon(path) except: icon = QIcon() button = QPushButton() button.setCheckable(True) button.setText(desc) button.setProperty("value", data) button.setIcon(icon) button.setIconSize(QSize(24,24)) self.widget.layout().addWidget(button) self.group.addButton(button) def initWidget(self, widget): pass def updatefromconfig(self): super(OptionWidget, self).updatefromconfig() listconfig = self.config['list'] self._buildfromlist(listconfig) super(OptionWidget, self).endupdatefromconfig() def validate(self, *args): button = self.group.checkedButton() if button: self.raisevalidationupdate(True) else: self.raisevalidationupdate(False) self.emitvaluechanged() def setvalue(self, value): for button in self.group.buttons(): if button.property("value") == value: button.setChecked(True) return def value(self): button = self.group.checkedButton() if not button: return None return button.property("value")
def create_rows(self, layout): u"""Build one row of the dialog box""" play_button_group = QButtonGroup(self) old_play_button_group = QButtonGroup(self) for num, (source, dest, text, dl_fname, dl_hash, extras, icon)\ in enumerate(self.list, 3): tt_text = self.build_text_help_label(text, source, extras) ico_label = QLabel('', self) ico_label.setToolTip(tt_text) if icon: ico_label.setPixmap(QPixmap.fromImage(icon)) layout.addWidget(ico_label, num, 0) tt_label = QLabel(text, self) tt_label.setToolTip(tt_text) layout.addWidget(tt_label, num, 1) if self.hide_text: tt_label.hide() # Play button. t_play_button = QPushButton(self) play_button_group.addButton(t_play_button, num - 3) t_play_button.setToolTip(self.play_help) t_play_button.setIcon(QIcon(os.path.join(icons_dir, 'play.png'))) layout.addWidget(t_play_button, num, self.play_column) if self.note[dest]: t_play_old_button = QPushButton(self) old_play_button_group.addButton(t_play_old_button, num - 3) t_play_old_button.setIcon( QIcon(os.path.join(icons_dir, 'play.png'))) if not self.hide_text: t_play_old_button.setToolTip(self.note[dest]) else: t_play_old_button.setToolTip(self.play_old_help_short) layout.addWidget(t_play_old_button, num, self.play_old_column) else: dummy_label = QLabel('', self) dummy_label.setToolTip(self.play_old_empty_line_help) layout.addWidget(dummy_label, num, self.play_old_column) # The group where we later look what to do: t_button_group = QButtonGroup(self) t_button_group.setExclusive(True) # Now the four buttons t_add_button = QPushButton(self) t_add_button.setCheckable(True) t_add_button.setChecked(True) t_add_button.setFlat(True) t_add_button.setToolTip(self.add_help_text_short) t_add_button.setIcon(QIcon(os.path.join(icons_dir, 'add.png'))) layout.addWidget(t_add_button, num, self.add_column) t_button_group.addButton(t_add_button, action['add']) t_keep_button = QPushButton(self) t_keep_button.setCheckable(True) t_keep_button.setFlat(True) t_keep_button.setToolTip(self.keep_help_text_short) t_keep_button.setIcon(QIcon(os.path.join(icons_dir, 'keep.png'))) layout.addWidget(t_keep_button, num, self.keep_column) t_button_group.addButton(t_keep_button, action['keep']) t_delete_button = QPushButton(self) t_delete_button.setCheckable(True) t_delete_button.setFlat(True) t_delete_button.setToolTip(self.delete_help_text_short) t_delete_button.setIcon( QIcon(os.path.join(icons_dir, 'delete.png'))) layout.addWidget(t_delete_button, num, self.delete_column) t_button_group.addButton(t_delete_button, action['delete']) t_blacklist_button = QPushButton(self) t_blacklist_button.setCheckable(True) t_blacklist_button.setFlat(True) t_blacklist_button.setToolTip(self.blacklist_help_text_short) t_blacklist_button.setIcon( QIcon(os.path.join(icons_dir, 'blacklist.png'))) if self.show_skull_and_bones: layout.addWidget(t_blacklist_button, num, self.blacklist_column) else: t_blacklist_button.hide() t_button_group.addButton(t_blacklist_button, action['blacklist']) self.buttons_groups.append(t_button_group) play_button_group.buttonClicked.connect( lambda button: play(self.list[play_button_group.id(button)][3])) old_play_button_group.buttonClicked.connect( lambda button: playFromText(self.note[self.list[ old_play_button_group.id(button)][1]]))
def __init__(self, parent = None, mainwindow = None, exitDialogSlot = None, exitDialogSlotArg1 = None, exitDialogSlotArg2 = None): QWidget.__init__(self, parent) self._exitDialogSlot = exitDialogSlot self._exitDialogSlotArg1 = exitDialogSlotArg1 self._exitDialogSlotArg2 = exitDialogSlotArg2 self._mainwindow = mainwindow # self.setWindowFlags(QtCore.Qt.FramelessWindowHint|QtCore.Qt.Dialog) self.setWindowFlags(QtCore.Qt.Window|QtCore.Qt.WindowCloseButtonHint) # zx comment: must be ApplicationModal. otherwise, this dialog cannot block following codes in same thread self.setWindowModality(QtCore.Qt.ApplicationModal) self.setEnabled(True) self._gLayout = QVBoxLayout() # QGridLayout() self.checkbox_groups = [] self.widgetsInfo = {} # format: { widgetGroupName: [[widgetObj, widgetName], ....], } for displayOrder, groupElementsList in config.STATISTICS_PLUGIN_DISPLAY_ELEMENTS_DICT.items(): groupName = groupElementsList[0] groupElementsList = groupElementsList[1] group_box = QGroupBox(str(groupName), self) flayout = FloatingLayout() # Create buttongroup checkbox_group = QButtonGroup(group_box) checkbox_group.setExclusive(False) checkboxs = [] for i, token in enumerate(groupElementsList): # print "i = {} token = {}".format(i, token) if token == config.ANNOTATION_UPPER_COLOR_TOKEN or token == config.ANNOTATION_LOWER_COLOR_TOKEN or token == config.ANNOTATION_VEHICLE_COLOR_TOKEN: if token == config.ANNOTATION_UPPER_COLOR_TOKEN or token == config.ANNOTATION_LOWER_COLOR_TOKEN: editor = self._mainwindow.property_editor4 else: editor = self._mainwindow.property_editor6 names_list, texts_list, displaycolors_list = editor.get_group_config(token) for t, text in enumerate(texts_list): checkbox = QCheckBox(text) # get widget display color if token == config.ANNOTATION_UPPER_COLOR_TOKEN or token == config.ANNOTATION_LOWER_COLOR_TOKEN or token == config.ANNOTATION_VEHICLE_COLOR_TOKEN: thisCheckboxBkgColorChecked = displaycolors_list[t] thisCheckboxBkgColor = thisCheckboxBkgColorChecked else: thisCheckboxBkgColorChecked = displaycolors_list[t] thisCheckboxBkgColor = None # calc widget text color # thisCheckboxBkgColorChecked string pattern: #123456 txtColorChecked = None if thisCheckboxBkgColorChecked is not None: import math rgba = utils.hexColorStrToRGBA(thisCheckboxBkgColorChecked) distance = math.sqrt((rgba[0] - 255) ** 2 + (rgba[1] - 255) ** 2 + (rgba[2] - 255) ** 2) txtColorChecked = '#ffffff' if distance > config.GUI_COLOR_TAG_TEXT_BLACKWHITE_TOGGLE_THRESHOLD else '#000000' txtColor = txtColorChecked if token == config.ANNOTATION_UPPER_COLOR_TOKEN or token == config.ANNOTATION_LOWER_COLOR_TOKEN or token == config.ANNOTATION_VEHICLE_COLOR_TOKEN else None desc = utils.set_qobj_stylesheet(checkbox, 'QCheckBox', thisCheckboxBkgColor, txtColor, thisCheckboxBkgColorChecked, txtColorChecked) checkbox_group.addButton(checkbox) flayout.addWidget(checkbox) # print u"checkbox_group.addcheckbox {}".format(checkbox.text()) checkbox.clicked.connect(self.onClickedWidget) checkbox.setChecked(False) checkboxs.append([checkbox, names_list[t]]) else: checkbox = QCheckBox(token) desc = utils.set_qobj_stylesheet(checkbox, 'QCheckBox', "#ffffff", "#000000", "#ffffff", "#000000") checkbox_group.addButton(checkbox) flayout.addWidget(checkbox) # print "checkbox_group.addButton {}".format(checkbox) checkbox.clicked.connect(self.onClickedWidget) checkboxs.append([checkbox, token]) all = QRadioButton("All") desc = utils.set_qobj_stylesheet(all, 'QRadioButton', "#ffffff", "#000000", "#ffffff", "#000000") checkbox_group.addButton(all) flayout.addWidget(all) all.clicked.connect(self.selectAllWidgetsInCurrentGroup) checkboxs.append([all, "all"]) group_box.setLayout(flayout) # add this checkboxgroup to layout self._gLayout.addWidget(group_box) self.checkbox_groups.append(checkbox_group) self.widgetsInfo[groupName] = checkboxs self._filtersGoup = QGroupBox("Filters", self) self._filtersGoup_layout = QHBoxLayout() self._filtersGoup.setLayout(self._filtersGoup_layout) self._gLayout.addWidget(self._filtersGoup) self._buttonStatisticWithFilterWidget = QPushButton("STATISTICS with filters") utils.set_qobj_stylesheet(self._buttonStatisticWithFilterWidget, 'QPushButton', '#C0C0C0', '#ff0000', '#909090', '#0080FF') self._buttonStatisticWithFilterWidget.clicked.connect(self.onClickedStatisticWithFilter) self._filtersGoup_layout.addWidget(self._buttonStatisticWithFilterWidget) """ self._buttonStatisticAllColorsWidget = QPushButton("STATISTICS all colors") utils.set_qobj_stylesheet(self._buttonStatisticAllColorsWidget, 'QPushButton', '#C0C0C0', '#ff0000', '#909090', '#0080FF') self._buttonStatisticAllColorsWidget.clicked.connect(self.onClickedStatisticAllColors) self._filtersGoup_layout.addWidget(self._buttonStatisticAllColorsWidget) """ self._buttonApplyFilterOnViewModeWidget = QPushButton("Apply filters on view mode") utils.set_qobj_stylesheet(self._buttonApplyFilterOnViewModeWidget, 'QPushButton', '#C0C0C0', '#ff0000', '#909090', '#0080FF') self._buttonApplyFilterOnViewModeWidget.clicked.connect(self.onClickedApplyFilterOnViewMode) self._filtersGoup_layout.addWidget(self._buttonApplyFilterOnViewModeWidget) self._statLabelWidget = QLabel(u'<font color="red">{}</font>'.format("statistics result")) self._statLabelWidget.setFont(QFont("Timers", 16, QFont.Bold)) self._gLayout.addWidget(self._statLabelWidget) self._statResultTxtWidget = QTextEdit('') self._gLayout.addWidget(self._statResultTxtWidget) self.setLayout(self._gLayout) self.setWindowTitle(config.STATISTIC_OR_APPLY_OBJVIEWFILTER_FOR_CUR_JSON_FILE_PLUGIN_DISPLAYTEXT) self.resize(1000, 800) utils.centerGuiWidget(self) return
class PlotWidget(QtGui.QWidget, plot_widget_class): """Wrapper widget for PyQtGraph adding some extra buttons""" def __init__(self, parent=None, fps=100, title="", *args): super(PlotWidget, self).__init__(*args) self.setupUi(self) # Limit the plot update to 10Hz self._ts = time() self._delay = 0.1 # Check if we could import PyQtGraph, if not then stop here if not _pyqtgraph_found: self.can_enable = False return else: self.can_enable = True self._items = {} self._last_item = 0 self.setSizePolicy(QtGui.QSizePolicy( QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding)) self.setMinimumSize(self.minimumSizeHint()) self.parent = parent pg.setConfigOption('background', 'w') pg.setConfigOption('foreground', 'k') self._plot_widget = pg.PlotWidget() self._plot_widget.hideButtons() self._plot_widget.setLabel('bottom', "Time", "ms") self._plot_widget.addLegend() self._plot_widget.getViewBox().disableAutoRange(ViewBox.XAxis) self._plot_widget.getViewBox().sigRangeChangedManually.connect(self._manual_range_change) self._plot_widget.getViewBox().setMouseEnabled(x=False, y=True) self._plot_widget.getViewBox().setMouseMode(ViewBox.PanMode) self.plotLayout.addWidget(self._plot_widget) #self.saveToFile.clicked.connect(self.saveToFileSignal) self._x_min = 0 self._x_max = 500 self._enable_auto_y.setChecked(True) self._enable_samples_x.setChecked(True) self._last_ts = None self._dtime = None self._x_range = (float(self._range_x_min.text()), float(self._range_x_max.text())) self._nbr_samples = int(self._nbr_of_samples_x.text()) self._nbr_of_samples_x.valueChanged.connect(self._nbr_samples_changed) self._range_y_min.valueChanged.connect(self._y_range_changed) self._range_y_max.valueChanged.connect(self._y_range_changed) self._y_btn_group = QButtonGroup() self._y_btn_group.addButton(self._enable_auto_y) self._y_btn_group.addButton(self._enable_range_y) self._y_btn_group.setExclusive(True) self._y_btn_group.buttonClicked.connect(self._y_mode_change) self._x_btn_group = QButtonGroup() self._x_btn_group.addButton(self._enable_range_x) self._x_btn_group.addButton(self._enable_samples_x) self._x_btn_group.addButton(self._enable_seconds_x) self._x_btn_group.addButton(self._enable_manual_x) self._x_btn_group.setExclusive(True) self._x_btn_group.buttonClicked.connect(self._x_mode_change) self._draw_graph = True self._auto_redraw.stateChanged.connect(self._auto_redraw_change) def _auto_redraw_change(self, state): """Callback from the auto redraw checkbox""" if state == 0: self._draw_graph = False else: self._draw_graph = True def _x_mode_change(self, box): """Callback when user changes the X-axis mode""" if box == self._enable_range_x: logger.info("Enable range x") self._x_range = (float(self._range_x_min.text()), float(self._range_x_max.text())) else: self._range_x_min.setEnabled(False) self._range_x_max.setEnabled(False) def _y_mode_change(self, box): """Callback when user changes the Y-axis mode""" if box == self._enable_range_y: self._range_y_min.setEnabled(True) self._range_y_max.setEnabled(True) y_range = (float(self._range_y_min.value()), float(self._range_y_max.value())) self._plot_widget.getViewBox().setRange(yRange=y_range) else: self._range_y_min.setEnabled(False) self._range_y_max.setEnabled(False) if box == self._enable_auto_y: self._plot_widget.getViewBox().enableAutoRange(ViewBox.YAxis) def _manual_range_change(self, obj): """Callback from pyqtplot when users changes the range of the plot using the mouse""" [[x_min,x_max],[y_min,y_max]] = self._plot_widget.getViewBox().viewRange() self._range_y_min.setValue(y_min) self._range_y_max.setValue(y_max) self._range_y_min.setEnabled(True) self._range_y_max.setEnabled(True) self._enable_range_y.setChecked(True) def _y_range_changed(self, val): """Callback when user changes Y range manually""" _y_range = (float(self._range_y_min.value()), float(self._range_y_max.value())) self._plot_widget.getViewBox().setRange(yRange=_y_range, padding=0) def _nbr_samples_changed(self, val): """Callback when user changes the number of samples to be shown""" self._nbr_samples = val def set_title(self, title): """ Set the title of the plot. title - the new title """ self._plot_widget.setTitle(title) def add_curve(self, title, pen='r'): """ Add a new curve to the plot. title - the name of the data pen - color of curve (using r for red and so on..) """ self._items[title] = PlotItemWrapper(self._plot_widget.plot(name=title, pen=pen)) def add_data(self, data, ts): """ Add new data to the plot. data - dictionary sent from logging layer containing variable/value pairs ts - timestamp of the data in ms """ if not self._last_ts: self._last_ts = ts elif not self._last_ts: self._dtime = ts - self._last_ts self._last_ts = ts x_min_limit = 0 x_max_limit = 0 # We are adding new datasets, calculate what we should show. if self._enable_samples_x.isChecked(): x_min_limit = max(0, self._last_item-self._nbr_samples) x_max_limit = max(self._last_item, self._nbr_samples) for name in self._items: self._items[name].add_point(data[name], ts) if self._draw_graph and time() > self._ts + self._delay: [self._x_min, self._x_max] = self._items[name].show_data(x_min_limit, x_max_limit) if time() > self._ts + self._delay: self._ts = time() if self._enable_samples_x.isChecked() and self._dtime and self._last_item < self._nbr_samples: self._x_max = self._x_min + self._nbr_samples * self._dtime self._last_item = self._last_item + 1 self._plot_widget.getViewBox().setRange(xRange=(self._x_min, self._x_max)) def removeAllDatasets(self): """Reset the plot by removing all the datasets""" for item in self._items: self._plot_widget.removeItem(self._items[item]) self._plot_widget.plotItem.legend.items = [] self._items = {} self._last_item = 0 self._last_ts = None self._dtime = None self._plot_widget.clear()
class PreferencesView(QTabWidget): closed = pyqtSignal() def __init__(self, parent = None): super(PreferencesView, self).__init__(parent) self.setWindowTitle("Preferences") # self.setFixedSize(self.maximumSize()) # self.setMinimumSize(self.maximumSize()) # self.setMaximumSize(self.maximumSize()) # self.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.chemicalSimulationDt = self.createFloatingPointEditor() self.chemicalDiffusionDt = self.createFloatingPointEditor() self.chemicalPlotUpdateInterval = self.createFloatingPointEditor() self.chemicalDefaultSimulationRuntime = self.createFloatingPointEditor() self.chemicalGuiUpdateInterval = self.createFloatingPointEditor() self.chemicalSolver = QButtonGroup() self.chemicalSolvers = { "Exponential Euler" : QRadioButton("Exponential Euler") , "Gillespie" : QRadioButton("Gillespie") , "Runge Kutta" : QRadioButton("Runge Kutta") } self.chemicalSimulationApply = QPushButton("Apply") self.chemicalSimulationCancel = QPushButton("Cancel") self.electricalSimulationDt = self.createFloatingPointEditor() self.electricalPlotUpdateInterval = self.createFloatingPointEditor() self.electricalDefaultSimulationRuntime = self.createFloatingPointEditor() self.electricalGuiUpdateInterval = self.createFloatingPointEditor() self.electricalSolver = QButtonGroup() self.electricalSolvers = { "Gillespie" : QRadioButton("Gillespie") , "Runge Kutta" : QRadioButton("Runge Kutta") } self.electricalSimulationApply = QPushButton("Apply") self.electricalSimulationCancel = QPushButton("Cancel") self.electricalVisualizationApply = QPushButton("Apply") self.electricalVisualizationCancel = QPushButton("Cancel") self.electricalBaseColorButton = QPushButton() self.electricalBaseColorDialog = QColorDialog() self.electricalPeakColorButton = QPushButton() self.electricalPeakColorDialog = QColorDialog() self.electricalBackgroundColorButton = QPushButton() self.electricalBackgroundColorDialog = QColorDialog() self.electricalBaseMembraneVoltage = self.createFloatingPointEditor() self.electricalPeakMembraneVoltage = self.createFloatingPointEditor() self.create() def closeEvent(self, event): self.closed.emit() def create(self): # Set up the column titles self.setUsesScrollButtons(True) self.setFocusPolicy(PyQt4.QtCore.Qt.NoFocus) self.addTab( self.createChemicalSettingsTab(),"Chemical") self.addTab( self.createElectricalSettingsTab(),"Electrical") def createChemicalSettingsTab(self): chemicalSettingsTab = QWidget() layout = QtGui.QGridLayout() chemicalSettingsTab.setLayout(layout) layout.addWidget(QLabel('Simulation dt'), 0, 0) layout.addWidget(self.chemicalSimulationDt, 0, 1) layout.addWidget(QLabel('Diffusion dt'), 1, 0) layout.addWidget(self.chemicalDiffusionDt, 1, 1) layout.addWidget(QLabel('Plot Update Interval'), 2, 0) layout.addWidget(self.chemicalPlotUpdateInterval, 2, 1) layout.addWidget(QLabel('GUI Update Interval'), 3, 0) layout.addWidget(self.chemicalGuiUpdateInterval, 3, 1) # layout.addWidget(QLabel('Default Runtime'), 4, 0) # layout.addWidget(self.chemicalDefaultSimulationRuntime, 4, 1) layout.addWidget(QLabel('Solver'), 5, 0) index = 0 for solver in self.chemicalSolvers: layout.addWidget(self.chemicalSolvers[solver], 5 + index, 1) self.chemicalSolver.addButton(self.chemicalSolvers[solver], index) self.chemicalSolvers[solver].setFocusPolicy(PyQt4.QtCore.Qt.NoFocus) index += 1 self.chemicalSolver.setExclusive(True) buttonLayout = QGridLayout() layout.addLayout(buttonLayout, 5 + index, 1) buttonLayout.addWidget(self.chemicalSimulationCancel, 0, 0, Qt.Qt.AlignRight) buttonLayout.addWidget(self.chemicalSimulationApply, 0, 1, Qt.Qt.AlignLeft) return chemicalSettingsTab def createElectricalSettingsTab(self): electricalSettingsTab = QTabWidget() electricalSettingsTab.addTab( self.createElectricalSimulationSettingsTab() , "Simulation" ) electricalSettingsTab.addTab( self.createElectricalSimulationVisualizationTab() , "Visualization" ) electricalSettingsTab.setTabPosition(QTabWidget.East) electricalSettingsTab.setTabShape(QTabWidget.Triangular) electricalSettingsTab.setDocumentMode(True) electricalSettingsTab.setUsesScrollButtons(True) electricalSettingsTab.setFocusPolicy(PyQt4.QtCore.Qt.NoFocus) return electricalSettingsTab def createElectricalSimulationSettingsTab(self): widget = QWidget() layout = QtGui.QGridLayout() widget.setLayout(layout) layout.addWidget(QLabel('Simulation dt'), 0, 0) layout.addWidget(self.electricalSimulationDt, 0, 1) layout.addWidget(QLabel('Plot Update Interval'), 2, 0) layout.addWidget(self.electricalPlotUpdateInterval, 2, 1) layout.addWidget(QLabel('GUI Update Interval'), 3, 0) layout.addWidget(self.electricalGuiUpdateInterval, 3, 1) # layout.addWidget(QLabel('Default Runtime'), 4, 0) # layout.addWidget(self.electricalDefaultSimulationRuntime, 4, 1) # layout.addWidget(QLabel('Solver'), 5, 0) index = 0 for solver in self.electricalSolvers: # layout.addWidget(self.electricalSolvers[solver], 5 + index, 1) self.electricalSolver.addButton(self.electricalSolvers[solver], index) self.electricalSolvers[solver].setFocusPolicy(PyQt4.QtCore.Qt.NoFocus) index += 1 self.electricalSolver.setExclusive(True) buttonLayout = QGridLayout() layout.addLayout(buttonLayout, 5 + index, 1) buttonLayout.addWidget(self.electricalSimulationCancel, 0, 0, Qt.Qt.AlignRight) buttonLayout.addWidget(self.electricalSimulationApply, 0, 1, Qt.Qt.AlignLeft) return widget def createElectricalSimulationVisualizationTab(self): widget = QWidget() layout = QtGui.QGridLayout() widget.setLayout(layout) layout.addWidget(QLabel('Base Membrane Voltage'), 1, 0) layout.addWidget(self.electricalBaseMembraneVoltage, 1, 1) layout.addWidget(QLabel('Base Compartment Color'), 2, 0) self.electricalBaseColorDialog.setOption(QColorDialog.ShowAlphaChannel, True) layout.addWidget(self.electricalBaseColorButton, 2, 1) self.electricalBaseColorButton.clicked.connect(self.electricalBaseColorDialog.show) self.electricalBaseColorButton.setFocusPolicy(PyQt4.QtCore.Qt.NoFocus) self.electricalBaseColorDialog.colorSelected.connect( lambda color: self.electricalBaseColorButton.setStyleSheet( "QPushButton {" + "background-color: {0}; color: {0};".format(color.name()) + "}" ) ) layout.addWidget(QLabel('Peak Membrane Voltage'), 3, 0) layout.addWidget(self.electricalPeakMembraneVoltage, 3, 1) layout.addWidget(QLabel('Peak Compartment Color'), 4, 0) self.electricalPeakColorDialog.setOption(QColorDialog.ShowAlphaChannel, True) layout.addWidget(self.electricalPeakColorButton, 4, 1) self.electricalPeakColorButton.clicked.connect(self.electricalPeakColorDialog.show) self.electricalPeakColorButton.setFocusPolicy(PyQt4.QtCore.Qt.NoFocus) self.electricalPeakColorDialog.colorSelected.connect( lambda color: self.electricalPeakColorButton.setStyleSheet( "QPushButton {" + "background-color: {0}; color: {0};".format(color.name()) + "}" ) ) layout.addWidget(QLabel('Background Color'), 5, 0) self.electricalBackgroundColorDialog.setOption(QColorDialog.ShowAlphaChannel, True) layout.addWidget(self.electricalBackgroundColorButton, 5, 1) self.electricalBackgroundColorButton.clicked.connect(self.electricalBackgroundColorDialog.show) self.electricalBackgroundColorButton.setFocusPolicy(PyQt4.QtCore.Qt.NoFocus) self.electricalBackgroundColorDialog.colorSelected.connect( lambda color: self.electricalBackgroundColorButton.setStyleSheet( "QPushButton {" + "background-color: {0}; color: {0};".format(color.name()) + "}" ) ) buttonLayout = QGridLayout() layout.addLayout(buttonLayout, 6, 1) buttonLayout.addWidget(self.electricalVisualizationCancel, 0, 0, Qt.Qt.AlignRight) buttonLayout.addWidget(self.electricalVisualizationApply, 0, 1, Qt.Qt.AlignLeft) return widget def createFloatingPointEditor(self, value = 0.0, minValue = float("-inf"), maxValue = float("+inf"), decimals = 1000): floatingPointEditor = QLineEdit(str(value)) floatingPointEditor.setValidator(QDoubleValidator(minValue, maxValue, decimals)) return floatingPointEditor
class DateTimePickerWidget(datepicker_widget, QWidget): ok = pyqtSignal() cancel = pyqtSignal() """ A custom date picker with a time and date picker """ def __init__(self, parent=None, mode="DateTime"): super(DateTimePickerWidget, self).__init__(parent) self.setupUi(self) self.mode = mode self.group = QButtonGroup() self.group.setExclusive(True) self.group.addButton(self.ambutton) self.group.addButton(self.pmbutton) self.ambutton.toggled.connect(self.isDirty) self.pmbutton.toggled.connect(self.isDirty) self.datepicker.selectionChanged.connect(self.isDirty) self.hourpicker.itemSelectionChanged.connect(self.isDirty) self.minutepicker.itemSelectionChanged.connect(self.isDirty) self.setasnowbutton.pressed.connect(self.setAsNow) self.setWindowFlags(Qt.Dialog | Qt.CustomizeWindowHint) self.okButton.pressed.connect(self.ok.emit) self.closebutton.pressed.connect(self.cancel.emit) def setMinValue(self, mindate): self.datepicker.setMinimumDate(mindate) def setmode(self, mode): if mode == "Date": self.timesection.hide() elif mode == "Time": self.datepicker.hide() def isDirty(self, *args): date = self.getSelectedDate() time = self.getSelectedTime() datetime = QDateTime(date, time) if self.mode == "Date": value = datetime.toString("ddd d MMM yyyy") elif self.mode == "Time": value = datetime.toString("hh:mm ap") else: value = datetime.toString("ddd d MMM yyyy 'at' hh:mm ap") self.label.setText("Set as: {}".format(value)) def setDateTime(self, datetime): """ Set the picker to datatime datetime - The QDateTime with the value to set. """ self.setTime(datetime.time()) self.setDate(datetime.date()) def setAsNow(self): """ Set the current date and time on the picker as now. """ now = QDateTime.currentDateTime() self.setDateTime(now) def setTime(self, time): """ Set just the time part of the picker """ hour = time.hour() if hour > 12: hour = hour - 12 if hour == 0: hour = hour + 12 minute = time.minute() minute = int(round(minute / 5.0) * 5.0) amap = time.toString("AP") utils.log("Hour %s Minute %s" % (hour, minute)) try: houritems = self.hourpicker.findItems(str(hour), Qt.MatchFixedString) self.hourpicker.setCurrentItem(houritems[0]) except IndexError: utils.log("Can't find hour") try: minuteitems = self.minutepicker.findItems(str(minute), Qt.MatchFixedString) self.minutepicker.setCurrentItem(minuteitems[0]) except IndexError: utils.log("Can't find minute") if amap == "PM": self.pmbutton.toggle() def setDate(self, date): """ Set just the date part of the picker """ self.datepicker.setSelectedDate(date) def getSelectedTime(self): """ Returns the currently selected data and time """ try: hour = self.hourpicker.currentItem().text() except AttributeError: hour = "" try: minute = self.minutepicker.currentItem().text() except AttributeError: minute = "" zone = self.ambutton.isChecked() and "AM" or "PM" return QTime.fromString("%s%s%s" % (hour, minute, zone), "hmAP") def getSelectedDate(self): """ Returns just the date part of the picker """ return self.datepicker.selectedDate() @property def value(self): datetime = QDateTime() datetime.setDate(self.getSelectedDate()) datetime.setTime(self.getSelectedTime()) return datetime @value.setter def value(self, value): if value is None: self.setAsNow() return if isinstance(value, basestring): value = QDateTime.fromString(value, Qt.ISODate) self.setDate(value.date()) self.setTime(value.time())
class PetaBencanaDialog(QDialog, FORM_CLASS): """Downloader for PetaBencana data. .. versionadded: 3.3 """ def __init__(self, parent=None, iface=None): """Constructor for import dialog. .. versionadded: 3.3 :param parent: Optional widget to use as parent. :type parent: QWidget :param iface: An instance of QGisInterface. :type iface: QGisInterface """ QDialog.__init__(self, parent) self.parent = parent self.setupUi(self) title = self.tr('PetaBencana Downloader') self.setWindowTitle(title) self.iface = iface self.source = None self.radio_button_group = QButtonGroup() self.radio_button_group.addButton(self.radio_button_production) self.radio_button_group.addButton(self.radio_button_development) self.radio_button_group.setExclusive(True) self.radio_button_production.setChecked(True) self.populate_combo_box() developer_mode = setting('developer_mode', False, bool) if not developer_mode: self.radio_button_widget.hide() self.source_label.hide() self.output_group.adjustSize() # signals self.radio_button_production.clicked.connect(self.populate_combo_box) self.radio_button_development.clicked.connect(self.populate_combo_box) # creating progress dialog for download self.progress_dialog = QProgressDialog(self) self.progress_dialog.setAutoClose(False) self.progress_dialog.setWindowTitle(title) # Set up things for context help self.help_button = self.button_box.button(QtGui.QDialogButtonBox.Help) # Allow toggling the help button self.help_button.setCheckable(True) self.help_button.toggled.connect(self.help_toggled) self.main_stacked_widget.setCurrentIndex(1) # set up the validator for the file name prefix expression = QRegExp('^[A-Za-z0-9-_]*$') validator = QRegExpValidator(expression, self.filename_prefix) self.filename_prefix.setValidator(validator) self.time_stamp = None self.restore_state() @pyqtSlot() @pyqtSignature('bool') # prevents actions being handled twice def help_toggled(self, flag): """Show or hide the help tab in the stacked widget. .. versionadded: 3.3 :param flag: Flag indicating whether help should be shown or hidden. :type flag: bool """ if flag: self.help_button.setText(self.tr('Hide Help')) self.show_help() else: self.help_button.setText(self.tr('Show Help')) self.hide_help() def hide_help(self): """Hide the usage info from the user. .. versionadded:: 3.3 """ self.main_stacked_widget.setCurrentIndex(1) def show_help(self): """Show usage info to the user. .. versionadded: 3.3 """ # Read the header and footer html snippets self.main_stacked_widget.setCurrentIndex(0) header = html_header() footer = html_footer() string = header message = peta_bencana_help() string += message.to_html() string += footer self.help_web_view.setHtml(string) def restore_state(self): """Read last state of GUI from configuration file. .. versionadded: 3.3 """ settings = QSettings() try: last_path = settings.value('directory', type=str) except TypeError: last_path = '' self.output_directory.setText(last_path) def save_state(self): """Store current state of GUI to configuration file. .. versionadded: 3.3 """ settings = QSettings() settings.setValue('directory', self.output_directory.text()) @pyqtSignature('') # prevents actions being handled twice def on_directory_button_clicked(self): """Show a dialog to choose directory. .. versionadded: 3.3 """ # noinspection PyCallByClass,PyTypeChecker self.output_directory.setText(QFileDialog.getExistingDirectory( self, self.tr('Select download directory'))) def accept(self): """Do PetaBencana download and display it in QGIS. .. versionadded: 3.3 """ self.save_state() try: self.require_directory() except CanceledImportDialogError: return QtGui.qApp.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor)) source = self.define_url() # save the file as json first name = 'jakarta_flood.json' output_directory = self.output_directory.text() output_prefix = self.filename_prefix.text() overwrite = self.overwrite_flag.isChecked() date_stamp_flag = self.include_date_flag.isChecked() output_base_file_path = self.get_output_base_path( output_directory, output_prefix, date_stamp_flag, name, overwrite) title = self.tr("Can't access API") try: self.download(source, output_base_file_path) # Open downloaded file as QgsMapLayer layer = QgsVectorLayer( output_base_file_path, 'flood', 'ogr', False) except Exception as e: disable_busy_cursor() QMessageBox.critical(self, title, str(e)) return self.time_stamp = time.strftime('%d-%b-%Y %H:%M:%S') # Now save as shp name = 'jakarta_flood.shp' output_base_file_path = self.get_output_base_path( output_directory, output_prefix, date_stamp_flag, name, overwrite) QgsVectorFileWriter.writeAsVectorFormat( layer, output_base_file_path, 'CP1250', None, 'ESRI Shapefile') # Get rid of the GeoJSON layer and rather use local shp del layer self.copy_style(output_base_file_path) self.copy_keywords(output_base_file_path) layer = self.add_flooded_field(output_base_file_path) # check if the layer has feature or not if layer.featureCount() <= 0: city = self.city_combo_box.currentText() message = self.tr( 'There are no floods data available on {city} ' 'at this time.').format(city=city) display_warning_message_box( self, self.tr('No data'), message) disable_busy_cursor() else: # add the layer to the map registry = QgsMapLayerRegistry.instance() registry.addMapLayer(layer) disable_busy_cursor() self.done(QDialog.Accepted) def add_flooded_field(self, shapefile_path): """Create the layer from the local shp adding the flooded field. .. versionadded:: 3.3 Use this method to add a calculated field to a shapefile. The shapefile should have a field called 'count' containing the number of flood reports for the field. The field values will be set to 0 if the count field is < 1, otherwise it will be set to 1. :param shapefile_path: Path to the shapefile that will have the flooded field added. :type shapefile_path: basestring :return: A vector layer with the flooded field added. :rtype: QgsVectorLayer """ layer = QgsVectorLayer( shapefile_path, self.tr('Jakarta Floods'), 'ogr') # Add a calculated field indicating if a poly is flooded or not # from PyQt4.QtCore import QVariant layer.startEditing() # Add field with integer from 0 to 4 which represents the flood # class. Its the same as 'state' field except that is being treated # as a string. # This is used for cartography flood_class_field = QgsField('floodclass', QVariant.Int) layer.dataProvider().addAttributes([flood_class_field]) layer.commitChanges() layer.startEditing() flood_class_idx = layer.fieldNameIndex('floodclass') flood_class_expression = QgsExpression('to_int(state)') context = QgsExpressionContext() context.setFields(layer.pendingFields()) flood_class_expression.prepare(context) # Add field with boolean flag to say if the area is flooded # This is used by the impact function flooded_field = QgsField('flooded', QVariant.Int) layer.dataProvider().addAttributes([flooded_field]) layer.commitChanges() layer.startEditing() flooded_idx = layer.fieldNameIndex('flooded') flood_flag_expression = QgsExpression('state > 0') flood_flag_expression.prepare(context) for feature in layer.getFeatures(): context.setFeature(feature) feature[flood_class_idx] = flood_class_expression.evaluate(context) feature[flooded_idx] = flood_flag_expression.evaluate(context) layer.updateFeature(feature) layer.commitChanges() return layer def copy_keywords(self, shapefile_path): """Copy keywords from the OSM resource directory to the output path. .. versionadded: 3.3 In addition to copying the template, tokens within the template will be replaced with new values for the date token and title token. :param shapefile_path: Path to the shapefile that will have the flooded field added. :type shapefile_path: basestring """ source_xml_path = resources_path('petabencana', 'flood-keywords.xml') output_xml_path = shapefile_path.replace('shp', 'xml') LOGGER.info('Copying xml to: %s' % output_xml_path) title_token = '[TITLE]' new_title = self.tr('Jakarta Floods - %s' % self.time_stamp) date_token = '[DATE]' new_date = self.time_stamp with open(source_xml_path) as source_file, \ open(output_xml_path, 'w') as output_file: for line in source_file: line = line.replace(date_token, new_date) line = line.replace(title_token, new_title) output_file.write(line) @staticmethod def copy_style(shapefile_path): """Copy style from the OSM resource directory to the output path. .. versionadded: 3.3 :param shapefile_path: Path to the shapefile that should get the path added. :type shapefile_path: basestring """ source_qml_path = resources_path('petabencana', 'flood-style.qml') output_qml_path = shapefile_path.replace('shp', 'qml') LOGGER.info('Copying qml to: %s' % output_qml_path) copy(source_qml_path, output_qml_path) def get_output_base_path( self, output_directory, output_prefix, with_date_stamp, feature_type, overwrite): """Get a full base name path to save the shapefile. TODO: This is cut & paste from OSM - refactor to have one method :param output_directory: The directory where to put results. :type output_directory: str :param output_prefix: The prefix to add for the shapefile. :type output_prefix: str :param with_date_stamp: Whether to add a datestamp in between the file prefix and the feature_type for the shapefile name. :type output_prefix: str :param feature_type: What kind of data will be downloaded. Will be used for the shapefile name. :type feature_type: str :param overwrite: Boolean to know if we can overwrite existing files. :type overwrite: bool :return: The base path. :rtype: str """ if with_date_stamp and self.time_stamp is not None: time_stamp = self.time_stamp.replace(' ', '-') time_stamp = time_stamp.replace(':', '-') time_stamp += '-' feature_type = time_stamp + feature_type path = os.path.join( output_directory, '%s%s' % (output_prefix, feature_type)) if overwrite: # If a shapefile exists, we must remove it (only the .shp) shp = '%s.shp' % path if os.path.isfile(shp): os.remove(shp) else: separator = '-' suffix = self.get_unique_file_path_suffix( '%s.shp' % path, separator) if suffix: path = os.path.join(output_directory, '%s%s%s%s' % ( output_prefix, feature_type, separator, suffix)) return path @staticmethod def get_unique_file_path_suffix(file_path, separator='-', i=0): """Return the minimum number to suffix the file to not overwrite one. Example : /tmp/a.txt exists. - With file_path='/tmp/b.txt' will return 0. - With file_path='/tmp/a.txt' will return 1 (/tmp/a-1.txt) TODO: This is cut & paste from OSM - refactor to have one method :param file_path: The file to check. :type file_path: str :param separator: The separator to add before the prefix. :type separator: str :param i: The minimum prefix to check. :type i: int :return: The minimum prefix you should add to not overwrite a file. :rtype: int """ basename = os.path.splitext(file_path) if i != 0: file_path_test = os.path.join( '%s%s%s%s' % (basename[0], separator, i, basename[1])) else: file_path_test = file_path if os.path.isfile(file_path_test): return PetaBencanaDialog.get_unique_file_path_suffix( file_path, separator, i + 1) else: return i def require_directory(self): """Ensure directory path entered in dialog exist. When the path does not exist, this function will ask the user if he want to create it or not. TODO: This is cut & paste from OSM - refactor to have one method :raises: CanceledImportDialogError - when user choose 'No' in the question dialog for creating directory. """ path = self.output_directory.text() if os.path.exists(path): return title = self.tr('Directory %s not exist') % path question = self.tr( 'Directory %s not exist. Do you want to create it?') % path # noinspection PyCallByClass,PyTypeChecker answer = QMessageBox.question( self, title, question, QMessageBox.Yes | QMessageBox.No) if answer == QMessageBox.Yes: if len(path) != 0: os.makedirs(path) else: # noinspection PyCallByClass,PyTypeChecker,PyArgumentList display_warning_message_box( self, self.tr('InaSAFE error'), self.tr('Output directory can not be empty.')) raise CanceledImportDialogError() else: raise CanceledImportDialogError() def load_shapefile(self, feature_type, base_path): """Load downloaded shape file to QGIS Main Window. TODO: This is cut & paste from OSM - refactor to have one method :param feature_type: What kind of features should be downloaded. Currently 'buildings', 'building-points' or 'roads' are supported. :type feature_type: str :param base_path: The base path of the shape file (without extension). :type base_path: str :raises: FileMissingError - when buildings.shp not exist """ path = '%s.shp' % base_path if not os.path.exists(path): message = self.tr( '%s does not exist. The server does not have any data for ' 'this extent.' % path) raise FileMissingError(message) self.iface.addVectorLayer(path, feature_type, 'ogr') canvas_srid = self.canvas.mapSettings().destinationCrs().srsid() on_the_fly_projection = self.canvas.hasCrsTransformEnabled() if canvas_srid != 4326 and not on_the_fly_projection: if QGis.QGIS_VERSION_INT >= 20400: self.canvas.setCrsTransformEnabled(True) else: display_warning_message_bar( self.iface, self.tr('Enable \'on the fly\''), self.tr( 'Your current projection is different than EPSG:4326. ' 'You should enable \'on the fly\' to display ' 'correctly your layers') ) def reject(self): """Redefinition of the method. It will call the super method. """ super(PetaBencanaDialog, self).reject() def download(self, url, output_path): """Download file from API url and write to output path. :param url: URL of the API. :type url: str :param output_path: Path of output file, :type output_path: str """ request_failed_message = self.tr( "Can't access PetaBencana API: {source}").format( source=url) downloader = FileDownloader(url, output_path) result, message = downloader.download() if not result: display_warning_message_box( self, self.tr('Download error'), self.tr(request_failed_message + '\n' + message)) if result == QNetworkReply.OperationCanceledError: display_warning_message_box( self, self.tr('Download error'), self.tr(message)) # The function below might be usefull for future usage. # def get_available_area(self): # """Function to automatically get the available area on API. # *still cannot get string data from QByteArray* # """ # available_area = [] # network_manager = QgsNetworkAccessManager.instance() # api_url = QUrl('https://data.petabencana.id/cities') # api_request = QNetworkRequest(api_url) # api_response = network_manager.get(api_request) # data = api_response.readAll() # json_response = QScriptEngine().evaluate(data) # geometries = json_response.property('output').property('geometries') # iterator = QScriptValueIterator(geometries) # while iterator.hasNext(): # iterator.next() # geometry = iterator.value() # geometry_code = ( # geometry.property('properties').property('code').toString()) # available_area.append(geometry_code) def populate_combo_box(self): """Populate combobox for selecting city.""" if self.radio_button_production.isChecked(): self.source = production_api['url'] available_data = production_api['available_data'] else: self.source = development_api['url'] available_data = development_api['available_data'] self.city_combo_box.clear() for index, data in enumerate(available_data): self.city_combo_box.addItem(data['name']) self.city_combo_box.setItemData( index, data['code'], Qt.UserRole) def define_url(self): """Define API url based on which source is selected. :return: Valid url of selected source. :rtype: str """ current_index = self.city_combo_box.currentIndex() city_code = self.city_combo_box.itemData(current_index, Qt.UserRole) source = (self.source).format(city_code=city_code) return source
class PetaBencanaDialog(QDialog, FORM_CLASS): """Downloader for PetaBencana data. .. versionadded: 3.3 """ def __init__(self, parent=None, iface=None): """Constructor for import dialog. .. versionadded: 3.3 :param parent: Optional widget to use as parent. :type parent: QWidget :param iface: An instance of QGisInterface. :type iface: QGisInterface """ QDialog.__init__(self, parent) self.parent = parent self.setupUi(self) title = self.tr('PetaBencana Downloader') self.setWindowTitle(title) self.iface = iface self.source = None self.radio_button_group = QButtonGroup() self.radio_button_group.addButton(self.radio_button_production) self.radio_button_group.addButton(self.radio_button_development) self.radio_button_group.setExclusive(True) self.radio_button_production.setChecked(True) self.populate_combo_box() developer_mode = setting('developer_mode', False, bool) if not developer_mode: self.radio_button_widget.hide() self.source_label.hide() self.output_group.adjustSize() # signals self.radio_button_production.clicked.connect(self.populate_combo_box) self.radio_button_development.clicked.connect(self.populate_combo_box) # creating progress dialog for download self.progress_dialog = QProgressDialog(self) self.progress_dialog.setAutoClose(False) self.progress_dialog.setWindowTitle(title) # Set up things for context help self.help_button = self.button_box.button(QtGui.QDialogButtonBox.Help) # Allow toggling the help button self.help_button.setCheckable(True) self.help_button.toggled.connect(self.help_toggled) self.main_stacked_widget.setCurrentIndex(1) # set up the validator for the file name prefix expression = QRegExp('^[A-Za-z0-9-_]*$') validator = QRegExpValidator(expression, self.filename_prefix) self.filename_prefix.setValidator(validator) self.time_stamp = None self.restore_state() @pyqtSlot() @pyqtSignature('bool') # prevents actions being handled twice def help_toggled(self, flag): """Show or hide the help tab in the stacked widget. .. versionadded: 3.3 :param flag: Flag indicating whether help should be shown or hidden. :type flag: bool """ if flag: self.help_button.setText(self.tr('Hide Help')) self.show_help() else: self.help_button.setText(self.tr('Show Help')) self.hide_help() def hide_help(self): """Hide the usage info from the user. .. versionadded:: 3.3 """ self.main_stacked_widget.setCurrentIndex(1) def show_help(self): """Show usage info to the user. .. versionadded: 3.3 """ # Read the header and footer html snippets self.main_stacked_widget.setCurrentIndex(0) header = html_header() footer = html_footer() string = header message = peta_bencana_help() string += message.to_html() string += footer self.help_web_view.setHtml(string) def restore_state(self): """Read last state of GUI from configuration file. .. versionadded: 3.3 """ settings = QSettings() try: last_path = settings.value('directory', type=str) except TypeError: last_path = '' self.output_directory.setText(last_path) def save_state(self): """Store current state of GUI to configuration file. .. versionadded: 3.3 """ settings = QSettings() settings.setValue('directory', self.output_directory.text()) @pyqtSignature('') # prevents actions being handled twice def on_directory_button_clicked(self): """Show a dialog to choose directory. .. versionadded: 3.3 """ # noinspection PyCallByClass,PyTypeChecker self.output_directory.setText( QFileDialog.getExistingDirectory( self, self.tr('Select download directory'))) def accept(self): """Do PetaBencana download and display it in QGIS. .. versionadded: 3.3 """ self.save_state() try: self.require_directory() except CanceledImportDialogError: return QtGui.qApp.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor)) source = self.define_url() # save the file as json first name = 'jakarta_flood.json' output_directory = self.output_directory.text() output_prefix = self.filename_prefix.text() overwrite = self.overwrite_flag.isChecked() date_stamp_flag = self.include_date_flag.isChecked() output_base_file_path = self.get_output_base_path( output_directory, output_prefix, date_stamp_flag, name, overwrite) title = self.tr("Can't access API") try: self.download(source, output_base_file_path) # Open downloaded file as QgsMapLayer layer = QgsVectorLayer(output_base_file_path, 'flood', 'ogr', False) except Exception as e: disable_busy_cursor() QMessageBox.critical(self, title, str(e)) return self.time_stamp = time.strftime('%d-%b-%Y %H:%M:%S') # Now save as shp name = 'jakarta_flood.shp' output_base_file_path = self.get_output_base_path( output_directory, output_prefix, date_stamp_flag, name, overwrite) QgsVectorFileWriter.writeAsVectorFormat(layer, output_base_file_path, 'CP1250', None, 'ESRI Shapefile') # Get rid of the GeoJSON layer and rather use local shp del layer self.copy_style(output_base_file_path) self.copy_keywords(output_base_file_path) layer = self.add_flooded_field(output_base_file_path) # check if the layer has feature or not if layer.featureCount() <= 0: city = self.city_combo_box.currentText() message = self.tr('There are no floods data available on {city} ' 'at this time.').format(city=city) display_warning_message_box(self, self.tr('No data'), message) disable_busy_cursor() else: # add the layer to the map registry = QgsMapLayerRegistry.instance() registry.addMapLayer(layer) disable_busy_cursor() self.done(QDialog.Accepted) def add_flooded_field(self, shapefile_path): """Create the layer from the local shp adding the flooded field. .. versionadded:: 3.3 Use this method to add a calculated field to a shapefile. The shapefile should have a field called 'count' containing the number of flood reports for the field. The field values will be set to 0 if the count field is < 1, otherwise it will be set to 1. :param shapefile_path: Path to the shapefile that will have the flooded field added. :type shapefile_path: basestring :return: A vector layer with the flooded field added. :rtype: QgsVectorLayer """ layer = QgsVectorLayer(shapefile_path, self.tr('Jakarta Floods'), 'ogr') # Add a calculated field indicating if a poly is flooded or not # from PyQt4.QtCore import QVariant layer.startEditing() # Add field with integer from 0 to 4 which represents the flood # class. Its the same as 'state' field except that is being treated # as a string. # This is used for cartography flood_class_field = QgsField('floodclass', QVariant.Int) layer.dataProvider().addAttributes([flood_class_field]) layer.commitChanges() layer.startEditing() flood_class_idx = layer.fieldNameIndex('floodclass') flood_class_expression = QgsExpression('to_int(state)') context = QgsExpressionContext() context.setFields(layer.pendingFields()) flood_class_expression.prepare(context) # Add field with boolean flag to say if the area is flooded # This is used by the impact function flooded_field = QgsField('flooded', QVariant.Int) layer.dataProvider().addAttributes([flooded_field]) layer.commitChanges() layer.startEditing() flooded_idx = layer.fieldNameIndex('flooded') flood_flag_expression = QgsExpression('state > 0') flood_flag_expression.prepare(context) for feature in layer.getFeatures(): context.setFeature(feature) feature[flood_class_idx] = flood_class_expression.evaluate(context) feature[flooded_idx] = flood_flag_expression.evaluate(context) layer.updateFeature(feature) layer.commitChanges() return layer def copy_keywords(self, shapefile_path): """Copy keywords from the OSM resource directory to the output path. .. versionadded: 3.3 In addition to copying the template, tokens within the template will be replaced with new values for the date token and title token. :param shapefile_path: Path to the shapefile that will have the flooded field added. :type shapefile_path: basestring """ source_xml_path = resources_path('petabencana', 'flood-keywords.xml') output_xml_path = shapefile_path.replace('shp', 'xml') LOGGER.info('Copying xml to: %s' % output_xml_path) title_token = '[TITLE]' new_title = self.tr('Jakarta Floods - %s' % self.time_stamp) date_token = '[DATE]' new_date = self.time_stamp with open(source_xml_path) as source_file, \ open(output_xml_path, 'w') as output_file: for line in source_file: line = line.replace(date_token, new_date) line = line.replace(title_token, new_title) output_file.write(line) @staticmethod def copy_style(shapefile_path): """Copy style from the OSM resource directory to the output path. .. versionadded: 3.3 :param shapefile_path: Path to the shapefile that should get the path added. :type shapefile_path: basestring """ source_qml_path = resources_path('petabencana', 'flood-style.qml') output_qml_path = shapefile_path.replace('shp', 'qml') LOGGER.info('Copying qml to: %s' % output_qml_path) copy(source_qml_path, output_qml_path) def get_output_base_path(self, output_directory, output_prefix, with_date_stamp, feature_type, overwrite): """Get a full base name path to save the shapefile. TODO: This is cut & paste from OSM - refactor to have one method :param output_directory: The directory where to put results. :type output_directory: str :param output_prefix: The prefix to add for the shapefile. :type output_prefix: str :param with_date_stamp: Whether to add a datestamp in between the file prefix and the feature_type for the shapefile name. :type output_prefix: str :param feature_type: What kind of data will be downloaded. Will be used for the shapefile name. :type feature_type: str :param overwrite: Boolean to know if we can overwrite existing files. :type overwrite: bool :return: The base path. :rtype: str """ if with_date_stamp and self.time_stamp is not None: time_stamp = self.time_stamp.replace(' ', '-') time_stamp = time_stamp.replace(':', '-') time_stamp += '-' feature_type = time_stamp + feature_type path = os.path.join(output_directory, '%s%s' % (output_prefix, feature_type)) if overwrite: # If a shapefile exists, we must remove it (only the .shp) shp = '%s.shp' % path if os.path.isfile(shp): os.remove(shp) else: separator = '-' suffix = self.get_unique_file_path_suffix('%s.shp' % path, separator) if suffix: path = os.path.join( output_directory, '%s%s%s%s' % (output_prefix, feature_type, separator, suffix)) return path @staticmethod def get_unique_file_path_suffix(file_path, separator='-', i=0): """Return the minimum number to suffix the file to not overwrite one. Example : /tmp/a.txt exists. - With file_path='/tmp/b.txt' will return 0. - With file_path='/tmp/a.txt' will return 1 (/tmp/a-1.txt) TODO: This is cut & paste from OSM - refactor to have one method :param file_path: The file to check. :type file_path: str :param separator: The separator to add before the prefix. :type separator: str :param i: The minimum prefix to check. :type i: int :return: The minimum prefix you should add to not overwrite a file. :rtype: int """ basename = os.path.splitext(file_path) if i != 0: file_path_test = os.path.join( '%s%s%s%s' % (basename[0], separator, i, basename[1])) else: file_path_test = file_path if os.path.isfile(file_path_test): return PetaBencanaDialog.get_unique_file_path_suffix( file_path, separator, i + 1) else: return i def require_directory(self): """Ensure directory path entered in dialog exist. When the path does not exist, this function will ask the user if he want to create it or not. TODO: This is cut & paste from OSM - refactor to have one method :raises: CanceledImportDialogError - when user choose 'No' in the question dialog for creating directory. """ path = self.output_directory.text() if os.path.exists(path): return title = self.tr('Directory %s not exist') % path question = self.tr( 'Directory %s not exist. Do you want to create it?') % path # noinspection PyCallByClass,PyTypeChecker answer = QMessageBox.question(self, title, question, QMessageBox.Yes | QMessageBox.No) if answer == QMessageBox.Yes: if len(path) != 0: os.makedirs(path) else: # noinspection PyCallByClass,PyTypeChecker,PyArgumentList display_warning_message_box( self, self.tr('InaSAFE error'), self.tr('Output directory can not be empty.')) raise CanceledImportDialogError() else: raise CanceledImportDialogError() def load_shapefile(self, feature_type, base_path): """Load downloaded shape file to QGIS Main Window. TODO: This is cut & paste from OSM - refactor to have one method :param feature_type: What kind of features should be downloaded. Currently 'buildings', 'building-points' or 'roads' are supported. :type feature_type: str :param base_path: The base path of the shape file (without extension). :type base_path: str :raises: FileMissingError - when buildings.shp not exist """ path = '%s.shp' % base_path if not os.path.exists(path): message = self.tr( '%s does not exist. The server does not have any data for ' 'this extent.' % path) raise FileMissingError(message) self.iface.addVectorLayer(path, feature_type, 'ogr') canvas_srid = self.canvas.mapSettings().destinationCrs().srsid() on_the_fly_projection = self.canvas.hasCrsTransformEnabled() if canvas_srid != 4326 and not on_the_fly_projection: if QGis.QGIS_VERSION_INT >= 20400: self.canvas.setCrsTransformEnabled(True) else: display_warning_message_bar( self.iface, self.tr('Enable \'on the fly\''), self.tr( 'Your current projection is different than EPSG:4326. ' 'You should enable \'on the fly\' to display ' 'correctly your layers')) def reject(self): """Redefinition of the method. It will call the super method. """ super(PetaBencanaDialog, self).reject() def download(self, url, output_path): """Download file from API url and write to output path. :param url: URL of the API. :type url: str :param output_path: Path of output file, :type output_path: str """ request_failed_message = self.tr( "Can't access PetaBencana API: {source}").format(source=url) downloader = FileDownloader(url, output_path) result, message = downloader.download() if not result: display_warning_message_box( self, self.tr('Download error'), self.tr(request_failed_message + '\n' + message)) if result == QNetworkReply.OperationCanceledError: display_warning_message_box(self, self.tr('Download error'), self.tr(message)) # The function below might be usefull for future usage. # def get_available_area(self): # """Function to automatically get the available area on API. # *still cannot get string data from QByteArray* # """ # available_area = [] # network_manager = QgsNetworkAccessManager.instance() # api_url = QUrl('https://data.petabencana.id/cities') # api_request = QNetworkRequest(api_url) # api_response = network_manager.get(api_request) # data = api_response.readAll() # json_response = QScriptEngine().evaluate(data) # geometries = json_response.property('output').property('geometries') # iterator = QScriptValueIterator(geometries) # while iterator.hasNext(): # iterator.next() # geometry = iterator.value() # geometry_code = ( # geometry.property('properties').property('code').toString()) # available_area.append(geometry_code) def populate_combo_box(self): """Populate combobox for selecting city.""" if self.radio_button_production.isChecked(): self.source = production_api['url'] available_data = production_api['available_data'] else: self.source = development_api['url'] available_data = development_api['available_data'] self.city_combo_box.clear() for index, data in enumerate(available_data): self.city_combo_box.addItem(data['name']) self.city_combo_box.setItemData(index, data['code'], Qt.UserRole) def define_url(self): """Define API url based on which source is selected. :return: Valid url of selected source. :rtype: str """ current_index = self.city_combo_box.currentIndex() city_code = self.city_combo_box.itemData(current_index, Qt.UserRole) source = (self.source).format(city_code=city_code) return source
def create_rows(self, layout): play_button_group = QButtonGroup(self) old_play_button_group = QButtonGroup(self) for num, (source, dest, text, dl_fname, dl_hash, extras, icon)\ in enumerate(self.list, 3): tt_text = self.build_text_help_label(text, source, extras) ico_label = QLabel('', self) ico_label.setToolTip(tt_text) if icon: ico_label.setPixmap(QPixmap.fromImage(icon)) layout.addWidget(ico_label, num, 0) tt_label = QLabel(text, self) tt_label.setToolTip(tt_text) layout.addWidget(tt_label, num, 1) if self.hide_text: tt_label.hide() # Play button. t_play_button = QPushButton(self) play_button_group.addButton(t_play_button, num - 3) t_play_button.setToolTip(self.play_help) t_play_button.setIcon(QIcon(os.path.join(icons_dir, 'play.png'))) layout.addWidget(t_play_button, num, self.play_column) if self.note[dest]: t_play_old_button = QPushButton(self) old_play_button_group.addButton(t_play_old_button, num - 3) t_play_old_button.setIcon( QIcon(os.path.join(icons_dir, 'play.png'))) if not self.hide_text: t_play_old_button.setToolTip(self.note[dest]) else: t_play_old_button.setToolTip(self.play_old_help_short) layout.addWidget(t_play_old_button, num, self.play_old_column) else: dummy_label = QLabel('', self) dummy_label.setToolTip(self.play_old_empty_line_help) layout.addWidget(dummy_label, num, self.play_old_column) # The group where we later look what to do: t_button_group = QButtonGroup(self) t_button_group.setExclusive(True) # Now the four buttons t_add_button = QPushButton(self) t_add_button.setCheckable(True) t_add_button.setChecked(True) t_add_button.setFlat(True) t_add_button.setToolTip(self.add_help_text_short) t_add_button.setIcon(QIcon(os.path.join(icons_dir, 'add.png'))) layout.addWidget(t_add_button, num, self.add_column) t_button_group.addButton(t_add_button, action['add']) t_keep_button = QPushButton(self) t_keep_button.setCheckable(True) t_keep_button.setFlat(True) t_keep_button.setToolTip(self.keep_help_text_short) t_keep_button.setIcon(QIcon(os.path.join(icons_dir, 'keep.png'))) layout.addWidget(t_keep_button, num, self.keep_column) t_button_group.addButton(t_keep_button, action['keep']) t_delete_button = QPushButton(self) t_delete_button.setCheckable(True) t_delete_button.setFlat(True) t_delete_button.setToolTip(self.delete_help_text_short) t_delete_button.setIcon(QIcon(os.path.join(icons_dir, 'delete.png'))) layout.addWidget(t_delete_button, num, self.delete_column) t_button_group.addButton(t_delete_button, action['delete']) t_blacklist_button = QPushButton(self) t_blacklist_button.setCheckable(True) t_blacklist_button.setFlat(True) t_blacklist_button.setToolTip(self.blacklist_help_text_short) t_blacklist_button.setIcon(QIcon(os.path.join(icons_dir, 'blacklist.png'))) if self.show_skull_and_bones: layout.addWidget( t_blacklist_button, num, self.blacklist_column) else: t_blacklist_button.hide() t_button_group.addButton(t_blacklist_button, action['blacklist']) self.buttons_groups.append(t_button_group) play_button_group.buttonClicked.connect( lambda button: play(self.list[play_button_group.id(button)][3])) old_play_button_group.buttonClicked.connect( lambda button: playFromText( self.note[self.list[old_play_button_group.id(button)][1]]))
class DateTimePickerWidget(datepicker_widget, QWidget): ok = pyqtSignal() cancel = pyqtSignal() """ A custom date picker with a time and date picker """ def __init__(self, parent=None, mode="DateTime"): super(DateTimePickerWidget, self).__init__(parent) self.setupUi(self) self.mode = mode self.group = QButtonGroup() self.group.setExclusive(True) self.group.addButton(self.ambutton) self.group.addButton(self.pmbutton) self.ambutton.toggled.connect(self.isDirty) self.pmbutton.toggled.connect(self.isDirty) self.datepicker.selectionChanged.connect(self.isDirty) self.hourpicker.itemSelectionChanged.connect(self.isDirty) self.minutepicker.itemSelectionChanged.connect(self.isDirty) self.setasnowbutton.pressed.connect(self.setAsNow) self.setWindowFlags(Qt.Dialog | Qt.CustomizeWindowHint) self.okButton.pressed.connect(self.ok.emit) self.closebutton.pressed.connect(self.cancel.emit) def setMinValue(self, mindate): self.datepicker.setMinimumDate(mindate) def setmode(self, mode): if mode == "Date": self.timesection.hide() self.setasnowbutton.setText("Set as current date") elif mode == "Time": self.datepicker.hide() self.setasnowbutton.setText("Set as current time") def isDirty(self, *args): date = self.getSelectedDate() time = self.getSelectedTime() datetime = QDateTime(date, time) if self.mode == "Date": value = datetime.toString("ddd d MMM yyyy") elif self.mode == "Time": value = datetime.toString("h:m ap") else: value = datetime.toString("ddd d MMM yyyy 'at' h:m ap") self.label.setText(value) def setDateTime(self, datetime): """ Set the picker to datatime datetime - The QDateTime with the value to set. """ self.setTime(datetime.time()) self.setDate(datetime.date()) def setAsNow(self): """ Set the current date and time on the picker as now. """ now = QDateTime.currentDateTime() self.setDateTime(now) def setTime(self, time): """ Set just the time part of the picker """ hour = time.hour() if hour > 12: hour = hour - 12 if hour == 0: hour = hour + 12 minute = time.minute() minute = int(round(minute / 5.0) * 5.0) amap = time.toString("AP") utils.log("Hour %s Minute %s" % (hour, minute)) try: houritems = self.hourpicker.findItems(str(hour), Qt.MatchFixedString) self.hourpicker.setCurrentItem(houritems[0]) except IndexError: utils.log("Can't find hour") try: minuteitems = self.minutepicker.findItems(str(minute), Qt.MatchFixedString) self.minutepicker.setCurrentItem(minuteitems[0]) except IndexError: utils.log("Can't find minute") if amap == "PM": self.pmbutton.toggle() def setDate(self, date): """ Set just the date part of the picker """ self.datepicker.setSelectedDate(date) def getSelectedTime(self): """ Returns the currently selected data and time """ try: hour = self.hourpicker.currentItem().text() except AttributeError: hour = "" try: minute = self.minutepicker.currentItem().text() except AttributeError: minute = "" zone = self.ambutton.isChecked() and "AM" or "PM" return QTime.fromString("%s%s%s" % (hour, minute, zone), "hmAP") def getSelectedDate(self): """ Returns just the date part of the picker """ return self.datepicker.selectedDate() @property def value(self): datetime = QDateTime() datetime.setDate(self.getSelectedDate()) datetime.setTime(self.getSelectedTime()) return datetime @value.setter def value(self, value): if value is None: self.setAsNow() return if isinstance(value, basestring): value = QDateTime.fromString(value, Qt.ISODate) self.setDate(value.date()) self.setTime(value.time())
class PreferencesView(QTabWidget): closed = pyqtSignal() def __init__(self, parent=None): super(PreferencesView, self).__init__(parent) self.setWindowTitle("Preferences") # self.setFixedSize(self.maximumSize()) # self.setMinimumSize(self.maximumSize()) # self.setMaximumSize(self.maximumSize()) # self.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) self.chemicalSimulationDt = self.createFloatingPointEditor() self.chemicalDiffusionDt = self.createFloatingPointEditor() self.chemicalPlotUpdateInterval = self.createFloatingPointEditor() self.chemicalDefaultSimulationRuntime = self.createFloatingPointEditor( ) self.chemicalGuiUpdateInterval = self.createFloatingPointEditor() self.chemicalSolver = QButtonGroup() self.chemicalSolvers = { "Exponential Euler": QRadioButton("Exponential Euler"), "Gillespie": QRadioButton("Gillespie"), "Runge Kutta": QRadioButton("Runge Kutta") } self.chemicalSimulationApply = QPushButton("Apply") self.chemicalSimulationCancel = QPushButton("Cancel") self.electricalSimulationDt = self.createFloatingPointEditor() self.electricalPlotUpdateInterval = self.createFloatingPointEditor() self.electricalDefaultSimulationRuntime = self.createFloatingPointEditor( ) self.electricalGuiUpdateInterval = self.createFloatingPointEditor() self.electricalSolver = QButtonGroup() self.electricalSolvers = { "Gillespie": QRadioButton("Gillespie"), "Runge Kutta": QRadioButton("Runge Kutta") } self.electricalSimulationApply = QPushButton("Apply") self.electricalSimulationCancel = QPushButton("Cancel") self.electricalVisualizationApply = QPushButton("Apply") self.electricalVisualizationCancel = QPushButton("Cancel") self.electricalBaseColorButton = QPushButton() self.electricalBaseColorDialog = QColorDialog() self.electricalPeakColorButton = QPushButton() self.electricalPeakColorDialog = QColorDialog() self.electricalBackgroundColorButton = QPushButton() self.electricalBackgroundColorDialog = QColorDialog() self.electricalBaseMembraneVoltage = self.createFloatingPointEditor() self.electricalPeakMembraneVoltage = self.createFloatingPointEditor() self.create() def closeEvent(self, event): self.closed.emit() def create(self): # Set up the column titles self.setUsesScrollButtons(True) self.setFocusPolicy(PyQt4.QtCore.Qt.NoFocus) self.addTab(self.createChemicalSettingsTab(), "Chemical") self.addTab(self.createElectricalSettingsTab(), "Electrical") def createChemicalSettingsTab(self): chemicalSettingsTab = QWidget() layout = QtGui.QGridLayout() chemicalSettingsTab.setLayout(layout) layout.addWidget(QLabel('Simulation dt'), 0, 0) layout.addWidget(self.chemicalSimulationDt, 0, 1) layout.addWidget(QLabel('Diffusion dt'), 1, 0) layout.addWidget(self.chemicalDiffusionDt, 1, 1) layout.addWidget(QLabel('Plot Update Interval'), 2, 0) layout.addWidget(self.chemicalPlotUpdateInterval, 2, 1) layout.addWidget(QLabel('GUI Update Interval'), 3, 0) layout.addWidget(self.chemicalGuiUpdateInterval, 3, 1) # layout.addWidget(QLabel('Default Runtime'), 4, 0) # layout.addWidget(self.chemicalDefaultSimulationRuntime, 4, 1) layout.addWidget(QLabel('Solver'), 5, 0) index = 0 for solver in self.chemicalSolvers: layout.addWidget(self.chemicalSolvers[solver], 5 + index, 1) self.chemicalSolver.addButton(self.chemicalSolvers[solver], index) self.chemicalSolvers[solver].setFocusPolicy( PyQt4.QtCore.Qt.NoFocus) index += 1 self.chemicalSolver.setExclusive(True) buttonLayout = QGridLayout() layout.addLayout(buttonLayout, 5 + index, 1) buttonLayout.addWidget(self.chemicalSimulationCancel, 0, 0, Qt.Qt.AlignRight) buttonLayout.addWidget(self.chemicalSimulationApply, 0, 1, Qt.Qt.AlignLeft) return chemicalSettingsTab def createElectricalSettingsTab(self): electricalSettingsTab = QTabWidget() electricalSettingsTab.addTab( self.createElectricalSimulationSettingsTab(), "Simulation") electricalSettingsTab.addTab( self.createElectricalSimulationVisualizationTab(), "Visualization") electricalSettingsTab.setTabPosition(QTabWidget.East) electricalSettingsTab.setTabShape(QTabWidget.Triangular) electricalSettingsTab.setDocumentMode(True) electricalSettingsTab.setUsesScrollButtons(True) electricalSettingsTab.setFocusPolicy(PyQt4.QtCore.Qt.NoFocus) return electricalSettingsTab def createElectricalSimulationSettingsTab(self): widget = QWidget() layout = QtGui.QGridLayout() widget.setLayout(layout) layout.addWidget(QLabel('Simulation dt'), 0, 0) layout.addWidget(self.electricalSimulationDt, 0, 1) layout.addWidget(QLabel('Plot Update Interval'), 2, 0) layout.addWidget(self.electricalPlotUpdateInterval, 2, 1) layout.addWidget(QLabel('GUI Update Interval'), 3, 0) layout.addWidget(self.electricalGuiUpdateInterval, 3, 1) # layout.addWidget(QLabel('Default Runtime'), 4, 0) # layout.addWidget(self.electricalDefaultSimulationRuntime, 4, 1) # layout.addWidget(QLabel('Solver'), 5, 0) index = 0 for solver in self.electricalSolvers: # layout.addWidget(self.electricalSolvers[solver], 5 + index, 1) self.electricalSolver.addButton(self.electricalSolvers[solver], index) self.electricalSolvers[solver].setFocusPolicy( PyQt4.QtCore.Qt.NoFocus) index += 1 self.electricalSolver.setExclusive(True) buttonLayout = QGridLayout() layout.addLayout(buttonLayout, 5 + index, 1) buttonLayout.addWidget(self.electricalSimulationCancel, 0, 0, Qt.Qt.AlignRight) buttonLayout.addWidget(self.electricalSimulationApply, 0, 1, Qt.Qt.AlignLeft) return widget def createElectricalSimulationVisualizationTab(self): widget = QWidget() layout = QtGui.QGridLayout() widget.setLayout(layout) layout.addWidget(QLabel('Base Membrane Voltage'), 1, 0) layout.addWidget(self.electricalBaseMembraneVoltage, 1, 1) layout.addWidget(QLabel('Base Compartment Color'), 2, 0) self.electricalBaseColorDialog.setOption(QColorDialog.ShowAlphaChannel, True) layout.addWidget(self.electricalBaseColorButton, 2, 1) self.electricalBaseColorButton.clicked.connect( self.electricalBaseColorDialog.show) self.electricalBaseColorButton.setFocusPolicy(PyQt4.QtCore.Qt.NoFocus) self.electricalBaseColorDialog.colorSelected.connect( lambda color: self.electricalBaseColorButton.setStyleSheet( "QPushButton {" + "background-color: {0}; color: {0};".format( color.name()) + "}")) layout.addWidget(QLabel('Peak Membrane Voltage'), 3, 0) layout.addWidget(self.electricalPeakMembraneVoltage, 3, 1) layout.addWidget(QLabel('Peak Compartment Color'), 4, 0) self.electricalPeakColorDialog.setOption(QColorDialog.ShowAlphaChannel, True) layout.addWidget(self.electricalPeakColorButton, 4, 1) self.electricalPeakColorButton.clicked.connect( self.electricalPeakColorDialog.show) self.electricalPeakColorButton.setFocusPolicy(PyQt4.QtCore.Qt.NoFocus) self.electricalPeakColorDialog.colorSelected.connect( lambda color: self.electricalPeakColorButton.setStyleSheet( "QPushButton {" + "background-color: {0}; color: {0};".format( color.name()) + "}")) layout.addWidget(QLabel('Background Color'), 5, 0) self.electricalBackgroundColorDialog.setOption( QColorDialog.ShowAlphaChannel, True) layout.addWidget(self.electricalBackgroundColorButton, 5, 1) self.electricalBackgroundColorButton.clicked.connect( self.electricalBackgroundColorDialog.show) self.electricalBackgroundColorButton.setFocusPolicy( PyQt4.QtCore.Qt.NoFocus) self.electricalBackgroundColorDialog.colorSelected.connect( lambda color: self.electricalBackgroundColorButton.setStyleSheet( "QPushButton {" + "background-color: {0}; color: {0};".format( color.name()) + "}")) buttonLayout = QGridLayout() layout.addLayout(buttonLayout, 6, 1) buttonLayout.addWidget(self.electricalVisualizationCancel, 0, 0, Qt.Qt.AlignRight) buttonLayout.addWidget(self.electricalVisualizationApply, 0, 1, Qt.Qt.AlignLeft) return widget def createFloatingPointEditor(self, value=0.0, minValue=float("-inf"), maxValue=float("+inf"), decimals=1000): floatingPointEditor = QLineEdit(str(value)) floatingPointEditor.setValidator( QDoubleValidator(minValue, maxValue, decimals)) return floatingPointEditor