예제 #1
0
class About(QDialog):

    ICON = util.file_path(__file__, "icon.png")

    def __init__(self, parent=None):
        super().__init__(parent)

        self.setWindowModality(QtCore.Qt.ApplicationModal)
        self.setWindowTitle('About Linux Show Player')
        self.setMaximumSize(500, 420)
        self.setMinimumSize(500, 420)
        self.resize(500, 420)

        self.setLayout(QGridLayout())

        self.icon = QLabel(self)
        self.icon.setPixmap(QPixmap(self.ICON).scaled(100, 100,
                            transformMode=Qt.SmoothTransformation))
        self.layout().addWidget(self.icon, 0, 0)

        self.shortInfo = QLabel(self)
        self.shortInfo.setAlignment(Qt.AlignCenter)
        self.shortInfo.setText('<h2>Linux Show Player   ' +
                               str(lisp.__version__) + '</h2>'
                               'Copyright © Francesco Ceruti')
        self.layout().addWidget(self.shortInfo, 0, 1)

        self.layout().addWidget(QWidget(), 1, 0, 1, 2)

        # Informations tabs
        self.tabWidget = QTabWidget(self)
        self.layout().addWidget(self.tabWidget, 2, 0, 1, 2)

        self.info = QTextBrowser(self)
        self.info.setOpenExternalLinks(True)
        self.info.setHtml(self.INFO)
        self.tabWidget.addTab(self.info, 'Info')

        self.license = QTextBrowser(self)
        self.license.setOpenExternalLinks(True)
        self.license.setHtml(self.LICENSE)
        self.tabWidget.addTab(self.license, 'License')

        self.contributors = QTextBrowser(self)
        self.contributors.setOpenExternalLinks(True)
        self.contributors.setHtml(self.CONTRIBUTORS)
        self.tabWidget.addTab(self.contributors, 'Contributors')

        # Ok button
        self.buttons = QDialogButtonBox(QDialogButtonBox.Ok)
        self.buttons.accepted.connect(self.accept)
        self.layout().addWidget(self.buttons, 3, 1)

        self.layout().setColumnStretch(0, 1)
        self.layout().setColumnStretch(1, 3)

        self.layout().setRowStretch(0, 6)
        self.layout().setRowStretch(1, 1)
        self.layout().setRowStretch(2, 16)
        self.layout().setRowStretch(3, 3)

        self.buttons.setFocus()

    LICENSE = '''
<center>
    Linux Show Player is free software: you can redistribute it and/or
    modify it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.<br />
    <br />
    Linux Show Player is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
</center>'''

    INFO = '''
<center><br />
    Linux Show Player is a cue-player designed for stage productions.<br \>
</center>
<center><br />
    Web site: <a href="http://linux-show-player.sourceforge.net">linux-show-player.sourceforge.net</a><br \>
    User group: <a href="http://groups.google.com/group/linux-show-player---users">groups.google.com</a><br \>
    Source code: <a href="https://github.com/FrancescoCeruti/linux-show-player">GitHub</a>
</center>'''

    CONTRIBUTORS = '''
예제 #2
0
class TriggerRecordDialog(QDialog):
    def __init__(self, initialTriggerChannel, initialTriggerPolarity, initialTriggerBuffer, initialPostTrigger, initialSaveTriggerChannel, parent):
        super().__init__(parent)

        self.setWindowTitle("Episodic Triggered Recording Control")

        label1 = QLabel(
            "Digital or analog inputs lines may be used to trigger recording.  If an analog input line is selected, the threshold between logic high and logic low is 1.65 V.")
        label1.setWordWrap(True)

        digitalInputComboBox = QComboBox()
        digitalInputComboBox.addItem("Digital Input 0")
        digitalInputComboBox.addItem("Digital Input 1")
        digitalInputComboBox.addItem("Digital Input 2")
        digitalInputComboBox.addItem("Digital Input 3")
        digitalInputComboBox.addItem("Digital Input 4")
        digitalInputComboBox.addItem("Digital Input 5")
        digitalInputComboBox.addItem("Digital Input 6")
        digitalInputComboBox.addItem("Digital Input 7")
        digitalInputComboBox.addItem("Digital Input 8")
        digitalInputComboBox.addItem("Digital Input 9")
        digitalInputComboBox.addItem("Digital Input 10")
        digitalInputComboBox.addItem("Digital Input 11")
        digitalInputComboBox.addItem("Digital Input 12")
        digitalInputComboBox.addItem("Digital Input 13")
        digitalInputComboBox.addItem("Digital Input 14")
        digitalInputComboBox.addItem("Digital Input 15")
        digitalInputComboBox.addItem("Analog Input 1")
        digitalInputComboBox.addItem("Analog Input 2")
        digitalInputComboBox.addItem("Analog Input 3")
        digitalInputComboBox.addItem("Analog Input 4")
        digitalInputComboBox.addItem("Analog Input 5")
        digitalInputComboBox.addItem("Analog Input 6")
        digitalInputComboBox.addItem("Analog Input 7")
        digitalInputComboBox.addItem("Analog Input 8")
        digitalInputComboBox.setCurrentIndex(initialTriggerChannel)

        digitalInputComboBox.currentIndexChanged.connect(self.setDigitalInput)

        triggerPolarityComboBox = QComboBox()
        triggerPolarityComboBox.addItem("Trigger on Logic High")
        triggerPolarityComboBox.addItem("Trigger on Logic Low")
        triggerPolarityComboBox.setCurrentIndex(initialTriggerPolarity)

        triggerPolarityComboBox.currentIndexChanged.connect(
            self.setTriggerPolarity)

        self.saveTriggerChannelCheckBox = QCheckBox(
            "Automatically Save Trigger Channel")
        self.saveTriggerChannelCheckBox.setChecked(initialSaveTriggerChannel)

        triggerControls = QVBoxLayout()
        triggerControls.addWidget(digitalInputComboBox)
        triggerControls.addWidget(triggerPolarityComboBox)
        triggerControls.addWidget(self.saveTriggerChannelCheckBox)

        triggerHBox = QHBoxLayout()
        triggerHBox.addLayout(triggerControls)
        triggerHBox.addStretch(1)

        triggerLayout = QVBoxLayout()
        triggerLayout.addWidget(label1)
        triggerLayout.addLayout(triggerHBox)

        triggerGroupBox = QGroupBox("Trigger Source")
        triggerGroupBox.setLayout(triggerLayout)

        triggerHLayout = QHBoxLayout()
        triggerHLayout.addWidget(triggerGroupBox)

        recordBufferSpinBox = QSpinBox()
        recordBufferSpinBox.setRange(1, 30)
        recordBufferSpinBox.setValue(initialTriggerBuffer)

        recordBufferSpinBox.valueChanged.connect(self.recordBufferSeconds)

        bufferSpinBoxLayout = QHBoxLayout()
        bufferSpinBoxLayout.addWidget(recordBufferSpinBox)
        bufferSpinBoxLayout.addWidget(QLabel("seconds"))
        bufferSpinBoxLayout.addStretch(1)

        label2 = QLabel("If a pretrigger buffer size of N seconds is selected, "
                        "slightly more than N seconds of pretrigger data will be "
                        "saved to disk when a trigger is detected, assuming that "
                        "data acquisition has been running for at least N seconds.")
        label2.setWordWrap(True)

        bufferSelectLayout = QVBoxLayout()
        bufferSelectLayout.addWidget(
            QLabel("Pretrigger data saved (range: 1-30 seconds):"))
        bufferSelectLayout.addLayout(bufferSpinBoxLayout)
        bufferSelectLayout.addWidget(label2)

        bufferGroupBox = QGroupBox("Pretrigger Buffer")
        bufferGroupBox.setLayout(bufferSelectLayout)

        bufferHLayout = QHBoxLayout()
        bufferHLayout.addWidget(bufferGroupBox)
    #    bufferHLayout.addStretch(1)

        postTriggerSpinBox = QSpinBox()
        postTriggerSpinBox.setRange(1, 9999)
        postTriggerSpinBox.setValue(initialPostTrigger)

        postTriggerSpinBox.valueChanged.connect(self.postTriggerSeconds)

        postTriggerSpinBoxLayout = QHBoxLayout()
        postTriggerSpinBoxLayout.addWidget(postTriggerSpinBox)
        postTriggerSpinBoxLayout.addWidget(QLabel("seconds"))
        postTriggerSpinBoxLayout.addStretch(1)

        label4 = QLabel("If a posttrigger time of M seconds is selected, "
                        "slightly more than M seconds of data will be "
                        "saved to disk after the trigger is de-asserted.")
        label4.setWordWrap(True)

        postTriggerSelectLayout = QVBoxLayout()
        postTriggerSelectLayout.addWidget(
            QLabel("Posttrigger data saved (range: 1-9999 seconds):"))
        postTriggerSelectLayout.addLayout(postTriggerSpinBoxLayout)
        postTriggerSelectLayout.addWidget(label4)

        postTriggerGroupBox = QGroupBox("Posttrigger Buffer")
        postTriggerGroupBox.setLayout(postTriggerSelectLayout)

        postTriggerHLayout = QHBoxLayout()
        postTriggerHLayout.addWidget(postTriggerGroupBox)
    #    postTriggerHLayout.addStretch(1)

        self.buttonBox = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel)

        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        label3 = QLabel("Press OK to start triggered recording with selected settings.  "
                        "Waveforms will be displayed in real time, but recording will "
                        "not start until the trigger is detected.  A tone will indicate "
                        "when the trigger has been detected.  A different tone indicates "
                        "that recording has stopped after a trigger has been de-asserted.  "
                        "Successive trigger events will create saved data files.  "
                        "Press the Stop button to exit triggered recording mode.")
        label3.setWordWrap(True)

        mainLayout = QVBoxLayout()
        mainLayout.addLayout(triggerHLayout)
        mainLayout.addLayout(bufferHLayout)
        mainLayout.addLayout(postTriggerHLayout)
        mainLayout.addWidget(label3)
        mainLayout.addWidget(self.buttonBox)

        self.setLayout(mainLayout)

        self.setDigitalInput(digitalInputComboBox.currentIndex())
        self.setTriggerPolarity(triggerPolarityComboBox.currentIndex())
        self.recordBufferSeconds(recordBufferSpinBox.value())
        self.postTriggerSeconds(postTriggerSpinBox.value())

    def setDigitalInput(self, index):
        self.digitalInput = index

    def setTriggerPolarity(self, index):
        self.triggerPolarity = index

    def recordBufferSeconds(self, value):
        self.recordBuffer = value
        self.buttonBox.setFocus()

    def postTriggerSeconds(self, value):
        self.postTriggerTime = value
        self.buttonBox.setFocus()
예제 #3
0
class GuiTimeLineView(QDialog):
    def __init__(self, theParent, theProject, theIndex):
        QDialog.__init__(self, theParent)

        logger.debug("Initialising TimeLineView ...")

        self.mainConf = nw.CONFIG
        self.theProject = theProject
        self.theParent = theParent
        self.theIndex = theIndex
        self.optState = TimeLineLastState(self.theProject, nwFiles.TLINE_OPT)
        self.optState.loadSettings()

        self.theMatrix = {}
        self.numRows = 0
        self.numCols = 0

        self.outerBox = QVBoxLayout()
        self.filterBox = QVBoxLayout()
        self.centreBox = QHBoxLayout()
        self.bottomBox = QHBoxLayout()

        self.setWindowTitle("Timeline View")
        self.setMinimumWidth(700)
        self.setMinimumHeight(400)

        winWidth = self.optState.validIntRange(
            self.optState.getSetting("winWidth"), 700, 10000, 700)
        winHeight = self.optState.validIntRange(
            self.optState.getSetting("winHeight"), 400, 10000, 400)
        self.resize(winWidth, winHeight)

        # TimeLine Table
        self.mainTable = QTableWidget()
        self.mainTable.setGridStyle(Qt.NoPen)

        self.hHeader = self.mainTable.horizontalHeader()
        self.hHeader.setSectionResizeMode(QHeaderView.ResizeToContents)
        self.mainTable.setHorizontalHeader(self.hHeader)

        self.vHeader = self.mainTable.verticalHeader()
        self.vHeader.setSectionResizeMode(QHeaderView.ResizeToContents)
        self.mainTable.setVerticalHeader(self.vHeader)

        # Option Box
        self.optFilter = QGroupBox("Include Tags", self)
        self.optFilterGrid = QGridLayout(self)
        self.optFilter.setLayout(self.optFilterGrid)

        self.filterPlot = QCheckBox("Plot tags", self)
        self.filterPlot.setChecked(self.optState.getSetting("fPlot"))
        self.filterPlot.stateChanged.connect(self._filterChange)

        self.filterChar = QCheckBox("Character tags", self)
        self.filterChar.setChecked(self.optState.getSetting("fChar"))
        self.filterChar.stateChanged.connect(self._filterChange)

        self.filterWorld = QCheckBox("Location tags", self)
        self.filterWorld.setChecked(self.optState.getSetting("fWorld"))
        self.filterWorld.stateChanged.connect(self._filterChange)

        self.filterTime = QCheckBox("Timeline tags", self)
        self.filterTime.setChecked(self.optState.getSetting("fTime"))
        self.filterTime.stateChanged.connect(self._filterChange)

        self.filterObject = QCheckBox("Object tags", self)
        self.filterObject.setChecked(self.optState.getSetting("fObject"))
        self.filterObject.stateChanged.connect(self._filterChange)

        self.filterCustom = QCheckBox("Custom tags", self)
        self.filterCustom.setChecked(self.optState.getSetting("fCustom"))
        self.filterCustom.stateChanged.connect(self._filterChange)

        self.optFilterGrid.addWidget(self.filterPlot, 0, 1)
        self.optFilterGrid.addWidget(self.filterChar, 1, 1)
        self.optFilterGrid.addWidget(self.filterWorld, 2, 1)
        self.optFilterGrid.addWidget(self.filterTime, 3, 1)
        self.optFilterGrid.addWidget(self.filterObject, 4, 1)
        self.optFilterGrid.addWidget(self.filterCustom, 5, 1)

        self.optHide = QGroupBox("Filters", self)
        self.optHideGrid = QGridLayout(self)
        self.optHide.setLayout(self.optHideGrid)

        self.hideUnused = QCheckBox("Hide unused", self)
        self.hideUnused.setChecked(self.optState.getSetting("hUnused"))
        self.hideUnused.stateChanged.connect(self._filterChange)

        self.optHideGrid.addWidget(self.hideUnused, 0, 1)

        # Button Box
        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
        self.buttonBox.rejected.connect(self._doClose)

        self.btnRebuild = QPushButton("Rebuild Index")
        self.btnRebuild.clicked.connect(self.theParent.rebuildIndex)

        self.btnRefresh = QPushButton("Refresh Table")
        self.btnRefresh.clicked.connect(self._buildNovelList)

        self.bottomBox.addWidget(self.btnRebuild)
        self.bottomBox.addWidget(self.btnRefresh)
        self.bottomBox.addStretch()
        self.bottomBox.addWidget(self.buttonBox)

        # Assemble
        self.filterBox.addWidget(self.optFilter)
        self.filterBox.addWidget(self.optHide)
        self.filterBox.addStretch()
        self.centreBox.addWidget(self.mainTable)
        self.centreBox.addLayout(self.filterBox)
        self.outerBox.addLayout(self.centreBox)
        self.outerBox.addLayout(self.bottomBox)
        self.setLayout(self.outerBox)

        self._buildNovelList()
        self.buttonBox.setFocus()

        self.show()

        logger.debug("TimeLineView initialisation complete")

        return

    def _buildNovelList(self):

        self.mainTable.clear()
        self.theIndex.buildNovelList()

        self.numRows = len(self.theIndex.novelList)
        self.mainTable.setRowCount(self.numRows)

        theFilters = {}
        theFilters["exClass"] = []
        theFilters["hUnused"] = self.hideUnused.isChecked()

        if not self.filterPlot.isChecked():
            theFilters["exClass"].append(nwItemClass.PLOT)
        if not self.filterChar.isChecked():
            theFilters["exClass"].append(nwItemClass.CHARACTER)
        if not self.filterWorld.isChecked():
            theFilters["exClass"].append(nwItemClass.WORLD)
        if not self.filterTime.isChecked():
            theFilters["exClass"].append(nwItemClass.TIMELINE)
        if not self.filterObject.isChecked():
            theFilters["exClass"].append(nwItemClass.OBJECT)
        if not self.filterCustom.isChecked():
            theFilters["exClass"].append(nwItemClass.CUSTOM)

        for n in range(len(self.theIndex.novelList)):
            iDepth = self.theIndex.novelList[n][1]
            iTitle = self.theIndex.novelList[n][2]
            newItem = QTableWidgetItem("%s%s  " % ("  " * iDepth, iTitle))
            self.mainTable.setVerticalHeaderItem(n, newItem)

        theMap = self.theIndex.buildTagNovelMap(self.theIndex.tagIndex.keys(),
                                                theFilters)
        self.numCols = len(theMap.keys())
        self.mainTable.setColumnCount(self.numCols)

        nCol = 0
        for theTag, theCols in theMap.items():
            newItem = QTableWidgetItem(" %s " % theTag)
            self.mainTable.setHorizontalHeaderItem(nCol, newItem)
            for n in range(len(theCols)):
                if theCols[n] == 1:
                    pxNew = QPixmap(10, 10)
                    pxNew.fill(QColor(0, 120, 0))
                    lblNew = QLabel()
                    lblNew.setPixmap(pxNew)
                    lblNew.setAlignment(Qt.AlignCenter)
                    lblNew.setAttribute(Qt.WA_TranslucentBackground)
                    self.mainTable.setCellWidget(n, nCol, lblNew)
                elif theCols[n] == 2:
                    pxNew = QPixmap(10, 10)
                    pxNew.fill(QColor(0, 0, 120))
                    lblNew = QLabel()
                    lblNew.setPixmap(pxNew)
                    lblNew.setAlignment(Qt.AlignCenter)
                    lblNew.setAttribute(Qt.WA_TranslucentBackground)
                    self.mainTable.setCellWidget(n, nCol, lblNew)
            nCol += 1

        return

    def _doClose(self):

        logger.verbose("GuiTimeLineView close button clicked")

        winWidth = self.width()
        winHeight = self.height()
        fPlot = self.filterPlot.isChecked()
        fChar = self.filterChar.isChecked()
        fWorld = self.filterWorld.isChecked()
        fTime = self.filterTime.isChecked()
        fObject = self.filterObject.isChecked()
        fCustom = self.filterCustom.isChecked()
        hUnused = self.hideUnused.isChecked()

        self.optState.setSetting("winWidth", winWidth)
        self.optState.setSetting("winHeight", winHeight)
        self.optState.setSetting("fPlot", fPlot)
        self.optState.setSetting("fChar", fChar)
        self.optState.setSetting("fWorld", fWorld)
        self.optState.setSetting("fTime", fTime)
        self.optState.setSetting("fObject", fObject)
        self.optState.setSetting("fCustom", fCustom)
        self.optState.setSetting("hUnused", hUnused)

        self.optState.saveSettings()
        self.close()

        return

    def _filterChange(self, checkState):
        self._buildNovelList()
        return
예제 #4
0
class GuiTimeLineView(QDialog):
    def __init__(self, theParent, theProject, theIndex):
        QDialog.__init__(self, theParent)

        logger.debug("Initialising TimeLineView ...")

        self.mainConf = nw.CONFIG
        self.theProject = theProject
        self.theParent = theParent
        self.theIndex = theIndex
        self.theMatrix = {}
        self.numRows = 0
        self.numCols = 0

        self.outerBox = QVBoxLayout()
        self.bottomBox = QHBoxLayout()

        self.setWindowTitle("Timeline View")
        self.setMinimumSize(*self.mainConf.dlgTimeLine)

        self.mainTable = QTableWidget()
        self.mainTable.setGridStyle(Qt.NoPen)

        self.hHeader = self.mainTable.horizontalHeader()
        self.hHeader.setSectionResizeMode(QHeaderView.ResizeToContents)
        self.mainTable.setHorizontalHeader(self.hHeader)

        self.vHeader = self.mainTable.verticalHeader()
        self.vHeader.setSectionResizeMode(QHeaderView.ResizeToContents)
        self.mainTable.setVerticalHeader(self.vHeader)

        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
        self.buttonBox.rejected.connect(self._doClose)

        self.btnRebuild = QPushButton("Rebuild Index")
        self.btnRebuild.clicked.connect(self.theParent.rebuildIndex)

        self.btnRefresh = QPushButton("Refresh Table")
        self.btnRefresh.clicked.connect(self._buildNovelList)

        self.setLayout(self.outerBox)
        self.outerBox.addWidget(self.mainTable)
        self.outerBox.addLayout(self.bottomBox)
        self.bottomBox.addWidget(self.btnRebuild)
        self.bottomBox.addWidget(self.btnRefresh)
        self.bottomBox.addStretch()
        self.bottomBox.addWidget(self.buttonBox)

        self._buildNovelList()
        self.buttonBox.setFocus()

        self.show()

        logger.debug("TimeLineView initialisation complete")

        return

    def _buildNovelList(self):

        self.theIndex.buildNovelList()
        self.numRows = len(self.theIndex.novelList)
        self.numCols = len(self.theIndex.tagIndex.keys())

        self.mainTable.clear()
        self.mainTable.setRowCount(self.numRows)
        self.mainTable.setColumnCount(self.numCols)

        for n in range(len(self.theIndex.novelList)):
            iDepth = self.theIndex.novelList[n][1]
            iTitle = self.theIndex.novelList[n][2]
            newItem = QTableWidgetItem("%s%s  " % ("  " * iDepth, iTitle))
            self.mainTable.setVerticalHeaderItem(n, newItem)

        theMap = self.theIndex.buildTagNovelMap(self.theIndex.tagIndex.keys())
        nCol = 0
        for theTag, theCols in theMap.items():
            newItem = QTableWidgetItem(" %s " % theTag)
            self.mainTable.setHorizontalHeaderItem(nCol, newItem)
            for n in range(len(theCols)):
                if theCols[n] == 1:
                    pxNew = QPixmap(10, 10)
                    pxNew.fill(QColor(0, 120, 0))
                    lblNew = QLabel()
                    lblNew.setPixmap(pxNew)
                    lblNew.setAlignment(Qt.AlignCenter)
                    lblNew.setAttribute(Qt.WA_TranslucentBackground)
                    self.mainTable.setCellWidget(n, nCol, lblNew)
                elif theCols[n] == 2:
                    pxNew = QPixmap(10, 10)
                    pxNew.fill(QColor(0, 0, 120))
                    lblNew = QLabel()
                    lblNew.setPixmap(pxNew)
                    lblNew.setAlignment(Qt.AlignCenter)
                    lblNew.setAttribute(Qt.WA_TranslucentBackground)
                    self.mainTable.setCellWidget(n, nCol, lblNew)
            nCol += 1

        return

    def _doClose(self):
        self.mainConf.setTLineSize(self.width(), self.height())
        self.close()
        return
예제 #5
0
class About(QDialog):
    LICENSE = '''
    <p>
    Linux Show Player is free software: you can redistribute it and/or<br />
    modify it under the terms of the GNU General Public License as published by<br />
    the Free Software Foundation, either version 3 of the License, or<br />
    (at your option) any later version.<br />
    <br />
    Linux Show Player is distributed in the hope that it will be useful,<br />
    but WITHOUT ANY WARRANTY; without even the implied warranty of<br />
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the<br />
    GNU General Public License for more details.
    </p>
    '''

    DESCRIPTION = QT_TRANSLATE_NOOP(
        'AboutDialog',
        'Linux Show Player is a cue-player designed for stage productions.')
    WEB_SITE = 'http://linux-show-player.sourceforge.net'
    USER_GROUP = 'http://groups.google.com/group/linux-show-player---users'
    SOURCE_CODE = 'https://github.com/FrancescoCeruti/linux-show-player'

    CONTRIBUTORS = OrderedDict({
        QT_TRANSLATE_NOOP('About', 'Authors'):
        [('Francesco Ceruti', '*****@*****.**')],
        QT_TRANSLATE_NOOP('About', 'Contributors'):
        [('Yinameah', 'https://github.com/Yinameah'),
         ('nodiscc', 'https://github.com/nodiscc'),
         ('Thomas Achtner', '*****@*****.**')],
        QT_TRANSLATE_NOOP('About', 'Translators'):
        [('aroomthedoomed', 'https://github.com/aroomthedoomed'),
         ('fri', 'https://www.transifex.com/user/profile/fri'),
         ('Luis García-Tornel', '*****@*****.**'),
         ('miharix', 'https://github.com/miharix'),
         ('Olivier Humbert', 'https://github.com/trebmuh')],
    })

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowModality(QtCore.Qt.ApplicationModal)
        self.setWindowTitle(translate('About', 'About Linux Show Player'))
        self.setMaximumSize(500, 420)
        self.setMinimumSize(500, 420)
        self.resize(500, 420)

        self.setLayout(QGridLayout())

        self.iconLabel = QLabel(self)
        self.iconLabel.setPixmap(
            QIcon.fromTheme('linux-show-player').pixmap(100, 100))
        self.layout().addWidget(self.iconLabel, 0, 0)

        self.shortInfo = QLabel(self)
        self.shortInfo.setAlignment(Qt.AlignCenter)
        self.shortInfo.setText('<h2>Linux Show Player   {0}</h2>'
                               'Copyright © Francesco Ceruti'.format(
                                   str(lisp.__version__)))
        self.layout().addWidget(self.shortInfo, 0, 1)

        self.layout().addWidget(QWidget(), 1, 0, 1, 2)

        # Information tabs
        self.tabWidget = QTabWidget(self)
        self.layout().addWidget(self.tabWidget, 2, 0, 1, 2)

        self.info = QTextBrowser(self)
        self.info.setOpenExternalLinks(True)
        self.info.setHtml('''
            <center><br />{0}<br /><br />
            <a href="{1}">{2}</a><br />
            <a href="{3}">{4}</a><br />
            <a href="{5}">{6}</a><br /><center>'''.format(
            translate('AboutDialog', self.DESCRIPTION), self.WEB_SITE,
            translate('AboutDialog', 'Web site'), self.USER_GROUP,
            translate('AboutDialog', 'Users  group'), self.SOURCE_CODE,
            translate('AboutDialog', 'Source code')))
        self.tabWidget.addTab(self.info, translate('AboutDialog', 'Info'))

        self.license = QTextBrowser(self)
        self.license.setOpenExternalLinks(True)
        self.license.setHtml(self.LICENSE)
        self.tabWidget.addTab(self.license, translate('AboutDialog',
                                                      'License'))

        self.contributors = QTextBrowser(self)
        self.contributors.setOpenExternalLinks(True)

        self.contributors.setHtml(self.__contributors())
        self.tabWidget.addTab(self.contributors,
                              translate('AboutDialog', 'Contributors'))

        # Ok button
        self.buttons = QDialogButtonBox(QDialogButtonBox.Ok)
        self.buttons.accepted.connect(self.accept)
        self.layout().addWidget(self.buttons, 3, 1)

        self.layout().setColumnStretch(0, 1)
        self.layout().setColumnStretch(1, 3)

        self.layout().setRowStretch(0, 6)
        self.layout().setRowStretch(1, 1)
        self.layout().setRowStretch(2, 16)
        self.layout().setRowStretch(3, 3)

        self.buttons.setFocus()

    def __contributors(self):
        text = ''
        for section, people in self.CONTRIBUTORS.items():
            text += '<u><b>{0}:</b></u><br />'.format(
                translate('About', section))

            for person in people:
                text += person[0]
                if '://' in person[1]:
                    text += ' - <a href="{0}">{1}</a>'.format(
                        person[1], person[1][person[1].index('://') + 3:])
                elif person[1]:
                    text += ' - <a href="mailto:{0}">{0}</a>'.format(person[1])
                text += '<br />'

            text += '<br />'

        return text