Пример #1
0
class LoadingWidget(QLabel):
    def __init__(self, *args, **kwargs):
        super(LoadingWidget, self).__init__(*args, **kwargs)
        self.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        self._movie = QMovie("loading.gif")
        self.setMovie(self._movie)

    def deleteLater(self):
        self._movie.stop()
        self._movie.deleteLater()
        del self._movie
        super(LoadingWidget, self).deleteLater()

    def show(self):
        self.setVisible(True)
        super(LoadingWidget, self).show()
        self._movie.start()

    def closeEvent(self, event):
        self._movie.stop()
        self.setVisible(False)
        super(LoadingWidget, self).closeEvent(event)
Пример #2
0
class Load(QWidget):
    def __init__(self):
        super().__init__()
        self.movie = QMovie("load.gif", QByteArray(), self)
        size = self.size()
        screenGeometry = QDesktopWidget().screenGeometry(-1).size()
        self.setGeometry((screenGeometry.width() - size.width()) // 2,
                         (screenGeometry.height() - size.height()) // 2,
                         size.width(), size.height())
        self.setWindowTitle('')
        self.movie_screen = QLabel()
        self.movie_screen.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Expanding)
        self.movie_screen.setAlignment(Qt.AlignCenter)
        main_layout = QVBoxLayout()
        main_layout.addWidget(self.movie_screen)
        self.setLayout(main_layout)
        self.movie.setCacheMode(QMovie.CacheAll)
        self.movie_screen.setMovie(self.movie)
        self.frame_count = self.movie.frameCount()
        self.movie.frameChanged.connect(self.frameChanged)
        self.frame = 0
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_NoSystemBackground, True)
        self.setAttribute(Qt.WA_TranslucentBackground, True)
        self.movie.start()
        self.app = MainApp()
        self.movie.loopCount()

    def frameChanged(self):
        self.frame += 1
        if self.frame >= self.frame_count:
            self.movie.stop()
            self.movie.setParent(None)
            self.movie.deleteLater()
            self.setAttribute(Qt.WA_NoSystemBackground, False)
            self.setAttribute(Qt.WA_TranslucentBackground, False)
            self.destroy()
            self.app.show()
