Exemplo n.º 1
0
class MyWidget2(QMainWindow, Ui_MainWindow1):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.init_ui()
        self.dialog = MyWidget2()

    def init_ui(self):
        self.easy_btn.clicked.connect(self.openGame)
        self.show()

    def init_pygame(self):
        self.game = Game()
        self.timer = QTimer()
        self.timer.timeout.connect(self.pygame_loop)
        self.timer.start(10)

    def pygame_loop(self):
        if self.game.loop(self):
            self.timer.stop()
            self.timer.disconnect()
            pygame.quit()

    def openGame(self):
        self.init_pygame()
        self.dialog.close()
Exemplo n.º 2
0
class proxyTryconnect(QObject):
    reconnectproxy = pyqtSignal()

    def __init__(self):
        super(proxyTryconnect, self).__init__()
        self.trytimes = 1
        self.keeptrytimes = False
        self.resetTime = False
        self.resetTimeCount = 0
        self.periodicCheck = QTimer()

    def periodicCheckProxyStatus(self):
        self.resetTimeCount += 1
        if self.resetTimeCount <= self.resetTime and self.trytimes <= 0:
            self.reconnectproxy.emit()
            self.reset()
        elif self.resetTimeCount >= self.resetTime and self.trytimes > 0:
            self.resetTimeCount = 0

    def reset(self):
        self.resetTimeCount = 0
        self.trytimes = copy.deepcopy(self.keeptrytimes)

    def setresetTime(self, seconds, trytimes):
        if not isinstance(seconds, int): seconds = 60
        if not isinstance(trytimes, int): trytimes = 3
        if seconds == 0: seconds = 1
        if trytimes == 0: self.trytimes = 1
        else: self.trytimes = copy.deepcopy(trytimes)
        self.keeptrytimes = copy.deepcopy(self.trytimes)

        self.resetTime = seconds * self.keeptrytimes

        self.periodicCheck.timeout.connect(self.periodicCheckProxyStatus)
        self.periodicCheck.start(1000)

    def stopperiodicCheckProxyStatus(self):
        self.periodicCheck.stop()
        self.periodicCheck.disconnect(self.periodicCheckProxyStatus)

    def trytimesDecrease(self):
        self.trytimes -= 1
