Example #1
0
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()
Example #2
0
 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)
Example #3
0
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)
Example #5
0
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
Example #6
0
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()
Example #9
0
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)
Example #10
0
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}
Example #11
0
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)
Example #12
0
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_()
Example #13
0
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()
Example #14
0
def createLabelAndList(labelText):
    widget, label = _createLabelInWidget(labelText, QGridLayout)
    buttonGroup = QButtonGroup(widget)
    buttonGroup.setObjectName('buttonGroup')
    buttonGroup.setExclusive(False)
    return (widget, label, buttonGroup)
Example #15
0
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}
Example #16
0
 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)
Example #19
0
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))
Example #21
0
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")
Example #22
0
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()
Example #24
0
    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)
Example #25
0
 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)
Example #27
0
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")
Example #28
0
 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]]))
Example #29
0
    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()
Example #31
0
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
Example #34
0
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
Example #35
0
 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]]))
Example #36
0
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