Пример #3
0
class VidCutter(QWidget):
    def __init__(self, parent):
        super(VidCutter, self).__init__(parent)
        self.parent = parent
        self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        self.videoWidget = VideoWidget()
        self.videoService = VideoService(self)

        QFontDatabase.addApplicationFont(
            os.path.join(self.getAppPath(), 'fonts', 'DroidSansMono.ttf'))
        QFontDatabase.addApplicationFont(
            os.path.join(self.getAppPath(), 'fonts', 'HelveticaNeue.ttf'))
        qApp.setFont(QFont('Helvetica Neue', 10))

        self.clipTimes = []
        self.inCut = False
        self.movieFilename = ''
        self.movieLoaded = False
        self.timeformat = 'hh:mm:ss'
        self.finalFilename = ''
        self.totalRuntime = 0

        self.initIcons()
        self.initActions()

        self.toolbar = QToolBar(
            floatable=False,
            movable=False,
            iconSize=QSize(28, 28),
            toolButtonStyle=Qt.ToolButtonTextUnderIcon,
            styleSheet=
            'QToolBar QToolButton { min-width:82px; margin-left:10px; margin-right:10px; font-size:14px; }'
        )
        self.initToolbar()

        self.aboutMenu, self.cliplistMenu = QMenu(), QMenu()
        self.initMenus()

        self.seekSlider = VideoSlider(parent=self,
                                      sliderMoved=self.setPosition)
        self.seekSlider.installEventFilter(self)

        self.initNoVideo()

        self.cliplist = QListWidget(
            sizePolicy=QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding),
            contextMenuPolicy=Qt.CustomContextMenu,
            uniformItemSizes=True,
            iconSize=QSize(100, 700),
            dragDropMode=QAbstractItemView.InternalMove,
            alternatingRowColors=True,
            customContextMenuRequested=self.itemMenu,
            styleSheet='QListView::item { margin:10px 5px; }')
        self.cliplist.setFixedWidth(185)
        self.cliplist.model().rowsMoved.connect(self.syncClipList)

        listHeader = QLabel(pixmap=QPixmap(
            os.path.join(self.getAppPath(), 'images', 'clipindex.png'), 'PNG'),
                            alignment=Qt.AlignCenter)
        listHeader.setStyleSheet(
            '''padding:5px; padding-top:8px; border:1px solid #b9b9b9; border-bottom:none;
                                    background-color:qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFF,
                                    stop: 0.5 #EAEAEA, stop: 0.6 #EAEAEA stop:1 #FFF);'''
        )

        self.runtimeLabel = QLabel('<div align="right">00:00:00</div>',
                                   textFormat=Qt.RichText)
        self.runtimeLabel.setStyleSheet(
            '''font-family:Droid Sans Mono; font-size:10pt; color:#FFF;
                                           background:rgb(106, 69, 114) url(:images/runtime.png)
                                           no-repeat left center; padding:2px; padding-right:8px;
                                           border:1px solid #b9b9b9; border-top:none;'''
        )

        self.clipindexLayout = QVBoxLayout(spacing=0)
        self.clipindexLayout.setContentsMargins(0, 0, 0, 0)
        self.clipindexLayout.addWidget(listHeader)
        self.clipindexLayout.addWidget(self.cliplist)
        self.clipindexLayout.addWidget(self.runtimeLabel)

        self.videoLayout = QHBoxLayout()
        self.videoLayout.setContentsMargins(0, 0, 0, 0)
        self.videoLayout.addWidget(self.novideoWidget)
        self.videoLayout.addLayout(self.clipindexLayout)

        self.timeCounter = QLabel('00:00:00 / 00:00:00',
                                  autoFillBackground=True,
                                  alignment=Qt.AlignCenter,
                                  sizePolicy=QSizePolicy(
                                      QSizePolicy.Expanding,
                                      QSizePolicy.Fixed))
        self.timeCounter.setStyleSheet(
            'color:#FFF; background:#000; font-family:Droid Sans Mono; font-size:10.5pt; padding:4px;'
        )

        videoplayerLayout = QVBoxLayout(spacing=0)
        videoplayerLayout.setContentsMargins(0, 0, 0, 0)
        videoplayerLayout.addWidget(self.videoWidget)
        videoplayerLayout.addWidget(self.timeCounter)

        self.videoplayerWidget = QWidget(self, visible=False)
        self.videoplayerWidget.setLayout(videoplayerLayout)

        self.menuButton = QPushButton(icon=self.aboutIcon,
                                      flat=True,
                                      toolTip='About',
                                      statusTip='About',
                                      iconSize=QSize(24, 24),
                                      cursor=Qt.PointingHandCursor)
        self.menuButton.setMenu(self.aboutMenu)

        self.muteButton = QPushButton(icon=self.unmuteIcon,
                                      flat=True,
                                      toolTip='Mute',
                                      statusTip='Toggle audio mute',
                                      cursor=Qt.PointingHandCursor,
                                      clicked=self.muteAudio)

        self.volumeSlider = QSlider(Qt.Horizontal,
                                    toolTip='Volume',
                                    statusTip='Adjust volume level',
                                    cursor=Qt.PointingHandCursor,
                                    value=50,
                                    sizePolicy=QSizePolicy(
                                        QSizePolicy.Fixed,
                                        QSizePolicy.Minimum),
                                    minimum=0,
                                    maximum=100,
                                    sliderMoved=self.setVolume)
        self.volumeSlider.setStyleSheet(
            '''QSlider::groove:horizontal { height:40px; }
                                           QSlider::sub-page:horizontal { border:1px outset #6A4572; background:#6A4572; margin:2px; }
                                           QSlider::handle:horizontal { image: url(:images/knob.png) no-repeat top left; width:20px; }'''
        )

        self.saveAction = QPushButton(
            self.parent,
            icon=self.saveIcon,
            text='Save Video',
            flat=True,
            toolTip='Save Video',
            clicked=self.cutVideo,
            cursor=Qt.PointingHandCursor,
            iconSize=QSize(30, 30),
            statusTip='Save video clips merged as a new video file',
            enabled=False)
        self.saveAction.setStyleSheet(
            '''QPushButton { color:#FFF; padding:8px; font-size:12pt;
                                            border:1px inset #481953; border-radius:4px;
                                            background-color:rgb(106, 69, 114); }
                                         QPushButton:!enabled { background-color:rgba(0, 0, 0, 0.1);
                                            color:rgba(0, 0, 0, 0.3); border:1px inset #CDCDCD; }
                                         QPushButton:hover { background-color:rgba(255, 255, 255, 0.8); color:#444; }
                                         QPushButton:pressed { background-color:rgba(218, 218, 219, 0.8); color:#444; }'''
        )

        controlsLayout = QHBoxLayout()
        controlsLayout.addStretch(1)
        controlsLayout.addWidget(self.toolbar)
        controlsLayout.addSpacerItem(QSpacerItem(20, 1))
        controlsLayout.addWidget(self.saveAction)
        controlsLayout.addStretch(1)
        controlsLayout.addWidget(self.muteButton)
        controlsLayout.addWidget(self.volumeSlider)
        controlsLayout.addSpacing(1)
        controlsLayout.addWidget(self.menuButton)

        layout = QVBoxLayout()
        layout.setContentsMargins(10, 10, 10, 4)
        layout.addLayout(self.videoLayout)
        layout.addWidget(self.seekSlider)
        layout.addLayout(controlsLayout)

        self.setLayout(layout)

        self.mediaPlayer.setVideoOutput(self.videoWidget)
        self.mediaPlayer.stateChanged.connect(self.mediaStateChanged)
        self.mediaPlayer.positionChanged.connect(self.positionChanged)
        self.mediaPlayer.durationChanged.connect(self.durationChanged)
        self.mediaPlayer.error.connect(self.handleError)

    def initNoVideo(self) -> None:
        novideoImage = QLabel(alignment=Qt.AlignCenter,
                              autoFillBackground=False,
                              pixmap=QPixmap(
                                  os.path.join(self.getAppPath(), 'images',
                                               'novideo.png'), 'PNG'),
                              sizePolicy=QSizePolicy(
                                  QSizePolicy.Expanding,
                                  QSizePolicy.MinimumExpanding))
        novideoImage.setBackgroundRole(QPalette.Dark)
        novideoImage.setContentsMargins(0, 20, 0, 20)
        self.novideoLabel = QLabel(alignment=Qt.AlignCenter,
                                   autoFillBackground=True,
                                   sizePolicy=QSizePolicy(
                                       QSizePolicy.Expanding,
                                       QSizePolicy.Minimum))
        self.novideoLabel.setBackgroundRole(QPalette.Dark)
        self.novideoLabel.setContentsMargins(0, 20, 15, 60)
        novideoLayout = QVBoxLayout(spacing=0)
        novideoLayout.addWidget(novideoImage)
        novideoLayout.addWidget(self.novideoLabel, alignment=Qt.AlignTop)
        self.novideoMovie = QMovie(
            os.path.join(self.getAppPath(), 'images', 'novideotext.gif'))
        self.novideoMovie.frameChanged.connect(self.setNoVideoText)
        self.novideoMovie.start()
        self.novideoWidget = QWidget(self, autoFillBackground=True)
        self.novideoWidget.setBackgroundRole(QPalette.Dark)
        self.novideoWidget.setLayout(novideoLayout)

    def initIcons(self) -> None:
        self.appIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'vidcutter.png'))
        self.openIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'addmedia.png'))
        self.playIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'play.png'))
        self.pauseIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'pause.png'))
        self.cutStartIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'cut-start.png'))
        self.cutEndIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'cut-end.png'))
        self.saveIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'save.png'))
        self.muteIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'muted.png'))
        self.unmuteIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'unmuted.png'))
        self.upIcon = QIcon(os.path.join(self.getAppPath(), 'images',
                                         'up.png'))
        self.downIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'down.png'))
        self.removeIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'remove.png'))
        self.removeAllIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'remove-all.png'))
        self.successIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'success.png'))
        self.aboutIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'about.png'))
        self.completePlayIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'complete-play.png'))
        self.completeOpenIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'complete-open.png'))
        self.completeRestartIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'complete-restart.png'))
        self.completeExitIcon = QIcon(
            os.path.join(self.getAppPath(), 'images', 'complete-exit.png'))

    def initActions(self) -> None:
        self.openAction = QAction(self.openIcon,
                                  'Add Media',
                                  self,
                                  statusTip='Select media source',
                                  triggered=self.openFile)
        self.playAction = QAction(self.playIcon,
                                  'Play Video',
                                  self,
                                  statusTip='Play selected media',
                                  triggered=self.playVideo,
                                  enabled=False)
        self.cutStartAction = QAction(self.cutStartIcon,
                                      'Set Start',
                                      self,
                                      toolTip='Set Start',
                                      statusTip='Set start marker',
                                      triggered=self.cutStart,
                                      enabled=False)
        self.cutEndAction = QAction(self.cutEndIcon,
                                    'Set End',
                                    self,
                                    statusTip='Set end marker',
                                    triggered=self.cutEnd,
                                    enabled=False)
        self.moveItemUpAction = QAction(
            self.upIcon,
            'Move Up',
            self,
            statusTip='Move clip position up in list',
            triggered=self.moveItemUp,
            enabled=False)
        self.moveItemDownAction = QAction(
            self.downIcon,
            'Move Down',
            self,
            statusTip='Move clip position down in list',
            triggered=self.moveItemDown,
            enabled=False)
        self.removeItemAction = QAction(
            self.removeIcon,
            'Remove clip',
            self,
            statusTip='Remove selected clip from list',
            triggered=self.removeItem,
            enabled=False)
        self.removeAllAction = QAction(self.removeAllIcon,
                                       'Clear list',
                                       self,
                                       statusTip='Clear all clips from list',
                                       triggered=self.clearList,
                                       enabled=False)
        self.aboutAction = QAction('About %s' % qApp.applicationName(),
                                   self,
                                   statusTip='Credits and acknowledgements',
                                   triggered=self.aboutInfo)
        self.aboutQtAction = QAction('About Qt',
                                     self,
                                     statusTip='About Qt',
                                     triggered=qApp.aboutQt)
        self.mediaInfoAction = QAction(
            'Media Information',
            self,
            statusTip='Media information from loaded video file',
            triggered=self.mediaInfo,
            enabled=False)

    def initToolbar(self) -> None:
        self.toolbar.addAction(self.openAction)
        self.toolbar.addAction(self.playAction)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.cutStartAction)
        self.toolbar.addAction(self.cutEndAction)
        self.toolbar.addSeparator()

    def initMenus(self) -> None:
        self.aboutMenu.addAction(self.mediaInfoAction)
        self.aboutMenu.addSeparator()
        self.aboutMenu.addAction(self.aboutQtAction)
        self.aboutMenu.addAction(self.aboutAction)
        self.cliplistMenu.addAction(self.moveItemUpAction)
        self.cliplistMenu.addAction(self.moveItemDownAction)
        self.cliplistMenu.addSeparator()
        self.cliplistMenu.addAction(self.removeItemAction)
        self.cliplistMenu.addAction(self.removeAllAction)

    def setRunningTime(self, runtime: str) -> None:
        self.runtimeLabel.setText('<div align="right">%s</div>' % runtime)

    @pyqtSlot(int)
    def setNoVideoText(self, frame: int) -> None:
        self.novideoLabel.setPixmap(self.novideoMovie.currentPixmap())

    def itemMenu(self, pos: QPoint) -> None:
        globalPos = self.cliplist.mapToGlobal(pos)
        self.moveItemUpAction.setEnabled(False)
        self.moveItemDownAction.setEnabled(False)
        self.removeItemAction.setEnabled(False)
        self.removeAllAction.setEnabled(False)
        index = self.cliplist.currentRow()
        if index != -1:
            if not self.inCut:
                if index > 0:
                    self.moveItemUpAction.setEnabled(True)
                if index < self.cliplist.count() - 1:
                    self.moveItemDownAction.setEnabled(True)
            if self.cliplist.count() > 0:
                self.removeItemAction.setEnabled(True)
        if self.cliplist.count() > 0:
            self.removeAllAction.setEnabled(True)
        self.cliplistMenu.exec_(globalPos)

    def moveItemUp(self) -> None:
        index = self.cliplist.currentRow()
        tmpItem = self.clipTimes[index]
        del self.clipTimes[index]
        self.clipTimes.insert(index - 1, tmpItem)
        self.renderTimes()

    def moveItemDown(self) -> None:
        index = self.cliplist.currentRow()
        tmpItem = self.clipTimes[index]
        del self.clipTimes[index]
        self.clipTimes.insert(index + 1, tmpItem)
        self.renderTimes()

    def removeItem(self) -> None:
        index = self.cliplist.currentRow()
        del self.clipTimes[index]
        if self.inCut and index == self.cliplist.count() - 1:
            self.inCut = False
            self.initMediaControls()
        self.renderTimes()

    def clearList(self) -> None:
        self.clipTimes.clear()
        self.cliplist.clear()
        self.inCut = False
        self.renderTimes()
        self.initMediaControls()

    def mediaInfo(self) -> None:
        if self.mediaPlayer.isMetaDataAvailable():
            content = '<table cellpadding="4">'
            for key in self.mediaPlayer.availableMetaData():
                val = self.mediaPlayer.metaData(key)
                if type(val) is QSize:
                    val = '%s x %s' % (val.width(), val.height())
                content += '<tr><td align="right"><b>%s:</b></td><td>%s</td></tr>\n' % (
                    key, val)
            content += '</table>'
            mbox = QMessageBox(windowTitle='Media Information',
                               windowIcon=self.parent.windowIcon(),
                               textFormat=Qt.RichText)
            mbox.setText('<b>%s</b>' % os.path.basename(
                self.mediaPlayer.currentMedia().canonicalUrl().toLocalFile()))
            mbox.setInformativeText(content)
            mbox.exec_()
        else:
            QMessageBox.critical(
                self.parent, 'Could not retrieve media information',
                '''There was a problem in tring to retrieve media information.
                                    This DOES NOT mean there is a problem with the file and you should
                                    be able to continue using it.''')

    def aboutInfo(self) -> None:
        about_html = '''<style>
    a { color:#441d4e; text-decoration:none; font-weight:bold; }
    a:hover { text-decoration:underline; }
</style>
<p style="font-size:26pt; font-weight:bold;">%s</p>
<p>
    <span style="font-size:13pt;"><b>Version: %s</b></span>
    <span style="font-size:10pt;position:relative;left:5px;">( %s )</span>
</p>
<p style="font-size:13px;">
    Copyright &copy; 2016 <a href="mailto:[email protected]">Pete Alexandrou</a>
    <br/>
    Website: <a href="%s">%s</a>
</p>
<p style="font-size:13px;">
    Thanks to the folks behind the <b>Qt</b>, <b>PyQt</b> and <b>FFmpeg</b>
    projects for all their hard and much appreciated work.
</p>
<p style="font-size:11px;">
    This program 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 2
    of the License, or (at your option) any later version.
</p>
<p style="font-size:11px;">
    This software uses libraries from the <a href="https://www.ffmpeg.org">FFmpeg</a> project under the
    <a href="https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html">LGPLv2.1</a>
</p>''' % (qApp.applicationName(), qApp.applicationVersion(),
           platform.architecture()[0], qApp.organizationDomain(),
           qApp.organizationDomain())
        QMessageBox.about(self.parent, 'About %s' % qApp.applicationName(),
                          about_html)

    def openFile(self) -> None:
        filename, _ = QFileDialog.getOpenFileName(self.parent,
                                                  caption='Select video',
                                                  directory=QDir.homePath())
        if filename != '':
            self.loadFile(filename)

    def loadFile(self, filename: str) -> None:
        self.movieFilename = filename
        if not os.path.exists(filename):
            return
        self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(filename)))
        self.initMediaControls(True)
        self.cliplist.clear()
        self.clipTimes = []
        self.parent.setWindowTitle(
            '%s - %s' % (qApp.applicationName(), os.path.basename(filename)))
        if not self.movieLoaded:
            self.videoLayout.replaceWidget(self.novideoWidget,
                                           self.videoplayerWidget)
            self.novideoMovie.stop()
            self.novideoMovie.deleteLater()
            self.novideoWidget.deleteLater()
            self.videoplayerWidget.show()
            self.videoWidget.show()
            self.movieLoaded = True
        if self.mediaPlayer.isVideoAvailable():
            self.mediaPlayer.setPosition(1)
        self.mediaPlayer.play()
        self.mediaPlayer.pause()

    def playVideo(self) -> None:
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.mediaPlayer.pause()
            self.playAction.setText('Play Video')
        else:
            self.mediaPlayer.play()
            self.playAction.setText('Pause Video')

    def initMediaControls(self, flag: bool = True) -> None:
        self.playAction.setEnabled(flag)
        self.saveAction.setEnabled(False)
        self.cutStartAction.setEnabled(flag)
        self.cutEndAction.setEnabled(False)
        self.mediaInfoAction.setEnabled(flag)
        if flag:
            self.seekSlider.setRestrictValue(0)

    def setPosition(self, position: int) -> None:
        self.mediaPlayer.setPosition(position)

    def positionChanged(self, progress: int) -> None:
        self.seekSlider.setValue(progress)
        currentTime = self.deltaToQTime(progress)
        totalTime = self.deltaToQTime(self.mediaPlayer.duration())
        self.timeCounter.setText('%s / %s' % (currentTime.toString(
            self.timeformat), totalTime.toString(self.timeformat)))

    @pyqtSlot()
    def mediaStateChanged(self) -> None:
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.playAction.setIcon(self.pauseIcon)
        else:
            self.playAction.setIcon(self.playIcon)

    def durationChanged(self, duration: int) -> None:
        self.seekSlider.setRange(0, duration)

    def muteAudio(self, muted: bool) -> None:
        if self.mediaPlayer.isMuted():
            self.mediaPlayer.setMuted(not self.mediaPlayer.isMuted())
            self.muteButton.setIcon(self.unmuteIcon)
            self.muteButton.setToolTip('Mute')
        else:
            self.mediaPlayer.setMuted(not self.mediaPlayer.isMuted())
            self.muteButton.setIcon(self.muteIcon)
            self.muteButton.setToolTip('Unmute')

    def setVolume(self, volume: int) -> None:
        self.mediaPlayer.setVolume(volume)

    def toggleFullscreen(self) -> None:
        self.videoWidget.setFullScreen(not self.videoWidget.isFullScreen())

    def cutStart(self) -> None:
        self.clipTimes.append([
            self.deltaToQTime(self.mediaPlayer.position()), '',
            self.captureImage()
        ])
        self.cutStartAction.setDisabled(True)
        self.cutEndAction.setEnabled(True)
        self.seekSlider.setRestrictValue(self.seekSlider.value() + 1000)
        self.mediaPlayer.setPosition(self.seekSlider.restrictValue)
        self.inCut = True
        self.renderTimes()

    def cutEnd(self) -> None:
        item = self.clipTimes[len(self.clipTimes) - 1]
        selected = self.deltaToQTime(self.mediaPlayer.position())
        if selected.__lt__(item[0]):
            QMessageBox.critical(
                self.parent, 'Invalid END Time',
                'The clip end time must come AFTER it\'s start time. Please try again.'
            )
            return
        item[1] = selected
        self.cutStartAction.setEnabled(True)
        self.cutEndAction.setDisabled(True)
        self.seekSlider.setRestrictValue(0)
        self.inCut = False
        self.renderTimes()

    @pyqtSlot(QModelIndex, int, int, QModelIndex, int)
    def syncClipList(self, parent: QModelIndex, start: int, end: int,
                     destination: QModelIndex, row: int) -> None:
        if start < row:
            index = row - 1
        else:
            index = row
        clip = self.clipTimes.pop(start)
        self.clipTimes.insert(index, clip)

    def renderTimes(self) -> None:
        self.cliplist.clear()
        self.seekSlider.setCutMode(self.inCut)
        if len(self.clipTimes) > 4:
            self.cliplist.setFixedWidth(200)
        else:
            self.cliplist.setFixedWidth(185)
        self.totalRuntime = 0
        for item in self.clipTimes:
            endItem = ''
            if type(item[1]) is QTime:
                endItem = item[1].toString(self.timeformat)
                self.totalRuntime += item[0].msecsTo(item[1])
            listitem = QListWidgetItem()
            listitem.setTextAlignment(Qt.AlignVCenter)
            if type(item[2]) is QPixmap:
                listitem.setIcon(QIcon(item[2]))
            self.cliplist.addItem(listitem)
            marker = QLabel(
                '''<style>b { font-size:8pt; } p { margin:5px; }</style>
                            <p><b>START</b><br/>%s</p><p><b>END</b><br/>%s</p>'''
                % (item[0].toString(self.timeformat), endItem))
            self.cliplist.setItemWidget(listitem, marker)
            listitem.setFlags(Qt.ItemIsSelectable | Qt.ItemIsDragEnabled
                              | Qt.ItemIsEnabled)
        if len(self.clipTimes) and not self.inCut:
            self.saveAction.setEnabled(True)
        if self.inCut or len(self.clipTimes) == 0 or not type(
                self.clipTimes[0][1]) is QTime:
            self.saveAction.setEnabled(False)
        self.setRunningTime(
            self.deltaToQTime(self.totalRuntime).toString(self.timeformat))

    @staticmethod
    def deltaToQTime(millisecs: int) -> QTime:
        secs = millisecs / 1000
        return QTime((secs / 3600) % 60, (secs / 60) % 60, secs % 60,
                     (secs * 1000) % 1000)

    def captureImage(self) -> None:
        frametime = self.deltaToQTime(
            self.mediaPlayer.position()).addSecs(1).toString(self.timeformat)
        inputfile = self.mediaPlayer.currentMedia().canonicalUrl().toLocalFile(
        )
        imagecap = self.videoService.capture(inputfile, frametime)
        if type(imagecap) is QPixmap:
            return imagecap

    def cutVideo(self) -> bool:
        self.setCursor(Qt.BusyCursor)
        clips = len(self.clipTimes)
        filename, filelist = '', []
        source = self.mediaPlayer.currentMedia().canonicalUrl().toLocalFile()
        _, sourceext = os.path.splitext(source)
        if clips > 0:
            self.finalFilename, _ = QFileDialog.getSaveFileName(
                self.parent, 'Save video', source,
                'Video files (*%s)' % sourceext)
            if self.finalFilename != '':
                self.saveAction.setDisabled(True)
                self.showProgress(clips)
                file, ext = os.path.splitext(self.finalFilename)
                index = 1
                self.progress.setLabelText('Cutting video clips...')
                qApp.processEvents()
                for clip in self.clipTimes:
                    duration = self.deltaToQTime(clip[0].msecsTo(
                        clip[1])).toString(self.timeformat)
                    filename = '%s_%s%s' % (file, '{0:0>2}'.format(index), ext)
                    filelist.append(filename)
                    self.videoService.cut(source, filename,
                                          clip[0].toString(self.timeformat),
                                          duration)
                    index += 1
                if len(filelist) > 1:
                    self.joinVideos(filelist, self.finalFilename)
                else:
                    QFile.remove(self.finalFilename)
                    QFile.rename(filename, self.finalFilename)
                self.unsetCursor()
                self.progress.setLabelText('Complete...')
                qApp.processEvents()
                self.saveAction.setEnabled(True)
                self.progress.close()
                self.progress.deleteLater()
                self.complete()
                self.saveAction.setEnabled(True)
            self.unsetCursor()
            self.saveAction.setDisabled(True)
            return True
        self.unsetCursor()
        self.saveAction.setDisabled(True)
        return False

    def joinVideos(self, joinlist: list, filename: str) -> None:
        listfile = os.path.normpath(
            os.path.join(os.path.dirname(joinlist[0]), '.vidcutter.list'))
        fobj = open(listfile, 'w')
        for file in joinlist:
            fobj.write('file \'%s\'\n' % file.replace("'", "\\'"))
        fobj.close()
        self.videoService.join(listfile, filename)
        try:
            QFile.remove(listfile)
            for file in joinlist:
                if os.path.isfile(file):
                    QFile.remove(file)
        except:
            pass

    def showProgress(self,
                     steps: int,
                     label: str = 'Processing video...') -> None:
        self.progress = QProgressDialog(label,
                                        None,
                                        0,
                                        steps,
                                        self.parent,
                                        windowModality=Qt.ApplicationModal,
                                        windowIcon=self.parent.windowIcon(),
                                        minimumDuration=0,
                                        minimumWidth=500)
        self.progress.show()
        for i in range(steps):
            self.progress.setValue(i)
            qApp.processEvents()
            time.sleep(1)

    def complete(self) -> None:
        info = QFileInfo(self.finalFilename)
        mbox = QMessageBox(windowTitle='Success',
                           windowIcon=self.parent.windowIcon(),
                           minimumWidth=500,
                           iconPixmap=self.successIcon.pixmap(48, 49),
                           textFormat=Qt.RichText)
        mbox.setText(
            '''
<style>
    table.info { margin:8px; padding:4px 15px; }
    td.label { font-weight:bold; font-size:9pt; text-align:right; background-color:#444; color:#FFF; }
    td.value { background-color:#FFF !important; font-size:10pt; }
</style>
<p>Your video was successfully created.</p>
<p align="center">
    <table class="info" cellpadding="6" cellspacing="0">
        <tr>
            <td class="label"><b>Filename</b></td>
            <td class="value" nowrap>%s</td>
        </tr>
        <tr>
            <td class="label"><b>Size</b></td>
            <td class="value">%s</td>
        </tr>
        <tr>
            <td class="label"><b>Runtime</b></td>
            <td class="value">%s</td>
        </tr>
    </table>
</p>
<p>How would you like to proceed?</p>''' %
            (QDir.toNativeSeparators(
                self.finalFilename), self.sizeof_fmt(int(info.size())),
             self.deltaToQTime(self.totalRuntime).toString(self.timeformat)))
        play = mbox.addButton('Play', QMessageBox.AcceptRole)
        play.setIcon(self.completePlayIcon)
        play.clicked.connect(self.openResult)
        fileman = mbox.addButton('Open', QMessageBox.AcceptRole)
        fileman.setIcon(self.completeOpenIcon)
        fileman.clicked.connect(self.openFolder)
        end = mbox.addButton('Exit', QMessageBox.AcceptRole)
        end.setIcon(self.completeExitIcon)
        end.clicked.connect(self.close)
        new = mbox.addButton('Restart', QMessageBox.AcceptRole)
        new.setIcon(self.completeRestartIcon)
        new.clicked.connect(self.startNew)
        mbox.setDefaultButton(new)
        mbox.setEscapeButton(new)
        mbox.exec_()

    def sizeof_fmt(self, num: float, suffix: chr = 'B') -> str:
        for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']:
            if abs(num) < 1024.0:
                return "%3.1f%s%s" % (num, unit, suffix)
            num /= 1024.0
        return "%.1f%s%s" % (num, 'Y', suffix)

    @pyqtSlot()
    def openFolder(self) -> None:
        self.openResult(pathonly=True)

    @pyqtSlot(bool)
    def openResult(self, pathonly: bool = False) -> None:
        self.startNew()
        if len(self.finalFilename) and os.path.exists(self.finalFilename):
            target = self.finalFilename if not pathonly else os.path.dirname(
                self.finalFilename)
            QDesktopServices.openUrl(QUrl.fromLocalFile(target))

    @pyqtSlot()
    def startNew(self) -> None:
        self.unsetCursor()
        self.clearList()
        self.seekSlider.setValue(0)
        self.seekSlider.setRange(0, 0)
        self.mediaPlayer.setMedia(QMediaContent())
        self.initNoVideo()
        self.videoLayout.replaceWidget(self.videoplayerWidget,
                                       self.novideoWidget)
        self.initMediaControls(False)
        self.parent.setWindowTitle('%s' % qApp.applicationName())

    def wheelEvent(self, event: QWheelEvent) -> None:
        if self.mediaPlayer.isVideoAvailable(
        ) or self.mediaPlayer.isAudioAvailable():
            if event.angleDelta().y() > 0:
                newval = self.seekSlider.value() - 1000
            else:
                newval = self.seekSlider.value() + 1000
            self.seekSlider.setValue(newval)
            self.seekSlider.setSliderPosition(newval)
            self.mediaPlayer.setPosition(newval)
        event.accept()

    def keyPressEvent(self, event: QKeyEvent) -> None:
        if self.mediaPlayer.isVideoAvailable(
        ) or self.mediaPlayer.isAudioAvailable():
            addtime = 0
            if event.key() == Qt.Key_Left:
                addtime = -1000
            elif event.key() == Qt.Key_PageUp or event.key() == Qt.Key_Up:
                addtime = -10000
            elif event.key() == Qt.Key_Right:
                addtime = 1000
            elif event.key() == Qt.Key_PageDown or event.key() == Qt.Key_Down:
                addtime = 10000
            elif event.key() == Qt.Key_Enter:
                self.toggleFullscreen()
            elif event.key(
            ) == Qt.Key_Escape and self.videoWidget.isFullScreen():
                self.videoWidget.setFullScreen(False)
            if addtime != 0:
                newval = self.seekSlider.value() + addtime
                self.seekSlider.setValue(newval)
                self.seekSlider.setSliderPosition(newval)
                self.mediaPlayer.setPosition(newval)
        event.accept()

    def mousePressEvent(self, event: QMouseEvent) -> None:
        if event.button() == Qt.BackButton and self.cutStartAction.isEnabled():
            self.cutStart()
            event.accept()
        elif event.button(
        ) == Qt.ForwardButton and self.cutEndAction.isEnabled():
            self.cutEnd()
            event.accept()
        else:
            super(VidCutter, self).mousePressEvent(event)

    def eventFilter(self, obj: QObject, event: QEvent) -> bool:
        if event.type() == QEvent.MouseButtonRelease and isinstance(
                obj, VideoSlider):
            if obj.objectName() == 'VideoSlider' and (
                    self.mediaPlayer.isVideoAvailable()
                    or self.mediaPlayer.isAudioAvailable()):
                obj.setValue(
                    QStyle.sliderValueFromPosition(obj.minimum(),
                                                   obj.maximum(), event.x(),
                                                   obj.width()))
                self.mediaPlayer.setPosition(obj.sliderPosition())
        return QWidget.eventFilter(self, obj, event)

    @pyqtSlot(QMediaPlayer.Error)
    def handleError(self, error: QMediaPlayer.Error) -> None:
        self.unsetCursor()
        self.startNew()
        if error == QMediaPlayer.ResourceError:
            QMessageBox.critical(
                self.parent, 'Error',
                'Invalid media file detected at:<br/><br/><b>%s</b><br/><br/>%s'
                % (self.movieFilename, self.mediaPlayer.errorString()))
        else:
            QMessageBox.critical(self.parent, 'Error',
                                 self.mediaPlayer.errorString())

    def getAppPath(self) -> str:
        return ':'

    def closeEvent(self, event: QCloseEvent) -> None:
        self.parent.closeEvent(event)