Exemplo n.º 3
0
class bridgePanel(QMainWindow, QObject):
    start = pyqtSignal()
    stop = pyqtSignal()

    def __init__(self, app):
        super().__init__()
        self.bridgetreasureChest = bridgetreasureChest.bridgetreasureChest()
        self.app = app
        self.translate = QCoreApplication.translate
        self.__v2rayshellVersion = "20180511"
        self.__windowTitile = "V2Ray-shell" + " " + self.__v2rayshellVersion
        self.runv2raycore = False
        self.iconStart = QIcon()
        self.iconStop = QIcon()
        self.__iconSize = QSize(32, 32)
        self.iconStart.addPixmap(QPixmap(filePath + "/icons/start.png"),
                                 QIcon.Normal, QIcon.On)
        self.iconStop.addPixmap(QPixmap(filePath + "/icons/stop.png"),
                                QIcon.Disabled, QIcon.On)
        self.currentRowRightClicked = False
        self.v2rayshellTrayIcon = QSystemTrayIcon()
        self.v2rayshellTrayIcon.setIcon(self.iconStart)
        self.v2rayshellTrayIcon.show()

        self.radioButtonGroup = QButtonGroup()

        self.setV2RayshellLanguage()
        self.trytimes = self.bridgetreasureChest.getConnectiontrytimes()
        self.interval = self.bridgetreasureChest.getConnectioninterval()
        self.proxyTryConnect = proxyTryconnect()
        if v2rayshellDebug: self.proxyTryConnect.setresetTime(6, 3)
        else: self.proxyTryConnect.setresetTime(self.interval, self.trytimes)
        self.labelBridge = (self.translate("bridgePanel", "Start/Stop"),
                            self.translate("bridgePanel", "Host Name"),
                            self.translate("bridgePanel", "Config Name"),
                            self.translate("bridgePanel", "Proxy"),
                            self.translate("bridgePanel", "Time Lag"))
        self.checkTrayicon = QTimer()
        self.createBridgePanel()

    def createBridgePanel(self):
        self.setWindowTitle(self.__windowTitile)
        self.setWindowIcon(self.iconStart)
        menubar = self.menuBar()
        self.statusBar()

        self.actionNewV2rayConfigFile = QAction(
            self.translate("bridgePanel", "Add V2Ray-core Config File"), self)
        self.actionNewV2rayConfigFile.setShortcut(QKeySequence.New)
        self.actionNewV2rayConfigFile.setStatusTip(
            self.translate("bridgePanel", "Add V2Ray-core Config File"))

        self.actionSaveV2rayshellConfigFile = QAction(
            self.translate("bridgePanel", "Save V2Ray-shell Config File"),
            self)
        self.actionSaveV2rayshellConfigFile.setShortcut(QKeySequence.Save)
        self.actionSaveV2rayshellConfigFile.setStatusTip(
            self.translate("bridgePanel", "Save V2Ray-shell Config File"))

        self.actionReloadV2rayshellConfigFile = QAction(
            self.translate("bridgePanel", "Open V2Ray-shell Config File"),
            self)
        self.actionReloadV2rayshellConfigFile.setShortcut(QKeySequence.Open)
        self.actionReloadV2rayshellConfigFile.setStatusTip(
            self.translate("bridgePanel", "Open V2Ray-shell Config File"))

        self.actionQuitV2rayshellPanel = QAction(
            self.translate("bridgePanel", "Quit"), self)
        if sys.platform.startswith('win'):
            self.actionQuitV2rayshellPanel.setShortcut("Ctrl+Q")
        else:
            self.actionQuitV2rayshellPanel.setShortcut(QKeySequence.Quit)
        self.actionQuitV2rayshellPanel.setStatusTip(
            self.translate("bridgePanel", "Quit V2Ray-shell"))

        fileMenu = menubar.addMenu(self.translate("bridgePanel", "&File"))
        fileMenu.addAction(self.actionNewV2rayConfigFile)
        fileMenu.addSeparator()
        fileMenu.addAction(self.actionReloadV2rayshellConfigFile)
        fileMenu.addAction(self.actionSaveV2rayshellConfigFile)
        fileMenu.addSeparator()
        fileMenu.addAction(self.actionQuitV2rayshellPanel)

        self.texteditBridge = QTextEdit(self)
        self.texteditBridge.setReadOnly(True)

        self.tableWidgetBridge = QTableWidget()
        self.tableWidgetBridge.setRowCount(0)
        self.tableWidgetBridge.setColumnCount(5)
        self.tableWidgetBridge.setHorizontalHeaderLabels(self.labelBridge)
        self.tableWidgetBridge.setSelectionMode(
            QAbstractItemView.SingleSelection)
        self.tableWidgetBridge.setSelectionBehavior(
            QAbstractItemView.SelectRows)
        self.tableWidgetBridge.setEditTriggers(
            QAbstractItemView.NoEditTriggers)
        #self.tableWidgetBridge.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.tableWidgetBridge.setContextMenuPolicy(Qt.CustomContextMenu)

        self.popMenu = popMenu = QMenu(self.tableWidgetBridge)
        self.actionpopMenuAddV2rayConfigFile = QAction(
            self.translate("bridgePanel", "Add V2Ray Config File"), self)
        self.actionpopMenuAddV2rayConfigFile.setShortcut("Ctrl+n")
        self.actionpopMenuEditV2rayConfigFile = QAction(
            self.translate("bridgePanel", "Edit V2Ray Config File"), self)
        self.actionpopMenuProxyCheckTimeLag = QAction(
            self.translate("bridgePanel", "Proxy Time Lag Check..."), self)
        self.actionpopMenuDeleteRow = QAction(
            self.translate("bridgePanel", "Delete"), self)

        popMenu.addAction(self.actionpopMenuAddV2rayConfigFile)
        popMenu.addAction(self.actionpopMenuEditV2rayConfigFile)
        popMenu.addAction(self.actionpopMenuProxyCheckTimeLag)
        popMenu.addAction(self.actionpopMenuDeleteRow)

        self.actionopenV2rayshellPreferencesPanel = QAction(
            self.translate("bridgePanel", "preferences"), self)
        self.actionopenV2rayshellPreferencesPanel.setStatusTip(
            self.translate("bridgePanel", "Setting V2Ray-shell"))

        optionMenu = menubar.addMenu(self.translate("bridgePanel", "&options"))
        optionMenu.addAction(self.actionpopMenuProxyCheckTimeLag)
        optionMenu.addAction(self.actionopenV2rayshellPreferencesPanel)

        helpMenu = menubar.addMenu(self.translate("bridgePanel", "&help"))
        self.actioncheckv2raycoreupdate = QAction(
            self.translate("bridgePanel", "check V2Ray-core update"), self)
        self.actionv2rayshellBugreport = QAction(
            self.translate("bridgePanel", "Bug Report"), self)
        self.actionaboutv2rayshell = QAction(
            self.translate("bridgePanel", "About"), self)

        helpMenu.addAction(self.actioncheckv2raycoreupdate)
        helpMenu.addAction(self.actionv2rayshellBugreport)
        helpMenu.addAction(self.actionaboutv2rayshell)

        toolBar = QToolBar()
        self.actionV2rayStart = QAction(self.translate("bridgePanel", "Start"))
        self.actionV2rayStart.setIcon(self.style().standardIcon(
            getattr(QStyle, "SP_MediaPlay")))
        self.actionV2rayStop = QAction(self.translate("bridgePanel", "Stop"))
        self.actionV2rayStop.setIcon(self.style().standardIcon(
            getattr(QStyle, "SP_MediaStop")))
        toolBar.addAction(self.actionV2rayStart)
        toolBar.addAction(self.actionV2rayStop)
        self.addToolBar(toolBar)

        self.trayIconMenu = QMenu()
        self.v2rayshellTrayIcon.setContextMenu(self.trayIconMenu)

        self.trayIconMenushowhidePanel = QAction(
            self.translate("bridgePanel", "Show/Hide"))
        self.trayIconMenuclosePanel = QAction(
            self.translate("bridgePanel", "Quit"))

        self.trayIconMenu.addAction(self.trayIconMenushowhidePanel)
        self.trayIconMenu.addSeparator()
        self.trayIconMenu.addAction(self.trayIconMenuclosePanel)

        self.splitterBridge = QSplitter(Qt.Vertical)
        self.splitterBridge.addWidget(self.tableWidgetBridge)
        self.splitterBridge.addWidget(self.texteditBridge)

        self.setCentralWidget(self.splitterBridge)

        self.createBridgePanelSignals()

        self.onloadV2rayshellConfigFile(init=True)

        self.onv2raycoreStart()

        self.autocheckv2raycoreUpdate()

    def createBridgePanelSignals(self):
        self.actionNewV2rayConfigFile.triggered.connect(
            self.tableWidgetBridgeAddNewV2rayConfigFile)
        self.actionReloadV2rayshellConfigFile.triggered.connect(
            self.onloadV2rayshellConfigFile)
        self.actionSaveV2rayshellConfigFile.triggered.connect(
            self.onsaveV2rayshellConfigFile)
        self.actionopenV2rayshellPreferencesPanel.triggered.connect(
            self.createBridgepreferencesPanel)
        self.actionpopMenuAddV2rayConfigFile.triggered.connect(
            self.tableWidgetBridgeAddNewV2rayConfigFile)
        self.actionpopMenuEditV2rayConfigFile.triggered.connect(
            self.oncreatenauticalChartPanel)
        self.actionpopMenuDeleteRow.triggered.connect(
            self.tableWidgetBridgeDelete)
        self.actionpopMenuProxyCheckTimeLag.triggered.connect(
            self.onproxyserverTimeLagTest)
        self.actioncheckv2raycoreupdate.triggered.connect(
            self.onopenv2rayupdatePanel)
        self.actionv2rayshellBugreport.triggered.connect(self.bugReportPanel)
        self.actionQuitV2rayshellPanel.triggered.connect(self.close)
        self.actionV2rayStart.triggered.connect(self.onv2raycoreStart)
        self.actionV2rayStop.triggered.connect(self.onv2raycoreStop)
        self.actionaboutv2rayshell.triggered.connect(self.about)
        self.radioButtonGroup.buttonClicked.connect(self.onradioButtonClicked)
        self.tableWidgetBridge.cellDoubleClicked.connect(
            self.ontableWidgetBridgecellDoubleClicked)
        self.tableWidgetBridge.customContextMenuRequested.connect(
            self.ontableWidgetBridgeRightClicked)
        self.v2rayshellTrayIcon.activated.connect(self.restorebridgePanel)
        self.trayIconMenushowhidePanel.triggered.connect(
            self.onsystemTrayIconMenushowhidebridgePanel)
        self.trayIconMenuclosePanel.triggered.connect(self.close)
        self.proxyTryConnect.reconnectproxy.connect(self.swapNextConfigFile)
        self.start.connect(self.onupdateinstallFinishedstartNewV2raycore)
        self.stop.connect(self.onv2raycoreStop)
        self.checkTrayicon.timeout.connect(self.checkSystemTrayIconStatus)
        self.checkTrayicon.start(1000 * 60)

    def checkSystemTrayIconStatus(self):
        """
        maybe auto startup will missing trayicon
        """
        if not self.v2rayshellTrayIcon.isVisible():
            self.v2rayshellTrayIcon.show()
        else:
            self.checkTrayicon.disconnect()

    def setV2RayshellLanguage(self):
        self.trans = QTranslator()
        language = self.bridgetreasureChest.getLanguage()
        allLanguages = self.bridgetreasureChest.getAllLanguage()
        if language and allLanguages:
            if language in allLanguages:
                self.trans.load(allLanguages[language])
                self.app.installTranslator(self.trans)

    def autocheckv2raycoreUpdate(self):
        self.bridgeSingal = (self.start, self.stop)
        self.v2rayshellautoUpdate = updatePanel.autoCheckUpdate(
            bridgetreasureChest=self.bridgetreasureChest,
            bridgeSingal=self.bridgeSingal)

    def event(self, event):
        if (event.type() == QEvent.WindowStateChange and self.isMinimized()):
            self.setWindowFlags(self.windowFlags() & ~Qt.Tool)
            self.v2rayshellTrayIcon.show()
            return True
        else:
            return super(bridgePanel, self).event(event)

    def onsystemTrayIconMenushowhidebridgePanel(self):
        if self.isHidden():
            self.showNormal()
        elif self.isVisible():
            self.hide()

    def restorebridgePanel(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            if self.isVisible():
                self.hide()
            elif self.isHidden():
                self.showNormal()

    def close(self):
        super(bridgePanel, self).close()
        self.v2rayshellTrayIcon.hide()
        self.onv2raycoreStop()

    def closeEvent(self, event):
        self.close()
        event.accept()
        sys.exit(self.app.exec_())

    def onv2raycoreStop(self):
        if (self.runv2raycore):
            self.runv2raycore.stop.emit()
        try:
            # force stop checking proxy time lag
            del self.autoCheckTimer
        except Exception:
            pass

    def onupdateinstallFinishedstartNewV2raycore(self):
        self.onloadV2rayshellConfigFile(init=True)
        self.onv2raycoreStart()

    def onv2raycoreStart(self):
        currentActiveRow = False
        rowCount = self.tableWidgetBridge.rowCount()
        for i in range(rowCount):
            currentActiveRow = self.tableWidgetBridge.cellWidget(i, 0)
            if currentActiveRow.isChecked():
                self.texteditBridge.clear()
                option = self.tableWidgetBridge.item(i, 2)
                if option:
                    option = '-config="{}" -format=json'.format(option.text())
                else:
                    option = ""
                filePath = self.bridgetreasureChest.getV2raycoreFilePath()
                if (not filePath):
                    filePath = "v2ray"
                self.runv2raycore = runV2raycore.runV2raycore(
                    outputTextEdit=self.texteditBridge,
                    v2rayPath=filePath,
                    v2rayOption=option,
                    bridgetreasureChest=self.bridgetreasureChest)

                self.runv2raycore.start.emit()
                self.autocheckProxy(i)
                break
            else:
                del currentActiveRow

    def autocheckProxy(self, row):
        # TODO
        """
        Frequent access to the server may cause suspicion of DDOS attacks, 
        which may put the VPS server at risk.
        """
        enableAutoCheck = self.bridgetreasureChest.getConnectionEnable()

        if (enableAutoCheck):
            self.proxyStatus = proxyTest.proxyStatus()
            self.autoCheckTimer = QTimer()
            invervalTime = self.bridgetreasureChest.getConnectioninterval()
            timeout = self.bridgetreasureChest.getConnectiontimeout()
            proxyAddress = self.getProxyAddressFromTableWidget(row)

            if proxyAddress:
                self.autoCheckTimer.timeout.connect(
                    lambda: self.startCheckProxy(timeout=timeout,
                                                 proxyAddress=proxyAddress,
                                                 row=row,
                                                 proxyStatus=self.proxyStatus))

                self.bridgetreasureChest.setProxy(proxyAddress)

                if v2rayshellDebug: self.autoCheckTimer.start(6000)
                else: self.autoCheckTimer.start(1000 * invervalTime)

                self.autoCheckTimer.singleShot(
                    100,
                    lambda: self.startCheckProxy(timeout=timeout,
                                                 proxyAddress=proxyAddress,
                                                 row=row,
                                                 proxyStatus=self.proxyStatus))

    def setTableWidgetTimelag(self, row, proxyStatus):
        newlabelTimelag = self.setlabelTimeLagColor(proxyStatus)
        oldlabelTimelag = self.tableWidgetBridge.cellWidget(row, 4)
        del oldlabelTimelag
        self.tableWidgetBridge.setCellWidget(row, 4, newlabelTimelag)
        self.tableWidgetBridge.resizeColumnsToContents()

    def startCheckProxy(self, timeout, proxyAddress, row, proxyStatus):
        if (proxyAddress):
            proxyStatus.clear()
            proxyStatus.signal.connect(
                lambda: self.setTableWidgetTimelag(row, proxyStatus))

            self.proxy = proxyTest.proxyTest(proxyprotocol=proxyAddress[0],
                                             proxyhostname=proxyAddress[1],
                                             proxyhostport=int(
                                                 proxyAddress[2]),
                                             getproxyStatus=proxyStatus,
                                             timeout=int(timeout))

    def setlabelTimeLagColor(self, proxyStatus=False):
        labelTimeLag = QLabel()
        if (proxyStatus and not proxyStatus.getProxyError()):
            labelFont = QFont()
            labelFont.setPointSize(12)
            labelFont.setBold(True)
            labelTimeLag.setFont(labelFont)
            forestGreen = "QLabel {color: rgb(34, 139, 34)}"
            darkOrange = "QLabel {color: rgb(255, 140, 0)}"
            red = "QLabel {color: rgb(194,24,7)}"

            if (proxyStatus.getElapsedTime() < 260):
                labelTimeLag.setStyleSheet(forestGreen)
            elif (proxyStatus.getElapsedTime() > 420):
                labelTimeLag.setStyleSheet(red)
            else:
                labelTimeLag.setStyleSheet(darkOrange)
            labelTimeLag.setText("{} ms".format(
                str(proxyStatus.getElapsedTime())))

            return labelTimeLag

        elif (proxyStatus and proxyStatus.getProxyError()):
            labelTimeLag.setText("{}:{}".format(
                proxyStatus.getProxyErrorString(),
                proxyStatus.getProxyErrorCode()))

            self.proxyTryConnect.trytimesDecrease()
            return labelTimeLag

    def swapNextConfigFile(self):
        self.onv2raycoreStop()
        try:
            self.trytimes = self.bridgetreasureChest.getConnectiontrytimes()
            self.interval = self.bridgetreasureChest.getConnectioninterval()
            self.proxyTryConnect.stopperiodicCheckProxyStatus()
            if v2rayshellDebug: self.proxyTryConnect.setresetTime(6, 3)
            else:
                self.proxyTryConnect.setresetTime(self.interval, self.trytimes)
        except Exception:
            self.proxyTryConnect.setresetTime(60, 3)

        if (self.bridgetreasureChest.connectionisSwitch()):
            # swap next row's configFile
            buttons = self.radioButtonGroup.buttons()
            buttonsNumber = len(buttons)
            activeRow = False
            for i in range(buttonsNumber):
                if buttons[i].isChecked():
                    buttons[i].setChecked(False)
                    if i == buttonsNumber - 1:
                        buttons[0].setChecked(True)
                        activeRow = 0
                        break
                    else:
                        buttons[i + 1].setChecked(True)
                        activeRow = i + 1
                    break

            # change the row icons
            for i in range(buttonsNumber):
                widget = self.tableWidgetBridge.cellWidget(i, 0)
                if (widget):
                    widget.setIcon(self.iconStop)
                    widget.setIconSize(self.__iconSize)
                    if (widget.isChecked()):
                        pass
            widget = self.tableWidgetBridge.cellWidget(activeRow, 0)
            if widget:
                widget.setIcon(self.iconStart)
                widget.setIconSize(self.__iconSize)

        self.onv2raycoreStart()

    def onopenv2rayupdatePanel(self):
        currentActiveRow = False
        rowCount = self.tableWidgetBridge.rowCount()
        currentRow = False
        for i in range(rowCount):
            currentActiveRow = self.tableWidgetBridge.cellWidget(i, 0)
            if currentActiveRow.isChecked():
                currentRow = i
                break

        if (currentActiveRow and currentActiveRow.isChecked()):
            proxy = self.tableWidgetBridge.item(currentRow, 3)
            proxy = proxy.text().split(":")
            protocol = QNetworkProxy.Socks5Proxy
            if (proxy[0] == "socks"):
                protocol = QNetworkProxy.Socks5Proxy
            elif (proxy[0] == "http"):
                protocol = QNetworkProxy.HttpProxy
            hostName = proxy[1]
            hostPort = int(proxy[2])

            v2rayAPI = updatePanel.v2rayAPI()
            self.createupdatePanel = updatePanel.v2rayUpdatePanel(
                v2rayapi=v2rayAPI,
                protocol=protocol,
                proxyhostName=hostName,
                port=hostPort,
                bridgetreasureChest=self.bridgetreasureChest)
            self.createupdatePanel.createPanel()
            self.createupdatePanel.setAttribute(Qt.WA_DeleteOnClose)
            self.createupdatePanel.setWindowIcon(self.iconStart)
            self.createupdatePanel.setWindowTitle(
                self.translate("bridgePanel", "Check V2Ray-core update"))
            self.createupdatePanel.resize(QSize(1024, 320))
            self.createupdatePanel.move(
                QApplication.desktop().screen().rect().center() -
                self.createupdatePanel.rect().center())
            self.createupdatePanel.show()
            self.createupdatePanel.exec_()
        else:
            self.noPoxyServerRunning()

    def ontableWidgetBridgeRightClicked(self, pos):
        index = self.tableWidgetBridge.indexAt(pos)
        clickedRow.rightClickedRow = index.row()
        clickedRow.mousePos = QCursor().pos()
        self.popMenu.move(QCursor().pos())
        self.popMenu.show()

    def ontableWidgetBridgecellDoubleClicked(self, row, column):
        if (column == 1):
            hostName, ok = QInputDialog.getText(
                self, self.translate("bridgePanel", 'Host Name'),
                self.translate("bridgePanel", 'Enter Host Name:'))
            if (ok):
                self.tableWidgetBridge.setItem(row, column,
                                               QTableWidgetItem(str(hostName)))
                self.tableWidgetBridge.resizeColumnsToContents()
        elif (column == 2):
            fileNames = self.onopenV2rayConfigJSONFile()
            if (fileNames):
                for fileName in fileNames:
                    self.tableWidgetBridge.setItem(
                        row, column, QTableWidgetItem(str(fileName)))
                    self.tableWidgetBridge.resizeColumnsToContents()
        elif (column == 3):
            self.onproxyserverTimeLagTest()
        elif (column == 4):
            self.onproxyserverTimeLagTest()

    def getProxyAddressFromTableWidget(self, row):
        proxy = self.tableWidgetBridge.item(row, 3)
        try:
            proxy = proxy.text().split(":")
        except Exception:
            return False

        if (proxy[0] == "socks"):
            proxy[0] = QNetworkProxy.Socks5Proxy
        elif (proxy[0] == "http"):
            proxy[0] = QNetworkProxy.HttpProxy

        if len(proxy) < 3: return False
        else: return proxy

    def onproxyserverTimeLagTest(self):
        proxyStatus = proxyTest.proxyStatus()
        """
        right clicked mouse button pop a menu check proxy
        """
        currentActiveRow = False
        rowCount = self.tableWidgetBridge.rowCount()
        currentRow = False
        for i in range(rowCount):
            currentActiveRow = self.tableWidgetBridge.cellWidget(i, 0)
            if currentActiveRow.isChecked():
                currentRow = i
                break
        if (currentActiveRow and currentActiveRow.isChecked()):
            proxy = self.getProxyAddressFromTableWidget(currentRow)
            if not proxy: return
            protocol = proxy[0]
            hostName = proxy[1]
            hostPort = int(proxy[2])

            proxy = proxyTest.proxyTestPanel(proxyhostname=hostName,
                                             proxyhostport=hostPort,
                                             proxyprotocol=protocol,
                                             getproxyStatus=proxyStatus)
            proxy.createproxyTestPanel()
            proxy.setAttribute(Qt.WA_DeleteOnClose)
            proxy.setWindowTitle(
                self.translate("bridgePanel", "Proxy Time Lag Check"))
            proxy.setWindowIcon(self.iconStart)
            proxy.resize(QSize(600, 480))
            proxy.move(QApplication.desktop().screen().rect().center() -
                       proxy.rect().center())
            proxy.show()
            proxy.exec_()
        else:
            self.noPoxyServerRunning()

    def noPoxyServerRunning(self):
        warningPanel = QDialog()
        warningPanel.setAttribute(Qt.WA_DeleteOnClose)
        warningPanel.setWindowTitle(self.translate("bridgePanel",
                                                   "Warnnig..."))
        warningPanel.setWindowIcon(self.iconStop)
        labelMsg = QLabel(
            self.translate(
                "bridgePanel",
                "There no any server is running, \n[File]->[Add V2Ray-core Config File] (Ctrl+n) add a config.json."
            ))
        vbox = QVBoxLayout()
        vbox.addWidget(labelMsg)
        warningPanel.setLayout(vbox)
        warningPanel.move(QApplication.desktop().screen().rect().center() -
                          warningPanel.rect().center())
        warningPanel.open()
        warningPanel.exec_()

    def getProxyAddressFromJSONFile(self, filePath):
        from bridgehouse.editMap.port import treasureChest, openV2rayJSONFile
        tempTreasureChest = treasureChest.treasureChest()
        openV2rayJSONFile.openV2rayJSONFile(
            filePath, tempTreasureChest, disableLog=True).initboundJSONData()
        inbound = tempTreasureChest.getInbound()
        if (inbound):
            try:
                protocol = inbound["protocol"]
                ipAddress = inbound["listen"]
                port = inbound["port"]
                if (protocol == "socks" or protocol == "http"):
                    return "{}:{}:{}".format(protocol, ipAddress, port)
                else:
                    return False
            except Exception:
                return False
        else:
            return False

    def onradioButtonClicked(self, e):
        rowCount = self.tableWidgetBridge.rowCount()
        # radioButtonClickedRow = 0
        for i in range(rowCount):
            widget = self.tableWidgetBridge.cellWidget(i, 0)
            if (widget):
                widget.setIcon(self.iconStop)
                widget.setIconSize(self.__iconSize)
                if (widget.isChecked()):
                    # radioButtonClickedRow = i
                    pass
        e.setIcon(self.iconStart)
        e.setIconSize(self.__iconSize)

    def onloadV2rayshellConfigFile(self, init=False):
        """
        when the script first start, and auto load v2ray-shell config file.
        """
        if init:
            self.settingv2rayshelltableWidget()
        else:

            def openV2rayshellConfigFile():
                options = QFileDialog.Options()
                filePath, _ = QFileDialog.getOpenFileName(
                    self,
                    self.translate("bridgePanel",
                                   "Open V2Ray-sehll Config File"),
                    "",
                    "V2Ray-shell config file (*.v2rayshell)",
                    options=options)
                if (filePath):
                    self.bridgetreasureChest.clear()
                    self.tableWidgetBridge.setRowCount(0)
                    self.bridgetreasureChest.initbridgeJSONData(
                        v2rayshellConfigFileName=filePath)
                    self.settingv2rayshelltableWidget()

            openV2rayshellConfigFile()

    def onopenV2rayConfigJSONFile(self):
        """
        open a new v2ray config file to tabelWidget
        """
        options = QFileDialog.Options()
        filePaths, _ = QFileDialog.getOpenFileNames(
            self,
            self.translate("bridgePanel", "Open V2Ray-core Config File"),
            "",
            """
                                                  V2Ray config file (*.json);;
                                                  All File (*);;
                                                  """,
            options=options)

        if (filePaths):
            return filePaths
        else:
            return False

    def createBridgepreferencesPanel(self):
        self.createpreferencesPanel = bridgePreference.bridgepreferencesPanel(
            self.bridgetreasureChest)
        self.createpreferencesPanel.setAttribute(Qt.WA_DeleteOnClose)
        self.createpreferencesPanel.createpreferencesPanel()
        self.createpreferencesPanel.setWindowIcon(self.iconStart)
        self.createpreferencesPanel.move(
            QApplication.desktop().screen().rect().center() -
            self.createpreferencesPanel.rect().center())
        self.createpreferencesPanel.open()
        self.createpreferencesPanel.exec_()

    def settingv2rayshelltableWidget(self):
        v2rayConfigFiles = self.bridgetreasureChest.getV2raycoreconfigFiles()
        if not v2rayConfigFiles: return
        v2rayConfigFilesNumber = len(v2rayConfigFiles)
        if (v2rayConfigFilesNumber):
            self.tableWidgetBridge.setRowCount(0)
            for i in range(v2rayConfigFilesNumber):
                try:
                    enable = bool(v2rayConfigFiles[i]["enable"])
                    hostName = str(v2rayConfigFiles[i]["hostName"])
                    configFileName = str(v2rayConfigFiles[i]["configFileName"])
                except Exception:
                    pass

                radioButtonStopStart = QRadioButton(self)
                radioButtonStopStart.setIcon(
                    self.iconStop if not enable else self.iconStart)
                radioButtonStopStart.setChecked(True if enable else False)
                radioButtonStopStart.setIconSize(self.__iconSize)
                self.radioButtonGroup.addButton(radioButtonStopStart)
                self.tableWidgetBridge.setRowCount(i + 1)
                self.tableWidgetBridge.setCellWidget(i, 0,
                                                     radioButtonStopStart)
                self.tableWidgetBridge.setItem(i, 1,
                                               QTableWidgetItem(hostName))
                self.tableWidgetBridge.setItem(
                    i, 2, QTableWidgetItem(configFileName))
                self.tableWidgetBridge.setItem(
                    i, 3,
                    QTableWidgetItem(
                        self.getProxyAddressFromJSONFile(configFileName)))
                self.tableWidgetBridge.resizeColumnsToContents()
                #self.tableWidgetBridge.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

    def onsaveV2rayshellConfigFile(self):
        self.bridgetreasureChest.clearconfigFiles()
        rowCount = self.tableWidgetBridge.rowCount()
        for i in range(rowCount):
            enable = self.tableWidgetBridge.cellWidget(i, 0)
            if enable and enable.isChecked():
                enable = True
            else:
                enable = False

            hostName = self.tableWidgetBridge.item(i, 1)
            if hostName:
                hostName = hostName.text()
            else:
                hostName = ""

            config = self.tableWidgetBridge.item(i, 2)
            if config:
                config = config.text()
            else:
                config = ""
            self.bridgetreasureChest.setV2raycoreconfigFiles(
                enable, hostName, configFileName=config)
        self.bridgetreasureChest.save.emit()

    def oncreatenauticalChartPanel(self):
        v2rayConfigFileName = self.tableWidgetBridge.item(
            clickedRow.rightClickedRow, 2)
        if (v2rayConfigFileName):
            nc = nauticalChartPanel.nauticalChartPanel(
                v2rayConfigFileName.text())
            nc.setAttribute(Qt.WA_DeleteOnClose)
            nc.createPanel()
            nc.setWindowTitle(
                self.translate("bridgePanel", "V2Ray config file edit"))
            nc.setWindowIcon(self.iconStart)
            nc.setGeometry(0, 0, 1024, 768)
            # move widget to center
            nc.move(QApplication.desktop().screen().rect().center() -
                    nc.rect().center())
            nc.show()
            nc.exec_()

    def tableWidgetBridgeAddNewV2rayConfigFile(self):
        configFileNames = self.onopenV2rayConfigJSONFile()
        if (configFileNames):
            for configFileName in configFileNames:
                rowCount = self.tableWidgetBridge.rowCount()
                radioButtonStopStart = QRadioButton(self)
                radioButtonStopStart.setIcon(self.iconStop)
                radioButtonStopStart.setIconSize(self.__iconSize)
                self.radioButtonGroup.addButton(radioButtonStopStart)

                self.tableWidgetBridge.setRowCount(rowCount + 1)
                self.tableWidgetBridge.setCellWidget(rowCount, 0,
                                                     radioButtonStopStart)
                self.tableWidgetBridge.setItem(rowCount, 1,
                                               QTableWidgetItem(""))
                self.tableWidgetBridge.setItem(
                    rowCount, 2, QTableWidgetItem(configFileName))
                self.tableWidgetBridge.setItem(
                    rowCount, 3,
                    QTableWidgetItem(
                        self.getProxyAddressFromJSONFile(configFileName)))
                self.tableWidgetBridge.resizeColumnsToContents()
        else:
            pass

    def tableWidgetBridgeDelete(self):
        self.tableWidgetBridge.removeRow(clickedRow.rightClickedRow)

    def validateV2rayJSONFile(self, JSONData):
        """
        simply validate a V2Ray json file.
        """
        try:
            JSONData["inbound"]
            JSONData["outbound"]
        except KeyError:
            return False
        else:
            return True

    def about(self):
        NineteenEightySeven = QLabel(
            self.translate(
                "bridgePanel",
                """Across the Great Wall, we can reach every corner in the world."""
            ))  ### Crossing the Great Wall to Join the World
        Timeless = QLabel(
            self.translate(
                "bridgePanel",
                """You weren't thinking about that when you were creating it.\nBecause if you did? You never would have gone through with it."""
            ))
        DwayneRichardHipp = QLabel(
            self.translate(
                "bridgePanel",
                """May you do good and not evil.\nMay you find forgiveness for yourself and forgive others.\nMay you share freely, never taking more than you give."""
            ))
        vbox = QVBoxLayout()
        vbox.addWidget(NineteenEightySeven)
        vbox.addWidget(Timeless)
        vbox.addWidget(DwayneRichardHipp)

        dialogAbout = QDialog()
        dialogAbout.setAttribute(Qt.WA_DeleteOnClose)
        dialogAbout.setWindowTitle(
            self.translate("bridgePanel", "About V2Ray-shell"))
        dialogAbout.setWindowIcon(self.iconStart)
        dialogAbout.move(QApplication.desktop().screen().rect().center() -
                         dialogAbout.rect().center())
        dialogAbout.setLayout(vbox)
        dialogAbout.open()
        dialogAbout.exec_()

    def bugReportPanel(self):
        self.bugReport = bugReport.bugReport()
        self.bugReport.setAttribute(Qt.WA_DeleteOnClose)
        self.bugReport.setWindowTitle(
            self.translate("bridgePanel", "Bug Report"))
        self.bugReport.setWindowIcon(self.iconStart)
        self.bugReport.createPanel()
        self.bugReport.show()
        self.bugReport.setGeometry(250, 150, 1024, 768)
Exemplo n.º 4
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupTrayicon()
        self.setupVariables()
        self.setupUi()
        self.setupConnections()
        self.show()

    def setupVariables(self):
        settings = QSettings()
        self.workEndTime = QTime(
            int(settings.value(workHoursKey, 0)),
            int(settings.value(workMinutesKey, 25)),
            int(settings.value(workSecondsKey, 0)),
        )
        self.restEndTime = QTime(
            int(settings.value(restHoursKey, 0)),
            int(settings.value(restMinutesKey, 5)),
            int(settings.value(restSecondsKey, 0)),
        )
        self.timeFormat = "hh:mm:ss"
        self.time = QTime(0, 0, 0, 0)
        self.workTime = QTime(0, 0, 0, 0)
        self.restTime = QTime(0, 0, 0, 0)
        self.totalTime = QTime(0, 0, 0, 0)
        self.currentMode = Mode.work
        self.maxRepetitions = -1
        self.currentRepetitions = 0

    def setupConnections(self):
        """ Create button connections """
        self.startButton.clicked.connect(self.startTimer)
        self.startButton.clicked.connect(
            lambda: self.startButton.setDisabled(True))
        self.startButton.clicked.connect(
            lambda: self.pauseButton.setDisabled(False))
        self.startButton.clicked.connect(
            lambda: self.resetButton.setDisabled(False))
        self.pauseButton.clicked.connect(self.pauseTimer)
        self.pauseButton.clicked.connect(
            lambda: self.startButton.setDisabled(False))
        self.pauseButton.clicked.connect(
            lambda: self.pauseButton.setDisabled(True))
        self.pauseButton.clicked.connect(
            lambda: self.resetButton.setDisabled(False))
        self.pauseButton.clicked.connect(
            lambda: self.startButton.setText("continue"))
        self.resetButton.clicked.connect(self.resetTimer)
        self.resetButton.clicked.connect(
            lambda: self.startButton.setDisabled(False))
        self.resetButton.clicked.connect(
            lambda: self.pauseButton.setDisabled(True))
        self.resetButton.clicked.connect(
            lambda: self.resetButton.setDisabled(True))
        self.resetButton.clicked.connect(
            lambda: self.startButton.setText("start"))
        self.acceptTaskButton.pressed.connect(self.insertTask)
        self.deleteTaskButton.pressed.connect(self.deleteTask)
        """ Create spinbox  connections """
        self.workHoursSpinBox.valueChanged.connect(self.updateWorkEndTime)
        self.workMinutesSpinBox.valueChanged.connect(self.updateWorkEndTime)
        self.workSecondsSpinBox.valueChanged.connect(self.updateWorkEndTime)
        self.restHoursSpinBox.valueChanged.connect(self.updateRestEndTime)
        self.restMinutesSpinBox.valueChanged.connect(self.updateRestEndTime)
        self.restSecondsSpinBox.valueChanged.connect(self.updateRestEndTime)
        self.repetitionsSpinBox.valueChanged.connect(self.updateMaxRepetitions)
        """ Create combobox connections """
        self.modeComboBox.currentTextChanged.connect(self.updateCurrentMode)
        """ Create tablewidget connections """
        self.tasksTableWidget.cellDoubleClicked.connect(
            self.markTaskAsFinished)

    def setupUi(self):
        self.size_policy = sizePolicy = QSizePolicy(QSizePolicy.Expanding,
                                                    QSizePolicy.Expanding)
        """ Create tabwidget """
        self.tabWidget = QTabWidget()
        """ Create tab widgets """
        timerWidget = self.setupTimerTab()
        tasksWidget = self.setupTasksTab()
        statisticsWidget = self.setupStatisticsTab()
        """ add tab widgets to tabwidget"""
        self.timerTab = self.tabWidget.addTab(timerWidget, makeIcon("timer"),
                                              "Timer")
        self.tasksTab = self.tabWidget.addTab(tasksWidget, makeIcon("tasks"),
                                              "Tasks")
        self.statisticsTab = self.tabWidget.addTab(statisticsWidget,
                                                   makeIcon("statistics"),
                                                   "Statistics")
        """ Set mainwindows central widget """
        self.setCentralWidget(self.tabWidget)

    def setupTimerTab(self):
        settings = QSettings()
        self.timerContainer = QWidget(self)
        self.timerContainerLayout = QVBoxLayout(self.timerContainer)
        self.timerContainer.setLayout(self.timerContainerLayout)
        """ Create work groupbox"""
        self.workGroupBox = QGroupBox("Work")
        self.workGroupBoxLayout = QHBoxLayout(self.workGroupBox)
        self.workGroupBox.setLayout(self.workGroupBoxLayout)
        self.workHoursSpinBox = QSpinBox(
            minimum=0,
            maximum=24,
            value=int(settings.value(workHoursKey, 0)),
            suffix="h",
            sizePolicy=self.size_policy,
        )
        self.workMinutesSpinBox = QSpinBox(
            minimum=0,
            maximum=60,
            value=int(settings.value(workMinutesKey, 25)),
            suffix="m",
            sizePolicy=self.size_policy,
        )
        self.workSecondsSpinBox = QSpinBox(
            minimum=0,
            maximum=60,
            value=int(settings.value(workSecondsKey, 0)),
            suffix="s",
            sizePolicy=self.size_policy,
        )
        """ Create rest groupbox"""
        self.restGroupBox = QGroupBox("Rest")
        self.restGroupBoxLayout = QHBoxLayout(self.restGroupBox)
        self.restGroupBox.setLayout(self.restGroupBoxLayout)
        self.restHoursSpinBox = QSpinBox(
            minimum=0,
            maximum=24,
            value=int(settings.value(restHoursKey, 0)),
            suffix="h",
            sizePolicy=self.size_policy,
        )
        self.restMinutesSpinBox = QSpinBox(
            minimum=0,
            maximum=60,
            value=int(settings.value(restMinutesKey, 5)),
            suffix="m",
            sizePolicy=self.size_policy,
        )
        self.restSecondsSpinBox = QSpinBox(
            minimum=0,
            maximum=60,
            value=int(settings.value(restSecondsKey, 0)),
            suffix="s",
            sizePolicy=self.size_policy,
        )
        self.restGroupBoxLayout.addWidget(self.restHoursSpinBox)
        self.restGroupBoxLayout.addWidget(self.restMinutesSpinBox)
        self.restGroupBoxLayout.addWidget(self.restSecondsSpinBox)
        """ Create other groupbox"""
        self.otherGroupBox = QGroupBox("Other")
        self.otherGroupBoxLayout = QHBoxLayout(self.otherGroupBox)
        self.otherGroupBox.setLayout(self.otherGroupBoxLayout)
        self.repetitionsLabel = QLabel("Repetitions")
        self.repetitionsSpinBox = QSpinBox(
            minimum=0,
            maximum=10000,
            value=0,
            sizePolicy=self.size_policy,
            specialValueText="∞",
        )
        self.modeLabel = QLabel("Mode")
        self.modeComboBox = QComboBox(sizePolicy=self.size_policy)
        self.modeComboBox.addItems(["work", "rest"])
        self.otherGroupBoxLayout.addWidget(self.repetitionsLabel)
        self.otherGroupBoxLayout.addWidget(self.repetitionsSpinBox)
        self.otherGroupBoxLayout.addWidget(self.modeLabel)
        self.otherGroupBoxLayout.addWidget(self.modeComboBox)
        """ Create timer groupbox"""
        self.lcdDisplayGroupBox = QGroupBox("Time")
        self.lcdDisplayGroupBoxLayout = QHBoxLayout(self.lcdDisplayGroupBox)
        self.lcdDisplayGroupBox.setLayout(self.lcdDisplayGroupBoxLayout)
        self.timeDisplay = QLCDNumber(8, sizePolicy=self.size_policy)
        self.timeDisplay.setFixedHeight(100)
        self.timeDisplay.display("00:00:00")
        self.lcdDisplayGroupBoxLayout.addWidget(self.timeDisplay)
        """ Create pause, start and reset buttons"""
        self.buttonContainer = QWidget()
        self.buttonContainerLayout = QHBoxLayout(self.buttonContainer)
        self.buttonContainer.setLayout(self.buttonContainerLayout)
        self.startButton = self.makeButton("start", disabled=False)
        self.resetButton = self.makeButton("reset")
        self.pauseButton = self.makeButton("pause")
        """ Add widgets to container """
        self.workGroupBoxLayout.addWidget(self.workHoursSpinBox)
        self.workGroupBoxLayout.addWidget(self.workMinutesSpinBox)
        self.workGroupBoxLayout.addWidget(self.workSecondsSpinBox)
        self.timerContainerLayout.addWidget(self.workGroupBox)
        self.timerContainerLayout.addWidget(self.restGroupBox)
        self.timerContainerLayout.addWidget(self.otherGroupBox)
        self.timerContainerLayout.addWidget(self.lcdDisplayGroupBox)
        self.buttonContainerLayout.addWidget(self.pauseButton)
        self.buttonContainerLayout.addWidget(self.startButton)
        self.buttonContainerLayout.addWidget(self.resetButton)
        self.timerContainerLayout.addWidget(self.buttonContainer)
        return self.timerContainer

    def setupTasksTab(self):
        settings = QSettings()
        """ Create vertical tasks container """
        self.tasksWidget = QWidget(self.tabWidget)
        self.tasksWidgetLayout = QVBoxLayout(self.tasksWidget)
        self.tasksWidget.setLayout(self.tasksWidgetLayout)
        """ Create horizontal input container """
        self.inputContainer = QWidget()
        self.inputContainer.setFixedHeight(50)
        self.inputContainerLayout = QHBoxLayout(self.inputContainer)
        self.inputContainerLayout.setContentsMargins(0, 0, 0, 0)
        self.inputContainer.setLayout(self.inputContainerLayout)
        """ Create text edit """
        self.taskTextEdit = QTextEdit(
            placeholderText="Describe your task briefly.",
            undoRedoEnabled=True)
        """ Create vertical buttons container """
        self.inputButtonContainer = QWidget()
        self.inputButtonContainerLayout = QVBoxLayout(
            self.inputButtonContainer)
        self.inputButtonContainerLayout.setContentsMargins(0, 0, 0, 0)
        self.inputButtonContainer.setLayout(self.inputButtonContainerLayout)
        """ Create buttons """
        self.acceptTaskButton = QToolButton(icon=makeIcon("check"))
        self.deleteTaskButton = QToolButton(icon=makeIcon("trash"))
        """ Create tasks tablewidget """
        self.tasksTableWidget = QTableWidget(0, 1)
        self.tasksTableWidget.setHorizontalHeaderLabels(["Tasks"])
        self.tasksTableWidget.horizontalHeader().setStretchLastSection(True)
        self.tasksTableWidget.verticalHeader().setVisible(False)
        self.tasksTableWidget.setWordWrap(True)
        self.tasksTableWidget.setTextElideMode(Qt.ElideNone)
        self.tasksTableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tasksTableWidget.setSelectionMode(
            QAbstractItemView.SingleSelection)
        self.insertTasks(*settings.value(tasksKey, []))
        """ Add widgets to container widgets """
        self.inputButtonContainerLayout.addWidget(self.acceptTaskButton)
        self.inputButtonContainerLayout.addWidget(self.deleteTaskButton)
        self.inputContainerLayout.addWidget(self.taskTextEdit)
        self.inputContainerLayout.addWidget(self.inputButtonContainer)
        self.tasksWidgetLayout.addWidget(self.inputContainer)
        self.tasksWidgetLayout.addWidget(self.tasksTableWidget)
        return self.tasksWidget

    def setupStatisticsTab(self):
        """ Create statistics container """
        self.statisticsContainer = QWidget()
        self.statisticsContainerLayout = QVBoxLayout(self.statisticsContainer)
        self.statisticsContainer.setLayout(self.statisticsContainerLayout)
        """ Create work time groupbox """
        self.statisticsWorkTimeGroupBox = QGroupBox("Work Time")
        self.statisticsWorkTimeGroupBoxLayout = QHBoxLayout()
        self.statisticsWorkTimeGroupBox.setLayout(
            self.statisticsWorkTimeGroupBoxLayout)
        self.statisticsWorkTimeDisplay = QLCDNumber(8)
        self.statisticsWorkTimeDisplay.display("00:00:00")
        self.statisticsWorkTimeGroupBoxLayout.addWidget(
            self.statisticsWorkTimeDisplay)
        """ Create rest time groupbox """
        self.statisticsRestTimeGroupBox = QGroupBox("Rest Time")
        self.statisticsRestTimeGroupBoxLayout = QHBoxLayout()
        self.statisticsRestTimeGroupBox.setLayout(
            self.statisticsRestTimeGroupBoxLayout)
        self.statisticsRestTimeDisplay = QLCDNumber(8)
        self.statisticsRestTimeDisplay.display("00:00:00")
        self.statisticsRestTimeGroupBoxLayout.addWidget(
            self.statisticsRestTimeDisplay)
        """ Create total time groupbox """
        self.statisticsTotalTimeGroupBox = QGroupBox("Total Time")
        self.statisticsTotalTimeGroupBoxLayout = QHBoxLayout()
        self.statisticsTotalTimeGroupBox.setLayout(
            self.statisticsTotalTimeGroupBoxLayout)
        self.statisticsTotalTimeDisplay = QLCDNumber(8)
        self.statisticsTotalTimeDisplay.display("00:00:00")
        self.statisticsTotalTimeGroupBoxLayout.addWidget(
            self.statisticsTotalTimeDisplay)
        """ Add widgets to container """
        self.statisticsContainerLayout.addWidget(
            self.statisticsTotalTimeGroupBox)
        self.statisticsContainerLayout.addWidget(
            self.statisticsWorkTimeGroupBox)
        self.statisticsContainerLayout.addWidget(
            self.statisticsRestTimeGroupBox)
        return self.statisticsContainer

    def setupTrayicon(self):
        self.trayIcon = QSystemTrayIcon(makeIcon("tomato"))
        self.trayIcon.setContextMenu(QMenu())
        self.quitAction = self.trayIcon.contextMenu().addAction(
            makeIcon("exit"), "Quit", self.exit)
        self.quitAction.triggered.connect(self.exit)
        self.trayIcon.activated.connect(self.onActivate)
        self.trayIcon.show()

    def leaveEvent(self, event):
        super(MainWindow, self).leaveEvent(event)
        self.tasksTableWidget.clearSelection()

    def closeEvent(self, event):
        super(MainWindow, self).closeEvent(event)
        settings = QSettings()
        settings.setValue(workHoursKey, self.workHoursSpinBox.value())
        settings.setValue(
            workMinutesKey,
            self.workMinutesSpinBox.value(),
        )
        settings.setValue(
            workSecondsKey,
            self.workSecondsSpinBox.value(),
        )
        settings.setValue(restHoursKey, self.restHoursSpinBox.value())
        settings.setValue(
            restMinutesKey,
            self.restMinutesSpinBox.value(),
        )
        settings.setValue(
            restSecondsKey,
            self.restSecondsSpinBox.value(),
        )

        tasks = []
        for i in range(self.tasksTableWidget.rowCount()):
            item = self.tasksTableWidget.item(i, 0)
            if not item.font().strikeOut():
                tasks.append(item.text())
        settings.setValue(tasksKey, tasks)

    def startTimer(self):
        try:
            if not self.timer.isActive():
                self.createTimer()
        except:
            self.createTimer()

    def createTimer(self):
        self.timer = QTimer()
        self.timer.timeout.connect(self.updateTime)
        self.timer.timeout.connect(self.maybeChangeMode)
        self.timer.setInterval(1000)
        self.timer.setSingleShot(False)
        self.timer.start()

    def pauseTimer(self):
        try:
            self.timer.stop()
            self.timer.disconnect()
        except:
            pass

    def resetTimer(self):
        try:
            self.pauseTimer()
            self.time = QTime(0, 0, 0, 0)
            self.displayTime()
        except:
            pass

    def maybeStartTimer(self):
        if self.currentRepetitions != self.maxRepetitions:
            self.startTimer()
            started = True
        else:
            self.currentRepetitions = 0
            started = False
        return started

    def updateWorkEndTime(self):
        self.workEndTime = QTime(
            self.workHoursSpinBox.value(),
            self.workMinutesSpinBox.value(),
            self.workSecondsSpinBox.value(),
        )

    def updateRestEndTime(self):
        self.restEndTime = QTime(
            self.restHoursSpinBox.value(),
            self.restMinutesSpinBox.value(),
            self.restSecondsSpinBox.value(),
        )

    def updateCurrentMode(self, mode: str):
        self.currentMode = Mode.work if mode == "work" else Mode.rest

    def updateTime(self):
        self.time = self.time.addSecs(1)
        self.totalTime = self.totalTime.addSecs(1)
        if self.modeComboBox.currentText() == "work":
            self.workTime = self.workTime.addSecs(1)
        else:
            self.restTime = self.restTime.addSecs(1)
        self.displayTime()

    def updateMaxRepetitions(self, value):
        if value == 0:
            self.currentRepetitions = 0
            self.maxRepetitions = -1
        else:
            self.maxRepetitions = 2 * value

    def maybeChangeMode(self):
        if self.currentMode is Mode.work and self.time >= self.workEndTime:
            self.resetTimer()
            self.modeComboBox.setCurrentIndex(1)
            self.incrementCurrentRepetitions()
            started = self.maybeStartTimer()
            self.showWindowMessage(
                Status.workFinished if started else Status.repetitionsReached)
        elif self.currentMode is Mode.rest and self.time >= self.restEndTime:
            self.resetTimer()
            self.modeComboBox.setCurrentIndex(0)
            self.incrementCurrentRepetitions()
            started = self.maybeStartTimer()
            self.showWindowMessage(
                Status.restFinished if started else Status.repetitionsReached)

    def incrementCurrentRepetitions(self):
        if self.maxRepetitions > 0:
            self.currentRepetitions += 1

    def insertTask(self):
        task = self.taskTextEdit.toPlainText()
        self.insertTasks(task)

    def insertTasks(self, *tasks):
        for task in tasks:
            if task:
                rowCount = self.tasksTableWidget.rowCount()
                self.tasksTableWidget.setRowCount(rowCount + 1)
                self.tasksTableWidget.setItem(rowCount, 0,
                                              QTableWidgetItem(task))
                self.tasksTableWidget.resizeRowsToContents()
                self.taskTextEdit.clear()

    def deleteTask(self):
        selectedIndexes = self.tasksTableWidget.selectedIndexes()
        if selectedIndexes:
            self.tasksTableWidget.removeRow(selectedIndexes[0].row())

    def markTaskAsFinished(self, row, col):
        item = self.tasksTableWidget.item(row, col)
        font = self.tasksTableWidget.item(row, col).font()
        font.setStrikeOut(False if item.font().strikeOut() else True)
        item.setFont(font)

    def displayTime(self):
        self.timeDisplay.display(self.time.toString(self.timeFormat))
        self.statisticsRestTimeDisplay.display(
            self.restTime.toString(self.timeFormat))
        self.statisticsWorkTimeDisplay.display(
            self.workTime.toString(self.timeFormat))
        self.statisticsTotalTimeDisplay.display(
            self.totalTime.toString(self.timeFormat))

    def showWindowMessage(self, status):
        if status is Status.workFinished:
            self.trayIcon.showMessage("Break", choice(work_finished_phrases),
                                      makeIcon("tomato"))
        elif status is Status.restFinished:
            self.trayIcon.showMessage("Work", choice(rest_finished_phrases),
                                      makeIcon("tomato"))
        else:
            self.trayIcon.showMessage("Finished",
                                      choice(pomodoro_finished_phrases),
                                      makeIcon("tomato"))
            self.resetButton.click()

    def makeButton(self, text, iconName=None, disabled=True):
        button = QPushButton(text, sizePolicy=self.size_policy)
        if iconName:
            button.setIcon(makeIcon(iconName))
        button.setDisabled(disabled)
        return button

    def exit(self):
        self.close()
        app = QApplication.instance()
        if app:
            app.quit()

    def onActivate(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            self.show()
Exemplo n.º 5
0
class MainWindow(QWidget):

    screenWidth = None  # 窗口的宽度
    screenHeight = None  # 窗口的高度
    pixmap = None  # 临时存储图片路径
    background = None  # 开始时的背景图片
    timer = None  # 定时器

    # 按钮
    closeButton = None  # 关闭窗口按钮
    minimizeButton = None  # 最小化窗口按钮
    startButton = None  # 开始游戏按钮
    muteButton = None  # 静音按钮
    cancelMuteButton = None  # 取消静音按钮
    nextMusicButton = None  # 下一首音乐按钮
    previousMusicButton = None  # 上一首音乐按钮

    buttonSize = 30 + 5

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

        # self.parent = parent

        self.player = Player(self)
        self.game = Tetris(self)

        self.screenWidth = 900
        self.screenHeight = 800
        self.initWindow()
        self.initUI()
        self.initButton()

    def initWindow(self):
        """初始化窗口"""
        self.resize(self.screenWidth, self.screenHeight)  # 窗口大小
        self.setWindowTitle('Tetris')
        self.setWindowFlag(Qt.FramelessWindowHint)  # 无边框
        self.setWindowState(Qt.WindowActive)  # 活动窗口
        self.setWindowIcon(QIcon('./icons/captain_America.ico'))  # 设置图标

    def initUI(self):
        """绘制背景图片"""
        # 第一张背景图片
        self.background = QLabel(self)
        self.pixmap = QPixmap('./icons/background.png')
        self.background.setPixmap(self.pixmap)

    def initButton(self):
        """初始化按钮属性,创建按钮"""
        # 读取qss文件
        with open('./QSS/mainWindow.qss', 'r', encoding='utf-8') as fp:
            self.setStyleSheet(fp.read())
            fp.close()

        # 右上角的关闭按钮
        self.closeButton = QPushButton(self)
        self.closeButton.setObjectName('closeButton')
        self.closeButton.setShortcut('ESC')  # 按钮热键esc
        self.closeButton.setToolTip('关闭')  # 悬停在按钮上的提示->关闭
        self.closeButton.move(self.screenWidth - self.buttonSize, 5)  # 按钮的位置
        self.closeButton.clicked.connect(self.close)

        # 右上角的最小化按钮
        self.minimizeButton = QPushButton(self)
        self.minimizeButton.setObjectName('minimizeButton')
        self.minimizeButton.setToolTip('最小化')  # 悬停在按钮上的提示->最小化
        self.minimizeButton.move(self.screenWidth - 2 * self.buttonSize,
                                 5)  # 按钮的位置
        self.minimizeButton.clicked.connect(self.showMinimized)

        # 开始游戏的按钮
        self.startButton = QPushButton(self)
        self.startButton.setObjectName('startButton')
        self.startButton.move(self.screenWidth // 2 - 100,
                              self.screenHeight // 2 - 50)  # 按钮的位置
        self.startButton.clicked.connect(
            lambda: {
                self.startButton.hide(),
                self.background.hide(),
                self.game.start(),
                self.setTimer(),
            })

        # 静音按钮
        self.muteButton = QPushButton(self)
        self.muteButton.setObjectName('muteButton')
        self.muteButton.move(self.screenWidth - 3 * self.buttonSize,
                             5)  # 按钮的位置
        self.muteButton.hide()  # 默认隐藏
        self.muteButton.clicked.connect(
            lambda: {
                self.player.cancelMute(),
                self.cancelMuteButton.show(),
                self.muteButton.hide(),
            })

        # 取消静音按钮
        self.cancelMuteButton = QPushButton(self)
        self.cancelMuteButton.setObjectName('cancelMuteButton')
        self.cancelMuteButton.move(self.screenWidth - 3 * self.buttonSize,
                                   5)  # 按钮的位置
        self.cancelMuteButton.clicked.connect(
            lambda: {
                self.player.mute(),
                self.cancelMuteButton.hide(),
                self.muteButton.show(),
            })

        # 下一首音乐按钮
        self.nextMusicButton = QPushButton(self)
        self.nextMusicButton.setObjectName('nextMusicButton')
        self.nextMusicButton.setToolTip('下一首')  # 悬停在按钮上的提示->下一首
        self.nextMusicButton.move(self.screenWidth - 4 * self.buttonSize,
                                  5)  # 按钮的位置
        self.nextMusicButton.clicked.connect(self.player.nextMusic)

        # 上一首音乐按钮
        self.previousMusicButton = QPushButton(self)
        self.previousMusicButton.setObjectName('previousMusicButton')
        self.previousMusicButton.setToolTip('上一首')  # 悬停在按钮上的提示->上一首
        self.previousMusicButton.move(self.screenWidth - 5 * self.buttonSize,
                                      5)  # 按钮的位置
        self.previousMusicButton.clicked.connect(self.player.previousMusic)

    def setTimer(self):
        """设置Timer, 每隔500ms检测游戏是否结束"""
        self.timer = QTimer()
        interval = 500
        self.timer.start(interval)
        self.timer.timeout.connect(self.gameOver)

    def gameOver(self):
        """判断游戏是否结束"""
        if self.game.isGameOver is True:
            self.background.show()
            self.startButton.show()
            self.timer.disconnect()
            self.game.isGameStart = False
            self.game.restartButton.hide()
            self.game.gameOverImage.hide()
Exemplo n.º 6
0
class Tetris(QWidget):

    screenWidth = None  # 窗口宽度
    screenHeight = None  # 窗口高度
    isGameStart = None  # 游戏是否开始
    isGameOver = None  # 游戏是否结束
    isPause = None  # 游戏是否暂停
    pauseButton = None  # 暂停游戏按钮
    resumeButton = None  # 继续游戏按钮
    restartButton = None  # 重新开始游戏按钮
    gameOverImage = None  # 游戏结束时显示的图片
    blockSize = None  # 一个方块的大小(像素px)
    allRows = None  # 所有的行
    allColumns = None  # 所有的列
    allBlock = None  # 二维数组, 记录方块
    currentRow = None  # 当前行
    currentColumn = None  # 当前列
    dropTimer = None  # 方块下降的定时器
    updateTimer = None  # 屏幕更新的定时器
    removeBlockTimer = None  # 消除方块的定时器
    dropInterval = None  # 方块下降定时器的时间间隔
    updateInterval = None  # 屏幕更新定时器的时间间隔
    removeBlockInterval = None  # 消除方块定时器的时间间隔
    blocks = None  # 枚举所有的方块
    blockDict = None  # 存储方块属性的字典
    nextBlockDict = None  # 存储下一个方块属性的字典
    block = None  # 当前的方块
    shape = None  # 当前方块的类型
    index = None  # 当前方块类型的下标
    score = None  # 得分情况
    pixmap = None  # 临时存储图片路径
    paint = None  # 画笔
    font = None  # 字体

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

        self.screenWidth = 900
        self.screenHeight = 800
        self.setFocusPolicy(Qt.StrongFocus)  # 设置焦点, 监听键盘
        self.resize(self.screenWidth, self.screenHeight)

        self.initButton()
        self.initImage()

    def initButton(self):
        """初始化重新开始游戏的按钮"""
        # 暂停游戏按钮
        self.pauseButton = QPushButton(self)
        self.pauseButton.setObjectName('pauseButton')
        self.pauseButton.setShortcut('P')
        self.pauseButton.setToolTip('暂停')  # 悬停在按钮上的提示->暂停
        self.pauseButton.move(self.screenWidth - 210, 5)  # 按钮的位置
        self.pauseButton.hide()  # 默认隐藏
        self.pauseButton.clicked.connect(lambda: {
            self.pause(),
            self.pauseButton.hide(),
            self.resumeButton.show(),
        })

        # 继续游戏按钮
        self.resumeButton = QPushButton(self)
        self.resumeButton.setObjectName('resumeButton')
        self.resumeButton.setToolTip('继续')  # 悬停在按钮上的提示->继续
        self.resumeButton.move(self.screenWidth - 210, 5)  # 按钮的位置
        self.resumeButton.hide()  # 默认隐藏
        self.resumeButton.clicked.connect(lambda: {
            self.resume(),
            self.resumeButton.hide(),
            self.pauseButton.show(),
        })

        # 重新开始游戏按钮
        self.restartButton = QPushButton(self)
        self.restartButton.setObjectName('restartButton')
        self.restartButton.move(self.screenWidth // 2 - 200,
                                self.screenHeight // 2 - 50)
        self.restartButton.hide()  # 默认隐藏
        self.restartButton.clicked.connect(self.gameOver)

    def initImage(self):
        """初始化游戏结束的图片"""
        self.gameOverImage = QLabel(self)
        self.gameOverImage.setPixmap(QPixmap('./icons/game_over.png'))
        self.gameOverImage.move(self.screenWidth // 24, self.screenHeight // 4)
        self.gameOverImage.hide()  # 默认隐藏

    def initSetting(self):
        """初始化方块的一些初始值"""
        self.blocks = {
            'L Shape': [[[0, 0], [0, -1], [0, -2], [1, -2]],
                        [[-1, -1], [0, -1], [1, -1], [-1, -2]],
                        [[-1, 0], [0, 0], [0, -1], [0, -2]],
                        [[-1, -1], [0, -1], [1, -1], [1, 0]]],
            'J Shape': [[[0, 0], [0, -1], [0, -2], [-1, -2]],
                        [[-1, 0], [-1, -1], [0, -1], [1, -1]],
                        [[0, 0], [1, 0], [0, -1], [0, -2]],
                        [[-1, -1], [0, -1], [1, -1], [1, -2]]],
            'Z Shape': [[[-1, 0], [0, 0], [0, -1], [1, -1]],
                        [[0, 0], [0, -1], [-1, -1], [-1, -2]],
                        [[-1, 0], [0, 0], [0, -1], [1, -1]],
                        [[0, 0], [0, -1], [-1, -1], [-1, -2]]],
            'S Shape': [[[-1, 0], [-1, -1], [0, -1], [0, -2]],
                        [[0, 0], [1, 0], [-1, -1], [0, -1]],
                        [[-1, 0], [-1, -1], [0, -1], [0, -2]],
                        [[0, 0], [1, 0], [-1, -1], [0, -1]]],
            'O Shape': [[[-1, 0], [0, 0], [-1, -1], [0, -1]],
                        [[-1, 0], [0, 0], [-1, -1], [0, -1]],
                        [[-1, 0], [0, 0], [-1, -1], [0, -1]],
                        [[-1, 0], [0, 0], [-1, -1], [0, -1]]],
            'I Shape': [[[0, 0], [0, -1], [0, -2], [0, -3]],
                        [[-2, -1], [-1, -1], [0, -1], [1, -1]],
                        [[0, 0], [0, -1], [0, -2], [0, -3]],
                        [[-2, -1], [-1, -1], [0, -1], [1, -1]]],
            'T Shape': [[[-1, -1], [0, -1], [1, -1], [0, -2]],
                        [[0, 0], [-1, -1], [0, -1], [0, -2]],
                        [[0, 0], [-1, -1], [0, -1], [1, -1]],
                        [[0, 0], [0, -1], [1, -1], [0, -2]]]
        }
        self.score = 0
        self.blockSize = 40  # 方块的大小
        self.allRows = 20  # 总共20行
        self.allColumns = 15  # 总共15列
        self.currentRow = self.allRows + 4  # +4行是用来放置待出现的方块的
        self.currentColumn = self.allColumns // 2
        self.allBlock = [[0 for row in range(self.allColumns)]
                         for column in range(self.allRows + 5)]
        self.allBlock[0] = [1
                            for column in range(self.allColumns)]  # 用来判断方块是否到底
        # print(self.allBlock)

    def initFont(self):
        """初始化字体"""
        # 使用本地字体
        fontID = QFontDatabase.addApplicationFont('./Font/Consolas Italic.ttf')
        self.font = QFont()
        self.font.setFamily(QFontDatabase.applicationFontFamilies(fontID)[0])
        self.font.setItalic(True)  # 斜体
        self.font.setBold(True)  # 粗体
        self.font.setPixelSize(40)  # 字体大小

    def initTimer(self):
        """初始化定时器"""
        # 方块下降的定时器
        self.dropTimer = QTimer(self)
        self.dropInterval = 500  # 每0.5秒下降一格
        self.dropTimer.start(self.dropInterval)
        self.dropTimer.timeout.connect(self.blockDrop)

        # paintEvent更新的定时器
        self.updateTimer = QTimer(self)
        self.updateInterval = 10
        self.updateTimer.start(self.updateInterval)
        self.updateTimer.timeout.connect(self.update)

        # 消除方块的定时器
        self.removeBlockTimer = QTimer(self)
        self.removeBlockInterval = 150
        self.removeBlockTimer.start(self.removeBlockInterval)
        self.removeBlockTimer.timeout.connect(self.removeBlock)

    def getBlock(self):
        """获取方块"""
        shape = random.choice(list(self.blocks.keys()))  # 选择随机方块的类型
        index = random.randint(0, 3)
        # if shape == 'L Shape' and index == 3:
        #     pass
        block = self.blocks[shape][index]
        blockDict = {
            'shape': shape,
            'index': index,
            'block': block,
        }
        return blockDict

    def getCurrentBlock(self):
        """获取目前的方块"""
        self.blockDict = self.nextBlockDict
        self.shape = self.blockDict['shape']
        self.index = self.blockDict['index']
        self.block = self.blockDict['block']
        self.nextBlockDict = self.getBlock()

    def blockDrop(self):
        """每运行一次, 方块下降一格, 通过QTimer每隔一定时间运行一次"""
        for position1 in self.block:
            x = position1[0] + self.currentColumn  # x->column
            y = position1[1] + self.currentRow  # y->row
            # print(x, y)
            if self.allBlock[y - 1][x] == 1:
                for position2 in self.block:
                    self.allBlock[position2[1] +
                                  self.currentRow][position2[0] +
                                                   self.currentColumn] = 1
                break
        else:
            # 下落方块没有接触到其他方块或者没有到底, 继续下降
            self.currentRow -= 1
            return

        # 判断游戏结束
        if 1 in self.allBlock[self.allRows]:
            self.pause()
            self.update()
            self.removeBlockTimer.disconnect()
            self.updateTimer.disconnect()
            self.pauseButton.hide()
            self.gameOverImage.show()
            self.restartButton.show()
            return

        # 方块下落完成, 获取下一个方块
        self.getCurrentBlock()
        self.currentRow = self.allRows + 4
        self.currentColumn = self.allColumns // 2

    def removeBlock(self):
        """消除方块"""
        # 叠满一行时消除方块, 从上往下消除
        for row in range(self.allRows, 0, -1):
            if 0 not in self.allBlock[row]:
                # 消除方块时触发音效, 消除一行触发一次
                player = QMediaPlayer(self)
                player.setMedia(
                    QMediaContent(
                        QUrl.fromLocalFile('./AudioFrequency/dingdong.mp3')))
                player.play()

                self.allBlock.pop(row)  # 即删即增
                self.allBlock.append([0 for column in range(self.allColumns)])
                self.score += 1

                break

    def blockMove(self, movePosition):
        """左右移动方块movePosition>0 代表向右移动一格 <0 代表向左移动一格"""
        for position in self.block:
            x = position[0] + self.currentColumn + movePosition
            y = position[1] + self.currentRow
            if x < 0 or x > self.allColumns - 1 or y > self.allRows:
                # 说明方块左右移动出边界了
                return
            elif self.allBlock[y][x] == 1:
                # 说明方块左右移动碰到方块了
                return
        else:
            self.currentColumn += movePosition

    def rotate(self):
        """顺时针旋转方块"""
        for position in self.blocks[self.shape][(self.index + 1) % 4]:
            x = position[0] + self.currentColumn
            y = position[1] + self.currentRow
            # print(x, y)
            if x < 0 or x > self.allColumns - 1 or y > self.allRows:
                # 说明方块旋转时候出边界了
                return
            elif self.allBlock[y][x] == 1:
                # 说明方块旋转时候碰到方块了
                return
        else:
            self.index += 1
            # print(self.blocks[self.shape][self.index % 4])
            self.block = self.blocks[self.shape][self.index % 4]

    def start(self):
        """开始游戏"""
        self.isGameStart = True
        self.isGameOver = False
        self.isPause = False
        self.pauseButton.show()
        self.initSetting()
        self.initFont()
        self.initTimer()
        self.nextBlockDict = self.getBlock()
        self.getCurrentBlock()

    def pause(self):
        """游戏暂停"""
        self.isPause = True
        self.dropTimer.disconnect()

    def resume(self):
        """游戏继续"""
        self.isPause = False
        self.dropTimer.start(self.dropInterval)
        self.dropTimer.timeout.connect(self.blockDrop)

    def gameOver(self):
        """游戏结束"""
        self.isGameOver = True

    def paintEvent(self, event):
        """重写paintEvent, 使用QTimer, 每10ms调用一次"""
        self.paint = QPainter(self)
        self.paint.begin(self)  # 开始重绘

        if self.isGameStart is True:
            penColor = QColor(255, 255, 255)  # 白色
            # backgroundColor = QColor(255, 192, 203)  # 粉色
            self.paint.setPen(QPen(penColor, 2, Qt.SolidLine,
                                   Qt.RoundCap))  # 白色,
            self.pixmap = QPixmap('./icons/game_background.png')
            self.paint.drawPixmap(
                QRect(0, 0, self.screenWidth, self.screenHeight),
                self.pixmap)  # 背景图片
            self.paint.drawLine(self.screenWidth - 300, 0,
                                self.screenWidth - 300,
                                self.screenHeight)  # 分割线

            # 绘制正在下落的方块
            for position in self.block:
                x = position[0] + self.currentColumn
                y = position[1] + self.currentRow
                self.paint.drawPixmap(
                    QRect(x * self.blockSize,
                          (self.allRows - y) * self.blockSize, self.blockSize,
                          self.blockSize), QPixmap('./icons/block.png'))

            # 绘制静态方块
            for row in range(1, self.allRows + 1):
                for column in range(self.allColumns):
                    if self.allBlock[row][column] == 1:
                        self.paint.drawPixmap(
                            QRect(column * self.blockSize,
                                  (self.allRows - row) * self.blockSize,
                                  self.blockSize, self.blockSize),
                            QPixmap('./icons/fill_block.png'))

            # 绘制下一个出现的方块
            for position in self.nextBlockDict['block']:
                x = position[0] + 18.5  # 18.5是740px/40px(方块大小)
                y = position[1] + 12.5  # 7.5是500px/40px(方块大小) 从下往上
                self.paint.drawPixmap(
                    QRect(int(x * self.blockSize),
                          int((self.allRows - y) * self.blockSize),
                          self.blockSize, self.blockSize),
                    QPixmap('./icons/block.png'))

            # 绘制得分情况
            self.paint.setFont(self.font)
            self.paint.drawText(self.screenWidth - 250, 150,
                                'Score: %d' % self.score)

        self.paint.end()  # 结束重绘

    def keyPressEvent(self, event):
        """重写keyPressEvent"""
        if self.isGameOver is False and self.isPause is False:
            if event.key() == Qt.Key_A:
                self.blockMove(-1)
            elif event.key() == Qt.Key_D:
                self.blockMove(1)
            if event.key() == Qt.Key_W:
                self.rotate()
            if event.key() == Qt.Key_S:
                # 加速下降, 加速一个方格
                self.blockDrop()
Exemplo n.º 7
0
class PokerTable(QMainWindow):
    exit_table = pyqtSignal()

    def __init__(self, api_obj: api.API, connect_ssl, host, port, table_id, bb,
                 socks_ip, socks_port, socks5, parent_window, cards,
                 spectator: bool, currency_unit: str):
        """
        :type connect_ssl: bool
        :type socks5: bool
        :type cards: dict
        """
        super(PokerTable, self).__init__()
        self.spectator = spectator
        self.currency_unit = currency_unit
        self.parent_window = parent_window
        self.api = api_obj
        self.socks5 = socks5
        self.socks_port = socks_port
        self.socks_ip = socks_ip
        self.connect_ssl = connect_ssl
        self.bb = bb
        self.table_id = table_id
        self.port = port
        self.host = host
        self.cards = cards
        self.thread_pool = [
        ]  # used to store reference to all newly created threads
        self.close_overrider = False  # decides whether to show messsage box or not

        global CARDS
        CARDS = self.cards

        self.ui = table_window.Ui_MainWindow()
        self.ui.setupUi(self)
        self.curr_progress_bar = self.ui.progressBar_pl_1

        # signals
        self.ui.lineEdit_chat.returnPressed.connect(self.prepare_message_send)
        # [!] call, fold and raise request
        self.ui.pushButton_call.clicked.connect(partial(self.CRF, 'call'))
        self.ui.pushButton_fold.clicked.connect(partial(self.CRF, "fold"))
        self.ui.pushButton_raise.clicked.connect(partial(self.CRF, "raise"))
        self.ui.pushButton_quit.clicked.connect(self.prepare_quit_table)

        # change in input amt will be retained in the next turn
        self.ui.spinBox.valueChanged.connect(self.change_input_amt)

        # [!] set size policy for all other widgets
        self.set_size_retain_policy()

        # [!] HIDE buttons at start
        self.hide_action_buttons()
        # [!] Hide all Dealer buttons
        for label in self.findChildren(QLabel):
            label: QLabel
            if label.objectName().endswith('dealer'):
                label.setVisible(False)

        self.hide_show()

        # prepare sound file for sound at myturn=true
        self.sound_is_muted = False
        self.ui.pushButton_sound.setIcon(QIcon(UNMUTE_ICON))
        if MULTIMEDIA_PACKAGE:
            self.ui.pushButton_sound.clicked.connect(self.mute_sound)
        else:  # if multimedia package not found
            self.mute_sound()  # set button icon to mute
            self.ui.pushButton_sound.setDisabled(True)  # set button disabled

        # [!] initialize thread
        self.request_thread = QtCore.QThread()
        self.thread_pool.append(self.request_thread)

        if not self.spectator:
            self.ui.statusbar.clearMessage()
            self.ui.statusbar.showMessage("Joining table...", 20 * 60 * 1000)
        # [!] Sets plain text for all labels accepting API data
        self.set_plain_text_format()
        # [!] table update timer
        self.start_time_loop()

    def hide_action_buttons(self):
        self.ui.pushButton_raise.setVisible(False)
        self.ui.pushButton_fold.setVisible(False)
        self.ui.pushButton_call.setVisible(False)
        self.ui.spinBox.setVisible(False)
        self.ui.horizontalSlider_amt.setVisible(False)

    def mute_sound(self):
        try:
            if self.sound_is_muted:
                self.ui.pushButton_sound.setIcon(QIcon(UNMUTE_ICON))
                self.sound_is_muted = False
            else:
                self.ui.pushButton_sound.setIcon(QIcon(MUTE_ICON))
                self.sound_is_muted = True
        except (FileNotFoundError, FileExistsError):
            self.ui.pushButton_sound.setIcon(QIcon(MUTE_ICON))
            self.sound_is_muted = True

    def progress_bar_timer(self, progressbar: QProgressBar):
        self.m_2_countdown = QTimer()
        self.m_2_countdown.timeout.connect(
            partial(self.update_progress_bar_value, progressbar))
        self.m_2_countdown.start(1000)

    def update_progress_bar_value(self,
                                  progressbar: QProgressBar,
                                  set_value=None):
        if set_value is not None:
            self.progress_curr_time = set_value  # after each 15 sec this function called from API results and the
            # current timer countdown gets corrected
        if self.progress_curr_time > 0:
            self.progress_curr_time -= 1  # update after each 1 sec and decrease the time count from 2 mins to 0 sec gradually
        else:
            self.progress_curr_time = 0
            self.m_2_countdown.stop()
        progressbar.setValue(self.progress_curr_time)
        self.update()

    def set_plain_text_format(self):
        # format for name labels
        regex_label_name = QRegularExpression("label_pl_[1-6]_name")
        for label_name in self.findChildren(QLabel, regex_label_name,
                                            Qt.FindChildrenRecursively):
            label_name: QLabel
            label_name.setTextFormat(Qt.PlainText)

        # format for stack of each player
        regex_label_btc = QRegularExpression("label_pl_[1-6]_btc")
        for label_btc in self.findChildren(QLabel, regex_label_btc,
                                           Qt.FindChildrenRecursively):
            label_name: QLabel
            label_btc.setTextFormat(Qt.PlainText)

        # format for bet amount of each player
        regex_label_bet = QRegularExpression("label_pl_[1-6]_bet_amt")
        for label_bet in self.findChildren(QLabel, regex_label_bet,
                                           Qt.FindChildrenRecursively):
            label_name: QLabel
            label_bet.setTextFormat(Qt.PlainText)

        # for pot and result label
        self.ui.label_result.setTextFormat(Qt.PlainText)
        self.ui.label_pot.setTextFormat(Qt.PlainText)

    def set_size_retain_policy(self):
        """
        retain size for all widgets that may need to be hidden
        :return: None
        """
        widget_types = [
            QLabel, QProgressBar, QFrame, QPushButton, QSpinBox, QSlider,
            QSpacerItem
        ]
        for widget in widget_types:
            for parent_widgets in self.findChildren(
                    widget, options=Qt.FindChildrenRecursively):
                size_policy = parent_widgets.sizePolicy()
                size_policy.setRetainSizeWhenHidden(True)
                parent_widgets.setSizePolicy(size_policy)

    def prepare_quit_table(self):
        params = ('GET /json/table/{table_id}/quit', None, {
            'table_id': self.table_id
        })
        self.request_ = RequestThread.RequestThread(params, self.api)
        self.request_.moveToThread(self.request_thread)
        self.request_.resp.connect(self.quit_table)
        self.request_.error_signal.connect(
            partial(self.user_retry, 'quit_table'))
        self.request_.complete.connect(self.close_request_thread)
        self.request_thread.started.connect(self.request_.run)
        self.request_thread.start()
        show_request_status(self)

    def quit_table(self, res_list: list):
        self.ui.statusbar.clearMessage()
        res = res_list[0]
        if res is not None and res == {}:
            self.close_timers()
            self.close_all_threads()
            self.close_overrider = True
            self.close()
            self.exit_table.emit(
            )  # signal to close this window and show the join list
        else:
            show_message(ERROR_POPUP_TITLE, ERROR_MSG, 'error')

    # hide/display specific widgets for player
    def hide_show(self, show=False, pos=None):
        for i in range(1, 7):
            pl_frame = self.findChildren(QFrame, f"frame_pl_{i}")[0]
            try:
                if show and pos == i:
                    pl_frame.setVisible(True)
                elif (not show and not pos) or (not show and pos == i):
                    pl_frame.setVisible(False)
                if i in [
                        1, 4
                ]:  # hide/show progress bar for player 1 and player 4, rest of the progress bars get
                    # hidden with the frame_pl_{n}
                    progress_bar = self.findChild(QProgressBar,
                                                  f'progressBar_pl_{i}')
                    clock_icon = self.findChild(QLabel, f"clock_label_{i}",
                                                Qt.FindChildrenRecursively)
                    if show and pos == i:
                        progress_bar.setVisible(True)
                        clock_icon.setVisible(True)
                    elif (not show and not pos) or (not show and pos == i):
                        progress_bar.setVisible(False)
                        clock_icon.setVisible(False)
                frame_map = {
                    2: 16,
                    3: 19,
                    5: 17,
                    6: 15
                }  # hides all frames for players [2,3,5,6]
                if i in frame_map:
                    frame = self.findChild(QFrame, f"frame_{frame_map[i]}")
                    if show and pos == i:
                        frame.setVisible(True)
                    elif not show and not pos:
                        frame.setVisible(False)
                    elif not show and pos == i:
                        frame.setVisible(False)
            except (AttributeError, KeyError):
                if show_message(ERROR_POPUP_TITLE, ERROR_MSG, 'warning'):
                    self.hide_show(show, pos)
        if show is False and pos is None:
            self.ui.frame_table_top.setVisible(False)

    def update_player_view(self, players):
        frame = self.findChild(QFrame,
                               f'frame_pl_{players[0]}',
                               options=Qt.FindChildrenRecursively)
        frame.setVisible(False)
        self.hide_show(pos=int(players[0]))

    def update_progressbar(self, players, mode='hide'):
        for player_index, player in enumerate(players, 1):
            progress_bar = self.findChild(QProgressBar,
                                          f"progressBar_pl_{player}",
                                          Qt.FindChildrenRecursively)
            clock_icon = self.findChild(QLabel, f"clock_label_{player}",
                                        Qt.FindChildrenRecursively)
            if mode == 'show':
                progress_bar.setVisible(True)
                clock_icon.setVisible(True)
            else:
                progress_bar.setHidden(True)
                clock_icon.setHidden(True)

    def update_player_cards(self, players, mode='hide'):
        label_card_1 = self.findChild(QLabel,
                                      f"label_p{players[0]}c{1}",
                                      options=Qt.FindChildrenRecursively)
        label_card_2 = self.findChild(QLabel,
                                      f"label_p{players[0]}c{2}",
                                      options=Qt.FindChildrenRecursively)
        avatar = self.findChild(QLabel, f"pl_{players[0]}_avatar")
        visibility = True if mode == 'show' else False
        label_card_1.setVisible(visibility)
        label_card_2.setVisible(visibility)
        avatar.setVisible(not visibility)

    def close_request_thread(self):
        try:
            self.request_thread.quit()
            self.request_thread.disconnect()
        except Exception as e:
            pass

    def start_time_loop(self):
        """
        calls: get /json/table/:id
        :return:
        """
        self.s_15_timer = QTimer()
        self.s_15_timer.timeout.connect(self.update_time)
        self.curr_time = 0
        self.timer_pause = False
        self.prepare_update()
        self.s_15_timer.start(1000)

    def update_time(self):
        """
        gets called after each 1 second
        :return:
        """
        if not self.timer_pause:
            self.curr_time += 1
            if self.curr_time == TABLE_REFRESH_TIME:
                self.curr_time = 0
                self.prepare_update()
                self.update()

    def update_players(self, players):
        def player_details():
            if player.get('name'):
                label_name = self.findChild(QLabel,
                                            f"label_pl_{position}_name",
                                            options=Qt.FindChildrenRecursively)
                label_name.setText(str(player['name']))
            if 'stack' in player:
                label_stack = self.findChild(
                    QLabel,
                    f"label_pl_{position}_btc",
                    options=Qt.FindChildrenRecursively)
                label_stack.setText(f"{player['stack']}{self.currency_unit}")

        def player_cards():
            if player.get('card1') and player.get("card2"):
                # [!] card 1
                self.update_player_cards([position], mode='show')
                label_card_1 = self.findChild(
                    QLabel,
                    f"label_p{position}c{1}",
                    options=Qt.FindChildrenRecursively)
                card_1_name = player['card1']
                if card_1_name and card_1_name in CARDS:
                    label_card_1.setPixmap(CARDS[card_1_name])
                else:  # if some invalid card name is received then card image is hidden
                    label_card_1.setVisible(False)

                # [!] card 2
                label_card_2 = self.findChild(
                    QLabel,
                    f"label_p{position}c{2}",
                    options=Qt.FindChildrenRecursively)
                card_2_name = player['card2']
                if card_2_name and card_2_name in CARDS:
                    label_card_2.setPixmap(CARDS[card_2_name])
                else:  # if some invalid card name is received then card image is hidden
                    label_card_2.setVisible(False)
            else:
                self.update_player_cards([position], mode='hide')

        def players_turn():
            progress_bar = self.findChild(QProgressBar,
                                          f"progressBar_pl_{position}",
                                          options=Qt.FindChildrenRecursively)
            progress_bar: QProgressBar
            if player.get('timeleft'):
                self.update_progressbar(
                    [position], mode='show')  # show progress bar + clock icon
                progress_bar.setMaximum(
                    PROGRESS_BAR_MAX
                )  # since using time left parameter, so setting it to calculate in percentage
                if player.get("timeleft") and str(
                        player.get("timeleft")).isdigit():
                    value = int(
                        int(player['timeleft']) / 100 * PROGRESS_BAR_MAX)
                    try:
                        if self.m_2_countdown.isActive(
                        ) and self.curr_progress_bar != progress_bar:
                            self.m_2_countdown.stop()
                            self.m_2_countdown.disconnect()
                            self.curr_progress_bar = progress_bar
                            self.progress_bar_timer(progress_bar)
                            self.progress_curr_time = value
                        else:
                            self.m_2_countdown.stop()
                            self.m_2_countdown.timeout.disconnect()
                            self.progress_bar_timer(
                                progress_bar)  # after stop activation
                            self.curr_progress_bar = progress_bar
                            self.progress_curr_time = value
                    except AttributeError:
                        self.progress_bar_timer(
                            progress_bar)  # first activation
                        self.progress_curr_time = value
            else:
                progress_bar.setVisible(False)
                self.update_progressbar([position], 'hide')

        def player_is_dealer():
            label_dealer = self.findChild(QLabel,
                                          f"label_pl_{position}_dealer",
                                          options=Qt.FindChildrenRecursively)
            if player.get('button'):
                # [!] need to display or hide the "Dealer" sign
                if player.get('button') is True:
                    label_dealer.setVisible(True)
                else:
                    label_dealer.setVisible(False)
            else:
                label_dealer.setVisible(False)

        def players_bet():
            label_bet = self.findChild(QLabel, f"label_pl_{position}_bet")
            label_bet_amt = self.findChild(QLabel,
                                           f"label_pl_{position}_bet_amt")

            if player.get('bet') and str(player.get('bet')).isdigit(
            ):  # shows bet amt when bet is not null and
                # don't show if bet isn't greater than 0, and if it's an integer
                label_bet.setVisible(True)
                label_bet_amt.setVisible(True)
                label_bet_amt.setText(str(player.get('bet')))
            else:
                label_bet.setVisible(False)
                label_bet_amt.setVisible(False)

        for player_index in range(1, 7):
            if str(player_index) in players:
                player = players[str(player_index)]
            else:
                self.update_player_view([player_index])
                continue
            player: Dict
            position = player['position']
            self.hide_show(show=True, pos=int(
                position))  # displays the frame and the players attributes

            # player view initializations
            player_details()
            player_is_dealer()
            players_bet()
            player_cards()
            players_turn()

    def update_action_buttons(self, table_data: Dict):
        try:
            self.ui.pushButton_fold.setVisible(True)  # display fold button
            mybet = int(table_data['mybet'])
            max_bet = int(table_data['maxbet'])
            mystack = int(table_data['mystack'])
            bb = int(self.bb)  # table.bb from /json/tables
            if mybet >= max_bet:
                self.ui.pushButton_call.setVisible(True)
                self.ui.pushButton_call.setText("CHECK")
            if mybet < max_bet:
                self.ui.pushButton_call.setVisible(True)
                self.ui.pushButton_call.setText("CALL")
            if mystack >= (
                    max_bet - mybet +
                    bb):  # display raise button with slider and input number
                self.ui.horizontalSlider_amt.setVisible(True)  # show slider
                self.ui.spinBox.setVisible(True)  # show input number
                self.ui.pushButton_raise.setVisible(True)  # show raise button

                # set minimum
                if (2 * max_bet) > bb:
                    self.ui.spinBox.setMinimum(2 * max_bet)

                    self.ui.horizontalSlider_amt.setMinimum(2 * max_bet)
                else:
                    self.ui.spinBox.setMinimum(bb)
                    self.ui.horizontalSlider_amt.setMinimum(bb)
                # set maximum
                self.ui.spinBox.setMaximum(mystack + mybet)
                self.ui.horizontalSlider_amt.setMaximum(mystack + mybet)
                self.ui.spinBox.setValue(self.ui.spinBox.minimum())

            if not self.sound_is_muted and MULTIMEDIA_PACKAGE:
                beep_sound()  # play the beep sound
        except Exception as e:
            show_message(ERROR_POPUP_TITLE, ERROR_MSG, 'error')

    def change_input_amt(self, value):
        """
        called when value in input amt box is changed
        """
        self.last_input_amt = value

    def update_board(self, table_data: Dict):
        if 'board' in table_data:
            # [!] data:{board:[...]} --> Table top 5 cards list
            # [!] Show/hide 5 card images
            board = table_data['board']
            self.ui.frame_table_top.setVisible(
                True
            )  # this will display 5 card images with result and pot label, unavailable data will
            # set corresponding label to hide (For example: if there's no result, label_result will be hidden)
            for card_index, card in enumerate(board):
                label = self.findChild(QLabel,
                                       f"label_c{card_index + 1}",
                                       options=Qt.FindChildrenRecursively)
                if card and card in CARDS:
                    label.setVisible(True)
                    label.setPixmap(
                        CARDS[card]
                    )  # CARDS[card] returns QPixmap object, loaded at the start from Image files
                else:
                    label.setVisible(False)
        else:
            self.ui.frame_table_top.setVisible(False)

        if table_data.get('result') and table_data.get('result'):
            # [!] shows the result
            self.ui.label_result.setVisible(True)
            result = str(table_data.get('result'))
            self.ui.label_result.setText(result)
        else:
            self.ui.label_result.setVisible(False)

        if 'pot' in table_data and str(table_data.get('pot')).isdigit():
            self.ui.label_pot.setVisible(True)
            self.ui.label_pot.setText(
                f"{table_data['pot']}{self.currency_unit}")
        else:
            self.ui.label_pot.setVisible(False)

    def update_messages(self, res: Dict):
        chat_widget.delete_message(self, clear_all=True)
        messages = res.get("messages")
        if len(messages) > 5:
            chat_widget.delete_message(self, clear_all=True)
            del messages[0]
        for message in messages:
            name = message['name']
            content = message['message']
            timer = message['timer']
            if timer and str(timer).isdigit():
                chat_widget.add_message(self, name, timer, content)

    def user_retry(self, call_name):
        response = show_error_message()

        loop = QtCore.QEventLoop()
        QtCore.QTimer.singleShot(
            1500,
            loop.quit)  # wait 1.5 seconds before making the next requests
        loop.exec_()

        if call_name != 'update_table':
            self.close_request_thread()

        if call_name == 'update_table':
            self.close_table_thread()
            if response:
                self.prepare_update()
            else:
                self.timer_pause = False
        elif call_name == 'message' and response:
            self.prepare_message_send()
        elif call_name == 'quit_table' and response:
            self.prepare_quit_table()
        elif call_name == 'call' and response:
            self.prepare_call_action()
        elif call_name == 'check' and response:
            self.prepare_check_action()
        elif call_name == 'fold' and response:
            self.prepare_fold_action()
        elif call_name == 'raise' and response:
            self.prepare_raise_action()

    def prepare_update(self):
        if not self.spectator:
            self.ui.statusbar.showMessage("Joining table...", 20 * 60 * 1000)

        self.timer_pause = True  # set timer pause, so that countdown pauses during table update
        params = tuple(
            ['GET /json/table/{table_id}', None, {
                'table_id': self.table_id
            }])
        if not hasattr(self, 'table_thread'):
            self.table_thread = QtCore.QThread()
            self.thread_pool.append(self.table_thread)
        self.request_ = RequestThread.RequestThread(params, self.api)
        self.request_.moveToThread(self.table_thread)
        self.request_.resp.connect(self.update_table)
        self.request_.error_signal.connect(
            partial(self.user_retry, 'update_table'))
        self.request_.complete.connect(self.close_table_thread)
        self.table_thread.started.connect(self.request_.run)
        self.table_thread.start()
        show_request_status(self)

    def close_table_thread(self):
        try:
            self.table_thread.quit()
            self.table_thread.disconnect()
        except Exception as e:
            pass

    def update_table(self, res_list: list):  # updates table view and messages
        """
        This function will basically refresh the table and update the message box
        :return:
        """
        self.ui.statusbar.clearMessage()
        self.timer_pause = False
        res = res_list[0]
        if res is not None and 'error' not in res and type(res) == dict:
            if 'data' in res:
                res: Dict
                table_data = res['data']
                self.update_board(table_data)

                if table_data.get(
                        'players') and table_data.get('players') != 'null':
                    players = table_data.get('players')
                    players: Dict[Dict]
                    self.update_players(players)

                if table_data.get(
                        'myturn'
                ) and 'mybet' in table_data and 'maxbet' in table_data and 'mystack' in table_data:
                    self.ui.statusbar.clearMessage(
                    )  # clear "joining table..." status when mystack > 0
                    self.update_action_buttons(table_data)
                else:
                    if not self.spectator:
                        self.ui.statusbar.showMessage("Joining table...",
                                                      20 * 60 * 1000)
                        self.spectator = False
                    if table_data.get('mystack') is not None:
                        self.spectator = True
                        self.ui.statusbar.clearMessage()

                    self.ui.pushButton_call.setVisible(
                        False)  # hide call button
                    self.ui.horizontalSlider_amt.setVisible(
                        False)  # hide slider
                    self.ui.spinBox.setVisible(False)  # hide input number
                    self.ui.pushButton_raise.setVisible(
                        False)  # hide raise button
                    self.ui.pushButton_fold.setVisible(
                        False)  # hide fold button
            if res.get('messages'):
                self.update_messages(res)

    def prepare_call_action(self):
        self.request_ = RequestThread.RequestThread(
            params=('POST /json/table/{table_id}/call', None, {
                'table_id': self.table_id
            }),
            api_obj=self.api)
        self.request_.resp.connect(self.do_call_action)
        self.request_.error_signal.connect(partial(self.user_retry, 'call'))
        self.request_.complete.connect(self.close_request_thread)

        self.request_.moveToThread(self.request_thread)
        self.request_thread.started.connect(self.request_.run)
        self.request_thread.start()
        show_request_status(self)

    def do_call_action(self, res_list: list):
        self.ui.statusbar.clearMessage()
        res = res_list[0]
        if (res and "error" in res) or (res is None):
            show_message(ERROR_POPUP_TITLE, ERROR_MSG, 'error')
        elif res and res.get('table'):
            self.prepare_update()
            return 0

    def prepare_check_action(self):
        self.request_ = RequestThread.RequestThread(
            params=('POST /json/table/{table_id}/check', None, {
                'table_id': self.table_id
            }),
            api_obj=self.api)
        self.request_.resp.connect(self.do_check_action)
        self.request_.error_signal.connect(partial(self.user_retry, 'check'))
        self.request_.complete.connect(self.close_request_thread)

        self.request_.moveToThread(self.request_thread)
        self.request_thread.started.connect(self.request_.run)
        self.request_thread.start()
        show_request_status(self)

    def do_check_action(self, res_list: list):
        self.ui.statusbar.clearMessage()
        res = res_list[0]
        if res is None or 'error' in res:
            show_message(ERROR_POPUP_TITLE, ERROR_MSG, 'error')
        elif res and res.get('table'):
            self.prepare_update()
            return 0

    def prepare_fold_action(self):
        self.request_ = RequestThread.RequestThread(
            ('POST /json/table/{table_id}/fold', None, {
                'table_id': self.table_id
            }),
            api_obj=self.api)

        self.request_.resp.connect(self.do_fold_action)
        self.request_.error_signal.connect(partial(self.user_retry, 'fold'))
        self.request_.complete.connect(self.close_request_thread)
        self.request_.moveToThread(self.request_thread)

        self.request_thread.started.connect(self.request_.run)
        self.request_thread.start()
        show_request_status(self)

    def do_fold_action(self, res_list: list):
        self.ui.statusbar.clearMessage()
        res = res_list[0]
        if res and res.get('table'):  # res['table'] will be table_id here
            self.prepare_update()
            return 0
        elif res is None:
            show_message(ERROR_POPUP_TITLE, ERROR_MSG, 'error')

    def prepare_raise_action(self):
        amt_raise = self.ui.horizontalSlider_amt.value()
        body_bytes = f"amount={amt_raise}".encode('iso-8859-1')
        self.request_ = RequestThread.RequestThread(
            ('POST /json/table/{table_id}/raise', body_bytes, {
                'table_id': self.table_id
            }),
            api_obj=self.api)
        self.request_.resp.connect(self.do_raise_action)
        self.request_.error_signal.connect(partial(self.user_retry, 'raise'))
        self.request_.complete.connect(self.close_request_thread)

        self.request_.moveToThread(self.request_thread)
        self.request_thread.started.connect(self.request_.run)
        self.request_thread.start()
        show_request_status(self)

    def do_raise_action(self, res_list: list):
        self.ui.statusbar.clearMessage()
        res = res_list[0]
        if res and res.get('table'):
            self.prepare_update()
            return 0
        else:
            show_message(ERROR_POPUP_TITLE, ERROR_MSG, 'error')

    def CRF(self, request):
        """
        Handles the CALL, RAISE AND FOLD button action
        :param request: alias for button action performed
        :return:
        """
        self.hide_action_buttons(
        )  # hide all action button, if any one is pressed
        if request == 'call' and self.ui.pushButton_call.text().lower(
        ) == 'check':
            request = 'check'
        if request == 'call':
            self.prepare_call_action()
        elif request == 'check':
            self.prepare_check_action()
        elif request == 'fold':
            self.prepare_fold_action()
        elif request == 'raise':
            self.prepare_raise_action()

    def prepare_message_send(self):
        content = self.ui.lineEdit_chat.text()
        if content and content.replace(' ', ''):
            content = content.strip()
            if len(content
                   ) < 50:  # length of each message is less than 50 (49 chars)
                # post message content
                body_bytes = f"message={content}".encode('iso-8859-1')
                if not hasattr(self, 'message_thread'):
                    self.message_thread = QtCore.QThread()
                    self.thread_pool.append(self.message_thread)
                self.request_ = RequestThread.RequestThread(
                    ('POST /json/table/{table_id}/message', body_bytes, {
                        'table_id': self.table_id
                    }), self.api)

                self.request_.resp.connect(self.send_message)
                self.request_.error_signal.connect(
                    partial(self.user_retry, 'message'))
                self.request_.complete.connect(self.close_message_thread)

                self.request_.moveToThread(self.message_thread)
                self.message_thread.started.connect(self.request_.run)
                self.message_thread.start()
                show_request_status(self)

                self.ui.lineEdit_chat.clear(
                )  # clear line after message send request posted

    def send_message(self, res_list):
        self.ui.statusbar.clearMessage()
        res = res_list[0]
        if res is None:
            show_message(ERROR_POPUP_TITLE, ERROR_MSG, 'error')
        elif res is not None and 'table' in res:
            pass
        else:
            show_message(ERROR_POPUP_TITLE, ERROR_MSG, 'error')
        self.prepare_update()  # update table after sending message
        self.update()

    def close_message_thread(self):
        try:
            self.message_thread.quit()
            self.message_thread.disconnect()
        except Exception as e:
            pass

    def close_all_threads(self):
        for thread in self.thread_pool:
            try:
                thread.quit()
                thread.disconnect()
            except Exception as e:
                pass

    def close_timers(self):
        try:
            self.s_15_timer.stop()
            if hasattr(self, 'm_2_countdown'):
                self.m_2_countdown.stop()
        except Exception as e:
            pass

    def closeEvent(self, event: 'QtCore.QEvent') -> None:
        if event.spontaneous():
            message = QMessageBox(
                QMessageBox.Question, "Close Confirmation - Torpoker",
                "Are you sure you want to close this window?",
                QMessageBox.Yes | QMessageBox.Cancel)
            res = message.exec_()
            if res == QMessageBox.Yes:
                self.s_15_timer.stop()
                self.close_timers()
                self.close_all_threads()
                self.exit_table.emit(
                )  # emit signal to go back to the tables list window
                self.close()
            else:
                event.ignore()
        else:
            self.close_timers()
            self.close_all_threads()
            self.s_15_timer.stop()
            self.close()
Exemplo n.º 8
0
class OfflineWindow(QMainWindow, Ui_offline):
    def __init__(self, parent=None):
        super(OfflineWindow, self).__init__(parent)
        self.setupUi(self)
        self.initUI()
        self.initEvent()
        self.timer = QTimer(self)
        self.isPlay = False
        self.frameIndex = 0
        self.output_path = '/home/mmap/work/VSA_Client/sequences/zjz/'

    def initUI(self):
        self.setStyleSheet("QGroupBox#gboxMain{border-width:0px;}")
        self.setProperty("Form", True)
        self.setWindowFlags(Qt.Widget)
        self.setWindowTitle("本地视频文件处理")
        self.widget_alg.move(0, 0)
        self.widge_title.move(0, 40)
        self.widget_main.move(0, 70)
        self.play_show.setText("")
        self.play_show.setFrameShape(QFrame.Box)
        self.play_show.setStyleSheet(
            "border-width: 1px;border-style: solid;border-color: rgb(128,128,128);"
        )

        self.play_show2.setText("")
        self.play_show2.setFrameShape(QFrame.Box)
        self.play_show2.setStyleSheet(
            "border-width: 1px;border-style: solid;border-color: rgb(128,128,128);"
        )
        # str_bg = ["背景建模", "KNN", "MOG2"]
        # self.addCboxItem(self.cbox_bg, str_bg)
        # str_od = ["行人检测", "YOLOV3_tiny", "YOLOV3"]
        # self.addCboxItem(self.cbox_od, str_od)
        # str_sot = ["单目标跟踪", "SiamFC", "SiamRPN", "SiamRPN-CIR"]
        # self.addCboxItem(self.cbox_sot, str_sot)
        # str_mot = ["多目标跟踪", "DeepSort"]
        # self.addCboxItem(self.cbox_mot, str_mot)
    def initEvent(self):
        self.btn_back2online.clicked.connect(
            self.back2onlineHandle)  #点击了"返回在线处理"按钮,则执行back2onlineHandle函数
        self.btn_open.clicked.connect(self.open_query_video)
        self.btn_play.clicked.connect(self.label_click)

    def addCboxItem(self, target, items):
        for i in range(len(items)):
            target.addItem(items[i])

    def back2onlineHandle(self):
        pass
        # self.myMain=MyMainWindow(self.widget_show)
        # self.myMain.setAttribute(Qt.WA_DeleteOnClose)
        # self.myMain.show()
        # self.myOffline.move(0, 0)
        # self.myOffline = OfflineWindow(self.widget_show)
        # self.myOffline.setAttribute(Qt.WA_DeleteOnClose)
        # self.widget_alg.hide()  # 这一行去掉了还能用,搞清楚它是干嘛的
        # self.widget_main.hide()  # 这一行去掉了还能用,搞清楚它是干嘛的
        # self.myOffline.show()
        # self.myOffline.move(0, 0)  # 这一行去掉了还能用,搞清楚它是干嘛的

    def open_query_video(self):
        self.query_video, fileType = QFileDialog.getOpenFileName(
            self, 'Open a query video', './source',
            '*.mp4;;*.avi;;All Files(*)')
        self.vdo = cv2.VideoCapture(self.query_video)
        self.isPlay = True
        self.btn_play.setText("暂停")
        self.timer.timeout.connect(self.play)
        self.timer.start(50)

    def play(self):
        ret, frame = self.vdo.read()
        if ret:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            frame = cv2.resize(frame, (850, 480))
            height, width, channel = frame.shape
            bytesPerLine = 3 * width
            qimg = QtGui.QImage(frame.data, width, height, bytesPerLine,
                                QtGui.QImage.Format_RGB888)
            qimg = QtGui.QPixmap.fromImage(qimg)
            self.play_show.setPixmap(qimg)
            self.play_show.setScaledContents(True)
            self.frameIndex += 1
        else:
            self.timer.disconnect()

    def playFrame(self):
        frame_index = '%04d' % self.frameIndex
        frame_path = self.output_path + frame_index + '.jpg'
        frame = cv2.imread(frame_path)
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        frame = cv2.resize(frame, (850, 480))
        height, width, channel = frame.shape
        bytesPerLine = 3 * width
        qimg = QtGui.QImage(frame.data, width, height, bytesPerLine,
                            QtGui.QImage.Format_RGB888)
        qimg = QtGui.QPixmap.fromImage(qimg)
        self.play_show2.setPixmap(qimg)
        self.play_show2.setScaledContents(True)
        self.frameIndex += 1

    def label_click(self):
        if self.isPlay == True:
            self.btn_play.setText("播放")
            self.timer.disconnect()
            self.isPlay = False
        else:
            self.btn_play.setText("暂停")
            self.isPlay = True
            self.play_show.hide()
            self.play_show2.show()
            self.timer.timeout.connect(self.playFrame)
            self.timer.start()
Exemplo n.º 9
0
class SeeingMonitor(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(SeeingMonitor, self).__init__()
        self.setupUi(self)

        self.Camera = None
        self.THRESH = None
        self.threshold_auto = False
        self.frame = None
        self.draw_only_frame = None
        self.video_source = VideoSource.NONE
        self.export_video = False
        self.select_noiseArea = False
        self.coordinates_noiseArea = []
        self.lineedit_path.setText(QDir.currentPath())
        self.lineedit_filename.setText("seeing.csv")
        self.save_filename = None
        self._updateFileSave()
        self.pause_pressed = False

        self.datetimeedit_start.setMinimumDateTime(QDateTime.currentDateTime())
        self.datetimeedit_end.setMinimumDateTime(QDateTime.currentDateTime())

        if platform.system() == 'Linux':
            self.button_start.setEnabled(False)
            self.button_settings.setEnabled(False)

        self.button_start.clicked.connect(self.startLiveCamera)
        self.button_settings.clicked.connect(self.showSettings)
        self.button_simulation.clicked.connect(self.startSimulation)
        self.button_import.clicked.connect(self.importVideo)
        self.button_export.clicked.connect(self.exportVideo)
        self.button_noise.clicked.connect(self.selectNoiseArea)
        self.lineedit_path.textEdited.connect(self._updateFileSave)
        self.lineedit_filename.textEdited.connect(self._updateFileSave)
        self.slider_threshold.valueChanged.connect(self._updateThreshold)
        self.checkbox_thresh.stateChanged.connect(self._updateThresholdState)

        # Update the Tilt value
        self.spinbox_b.valueChanged.connect(self._updateFormulaZTilt)
        self.spinbox_d.valueChanged.connect(self._updateFormulaZTilt)
        # Update the constants in the FWHM seeing formula
        self.spinbox_d.valueChanged.connect(self._updateFormulaConstants)
        self.spinbox_lambda.valueChanged.connect(self._updateFormulaConstants)

        # Timer for acquiring images at regular intervals
        self.acquisition_timer = QTimer(parent=self.centralwidget)
        self.timer_interval = None

        self._updateThreshold()
        self._updateFormulaZTilt()
        self._updateFormulaConstants()

        # Storing the Delta X and Y in an array to calculate the Standard Deviation
        self.arr_delta_x = deque(maxlen=100)
        self.arr_delta_y = deque(maxlen=100)

        self.plot_length = 1000
        self.fwhm_lat = 0
        self.fwhm_tra = 0
        self.max_lat = 1
        self.min_lat = 0
        self.max_tra = 1
        self.min_tra = 0

        self.series_lat = QLineSeries()
        self.series_lat.setName("Lateral")
        self.series_tra = QLineSeries()
        self.series_tra.setName("Transversal")

        self.chart = QChart()
        self.chart.addSeries(self.series_lat)
        self.chart.addSeries(self.series_tra)

        # self.chart.createDefaultAxes()
        self.axis_horizontal = QDateTimeAxis()
        self.axis_horizontal.setMin(QDateTime.currentDateTime().addSecs(-60 *
                                                                        1))
        self.axis_horizontal.setMax(QDateTime.currentDateTime().addSecs(0))
        self.axis_horizontal.setFormat("HH:mm:ss.zzz")
        self.axis_horizontal.setLabelsFont(
            QFont(QFont.defaultFamily(self.font()), pointSize=5))
        self.axis_horizontal.setLabelsAngle(-20)
        self.chart.addAxis(self.axis_horizontal, Qt.AlignBottom)

        self.axis_vertical_lat = QValueAxis()
        self.axis_vertical_lat.setRange(self.max_lat, self.min_lat)
        self.chart.addAxis(self.axis_vertical_lat, Qt.AlignLeft)

        self.axis_vertical_tra = QValueAxis()
        self.axis_vertical_tra.setRange(self.max_tra, self.min_tra)
        self.chart.addAxis(self.axis_vertical_tra, Qt.AlignRight)

        self.series_lat.attachAxis(self.axis_horizontal)
        self.series_lat.attachAxis(self.axis_vertical_lat)

        self.series_tra.attachAxis(self.axis_horizontal)
        self.series_tra.attachAxis(self.axis_vertical_tra)

        self.chart.setTitle("Full Width at Half Maximum")
        self.chart.legend().setVisible(True)
        self.chart.legend().setAlignment(Qt.AlignBottom)
        self.chartView = QChartView(self.chart, parent=self.graphicsView)
        self.chartView.resize(640, 250)
        self.chartView.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        self.chartView.setRenderHint(QPainter.Antialiasing)

    def closeEvent(self, event):
        try:
            self.Camera.StopLive()
        except AttributeError:
            pass

        try:
            self.cap.release()
        except AttributeError:
            pass

        try:
            self.video_writer.release()
        except AttributeError:
            pass

        event.accept()

    def _callbackFunction(self, hGrabber, pBuffer, framenumber, pData):
        """ This is an example callback function for image processig  with 
            opencv. The image data in pBuffer is converted into a cv Matrix
            and with cv.mean() the average brightness of the image is
            measuered.

        :param: hGrabber: This is the real pointer to the grabber object.
        :param: pBuffer : Pointer to the first pixel's first byte
        :param: framenumber : Number of the frame since the stream started
        :param: pData : Pointer to additional user data structure
        """
        if pData.buffer_size > 0:
            image = C.cast(pBuffer, C.POINTER(C.c_ubyte * pData.buffer_size))

            cvMat = np.ndarray(buffer=image.contents,
                               dtype=np.uint8,
                               shape=(pData.height, pData.width,
                                      pData.iBitsPerPixel))

            frame = np.uint8(cvMat)
            self.frame = cv2.resize(frame, (640, 480))
            self.draw_only_frame = self.frame.copy()
            self._monitor()

    def _startLiveCamera(self):

        # Create a function pointer
        Callbackfunc = IC.TIS_GrabberDLL.FRAMEREADYCALLBACK(
            self._callbackFunction)
        ImageDescription = CallbackUserData()

        # Create the camera object
        self.Camera = IC.TIS_CAM()

        self.Camera.ShowDeviceSelectionDialog()
        if self.Camera.IsDevValid() != 1:
            print("[Error Camera Selection] Couldn't open camera device !")
            # QMessageBox.warning(self, "Error Camera Selection", "Couldn't open camera device !")
            # raise Exception("Unable to open camera device !")
            return

        # Now pass the function pointer and our user data to the library
        self.Camera.SetFrameReadyCallback(Callbackfunc, ImageDescription)

        # Handle each incoming frame automatically
        self.Camera.SetContinuousMode(0)

        print('Starting live stream ...')
        self.Camera.StartLive(
            0
        )  ####### PAUSE LIVE STREAM WHEN PAUSE CLICKED ??? ##############################################
        # self.Camera.StartLive(1)

        Imageformat = self.Camera.GetImageDescription()[:3]
        ImageDescription.width = Imageformat[0]
        ImageDescription.height = Imageformat[1]
        ImageDescription.iBitsPerPixel = Imageformat[2] // 8
        ImageDescription.buffer_size = ImageDescription.width * ImageDescription.height * ImageDescription.iBitsPerPixel

        while self.video_source == VideoSource.CAMERA:
            pass

        # self.timer_interval = 20
        # try:
        #     self.acquisition_timer.disconnect()
        # except TypeError:
        #     pass
        # self.acquisition_timer.timeout.connect(self._updateLiveCamera)
        # self.acquisition_timer.start(self.timer_interval)

    def startLiveCamera(self):
        try:
            self.acquisition_timer.disconnect()
        except TypeError:
            pass

        self.video_source = VideoSource.CAMERA
        self.button_export.setEnabled(True)
        self._setPauseButton()

        # Disable other functionalities
        # self.button_simulation.setEnabled(False)

        t = threading.Thread(target=self._startLiveCamera,
                             args=(),
                             daemon=True)
        t.start()

    def showSettings(self):
        if not self.Camera.IsDevValid():
            QMessageBox.warning(
                self, "Camera Selection Error",
                "Please select a camera first by clicking on the button <strong>Start</strong>"
            )
            return

        try:
            self.Camera.ShowPropertyDialog()
        except Exception as e:
            logging.error(traceback.format_exc())
            QMessageBox.warning(self, "Property Dialog Error",
                                traceback.format_exc())

    # def _updateLiveCamera(self):
    #     # Capturing a frame
    #     self.Camera.SnapImage()
    #     frame = self.Camera.GetImage()
    #     frame = np.uint8(frame)
    #     self.frame = cv2.resize(frame, (640, 480))
    #     self.draw_only_frame = self.frame.copy()
    #     self._monitor()

    # self.displayParameters()

    def displayParameters(self):
        parameters_text = ""

        ExposureTime = [0]
        self.Camera.GetPropertyAbsoluteValue("Exposure", "Value", ExposureTime)
        parameters_text = parameters_text + str(ExposureTime[0]) + "\n"

        GainValue = [0]
        self.Camera.GetPropertyAbsoluteValue("Gain", "Value", GainValue)
        parameters_text = parameters_text + str(GainValue[0]) + "\n"

        self.parameters_label.setText(parameters_text)
        self.parameters_label.adjustSize()

    def startSimulation(self):

        if self.Camera != None and self.Camera.IsDevValid() == 1:
            self.Camera.StopLive()
        self.video_source = VideoSource.SIMULATION
        self.button_export.setEnabled(True)
        self._setPauseButton()

        # Disable other functionalities
        # self.button_start.setEnabled(False)
        self.button_settings.setEnabled(False)

        # Generating fake images of DIMM star (One single star that is split by the DIMM)
        self.starsGenerator = FakeStars()
        self.timer_interval = 100

        try:
            self.acquisition_timer.disconnect()
        except TypeError:
            pass
        self.acquisition_timer.timeout.connect(self._updateSimulation)
        self.acquisition_timer.start(self.timer_interval)

    def _updateSimulation(self):
        frame = self.starsGenerator.generate()
        self.frame = cv2.resize(frame, (640, 480))
        self.draw_only_frame = self.frame.copy()
        self._monitor()


################################################################################################################################################################

    def _writeCSV(self, headerOnly=False):
        if headerOnly:
            with open(self.save_filename, "w") as csvFile:
                fieldnames = ["timestamp", "lateral", "transversal", "star"]
                writer = csv.DictWriter(csvFile, fieldnames=fieldnames)
                writer.writeheader()
                csvFile.close()

        else:
            with open(self.save_filename, "a") as csvFile:
                writer = csv.writer(csvFile)
                writer.writerow([
                    self.current.toTime_t(), self.fwhm_lat, self.fwhm_tra,
                    self.lineedit_star.text()
                ])
                # csvFile.write(",".join([str(self.current) , str(self.fwhm_lat), str(self.fwhm_tra), self.lineedit_star.text()]))
                # csvFile.write("\n")
                # csvFile.close()

    def selectNoiseArea(self):
        self.label_info.setText("Please select on the video a noise area.")
        self.button_noise.setText("Selecting ...")
        self.coordinates_noiseArea = []
        self.select_noiseArea = True

    def _set_noiseArea(self, x1, y1, x2, y2):
        if len(self.coordinates_noiseArea) == 0:
            self.coordinates_noiseArea.append([x1, y1])
            self.coordinates_noiseArea.append([x2, y2])

        elif len(self.coordinates_noiseArea) == 2:
            self.coordinates_noiseArea[0] = [x1, y1]
            self.coordinates_noiseArea[1] = [x2, y2]

    def _draw_noiseArea(self):
        if len(self.coordinates_noiseArea) >= 2:
            cv2.rectangle(self.draw_only_frame,
                          (self.coordinates_noiseArea[0][0],
                           self.coordinates_noiseArea[0][1]),
                          (self.coordinates_noiseArea[1][0],
                           self.coordinates_noiseArea[1][1]), (0, 255, 0), 1)

    def _updateFileSave(self):
        self.save_filename = join(self.lineedit_path.text(),
                                  self.lineedit_filename.text())
        self._writeCSV(headerOnly=True)

    def _updateThreshold(self):
        if self.threshold_auto:
            if self.coordinates_noiseArea.__len__() >= 2:
                noise_area = self.frame[self.coordinates_noiseArea[0][1]:self.
                                        coordinates_noiseArea[1][1],
                                        self.coordinates_noiseArea[0][0]:self.
                                        coordinates_noiseArea[1][0]]
                try:
                    self.THRESH = noise_area.max() + 20
                    # self.THRESH = int(round(noise_area.mean()))
                except ValueError:
                    return

                self.slider_threshold.setValue(self.THRESH)
                self.checkbox_thresh.setText("Threshold ({}, auto)".format(
                    self.THRESH))
        else:
            self.THRESH = self.slider_threshold.value()
            self.checkbox_thresh.setText("Threshold ({})".format(self.THRESH))

    def _updateThresholdState(self, state):
        if state == 0:
            self.threshold_auto = False
            self.slider_threshold.setEnabled(True)
        else:
            if self.coordinates_noiseArea.__len__() < 2:
                QMessageBox.information(self, "Select Noise Area",
                                        "Please select the noise area")
                self.selectNoiseArea()

            self.threshold_auto = True
            self.slider_threshold.setEnabled(False)

    def _updateFormulaZTilt(self):
        self.spinbox_d.setStyleSheet("QSpinBox { background-color: blue; }")
        try:
            b = float(self.spinbox_b.value()) / float(self.spinbox_d.value())
        except ZeroDivisionError:
            QMessageBox.warning(self, "Zero Division Error",
                                "D (Apertures Diameter cannot be Zero")
            return
        self.K_lat = 0.364 * (1 - 0.532 * np.power(b, -1 / 3) -
                              0.024 * np.power(b, -7 / 3))
        self.K_tra = 0.364 * (1 - 0.798 * np.power(b, -1 / 3) -
                              0.018 * np.power(b, -7 / 3))

    def _updateFormulaConstants(self):
        # Calculate value to make process faster
        self.A = 0.98 * np.power(
            float(self.spinbox_d.value()) / float(self.spinbox_lambda.value()),
            0.2)

    def _calcSeeing(self):
        std_x = np.std(self.arr_delta_x)
        std_y = np.std(self.arr_delta_y)

        # Seeing
        self.current = QDateTime.currentDateTime()
        self.fwhm_lat = self.A * np.power(std_x / self.K_lat, 0.6)
        self.fwhm_tra = self.A * np.power(std_y / self.K_tra, 0.6)

        threading.Thread(target=self._plotSeeing, args=(), daemon=True).start()
        threading.Thread(target=self._writeCSV, args=(), daemon=True).start()

        self.label_info.setText("lat: " + str(self.fwhm_lat) + " | lon: " +
                                str(self.fwhm_tra))

    def _calcSeeing_arcsec(self):
        std_x = np.std(self.arr_delta_x)
        std_y = np.std(self.arr_delta_y)

        # Seeing
        self.current = QDateTime.currentDateTime()
        self.fwhm_lat = self.A * np.power(
            std_x / self.K_lat, 0.6) * 205.0 * self.spinbox_pwidth.value(
            ) / self.spinbox_focal.value()
        self.fwhm_tra = self.A * np.power(
            std_y / self.K_tra, 0.6) * 205.0 * self.spinbox_pheight.value(
            ) / self.spinbox_focal.value()

        threading.Thread(target=self._plotSeeing, args=(), daemon=True).start()
        threading.Thread(target=self._writeCSV, args=(), daemon=True).start()

        self.label_info.setText("lat: " + str(self.fwhm_lat) + " | lon: " +
                                str(self.fwhm_tra))

    def _monitor(self):

        tic = time.time()

        gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY)

        self._updateThreshold()
        _, thresholded = cv2.threshold(gray, self.THRESH, 255,
                                       cv2.THRESH_TOZERO)

        # _, contours, _ = cv2.findContours(thresholded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        contours, _ = cv2.findContours(thresholded, cv2.RETR_EXTERNAL,
                                       cv2.CHAIN_APPROX_NONE)

        contours = contours[:2]

        # if contours.__len__() > 2:
        #     QMessageBox.warning(self, "Thresholding error", "More than 2 projections were found. " + \
        #         "Please increase threshold manually or select a better noise area.")

        cv2.drawContours(self.draw_only_frame, contours, -1, (0, 255, 0), 2)
        self._draw_noiseArea()

        try:
            moments_star_1 = cv2.moments(contours[0])
            moments_star_2 = cv2.moments(contours[1])

        except IndexError:
            print("Only {} were found ! (Must be at least 2)".format(
                len(contours)))

        else:

            try:
                cX_star1 = int(moments_star_1["m10"] / moments_star_1["m00"])
                cY_star1 = int(moments_star_1["m01"] / moments_star_1["m00"])

                cX_star2 = int(moments_star_2["m10"] / moments_star_2["m00"])
                cY_star2 = int(moments_star_2["m01"] / moments_star_2["m00"])

            except ZeroDivisionError:
                return

            if self.enable_seeing.isChecked():
                delta_x = abs(cX_star2 - cX_star1)
                delta_y = abs(cY_star2 - cY_star1)

                self.arr_delta_x.append(delta_x)
                self.arr_delta_y.append(delta_y)

                # self._calcSeeing()
                self._calcSeeing_arcsec()

            cv2.drawMarker(self.draw_only_frame, (cX_star1, cY_star1),
                           color=(0, 0, 255),
                           markerSize=30,
                           thickness=1)
            cv2.drawMarker(self.draw_only_frame, (cX_star2, cY_star2),
                           color=(0, 0, 255),
                           markerSize=30,
                           thickness=1)

        finally:

            self._displayImage()

            threading.Thread(target=self._writeVideoFile, args=(),
                             daemon=True).start()

        toc = time.time()
        elapsed = toc - tic
        try:
            print("FPS max = {}".format(int(1.0 / elapsed)))
        except ZeroDivisionError:
            pass

    def _displayImage(self):
        qImage = array2qimage(self.draw_only_frame)
        self.stars_capture.setPixmap(QPixmap(qImage))

    def _plotSeeing(self):

        self.axis_horizontal.setMin(QDateTime.currentDateTime().addSecs(-60 *
                                                                        1))
        self.axis_horizontal.setMax(QDateTime.currentDateTime().addSecs(0))

        if self.series_lat.count() > self.plot_length - 1:
            self.series_lat.removePoints(
                0,
                self.series_lat.count() - self.plot_length - 1)

        if self.series_tra.count() > self.plot_length - 1:
            self.series_tra.removePoints(
                0,
                self.series_tra.count() - self.plot_length - 1)

        if self.fwhm_lat > self.max_lat:
            self.max_lat = self.fwhm_lat
            self.axis_vertical_lat.setMax(self.max_lat + 10)
        if self.fwhm_lat < self.min_lat:
            self.min_lat = self.fwhm_lat
            self.axis_vertical_lat.setMax(self.min_lat - 10)
        if self.fwhm_tra > self.max_tra:
            self.max_tra = self.fwhm_tra
            self.axis_vertical_tra.setMax(self.max_tra + 10)
        if self.fwhm_tra < self.min_tra:
            self.min_tra = self.fwhm_tra
            self.axis_vertical_tra.setMax(self.min_tra - 10)

        # print(self.fwhm_lat, self.fwhm_tra)

        self.series_lat.append(self.current.toMSecsSinceEpoch(), self.fwhm_lat)
        self.series_tra.append(self.current.toMSecsSinceEpoch(), self.fwhm_tra)

    def importVideo(self):

        self.video_source = VideoSource.VIDEO
        self.button_export.setEnabled(True)
        self._setPauseButton()

        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        filename, _ = QFileDialog.getOpenFileName(
            self,
            "Import from Video File",
            QDir.currentPath(),
            "Video Files (*.avi *.mp4 *.mpeg *.flv *.3gp *.mov);;All Files (*)",
            options=options)

        if filename:
            if self.Camera != None and self.Camera.IsDevValid() == 1:
                self.Camera.StopLive()

            self.cap = cv2.VideoCapture(filename)

            # print("CAP_PROP_POS_MSEC :", self.cap.get(cv2.CAP_PROP_POS_MSEC))
            # print("CAP_PROP_POS_FRAMES :", self.cap.get(cv2.CAP_PROP_POS_FRAMES))
            # print("CAP_PROP_POS_AVI_RATIO :", self.cap.get(cv2.CAP_PROP_POS_AVI_RATIO))
            # print("CAP_PROP_FRAME_WIDTH :", self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            # print("CAP_PROP_FRAME_HEIGHT :", self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            # print("CAP_PROP_FPS :", self.cap.get(cv2.CAP_PROP_FPS))
            # print("CAP_PROP_FOURCC :", self.cap.get(cv2.CAP_PROP_FOURCC))
            # print("CAP_PROP_FRAME_COUNT :", self.cap.get(cv2.CAP_PROP_FRAME_COUNT))
            # print("CAP_PROP_FORMAT :", self.cap.get(cv2.CAP_PROP_FORMAT))
            # print("CAP_PROP_MODE :", self.cap.get(cv2.CAP_PROP_MODE))
            # print("CAP_PROP_BRIGHTNESS :", self.cap.get(cv2.CAP_PROP_BRIGHTNESS))
            # print("CAP_PROP_CONTRAST :", self.cap.get(cv2.CAP_PROP_CONTRAST))
            # print("CAP_PROP_SATURATION :", self.cap.get(cv2.CAP_PROP_SATURATION))
            # print("CAP_PROP_HUE :", self.cap.get(cv2.CAP_PROP_HUE))
            # print("CAP_PROP_GAIN :", self.cap.get(cv2.CAP_PROP_GAIN))
            # print("CAP_PROP_EXPOSURE :", self.cap.get(cv2.CAP_PROP_EXPOSURE))
            # print("CAP_PROP_CONVERT_RGB :", self.cap.get(cv2.CAP_PROP_CONVERT_RGB))
            # print("CAP_PROP_WHITE_APERTURE :", self.cap.get(cv2.CAP_PROP_APERTURE))
            # print("CAP_PROP_RECTIFICATION :", self.cap.get(cv2.CAP_PROP_RECTIFICATION))
            # print("CAP_PROP_ISO_SPEED :", self.cap.get(cv2.CAP_PROP_ISO_SPEED))
            # print("CAP_PROP_BUFFERSIZE :", self.cap.get(cv2.CAP_PROP_BUFFERSIZE))

            if self.cap.isOpened() == False:
                QMessageBox.warning(self, "Import from Video",
                                    "Cannot load file '{}'.".format(filename))
                return

            self.timer_interval = round(1000.0 /
                                        self.cap.get(cv2.CAP_PROP_FPS))
            try:
                self.acquisition_timer.disconnect()
            except TypeError:
                pass
            self.acquisition_timer.timeout.connect(self._grabVideoFrame)
            self.acquisition_timer.start(self.timer_interval)

    def _grabVideoFrame(self):
        ret, frame = self.cap.read()
        if ret == True:
            self.frame = cv2.resize(frame, (640, 480))
            self.draw_only_frame = self.frame.copy()
            self._monitor()

        else:
            try:
                self.acquisition_timer.disconnect()
            except TypeError:
                pass

            QMessageBox.information(self, "Import from Video",
                                    "Video complete !")
            self.cap.release()

    def exportVideo(self):
        # if not self.enable_seeing.isChecked():
        #     answer = QMessageBox.question(self,
        #         "Export to Video File",
        #         "Seeing Monitoring is not activated. Continue ?",
        #         QMessageBox.Yes|QMessageBox.No,
        #         QMessageBox.No)

        #     if answer == QMessageBox.No:
        #         return

        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        filename, _ = QFileDialog.getSaveFileName(
            self,
            "Export to Video File",
            QDir.currentPath(),
            "All Files (*);;Video Files (*.avi *.mp4 *.mpeg *.flv *.3gp *.mov)",
            options=options)

        if filename:
            if splitext(filename)[1] != ".avi":
                filename = splitext(filename)[0] + ".avi"
                QMessageBox.information(
                    self, "Export to Video File",
                    "Only '.avi' extension is supported. Video will be saved as '{}'"
                    .format(filename))

            print(round(1000.0 / float(self.timer_interval)))

            self.video_writer = cv2.VideoWriter(
                filename,
                cv2.VideoWriter_fourcc(*'MJPG'),
                round(1000.0 / float(self.timer_interval)),
                (
                    640, 480
                )  #################################################################################
            )
            self.export_video = True

    def _writeVideoFile(self):
        current = QDateTime.currentDateTime()
        if self.export_video and current >= self.datetimeedit_start.dateTime() and \
            current < self.datetimeedit_end.dateTime():

            # self.video_writer.write(self.frame)
            self.video_writer.write(self.draw_only_frame)

    def _setPauseButton(self):
        self.button_pause.setEnabled(True)
        self.button_pause.setText("⏸ Pause")
        self.button_pause.clicked.connect(self._pause)

    def _pause(self):
        self.pause_pressed = True

        # IC_SuspendLive IC_StopLive ##################################################################################
        self.button_pause.setText("▶ Resume")
        self.button_pause.clicked.connect(self._resume)

        if self.video_source == VideoSource.CAMERA:
            self.Camera.StopLive()
        else:
            self.acquisition_timer.stop()

    def _resume(self):
        self.pause_pressed = False
        self._setPauseButton()

        if self.video_source == VideoSource.CAMERA:
            self.Camera.StartLive(0)
        else:
            try:
                self.acquisition_timer.disconnect()
            except TypeError:
                pass

            self.acquisition_timer.start(self.timer_interval)

            if self.video_source == VideoSource.CAMERA:
                pass
            elif self.video_source == VideoSource.SIMULATION:
                self.acquisition_timer.timeout.connect(self._updateSimulation)
            elif self.video_source == VideoSource.VIDEO:
                self.acquisition_timer.timeout.connect(self._grabVideoFrame)
Exemplo n.º 10
0
class Player(QMainWindow, Ui_MainWindow):
    play_signal = pyqtSignal(object)
    IDLE = 0
    READY = 1
    PLAY = 2

    def __init__(self):
        super(Player, self).__init__()
        # init UI
        self.setupUi(self)
        self.media_player = QMediaPlayer(self)
        self.video_widget = QVideoWidget(self)
        self.media_player.setVideoOutput(self.video_widget)
        self.centralwidget.layout().insertWidget(0, self.video_widget)
        self.playBtn.clicked.connect(self.play_media)
        self.pauseBtn.clicked.connect(self.pause_media)
        self.stopBtn.clicked.connect(self.stop_media)
        self.progressSlider.originMouseMoveEvent = self.progressSlider.mouseMoveEvent
        self.progressSlider.mouseMoveEvent = self.progressSlider_mouse_move
        self.progressSlider.sliderReleased.connect(self.reposition_media)
        self.progressSlider.setDisabled(True)

        self.urlLineEdit.setText('rtsp://127.0.0.1:57501/1')

        # init component
        self.timer = QTimer(self)

        # init sockets
        self.client_rtsp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_rtsp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        self.client_rtp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.client_rtp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        self.client_rtcp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.client_rtcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        # init thread
        self.client_rtp_thread = None
        self.play_event = None

        # init client parameters
        self.seq = 0
        self.client_rtp_port = None
        self.client_rtcp_port = None
        self.client_session_id = None
        self.url = None
        self.status = self.IDLE
        self.media_duration = 0
        self.current_time = 0
        self.init_end_time_label()
        self.set_play_time()

        # init cache file
        self.client_root = os.path.split(os.path.abspath(__file__))[0]
        self.cache_filename = os.path.join(self.client_root, 'Cache/tmp.ts')
        self.file = None

    def setup_play(self, url):
        url_tup = util.parse_url(url)
        if not url_tup:
            QMessageBox.warning(self, 'Warning', 'Invalid URL.')
            return -1
        ip = url_tup[0]
        port = int(url_tup[1])
        path = url_tup[2]
        try:
            self.client_rtsp_socket.connect((ip, port))
        except Exception as e:
            QMessageBox.warning(self, 'Warning', 'Error: connect to media server failed.')
            return -1

        # send OPTIONS
        request_dict = {'CSeq': str(self.seq)}
        request = rtsp.generate_request('OPTIONS', url, request_dict)
        self.client_rtsp_socket.send(request.encode())
        response = self.client_rtsp_socket.recv(1024).decode()
        if rtsp.get_status_code(response) != 200:
            # self.close_rtsp_connection()
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: unexpected server response code.')
            return -1
        response_dict = rtsp.get_response_dict(response)
        if int(response_dict.get('CSeq')) != self.seq:
            # self.close_rtsp_connection()
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: unexpected server response SN.')
            return -1
        self.seq += 1
        # send DESCRIBE
        request_dict = {'CSeq': str(self.seq), 'Accept': 'application/sdp'}
        request = rtsp.generate_request('DESCRIBE', url, request_dict)
        self.client_rtsp_socket.send(request.encode())
        response = self.client_rtsp_socket.recv(1024).decode()
        if rtsp.get_status_code(response) != 200:
            # self.close_rtsp_connection()
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: unexpected server response code.')
            return -1
        response_dict = rtsp.get_response_dict(response)
        if int(response_dict.get('CSeq')) != self.seq:
            # self.close_rtsp_connection()
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: unexpected server response SN.')
            return -1
        self.client_rtp_port = util.match_rtp_port(response)
        if not self.client_rtp_port:
            # self.close_rtsp_connection()
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: can not specify RTP port.')
            return -1
        self.client_rtcp_port = self.client_rtp_port+1
        self.seq += 1
        # setup RTP and RTCP socket
        self.client_rtp_socket.bind(('127.0.0.1', self.client_rtp_port))
        self.client_rtcp_socket.bind(('127.0.0.1', self.client_rtcp_port))
        self.status = self.READY
        # send SETUP
        request_dict = {'CSeq': str(self.seq), 'Transport': 'RTP/AVP;unicast;client_port=%d-%d' % (self.client_rtp_port,
                                                                                                   self.client_rtcp_port)}
        request = rtsp.generate_request('SETUP', url, request_dict)
        self.client_rtsp_socket.send(request.encode())
        response = self.client_rtsp_socket.recv(1024).decode()
        if rtsp.get_status_code(response) != 200:
            # self.close_rtsp_connection()
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: unexpected server response code.')
            return -1
        response_dict = rtsp.get_response_dict(response)
        if int(response_dict.get('CSeq')) != self.seq:
            # self.close_rtsp_connection()
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: unexpected server response SN.')
            return -1
        self.client_session_id = int(response_dict.get('Session'))
        self.seq += 1
        self.status = self.READY
        # send PLAY
        request_dict = {'CSeq': str(self.seq), 'Session': self.client_session_id, 'Range': 'npt=0.000-'}
        request = rtsp.generate_request('PLAY', url, request_dict)
        self.client_rtsp_socket.send(request.encode())
        response = self.client_rtsp_socket.recv(1024).decode()
        if rtsp.get_status_code(response) != 200:
            # self.close_rtsp_connection()
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: unexpected server response code.')
            return -1
        response_dict = rtsp.get_response_dict(response)
        if int(response_dict.get('CSeq')) != self.seq:
            # self.close_rtsp_connection()
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: unexpected server response SN.')
            return -1
        self.seq += 1
        self.current_time, self.media_duration = util.match_media_time(response)
        return 0

    def recv_stream(self, cache_filename):
        cur_seq = 0
        self.file = open(cache_filename, 'wb')
        while True:
            if self.status == self.READY:
                self.play_event.wait()
            if self.status == self.IDLE:
                break
            try:
                data = self.client_rtp_socket.recv(rtp.TS_RTP_PACKET_SIZE)
            except:
                continue
            seq = rtp_packet.get_seq(data)
            if seq and seq < cur_seq:
                continue
            cur_seq = seq
            payload = rtp_packet.get_payload(data)
            self.file.write(payload)
        if self.file:
            self.file.close()

    def start_play(self):
        self.init_progress_slider()
        self.init_end_time_label()
        self.timer.stop()
        self.timer.disconnect()
        self.timer.timeout.connect(self.update_play_time)
        self.timer.start(1000)
        self.progressSlider.setDisabled(False)
        self.media_player.setMedia(QMediaContent(QUrl.fromLocalFile(self.cache_filename)))
        self.media_player.play()

    def progressSlider_mouse_move(self, event):
        self.progressSlider.originMouseMoveEvent(event)
        self.current_time = self.progressSlider.value()
        self.set_play_time()

    def init_progress_slider(self):
        self.progressSlider.setMinimum(0)
        self.progressSlider.setMaximum(self.media_duration)

    def init_end_time_label(self):
        self.endTimeLabel.setText('%d:%02d' % (self.media_duration // 60, self.media_duration % 60))

    def set_play_time(self):
        if self.current_time >= self.media_duration:
            self.stop_media()
        self.progressSlider.setValue(self.current_time)
        current_time = self.current_time
        self.curTimeLabel.setText('%d:%02d' % (current_time // 60, current_time % 60))

    def update_play_time(self):
        self.current_time += 1
        self.set_play_time()

    def closeEvent(self, event):
        if self.status != self.IDLE:
            self.stop_media()

    def play_media(self):
        if self.status == self.IDLE:
            # setup and play
            url = self.urlLineEdit.text()
            res = self.setup_play(url)
            if res != -1:
                # remove cache file
                if os.path.exists(self.cache_filename):
                    os.remove(self.cache_filename)
                self.url = url
                self.client_rtp_thread = threading.Thread(target=self.recv_stream, args=(self.cache_filename,))
                self.status = self.PLAY
                self.play_event = threading.Event()
                self.client_rtp_thread.start()
                self.timer.timeout.connect(self.start_play)
                self.timer.start(3000)
        elif self.status == self.READY:
            # send PLAY
            request_dict = {'CSeq': str(self.seq), 'Session': self.client_session_id, 'Range': 'npt=now-'}
            request = rtsp.generate_request('PLAY', self.url, request_dict)
            self.client_rtsp_socket.send(request.encode())
            response = self.client_rtsp_socket.recv(1024).decode()
            if rtsp.get_status_code(response) != 200:
                # self.close_rtsp_connection()
                self.destroy_connection()
                QMessageBox.warning(self, 'Warning', 'Error: unexpected server response code.')
                return
            response_dict = rtsp.get_response_dict(response)
            if int(response_dict.get('CSeq')) != self.seq:
                # self.close_rtsp_connection()
                self.destroy_connection()
                QMessageBox.warning(self, 'Warning', 'Error: unexpected server response SN.')
                return
            self.seq += 1
            # resume
            self.status = self.PLAY
            self.play_event.set()
            self.media_player.play()
            self.timer.start(1000)
        else:
            return

    def pause_media(self):
        if self.status != self.PLAY:
            return
        self.media_player.pause()
        self.timer.stop()
        self.play_event.clear()
        self.status = self.READY
        # send PAUSE
        request_dict = {'CSeq': str(self.seq), 'Session': self.client_session_id}
        request = rtsp.generate_request('PAUSE', self.url, request_dict)
        self.client_rtsp_socket.send(request.encode())
        response = self.client_rtsp_socket.recv(1024).decode()
        if rtsp.get_status_code(response) != 200:
            # self.close_rtsp_connection()
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: unexpected server response code.')
            return -1
        response_dict = rtsp.get_response_dict(response)
        if int(response_dict.get('CSeq')) != self.seq:
            # self.close_rtsp_connection()
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: unexpected server response SN.')
            return -1
        self.seq += 1

    def stop_media(self):
        if self.status == self.IDLE:
            return
        request_dict = {'CSeq': str(self.seq), 'Session': self.client_session_id}
        request = rtsp.generate_request('TEARDOWN', self.url, request_dict)
        self.client_rtsp_socket.send(request.encode())
        response = self.client_rtsp_socket.recv(1024).decode()
        if rtsp.get_status_code(response) != 200:
            # self.close_rtsp_connection()
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: unexpected server response code.')
            return
        response_dict = rtsp.get_response_dict(response)
        if int(response_dict.get('CSeq')) != self.seq:
            # self.close_rtsp_connection()
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: unexpected server response SN.')
            return
        self.seq += 1
        self.destroy_connection()

    def reposition_media(self):
        if self.status == self.IDLE:
            return
        self.pause_media()
        self.media_player.stop()
        self.media_player.setMedia(QMediaContent())
        self.timer.stop()
        self.timer.disconnect()
        self.play_event.clear()
        self.status = self.READY
        self.current_time = self.progressSlider.value()
        self.set_play_time()

        # reset socket
        self.client_rtp_socket.shutdown(socket.SHUT_RDWR)
        self.client_rtp_socket.close()
        self.client_rtp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.client_rtp_socket.bind(('127.0.0.1', self.client_rtp_port))

        # send PLAY
        request_dict = {'CSeq': str(self.seq), 'Session': self.client_session_id, 'Range': 'npt=%.3f-%.3f' %
                                                                                           (self.current_time,
                                                                                            self.media_duration)}
        request = rtsp.generate_request('PLAY', self.url, request_dict)
        self.client_rtsp_socket.send(request.encode())
        response = self.client_rtsp_socket.recv(1024).decode()
        if rtsp.get_status_code(response) != 200:
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: unexpected server response code.')
            return
        response_dict = rtsp.get_response_dict(response)
        if int(response_dict.get('CSeq')) != self.seq:
            self.destroy_connection()
            QMessageBox.warning(self, 'Warning', 'Error: unexpected server response SN.')
            return
        self.seq += 1
        self.current_time, self.media_duration = util.match_media_time(response)

        # reset cache file
        self.file.close()
        os.remove(self.cache_filename)
        self.file = open(self.cache_filename, 'wb')
        # resume
        self.status = self.PLAY
        self.play_event.set()
        self.timer.timeout.connect(self.start_play)
        self.timer.start(3000)

    def destroy_connection(self):
        # reset status
        self.status = self.IDLE

        # reset player
        self.media_player.stop()
        self.media_player.setMedia(QMediaContent())

        # reset RTSP socket
        self.client_rtsp_socket.shutdown(socket.SHUT_RDWR)
        self.client_rtsp_socket.close()
        self.client_rtsp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_rtsp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        # reset RTP socket
        self.client_rtp_socket.shutdown(socket.SHUT_RDWR)
        self.client_rtp_socket.close()
        self.client_rtp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.client_rtp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        # reset RTCP socket
        self.client_rtcp_socket.shutdown(socket.SHUT_RDWR)
        self.client_rtcp_socket.close()
        self.client_rtcp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.client_rtcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        # reset thread
        self.client_rtp_thread = None
        self.play_event = None

        # reset timer
        self.timer.stop()
        self.timer.disconnect()

        # reset client parameters
        self.seq = 0
        self.client_rtp_port = None
        self.client_rtcp_port = None
        self.client_session_id = None
        self.url = None
        self.media_duration = 0
        self.current_time = 0
        self.init_end_time_label()
        self.set_play_time()

        # reset UI
        self.progressSlider.setDisabled(True)

        # reset cache file
        self.file = None
Exemplo n.º 11
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        settings = QSettings()
        self.setup_trayicon()
        self.setup_ui()
        self.update_work_end_time()
        self.update_rest_end_time()
        self.setup_connections()
        self.timeFormat = "hh:mm:ss"
        self.time = QTime(0, 0, 0, 0)
        self.workTime = QTime(0, 0, 0, 0)
        self.restTime = QTime(0, 0, 0, 0)
        self.totalTime = QTime(0, 0, 0, 0)
        self.currentMode = Mode.work
        self.maxRepetitions = -1
        self.currentRepetitions = 0
        self.show()

    def leaveEvent(self, event):
        super(MainWindow, self).leaveEvent(event)
        self.tasksTableWidget.clearSelection()

    def closeEvent(self, event):
        super(MainWindow, self).closeEvent(event)
        settings = QSettings()
        settings.setValue("timer/work/hours", self.workHoursSpinBox.value())
        settings.setValue("timer/work/minutes",
                          self.workMinutesSpinBox.value())
        settings.setValue("timer/work/seconds",
                          self.workSecondsSpinBox.value())
        settings.setValue("timer/rest/hours", self.restHoursSpinBox.value())
        settings.setValue("timer/rest/minutes",
                          self.restMinutesSpinBox.value())
        settings.setValue("timer/rest/seconds",
                          self.restSecondsSpinBox.value())

        tasks = []
        for i in range(self.tasksTableWidget.rowCount()):
            item = self.tasksTableWidget.item(i, 0)
            if not item.font().strikeOut():
                tasks.append(item.text())
        settings.setValue("tasks/tasks", tasks)

    def start_timer(self):
        try:
            if not self.timer.isActive():
                self.create_timer()
        except:
            self.create_timer()

    def create_timer(self):
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_time)
        self.timer.timeout.connect(self.maybe_change_mode)
        self.timer.setInterval(1000)
        self.timer.setSingleShot(False)
        self.timer.start()

    def pause_timer(self):
        try:
            self.timer.stop()
            self.timer.disconnect()
        except:
            pass

    def reset_timer(self):
        try:
            self.pause_timer()
            self.time = QTime(0, 0, 0, 0)
            self.display_time()
        except:
            pass

    def maybe_start_timer(self):
        if self.currentRepetitions != self.maxRepetitions:
            self.start_timer()
            started = True
        else:
            self.currentRepetitions = 0
            started = False
        return started

    def update_work_end_time(self):
        self.workEndTime = QTime(self.workHoursSpinBox.value(),
                                 self.workMinutesSpinBox.value(),
                                 self.workSecondsSpinBox.value())

    def update_rest_end_time(self):
        self.restEndTime = QTime(self.restHoursSpinBox.value(),
                                 self.restMinutesSpinBox.value(),
                                 self.restSecondsSpinBox.value())

    def update_current_mode(self, mode: str):
        self.currentMode = Mode.work if mode == "work" else Mode.rest

    def update_time(self):
        self.time = self.time.addSecs(1)
        self.totalTime = self.totalTime.addSecs(1)
        if self.modeComboBox.currentText() == "work":
            self.workTime = self.workTime.addSecs(1)
        else:
            self.restTime = self.restTime.addSecs(1)
        self.display_time()

    def update_max_repetitions(self, value):
        if value == 0:
            self.currentRepetitions = 0
            self.maxRepetitions = -1
        else:
            self.maxRepetitions = 2 * value

    def maybe_change_mode(self):
        if self.currentMode is Mode.work and self.time >= self.workEndTime:
            self.reset_timer()
            self.modeComboBox.setCurrentIndex(1)
            self.increment_current_repetitions()
            started = self.maybe_start_timer()
            self.show_window_message(
                Status.workFinished if started else Status.repetitionsReached)
        elif self.currentMode is Mode.rest and self.time >= self.restEndTime:
            self.reset_timer()
            self.modeComboBox.setCurrentIndex(0)
            self.increment_current_repetitions()
            started = self.maybe_start_timer()
            self.show_window_message(
                Status.restFinished if started else Status.repetitionsReached)

    def increment_current_repetitions(self):
        if self.maxRepetitions > 0:
            self.currentRepetitions += 1

    def insert_task(self):
        task = self.taskTextEdit.toPlainText()
        self.insert_tasks(task)

    def insert_tasks(self, *tasks):
        for task in tasks:
            if task:
                rowCount = self.tasksTableWidget.rowCount()
                self.tasksTableWidget.setRowCount(rowCount + 1)
                self.tasksTableWidget.setItem(rowCount, 0,
                                              QTableWidgetItem(task))
                self.tasksTableWidget.resizeRowsToContents()
                self.taskTextEdit.clear()

    def delete_task(self):
        selectedIndexes = self.tasksTableWidget.selectedIndexes()
        if selectedIndexes:
            self.tasksTableWidget.removeRow(selectedIndexes[0].row())

    def mark_task_as_finished(self, row, col):
        item = self.tasksTableWidget.item(row, col)
        font = self.tasksTableWidget.item(row, col).font()
        font.setStrikeOut(False if item.font().strikeOut() else True)
        item.setFont(font)

    def display_time(self):
        self.timeDisplay.display(self.time.toString(self.timeFormat))
        self.statisticsRestTimeDisplay.display(
            self.restTime.toString(self.timeFormat))
        self.statisticsWorkTimeDisplay.display(
            self.workTime.toString(self.timeFormat))
        self.statisticsTotalTimeDisplay.display(
            self.totalTime.toString(self.timeFormat))

    def show_window_message(self, status):
        if status is Status.workFinished:
            self.trayIcon.showMessage("Break", choice(work_finished_phrases),
                                      QIcon("icons/tomato.png"))
        elif status is Status.restFinished:
            self.trayIcon.showMessage("Work", choice(rest_finished_phrases),
                                      QIcon("icons/tomato.png"))
        else:
            self.trayIcon.showMessage("Finished",
                                      choice(pomodoro_finished_phrases),
                                      QIcon("icons/tomato.png"))
            self.resetButton.click()

    def setup_connections(self):
        self.playButton.clicked.connect(self.start_timer)
        self.playButton.clicked.connect(
            lambda: self.playButton.setDisabled(True))
        self.playButton.clicked.connect(
            lambda: self.pauseButton.setDisabled(False))
        self.playButton.clicked.connect(
            lambda: self.resetButton.setDisabled(False))

        self.pauseButton.clicked.connect(self.pause_timer)
        self.pauseButton.clicked.connect(
            lambda: self.playButton.setDisabled(False))
        self.pauseButton.clicked.connect(
            lambda: self.pauseButton.setDisabled(True))
        self.pauseButton.clicked.connect(
            lambda: self.resetButton.setDisabled(False))

        self.resetButton.clicked.connect(self.reset_timer)
        self.resetButton.clicked.connect(
            lambda: self.playButton.setDisabled(False))
        self.resetButton.clicked.connect(
            lambda: self.pauseButton.setDisabled(True))
        self.resetButton.clicked.connect(
            lambda: self.resetButton.setDisabled(True))

        self.workHoursSpinBox.valueChanged.connect(self.update_work_end_time)
        self.workMinutesSpinBox.valueChanged.connect(self.update_work_end_time)
        self.workSecondsSpinBox.valueChanged.connect(self.update_work_end_time)

        self.restHoursSpinBox.valueChanged.connect(self.update_rest_end_time)
        self.restMinutesSpinBox.valueChanged.connect(self.update_rest_end_time)
        self.restSecondsSpinBox.valueChanged.connect(self.update_rest_end_time)

        self.modeComboBox.currentTextChanged.connect(self.update_current_mode)
        self.repetitionsSpinBox.valueChanged.connect(
            self.update_max_repetitions)

        self.acceptTaskButton.pressed.connect(self.insert_task)
        self.deleteTaskButton.pressed.connect(self.delete_task)

        self.tasksTableWidget.cellDoubleClicked.connect(
            self.mark_task_as_finished)

    def setup_ui(self):
        settings = QSettings()

        self.size_policy = sizePolicy = QSizePolicy(QSizePolicy.Expanding,
                                                    QSizePolicy.Expanding)
        #TABWIDGET
        self.tabWidget = QTabWidget()

        self.pomodoroWidget = QWidget(self)

        self.pomodoroWidgetLayout = QVBoxLayout(self.pomodoroWidget)
        self.pomodoroWidget.setLayout(self.pomodoroWidgetLayout)
        # work
        self.workGroupBox = QGroupBox("Work")
        self.workGroupBoxLayout = QHBoxLayout(self.workGroupBox)
        self.workGroupBox.setLayout(self.workGroupBoxLayout)
        self.workHoursSpinBox = QSpinBox(minimum=0,
                                         maximum=24,
                                         value=settings.value(
                                             "timer/work/hours", 0),
                                         suffix="h",
                                         sizePolicy=self.size_policy)
        self.workMinutesSpinBox = QSpinBox(minimum=0,
                                           maximum=60,
                                           value=settings.value(
                                               "timer/work/minutes", 25),
                                           suffix="m",
                                           sizePolicy=self.size_policy)
        self.workSecondsSpinBox = QSpinBox(minimum=0,
                                           maximum=60,
                                           value=settings.value(
                                               "timer/work/seconds", 0),
                                           suffix="s",
                                           sizePolicy=self.size_policy)
        self.workGroupBoxLayout.addWidget(self.workHoursSpinBox)
        self.workGroupBoxLayout.addWidget(self.workMinutesSpinBox)
        self.workGroupBoxLayout.addWidget(self.workSecondsSpinBox)
        # rest
        self.restGroupBox = QGroupBox("Rest")
        self.restGroupBoxLayout = QHBoxLayout(self.restGroupBox)
        self.restGroupBox.setLayout(self.restGroupBoxLayout)
        self.restHoursSpinBox = QSpinBox(minimum=0,
                                         maximum=24,
                                         value=settings.value(
                                             "timer/rest/hours", 0),
                                         suffix="h",
                                         sizePolicy=self.size_policy)
        self.restMinutesSpinBox = QSpinBox(minimum=0,
                                           maximum=60,
                                           value=settings.value(
                                               "timer/rest/minutes", 5),
                                           suffix="m",
                                           sizePolicy=self.size_policy)
        self.restSecondsSpinBox = QSpinBox(minimum=0,
                                           maximum=60,
                                           value=settings.value(
                                               "timer/rest/seconds", 0),
                                           suffix="s",
                                           sizePolicy=self.size_policy)
        self.restGroupBoxLayout.addWidget(self.restHoursSpinBox)
        self.restGroupBoxLayout.addWidget(self.restMinutesSpinBox)
        self.restGroupBoxLayout.addWidget(self.restSecondsSpinBox)
        #OTHER
        self.otherGroupBox = QGroupBox("Other")
        self.otherGroupBoxLayout = QHBoxLayout(self.otherGroupBox)
        self.otherGroupBox.setLayout(self.otherGroupBoxLayout)
        self.repetitionsLabel = QLabel("Repetitions",
                                       sizePolicy=self.size_policy)
        self.repetitionsSpinBox = QSpinBox(minimum=0,
                                           maximum=10000,
                                           value=0,
                                           sizePolicy=self.size_policy,
                                           specialValueText="∞")
        self.modeLabel = QLabel("Mode", sizePolicy=self.size_policy)
        self.modeComboBox = QComboBox()
        self.modeComboBox.addItems(["work", "rest"])
        self.otherGroupBoxLayout.addWidget(self.repetitionsLabel)
        self.otherGroupBoxLayout.addWidget(self.repetitionsSpinBox)
        self.otherGroupBoxLayout.addWidget(self.modeLabel)
        self.otherGroupBoxLayout.addWidget(self.modeComboBox)
        #LCDDISPLAY
        self.lcdDisplayGroupBox = QGroupBox("Time")
        self.lcdDisplayGroupBoxLayout = QHBoxLayout(self.lcdDisplayGroupBox)
        self.lcdDisplayGroupBox.setLayout(self.lcdDisplayGroupBoxLayout)
        self.timeDisplay = QLCDNumber(8, sizePolicy=self.size_policy)
        self.timeDisplay.setFixedHeight(100)
        self.timeDisplay.display("00:00:00")
        self.lcdDisplayGroupBoxLayout.addWidget(self.timeDisplay)

        #BUTTONS
        self.buttonWidget = QWidget()
        self.buttonWidgetLayout = QHBoxLayout(self.buttonWidget)
        self.buttonWidget.setLayout(self.buttonWidgetLayout)
        self.playButton = self.make_button("start", disabled=False)
        self.resetButton = self.make_button("reset")
        self.pauseButton = self.make_button("pause")
        self.buttonWidgetLayout.addWidget(self.pauseButton)
        self.buttonWidgetLayout.addWidget(self.playButton)
        self.buttonWidgetLayout.addWidget(self.resetButton)

        #CENTRALWIDGET
        self.pomodoroWidgetLayout.addWidget(self.workGroupBox)
        self.pomodoroWidgetLayout.addWidget(self.restGroupBox)
        self.pomodoroWidgetLayout.addWidget(self.otherGroupBox)
        self.pomodoroWidgetLayout.addWidget(self.lcdDisplayGroupBox)
        self.pomodoroWidgetLayout.addWidget(self.buttonWidget)
        #CREATE TASKS TAB
        self.tasksWidget = QWidget(self.tabWidget)
        self.tasksWidgetLayout = QVBoxLayout(self.tasksWidget)
        self.tasksWidget.setLayout(self.tasksWidgetLayout)
        self.inputWidget = QWidget()
        self.inputWidget.setFixedHeight(50)
        self.inputWidgetLayout = QHBoxLayout(self.inputWidget)
        self.inputWidgetLayout.setContentsMargins(0, 0, 0, 0)
        self.inputWidget.setLayout(self.inputWidgetLayout)
        self.taskTextEdit = QTextEdit(
            placeholderText="Describe your task briefly.",
            undoRedoEnabled=True)
        self.inputButtonContainer = QWidget()
        self.inputButtonContainerLayout = QVBoxLayout(
            self.inputButtonContainer)
        self.inputButtonContainerLayout.setContentsMargins(0, 0, 0, 0)
        self.inputButtonContainer.setLayout(self.inputButtonContainerLayout)
        self.acceptTaskButton = QToolButton(icon=QIcon("icons/check.png"))
        self.deleteTaskButton = QToolButton(icon=QIcon("icons/trash.png"))
        self.inputButtonContainerLayout.addWidget(self.acceptTaskButton)
        self.inputButtonContainerLayout.addWidget(self.deleteTaskButton)

        self.inputWidgetLayout.addWidget(self.taskTextEdit)
        self.inputWidgetLayout.addWidget(self.inputButtonContainer)
        self.tasksTableWidget = QTableWidget(0, 1)
        self.tasksTableWidget.setHorizontalHeaderLabels(["Tasks"])
        self.tasksTableWidget.horizontalHeader().setStretchLastSection(True)
        self.tasksTableWidget.verticalHeader().setVisible(False)
        self.tasksTableWidget.setWordWrap(True)
        self.tasksTableWidget.setTextElideMode(Qt.ElideNone)
        self.tasksTableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tasksTableWidget.setSelectionMode(
            QAbstractItemView.SingleSelection)
        self.insert_tasks(*settings.value("tasks/tasks", []))

        self.tasksWidgetLayout.addWidget(self.inputWidget)
        self.tasksWidgetLayout.addWidget(self.tasksTableWidget)
        #CREATE STATISTICS TAB
        self.statisticsWidget = QWidget()
        self.statisticsWidgetLayout = QVBoxLayout(self.statisticsWidget)
        self.statisticsWidget.setLayout(self.statisticsWidgetLayout)

        self.statisticsWorkTimeGroupBox = QGroupBox("Work Time")
        self.statisticsWorkTimeGroupBoxLayout = QHBoxLayout()
        self.statisticsWorkTimeGroupBox.setLayout(
            self.statisticsWorkTimeGroupBoxLayout)
        self.statisticsWorkTimeDisplay = QLCDNumber(8)
        self.statisticsWorkTimeDisplay.display("00:00:00")
        self.statisticsWorkTimeGroupBoxLayout.addWidget(
            self.statisticsWorkTimeDisplay)

        self.statisticsRestTimeGroupBox = QGroupBox("Rest Time")
        self.statisticsRestTimeGroupBoxLayout = QHBoxLayout()
        self.statisticsRestTimeGroupBox.setLayout(
            self.statisticsRestTimeGroupBoxLayout)
        self.statisticsRestTimeDisplay = QLCDNumber(8)
        self.statisticsRestTimeDisplay.display("00:00:00")
        self.statisticsRestTimeGroupBoxLayout.addWidget(
            self.statisticsRestTimeDisplay)

        self.statisticsTotalTimeGroupBox = QGroupBox("Total Time")
        self.statisticsTotalTimeGroupBoxLayout = QHBoxLayout()
        self.statisticsTotalTimeGroupBox.setLayout(
            self.statisticsTotalTimeGroupBoxLayout)
        self.statisticsTotalTimeDisplay = QLCDNumber(8)
        self.statisticsTotalTimeDisplay.display("00:00:00")
        self.statisticsTotalTimeGroupBoxLayout.addWidget(
            self.statisticsTotalTimeDisplay)

        self.statisticsWidgetLayout.addWidget(self.statisticsTotalTimeGroupBox)
        self.statisticsWidgetLayout.addWidget(self.statisticsWorkTimeGroupBox)
        self.statisticsWidgetLayout.addWidget(self.statisticsRestTimeGroupBox)

        #ADD TABS
        self.timerTab = self.tabWidget.addTab(self.pomodoroWidget,
                                              QIcon("icons/timer.png"),
                                              "Timer")
        self.tasksTab = self.tabWidget.addTab(self.tasksWidget,
                                              QIcon("icons/tasks.png"),
                                              "Tasks")
        self.statisticsTab = self.tabWidget.addTab(
            self.statisticsWidget, QIcon("icons/statistics.png"), "Statistics")

        self.setCentralWidget(self.tabWidget)

    def make_button(self, text, iconPath=None, disabled=True):
        button = QPushButton(text, sizePolicy=self.size_policy)
        if iconPath:
            button.setIcon(QIcon(iconPath))
        button.setDisabled(disabled)
        return button

    def setup_trayicon(self):
        self.trayIcon = QSystemTrayIcon(QIcon("icons/tomato.png"))
        self.trayIcon.setContextMenu(QMenu())
        self.quitAction = self.trayIcon.contextMenu().addAction(
            QIcon("icons/exit.png"), "Quit", self.exit)
        self.quitAction.triggered.connect(self.exit)
        self.trayIcon.activated.connect(self.onActivate)
        self.trayIcon.show()

    def exit(self):
        self.close()
        app = QApplication.instance()
        if app:
            app.quit()

    def onActivate(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            self.show()
Exemplo n.º 12
0
class AnimateMainButtons(object):
    def __init__(self, context):
        self.context = context
        self.index = list()
        self.alpha = 0
        self.animation_number = -1;

        self.context.btn_new_card.setStyleSheet('color: rgb(0,0,0,%s)' % 0)
        self.context.btn_checkout.setStyleSheet('color: rgb(0,0,0,%s)' % 0)
        self.context.btn_charge.setStyleSheet('color: rgb(0,0,0,%s)' % 0)
        self.context.btn_vip.setStyleSheet('color: rgb(0,0,0,%s)' % 0)
        self.context.btn_reports.setStyleSheet('color: rgb(0,0,0,%s)' % 0)

        self.init_button_animation()

    def initButtonGeometryAnimation(self, element, start, end, duration=500, loopcount=1):
        element.setStartValue(start)
        element.setEndValue(end)
        element.setDuration(duration)
        element.setLoopCount(loopcount)
        element.setEasingCurve(QEasingCurve.OutCurve)

    def init_button_animation(self):
        self.b_position = []
        self.b_position.append(
            self.animation_button_geometry(self.context.btn_new_card, self.context.btn_new_card.geometry()))
        self.b_position.append(
            self.animation_button_geometry(self.context.btn_checkout, self.context.btn_checkout.geometry()))
        self.b_position.append(
            self.animation_button_geometry(self.context.btn_charge, self.context.btn_charge.geometry()))
        self.b_position.append(self.animation_button_geometry(self.context.btn_vip, self.context.btn_vip.geometry()))
        self.b_position.append(
            self.animation_button_geometry(self.context.btn_reports, self.context.btn_reports.geometry()))

        self.timers = []
        for i in range(len(self.b_position)):
            self.timers.append(QTimer())
            self.timers[i].timeout.connect(self.start_moving)
            self.timers[i].setSingleShot(True)
            self.timers[i].start(i * 100)
        self.timer = QTimer()
        self.timer.timeout.connect(self.animation_button_alpha)
        self.timer.start(4)

    def start_moving(self):
        self.animation_number += 1
        self.b_position[self.animation_number].start()

        self.index.append(self.animation_number)

    def animation_button_geometry(self, element, pos):
        start_x = 0
        start_y = pos.y()
        start_width = pos.width()
        start_height = pos.height()
        start = QRect(start_x, start_y, start_width, start_height)
        end = pos

        self.anim = QPropertyAnimation(element, 'geometry'.encode())
        self.initButtonGeometryAnimation(self.anim, start=start, end=end)
        return self.anim

    def animation_button_alpha(self):
        if 0 in self.index:
            alpha = self.context.btn_new_card.palette().color(QPalette.Text).alpha()
            alpha += 1
            if alpha < 256:
                self.context.btn_new_card.setStyleSheet('color: rgb(0,0,0,%s)' % alpha)
        if 1 in self.index:
            alpha = self.context.btn_checkout.palette().color(QPalette.Text).alpha()
            alpha += 1
            if alpha < 256:
                self.context.btn_checkout.setStyleSheet('color: rgb(0,0,0,%s)' % alpha)
        if 2 in self.index:
            alpha = self.context.btn_charge.palette().color(QPalette.Text).alpha()
            alpha += 1
            if alpha < 256:
                self.context.btn_charge.setStyleSheet('color: rgb(0,0,0,%s)' % alpha)
        if 3 in self.index:
            alpha = self.context.btn_vip.palette().color(QPalette.Text).alpha()
            alpha += 1
            if alpha < 256:
                self.context.btn_vip.setStyleSheet('color: rgb(0,0,0,%s)' % alpha)
        if 4 in self.index:
            alpha = self.context.btn_reports.palette().color(QPalette.Text).alpha()
            alpha += 1
            if alpha < 256:
                self.context.btn_reports.setStyleSheet('color: rgb(0,0,0,%s)' % alpha)
            if alpha == 255:
                self.timer.disconnect()
Exemplo n.º 13
0
class YTD(QWidget):
    def __init__(self, path="home/wasptheslimy/Music/YoutubeDownloads/"):
        super().__init__()
        self.setStyleSheet("background-color:  #697268")
        self.path = path
        self.resize(480, 140)
        self.initUI()
        self.setWindowTitle("Youtbe Downloader")

    def initUI(self):

        self.verticalLinkLayout = QVBoxLayout()

        self.headerHorizantalLayout = QHBoxLayout()

        self.headerHorizantalLayout.addStretch()

        cssTitle = """
        font-family: 'Aguero Serif';
        font-size:48px;
        background-color: 	#4e5340;
        color :#fffcf4;
        padding-top : 8px;
        padding-bottom : 8px;
        padding-left:12px;
        padding-right:12px;
        border-style: solid;
        border-width: 4px;
        border-color : #22181c;
        """
        cssIcon = """
        background-color:#fffcf4;
        padding = 1px;
        border-style: solid;
        border-width: 4px;
        border-color : 	#4e5340;
        border-radius:25px;
        """

        self.YoutubeIcon = QLabel()
        self.YoutubeIcon.setPixmap(
            QPixmap(
                "/home/wasptheslimy/Desktop/youtube_Downloader/Icons/youtubeAdjusted.png"
            ))
        self.YoutubeTitle = QLabel()
        self.YoutubeIcon.setStyleSheet(cssIcon)
        self.YoutubeTitle.setStyleSheet(cssTitle)
        self.YoutubeTitle.setText("Youtube Downloader")
        self.headerHorizantalLayout.addWidget(self.YoutubeIcon)
        self.headerHorizantalLayout.addWidget(self.YoutubeTitle)
        #self.headerHorizantalLayout.

        self.headerHorizantalLayout.addStretch()

        self.verticalLinkLayout.addLayout(self.headerHorizantalLayout)

        cssLinkLabel = """
        background-color:#240b36;
        color: 	#f2dc5d;
        border-style: solid;
        border-width: 1px;
        border-color :#697268;
        border-radius: 5px;
        font-family:'Immani Demo';
        padding:5px;
        """

        cssVideoLink = """
        background-color:#f6e8ea;
        color:#22181c;
        border-style: solid;
        border-width: 2px;
        border-color :#697268;
        """

        self.LinkLayout = QHBoxLayout()

        self.LinkLabel = QLabel()
        self.LinkLabel.setText("Youtube Link : ")
        self.videoLink = QLineEdit("Enter the youtube link")
        self.LinkLayout.addWidget(self.LinkLabel)
        self.LinkLayout.addWidget(self.videoLink)
        self.verticalLinkLayout.addLayout(self.LinkLayout)
        self.verticalLinkLayout.addStretch()

        self.LinkLabel.setStyleSheet(cssLinkLabel)
        self.videoLink.setStyleSheet(cssVideoLink)

        self.path = self.getPath()

        cssPathLabel = """
        background-color:#f6e8ea;
        color:#22181c;
        border-style: solid;
        border-width: 2px;
        border-radius:1px;
        border-color :#5a0001;
        font-family:'Times New Roman', Times, serif;
        font-size:14px;
        """
        self.PathLabel = QLabel()
        self.PathLabel.setStyleSheet(cssPathLabel)
        self.Pathscheme = "Current Download PATH : {}"

        self.PathLabel.setText(self.Pathscheme.format(self.path))

        self.horizontalOptionLayout = QHBoxLayout()
        self.newPath = QPushButton("Enter New Path")
        self.newPath.setStyleSheet(
            "background-color:#aac0aa;color:#405858;font-family:'Times New Roman', Times, serif;"
        )
        self.newPath.clicked.connect(self.newPathFunction)
        self.listmod = QPushButton("List Download Mod")
        self.listmod.setStyleSheet(
            "background-color:#aac0aa;color:#405858;font-family:'Times New Roman', Times, serif;"
        )

        self.listmod.clicked.connect(self.listmodFunction)
        self.horizontalOptionLayout.addWidget(self.newPath)
        self.horizontalOptionLayout.addWidget(self.listmod)
        self.horizontalOptionLayout.addStretch()

        #QFileDialog./home/wasptheslimy/Desktop/

        self.horizontalControlLayout = QHBoxLayout()
        self.Download = QPushButton("Download")
        self.Download.setStyleSheet(
            "background-color:#aac0aa;color:#202840;font-family:'Times New Roman', Times, serif;"
        )
        self.Download.clicked.connect(self.DownFunc)

        self.Cancel = QPushButton("Cancel")
        self.Cancel.setStyleSheet(
            "background-color:#aac0aa;color:#202840;font-family:'Times New Roman', Times, serif;"
        )
        self.Cancel.clicked.connect(self.cancelFunc)
        self.horizontalControlLayout.addWidget(self.Download)
        self.horizontalControlLayout.addWidget(self.Cancel)

        self.verticalLinkLayout.addWidget(self.PathLabel)
        self.verticalLinkLayout.addLayout(self.horizontalOptionLayout)
        self.verticalLinkLayout.addStretch()
        self.verticalLinkLayout.addLayout(self.horizontalControlLayout)

        self.setLayout(self.verticalLinkLayout)

    def newPathFunction(self):
        self.timer = QTimer()
        self.timer.timeout.connect(self.pathUpdate)
        self.timer.start(1000)

        self.popWindow = PathPage()
        #self.popWindow.setGeometry(548, 346, 303, 140)
        self.popWindow.show()

    def pathUpdate(self):
        if self.path != self.getPath():
            self.path = self.getPath()
            self.PathLabel.setText(self.Pathscheme.format(self.path))
            self.timer.disconnect()
        else:
            pass

    def getPath(self):
        with open("path.txt", "r") as pathFile:
            self.path = pathFile.readlines()[-1][:-1]

        return self.path

    def cancelFunc(self):
        self.close()

    def DownFunc(self):
        url = self.videoLink.text()
        if 'www.youtube.com' in url.split("/"):
            mp3Download([url], self.path)
        else:
            print("[ERROR] Invalid URL")
            exit()

    def listmodFunction(self):
        self.popWindow = ListDownload(self.path)
        self.popWindow.show()
Exemplo n.º 14
0
class client(QMainWindow):
    def __init__(self):
        super().__init__()
        # self.localPath = os.environ['HOME']
        self.localPath = '/'
        self.serverPath = '/'
        self.linkData = []
        self.serverFileInfo = []
        self.waitingTaskQueue = []
        self.finishedTaskQueue = []
        self.createServerDirQueue = []
        self.downloadingTask = []
        self.connectionNow = {
            'hostname': '',
            'username': '',
            'passwd': '',
            'port': 21
        }
        self.FTP = None
        self.clearFlag = 0
        self.t1 = None
        self.timer = QTimer(self)
        self.lock = threading.Lock()
        self.Mutex = threading.Semaphore(1)
        self.initUI()

    def initUI(self):
        self.setGeometry(100, 100, 1100, 600)
        self.setMinimumWidth(650)
        self.setWindowTitle('ftpClient')
        self.initMenuBar()
        self.initCenterWidget()
        self.show()

    def initMenuBar(self):
        linkManage = QAction('管理连接(&L)', self)
        linkManage.setShortcut('Ctrl+M')
        linkManage.setStatusTip('管理所有连接')
        linkManage.triggered.connect(self.startLinkManageDialog)

        exitAct = QAction('退出(&E)', self)
        exitAct.setShortcut('Ctrl+Q')
        exitAct.setStatusTip('退出程序')
        exitAct.triggered.connect(qApp.quit)

        menuBar = self.menuBar()
        fileMenu = menuBar.addMenu('文件(&F)')
        fileMenu.addAction(linkManage)
        fileMenu.addAction(exitAct)

    def initCenterWidget(self):
        centerWidget = QWidget()

        self.centerBox = QVBoxLayout()
        self.centerBox.setAlignment(Qt.AlignTop)
        self.initQuickLink()

        localWidget = QWidget()
        serverWidget = QWidget()

        localWidgetLayout = QVBoxLayout()
        serverWidgetLayout = QVBoxLayout()

        localLabelLayout = QHBoxLayout()
        serverLabelLayout = QHBoxLayout()

        self.localPathLineEdit = QLineEdit()
        self.serverPathLineEdit = QLineEdit()

        self.localPathLineEdit.setFocusPolicy(Qt.NoFocus)
        self.serverPathLineEdit.setFocusPolicy(Qt.NoFocus)

        self.initLocalFileBox()
        self.initServerFileBox()

        localLabelLayout.addWidget(QLabel('本地文件:'))
        localLabelLayout.addWidget(self.localPathLineEdit)

        serverLabelLayout.addWidget(QLabel('服务器文件:'))
        serverLabelLayout.addWidget(self.serverPathLineEdit)

        localWidgetLayout.addLayout(localLabelLayout)
        localWidgetLayout.addWidget(self.localFileTreeView)
        localWidgetLayout.setContentsMargins(0, 0, 0, 0)

        serverWidgetLayout.addLayout(serverLabelLayout)
        serverWidgetLayout.addWidget(self.serverFileTree)
        serverWidgetLayout.setContentsMargins(0, 0, 0, 0)

        localWidget.setLayout(localWidgetLayout)
        localWidget.setContentsMargins(0, 0, 0, 0)
        serverWidget.setLayout(serverWidgetLayout)
        serverWidget.setContentsMargins(0, 0, 0, 0)

        self.taskQueueTreeWidget = QTreeWidget()
        self.taskQueueTreeWidget.setColumnCount(6)
        self.taskQueueTreeWidget.setHeaderLabels(
            ['文件名', '本地文件夹', '传输方向', ' 远程文件夹', '文件大小', '当前状态'])
        self.taskQueueTreeWidget.setItemDelegate(MyDelegate())

        taskQueueWidget = QWidget()
        taskQueueLayout = QVBoxLayout()
        taskQueueLayout.addWidget(QLabel('任务队列:'))
        taskQueueLayout.addWidget(self.taskQueueTreeWidget)
        taskQueueLayout.setContentsMargins(0, 0, 0, 0)
        taskQueueWidget.setLayout(taskQueueLayout)
        taskQueueWidget.setContentsMargins(0, 0, 0, 0)

        splitter1 = QSplitter(Qt.Horizontal)
        splitter2 = QSplitter(Qt.Vertical)
        splitter3 = QSplitter(Qt.Vertical)
        splitter4 = QSplitter(Qt.Vertical)

        splitter2.addWidget(localWidget)
        splitter2.addWidget(self.localFileTreeWidget)
        splitter3.addWidget(serverWidget)
        splitter3.addWidget(self.serverFileTable)
        splitter1.addWidget(splitter2)
        splitter1.addWidget(splitter3)
        splitter4.addWidget(splitter1)
        splitter4.addWidget(taskQueueWidget)

        self.centerBox.addWidget(splitter4)

        centerWidget.setLayout(self.centerBox)
        self.setCentralWidget(centerWidget)

        self.refreshTableButton.clicked.connect(self.tableRefresh)

    def initQuickLink(self):
        self.hostInput = QLineEdit(self)
        self.userNameInput = QLineEdit(self)
        self.passwdInput = QLineEdit(self)
        self.portInput = QLineEdit('21', self)
        self.quickLoginButton = QPushButton('快速连接', self)
        self.anonymousLoginCheckBox = QCheckBox('匿名连接')
        self.refreshTableButton = QPushButton('刷新文件列表')

        self.passwdInput.setEchoMode(QLineEdit.Password)
        self.portInput.setValidator(QIntValidator(0, 65535))
        self.portInput.setMaximumWidth(40)

        quickLinkBox = QHBoxLayout()
        quickLinkBox.addWidget(QLabel('  主机:', self))
        quickLinkBox.addWidget(self.hostInput)
        quickLinkBox.addWidget(QLabel(' 用户名:', self))
        quickLinkBox.addWidget(self.userNameInput)
        quickLinkBox.addWidget(QLabel(' 密码:', self))
        quickLinkBox.addWidget(self.passwdInput)
        quickLinkBox.addWidget(QLabel(' 端口:', self))
        quickLinkBox.addWidget(self.portInput)
        quickLinkBox.addWidget(self.quickLoginButton)
        quickLinkBox.addWidget(self.anonymousLoginCheckBox)
        quickLinkBox.addWidget(self.refreshTableButton)
        quickLinkBox.addStretch(1)
        self.centerBox.addLayout(quickLinkBox)

        self.quickLoginButton.clicked.connect(self.connectFromQuickLink)
        self.anonymousLoginCheckBox.stateChanged.connect(
            self.quickLinkCheckBoxChanged)

    def initLocalFileBox(self):
        self.localFileTreeView = QTreeView()
        self.localFileTreeWidget = QTreeWidget()

        self.localDirModel = ChangedQDirModel()
        self.localFileTreeView.setModel(self.localDirModel)
        self.localFileTreeView.setColumnWidth(0, 240)
        self.localFileTreeView.setColumnWidth(2, 60)

        self.localFileTreeView.clicked.connect(self.localTreeClicked)

        self.localFileTreeWidget.setColumnCount(4)
        self.localFileTreeWidget.setHeaderLabels(
            ['文件名', '文件大小', '文件类型', '修改时间'])
        self.localFileTreeWidget.setColumnWidth(0, 240)
        self.localFileTreeWidget.setColumnWidth(2, 60)
        self.localFileTreeWidget.setItemDelegate(MyDelegate())

        self.localFileTable = []

        self.localFileRefesh()

        self.localFileTreeWidget.doubleClicked.connect(
            self.localTableDoubleClicked)
        self.localFileTreeWidget.itemPressed.connect(
            self.localTableRightClicked)

    def initServerFileBox(self):
        self.serverFileTree = QTreeWidget()
        self.serverFileTable = QTreeWidget()

        self.serverFileTree.setHeaderLabels(['目录结构'])
        self.serverFileTree.setItemDelegate(MyDelegate())

        self.serverFileTable.setColumnCount(5)
        self.serverFileTable.setHeaderLabels(
            ['文件名', '文件类型', '文件大小', '权限', '修改时间'])
        self.serverFileTable.setColumnWidth(0, 240)
        self.serverFileTable.setColumnWidth(1, 60)
        self.serverFileTable.setColumnWidth(2, 60)
        self.serverFileTable.setColumnWidth(3, 70)
        self.serverFileTable.setItemDelegate(MyDelegate())

        self.serverFileTree.itemExpanded.connect(self.serverFileTreeRefresh)
        self.serverFileTree.itemClicked.connect(self.serverFileTreeClicked)

        self.serverFileTable.doubleClicked.connect(
            self.serverTableDoubleClicked)
        self.serverFileTable.itemPressed.connect(self.serverTableRightClicked)

    def connectFromQuickLink(self):
        hostName = self.hostInput.text()
        userName = self.userNameInput.text()
        passwd = self.passwdInput.text()
        port = int(self.portInput.text())
        with open('linkdata.json', 'r') as f:
            self.linkData = json.load(f)
        data = {
            'hostname': hostName,
            'username': userName,
            'passwd': passwd,
            'port': port,
            'remark': '来自快速连接'
        }
        self.linkData[userName + '@' + hostName + ':' + str(port) + ' ' +
                      '来自快速连接'] = data
        with open('linkdata.json', 'w') as f:
            json.dump(self.linkData, f)

        try:
            self.aNewConnection(hostName, userName, passwd, port)
        except socket.gaierror:
            QMessageBox.information(self, '主机名错误', '主机名错误,请输入正确的主机名',
                                    QMessageBox.Ok, QMessageBox.Ok)
            return
        except ConnectionRefusedError:
            QMessageBox.information(self, '连接出错', '连接失败,请检查是否输入了正确的主机名或端口',
                                    QMessageBox.Ok, QMessageBox.Ok)
            return
        except ftplib.error_perm:
            QMessageBox.information(self, '登陆出错', '登陆失败,请检查是否输入了正确的用户名或密码',
                                    QMessageBox.Ok, QMessageBox.Ok)
            return

    def localFileRefesh(self):
        self.localFileTable.clear()
        self.localFileTreeWidget.clear()

        if self.localPath != '/':
            node = QTreeWidgetItem(self.localFileTreeWidget)
            node.setText(0, '..')
            self.localFileTable.append(node)

        for i in os.listdir(self.localPath):
            node = QTreeWidgetItem(self.localFileTreeWidget)
            node.setText(0, i)
            tempPath = os.path.join(self.localPath, i)
            if os.path.isfile(tempPath):
                node.setText(1, str(os.path.getsize(tempPath)))
                node.setText(2, 'File')
            elif os.path.isdir(tempPath):
                node.setText(1, '')
                node.setText(2, 'Folder')
            elif os.path.islink(tempPath):
                node.setText(1, '')
                node.setText(2, 'Shortcut')
            elif os.path.ismount(tempPath):
                node.setText(1, '')
                node.setText(2, 'Mount')
            try:
                node.setText(3, TimeStampToTime(os.path.getmtime(tempPath)))
            except FileNotFoundError:
                pass
            except PermissionError:
                pass
            self.localFileTable.append(node)

        self.localPathLineEdit.setText(self.localPath)

        for i in self.localFileTable:
            self.localFileTreeWidget.addTopLevelItem(i)

    def serverFileTableRefresh(self):
        self.Mutex.acquire()
        try:
            fileinfo = self.FTP.getdirinfo(self.serverPath)
        except ftplib.error_temp:
            self.reconnect()
            fileinfo = self.FTP.getdirinfo(self.serverPath)
        self.Mutex.release()

        for i in fileinfo:
            node = QTreeWidgetItem(self.serverFileTable)
            node.setText(0, i[0])
            node.setText(1, i[1])
            node.setText(2, i[2])
            node.setText(3, i[3])
            node.setText(4, i[4])
            self.serverFileInfo.append(node)

        self.serverPathLineEdit.setText(self.serverPath)

        for i in self.serverFileInfo:
            self.serverFileTable.addTopLevelItem(i)

    def serverFileTreeRefresh(self, item):
        if self.clearFlag == 0:
            self.clearFlag = 1
            return

        path = item.text(0)
        fatherNode = item
        while fatherNode != self.serverFileTreeRoot:
            fatherNode = fatherNode.parent()
            path = fatherNode.text(0) + '/' + path

        path = path[1:] + '/'

        childrenItemList = item.takeChildren()
        for i in childrenItemList:
            item.removeChild(i)
        self.Mutex.acquire()
        fileinfo = self.FTP.getdirinfo(path)

        for i in fileinfo:
            if i[1] == 'Folder':
                node = QTreeWidgetItem(item)
                node.setText(0, i[0])
                tempinfo = self.FTP.getdirinfo(path + i[0])
                for j in tempinfo:
                    if j[1] == 'Folder':
                        tempnode = QTreeWidgetItem(node)
                        tempnode.setText(0, j[0])
                        node.addChild(tempnode)
                item.addChild(node)
        self.Mutex.release()

    def serverFileTreeClicked(self, item, int_p):
        path = item.text(0)
        fatherNode = item
        while fatherNode != self.serverFileTreeRoot:
            fatherNode = fatherNode.parent()
            path = fatherNode.text(0) + '/' + path
        if path != '/':
            self.serverPath = path[1:]
        else:
            self.serverPath = path

        self.serverFileTable.clear()
        self.serverFileInfo.clear()

        if self.serverPath != '/':
            node = QTreeWidgetItem(self.serverFileTable)
            node.setText(0, '..')
            self.serverFileInfo.append(node)

        self.serverFileTableRefresh()

    def serverTableDoubleClicked(self, index):
        if qApp.mouseButtons() == Qt.RightButton:
            return

        if self.serverFileInfo[index.row()].text(1) == 'File':
            return

        if index.row() == 0:
            if self.serverPath == '/':
                self.localPath = self.serverPath + self.serverFileInfo[0].text(
                    0)
            else:
                tempPath = self.serverPath.split('/')[:-1]
                self.serverPath = ''
                for i in tempPath:
                    self.serverPath = self.serverPath + '/' + i
                if self.serverPath != '/':
                    self.serverPath = self.serverPath[1:]
        else:
            self.serverPath = os.path.join(
                self.serverPath, self.serverFileInfo[index.row()].text(0))

        self.serverFileTable.clear()
        self.serverFileInfo.clear()

        if self.serverPath != '/':
            node = QTreeWidgetItem(self.serverFileTable)
            node.setText(0, '..')
            self.serverFileInfo.append(node)

        self.serverFileTableRefresh()

    def serverTableRightClicked(self, item, int_p):
        if item.text(0) == '..':
            return
        if qApp.mouseButtons() == Qt.RightButton:
            serverMenu = QMenu()
            downLoadFile = QAction('download')
            downLoadFolder = QAction('downloadfolder')
            downLoadFile.triggered.connect(self.downloadFile)
            downLoadFolder.triggered.connect(self.downloadFolder)
            if item.text(1) == 'Folder':
                serverMenu.addAction(downLoadFolder)
            else:
                serverMenu.addAction(downLoadFile)

            serverMenu.exec_(QCursor.pos())

    def downloadFile(self):
        filename = self.serverFileTable.selectedItems()[0].text(0)
        self.lock.acquire()
        try:
            self.waitingTaskQueue.append({
                'filename':
                filename,
                'localpath':
                self.localPath,
                'direction':
                '<--',
                'serverpath':
                self.serverPath,
                'filesize':
                self.serverFileTable.selectedItems()[0].text(2)
            })

        finally:
            self.lock.release()
        self.taskQueueRefresh()
        if len(self.downloadingTask) == 0:
            if self.t1 == None:
                self.t1 = threading.Thread(target=self.taskQueueOpertion)
                self.t1.start()
            else:
                if self.t1.is_alive():
                    pass
                else:
                    self.t1 = threading.Thread(target=self.taskQueueOpertion)
                    self.t1.start()

    def downloadFolder(self):
        folderpath = os.path.join(
            self.serverPath,
            self.serverFileTable.selectedItems()[0].text(0))
        if self.localPath == '/':
            os.mkdir('/' + self.serverFileTable.selectedItems()[0].text(0))
        else:
            os.mkdir(self.localPath + '/' +
                     self.serverFileTable.selectedItems()[0].text(0))
        self.Mutex.acquire()
        self.lock.acquire()
        try:
            self.traversalServerDir(folderpath, self.localPath,
                                    self.serverPath)
        except ftplib.error_temp:
            self.reconnect()
            self.traversalServerDir(folderpath, self.localPath,
                                    self.serverPath)
        finally:
            self.lock.release()
        self.Mutex.release()
        self.taskQueueRefresh()
        if len(self.downloadingTask) == 0:
            if self.t1 == None:
                self.t1 = threading.Thread(target=self.taskQueueOpertion)
                self.t1.start()
            else:
                if self.t1.is_alive():
                    pass
                else:
                    self.t1 = threading.Thread(target=self.taskQueueOpertion)
                    self.t1.start()

    def localTreeClicked(self, index):
        if self.localDirModel.fileInfo(index).isDir():
            self.localPath = self.localDirModel.filePath(index)
        else:
            self.localPath = self.localDirModel.filePath(index)
            tempPath = self.localPath.split('/')[:-1]
            self.localPath = ''
            for i in tempPath:
                self.localPath = self.localPath + '/' + i
            if self.localPath != '/':
                self.localPath = self.localPath[1:]

        self.localFileRefesh()

    def localTableDoubleClicked(self, index):
        if qApp.mouseButtons() == Qt.RightButton:
            return

        if os.path.isdir(
                os.path.join(
                    self.localPath,
                    self.localFileTable[index.row()].text(0))) == False:
            return

        if index.row() == 0:
            if self.localPath == '/':
                self.localPath = self.localPath + self.localFileTable[0].text(
                    0)
            else:
                tempPath = self.localPath.split('/')[:-1]
                self.localPath = ''
                for i in tempPath:
                    self.localPath = self.localPath + '/' + i
                if self.localPath != '/':
                    self.localPath = self.localPath[1:]
        else:
            self.localPath = os.path.join(
                self.localPath, self.localFileTable[index.row()].text(0))

        self.localFileRefesh()

    def localTableRightClicked(self, item, int_p):
        if item.text(0) == '..':
            return
        if qApp.mouseButtons() == Qt.RightButton:
            localMenu = QMenu()
            upLoadFile = QAction('upload')
            upLoadFolder = QAction('uploadfolder')
            upLoadFile.triggered.connect(self.uploadFile)
            upLoadFolder.triggered.connect(self.uploadFolder)
            if item.text(2) == 'Folder':
                localMenu.addAction(upLoadFolder)
            else:
                localMenu.addAction(upLoadFile)

            localMenu.exec_(QCursor.pos())

    def uploadFile(self):
        filename = self.localFileTreeWidget.selectedItems()[0].text(0)
        self.lock.acquire()
        try:
            self.waitingTaskQueue.append({
                'filename':
                filename,
                'localpath':
                self.localPath,
                'direction':
                '-->',
                'serverpath':
                self.serverPath,
                'filesize':
                self.localFileTreeWidget.selectedItems()[0].text(1)
            })

        finally:
            self.lock.release()
        self.taskQueueRefresh()
        if len(self.downloadingTask) == 0:
            if self.t1 == None:
                self.t1 = threading.Thread(target=self.taskQueueOpertion)
                self.t1.start()
            else:
                if self.t1.is_alive():
                    pass
                else:
                    self.t1 = threading.Thread(target=self.taskQueueOpertion)
                    self.t1.start()

    def uploadFolder(self):
        folderpath = os.path.join(
            self.localPath,
            self.localFileTreeWidget.selectedItems()[0].text(0))
        self.lock.acquire()
        try:
            self.traversalLocalDir(folderpath, self.localPath, self.serverPath)
        except ftplib.error_temp:
            self.reconnect()
            self.traversalLocalDir(folderpath, self.localPath, self.serverPath)
        finally:
            self.lock.release()
        self.taskQueueRefresh()

        if len(self.downloadingTask) == 0:
            if self.t1 == None:
                self.t1 = threading.Thread(target=self.taskQueueOpertion)
                self.t1.start()
            else:
                if self.t1.is_alive():
                    pass
                else:
                    self.t1 = threading.Thread(target=self.taskQueueOpertion)
                    self.t1.start()

    def taskQueueOpertion(self):

        while len(self.createServerDirQueue) != 0:
            self.FTP.mkd(self.createServerDirQueue[0])
            self.createServerDirQueue.pop(0)

        while len(self.waitingTaskQueue) != 0:
            self.lock.acquire()
            try:
                self.downloadingTask.append(self.waitingTaskQueue[0])
                print('taskadded' + str(self.waitingTaskQueue[0]))
                self.waitingTaskQueue.pop(0)
                print('self.waitingTaskQueue.pop(0)')
            finally:
                self.lock.release()
            print('before self.taskQueueRefresh()')
            self.Mutex.acquire()
            if self.downloadingTask[0]['direction'] == '<--':
                if ' ' in self.downloadingTask[0]['filename']:
                    localName = self.downloadingTask[0]['filename'].replace(
                        ' ', '_')
                else:
                    localName = self.downloadingTask[0]['filename']
                with open(
                        self.downloadingTask[0]['localpath'] + '/' + localName,
                        'wb') as fp:
                    if self.downloadingTask[0]['serverpath'] == '/':
                        tempserverpath = '/' + self.downloadingTask[0][
                            'filename']
                    else:
                        tempserverpath = self.downloadingTask[0][
                            'serverpath'] + '/' + self.downloadingTask[0][
                                'filename']
                    try:
                        self.FTP.retrbinary('RETR ' + tempserverpath, fp.write,
                                            10240)
                    except ftplib.error_temp:
                        self.reconnect()
                        self.FTP.retrbinary('RETR ' + tempserverpath, fp.write,
                                            10240)
                    self.FTP.set_debuglevel(0)
            elif self.downloadingTask[0]['direction'] == '-->':
                if self.downloadingTask[0]['serverpath'] == '/':
                    tempserverpath = '/' + self.downloadingTask[0]['filename']
                else:
                    tempserverpath = self.downloadingTask[0][
                        'serverpath'] + '/' + self.downloadingTask[0][
                            'filename']
                with open(
                        self.downloadingTask[0]['localpath'] + '/' +
                        self.downloadingTask[0]['filename'], 'rb') as fp:
                    try:
                        self.FTP.storbinary('STOR ' + tempserverpath, fp,
                                            10240)
                    except ftplib.error_temp:
                        self.reconnect()
                        self.FTP.storbinary('STOR ' + tempserverpath, fp,
                                            10240)
                    self.FTP.set_debuglevel(0)
            self.Mutex.release()
            self.lock.acquire()
            try:
                self.finishedTaskQueue.insert(0, self.downloadingTask[0])
                print('finish' + str(self.downloadingTask[0]))
                self.downloadingTask.clear()
                print('downloadingTask.clear()')
            finally:
                self.lock.release()

            print('after self.taskQueueRefresh()')

    def startLinkManageDialog(self):
        with open('linkdata.json', 'r') as f:
            self.linkData = json.load(f)
        self.linkManageDialog = QDialog()
        self.linkManageDialog.setModal(True)
        linkManageLayout = QVBoxLayout()
        self.linkManageDialog.setLayout(linkManageLayout)
        self.linkManageDialog.setWindowTitle('连接管理')

        linkDisplayLayout = QHBoxLayout()
        bottomButtomGroupLayout = QHBoxLayout()

        connectButtom = QPushButton('连接')
        confirmButtom = QPushButton('确定')
        cancleButtom = QPushButton('取消')

        bottomButtomGroupLayout.addStretch(1)
        bottomButtomGroupLayout.addWidget(connectButtom)
        bottomButtomGroupLayout.addWidget(confirmButtom)
        bottomButtomGroupLayout.addWidget(cancleButtom)

        linkManageLayout.addLayout(linkDisplayLayout)
        linkManageLayout.addLayout(bottomButtomGroupLayout)

        linkListLayout = QVBoxLayout()
        linkEditLayout = QVBoxLayout()

        linkDisplayLayout.addLayout(linkListLayout)
        linkDisplayLayout.addLayout(linkEditLayout)

        self.linkList = QListWidget()
        addLinkButton = QPushButton('新建')
        removeLinkButton = QPushButton('删除')
        linkManageButtonGroupLayout = QHBoxLayout()
        linkManageButtonGroupLayout.addWidget(addLinkButton)
        linkManageButtonGroupLayout.addWidget(removeLinkButton)

        linkListLayout.addWidget(QLabel('连接列表:'), 0, Qt.AlignTop)
        linkListLayout.addWidget(self.linkList)
        linkListLayout.addLayout(linkManageButtonGroupLayout)

        hBox1 = QHBoxLayout()
        hBox2 = QHBoxLayout()
        hBox3 = QHBoxLayout()
        hBox4 = QHBoxLayout()
        hBox5 = QHBoxLayout()
        hBox6 = QHBoxLayout()

        self.host = QLineEdit()
        self.userName = QLineEdit()
        self.passwd = QLineEdit()
        self.port = QLineEdit()
        self.remark = QLineEdit()
        self.passwd.setEchoMode(QLineEdit.Password)
        self.port.setValidator(QIntValidator(0, 65535))
        self.anonymousLogin = QCheckBox('匿名登录')
        confirmEdit = QPushButton('确定修改')
        confirmEdit.setFixedWidth(80)

        self.anonymousLogin.stateChanged.connect(
            self.linkManageCheckBoxChanged)

        hBox1.addWidget(QLabel('主机:   '))
        hBox1.addWidget(self.host)
        hBox2.addWidget(QLabel('用户名:'))
        hBox2.addWidget(self.userName)
        hBox3.addWidget(QLabel('密码:   '))
        hBox3.addWidget(self.passwd)
        hBox4.addWidget(QLabel('端口:   '))
        hBox4.addWidget(self.port)
        hBox6.addWidget(QLabel('备注:   '))
        hBox6.addWidget(self.remark)
        hBox5.addWidget(self.anonymousLogin)
        hBox5.addWidget(confirmEdit, Qt.AlignRight)

        linkEditLayout.addLayout(hBox1)
        linkEditLayout.addLayout(hBox2)
        linkEditLayout.addLayout(hBox3)
        linkEditLayout.addLayout(hBox4)
        linkEditLayout.addLayout(hBox6)
        linkEditLayout.addLayout(hBox5)

        for key in self.linkData:
            item = QListWidgetItem(self.linkList)
            item.setText(key)

        self.linkList.setCurrentRow(0)
        if len(self.linkData) != 0:
            tempdata = self.linkData[self.linkList.currentItem().text()]

            self.host.setText(tempdata['hostname'])
            self.port.setText(str(tempdata['port']))
            self.remark.setText(tempdata['remark'])
            if tempdata['username'] == 'anonymous':
                self.anonymousLogin.setCheckState(Qt.Checked)
            else:
                self.userName.setText(tempdata['username'])
                self.passwd.setText(tempdata['passwd'])

        cancleButtom.clicked.connect(self.linkManageDialog.close)
        self.linkList.itemClicked.connect(self.listItemClicked)
        addLinkButton.clicked.connect(self.addNewLink)
        confirmEdit.clicked.connect(self.confirmEditLink)
        confirmButtom.clicked.connect(self.saveData)
        removeLinkButton.clicked.connect(self.removeLink)
        connectButtom.clicked.connect(self.connectFromDialog)

        self.linkManageDialog.show()

    def connectFromDialog(self):
        hostName = self.host.text()
        userName = self.userName.text()
        passwd = self.passwd.text()
        port = int(self.port.text())

        try:
            self.aNewConnection(hostName, userName, passwd, port)
        except socket.gaierror:
            QMessageBox.information(self, '主机名错误', '主机名错误,请输入正确的主机名',
                                    QMessageBox.Ok, QMessageBox.Ok)
            return
        except ConnectionRefusedError:
            QMessageBox.information(self, '连接出错', '连接失败,请检查是否输入了正确的主机名或端口',
                                    QMessageBox.Ok, QMessageBox.Ok)
            return
        except ftplib.error_perm:
            QMessageBox.information(self, '登陆出错', '登陆失败,请检查是否输入了正确的用户名或密码',
                                    QMessageBox.Ok, QMessageBox.Ok)
            return
        self.saveData()

    def removeLink(self):
        if len(self.linkData) == 0:
            return

        rowNow = self.linkList.currentRow()
        itemNow = self.linkList.currentItem()

        self.linkData.pop(itemNow.text())
        self.linkList.removeItemWidget(itemNow)

        self.linkList.clear()

        for key in self.linkData:
            item = QListWidgetItem(self.linkList)
            item.setText(key)

        if len(self.linkData) == 0:
            self.host.setText('')
            self.port.setText('')
            self.anonymousLogin.setCheckState(Qt.Unchecked)
            self.userName.setText('')
            self.passwd.setText('')
            self.remark.setText('')
            return
        elif len(self.linkData) < rowNow + 1:
            rowNow = len(self.linkData) - 1
            self.linkList.setCurrentRow(len(self.linkData) - 1)
        else:
            self.linkList.setCurrentRow(rowNow)

        self.listItemClicked(self.linkList.currentItem())

    def saveData(self):
        self.confirmEditLink()
        with open('linkdata.json', 'w') as f:
            json.dump(self.linkData, f)
        self.linkManageDialog.close()

    def confirmEditLink(self):
        hostName = self.host.text()
        userName = self.userName.text()
        passwd = self.passwd.text()
        port = int(self.port.text())
        remark = self.remark.text()

        data = {
            'hostname': hostName,
            'username': userName,
            'passwd': passwd,
            'port': port,
            "remark": remark
        }

        self.linkData.pop(self.linkList.currentItem().text())
        self.linkData[userName + '@' + hostName + ':' + str(port) + ' ' +
                      remark] = data

        self.linkList.clear()

        for key in self.linkData:
            item = QListWidgetItem(self.linkList)
            item.setText(key)

        self.linkList.setCurrentRow(len(self.linkList) - 1)

    def addNewLink(self):
        if '新连接' in self.linkData:
            return
        self.linkData['新连接'] = {
            'hostname': '',
            'username': '',
            'passwd': '',
            'port': '',
            'remark': ''
        }
        item = QListWidgetItem(self.linkList)
        item.setText('新连接')
        self.linkList.setCurrentRow(len(self.linkList) - 1)

        self.host.setText('')
        self.port.setText('21')
        self.anonymousLogin.setCheckState(Qt.Unchecked)
        self.userName.setText('')
        self.passwd.setText('')
        self.remark.setText('')

    def listItemClicked(self, item):
        tempdata = self.linkData[item.text()]

        self.host.setText(tempdata['hostname'])
        self.port.setText(str(tempdata['port']))
        self.remark.setText(tempdata['remark'])
        if tempdata['username'] == 'anonymous':
            self.anonymousLogin.setCheckState(Qt.Checked)
        else:
            self.anonymousLogin.setCheckState(Qt.Unchecked)
            self.userName.setText(tempdata['username'])
            self.passwd.setText(tempdata['passwd'])

    def quickLinkCheckBoxChanged(self):
        if self.anonymousLoginCheckBox.checkState() == Qt.Checked:
            self.userNameInput.setText('anonymous')
            self.passwdInput.setText('')
            self.userNameInput.setEnabled(False)
            self.passwdInput.setEnabled(False)
        elif self.anonymousLoginCheckBox.checkState() == Qt.Unchecked:
            self.userNameInput.setText('')
            self.passwdInput.setText('')
            self.userNameInput.setEnabled(True)
            self.passwdInput.setEnabled(True)

    def linkManageCheckBoxChanged(self):
        if self.anonymousLogin.checkState() == Qt.Checked:
            self.userName.setText('anonymous')
            self.passwd.setText('')
            self.userName.setEnabled(False)
            self.passwd.setEnabled(False)
        elif self.anonymousLogin.checkState() == Qt.Unchecked:
            self.userName.setText('')
            self.passwd.setText('')
            self.userName.setEnabled(True)
            self.passwd.setEnabled(True)

    def aNewConnection(self, host, username, passwd, port):
        if self.FTP != None:
            try:
                self.FTP.quit()
            except AttributeError:
                pass
            except EOFError:
                pass
        self.FTP = myFtp()
        self.FTP.set_pasv(True)
        self.connectionNow['hostname'] = host
        self.connectionNow['username'] = username
        self.connectionNow['passwd'] = passwd
        self.connectionNow['port'] = port
        self.FTP.connect(host, port)
        self.FTP.login(username, passwd)

        self.serverFileInfo = []
        self.serverPath = '/'
        self.serverFileTable.clear()
        self.serverFileTree.clear()

        self.serverFileTreeRoot = QTreeWidgetItem(self.serverFileTree)
        self.serverFileTreeRoot.setText(0, '/')
        self.serverFileTree.addTopLevelItem(self.serverFileTreeRoot)

        self.Mutex.acquire()
        fileinfo = self.FTP.getdirinfo(self.serverPath)

        for i in fileinfo:
            if i[1] == 'Folder':
                node = QTreeWidgetItem(self.serverFileTreeRoot)
                node.setText(0, i[0])
                tempinfo = self.FTP.getdirinfo(self.serverPath + i[0])
                for j in tempinfo:
                    if j[1] == 'Folder':
                        tempnode = QTreeWidgetItem(node)
                        tempnode.setText(0, j[0])
                        node.addChild(tempnode)
                self.serverFileTreeRoot.addChild(node)
        self.Mutex.release()

        self.serverFileTreeRoot.setExpanded(True)

        self.serverFileTableRefresh()

        if self.timer.isActive():
            self.timer.disconnect()

        self.timer.timeout.connect(self.taskQueueRefresh)
        self.timer.start(500)

    def reconnect(self):
        self.FTP.connect(self.connectionNow['hostname'],
                         self.connectionNow['port'])
        self.FTP.login(self.connectionNow['username'],
                       self.connectionNow['passwd'])

    def taskQueueRefresh(self):
        self.lock.acquire()
        try:
            self.taskQueueTreeWidget.clear()
            if len(self.downloadingTask) != 0:
                node = QTreeWidgetItem(self.taskQueueTreeWidget)
                node.setText(0, self.downloadingTask[0]['filename'])
                node.setText(1, self.downloadingTask[0]['localpath'])
                node.setText(2, self.downloadingTask[0]['direction'])
                node.setText(3, self.downloadingTask[0]['serverpath'])
                node.setText(4, self.downloadingTask[0]['filesize'])
                node.setText(5, '正在传输')
                self.taskQueueTreeWidget.addTopLevelItem(node)

            for i in self.waitingTaskQueue:
                node = QTreeWidgetItem(self.taskQueueTreeWidget)
                node.setText(0, i['filename'])
                node.setText(1, i['localpath'])
                node.setText(2, i['direction'])
                node.setText(3, i['serverpath'])
                node.setText(4, i['filesize'])
                node.setText(5, '等待传输')
                self.taskQueueTreeWidget.addTopLevelItem(node)

            for i in self.finishedTaskQueue:
                node = QTreeWidgetItem(self.taskQueueTreeWidget)
                node.setText(0, i['filename'])
                node.setText(1, i['localpath'])
                node.setText(2, i['direction'])
                node.setText(3, i['serverpath'])
                node.setText(4, i['filesize'])
                node.setText(5, '传输完成')
                self.taskQueueTreeWidget.addTopLevelItem(node)

        finally:
            self.lock.release()

    def tableRefresh(self):
        if self.connectionNow['hostname'] != '':
            self.serverFileTable.clear()
            self.serverFileInfo.clear()

            if self.serverPath != '/':
                node = QTreeWidgetItem(self.serverFileTable)
                node.setText(0, '..')
                self.serverFileInfo.append(node)

            self.serverFileTableRefresh()

        self.localFileRefesh()

    def traversalLocalDir(self, dir, localpath, serverpath):
        fs = os.listdir(dir)
        for i in fs:
            temppath = os.path.join(dir, i)
            if os.path.isdir(temppath) == False:
                if serverpath == '/' and localpath == '/':
                    print(i + ' ' + dir + ' ' + dir + ' ' +
                          str(os.path.getsize(temppath)))
                    self.waitingTaskQueue.append({
                        'filename':
                        i,
                        'localpath':
                        dir,
                        'direction':
                        '-->',
                        'serverpath':
                        dir,
                        'filesize':
                        str(os.path.getsize(temppath))
                    })
                elif serverpath == '/':
                    self.waitingTaskQueue.append({
                        'filename':
                        i,
                        'localpath':
                        dir,
                        'direction':
                        '-->',
                        'serverpath':
                        dir[len(localpath):],
                        'filesize':
                        str(os.path.getsize(temppath))
                    })
                    print(i + ' ' + dir + ' ' + dir[len(localpath):] + ' ' +
                          str(os.path.getsize(temppath)))
                elif localpath == '/':
                    self.waitingTaskQueue.append({
                        'filename':
                        i,
                        'localpath':
                        dir,
                        'direction':
                        '-->',
                        'serverpath':
                        serverpath + dir,
                        'filesize':
                        str(os.path.getsize(temppath))
                    })
                    print(i + ' ' + dir + ' ' + serverpath + dir + ' ' +
                          str(os.path.getsize(temppath)))
                else:
                    self.waitingTaskQueue.append({
                        'filename':
                        i,
                        'localpath':
                        dir,
                        'direction':
                        '-->',
                        'serverpath':
                        serverpath + dir[len(localpath):],
                        'filesize':
                        str(os.path.getsize(temppath))
                    })
                    print(i + ' ' + dir + ' ' + serverpath +
                          dir[len(localpath):] + ' ' +
                          str(os.path.getsize(temppath)))
            else:
                if serverpath == '/' and localpath == '/':
                    print(i + ' ' + temppath + ' ' + temppath)
                    self.createServerDirQueue.append(temppath)
                elif serverpath == '/':
                    print(i + ' ' + temppath + ' ' + temppath[len(localpath):])
                    self.createServerDirQueue.append(temppath[len(localpath):])
                elif localpath == '/':
                    print(i + ' ' + temppath + ' ' + serverpath + temppath)
                    self.createServerDirQueue.append(serverpath + temppath)
                else:
                    print(i + ' ' + temppath + ' ' + serverpath +
                          temppath[len(localpath):])
                    self.createServerDirQueue.append(serverpath +
                                                     temppath[len(localpath):])
                self.traversalLocalDir(temppath, localpath, serverpath)

    def traversalServerDir(self, dir, localpath, serverpath):
        fs = self.FTP.getdirinfo(dir)
        for i in fs:
            temppath = os.path.join(dir, i[0])
            if i[1] == 'File':
                if serverpath == '/' and localpath == '/':
                    print(i[0] + ' ' + dir + ' ' + dir + ' ' + i[2])
                    self.waitingTaskQueue.append({
                        'filename': i[0],
                        'localpath': dir,
                        'direction': '<--',
                        'serverpath': dir,
                        'filesize': i[2]
                    })
                elif serverpath == '/':
                    self.waitingTaskQueue.append({
                        'filename': i[0],
                        'localpath': localpath + dir,
                        'direction': '<--',
                        'serverpath': dir,
                        'filesize': i[2]
                    })
                    print(i[0] + ' ' + localpath + dir + ' ' + dir + ' ' +
                          i[2])
                elif localpath == '/':
                    self.waitingTaskQueue.append({
                        'filename':
                        i[0],
                        'localpath':
                        dir[len(serverpath):],
                        'direction':
                        '<--',
                        'serverpath':
                        dir,
                        'filesize':
                        i[2]
                    })
                    print(i[0] + ' ' + dir[len(serverpath):] + ' ' + dir +
                          ' ' + i[2])
                else:
                    self.waitingTaskQueue.append({
                        'filename':
                        i[0],
                        'localpath':
                        localpath + dir[len(serverpath):],
                        'direction':
                        '<--',
                        'serverpath':
                        dir,
                        'filesize':
                        i[2]
                    })
                    print(i[0] + ' ' + localpath + dir[len(serverpath):] +
                          ' ' + dir + ' ' + i[2])
            else:
                if serverpath == '/' and localpath == '/':
                    print(i[0] + ' ' + temppath + ' ' + temppath)
                    os.makedirs(temppath)
                elif serverpath == '/':
                    print(i[0] + ' ' + localpath + temppath + ' ' + temppath)
                    os.makedirs(localpath + temppath)
                elif localpath == '/':
                    print(i[0] + ' ' + temppath[len(serverpath):] + ' ' +
                          temppath)
                    os.makedirs(temppath[len(serverpath):])
                else:
                    print(i[0] + ' ' + localpath + temppath[len(serverpath):] +
                          ' ' + temppath)
                    os.makedirs(localpath + temppath[len(serverpath):])
                self.traversalServerDir(temppath, localpath, serverpath)