Пример #4
0
class UIConfiguracionesModal(modal):

    def __init__(self,**kwargs):
        super(UIConfiguracionesModal,self).__init__(**kwargs)
    
    def setupUI(self):
        ConfiguracionesModal = self
        ConfiguracionesModal.setObjectName("ConfiguracionesModal")
        ConfiguracionesModal.setWindowModality(QtCore.Qt.WindowModal)
        ConfiguracionesModal.resize(497, 720)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(ConfiguracionesModal.sizePolicy().hasHeightForWidth())
        ConfiguracionesModal.setSizePolicy(sizePolicy)
        ConfiguracionesModal.setMinimumSize(QtCore.QSize(480, 720))
        font = QtGui.QFont()
        font.setFamily("Noto Serif")
        font.setPointSize(11)
        font.setBold(True)
        font.setWeight(75)
        ConfiguracionesModal.setFont(font)
        ConfiguracionesModal.setContextMenuPolicy(QtCore.Qt.NoContextMenu)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("../../../../../.designer/if_16_1751363.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        ConfiguracionesModal.setWindowIcon(icon)
        ConfiguracionesModal.setStyleSheet("background-color: rgb(255, 255, 255);")
        ConfiguracionesModal.setInputMethodHints(QtCore.Qt.ImhSensitiveData)
        self.verticalLayout = QtWidgets.QVBoxLayout(ConfiguracionesModal)
        self.verticalLayout.setObjectName("verticalLayout")
        self.MainFrame = QtWidgets.QFrame(ConfiguracionesModal)
        self.MainFrame.setMinimumSize(QtCore.QSize(360, 0))
        self.MainFrame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.MainFrame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.MainFrame.setObjectName("MainFrame")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.MainFrame)
        self.verticalLayout_2.setContentsMargins(0, 0, 0, 20)
        self.verticalLayout_2.setSpacing(0)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.TitleFrame = QtWidgets.QFrame(self.MainFrame)
        self.TitleFrame.setMaximumSize(QtCore.QSize(16777215, 16777215))
        self.TitleFrame.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.TitleFrame.setFrameShadow(QtWidgets.QFrame.Plain)
        self.TitleFrame.setObjectName("TitleFrame")
        self.gridLayout = QtWidgets.QGridLayout(self.TitleFrame)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setSpacing(0)
        self.gridLayout.setObjectName("gridLayout")
        self.lblUDB = QtWidgets.QLabel(self.TitleFrame)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.lblUDB.sizePolicy().hasHeightForWidth())
        self.lblUDB.setSizePolicy(sizePolicy)
        self.lblUDB.setMinimumSize(QtCore.QSize(0, 116))
        self.lblUDB.setMaximumSize(QtCore.QSize(16777215, 116))
        self.lblUDB.setStyleSheet("background-color: rgb(65, 105, 225);\n"
"margin:0px;")
        self.lblUDB.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.lblUDB.setText("")
        self.lblUDB.setPixmap(QtGui.QPixmap(":/source/img/logo.png"))
        self.lblUDB.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.lblUDB.setObjectName("lblUDB")
        self.gridLayout.addWidget(self.lblUDB, 0, 0, 1, 1)
        self.ExitFrame = QtWidgets.QFrame(self.TitleFrame)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Minimum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.ExitFrame.sizePolicy().hasHeightForWidth())
        self.ExitFrame.setSizePolicy(sizePolicy)
        self.ExitFrame.setMinimumSize(QtCore.QSize(0, 116))
        self.ExitFrame.setMaximumSize(QtCore.QSize(16777215, 116))
        self.ExitFrame.setStyleSheet("background-color: rgb(65, 105, 225);")
        self.ExitFrame.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.ExitFrame.setFrameShadow(QtWidgets.QFrame.Plain)
        self.ExitFrame.setLineWidth(0)
        self.ExitFrame.setObjectName("ExitFrame")
        self.gridLayout_4 = QtWidgets.QGridLayout(self.ExitFrame)
        self.gridLayout_4.setContentsMargins(0, 0, 0, 0)
        self.gridLayout_4.setSpacing(0)
        self.gridLayout_4.setObjectName("gridLayout_4")
        self.btnExit = QtWidgets.QPushButton(self.ExitFrame)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.btnExit.sizePolicy().hasHeightForWidth())
        self.btnExit.setSizePolicy(sizePolicy)
        self.btnExit.setMaximumSize(QtCore.QSize(32, 32))
        self.btnExit.setLayoutDirection(QtCore.Qt.RightToLeft)
        self.btnExit.setText("")
        icon1 = QtGui.QIcon()
        icon1.addPixmap(QtGui.QPixmap(":/source/img/Cancelar.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.btnExit.setIcon(icon1)
        self.btnExit.setIconSize(QtCore.QSize(24, 24))
        self.btnExit.setFlat(True)
        self.btnExit.setObjectName("btnExit")
        self.gridLayout_4.addWidget(self.btnExit, 0, 1, 1, 1)
        self.lblIIE = QtWidgets.QLabel(self.ExitFrame)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.lblIIE.sizePolicy().hasHeightForWidth())
        self.lblIIE.setSizePolicy(sizePolicy)
        self.lblIIE.setMaximumSize(QtCore.QSize(16777215, 116))
        self.lblIIE.setStyleSheet("background-color: rgb(65, 105, 225);\n"
"margin:0px;")
        self.lblIIE.setText("")
        self.lblIIE.setPixmap(QtGui.QPixmap(":/source/img/iiie.png"))
        self.lblIIE.setScaledContents(False)
        self.lblIIE.setAlignment(QtCore.Qt.AlignCenter)
        self.lblIIE.setObjectName("lblIIE")
        self.gridLayout_4.addWidget(self.lblIIE, 0, 0, 2, 1)
        self.gridLayout.addWidget(self.ExitFrame, 0, 2, 1, 1)
        self.lblSCADA = QtWidgets.QLabel(self.TitleFrame)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.lblSCADA.sizePolicy().hasHeightForWidth())
        self.lblSCADA.setSizePolicy(sizePolicy)
        self.lblSCADA.setMinimumSize(QtCore.QSize(250, 116))
        self.lblSCADA.setMaximumSize(QtCore.QSize(16777215, 116))
        font = QtGui.QFont()
        font.setPointSize(21)
        font.setBold(True)
        font.setWeight(75)
        self.lblSCADA.setFont(font)
        self.lblSCADA.setAutoFillBackground(False)
        self.lblSCADA.setStyleSheet("color: rgb(255, 255, 0);background-color: rgb(65, 105, 225);\n"
"margin:0px;")
        self.lblSCADA.setObjectName("lblSCADA")
        self.gridLayout.addWidget(self.lblSCADA, 0, 1, 1, 1)
        self.verticalLayout_2.addWidget(self.TitleFrame)
        self.lblTitle = QtWidgets.QLabel(self.MainFrame)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.lblTitle.sizePolicy().hasHeightForWidth())
        self.lblTitle.setSizePolicy(sizePolicy)
        self.lblTitle.setMaximumSize(QtCore.QSize(16777215, 51))
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(14)
        font.setBold(True)
        font.setWeight(75)
        self.lblTitle.setFont(font)
        self.lblTitle.setStyleSheet("margin-top:5px;")
        self.lblTitle.setAlignment(QtCore.Qt.AlignCenter)
        self.lblTitle.setObjectName("lblTitle")
        self.verticalLayout_2.addWidget(self.lblTitle)
        self.ContentBox = QtWidgets.QGroupBox(self.MainFrame)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.ContentBox.sizePolicy().hasHeightForWidth())
        self.ContentBox.setSizePolicy(sizePolicy)
        self.ContentBox.setMinimumSize(QtCore.QSize(401, 520))
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(11)
        font.setBold(True)
        font.setWeight(75)
        self.ContentBox.setFont(font)
        self.ContentBox.setStyleSheet("background-color: rgb(255, 255, 255);")
        self.ContentBox.setAlignment(QtCore.Qt.AlignBottom|QtCore.Qt.AlignJustify)
        self.ContentBox.setFlat(False)
        self.ContentBox.setObjectName("ContentBox")
        self.ContentLayout = QtWidgets.QVBoxLayout(self.ContentBox)
        self.ContentLayout.setContentsMargins(10, 10, 10, 10)
        self.ContentLayout.setSpacing(10)
        self.ContentLayout.setObjectName("ContentLayout")
        self.ContentAPILocal = QtWidgets.QGroupBox()
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setBold(True)
        font.setWeight(75)
        self.ContentAPILocal.setFont(font)
        self.ContentAPILocal.setObjectName("ContentAPILocal")
        self.ContentLocalLayout = QtWidgets.QGridLayout(self.ContentAPILocal)
        self.ContentLocalLayout.setContentsMargins(0, 0, 0, 0)
        self.ContentLocalLayout.setSpacing(0)
        self.ContentLocalLayout.setObjectName("ContentLocalLayout")
        self.lblIPLocal = QtWidgets.QLabel(self.ContentAPILocal)
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.lblIPLocal.setFont(font)
        self.lblIPLocal.setLineWidth(0)
        self.lblIPLocal.setObjectName("lblIPLocal")
        self.ContentLocalLayout.addWidget(self.lblIPLocal, 0, 0, 1, 1)
        self.txtIPLocal = QtWidgets.QLineEdit(self.ContentAPILocal)
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.txtIPLocal.setFont(font)
        self.txtIPLocal.setStyleSheet("border-bottom:1px solid black;border-top:none;")
        self.txtIPLocal.setObjectName("txtIPLocal")
        self.ContentLocalLayout.addWidget(self.txtIPLocal, 0, 1, 1, 1)
        self.lblPuertoLocal = QtWidgets.QLabel(self.ContentAPILocal)
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.lblPuertoLocal.setFont(font)
        self.lblPuertoLocal.setLineWidth(0)
        self.lblPuertoLocal.setObjectName("lblPuertoLocal")
        self.ContentLocalLayout.addWidget(self.lblPuertoLocal, 0, 2, 1, 1)
        self.txtPuertoLocal = QtWidgets.QLineEdit(self.ContentAPILocal)
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.txtPuertoLocal.setFont(font)
        self.txtPuertoLocal.setStyleSheet("border-bottom:1px solid black;border-top:none;")
        self.txtPuertoLocal.setObjectName("txtPuertoLocal")
        self.ContentLocalLayout.addWidget(self.txtPuertoLocal, 0, 3, 1, 1)
        self.ContentMongoDB = QtWidgets.QGroupBox() #asd
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.ContentMongoDB.setFont(font)
        self.ContentMongoDB.setObjectName("ContentMongoDB")
        self.ContentMongoLayout = QtWidgets.QGridLayout(self.ContentMongoDB)
        self.ContentMongoLayout.setContentsMargins(0, 0, 0, 0)
        self.ContentMongoLayout.setSpacing(0)
        self.ContentMongoLayout.setObjectName("ContentMongoLayout")
        self.lblIPMongo = QtWidgets.QLabel(self.ContentMongoDB)
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.lblIPMongo.setFont(font)
        self.lblIPMongo.setLineWidth(0)
        self.lblIPMongo.setObjectName("lblIPMongo")
        self.ContentMongoLayout.addWidget(self.lblIPMongo, 0, 0, 1, 1)
        self.txtIPMongo = QtWidgets.QLineEdit(self.ContentMongoDB)
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.txtIPMongo.setFont(font)
        self.txtIPMongo.setStyleSheet("border-bottom:1px solid black;border-top:none;")
        self.txtIPMongo.setObjectName("txtIPMongo")
        self.ContentMongoLayout.addWidget(self.txtIPMongo, 0, 1, 1, 1)
        self.lblPuertoMOngo = QtWidgets.QLabel(self.ContentMongoDB)
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.lblPuertoMOngo.setFont(font)
        self.lblPuertoMOngo.setLineWidth(0)
        self.lblPuertoMOngo.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.lblPuertoMOngo.setObjectName("lblPuertoMOngo")
        self.ContentMongoLayout.addWidget(self.lblPuertoMOngo, 0, 2, 1, 1)
        self.txtPuertoMongo = QtWidgets.QLineEdit(self.ContentMongoDB)
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.txtPuertoMongo.setFont(font)
        self.txtPuertoMongo.setStyleSheet("border-bottom:1px solid black;border-top:none;")
        self.txtPuertoMongo.setObjectName("txtPuertoMongo")
        self.ContentMongoLayout.addWidget(self.txtPuertoMongo, 0, 3, 1, 1)
        self.lblUsuarioMongo = QtWidgets.QLabel(self.ContentMongoDB)
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.lblUsuarioMongo.setFont(font)
        self.lblUsuarioMongo.setLineWidth(0)
        self.lblUsuarioMongo.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.lblUsuarioMongo.setObjectName("lblUsuarioMongo")
        self.ContentMongoLayout.addWidget(self.lblUsuarioMongo, 1, 0, 1, 1)
        self.txtUsuarioMongo = QtWidgets.QLineEdit(self.ContentMongoDB)
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.txtUsuarioMongo.setFont(font)
        self.txtUsuarioMongo.setStyleSheet("border-bottom:1px solid black;border-top:none;")
        #self.txtUsuarioMongo.setInputMask("")
        self.txtUsuarioMongo.setText("")
        self.txtUsuarioMongo.setObjectName("txtUsuarioMongo")
        self.ContentMongoLayout.addWidget(self.txtUsuarioMongo, 1, 1, 1, 1)
        self.lblPasswordMongo = QtWidgets.QLabel(self.ContentMongoDB)
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.lblPasswordMongo.setFont(font)
        self.lblPasswordMongo.setLineWidth(0)
        self.lblPasswordMongo.setObjectName("lblPasswordMongo")
        self.ContentMongoLayout.addWidget(self.lblPasswordMongo, 1, 2, 1, 1)
        self.txtPassMongo = QtWidgets.QLineEdit(self.ContentMongoDB)
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.txtPassMongo.setFont(font)
        self.txtPassMongo.setStyleSheet("border-bottom:1px solid black;border-top:none;")
        self.txtPassMongo.setInputMask("")
        self.txtPassMongo.setText("")
        self.txtPassMongo.setObjectName("txtPassMongo")
        self.ContentMongoLayout.addWidget(self.txtPassMongo, 1, 3, 1, 1)
        self.ContentAPIExterna = QtWidgets.QGroupBox() # asd
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.ContentAPIExterna.setFont(font)
        self.ContentAPIExterna.setObjectName("ContentAPIExterna")
        self.ContentExternaLayout = QtWidgets.QGridLayout(self.ContentAPIExterna)
        self.ContentExternaLayout.setContentsMargins(0, 0, 0, 0)
        self.ContentExternaLayout.setSpacing(0)
        self.ContentExternaLayout.setObjectName("ContentExternaLayout")
        self.lblIPExterna = QtWidgets.QLabel(self.ContentAPIExterna)
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.lblIPExterna.setFont(font)
        self.lblIPExterna.setLineWidth(0)
        self.lblIPExterna.setObjectName("lblIPExterna")
        self.ContentExternaLayout.addWidget(self.lblIPExterna, 0, 0, 1, 1)
        self.txtIPExterna = QtWidgets.QLineEdit(self.ContentAPIExterna)
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.txtIPExterna.setFont(font)
        self.txtIPExterna.setStyleSheet("border-bottom:1px solid black;border-top:none;")
        #self.txtIPExterna.setInputMask("")
        self.txtIPExterna.setObjectName("txtIPExterna")
        self.ContentExternaLayout.addWidget(self.txtIPExterna, 0, 1, 1, 1)
        self.btnAceptar = QtWidgets.QPushButton()
        self.btnAceptar.setMinimumSize(QtCore.QSize(128, 48))
        self.btnAceptar.setMaximumSize(QtCore.QSize(128, 48))
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(11)
        font.setBold(True)
        font.setWeight(75)
        self.btnAceptar.setFont(font)
        self.btnAceptar.setStyleSheet("border:1px solid green;")
        icon2 = QtGui.QIcon()
        icon2.addPixmap(QtGui.QPixmap(":/source/img/OK.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.btnAceptar.setIcon(icon2)
        self.btnAceptar.setIconSize(QtCore.QSize(24, 24))
        self.btnAceptar.setShortcut("")
        self.btnAceptar.setCheckable(False)
        self.btnAceptar.setFlat(True)
        self.btnAceptar.setObjectName("btnAceptar")
        #UtilsFrame
        self.UtilsFrame = QtWidgets.QFrame(self.ContentBox)
        self.UtilsFrame.setGeometry(QtCore.QRect(30, 20, 256, 132))
        self.UtilsFrame.setMinimumSize(QtCore.QSize(256, 132))
        self.UtilsFrame.setMaximumSize(QtCore.QSize(128, 128))
        self.UtilsFrame.setStyleSheet("background-color: rgb(252, 252, 252);")
        self.UtilsFrame.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.UtilsFrame.setFrameShadow(QtWidgets.QFrame.Plain)
        self.UtilsFrame.setLineWidth(0)
        self.UtilsFrame.setObjectName("UtilsFrame")
        self.utilsLayout = QtWidgets.QVBoxLayout(self.UtilsFrame)
        self.utilsLayout.setContentsMargins(0, 0, 0, 0)
        self.utilsLayout.setSpacing(0)
        self.utilsLayout.setObjectName("utilsLayout")
        self.Status = QtWidgets.QLabel(self.UtilsFrame)
        self.Status.setMinimumSize(QtCore.QSize(64,64))
        self.Status.setMaximumSize(QtCore.QSize(64, 64))
        self.Status.setText("")
        self.Status.setPixmap(QtGui.QPixmap(":/source/img/Cargando.gif"))
        self.Status.setScaledContents(True)
        self.Status.setObjectName("Status")
        self.utilsLayout.addWidget(self.Status, 0, QtCore.Qt.AlignHCenter)
        self.lblStatus = QtWidgets.QLabel(self.UtilsFrame)
        self.lblStatus.setMaximumSize(QtCore.QSize(16777215, 24))
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(11)
        font.setBold(True)
        font.setWeight(75)
        self.lblStatus.setFont(font)
        self.lblStatus.setAlignment(QtCore.Qt.AlignCenter)
        self.lblStatus.setObjectName("lblStatus")
        self.utilsLayout.addWidget(self.lblStatus)
        self.btnReload = QtWidgets.QPushButton(self.UtilsFrame)
        self.btnReload.setMinimumSize(QtCore.QSize(0, 16))
        self.btnReload.setMaximumSize(QtCore.QSize(132, 42))
        font = QtGui.QFont()
        font.setFamily("Roboto")
        font.setPointSize(11)
        font.setBold(True)
        font.setWeight(75)
        self.btnReload.setFont(font)
        self.btnReload.setStyleSheet("border: 1px solid rgb(0, 170, 255);padding:5px;")
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/source/img/retry.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.btnReload.setIcon(icon)
        self.btnReload.setIconSize(QtCore.QSize(24, 24))
        self.btnReload.setFlat(True)
        self.btnReload.setObjectName("btnReload")
        self.utilsLayout.addWidget(self.btnReload, 0, QtCore.Qt.AlignHCenter)
        self.verticalLayout_2.addWidget(self.ContentBox, 0, QtCore.Qt.AlignHCenter)
        self.verticalLayout.addWidget(self.MainFrame)
        self.retranslateUi(ConfiguracionesModal)
        QtCore.QMetaObject.connectSlotsByName(ConfiguracionesModal)
        self.btnReload.hide()
        #Movie
        self.movie = QMovie(":/source/img/Cargando.gif")
        self.movie.setScaledSize(QtCore.QSize(64,64))
        self.Status.setMovie(self.movie)

        self.ContentLayout.addWidget(self.UtilsFrame, 0, QtCore.Qt.AlignHCenter)

        # listener
        self.parent.signals.resize.connect(self.center)
        self.btnExit.clicked.connect(self.exit)
        self.btnAceptar.clicked.connect(self.btnAceptar_Click)
        self.btnReload.clicked.connect(self.ObtenerConfguraciones)

        self.shortcut = QtWidgets.QShortcut(QtCore.Qt.Key_Return,self)
        self.shortcut.activated.connect(self.btnAceptar_Click)

    def showEvent(self,event):
        self.center()
        self.ObtenerConfguraciones()

    def ObtenerConfguraciones(self):
        self.btnReload.hide()
        self.lblStatus.setText("Cargando...")
        self.movie = QMovie(":/source/img/Cargando.gif")
        self.movie.setScaledSize(QtCore.QSize(64,64))
        self.movie.start()
        self.Status.setMovie(self.movie)
        worker = Worker(Logica.ObtenerConfiguraciones,**{"access_token":self.session.access_token})
        worker.signals.finished.connect(self.obtenerConfiguracionesCallBack)
        self.threadpool.start(worker)
        
    def obtenerConfiguracionesCallBack(self,response):
        if isinstance(response,Exception):
            self.btnReload.show()
            self.lblStatus.setText("¡Error! Ha ocurrido un error")
            self.movie = QMovie(":/source/img/Error.png")
            self.movie.setScaledSize(QtCore.QSize(64,64))
            self.movie.start()
            self.Status.setMovie(self.movie)
            return
        if len(response) == 0:
            self.btnReload.show()
            self.lblStatus.setText("¡Vacio! Aún no hay nada")
            self.movie = QMovie(":/source/img/Empty.png")
            self.movie.setScaledSize(QtCore.QSize(64,64))
            self.movie.start()
            self.Status.setMovie(self.movie)
            return
        self.btnReload.clicked.disconnect(self.ObtenerConfguraciones)
        self.UtilsFrame.deleteLater()
        self.config = configuracion(response)
        self.txtIPLocal.setText(response["APISCADA"]["Host"])
        self.txtPuertoLocal.setText(response["APISCADA"]["Port"])
        self.txtIPMongo.setText(response["MONGO"]["MONGO_HOST"])
        self.txtPuertoMongo.setText(response["MONGO"]["MONGO_PORT"])
        self.txtUsuarioMongo.setText(response["MONGO"]["MONGO_USER"])
        self.txtPassMongo.setText(response["MONGO"]["MONGO_PASS"])
        self.txtIPExterna.setText(response["APIPARTICLE"]["URI"])
        self.ContentLayout.addWidget(self.ContentAPILocal)
        self.ContentLayout.addWidget(self.ContentMongoDB)
        self.ContentLayout.addWidget(self.ContentAPIExterna)
        self.ContentLayout.addWidget(self.btnAceptar, 0, QtCore.Qt.AlignHCenter)

    def btnAceptar_Click(self):
        try:
            self.config.apiLocal.IP = self.txtIPLocal.text()
            self.config.apiLocal.puerto = self.txtPuertoLocal.text()
            self.config.mongoDB.IP = self.txtIPMongo.text()
            self.config.mongoDB.puerto = self.txtPuertoMongo.text()
            self.config.mongoDB.usuario = self.txtUsuarioMongo.text()
            self.config.mongoDB.password = self.txtPassMongo.text()
            self.config.apiExterna.uri = self.txtIPExterna.text()
        except ValueError as e:
            QMessageBox.warning(self,"¡Error!",str(e))
            return
        response = QMessageBox.question(self,"¡Confirmacion!","¿Seguro que desea guardar estas configuraciones?\nCualquier error podria provocar que API SCADA\nno se ejecute correctamente")
        if response == QMessageBox.Yes:
            self.guardarConfiguracione()

    def guardarConfiguracione(self):
        self.btnAceptar.hide()
        self.Status = QtWidgets.QLabel(self.ContentBox)
        self.Status.setMaximumSize(QtCore.QSize(64, 64))
        self.Status.setText("")
        self.Status.setPixmap(QtGui.QPixmap(":/source/img/Cargando.gif"))
        self.Status.setScaledContents(True)
        self.Status.setObjectName("Status")
        self.movie = QMovie(":/source/img/Cargando.gif")
        self.movie.start()
        self.Status.setMovie(self.movie)
        self.ContentLayout.addWidget(self.Status, 0, QtCore.Qt.AlignHCenter)
        worker = Worker(Logica.GuardarConfiguraciones,**{"access_token":self.getAccessToken(),"data":self.config.toJSON() } )
        worker.signals.finished.connect(self.guardarConfiguracionesCallback)
        self.threadpool.start(worker)

    def guardarConfiguracionesCallback(self,response):
        self.movie.deleteLater()
        self.Status.deleteLater()
        if isinstance(response,Exception):
            QMessageBox.warning(self,"¡Error!",str(response))
            self.btnAceptar.show()
            return
        if response["success"] == "false":
            QMessageBox.warning(self,"¡Error!",str(response["Message"]))
            self.btnAceptar.show()
        else:
            QMessageBox.information(self,"¡Exito!","¡Exito! Configuraciones actualizadas\nSurtiran efecto la proxima vez que\nse inicie el servicio API SCADA")
            self.success(None)

    def disconnectSignals(self):
        self.parent.signals.resize.disconnect(self.center)
        self.btnExit.clicked.disconnect(self.exit)
        self.btnAceptar.clicked.disconnect(self.btnAceptar_Click)

    def retranslateUi(self, ConfiguracionesModal):
        _translate = QtCore.QCoreApplication.translate
        ConfiguracionesModal.setWindowTitle(_translate("ConfiguracionesModal", "Sistema SCADA"))
        self.lblSCADA.setText(_translate("ConfiguracionesModal", "SCADA"))
        self.lblTitle.setText(_translate("ConfiguracionesModal", "Configuraciones"))
        self.ContentBox.setTitle(_translate("ConfiguracionesModal", "Conexión"))
        self.ContentAPILocal.setTitle(_translate("ConfiguracionesModal", "API Local"))
        self.lblIPLocal.setText(_translate("ConfiguracionesModal", "Dirección IP:"))
        self.txtIPLocal.setText(_translate("ConfiguracionesModal", "127.0.0.1"))
        self.lblPuertoLocal.setText(_translate("ConfiguracionesModal", "Puerto:"))
        self.txtPuertoLocal.setText(_translate("ConfiguracionesModal", "8080"))
        self.ContentMongoDB.setTitle(_translate("ConfiguracionesModal", "MongoDB"))
        self.lblIPMongo.setText(_translate("ConfiguracionesModal", "Dirección IP:"))
        self.txtIPMongo.setText(_translate("ConfiguracionesModal", "127.0.0.1"))
        self.lblPuertoMOngo.setText(_translate("ConfiguracionesModal", "Puerto:"))
        self.txtPuertoMongo.setText(_translate("ConfiguracionesModal", "8080"))
        self.lblUsuarioMongo.setText(_translate("ConfiguracionesModal", "Usuario:"))
        self.lblPasswordMongo.setText(_translate("ConfiguracionesModal", "Contraseña:"))
        self.ContentAPIExterna.setTitle(_translate("ConfiguracionesModal", "API Externa"))
        self.lblIPExterna.setText(_translate("ConfiguracionesModal", "Dirección IP:"))
        self.txtIPExterna.setText(_translate("ConfiguracionesModal", "api.particle.io/v1/devices"))
        self.btnAceptar.setText(_translate("ConfiguracionesModal", "Aceptar"))
        self.lblStatus.setText(_translate("Form", "Cargando..."))
        self.btnReload.setText(_translate("Form", "Reintentar"))
Пример #5
0
class MainWindow(QMainWindow):
    registration_thread: RegisterThread
    sponsor: object
    device_type: object
    mac_address: object
    username: object
    movie: QMovie
    gif_label: QLabel
    email_label: QLabel
    email_textbox: QLineEdit
    button_clicked: bool
    user_type: str
    light_mode_icon: QIcon
    dark_mode_icon: QIcon

    def __init__(self):
        super(MainWindow, self).__init__()
        self.thread_pool = QThreadPool()
        self.ui = uic.loadUi(_UI, self)
        self.config = configparser.RawConfigParser()
        self.center()
        self.mw = windows.ModernWindow(self)
        self.initUI()
        self.init_config()

    def initUI(self):
        self.setWindowIcon(QIcon(_logo))
        self.dark_mode_icon = QIcon('night_mode.ico')
        self.light_mode_icon = QIcon('light_mode.ico')
        self.ui.actionAbout.triggered.connect(self.show_about)
        self.ui.actionHelp.triggered.connect(self.show_help)
        self.ui.actionAdd_user_using_website.triggered.connect(
            lambda: webbrowser.open_new_tab(
                'http://fsunac-1.framingham.edu/administration'))
        self.ui.student_checkbox.stateChanged.connect(self.on_state_change)
        self.ui.faculty_checkbox.stateChanged.connect(self.on_state_change)
        self.ui.other_checkbox.stateChanged.connect(self.on_state_change)
        self.user_type = 'student'
        self.button_clicked = False
        self.mw.show()

    def init_config(self):
        try:
            # Open our config file and load configs if applicable
            with open(_config, 'r') as config_file:
                if os.path.getsize(_config):
                    self.config.read_file(config_file)
                    self.ui.sponsor_textbox.setText(
                        self.config.get('Default', 'sponsor'))

                    if self.config.getboolean('Default', 'dark_mode'):
                        self.ui.change_mode.setIconSize(QSize(35, 35))
                        self.ui.change_mode.setIcon(self.light_mode_icon)
                        styles.dark_mode(QApplication.instance())
                        self.ui.change_mode.setToolTip(
                            "<i><b>Light Mode</b></i>")
                    else:
                        self.ui.change_mode.setIconSize(QSize(25, 25))
                        self.ui.change_mode.setIcon(self.dark_mode_icon)
                        styles.light_mode(QApplication.instance())
                        self.ui.change_mode.setToolTip(
                            "<i><b>Dark Mode</b></i>")
                else:
                    raise FileNotFoundError
        except FileNotFoundError:
            # Create config file if no config found
            self.config.add_section('Default')
            self.config['Default']['sponsor'] = ''
            self.config['Default']['dark_mode'] = 'true'
            self.ui.change_mode.setIcon(self.light_mode_icon)
            self.ui.change_mode.setIconSize(QSize(35, 35))
            self.ui.change_mode.setIcon(self.light_mode_icon)
            styles.dark_mode(QApplication.instance())
            self.ui.change_mode.setToolTip("<i><b>Light Mode</b></i>")

            with open(_config, 'w') as config_file:
                self.config.write(config_file)

    def disable_widgets(self, bool_val):
        objects = [QPushButton, QLineEdit, QMenu, QMenuBar]
        for item in objects:
            for child in self.findChildren(item):
                if bool_val:
                    child.setEnabled(False)
                else:
                    child.setEnabled(True)

    def other_checked(self, other_checked=True):
        if other_checked:
            self.ui.username_label.setText(
                '<html><head/><body><p><span style=" color:#ff0000;">*</span>Full Name</p></body></html>'
            )
            self.ui.progress_label.move(10, 355)
            self.ui.register_button.move(230, 320)
            self.ui.sponsor_label.setGeometry(95, 265, 151, 41)
            self.ui.sponsor_textbox.move(250, 278)

            self.email_label = QLabel(
                '<html><head/><body><p><span style=" color:#ff0000;">*</span>User '
                'Email</p></body></html>', self)
            self.email_label.setStyleSheet('font: 16pt "Verdana";')
            self.email_label.setGeometry(94, 230, 151, 61)
            self.email_textbox = QLineEdit(self)
            self.email_textbox.setGeometry(250, 250, 221, 21)
            self.email_textbox.setStyleSheet('font: 11pt "Verdana";')
            self.setTabOrder(self.ui.device_textbox, self.ui.email_textbox)
            self.ui.email_textbox.returnPressed.connect(
                lambda: self.ui.register_button.animateClick())
            self.email_label.show()
            self.email_textbox.show()
        else:
            try:
                self.ui.username_label.setText(
                    '<html><head/><body><p><span style=" color:#ff0000;">*</span>Username</p></body></html>'
                )
                self.email_textbox.deleteLater()
                self.email_label.deleteLater()
                self.ui.progress_label.move(10, 330)
                self.ui.register_button.move(230, 280)
                self.ui.sponsor_label.setGeometry(95, 220, 151, 41)
                self.ui.sponsor_textbox.move(250, 230)
            except AttributeError:
                pass
            except RuntimeError:
                pass

    @pyqtSlot(int)
    def on_state_change(self, state):
        if state == Qt.Checked:
            if self.sender() == self.ui.student_checkbox:
                self.other_checked(other_checked=False)
                self.user_type = 'student'
                self.ui.faculty_checkbox.setChecked(False)
                self.ui.other_checkbox.setChecked(False)
            elif self.sender() == self.ui.faculty_checkbox:
                self.other_checked(other_checked=False)
                self.user_type = 'faculty'
                self.ui.student_checkbox.setChecked(False)
                self.ui.other_checkbox.setChecked(False)
            elif self.sender() == self.ui.other_checkbox:
                self.other_checked()
                self.user_type = 'other'
                self.ui.student_checkbox.setChecked(False)
                self.ui.faculty_checkbox.setChecked(False)
        else:
            if not self.ui.student_checkbox.isChecked(
            ) and not self.ui.faculty_checkbox.isChecked(
            ) and not self.ui.other_checkbox.isChecked():
                self.ui.student_checkbox.setChecked(True)

    def set_button_clicked(self, bool_val):
        if bool_val:
            self.button_clicked = True
        else:
            self.button_clicked = False

    # Function to display an error if we get one
    def popup_msg(self, title, error_string):
        QMessageBox.about(self, title, error_string)

    # Center our application instead of putting it in the top left
    def center(self):
        frame_gm = self.frameGeometry()
        screen = QApplication.desktop().screenNumber(
            QApplication.desktop().cursor().pos())
        center_point = QApplication.desktop().screenGeometry(screen).center()
        frame_gm.moveCenter(center_point)
        self.move(frame_gm.topLeft())

    def clear_textboxes(self):
        self.ui.username_textbox.clear()
        self.ui.mac_textbox.clear()
        self.ui.device_textbox.clear()
        try:
            self.ui.email_textbox.clear()
        except RuntimeError as r:
            pass
        except AttributeError as a:
            pass

    def change_ui(self):
        with open(_config, 'r'):
            if self.config.getboolean('Default', 'dark_mode'):
                styles.light_mode(QApplication.instance())
                self.ui.change_mode.setIcon(self.dark_mode_icon)
                self.ui.change_mode.setIconSize(QSize(25, 25))
                self.ui.change_mode.setToolTip("<i><b>Dark Mode</b></i>")
                with open(_config, 'w') as config:
                    self.config['Default']['dark_mode'] = 'false'
                    self.config.write(config)
            else:
                styles.dark_mode(QApplication.instance())
                self.ui.change_mode.setIcon(self.light_mode_icon)
                self.ui.change_mode.setIconSize(QSize(35, 35))
                self.ui.change_mode.setToolTip("<i><b>Light Mode</b></i>")
                with open(_config, 'w') as config:
                    self.config['Default']['dark_mode'] = 'true'
                    self.config.write(config)

    def show_about(self):
        with open(_about, 'r') as about:
            self.popup_msg('About', about.read())

    def show_help(self):
        with open(_help, 'r') as about:
            self.popup_msg('Help', about.read())

    def update_label(self, label_text):
        self.ui.progress_label.setText(label_text)

    @Slot()
    def on_change_mode_clicked(self):
        self.change_ui()

    def play_splash(self, bool_val):
        def blur_objects(blur=True):
            objects = [
                QLabel, QPushButton, QLineEdit, QCheckBox, QMenu, QMenuBar
            ]

            for item in objects:
                for child in self.findChildren(item):
                    if child is not self.ui.progress_label and child is not self.gif_label:
                        if blur:
                            child.setGraphicsEffect(QGraphicsBlurEffect())
                        else:
                            child.setGraphicsEffect(
                                QGraphicsBlurEffect().setBlurRadius(0))

        if bool_val:
            self.gif_label = QLabel(self)
            self.gif_label.setScaledContents(True)
            self.gif_label.setGeometry(140, 20, 301, 307)
            self.movie = QMovie(_gif)
            self.gif_label.setMovie(self.movie)
            blur_objects(blur=True)
            self.gif_label.show()
            self.movie.start()
        else:
            blur_objects(blur=False)
            self.movie.stop()
            self.movie.deleteLater()
            self.gif_label.deleteLater()

    @Slot()
    def on_register_button_clicked(self):
        self.button_clicked = True
        # Get the texts entered in the textbox and pass them to the thread
        self.username = self.ui.username_textbox.text()
        self.mac_address = self.ui.mac_textbox.text()
        self.device_type = self.ui.device_textbox.text()
        self.sponsor = self.ui.sponsor_textbox.text()

        if self.user_type == 'other':
            self.registration_thread = RegisterThread(
                self.username,
                self.mac_address,
                self.device_type,
                self.sponsor,
                user_type=self.email_textbox.text())
        else:
            self.registration_thread = RegisterThread(self.username,
                                                      self.mac_address,
                                                      self.device_type,
                                                      self.sponsor,
                                                      user_type=self.user_type)
        self.registration_thread.signals.clear_textboxes_signal.connect(
            self.clear_textboxes)
        self.registration_thread.signals.disable_widgets_signal.connect(
            self.disable_widgets)
        self.registration_thread.signals.popup_signal.connect(self.popup_msg)
        self.registration_thread.signals.label_update_signal.connect(
            self.update_label)
        self.registration_thread.signals.play_splash_signal.connect(
            self.play_splash)
        self.registration_thread.signals.set_button_clicked_signal.connect(
            self.set_button_clicked)

        self.thread_pool.start(self.registration_thread)

    # If the user clicks the red button to exit the window
    @Slot()
    def closeEvent(self, event):
        if self.button_clicked:
            while True:
                try:
                    self.registration_thread.browser.quit()
                    break
                except AttributeError:
                    pass

        with open(_config, 'r'):
            self.config['Default']['sponsor'] = self.ui.sponsor_textbox.text()
        with open(_config, 'w') as config:
            self.config.write(config)
            event.accept()
Пример #6
0
class VidCutter(QWidget):
    def __init__(self, parent):
        super(VidCutter, self).__init__(parent)
        self.novideoWidget = QWidget(self, autoFillBackground=True)
        self.parent = parent
        self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        self.videoWidget = VideoWidget(self)
        self.videoService = VideoService(self)

        QFontDatabase.addApplicationFont(
            MainWindow.get_path('fonts/DroidSansMono.ttf'))
        QFontDatabase.addApplicationFont(
            MainWindow.get_path('fonts/OpenSans.ttf'))

        fontSize = 12 if sys.platform == 'darwin' else 10
        appFont = QFont('Open Sans', fontSize, 300)
        qApp.setFont(appFont)

        self.clipTimes = []
        self.inCut = False
        self.movieFilename = ''
        self.movieLoaded = False
        self.timeformat = 'hh:mm:ss'
        self.finalFilename = ''
        self.totalRuntime = 0

        self.initIcons()
        self.initActions()

        self.toolbar = QToolBar(floatable=False,
                                movable=False,
                                iconSize=QSize(40, 36))
        self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toolbar.setStyleSheet('''QToolBar { spacing:10px; }
            QToolBar QToolButton { border:1px solid transparent; min-width:95px; font-size:11pt; font-weight:400;
                border-radius:5px; padding:1px 2px; color:#444; }
            QToolBar QToolButton:hover { border:1px inset #6A4572; color:#6A4572; background-color:rgba(255, 255, 255, 0.85); }
            QToolBar QToolButton:pressed { border:1px inset #6A4572; color:#6A4572; background-color:rgba(255, 255, 255, 0.25); }
            QToolBar QToolButton:disabled { color:#999; }''')
        self.initToolbar()

        self.appMenu, self.cliplistMenu = QMenu(), QMenu()
        self.initMenus()

        self.seekSlider = VideoSlider(parent=self,
                                      sliderMoved=self.setPosition)

        self.initNoVideo()

        self.cliplist = QListWidget(
            sizePolicy=QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding),
            contextMenuPolicy=Qt.CustomContextMenu,
            uniformItemSizes=True,
            iconSize=QSize(100, 700),
            dragDropMode=QAbstractItemView.InternalMove,
            alternatingRowColors=True,
            customContextMenuRequested=self.itemMenu,
            dragEnabled=True)
        self.cliplist.setStyleSheet(
            'QListView { border-radius:0; border:none; border-left:1px solid #B9B9B9; '
            +
            'border-right:1px solid #B9B9B9; } QListView::item { padding:10px 0; }'
        )
        self.cliplist.setFixedWidth(185)
        self.cliplist.model().rowsMoved.connect(self.syncClipList)

        listHeader = QLabel(pixmap=QPixmap(
            MainWindow.get_path('images/clipindex.png'), 'PNG'),
                            alignment=Qt.AlignCenter)
        listHeader.setStyleSheet(
            '''padding:5px; padding-top:8px; border:1px solid #b9b9b9;
                                    background-color:qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFF,
                                    stop: 0.5 #EAEAEA, stop: 0.6 #EAEAEA stop:1 #FFF);'''
        )

        self.runtimeLabel = QLabel('<div align="right">00:00:00</div>',
                                   textFormat=Qt.RichText)
        self.runtimeLabel.setStyleSheet(
            '''font-family:Droid Sans Mono; font-size:10pt; color:#FFF;
                                           background:rgb(106, 69, 114) url(:images/runtime.png)
                                           no-repeat left center; padding:2px; padding-right:8px;
                                           border:1px solid #B9B9B9;''')

        self.clipindexLayout = QVBoxLayout(spacing=0)
        self.clipindexLayout.setContentsMargins(0, 0, 0, 0)
        self.clipindexLayout.addWidget(listHeader)
        self.clipindexLayout.addWidget(self.cliplist)
        self.clipindexLayout.addWidget(self.runtimeLabel)

        self.videoLayout = QHBoxLayout()
        self.videoLayout.setContentsMargins(0, 0, 0, 0)
        self.videoLayout.addWidget(self.novideoWidget)
        self.videoLayout.addLayout(self.clipindexLayout)

        self.timeCounter = QLabel('00:00:00 / 00:00:00',
                                  autoFillBackground=True,
                                  alignment=Qt.AlignCenter,
                                  sizePolicy=QSizePolicy(
                                      QSizePolicy.Expanding,
                                      QSizePolicy.Fixed))
        self.timeCounter.setStyleSheet(
            'color:#FFF; background:#000; font-family:Droid Sans Mono; font-size:10.5pt; padding:4px;'
        )

        videoplayerLayout = QVBoxLayout(spacing=0)
        videoplayerLayout.setContentsMargins(0, 0, 0, 0)
        videoplayerLayout.addWidget(self.videoWidget)
        videoplayerLayout.addWidget(self.timeCounter)

        self.videoplayerWidget = QWidget(self, visible=False)
        self.videoplayerWidget.setLayout(videoplayerLayout)

        self.muteButton = QPushButton(icon=self.unmuteIcon,
                                      flat=True,
                                      toolTip='Mute',
                                      statusTip='Toggle audio mute',
                                      iconSize=QSize(16, 16),
                                      cursor=Qt.PointingHandCursor,
                                      clicked=self.muteAudio)

        self.volumeSlider = QSlider(Qt.Horizontal,
                                    toolTip='Volume',
                                    statusTip='Adjust volume level',
                                    cursor=Qt.PointingHandCursor,
                                    value=50,
                                    minimum=0,
                                    maximum=100,
                                    sliderMoved=self.setVolume)

        self.menuButton = QPushButton(
            icon=self.menuIcon,
            flat=True,
            toolTip='Menu',
            statusTip='Media + application information',
            iconSize=QSize(24, 24),
            cursor=Qt.PointingHandCursor)
        self.menuButton.setMenu(self.appMenu)

        toolbarLayout = QHBoxLayout()
        toolbarLayout.addWidget(self.toolbar)
        toolbarLayout.setContentsMargins(2, 2, 2, 2)

        toolbarGroup = QGroupBox()
        toolbarGroup.setFlat(False)
        toolbarGroup.setCursor(Qt.PointingHandCursor)
        toolbarGroup.setLayout(toolbarLayout)

        toolbarGroup.setStyleSheet(
            '''QGroupBox { background-color:rgba(0, 0, 0, 0.1);
            border:1px inset #888; border-radius:5px; }''')

        controlsLayout = QHBoxLayout(spacing=0)
        controlsLayout.addStretch(1)
        controlsLayout.addWidget(toolbarGroup)
        controlsLayout.addStretch(1)
        controlsLayout.addWidget(self.muteButton)
        controlsLayout.addWidget(self.volumeSlider)
        controlsLayout.addSpacing(1)
        controlsLayout.addWidget(self.menuButton)

        layout = QVBoxLayout()
        layout.setContentsMargins(10, 10, 10, 4)
        layout.addLayout(self.videoLayout)
        layout.addWidget(self.seekSlider)
        layout.addSpacing(5)
        layout.addLayout(controlsLayout)
        layout.addSpacing(2)

        self.setLayout(layout)

        self.mediaPlayer.setVideoOutput(self.videoWidget)
        self.mediaPlayer.stateChanged.connect(self.mediaStateChanged)
        self.mediaPlayer.positionChanged.connect(self.positionChanged)
        self.mediaPlayer.durationChanged.connect(self.durationChanged)
        self.mediaPlayer.error.connect(self.handleError)

    def initNoVideo(self) -> None:
        novideoImage = QLabel(
            alignment=Qt.AlignCenter,
            autoFillBackground=False,
            pixmap=QPixmap(MainWindow.get_path('images/novideo.png'), 'PNG'),
            sizePolicy=QSizePolicy(QSizePolicy.Expanding,
                                   QSizePolicy.MinimumExpanding))
        novideoImage.setBackgroundRole(QPalette.Dark)
        novideoImage.setContentsMargins(0, 20, 0, 20)
        self.novideoLabel = QLabel(alignment=Qt.AlignCenter,
                                   autoFillBackground=True,
                                   sizePolicy=QSizePolicy(
                                       QSizePolicy.Expanding,
                                       QSizePolicy.Minimum))
        self.novideoLabel.setBackgroundRole(QPalette.Dark)
        self.novideoLabel.setContentsMargins(0, 20, 15, 60)
        novideoLayout = QVBoxLayout(spacing=0)
        novideoLayout.addWidget(novideoImage)
        novideoLayout.addWidget(self.novideoLabel, alignment=Qt.AlignTop)
        self.novideoMovie = QMovie(
            MainWindow.get_path('images/novideotext.gif'))
        self.novideoMovie.frameChanged.connect(self.setNoVideoText)
        self.novideoMovie.start()
        self.novideoWidget.setBackgroundRole(QPalette.Dark)
        self.novideoWidget.setLayout(novideoLayout)

    def initIcons(self) -> None:
        self.appIcon = QIcon(MainWindow.get_path('images/vidcutter.png'))
        self.openIcon = icon('fa.film',
                             color='#444',
                             color_active='#6A4572',
                             scale_factor=0.9)
        self.playIcon = icon('fa.play-circle-o',
                             color='#444',
                             color_active='#6A4572',
                             scale_factor=1.1)
        self.pauseIcon = icon('fa.pause-circle-o',
                              color='#444',
                              color_active='#6A4572',
                              scale_factor=1.1)
        self.cutStartIcon = icon('fa.scissors',
                                 scale_factor=1.15,
                                 color='#444',
                                 color_active='#6A4572')
        endicon_normal = icon('fa.scissors', scale_factor=1.15,
                              color='#444').pixmap(QSize(36, 36)).toImage()
        endicon_active = icon('fa.scissors',
                              scale_factor=1.15,
                              color='#6A4572').pixmap(QSize(36, 36)).toImage()
        self.cutEndIcon = QIcon()
        self.cutEndIcon.addPixmap(
            QPixmap.fromImage(
                endicon_normal.mirrored(horizontal=True, vertical=False)),
            QIcon.Normal, QIcon.Off)
        self.cutEndIcon.addPixmap(
            QPixmap.fromImage(
                endicon_active.mirrored(horizontal=True, vertical=False)),
            QIcon.Active, QIcon.Off)
        self.saveIcon = icon('fa.video-camera',
                             color='#6A4572',
                             color_active='#6A4572')
        self.muteIcon = QIcon(MainWindow.get_path('images/muted.png'))
        self.unmuteIcon = QIcon(MainWindow.get_path('images/unmuted.png'))
        self.upIcon = icon('ei.caret-up', color='#444')
        self.downIcon = icon('ei.caret-down', color='#444')
        self.removeIcon = icon('ei.remove', color='#B41D1D')
        self.removeAllIcon = icon('ei.trash', color='#B41D1D')
        self.successIcon = QIcon(MainWindow.get_path('images/success.png'))
        self.menuIcon = icon('fa.cog', color='#444', scale_factor=1.15)
        self.completePlayIcon = icon('fa.play', color='#444')
        self.completeOpenIcon = icon('fa.folder-open', color='#444')
        self.completeRestartIcon = icon('fa.retweet', color='#444')
        self.completeExitIcon = icon('fa.sign-out', color='#444')
        self.mediaInfoIcon = icon('fa.info-circle', color='#444')
        self.updateCheckIcon = icon('fa.cloud-download', color='#444')

    def initActions(self) -> None:
        self.openAction = QAction(self.openIcon,
                                  'Open',
                                  self,
                                  statusTip='Open media file',
                                  triggered=self.openMedia)
        self.playAction = QAction(self.playIcon,
                                  'Play',
                                  self,
                                  statusTip='Play media file',
                                  triggered=self.playMedia,
                                  enabled=False)
        self.cutStartAction = QAction(self.cutStartIcon,
                                      ' Start',
                                      self,
                                      toolTip='Start',
                                      statusTip='Set clip start marker',
                                      triggered=self.setCutStart,
                                      enabled=False)
        self.cutEndAction = QAction(self.cutEndIcon,
                                    ' End',
                                    self,
                                    toolTip='End',
                                    statusTip='Set clip end marker',
                                    triggered=self.setCutEnd,
                                    enabled=False)
        self.saveAction = QAction(self.saveIcon,
                                  'Save',
                                  self,
                                  statusTip='Save clips to a new video file',
                                  triggered=self.cutVideo,
                                  enabled=False)
        self.moveItemUpAction = QAction(
            self.upIcon,
            'Move up',
            self,
            statusTip='Move clip position up in list',
            triggered=self.moveItemUp,
            enabled=False)
        self.moveItemDownAction = QAction(
            self.downIcon,
            'Move down',
            self,
            statusTip='Move clip position down in list',
            triggered=self.moveItemDown,
            enabled=False)
        self.removeItemAction = QAction(
            self.removeIcon,
            'Remove clip',
            self,
            statusTip='Remove selected clip from list',
            triggered=self.removeItem,
            enabled=False)
        self.removeAllAction = QAction(self.removeAllIcon,
                                       'Clear list',
                                       self,
                                       statusTip='Clear all clips from list',
                                       triggered=self.clearList,
                                       enabled=False)
        self.mediaInfoAction = QAction(
            self.mediaInfoIcon,
            'Media information',
            self,
            statusTip='View current media file information',
            triggered=self.mediaInfo,
            enabled=False)
        self.updateCheckAction = QAction(
            self.updateCheckIcon,
            'Check for updates...',
            self,
            statusTip='Check for application updates',
            triggered=self.updateCheck)
        self.aboutQtAction = QAction('About Qt',
                                     self,
                                     statusTip='About Qt',
                                     triggered=qApp.aboutQt)
        self.aboutAction = QAction('About %s' % qApp.applicationName(),
                                   self,
                                   statusTip='Credits and licensing',
                                   triggered=self.aboutInfo)

    def initToolbar(self) -> None:
        self.toolbar.addAction(self.openAction)
        self.toolbar.addAction(self.playAction)
        self.toolbar.addAction(self.cutStartAction)
        self.toolbar.addAction(self.cutEndAction)
        self.toolbar.addAction(self.saveAction)

    def initMenus(self) -> None:
        self.appMenu.addAction(self.mediaInfoAction)
        self.appMenu.addAction(self.updateCheckAction)
        self.appMenu.addSeparator()
        self.appMenu.addAction(self.aboutQtAction)
        self.appMenu.addAction(self.aboutAction)

        self.cliplistMenu.addAction(self.moveItemUpAction)
        self.cliplistMenu.addAction(self.moveItemDownAction)
        self.cliplistMenu.addSeparator()
        self.cliplistMenu.addAction(self.removeItemAction)
        self.cliplistMenu.addAction(self.removeAllAction)

    @staticmethod
    def getSpacer() -> QWidget:
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        return spacer

    def setRunningTime(self, runtime: str) -> None:
        self.runtimeLabel.setText('<div align="right">%s</div>' % runtime)

    @pyqtSlot(int)
    def setNoVideoText(self) -> None:
        self.novideoLabel.setPixmap(self.novideoMovie.currentPixmap())

    def itemMenu(self, pos: QPoint) -> None:
        globalPos = self.cliplist.mapToGlobal(pos)
        self.moveItemUpAction.setEnabled(False)
        self.moveItemDownAction.setEnabled(False)
        self.removeItemAction.setEnabled(False)
        self.removeAllAction.setEnabled(False)
        index = self.cliplist.currentRow()
        if index != -1:
            if not self.inCut:
                if index > 0:
                    self.moveItemUpAction.setEnabled(True)
                if index < self.cliplist.count() - 1:
                    self.moveItemDownAction.setEnabled(True)
            if self.cliplist.count() > 0:
                self.removeItemAction.setEnabled(True)
        if self.cliplist.count() > 0:
            self.removeAllAction.setEnabled(True)
        self.cliplistMenu.exec_(globalPos)

    def moveItemUp(self) -> None:
        index = self.cliplist.currentRow()
        tmpItem = self.clipTimes[index]
        del self.clipTimes[index]
        self.clipTimes.insert(index - 1, tmpItem)
        self.renderTimes()

    def moveItemDown(self) -> None:
        index = self.cliplist.currentRow()
        tmpItem = self.clipTimes[index]
        del self.clipTimes[index]
        self.clipTimes.insert(index + 1, tmpItem)
        self.renderTimes()

    def removeItem(self) -> None:
        index = self.cliplist.currentRow()
        del self.clipTimes[index]
        if self.inCut and index == self.cliplist.count() - 1:
            self.inCut = False
            self.initMediaControls()
        self.renderTimes()

    def clearList(self) -> None:
        self.clipTimes.clear()
        self.cliplist.clear()
        self.inCut = False
        self.renderTimes()
        self.initMediaControls()

    def mediaInfo(self) -> None:
        if self.mediaPlayer.isMetaDataAvailable():
            content = '<table cellpadding="4">'
            for key in self.mediaPlayer.availableMetaData():
                val = self.mediaPlayer.metaData(key)
                if type(val) is QSize:
                    val = '%s x %s' % (val.width(), val.height())
                content += '<tr><td align="right"><b>%s:</b></td><td>%s</td></tr>\n' % (
                    key, val)
            content += '</table>'
            mbox = QMessageBox(windowTitle='Media Information',
                               windowIcon=self.parent.windowIcon(),
                               textFormat=Qt.RichText)
            mbox.setText('<b>%s</b>' % os.path.basename(
                self.mediaPlayer.currentMedia().canonicalUrl().toLocalFile()))
            mbox.setInformativeText(content)
            mbox.exec_()
        else:
            QMessageBox.critical(
                self.parent, 'MEDIA ERROR',
                '<h3>Could not probe media file.</h3>' +
                '<p>An error occurred while analyzing the media file for its metadata details.'
                +
                '<br/><br/><b>This DOES NOT mean there is a problem with the file and you should '
                + 'be able to continue using it.</b></p>')

    def aboutInfo(self) -> None:
        about_html = '''<style>
    a { color:#441d4e; text-decoration:none; font-weight:bold; }
    a:hover { text-decoration:underline; }
</style>
<div style="min-width:650px;">
<p style="font-size:26pt; font-weight:bold; color:#6A4572;">%s</p>
<p>
    <span style="font-size:13pt;"><b>Version: %s</b></span>
    <span style="font-size:10pt;position:relative;left:5px;">( %s )</span>
</p>
<p style="font-size:13px;">
    Copyright &copy; 2016 <a href="mailto:[email protected]">Pete Alexandrou</a>
    <br/>
    Website: <a href="%s">%s</a>
</p>
<p style="font-size:13px;">
    Thanks to the folks behind the <b>Qt</b>, <b>PyQt</b> and <b>FFmpeg</b>
    projects for all their hard and much appreciated work.
</p>
<p style="font-size:11px;">
    This program 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 2
    of the License, or (at your option) any later version.
</p>
<p style="font-size:11px;">
    This software uses libraries from the <a href="https://www.ffmpeg.org">FFmpeg</a> project under the
    <a href="https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html">LGPLv2.1</a>
</p></div>''' % (qApp.applicationName(), qApp.applicationVersion(),
                 platform.architecture()[0], qApp.organizationDomain(),
                 qApp.organizationDomain())
        QMessageBox.about(self.parent, 'About %s' % qApp.applicationName(),
                          about_html)

    def openMedia(self) -> None:
        filename, _ = QFileDialog.getOpenFileName(self.parent,
                                                  caption='Select video',
                                                  directory=QDir.homePath())
        if filename != '':
            self.loadFile(filename)

    def loadFile(self, filename: str) -> None:
        self.movieFilename = filename
        if not os.path.exists(filename):
            return
        self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(filename)))
        self.initMediaControls(True)
        self.cliplist.clear()
        self.clipTimes = []
        self.parent.setWindowTitle(
            '%s - %s' % (qApp.applicationName(), os.path.basename(filename)))
        if not self.movieLoaded:
            self.videoLayout.replaceWidget(self.novideoWidget,
                                           self.videoplayerWidget)
            self.novideoMovie.stop()
            self.novideoMovie.deleteLater()
            self.novideoWidget.deleteLater()
            self.videoplayerWidget.show()
            self.videoWidget.show()
            self.movieLoaded = True
        if self.mediaPlayer.isVideoAvailable():
            self.mediaPlayer.setPosition(1)
        self.mediaPlayer.play()
        self.mediaPlayer.pause()

    def playMedia(self) -> None:
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.mediaPlayer.pause()
            self.playAction.setText('Play')
        else:
            self.mediaPlayer.play()
            self.playAction.setText('Pause')

    def initMediaControls(self, flag: bool = True) -> None:
        self.playAction.setEnabled(flag)
        self.saveAction.setEnabled(False)
        self.cutStartAction.setEnabled(flag)
        self.cutEndAction.setEnabled(False)
        self.mediaInfoAction.setEnabled(flag)
        if flag:
            self.seekSlider.setRestrictValue(0)

    def setPosition(self, position: int) -> None:
        self.mediaPlayer.setPosition(position)

    def positionChanged(self, progress: int) -> None:
        self.seekSlider.setValue(progress)
        currentTime = self.deltaToQTime(progress)
        totalTime = self.deltaToQTime(self.mediaPlayer.duration())
        self.timeCounter.setText('%s / %s' % (currentTime.toString(
            self.timeformat), totalTime.toString(self.timeformat)))

    @pyqtSlot()
    def mediaStateChanged(self) -> None:
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.playAction.setIcon(self.pauseIcon)
        else:
            self.playAction.setIcon(self.playIcon)

    def durationChanged(self, duration: int) -> None:
        self.seekSlider.setRange(0, duration)

    def muteAudio(self) -> None:
        if self.mediaPlayer.isMuted():
            self.muteButton.setIcon(self.unmuteIcon)
            self.muteButton.setToolTip('Mute')
        else:
            self.muteButton.setIcon(self.muteIcon)
            self.muteButton.setToolTip('Unmute')
        self.mediaPlayer.setMuted(not self.mediaPlayer.isMuted())

    def setVolume(self, volume: int) -> None:
        self.mediaPlayer.setVolume(volume)

    def toggleFullscreen(self) -> None:
        self.videoWidget.setFullScreen(not self.videoWidget.isFullScreen())

    def setCutStart(self) -> None:
        self.clipTimes.append([
            self.deltaToQTime(self.mediaPlayer.position()), '',
            self.captureImage()
        ])
        self.cutStartAction.setDisabled(True)
        self.cutEndAction.setEnabled(True)
        self.seekSlider.setRestrictValue(self.seekSlider.value(), True)
        self.inCut = True
        self.renderTimes()

    def setCutEnd(self) -> None:
        item = self.clipTimes[len(self.clipTimes) - 1]
        selected = self.deltaToQTime(self.mediaPlayer.position())
        if selected.__lt__(item[0]):
            QMessageBox.critical(
                self.parent, 'Invalid END Time',
                'The clip end time must come AFTER it\'s start time. Please try again.'
            )
            return
        item[1] = selected
        self.cutStartAction.setEnabled(True)
        self.cutEndAction.setDisabled(True)
        self.seekSlider.setRestrictValue(0, False)
        self.inCut = False
        self.renderTimes()

    @pyqtSlot(QModelIndex, int, int, QModelIndex, int)
    def syncClipList(self, parent: QModelIndex, start: int, end: int,
                     destination: QModelIndex, row: int) -> None:
        if start < row:
            index = row - 1
        else:
            index = row
        clip = self.clipTimes.pop(start)
        self.clipTimes.insert(index, clip)

    def renderTimes(self) -> None:
        self.cliplist.clear()
        if len(self.clipTimes) > 4:
            self.cliplist.setFixedWidth(200)
        else:
            self.cliplist.setFixedWidth(185)
        self.totalRuntime = 0
        for item in self.clipTimes:
            endItem = ''
            if type(item[1]) is QTime:
                endItem = item[1].toString(self.timeformat)
                self.totalRuntime += item[0].msecsTo(item[1])
            listitem = QListWidgetItem()
            listitem.setTextAlignment(Qt.AlignVCenter)
            if type(item[2]) is QPixmap:
                listitem.setIcon(QIcon(item[2]))
            self.cliplist.addItem(listitem)
            marker = QLabel(
                '''<style>b { font-size:7pt; } p { margin:2px 5px; }</style>
                            <p><b>START</b><br/>%s<br/><b>END</b><br/>%s</p>'''
                % (item[0].toString(self.timeformat), endItem))
            marker.setStyleSheet('border:none;')
            self.cliplist.setItemWidget(listitem, marker)
            listitem.setFlags(Qt.ItemIsSelectable | Qt.ItemIsDragEnabled
                              | Qt.ItemIsEnabled)
        if len(self.clipTimes) and not self.inCut:
            self.saveAction.setEnabled(True)
        if self.inCut or len(self.clipTimes) == 0 or not type(
                self.clipTimes[0][1]) is QTime:
            self.saveAction.setEnabled(False)
        self.setRunningTime(
            self.deltaToQTime(self.totalRuntime).toString(self.timeformat))

    @staticmethod
    def deltaToQTime(millisecs: int) -> QTime:
        secs = millisecs / 1000
        return QTime((secs / 3600) % 60, (secs / 60) % 60, secs % 60,
                     (secs * 1000) % 1000)

    def captureImage(self) -> QPixmap:
        frametime = self.deltaToQTime(self.mediaPlayer.position()).toString(
            self.timeformat)
        inputfile = self.mediaPlayer.currentMedia().canonicalUrl().toLocalFile(
        )
        imagecap = self.videoService.capture(inputfile, frametime)
        if type(imagecap) is QPixmap:
            return imagecap

    def cutVideo(self) -> bool:
        clips = len(self.clipTimes)
        filename, filelist = '', []
        source = self.mediaPlayer.currentMedia().canonicalUrl().toLocalFile()
        _, sourceext = os.path.splitext(source)
        if clips > 0:
            self.finalFilename, _ = QFileDialog.getSaveFileName(
                self.parent, 'Save video', source,
                'Video files (*%s)' % sourceext)
            if self.finalFilename == '':
                return False
            qApp.setOverrideCursor(Qt.BusyCursor)
            self.saveAction.setDisabled(True)
            self.showProgress(clips)
            file, ext = os.path.splitext(self.finalFilename)
            index = 1
            self.progress.setLabelText('Cutting media files...')
            qApp.processEvents()
            for clip in self.clipTimes:
                duration = self.deltaToQTime(clip[0].msecsTo(
                    clip[1])).toString(self.timeformat)
                filename = '%s_%s%s' % (file, '{0:0>2}'.format(index), ext)
                filelist.append(filename)
                self.videoService.cut(source, filename,
                                      clip[0].toString(self.timeformat),
                                      duration)
                index += 1
            if len(filelist) > 1:
                self.joinVideos(filelist, self.finalFilename)
            else:
                QFile.remove(self.finalFilename)
                QFile.rename(filename, self.finalFilename)
            self.progress.setLabelText('Complete...')
            self.progress.setValue(100)
            qApp.processEvents()
            self.progress.close()
            self.progress.deleteLater()
            qApp.restoreOverrideCursor()
            self.complete()
            return True
        return False

    def joinVideos(self, joinlist: list, filename: str) -> None:
        listfile = os.path.normpath(
            os.path.join(os.path.dirname(joinlist[0]), '.vidcutter.list'))
        fobj = open(listfile, 'w')
        for file in joinlist:
            fobj.write('file \'%s\'\n' % file.replace("'", "\\'"))
        fobj.close()
        self.videoService.join(listfile, filename)
        QFile.remove(listfile)
        for file in joinlist:
            if os.path.isfile(file):
                QFile.remove(file)

    def updateCheck(self) -> None:
        self.updater = Updater()
        self.updater.updateAvailable.connect(self.updateHandler)
        self.updater.start()

    def updateHandler(self, updateExists: bool, version: str = None):
        if updateExists:
            if Updater.notify_update(self, version) == QMessageBox.AcceptRole:
                self.updater.install_update(self)
        else:
            Updater.notify_no_update(self)

    def showProgress(self,
                     steps: int,
                     label: str = 'Analyzing media...') -> None:
        self.progress = QProgressDialog(label,
                                        None,
                                        0,
                                        steps,
                                        self.parent,
                                        windowModality=Qt.ApplicationModal,
                                        windowIcon=self.parent.windowIcon(),
                                        minimumDuration=0,
                                        minimumWidth=500)
        self.progress.show()
        for i in range(steps):
            self.progress.setValue(i)
            qApp.processEvents()
            time.sleep(1)

    def complete(self) -> None:
        info = QFileInfo(self.finalFilename)
        mbox = QMessageBox(windowTitle='VIDEO PROCESSING COMPLETE',
                           minimumWidth=500,
                           textFormat=Qt.RichText)
        mbox.setText(
            '''
    <style>
        table.info { margin:6px; padding:4px 15px; }
        td.label { font-weight:bold; font-size:10.5pt; text-align:right; }
        td.value { font-size:10.5pt; }
    </style>
    <table class="info" cellpadding="4" cellspacing="0">
        <tr>
            <td class="label"><b>File:</b></td>
            <td class="value" nowrap>%s</td>
        </tr>
        <tr>
            <td class="label"><b>Size:</b></td>
            <td class="value">%s</td>
        </tr>
        <tr>
            <td class="label"><b>Length:</b></td>
            <td class="value">%s</td>
        </tr>
    </table><br/>''' %
            (QDir.toNativeSeparators(
                self.finalFilename), self.sizeof_fmt(int(info.size())),
             self.deltaToQTime(self.totalRuntime).toString(self.timeformat)))
        play = mbox.addButton('Play', QMessageBox.AcceptRole)
        play.setIcon(self.completePlayIcon)
        play.clicked.connect(self.openResult)
        fileman = mbox.addButton('Open', QMessageBox.AcceptRole)
        fileman.setIcon(self.completeOpenIcon)
        fileman.clicked.connect(self.openFolder)
        end = mbox.addButton('Exit', QMessageBox.AcceptRole)
        end.setIcon(self.completeExitIcon)
        end.clicked.connect(self.close)
        new = mbox.addButton('Restart', QMessageBox.AcceptRole)
        new.setIcon(self.completeRestartIcon)
        new.clicked.connect(self.parent.restart)
        mbox.setDefaultButton(new)
        mbox.setEscapeButton(new)
        mbox.adjustSize()
        mbox.exec_()

    def sizeof_fmt(self, num: float, suffix: chr = 'B') -> str:
        for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']:
            if abs(num) < 1024.0:
                return "%3.1f%s%s" % (num, unit, suffix)
            num /= 1024.0
        return "%.1f%s%s" % (num, 'Y', suffix)

    @pyqtSlot()
    def openFolder(self) -> None:
        self.openResult(pathonly=True)

    @pyqtSlot(bool)
    def openResult(self, pathonly: bool = False) -> None:
        self.parent.restart()
        if len(self.finalFilename) and os.path.exists(self.finalFilename):
            target = self.finalFilename if not pathonly else os.path.dirname(
                self.finalFilename)
            QDesktopServices.openUrl(QUrl.fromLocalFile(target))

    @pyqtSlot()
    def startNew(self) -> None:
        qApp.restoreOverrideCursor()
        self.clearList()
        self.seekSlider.setValue(0)
        self.seekSlider.setRange(0, 0)
        self.mediaPlayer.setMedia(QMediaContent())
        self.initNoVideo()
        self.videoLayout.replaceWidget(self.videoplayerWidget,
                                       self.novideoWidget)
        self.initMediaControls(False)
        self.parent.setWindowTitle('%s' % qApp.applicationName())

    def wheelEvent(self, event: QWheelEvent) -> None:
        if self.mediaPlayer.isVideoAvailable(
        ) or self.mediaPlayer.isAudioAvailable():
            if event.angleDelta().y() > 0:
                newval = self.seekSlider.value() - 1000
            else:
                newval = self.seekSlider.value() + 1000
            self.seekSlider.setValue(newval)
            self.seekSlider.setSliderPosition(newval)
            self.mediaPlayer.setPosition(newval)
        event.accept()

    def keyPressEvent(self, event: QKeyEvent) -> None:
        if self.mediaPlayer.isVideoAvailable(
        ) or self.mediaPlayer.isAudioAvailable():
            addtime = 0
            if event.key() == Qt.Key_Left:
                addtime = -1000
            elif event.key() == Qt.Key_PageUp or event.key() == Qt.Key_Up:
                addtime = -10000
            elif event.key() == Qt.Key_Right:
                addtime = 1000
            elif event.key() == Qt.Key_PageDown or event.key() == Qt.Key_Down:
                addtime = 10000
            elif event.key() == Qt.Key_Enter:
                self.toggleFullscreen()
            elif event.key(
            ) == Qt.Key_Escape and self.videoWidget.isFullScreen():
                self.videoWidget.setFullScreen(False)
            if addtime != 0:
                newval = self.seekSlider.value() + addtime
                self.seekSlider.setValue(newval)
                self.seekSlider.setSliderPosition(newval)
                self.mediaPlayer.setPosition(newval)
        event.accept()

    def mousePressEvent(self, event: QMouseEvent) -> None:
        if event.button() == Qt.BackButton and self.cutStartAction.isEnabled():
            self.setCutStart()
            event.accept()
        elif event.button(
        ) == Qt.ForwardButton and self.cutEndAction.isEnabled():
            self.setCutEnd()
            event.accept()
        else:
            super(VidCutter, self).mousePressEvent(event)

    @pyqtSlot(QMediaPlayer.Error)
    def handleError(self, error: QMediaPlayer.Error) -> None:
        qApp.restoreOverrideCursor()
        self.startNew()
        if error == QMediaPlayer.ResourceError:
            QMessageBox.critical(
                self.parent, 'INVALID MEDIA',
                'Invalid media file detected at:<br/><br/><b>%s</b><br/><br/>%s'
                % (self.movieFilename, self.mediaPlayer.errorString()))
        else:
            QMessageBox.critical(self.parent, 'ERROR NOTIFICATION',
                                 self.mediaPlayer.errorString())

    def closeEvent(self, event: QCloseEvent) -> None:
        self.parent.closeEvent(event)