예제 #1
0
class Timer():
    def __init__(self):
        self.time = QTime()
        self.time.start()
        self.cur_time = timedelta(milliseconds=self.time.elapsed())
        # self.stop_time = self.time.
        # self.cur_time = self.stop_time - self.time

    def update_elapsed_time(self):
        self.cur_time = timedelta(milliseconds=self.time.elapsed())
예제 #2
0
파일: main.py 프로젝트: zsp00/dy
    def startPro(self):
        print("startPro")
        task_list = IM.getLocalTask(self)
        queue = Queue()
        for task in task_list:
            queue.put(task)

        self.pool.setMaxThreadCount(int(self.spinBoxProNum.value()))
        while True:
            if queue.empty():
                print("备份队列为空")
                task = None
            else:
                print("取备份任务")
                bak_info = queue.get_nowait()
                task = Task()
                task.task_info = json.loads(bak_info.get("task_info"))
                task.user_info = json.loads(bak_info.get("user_info"))
                task.uids = json.loads(
                    bak_info.get("uids")) if bak_info.get("uids") else None
                task.status = 1

                othread = mThread()
                othread.transfer(task=task, communicate=self.communicate)

                def setStatus(items):
                    self.model.item(items["index"], 4).setText(items["status"])

                self.communicate.connect(setStatus)
                self.pool.start(othread)
            time = QTime()
            time.start()
            while time.elapsed() < 5000:
                QCoreApplication.processEvents()
예제 #3
0
    def readUntil(self, expected=b"\n", size=None):
        r"""
        Public method to read data until an expected sequence is found
        (default: \n) or a specific size is exceeded.
        
        @param expected expected bytes sequence
        @type bytes
        @param size maximum data to be read
        @type int
        @return bytes read from the device including the expected sequence
        @rtype bytes
        """
        data = bytearray()
        self.__timedOut = False

        t = QTime()
        t.start()
        while True:
            QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
            c = bytes(self.read(1))
            if c:
                data += c
                if data.endswith(expected):
                    break
                if size is not None and len(data) >= size:
                    break
            if t.elapsed() > self.__timeout:
                self.__timedOut = True
                break

        return bytes(data)
예제 #4
0
파일: main.py 프로젝트: emslGit/qtapp
class Controller:
    def __init__(self):
        self.qt_app = QApplication(sys.argv)
        self.model = Model()
        self.view = View()
        self.view.button.clicked.connect(self.update_model)
        self.model.signal.connect(self.update_view)

        signal.signal(signal.SIGINT, self.keyboardInterruptHandler)
        self.time = QTime()
        timer = QTimer()
        timer.timeout.connect(lambda: None)
        timer.start(100)

        self.qt_app.exec()

    def update_model(self):
        self.time.start()
        self.model.setdata(self.view.getdata())

    def update_view(self):
        print("--- DONE IN {}ms ---".format(self.time.elapsed()))
        self.time.restart()
        self.view.setdata(self.model.getdata())

    def keyboardInterruptHandler(self, signal, frame):
        self.qt_app.exit()
예제 #5
0
class DigitalClock(QLCDNumber):
    def __init__(self):
        super(DigitalClock, self).__init__(8)
        self.setSegmentStyle(QLCDNumber.Filled)
        self.timer = QTimer()
        self.timer.timeout.connect(self.showTime)
        self.time = QTime(0, 0, 0)
        text = self.time.toString("hh:mm:ss")
        self.display(text)

    def start(self):
        self.time = QTime(0, 0, 0)
        self.time.start()
        self.timer.start(1000)

    def stop(self):
        self.timer.stop()

    @pyqtSlot()
    def showTime(self):
        # print(self.time.elapsed())
        tt = QTime(0, 0, 0)
        tt = tt.addMSecs(self.time.elapsed())
        text = tt.toString("hh:mm:ss")
        # print(text)
        self.display(text)
예제 #6
0
    def on_btnProgress_clicked(self):
        labText = "正在复制文件..."  #文字信息
        btnText = "取消"  #"取消"按钮的标题
        minV = 0
        maxV = 200
        dlgProgress = QProgressDialog(labText, btnText, minV, maxV, self)
        dlgProgress.canceled.connect(self.do_progress_canceled)  #canceled信号

        dlgProgress.setWindowTitle("复制文件")
        dlgProgress.setWindowModality(Qt.WindowModal)  #模态对话框

        dlgProgress.setAutoReset(
            True)  #calls reset() as soon as value() equals maximum()
        dlgProgress.setAutoClose(
            True)  #whether the dialog gets hidden by reset()

        msCounter = QTime()  #计时器
        for i in range(minV, maxV + 1):
            dlgProgress.setValue(i)
            dlgProgress.setLabelText("正在复制文件,第 %d 个" % i)

            msCounter.start()  #计时器重新开始
            while (msCounter.elapsed() < 30):  #延时 30ms
                None

            if (dlgProgress.wasCanceled()):  #中途取消
                break
예제 #7
0
class AutoSaver(QObject):
    """
    Class implementing the auto saver.
    """
    AUTOSAVE_IN = 1000 * 3
    MAXWAIT = 1000 * 15
    
    def __init__(self, parent, save):
        """
        Constructor
        
        @param parent reference to the parent object (QObject)
        @param save slot to be called to perform the save operation
        @exception RuntimeError raised, if no parent is given
        """
        super(AutoSaver, self).__init__(parent)
        
        if parent is None:
            raise RuntimeError("AutoSaver: parent must not be None.")
        
        self.__save = save
        
        self.__timer = QBasicTimer()
        self.__firstChange = QTime()
    
    def changeOccurred(self):
        """
        Public slot handling a change.
        """
        if self.__firstChange.isNull():
            self.__firstChange.start()
        
        if self.__firstChange.elapsed() > self.MAXWAIT:
            self.saveIfNeccessary()
        else:
            self.__timer.start(self.AUTOSAVE_IN, self)
    
    def timerEvent(self, evt):
        """
        Protected method handling timer events.
        
        @param evt reference to the timer event (QTimerEvent)
        """
        if evt.timerId() == self.__timer.timerId():
            self.saveIfNeccessary()
        else:
            super(AutoSaver, self).timerEvent(evt)
    
    def saveIfNeccessary(self):
        """
        Public method to activate the save operation.
        """
        if not self.__timer.isActive():
            return
        
        self.__timer.stop()
        self.__firstChange = QTime()
        self.__save()
예제 #8
0
class AutoSaver(QObject):
    """
    Class implementing the auto saver.
    """
    AUTOSAVE_IN = 1000 * 3
    MAXWAIT = 1000 * 15

    def __init__(self, parent, save):
        """
        Constructor
        
        @param parent reference to the parent object (QObject)
        @param save slot to be called to perform the save operation
        @exception RuntimeError raised, if no parent is given
        """
        super(AutoSaver, self).__init__(parent)

        if parent is None:
            raise RuntimeError("AutoSaver: parent must not be None.")

        self.__save = save

        self.__timer = QBasicTimer()
        self.__firstChange = QTime()

    def changeOccurred(self):
        """
        Public slot handling a change.
        """
        if self.__firstChange.isNull():
            self.__firstChange.start()

        if self.__firstChange.elapsed() > self.MAXWAIT:
            self.saveIfNeccessary()
        else:
            self.__timer.start(self.AUTOSAVE_IN, self)

    def timerEvent(self, evt):
        """
        Protected method handling timer events.
        
        @param evt reference to the timer event (QTimerEvent)
        """
        if evt.timerId() == self.__timer.timerId():
            self.saveIfNeccessary()
        else:
            super(AutoSaver, self).timerEvent(evt)

    def saveIfNeccessary(self):
        """
        Public method to activate the save operation.
        """
        if not self.__timer.isActive():
            return

        self.__timer.stop()
        self.__firstChange = QTime()
        self.__save()
예제 #9
0
    def _run_hid(self):
        runner_started_at = QTime()
        runner_started_at.start()
        auto_restart = False
        self._running = True
        try:
            h = self._hidapi.device()
            if self._hid_dev["path"]:
                Logger.log("d", "Trying to open %s",
                           self._hid_dev["path"].decode("utf-8"))
                h.open_path(self._hid_dev["path"])
            else:
                Logger.log("d", "Trying to open [%x,%x]",
                           self._hid_dev["vendor_id"],
                           self._hid_dev["product_id"])
                h.open(self._hid_dev["vendor_id"], self._hid_dev["product_id"])

            Logger.log("i", "Manufacturer: %s", h.get_manufacturer_string())
            Logger.log("i", "Product: %s", h.get_product_string())
            #Logger.log("i", "Serial No: %s", h.get_serial_number_string())

            self._last_camera_update_at = QTime()
            self._last_camera_update_at.start()
            self._fast_view = False
            while self._running:
                if self._main_window:
                    d = h.read(64, 50 if self._fast_view else 1000)
                    if d:
                        if self._main_window.isActive():
                            self._decoder(d)
                    elif self._fast_view:
                        self._controller.setActiveView("SimulationView")
                        self._fast_view = False
                else:
                    self._getComponents()
                    time.sleep(0.1)
            h.close()
        except IOError as e:
            Logger.log("e", "IOError while reading HID events: %s", e)
            auto_restart = (sys.platform == "win32")
        except Exception as e:
            Logger.log("e", "Exception while reading HID events: %s", e)
        self._running = False
        if auto_restart:
            # throttle restarts to avoid hogging the CPU
            min_restart_seconds = 5
            run_time = runner_started_at.elapsed() / 1000
            if run_time < min_restart_seconds:
                Logger.log("d", "Delaying restart...")
                time.sleep(min_restart_seconds - run_time)
            if not self._running:
                self._runner = None
                self._restart()
        else:
            self._runner = None
예제 #10
0
    def receive(self) -> str:
        time = QTime()
        time.start()

        data = ""
        while time.elapsed() <= self.long_timeout:
            if not self.waitForReadyRead(self.short_timeout):
                break
            line = str(bytes(self.readAll()).decode())

            # if line == "":
            #     break

            data += line

        return data
예제 #11
0
class QmyWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)  #调用父类构造函数,创建窗体
        self.ui = Ui_Widget()  #创建UI对象
        self.ui.setupUi(self)  #构造UI界面

        self.timer = QTimer()  #创建定时器
        self.timer.stop()  #停止
        self.timer.setInterval(1000)  #定时周期1000ms
        self.timer.timeout.connect(self.do_timer_timeout)

        self.counter = QTime()  #创建计时器

##  =========由connectSlotsByName() 自动连接的槽函数=============

    def on_btnStart_clicked(self):  ##“开始”按钮
        self.timer.start()  #开始定时
        self.counter.start()  #开始计时

        self.ui.btnStart.setEnabled(False)
        self.ui.btnStop.setEnabled(True)
        self.ui.btnSetIntv.setEnabled(False)

    def on_btnSetIntv_clicked(self):  ##设置定时器的周期
        self.timer.setInterval(self.ui.spinBoxIntv.value())

    def on_btnStop_clicked(self):  ##“停止”按钮
        self.timer.stop()  #定时器停止
        tmMs = self.counter.elapsed()  #计时器流逝的毫秒数

        ms = tmMs % 1000  #取余数,毫秒
        sec = tmMs / 1000  #整秒
        timeStr = "流逝的时间:%d 秒,%d 毫秒" % (sec, ms)
        self.ui.LabElapsedTime.setText(timeStr)

        self.ui.btnStart.setEnabled(True)
        self.ui.btnStop.setEnabled(False)
        self.ui.btnSetIntv.setEnabled(True)

##  ==========自定义槽函数==================================

    def do_timer_timeout(self):  ##定时中断响应
        curTime = QTime.currentTime()  #获取当前时间
        self.ui.LCDHour.display(curTime.hour())
        self.ui.LCDMin.display(curTime.minute())
        self.ui.LCDSec.display(curTime.second())
예제 #12
0
class QmyWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)  #调用父类构造函数,创建窗体
        self.ui = Ui_Widget()  #创建Ui对象
        self.ui.setupUi(self)  #构造UI

        self.timer = QTimer()  #创建定时器
        self.timer.stop()
        self.timer.setInterval(100)  #设定周期
        self.timer.timeout.connect(self.do_timer_timeout)
        self.counter = QTime()

    ##==========自定义功能函数==========

    ##==========事件处理函数===========

    ##==========由connectSlotsByName()自动关联的槽函数====
    def on_btnStart_clicked(self):
        self.timer.start()
        self.counter.start()
        self.ui.btnStart.setEnabled(False)
        self.ui.btnStop.setEnabled(True)
        self.ui.btnSetIntv.setEnabled(False)

    def on_btnStop_clicked(self):
        self.timer.stop()
        tmMs = self.counter.elapsed()  #计时器经过的时间
        ms = tmMs % 1000  #毫秒
        sec = tmMs / 1000  #秒
        timeStr = "经过的时间:{}秒,{}毫秒".format(sec, ms)
        self.ui.LabElapsedTime.setText(timeStr)
        self.ui.btnStart.setEnabled(True)
        self.ui.btnStop.setEnabled(False)
        self.ui.btnSetIntv.setEnabled(True)

    def on_btnSetIntv_clicked(self):
        self.timer.setInterval(self.ui.spinBoxIntv.value())

    ##=========自定义槽函数============
    def do_timer_timeout(self, ):
        curTime = QTime.currentTime()
        self.ui.LCDHour.display(curTime.hour())
        self.ui.LCDMin.display(curTime.minute())
        self.ui.LCDSec.display(curTime.second())
예제 #13
0
def fill_polygon(win):
    t = QTime()
    pix = QPixmap()
    p = QPainter()

    t.start()
    xm = int(find_max_x(win.edges))
    p.begin(win.image)

    for ed in win.edges:
        x1, y1 = ed[0], ed[1]
        x2, y2 = ed[2], ed[3]

        if y1 == y2:
            continue

        if y1 > y2:
            y1, y2 = y2, y1
            x1, x2 = x2, x1

        cur_y = y1
        end_y = y2
        dx = (x2 - x1) / (y2 - y1)
        start_x = x1

        while cur_y < end_y:
            x = start_x
            while x < xm:
                activate_pixel(win, p, x, cur_y)
                p.drawPoint(x, cur_y)
                x += 1

            start_x += dx
            cur_y += 1
            if win.delay.isChecked():
                delay(win, pix)

        pix.convertFromImage(win.image)
        win.scene.addPixmap(pix)
    p.end()
    displaytime(win, t.elapsed())
    draw_edges(win.image, win.edges)
예제 #14
0
파일: my0601.py 프로젝트: falomsc/pyqtStudy
    def on_qPushButton7_clicked(self):
        labText = "正在复制文件..."
        btnText = "取消"
        minV = 0
        maxV = 200
        dlgProgress = QProgressDialog(labText, btnText, minV, maxV, self)
        dlgProgress.canceled.connect(self.do_progress_cancled)

        dlgProgress.setWindowTitle("复制文件")
        dlgProgress.setWindowModality(Qt.WindowModal)
        dlgProgress.setAutoReset(True)
        dlgProgress.setAutoClose(True)

        msCounter = QTime()
        for i in range(minV, maxV + 1):
            dlgProgress.setValue(i)
            dlgProgress.setLabelText("正在复制文件,第 %d 个" % i)
            msCounter.start()
            while (msCounter.elapsed() < 30):
                None
            if (dlgProgress.wasCanceled()):
                break
예제 #15
0
    def on_btn2_1_click(self):
        video = cv2.VideoCapture('D:/data/bgSub.mp4')

        if not video.isOpened():
            print('video not found')
            return

        w = None
        subtractor = cv2.createBackgroundSubtractorMOG2()#detectShadows=False)
        t = QTime()

        t.start()

        while video.isOpened():
            ret, frame = video.read()

            if ret:
                fg = subtractor.apply(frame)

                if w is None:
                    w = MultiImageWindow(
                        title='2.1 Background Subtraction', images=[frame, fg])
                    w.show()

                    self.addWidget(w)
                else:
                    w.setImage(frame, 0)
                    w.setImage(fg, 1)
                    w.update()

                t.restart()

                while t.elapsed() < 33:
                    QApplication.processEvents()
            else:
                break

        video.release()
예제 #16
0
class QmyWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self._ui = Ui_Widget()
        self._ui.setupUi(self)

        self._timer = QTimer()
        self._timer.stop()
        self._timer.setInterval(1000)
        self._timer.timeout.connect(self.my_timer_timeout)
        self._counter = QTime()

    def on_pushButton_Start_clicked(self):
        self._timer.start()
        self._counter.start()
        self._ui.pushButton_Start.setEnabled(False)
        self._ui.pushButton_Stop.setEnabled(True)
        self._ui.pushButton_SetTime.setEnabled(False)

    def on_pushButton_Stop_clicked(self):
        self._timer.stop()
        tms = self._counter.elapsed()
        ms = tms % 1000
        sec = tms / 1000
        timerstr = f'当前经过时间:{sec}s {ms}ms'
        self._ui.label_Reduce.setText(timerstr)
        self._ui.pushButton_Start.setEnabled(True)
        self._ui.pushButton_Stop.setEnabled(False)
        self._ui.pushButton_SetTime.setEnabled(True)

    def on_pushButton_SetTime_clicked(self):
        self._timer.setInterval(self._ui.timeEdit.value())

    def my_timer_timeout(self):
        curTime = QTime.currentTime()
        self._ui.lcdNumber_Hour.display(curTime.hour())
        self._ui.lcdNumber_Minute.display(curTime.minute())
        self._ui.lcdNumber_Second.display(curTime.second())
예제 #17
0
class QmyWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_Widget()
        self.ui.setupUi(self)

        self.timer = QTimer()
        self.timer.stop()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.do_timer_timeout)
        self.count = QTime()

    def on_qPushButton1_clicked(self):
        self.timer.start()
        self.count.start()
        self.ui.qPushButton1.setEnabled(False)
        self.ui.qPushButton2.setEnabled(True)
        self.ui.qPushButton3.setEnabled(False)

    def on_qPushButton2_clicked(self):
        self.timer.stop()
        tm = self.count.elapsed()
        ms = tm % 1000
        s = tm // 1000
        self.ui.qLabel.setText("流逝的时间:%d秒 %d毫秒" % (s, ms))
        self.ui.qPushButton1.setEnabled(True)
        self.ui.qPushButton2.setEnabled(False)
        self.ui.qPushButton3.setEnabled(True)

    def on_qPushButton3_clicked(self):
        self.timer.setInterval(self.ui.qSpinBox.value())

    def do_timer_timeout(self):
        curTime = QTime.currentTime()
        self.ui.qLCDNumber1.display(curTime.hour())
        self.ui.qLCDNumber2.display(curTime.minute())
        self.ui.qLCDNumber3.display(curTime.second())
예제 #18
0
class MySimpleTimer(QtWidgets.QLabel):
    def __init__(self):
        super(MySimpleTimer, self).__init__()

        self.time = QTime(
        )  # we set the clock to 0; otherwise it'll copy the computer time
        # format = h, m, s, msec
        self.time.start()  # starting up the clock!

        timer = QTimer(self)  # when 1000 msec expires; to something & refresh
        timer.timeout.connect(self.update_seconds)
        timer.start(1000)
        self.update_seconds()  #so things don't look fishy?

    def update_seconds(self):

        elapsed_seconds, _ = divmod(self.time.elapsed(), 1000)
        m, s = divmod(elapsed_seconds, 60)
        h, m = divmod(m, 60)
        to_print_str = (f'{m:02d}:{s:02d}')  # Python 3.6+
        if h > 0:
            to_print_str = (f'{h:02d}:{m:02d}:{s:02d}')  # Python 3.6+

        self.setText(to_print_str)
예제 #19
0
class TcpS(QDialog, Ui_TcpServer):
    """
    文件传输服务器
    """

    sendFileName = pyqtSignal(str)

    def __init__(self, parent=None):
        """
        一些初始设置
        """
        super(TcpS, self).__init__(parent)
        self.setupUi(self)
        self.payloadSize = 64 * 1024
        # 读取数据64KB

        self.totalBytes = 0
        # 总大小

        self.bytesWritten = 0
        # 保存的数据

        self.bytesToWrite = 0
        # 每次减少连接写的数据量大小

        self.theFileName = ""
        # 文件名(不含路径)

        self.fileName = ""
        # 文件全名

        self.localFile = QFile()
        self.outBlock = QByteArray()
        # QByteArray()的对象,即字节数组

        self.time = QTime()
        self.initServer()

    def initServer(self):
        """
        网络设置初始化
        """
        self.tcpPort = 7788
        # 指定了TCP端口为7788

        self.tcpServer = QTcpServer(self)
        self.clientConnection = QTcpSocket(self)
        # 创建一个Tcp服务器和一个Tcp套接字

        self.tcpServer.newConnection.connect(self.sendMessage)
        # 当有新的连接来的时候发出newConnection信号,我们连接到sendMessage()函数。

        self.serverStatuslabel.setText("请选择要传送的文件")
        self.progressBar.reset()
        self.serverOpenBtn.setEnabled(True)
        self.serverSendBtn.setEnabled(False)
        self.tcpServer.close()
        # 显示我们开始创建的对话框,打开按钮是可用的,发送按钮是不可用的,进度条复位,先关闭服务器。

    def refused(self):
        """
        对端拒绝接收文件,主程序会调用服务器的refused()函数,关闭服务器。
        """
        self.tcpServer.close()
        self.serverStatuslabel.setText("对方拒绝接收")

    def closeEvent(self, event):
        """
        关闭事件
        """
        self.on_serverCloseBtn_clicked()
        # 产生关闭事件,直接调用关闭窗口按钮函数。

    def sendMessage(self):
        """
        发送文件
        """
        self.serverSendBtn.setEnabled(False)
        # 发送按钮不可用

        self.clientConnection = self.tcpServer.nextPendingConnection()
        # self.clientConnection作为连接的QTcpSocket对象返回下一个挂起的连接。

        self.clientConnection.bytesWritten.connect(self.updateClientProgress)
        # 当连接中每次将数据有效载荷写入设备的当前写通道时,都会发出此信号。在此有效负载中写入的数据量为字节数。

        self.serverStatuslabel.setText("开始传送文件 {} !".format(self.theFileName))

        self.localFile = QFile(self.fileName)
        if not (self.localFile.open(QFile.ReadOnly)):
            errorMsg = "无法读取文件 {}:\n {}".format(self.fileName,
                                                self.localFile.errorString())
            QMessageBox.warning(self, "应用程序", errorMsg)
            return
        # 尝试打开文件,要是存在问题就报错。

        self.serverCloseBtn.setText("取消")

        self.totalBytes = self.localFile.size()
        # 记录一下需要传输的文件大小。单位:字节

        sendOut = QDataStream(self.outBlock, QIODevice.WriteOnly)
        # 这里的self.outBlock是QByteArray()的对象,即字节数组;QIODevice的模式为WriteOnly

        sendOut.setVersion(QDataStream.Qt_5_4)
        # 设定QDataStream的版本为Qt_5_4

        self.time.start()
        # 开始计时

        currentFile = self.fileName.split("/")[-1]
        # 传输的文件名

        sendOut.writeInt64(0)
        sendOut.writeInt64(0)
        sendOut.writeQString(currentFile)
        self.totalBytes += self.outBlock.size()
        # 在sendOut中写入文件名以及文件名和文件的大小,大小都是以字节为单位的。

        sendOut.device().seek(0)
        sendOut.writeInt64(self.totalBytes)
        sendOut.writeInt64(self.outBlock.size() - 2)
        # QIODevice读写位置移动到0。然后分别写入总的大小和文件名大小。

        self.bytesToWrite = self.totalBytes - self.clientConnection.write(
            self.outBlock)
        # 待传输文件的大小。

        self.outBlock.resize(0)
        # outBlock清零。

    def updateClientProgress(self, numBytes):
        """
        发送进度显示
        """
        qApp.processEvents()
        # 长时间工作用,以免窗口假死

        self.bytesWritten += numBytes
        if self.bytesWritten > 0:
            self.block = self.localFile.read(
                min(self.bytesToWrite, self.payloadSize))
            self.bytesToWrite -= self.clientConnection.write(self.block)
        else:
            self.localFile.close()
        # 当我们待写入的字节数大于0时,我们每次读取的数据都是小于等于self.payloadSize的,这个self.payloadSize我们定义是64KB。
        # self.bytesToWrite每次减少连接写的数据量大小。
        # 要是待写入的字节数小于等于0,则关闭文件。

        byteSent = self.bytesWritten / (1024 * 1024)
        # 已经写了多少文件
        useTime = self.time.elapsed() / 1000
        # 传输用了多长时间
        speed = self.bytesWritten / useTime / (1024 * 1024)
        # 传输速度
        total = self.totalBytes / (1024 * 1024)
        # 总大小
        left = (total - byteSent) / speed
        # 表示剩余时间

        if byteSent < 0.01:
            byteSent = self.bytesWritten / 1024
            speed = self.bytesWritten / useTime / 1024
            total = self.totalBytes / 1024
            if left > 0:
                sendInfo = "已发送 {0:.2f}KB({1:.2f}KB/s)\n共{2:.2f}KB 已用时:{3:.1f}秒\n 估计剩余时间:{4:.1f}秒".format(
                    byteSent, speed, total, useTime, left)
            else:
                sendInfo = "已发送 {0:.2f}KB({1:.2f}KB/s)\n共{2:.2f}KB 用时:{3:.1f}秒\n".format(
                    byteSent, speed, total, useTime)
        else:
            if left > 0:
                sendInfo = "已发送 {0:.2f}MB({1:.2f}MB/s)\n共{2:.2f}MB 已用时:{3:.1f}秒\n 估计剩余时间:{4:.1f}秒".format(
                    byteSent, speed, total, useTime, left)
            else:
                sendInfo = "已发送 {0:.2f}MB({1:.2f}MB/s)\n共{2:.2f}MB 用时:{3:.1f}秒\n".format(
                    byteSent, speed, total, useTime)

        self.progressBar.setMaximum(total)
        self.progressBar.setValue(byteSent)

        if self.bytesWritten == self.totalBytes:
            self.serverCloseBtn.setText("关闭")
        # 进度条显示的方式,以及当传输的字节数等于总的字节数的时候,按钮就显示关闭。

        self.serverStatuslabel.setText(sendInfo)

    @pyqtSlot()
    def on_serverOpenBtn_clicked(self):
        """
        打开文件准备发送
        """
        self.fileName = QFileDialog.getOpenFileName(self, '打开文件', './')[0]
        if self.fileName:
            self.theFileName = self.fileName.split("/")[-1]
            self.serverStatuslabel.setText("要传送的文件为:{}".format(
                self.theFileName))
            self.serverSendBtn.setEnabled(True)
            self.serverOpenBtn.setEnabled(False)

    @pyqtSlot()
    def on_serverSendBtn_clicked(self):
        """
        发送文件,等待接收
        """
        if not (self.tcpServer.listen(QHostAddress.Any, self.tcpPort)):
            errorMsg = self.tcpServer.errorString()
            QMessageBox.warning(self, "错误", "发送失败:\n {}".format(errorMsg))
            self.TcpServer.close()
            return

        self.serverStatuslabel.setText("等待对方接收... ...")
        self.serverSendBtn.setEnabled(False)
        self.sendFileName.emit(self.theFileName)

    @pyqtSlot()
    def on_serverCloseBtn_clicked(self):
        """
        取消或者关闭
        """
        if self.tcpServer.isListening():
            self.tcpServer.close()
            if self.localFile.isOpen():
                self.localFile.close()
            self.clientConnection.abort()

        if self.serverCloseBtn.text() == "取消":
            self.serverCloseBtn.setText("关闭")
        else:
            self.close()
            self.serverOpenBtn.setEnabled(True)
            self.serverSendBtn.setEnabled(False)
            self.progressBar.reset()
            self.totalBytes = 0
            self.bytesWritten = 0
            self.bytesToWrite = 0
            self.serverStatuslabel.setText("请选择要传送的文件")
예제 #20
0
class Pricing_Validation_Main(QThread):
    """
	Runs in thread.
	"""

    txtProgress = pyqtSignal(str)
    countProgress = pyqtSignal(int)
    currStatus = pyqtSignal(list)

    def __init__(self, src_folder, tgt_folder, keyword, templates, pt_model):
        super(Pricing_Validation_Main, self).__init__()

        self._src_folder = src_folder
        self._tgt_folder = tgt_folder
        self._keyword = keyword
        self._l_templates = templates
        self._pt_model = pt_model
        self._common_mod = Common_Model()
        self._pv_model = Pricing_Validation_Model(self._common_mod,
                                                  self._pt_model)

        self.timer = QTime()
        self.elapsed_time = None

        self.is_running = True
        self._progress_count = 0
        self._abort_flg = False
        self._cancel_flg = False
        self._main_dir = os.getcwd()

        self.preval_price_df = None

    def run(self):
        ''' 
		Read source file to DataFrame and Excel file (for validation)
		Filter dataframe per Usage Type
		Perform Mappings
		Populate the validated dataframe to template
		'''

        # Start timer

        self.timer.start()

        self.txtProgress.emit('Loading source file to dataframes.')

        success = False
        while not success:
            try:

                df_price_all = self._pv_model.read_source_to_DF(
                    self._keyword, self._src_folder, 'Pricing')
                df_scales_all = self._pv_model.read_source_to_DF(
                    self._keyword, self._src_folder, 'Scales')
                df_minf_all = self._pv_model.read_source_to_DF(
                    self._keyword, self._src_folder, 'MINF')

                success = True
            except Exception as e:

                self.currStatus.emit([self._keyword, 'Load Source', str(e)])

                response = None
                while response is None:
                    response = self._pt_model.replyBtn
                    time.sleep(1)

                if response == QMessageBox.Close:
                    self._abort_flg = True
                    self._pt_model.replyBtn = None
                    success = True

        if not self._abort_flg:

            #Loop on the templates found

            for i in self._l_templates:

                usage_type = i[0]

                if self._cancel_flg: break

                status = self._pt_model.get_template_status(usage_type)

                if status == '':

                    wb_name = 'OTC_{}_Pricing_Pre_Validation_Report_{}.xlsx'.format(
                        usage_type, self._keyword.upper())
                    output_filenm = self._tgt_folder + "\\" + wb_name

                    # Create a Pandas Excel writer using XlsxWriter as the engine.
                    writer = pd.ExcelWriter(
                        output_filenm,
                        engine='xlsxwriter',
                        options={'strings_to_numbers': False})

                    # Get the xlsxwriter workbook and worksheet objects.
                    workbook = writer.book

                    #Set workbook formats

                    self._common_mod.set_workbook_formats(workbook)

                    l_price_tabs = self._pv_model._config['PricingTabs']

                    success = False
                    while not success:
                        try:

                            for d_tab in l_price_tabs:

                                for k, v in d_tab.items():

                                    tab = k
                                    template_sheet_name = v[
                                        'Template_Sheet_Name']
                                    template_mapping_idx = v[
                                        'Template_Mapping_Index']
                                    template_column_idx = v[
                                        'Template_Column_Index']
                                    chart_sheet_name = v['Chart_Sheeet_Name']
                                    details_sheet_name = v[
                                        'Details_Sheet_Name']

                                    self.txtProgress.emit(
                                        'Started: Processing {} - Initializing {} DataFrame.'
                                        .format(usage_type, tab))

                                    #Filter dataframe

                                    if tab == 'Price':
                                        preval_df = df_price_all[
                                            df_price_all['USAGE_TYPE_CD'] ==
                                            usage_type]
                                    elif tab == 'Scale':
                                        preval_df = df_scales_all[
                                            df_scales_all['USAGE_TYPE_CD'] ==
                                            usage_type]
                                    else:
                                        preval_df = df_minf_all[
                                            df_minf_all['USAGE_TYPE_CD'] ==
                                            usage_type]

                                    #Initialize Pricing dataframe

                                    preval_df = self._pv_model.initialize_preval_df(
                                        preval_df, tab)

                                    self.txtProgress.emit(
                                        'Finished: Processing {} - Initializing {} DataFrame.'
                                        .format(usage_type, tab))
                                    time.sleep(3)

                                    #Read Template columns for mapping

                                    self.txtProgress.emit(
                                        'Started: Processing {} - Get {} Template Column Mappings.'
                                        .format(usage_type, tab))

                                    template_columns = self._pv_model.get_template_mappings(
                                        usage_type, template_sheet_name,
                                        template_mapping_idx)

                                    self.txtProgress.emit(
                                        'Started: Processing {} - Get {} Template Column Mappings.'
                                        .format(usage_type, tab))
                                    time.sleep(3)

                                    #Generate Price template DF

                                    self.txtProgress.emit(
                                        'Started: Processing {} - Generating {} Template DataFrame.'
                                        .format(usage_type, tab))

                                    if tab == 'Price':
                                        self.preval_price_df = preval_df.copy()
                                        template_df = self._pv_model.generate_template_df(
                                            usage_type, preval_df,
                                            template_sheet_name,
                                            template_columns,
                                            template_column_idx, tab)
                                    elif tab == 'Scale':

                                        merge_scale_price_df = self._pv_model.merge_scale_price_df(
                                            preval_df, self.preval_price_df)
                                        template_df = self._pv_model.generate_template_df(
                                            usage_type, merge_scale_price_df,
                                            template_sheet_name,
                                            template_columns,
                                            template_column_idx, tab,
                                            self.preval_price_df)

                                    else:
                                        merge_minf_price_df = self._pv_model.merge_minf_price_df(
                                            preval_df, self.preval_price_df)
                                        template_df = self._pv_model.generate_template_df(
                                            usage_type, merge_minf_price_df,
                                            template_sheet_name,
                                            template_columns,
                                            template_column_idx, tab,
                                            self.preval_price_df)

                                    self.txtProgress.emit(
                                        'Finished: Processing {} - Generating {} Template DataFrame.'
                                        .format(usage_type, tab))
                                    time.sleep(3)

                                    #Populate Summary Chart

                                    self.txtProgress.emit(
                                        'Started: Processing {} - Populating {} Summary Chart.'
                                        .format(usage_type, tab))

                                    print(template_df.columns.to_list())
                                    self._pv_model.populate_summary_chart(
                                        usage_type, workbook, template_df,
                                        chart_sheet_name, template_column_idx)

                                    self.txtProgress.emit(
                                        'Finished: Processing {} - Populating {} Summary Chart.'
                                        .format(usage_type, tab))
                                    time.sleep(3)

                                    #Populate Details sheet

                                    self.txtProgress.emit(
                                        'Started: Processing {} - Populating {} Details Sheet.'
                                        .format(usage_type, tab))

                                    self._pv_model.populate_details_worksheet(
                                        writer, template_df,
                                        details_sheet_name,
                                        template_column_idx)

                                    self.txtProgress.emit(
                                        'Finished: Processing {} - Populating {} Details Sheet.'
                                        .format(usage_type, tab))
                                    time.sleep(3)

                                    #Generating Template Counts

                                    if not self._abort_flg:

                                        self.txtProgress.emit(
                                            'Started: Processing {} - Generating Data Counts.'
                                            .format(usage_type))

                                        data = {
                                            'Source': 0,
                                            'Template': preval_df.shape[0]
                                        }
                                        self._pt_model.append_template_logs(
                                            usage_type, 3, tab, data)

                                        self.txtProgress.emit(
                                            'Finished: Processing {} - Generating Data Counts.'
                                            .format(usage_type))

                            success = True

                        except Exception as e:

                            self.currStatus.emit([
                                usage_type, 'Populate Worksheet', tab,
                                str(e)
                            ])

                            response = None
                            while response is None:
                                response = self._pt_model.replyBtn
                                time.sleep(1)

                                if response == QMessageBox.Abort:
                                    self._abort_flg = True
                                    self._pt_model.replyBtn = None
                                    success = True
                                elif response == QMessageBox.Retry:
                                    self._pt_model.replyBtn = None
                                    workbook.close()
                                elif response == QMessageBox.Ignore:
                                    self._pt_model.update_template_status(
                                        usage_type, 'i')
                                    self._pt_model.replyBtn = None
                                    success = True
                                elif response == QMessageBox.Close:
                                    self._abort_flg = True
                                    self._pt_model.replyBtn = None
                                    success = True

                    if self._cancel_flg: break

                    #Save to workbook in output folder

                    status = self._pt_model.get_template_status(usage_type)

                    if status == '' and not self._abort_flg:

                        success = False
                        while not success:
                            try:
                                self.txtProgress.emit(
                                    'Started: Processing {} - Saving Workbook to Output Folder.'
                                    .format(usage_type))

                                writer.save()

                                self.txtProgress.emit(
                                    'Finished: Processing {} - Saving Workbook to Output Folder.'
                                    .format(usage_type))
                                time.sleep(3)

                                #Update Status
                                self._pt_model.update_template_status(
                                    usage_type, 'c')

                                success = True
                            except Exception as e:

                                self.currStatus.emit([
                                    usage_type, 'Save Template', wb_name,
                                    str(e)
                                ])

                                response = None
                                while response is None:
                                    response = self._pt_model.replyBtn
                                    time.sleep(1)

                                    if response == QMessageBox.Abort:
                                        self._abort_flg = True
                                        self._pt_model.replyBtn = None
                                        success = True
                                    elif response == QMessageBox.Retry:
                                        self._pt_model.replyBtn = None
                                    elif response == QMessageBox.Ignore:
                                        self._pt_model.update_template_status(
                                            usage_type, 'i')
                                        self._pt_model.replyBtn = None
                                        success = True
                                    elif response == QMessageBox.Close:
                                        self._abort_flg = True
                                        self._pt_model.replyBtn = None
                                        success = True
                    else:

                        workbook.close()

                self._progress_count += 1
                self.countProgress.emit(self._progress_count)

        ### Display Elapsed Time ###

        self.update_elapsed_time()

        self.txtProgress.emit('Finished')

    def update_elapsed_time(self):

        secs = self.timer.elapsed() / 1000
        mins = (secs / 60) % 60
        hours = (secs / 3600)
        seconds = secs % 60

        self.elapsed_time = str(hours).split('.')[0] + ' Hours ' + str(
            mins).split('.')[0] + ' Minutes ' + str(seconds).split(
                '.')[0] + ' Seconds'
예제 #21
0
class QOpenGLControllerWidget(QOpenGLWidget):
    """Widget that sets up specific OpenGL version profile."""
    def __init__(self, versionprofile=None, *args, **kwargs):
        """Initialize OpenGL version profile."""
        super(QOpenGLControllerWidget, self).__init__(*args, **kwargs)

        self.versionprofile = versionprofile

        self.timer = QTimer()
        self.timer.setInterval(0)
        self.timer.start()
        self.timer.timeout.connect(self.update)

        self.frame_count = 0
        self.fps_timer = QTime()

    def initializeGL(self):
        """Apply OpenGL version profile and initialize OpenGL functions."""

        print('Opengl Version : ', glGetString(GL_VERSION))

        self.rendering_program = shaders.compile_shaders(
            'graph.v.glsl', 'graph.f.glsl')
        self.vertex_array_object = glGenVertexArrays(1)

        glBindVertexArray(self.vertex_array_object)

    def paintGL(self):

        self._update_fps()
        """Painting callback that uses the initialized OpenGL functions."""
        now = time.time() * 5
        color = np.array(
            [np.sin(now) * 0.5 + 0.5,
             np.cos(now) * 0.5 + 0.5, 0., 1.],
            dtype=np.float32)
        glClearBufferfv(GL_COLOR, 0, color)

        glUseProgram(self.rendering_program)

        offset = np.array(
            [np.sin(now) * 0.5, np.cos(now) * 0.6, 0., 0.], dtype=np.float32)

        color = np.array(
            [np.cos(now) * 0.5 + 0.5,
             np.sin(now) * 0.5 + 0.5, 0., 1.],
            dtype=np.float32)

        glVertexAttrib4fv(0, offset)
        glVertexAttrib4fv(1, color)

        glDrawArrays(GL_TRIANGLES, 0, 3)

    def resizeGL(self, w, h):
        """Resize viewport to match widget dimensions."""
        glViewport(0, 0, w, h)

    def _update_fps(self):
        if self.frame_count == 0:
            self.fps_timer.start()
        else:
            fps = self.frame_count / self.fps_timer.elapsed() * 1000
            self.parentWidget().setWindowTitle("FPS is {:.2f}".format(fps))
        self.frame_count += 1
예제 #22
0
class TactileSurfaceArea(QTableWidget):

    signalRobotFinishWriting = pyqtSignal()

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

        self.myBrush = QBrush()
        self.myPen = QPen()
        self.pixmap = None
        self.pixmapHandwriting = None
        self.deviceDown = False
        self.time = QTime()
        self.lastPoints = [QPoint(), QPoint()]
        self.boxesToDraw = []
        self.data = []
        self.convert_pix_meter = 0.0001534

        self.initPixmaps()
        self.setAutoFillBackground(True)
        self.setCursor(Qt.BlankCursor)
        self.time.start()

    def initPixmaps(self):
        width = 8000
        height = 8000

        self.pixmap = QPixmap(width, height)
        self.pixmap.fill(QColor(255, 255, 255))

        self.pixmapHandwriting = QPixmap(width, height)
        self.pixmapHandwriting.fill(QColor(255, 255, 255))

        self.viewport().update()

    def paintEvent(self, event):
        p = QPainter()
        p.begin(self.viewport())
        p.drawPixmap(0, 0, self.pixmap)
        p.drawPixmap(0, 0, self.pixmapHandwriting)
        p.end()

    def tabletEvent(self, event):
        if event.type() == QTabletEvent.TabletPress:
            if self.deviceDown == False:
                self.deviceDown = True
                self.lastPoints[0] = event.pos()
                self.lastPoints[1] = event.pos()

        elif event.type() == QTabletEvent.TabletRelease:
            if self.deviceDown:
                self.deviceDown = False

        elif event.type() == QTabletEvent.TabletMove:
            self.lastPoints[1] = self.lastPoints[0]
            self.lastPoints[0] = event.pos()

            if self.deviceDown:
                self.updateBrush(event)
                painter = QPainter(self.pixmapHandwriting)
                self.paintPixmap(painter, event)
                self.data.append(
                    Data(self.time.elapsed(),
                         event.posF().x(),
                         event.posF().y(), event.xTilt(), event.yTilt(),
                         event.pressure()))

    def updateBrush(self, event):
        #hue, saturation, value, alpha;
        #myColor.getHsv(&hue, &saturation, &value, &alpha)
        myColor = QColor()

        vValue = int(((event.yTilt() + 60.0) / 120.0) * 255)
        hValue = int(((event.xTilt() + 60.0) / 120.0) * 255)
        alpha = int(event.pressure() * 255.0)

        # print vValue, hValue,alpha

        myColor.setHsv(0, vValue, hValue, alpha)
        #myColor.setAlpha(alpha)

        self.myPen.setWidthF(event.pressure() * 2 + 1)
        self.myBrush.setColor(myColor)
        self.myPen.setColor(myColor)

    def paintPixmap(self, painter, event):

        painter.setBrush(self.myBrush)
        painter.setPen(self.myPen)
        painter.drawLine(self.lastPoints[1], event.pos())
        self.viewport().update()

    def erasePixmap(self):

        newPixmap = QPixmap(self.width(), self.height())
        newPixmap.fill(QColor(255, 255, 255, 0))
        self.pixmapHandwriting = newPixmap
        painter = QPainter(self.pixmap)
        painter.drawPixmap(0, 0, self.pixmapHandwriting)
        painter.end()

        # update drawing
        self.viewport().update()

        # erase data
        self.data = []

        # restart timer
        self.time.start()

    def eraseRobotTrace(self):

        newPixmap = QPixmap(self.width(), self.height())
        newPixmap.fill(QColor(255, 255, 255, 0))
        self.pixmap = newPixmap
        painter = QPainter(self.pixmap)
        painter.drawPixmap(0, 0, self.pixmap)
        painter.end()

        # update drawing
        self.viewport().update()

        # erase data
        self.data = []

        # restart timer
        self.time.start()

    def drawWord(self, path):
        # prepare drawing
        painter = QPainter(self.pixmap)

        myColor = QColor(0, 0, 0)
        self.myBrush.setColor(myColor)
        self.myPen.setColor(myColor)
        self.myPen.setWidthF(SIZE_ROBOT_WRITING)
        painter.setBrush(self.myBrush)
        painter.setPen(self.myPen)

        x = []
        y = []
        penUp = []
        t = []
        for i, pose in enumerate(path.poses):
            x.append(float(pose.pose.position.x) / self.convert_pix_meter)
            y.append(float(pose.pose.position.y) / self.convert_pix_meter)
            penUp.append(pose.header.seq)
            t.append(pose.header.stamp.nsecs)

        # put y in touch pad coordinate
        y = [-y_ + min(y) + max(y) for y_ in y]

        # put word in top of screen
        y = [y_ - min(y) + DISTANCE_ROBOT_WRITING_TO_TOP for y_ in y]

        # wait that robot move its arm up
        rospy.sleep(3.)

        # draw
        for i in range(len(x)):
            if i > 1:
                if penUp[i] == 0 and penUp[i - 1] == 0:
                    painter.drawLine(QPoint(x[i - 1], y[i - 1]),
                                     QPoint(x[i], y[i]))
                    self.viewport().update()
                    waitingTime = (t[i] - t[i - 1]) / 1000000.0
                    rospy.sleep(TIME_BTW_POINTS)
                else:
                    rospy.sleep(TIME_PEN_UP)

        # advert that drawing is done
        self.signalRobotFinishWriting.emit()

    def drawBoxes(self):
        # prepare drawing
        painter = QPainter(self.pixmap)

        myColor = QColor(0, 0, 0)
        self.myBrush.setColor(myColor)
        self.myPen.setColor(myColor)
        self.myPen.setWidthF(SIZE_BOXES)
        painter.setBrush(self.myBrush)
        painter.setPen(self.myPen)

        for data in self.boxesToDraw:

            x = data[0] / self.convert_pix_meter
            y = self.height() - data[1] / self.convert_pix_meter

            width = data[2] / self.convert_pix_meter - data[
                0] / self.convert_pix_meter
            height = -data[3] / self.convert_pix_meter + data[
                1] / self.convert_pix_meter

            painter.drawRect(x, y, width, height)
            self.viewport().update()

    def getData(self):
        return self.data
예제 #23
0
파일: gl_widget.py 프로젝트: hibtc/madgui
class GLWidget(QOpenGLWidget):

    """
    OpenGL widget that shows a static 3D scene, allowing the observer to
    freely move and look around.
    """

    background_color = gl_array([1, 1, 1]) * 0.6
    ambient_color = gl_array([1, 1, 1]) * 0.1
    diffuse_color = gl_array([1, 1, 1])

    camera_speed = 1            # [m/s]
    zoom_speed = 1/10           # [1/deg]
    mouse_sensitivity = 1/100   # [rad/px]
    update_interval = 25        # [ms]

    shader_program = None
    update_timer = None

    def __init__(self, create_items, *args, **kwargs):
        """Create from a callable ``create_items: Camera -> [Object3D]``."""
        super().__init__(*args, **kwargs)
        self._create_items = create_items
        self.items = []
        self._key_state = {}
        self._update_time = QTime()
        self.resize(800, 600)
        self.camera = Camera()
        self.camera.updated.connect(self.update)
        # Enable multisampling (for antialiasing):
        # (must be set before initializeGL)
        surface_format = self.format()
        surface_format.setSamples(6)
        self.setFormat(surface_format)

    def free(self):
        """Free all items."""
        for item in self.items:
            item.delete()
        self.items.clear()

    def closeEvent(self, event):
        """Free items."""
        self.free()
        super().closeEvent(event)

    def showEvent(self, event):
        """Start scene updates (camera movement)."""
        super().showEvent(event)
        if self.update_timer is None:
            self.update_timer = QTimer(self)
            self.update_timer.setInterval(self.update_interval)
            self.update_timer.timeout.connect(self.update_event)
            self.update_timer.start()
            self._update_time.start()

    def hideEvent(self, event):
        """Stop scene updates (camera movement)."""
        super().hideEvent(event)
        if self.update_timer is not None:
            self.update_timer.timeout.disconnect(self.update_event)
            self.update_timer.stop()
            self.update_timer = None

    # def GL(self):
    #     from PyQt5.QtGui import QOpenGLVersionProfile
    #     version = QOpenGLVersionProfile()
    #     version.setVersion(2, 0)
    #     return self.context().versionFunctions(version)

    def initializeGL(self):
        """Called after first creating a valid OpenGL context. Creates shader
        program, sets up camera and creates an initial scene."""
        self.create_shader_program()
        self.create_scene()
        # Activate wireframe:
        # GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE)
        camera = self.camera
        camera.look_from(camera.theta, camera.phi, camera.psi)

    def create_scene(self):
        """Fetch new items from the given callable."""
        self.free()
        if self.shader_program is not None:
            self.items = self._create_items(self.camera)
            self.update()

    def paintGL(self):
        """Handle paint event by drawing the items returned by the creator
        function."""
        program = self.shader_program
        projection = self.camera.projection(self.width(), self.height())
        set_uniform_matrix(program, "view", self.camera.view_matrix)
        set_uniform_matrix(program, "projection", projection)

        set_uniform_vector(program, "ambient_color", self.ambient_color)
        set_uniform_vector(program, "diffuse_color", self.diffuse_color)
        set_uniform_vector(program, "diffuse_position", self.camera.position)

        GL.glClearColor(*self.background_color, 0)
        GL.glEnable(GL.GL_DEPTH_TEST)
        GL.glEnable(GL.GL_MULTISAMPLE)
        GL.glEnable(GL.GL_BLEND)
        GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA)
        GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)

        # Draw transparent items after opaque ones, and sorted by distance to
        # the observer (far to near). Note that this is only an approximation
        # that is correct only for point-like items; a 100% correct blending
        # order would have to be decided on the level of fragments (based on
        # the interpolated depth value).
        items = sorted(self.items, key=lambda item: (
            item.opaque(),
            np.linalg.norm(self.camera.position - item.position()),
        ), reverse=True)
        for item in items:
            item.draw()

    def create_shader_program(self):
        """Create simple program with generic fragment/vertex shaders used to
        render objects with a simple ambient+diffuse lighting model."""
        self.shader_program = create_shader_program([
            load_shader(GL.GL_VERTEX_SHADER, 'shader_vertex.glsl'),
            load_shader(GL.GL_FRAGMENT_SHADER, 'shader_fragment.glsl'),
        ])

    def minimumSizeHint(self):
        return QSize(50, 50)

    def sizeHint(self):
        return QSize(400, 400)

    def wheelEvent(self, event):
        """Handle mouse wheel as zoom."""
        self.camera.zoom(self.zoom_speed * event.angleDelta().y())

    def mousePressEvent(self, event):
        """Handle camera look around."""
        self.last_mouse_position = event.pos()
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        """Handle camera look around."""
        camera = self.camera
        delta = event.pos() - self.last_mouse_position
        if event.buttons() == Qt.RightButton:
            dx = delta.x() * self.mouse_sensitivity
            dy = delta.y() * self.mouse_sensitivity
            if event.modifiers() & Qt.ShiftModifier:
                camera.look_from(camera.theta + dx, camera.phi - dy, camera.psi)
            else:
                camera.look_toward(camera.theta + dx, camera.phi - dy, camera.psi)
        elif event.buttons() == Qt.RightButton | Qt.LeftButton:
            camera.zoom(-delta.y())
        else:
            return super().mouseMoveEvent(event)
        self.last_mouse_position = event.pos()
        event.accept()

    def keyPressEvent(self, event):
        """Maintain a list of pressed keys for camera movement."""
        key = event.key()
        if key in (Qt.Key_Escape, Qt.Key_Q):
            self.window().close()
        if not event.isAutoRepeat():
            self._key_state[key] = True
        super().keyPressEvent(event)

    def keyReleaseEvent(self, event):
        """Maintain a list of pressed keys for camera movement."""
        if not event.isAutoRepeat():
            self._key_state[event.key()] = False

    def update_event(self):
        """Implement camera movement. Called regularly."""
        pressed = lambda k: self._key_state.get(k, 0)
        upward = pressed(Qt.Key_Space) - pressed(Qt.Key_Control)
        forward = ((pressed(Qt.Key_Up) or pressed(Qt.Key_W)) -
                   (pressed(Qt.Key_Down) or pressed(Qt.Key_S)))
        leftward = ((pressed(Qt.Key_Left) or pressed(Qt.Key_A)) -
                    (pressed(Qt.Key_Right) or pressed(Qt.Key_D)))

        # we use this "update time" (a.k.a. "game time") to maintain a
        # somewhat framerate independent movement speed:
        ms_elapsed = self._update_time.elapsed()
        self._update_time.start()

        if forward or upward or leftward:
            direction = np.array([-leftward, upward, -forward])
            direction = direction / np.linalg.norm(direction)
            translate = direction * self.camera_speed * (ms_elapsed/1000)
            self.camera.translate(*translate)
예제 #24
0
class VCProgressBar(QDialog):
    taskbarprogress = pyqtSignal(float, bool)

    def __init__(self, parent=None, flags=Qt.Dialog | Qt.FramelessWindowHint):
        super(VCProgressBar, self).__init__(parent, flags)
        self.parent = parent
        self.setWindowModality(Qt.ApplicationModal)
        self.setStyleSheet('QDialog { border: 2px solid #000; }')
        self._progress = QProgressBar(self)
        self._progress.setRange(0, 0)
        self._progress.setTextVisible(False)
        self._progress.setStyle(QStyleFactory.create('Fusion'))
        self._label = QLabel(self)
        self._label.setAlignment(Qt.AlignCenter)
        layout = QGridLayout()
        layout.addWidget(self._progress, 0, 0)
        layout.addWidget(self._label, 0, 0)
        self._timerprefix = QLabel('<b>Elapsed time:</b>', self)
        self._timerprefix.setObjectName('progresstimer')
        self._timervalue = QLabel(self)
        self._timervalue.setObjectName('progresstimer')
        timerlayout = QHBoxLayout()
        timerlayout.addWidget(self._timerprefix)
        timerlayout.addWidget(self._timervalue)
        self._timerwidget = QWidget(self)
        self._timerwidget.setLayout(timerlayout)
        self._timerwidget.hide()
        self._time = QTime()
        self._timer = QTimer(self)
        self._timer.timeout.connect(self.updateTimer)
        self.setLayout(layout)
        self.setFixedWidth(550)

    def reset(self, steps: int = 0, timer: bool = False) -> None:
        self.setValue(0)
        self.setRange(0, steps)
        self.setText('Analyzing video source')
        self.showTimer() if timer else self.hideTimer()

    def showTimer(self) -> None:
        self._timerwidget.show()
        # noinspection PyArgumentList
        self.layout().addWidget(self._timerwidget, 1, 0,
                                Qt.AlignHCenter | Qt.AlignTop)
        self._time.start()
        self.updateTimer()
        self._timer.start(1000)

    def hideTimer(self) -> None:
        self._timerwidget.hide()
        self.layout().removeWidget(self._timerwidget)

    @pyqtSlot()
    def updateTimer(self) -> None:
        secs = self._time.elapsed() / 1000
        mins = int(secs / 60) % 60
        hrs = int(secs / 3600)
        secs = int(secs % 60)
        elapsed = '{hrs:02d}:{mins:02d}:{secs:02d}'.format(**locals())
        self._timervalue.setText(elapsed)

    def value(self) -> int:
        return self._progress.value()

    def setStyle(self, style: QStyle) -> None:
        self._progress.setStyle(style)

    def setText(self, val: str) -> None:
        if '<b>' in val:
            css = '<style>b { font-family:"Noto Sans UI"; font-weight:bold; }</style>'
            val = '{0}{1}'.format(css, val)
        self._label.setText(val)

    def setMinimum(self, val: int) -> None:
        self._progress.setMinimum(val)

    def setMaximum(self, val: int) -> None:
        self._progress.setMaximum(val)

    @pyqtSlot(int, int)
    def setRange(self, minval: int, maxval: int) -> None:
        self._progress.setRange(minval, maxval)

    def setValue(self, val: int) -> None:
        if sys.platform.startswith('linux') and self._progress.maximum() != 0:
            self.taskbarprogress.emit(float(val / self._progress.maximum()),
                                      True)
        self._progress.setValue(val)
        if val >= self._progress.maximum() and self._timer.isActive():
            self._timer.stop()

    @pyqtSlot(str)
    def updateProgress(self, text: str) -> None:
        self.setValue(self._progress.value() + 1)
        self.setText(text)
        qApp.processEvents()

    @pyqtSlot()
    def close(self) -> None:
        if sys.platform.startswith('linux'):
            self.taskbarprogress.emit(0.0, False)
        if self._timer.isActive():
            self._timer.stop()
        super(VCProgressBar, self).close()
예제 #25
0
class MainWindow(QGraphicsView):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.updateTimer = QTimer(self)
        self.demoStartTime = QTime()
        self.fpsTime = QTime()
        self.background = QPixmap()

        self.scene = None
        self.mainSceneRoot = None
        self.frameTimeList = []
        self.fpsHistory = []

        self.currentFps = Colors.fps
        self.fpsMedian = -1
        self.fpsLabel = None
        self.pausedLabel = None
        self.doneAdapt = False
        self.useTimer = False
        self.updateTimer.setSingleShot(True)
        self.companyLogo = None
        self.qtLogo = None

        self.setupWidget()
        self.setupScene()
        self.setupSceneItems()
        self.drawBackgroundToPixmap()

    def setupWidget(self):
        desktop = QApplication.desktop()
        screenRect = desktop.screenGeometry(desktop.primaryScreen())
        windowRect = QRect(0, 0, 800, 600)

        if screenRect.width() < 800:
            windowRect.setWidth(screenRect.width())

        if screenRect.height() < 600:
            windowRect.setHeight(screenRect.height())

        windowRect.moveCenter(screenRect.center())
        self.setGeometry(windowRect)
        self.setMinimumSize(80, 60)

        self.setWindowTitle("PyQt Examples")
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setFrameStyle(QFrame.NoFrame)
        self.setRenderingSystem()
        self.updateTimer.timeout.connect(self.tick)

    def setRenderingSystem(self):
        self.setCacheMode(QGraphicsView.CacheBackground)
        self.setViewport(QWidget())

    def start(self):
        self.switchTimerOnOff(True)
        self.demoStartTime.restart()
        MenuManager.instance().itemSelected(MenuManager.ROOT,
                Colors.rootMenuName)
        Colors.debug("- starting demo")

    def enableMask(self, enable):
        if not enable or Colors.noWindowMask:
            self.clearMask()
        else:
            region = QPolygon([
                    # North side.
                    0, 0,
                    800, 0,
                    # East side.
                    # 800, 70,
                    # 790, 90,
                    # 790, 480,
                    # 800, 500,
                    800, 600,
                    # South side.
                    700, 600,
                    670, 590,
                    130, 590,
                    100, 600,
                    0, 600,
                    # West side.
                    # 0, 550,
                    # 10, 530,
                    # 10, 520,
                    # 0, 520,
                    0, 0])

            self.setMask(QRegion(region))

    def setupScene(self):
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, 800, 600)
        self.setScene(self.scene)
        self.scene.setItemIndexMethod(QGraphicsScene.NoIndex)

    def switchTimerOnOff(self, on):
        ticker = MenuManager.instance().ticker
        if ticker and ticker.scene():
            ticker.tickOnPaint = not on or Colors.noTimerUpdate

        if on and not Colors.noTimerUpdate:
            self.useTimer = True
            self.fpsTime = QTime.currentTime()
            self.updateTimer.start(int(1000 / Colors.fps))
            update_mode = QGraphicsView.NoViewportUpdate
        else:
            self.useTimer = False
            self.updateTimer.stop()

            if Colors.noTicker:
                update_mode = QGraphicsView.MinimalViewportUpdate
            else:
                update_mode = QGraphicsView.SmartViewportUpdate

        self.setViewportUpdateMode(update_mode)

    def measureFps(self):
        # Calculate time difference.
        t = self.fpsTime.msecsTo(QTime.currentTime())
        if t == 0:
            t = 0.01

        self.currentFps = (1000.0 / t)
        self.fpsHistory.append(self.currentFps)
        self.fpsTime = QTime.currentTime()

        # Calculate median.
        size = len(self.fpsHistory)

        if size == 10:
            self.fpsHistory.sort()
            self.fpsMedian = self.fpsHistory[int(size / 2)]
            if self.fpsMedian == 0:
                self.fpsMedian = 0.01

            self.fpsHistory = []

            return True

        return False

    def forceFpsMedianCalculation(self):
        # Used for adaption in case things are so slow that no median has yet
        # been calculated.
        if self.fpsMedian != -1:
            return

        size = len(self.fpsHistory)

        if size == 0:
            self.fpsMedian = 0.01
            return

        self.fpsHistory.sort()
        self.fpsMedian = self.fpsHistory[size // 2]
        if self.fpsMedian == 0:
            self.fpsMedian = 0.01

    def tick(self):
        medianChanged = self.measureFps()
        self.checkAdapt()

        if medianChanged and self.fpsLabel and Colors.showFps:
            self.fpsLabel.setText("FPS: %d" % int(self.currentFps))

        if MenuManager.instance().ticker:
            MenuManager.instance().ticker.tick()

        self.viewport().update()

        if self.useTimer:
            self.updateTimer.start(int(1000 / Colors.fps))

    def setupSceneItems(self):
        if Colors.showFps:
            self.fpsLabel = DemoTextItem("FPS: --", Colors.buttonFont(),
                    Qt.white, -1, None, DemoTextItem.DYNAMIC_TEXT)
            self.fpsLabel.setZValue(1000)
            self.fpsLabel.setPos(Colors.stageStartX,
                    600 - QFontMetricsF(Colors.buttonFont()).height() - 5)

        self.mainSceneRoot = QGraphicsWidget()
        self.scene.addItem(self.mainSceneRoot)

        self.companyLogo = ImageItem(QImage(':/images/trolltech-logo.png'),
                1000, 1000, None, True, 0.5)
        self.qtLogo = ImageItem(QImage(':/images/qtlogo_small.png'), 1000,
                1000, None, True, 0.5)
        self.companyLogo.setZValue(100)
        self.qtLogo.setZValue(100)
        self.pausedLabel = DemoTextItem("PAUSED", Colors.buttonFont(),
                Qt.white, -1, None)
        self.pausedLabel.setZValue(100)
        fm = QFontMetricsF(Colors.buttonFont())
        self.pausedLabel.setPos(Colors.stageWidth - fm.width("PAUSED"),
                590 - fm.height())
        self.pausedLabel.setRecursiveVisible(False)

    def checkAdapt(self):
        if self.doneAdapt or Colors.noTimerUpdate or self.demoStartTime.elapsed() < 2000:
            return

        self.doneAdapt = True
        self.forceFpsMedianCalculation()
        Colors.benchmarkFps = self.fpsMedian
        Colors.debug("- benchmark: %d FPS" % int(Colors.benchmarkFps))

        if Colors.noAdapt:
            return

        if self.fpsMedian < 30:
            ticker = MenuManager.instance().ticker
            if ticker and ticker.scene():
                self.scene.removeItem(ticker)
                Colors.noTimerUpdate = True
                self.switchTimerOnOff(False)

                if self.fpsLabel:
                    self.fpsLabel.setText("FPS: (%d)" % int(self.fpsMedian))

                Colors.debug("- benchmark adaption: removed ticker (fps < 30)")

            if self.fpsMedian < 20:
                Colors.noAnimations = True
                Colors.debug("- benchmark adaption: animations switched off (fps < 20)")

            Colors.adapted = True

    def drawBackgroundToPixmap(self):
        r = self.scene.sceneRect()
        self.background = QPixmap(qRound(r.width()), qRound(r.height()))
        self.background.fill(Qt.black)
        painter = QPainter(self.background)

        bg = QImage(':/images/demobg.png')
        painter.drawImage(0, 0, bg)

    def drawBackground(self, painter, rect):
        painter.drawPixmap(QPoint(0, 0), self.background)

    def toggleFullscreen(self):
        if self.isFullScreen():
            self.enableMask(True)
            self.showNormal()
            if MenuManager.instance().ticker:
                MenuManager.instance().ticker.pause(False)
        else:
            self.enableMask(False)
            self.showFullScreen()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            QApplication.quit()
        elif event.key() == Qt.Key_F1:
            s = ""
            s += "\nAdapt: "
            s += ["on", "off"][Colors.noAdapt]
            s += "\nAdaption occured: "
            s += ["no", "yes"][Colors.adapted]
            w = QWidget()
            s += "\nColor bit depth: %d" % w.depth()
            s += "\nWanted FPS: %d" % Colors.fps
            s += "\nBenchmarked FPS: ";
            if Colors.benchmarkFps != -1:
                s += "%d" % Colors.benchmarkFps
            else:
                s += "not calculated"
            s += "\nAnimations: ";
            s += ["on", "off"][Colors.noAnimations]
            s += "\nBlending: ";
            s += ["on", "off"][Colors.useEightBitPalette]
            s += "\nTicker: ";
            s += ["on", "off"][Colors.noTicker]
            s += "\nPixmaps: ";
            s += ["off", "on"][Colors.usePixmaps]
            s += "\nRescale images on resize: ";
            s += ["on", "off"][Colors.noRescale]
            s += "\nTimer based updates: ";
            s += ["on", "off"][Colors.noTimerUpdate]
            s += "\nSeparate loop: ";
            s += ["no", "yes"][Colors.useLoop]
            s += "\nScreen sync: ";
            s += ["yes", "no"][Colors.noScreenSync]
            QMessageBox.information(None, "Current configuration", s)

        super(MainWindow, self).keyPressEvent(event)

    def focusInEvent(self, event):
        if not Colors.pause:
            return

        if MenuManager.instance().ticker:
            MenuManager.instance().ticker.pause(False)

        code = MenuManager.instance().currentMenuCode
        if code in (MenuManager.ROOT, MenuManager.MENU1):
            self.switchTimerOnOff(True)

        self.pausedLabel.setRecursiveVisible(False)

    def focusOutEvent(self, event):
        if not Colors.pause:
            return

        if MenuManager.instance().ticker:
            MenuManager.instance().ticker.pause(True)

        code = MenuManager.instance().currentMenuCode
        if code in (MenuManager.ROOT, MenuManager.MENU1):
            self.switchTimerOnOff(False)

        self.pausedLabel.setRecursiveVisible(True)

    def resizeEvent(self, event):
        self.resetTransform()
        self.scale(event.size().width() / 800.0, event.size().height() / 600.0)

        super(MainWindow, self).resizeEvent(event)

        DemoItem.setTransform(self.transform())

        if self.companyLogo:
            r = self.scene.sceneRect()
            ttb = self.companyLogo.boundingRect()
            self.companyLogo.setPos(int((r.width() - ttb.width()) / 2),
                    595 - ttb.height())
            qtb = self.qtLogo.boundingRect()
            self.qtLogo.setPos(802 - qtb.width(), 0)

        # Changing size will almost always hurt FPS during the change so ignore
        # it.
        self.fpsHistory = []
예제 #26
0
class BaseTestWidget(VisualWidget):
    def __init__(self, parent=None) -> None:
        """Base class for test widgets.

        This is not called directly, but contains methods which are inherited by all
        tests. These do much of the heavy lifting regarding running tests, storing data,
        and so on.

        """
        super(BaseTestWidget, self).__init__(parent)
        logger.debug(f"initialised {type(self)} with parent={parent}")

        # timers
        self.block_time = QTime()
        self.block_timer = QTimer()
        self.block_timer.setSingleShot(True)
        self.block_timer.timeout.connect(self._block_timeout)
        self.trial_time = QTime()
        self.trial_timer = QTimer()
        self.trial_timer.setSingleShot(True)
        self.trial_timer.timeout.connect(self._trial_timeout)

        # override these if necessary
        self.silent_block = False
        self.skip_countdown = False
        self.block_deadline = None
        self.trial_deadline = None
        self.procedure = None
        self.current_trial = None
        self.delete_skipped = False

        # silent attributes
        self._performing_block = False
        self._performing_trial = False
        self._mouse_visible = True

        # set focus so we can accept keyboard events
        self.setFocusPolicy(Qt.StrongFocus)

    @property
    def performing_block(self) -> bool:
        return self._performing_block

    @performing_block.setter
    def performing_block(self, value) -> None:
        """Block timers will be silently and automatically started or restarted here."""
        assert isinstance(value, bool), "performing_block must be a bool"
        self._performing_block = value
        time = self.block_time
        timer = self.block_timer
        deadline = self.block_deadline
        if timer.isActive():
            logger.debug("stopping block timer")
            timer.stop()
        if value is True:
            logger.debug("performing_block set to True")
            logger.debug("starting the block time")
            time.start()
        if value is True and deadline:
            logger.debug("block deadline: %s" % str(self.block_deadline))
            logger.debug("starting one-shot block timer")
            timer.start(deadline)

    @property
    def performing_trial(self) -> bool:
        return self._performing_trial

    @performing_trial.setter
    def performing_trial(self, value: bool) -> None:
        """Start of a trial defined from when the proband can start making responses.
        Trial timers will be silently and automatically started or restarted here.

        Args:
            value (bool): Are we performing a trial or not?

        """
        assert isinstance(value, bool), "performing_trial must be a bool"
        self._performing_trial = value
        time = self.trial_time
        timer = self.trial_timer
        deadline = self.trial_deadline
        if timer.isActive():
            logger.debug("stopping trial timer")
            timer.stop()
        if value is True:
            logger.debug("performing_trial set to True")
            logger.debug("starting the trial time")
            time.start()
        if value is True and deadline:
            logger.debug("trial deadline: %s" % str(self.trial_deadline))
            logger.debug("starting one-shot trial timer")
            timer.start(deadline)

    @property
    def mouse_visible(self) -> bool:
        return self._mouse_visible

    @mouse_visible.setter
    def mouse_visible(self, value: bool) -> None:
        """Makes the mouse visible or invisible."""
        assert isinstance(value, bool), "mouse_visible must be a bool"
        if value is False:
            self.setCursor(Qt.BlankCursor)
        else:
            self.setCursor(Qt.ArrowCursor)
        self._mouse_visible = value

    @property
    def _time_left_in_block(self) -> int:
        """Calculates difference between deadline and elapsed."""
        if isinstance(self.block_deadline, int):
            return self.block_deadline - self.block_time.elapsed()
        else:
            return 0

    @property
    def _block_time_up(self) -> bool:
        if isinstance(self._time_left_in_block, int):
            return self._time_left_in_block <= 0
        else:
            return False

    @property
    def _time_left_in_trial(self) -> int:
        """Calculates difference between deadline and elapsed."""
        if isinstance(self.trial_deadline, int):
            return self.trial_deadline - self.trial_time.elapsed()
        else:
            return 0

    @property
    def _trial_time_up(self) -> int:
        if isinstance(self._time_left_in_trial, int):
            return self._time_left_in_trial <= 0
        else:
            return 0

    def begin(self) -> None:
        """Start the test.

        Public method called by the parent widget. Starts by initialising a procedure
        (currently only SimpleProcedure implemented), creates a new trial list if
        needed, and steps into the test.

        """
        logger.debug("called begin()")
        if self.delete_skipped is True:
            self.kwds["delete_skipped"] = True
        self.procedure = SimpleProcedure(**self.kwds)
        started = self.procedure.data["test_started"]
        completed = self.procedure.data["test_completed"]
        if started is False and completed is False:
            logger.debug("generating new remaining_trials list")
            self.procedure.data["remaining_trials"] = self.make_trials()
            self.procedure.update()
            logger.debug(
                f"looks like {self.procedure.data['remaining_trials']}")
        self._step()

    def _step(self) -> None:
        """Step forward in the test.

        Private method. This could mean displaying instructions at the start of a block,
        starting the next trial, or continuing to the next test if all trials are done.

        """
        logger.debug("called _step()")
        self.performing_trial = False

        try:
            self.current_trial = self.procedure.next(self.current_trial)
            logger.debug(
                f"successfully iterated, got this: {self.current_trial}")

            if self.current_trial.first_trial_in_block:
                logger.debug("first trial in new block")
                self._block()
            else:
                logger.debug("after first trial in new block")
                if self._block_stopping_rule():
                    logger.debug("stopping rule says to stop")
                    self._stop_block()
                else:
                    logger.debug("stopping rule says to go")
                    self._trial()

        except StopIteration:
            logger.info("failed to iterate, end of test")
            self.safe_close()

    def _stop_block(self) -> None:
        """Stop the current block because stopping rule passed."""
        logger.debug("called _block_stop")
        self.procedure.skip_block(self.current_trial.block_number,
                                  "stopping rule failed")
        self.current_trial.status = "skipped"
        self.current_trial.reason_skipped = "stopping rule failed"
        self._next_trial()

    def _block_stopping_rule(self) -> bool:
        """Apply block stopping rule.

        Private method and a wrapper around the public method of the same name.

        """
        logger.debug("called _block_stopping_rule()")
        return False if self.current_trial is None else self.block_stopping_rule(
        )

    def _block(self) -> None:
        """Runs at the start of a new block of trials.

        Private method. Typically blocks are used to delineate trials of a different
        condition, when new instructions or a break are often needed.

        """
        logger.debug("called _block()")
        self.performing_block = False
        logger.debug("checking if this is a silent block")

        if self.silent_block:
            logger.debug("this is indeed a silent block")
            logger.debug("skipping the countdown")
            self.skip_countdown = True
            logger.debug("running _trial()")
            self._trial()
        else:
            logger.debug("this is a not a silent block")
            self.new_block.play()
            self.skip_countdown = False
            logger.debug("running block()")
            self.block()

    def _trial(self) -> None:
        """Runs at the start of a new trial.

        Private method. Displays the countdown if first in a new block, checks if very
        last trial, flags the fact that a trial is in progress, updates the results.

        """
        logger.debug("called _trial()")
        self.silence.play()
        if self.current_trial.first_trial_in_block and not self.skip_countdown:
            logger.debug("countdown requested")
            self.display_countdown()
        self.repaint()
        if self.current_trial.first_trial_in_block is True:
            logger.debug("this is the first trial in a new block")
            self.performing_block = True
        self.performing_trial = True
        self.trial()

    def block_stopping_rule(self) -> bool:
        """Override this method."""
        return False

    def make_trials(self) -> None:
        """Override this method."""
        raise AssertionError("make_trials must be overridden")

    def safe_close(self) -> None:
        """Safely clean up and save the data."""
        logger.debug("called safe_close()")

        # properly ended test
        if self.procedure.data["test_completed"] is True:
            logger.debug("summarising the results")
            self.procedure.data["summary"] = self.summarise()
            self.procedure.save()
            self.procedure.save_summary()

        # early quit
        else:
            logger.warning("quit early, need to save orphaned trial")
            rt = [t for t in self.procedure.data["remaining_trials"]]
            self.procedure.data["remaining_trials"] = [
                dict(self.current_trial)
            ] + rt
            self.procedure.save()

        # end test
        logger.debug("all done, so switching the central widget")
        self.parent().switch_central_widget()

    def _block_timeout(self) -> None:
        """End a block early because it had timed out."""
        logger.debug("called _block_timeout()")
        self.procedure.skip_block(self.current_trial.block_number, "timeout")
        self._trial_timeout()

    def _trial_timeout(self) -> None:
        """End a trial early because it had timed out."""
        logger.debug("called _trial_timeout()")
        self.current_trial.status = "skipped"
        self.current_trial.reason_skipped = "timeout"
        self._next_trial()

    def _next_trial(self) -> None:
        """Moves on to the next trial."""
        logger.debug("called _next_trial()")
        self._step()

    def next_trial(self) -> None:
        """Moves on to the next trial (public version)."""
        logger.debug("called next_trial()")
        self._next_trial()

    def mousePressEvent(self, event: QMouseEvent) -> None:
        """Overridden from `QtWidget`.

        Args:
            event (PyQt5.QtGui.QMouseEvent):
        """
        logger.debug(f"called mousePressEvent() with event={event}")
        if self.performing_trial:
            self.mousePressEvent_(event)
            self._add_timing_details()
            if self.current_trial.status == "completed":
                logger.debug("current_trial was completed successfully")
                self._next_trial()

    def keyReleaseEvent(self, event: QKeyEvent) -> None:
        """Overridden from `QtWidget`."""
        logger.debug(f"called keyReleaseEvent() with event={event}")
        if self.performing_trial:
            self.keyReleaseEvent_(event)
            self._add_timing_details()
            if self.current_trial.status == "completed":
                logger.debug("current_trial was completed successfully")
                self._next_trial()

    def _add_timing_details(self) -> None:
        """Gathers some details about the current state from the various timers."""
        logger.debug("called _add_timing_details()")
        dic = {
            "block_time_elapsed_ms": self.block_time.elapsed(),
            "trial_time_elapsed_ms": self.trial_time.elapsed(),
            "block_time_left_ms": self._time_left_in_block,
            "trial_time_left_ms": self._time_left_in_trial,
            "block_time_up_ms": self._block_time_up,
            "trial_time_up_ms": self._trial_time_up,
        }
        self.current_trial.update(dic)

    def block(self) -> None:
        """Override this method."""
        raise AssertionError("block must be overridden")

    def trial(self) -> None:
        """Override this method."""
        raise AssertionError("trial must be overridden")

    def summarise(self) -> dict:
        """This method can be overridden."""
        return basic_summary(self.procedure.data["completed_trials"])

    def mousePressEvent_(self, event: QMouseEvent) -> None:
        """Override this method."""
        pass

    def keyReleaseEvent_(self, event: QKeyEvent) -> None:
        """Override this method."""
        pass

    def sleep(self, t: int) -> None:
        """Sleep for `t` ms.

        Use instead of `time.sleep()` or any other method of sleeping because (a) Qt
        handles it properly and (b) it prevents a `closeEvent` from quitting the test
        during this time.

        Args:
            t (int): Time to sleep in seconds.

        """
        logger.debug(f"called sleep with t={t}")
        self.parent().ignore_close_event = True
        loop = QEventLoop()
        QTimer.singleShot(t, loop.quit)
        loop.exec_()
        self.parent().ignore_close_event = False
class Pricing_Template_Main(QThread):
    """
    Runs in thread.
    """

    txtProgress = pyqtSignal(str)
    countProgress = pyqtSignal(int)
    currStatus = pyqtSignal(list)

    def __init__(self, src_folder, tgt_folder, keyword, templates, pt_model):
        super(Pricing_Template_Main, self).__init__()

        self._src_folder = src_folder
        self._tgt_folder = tgt_folder
        self._keyword = keyword
        self._l_templates = templates
        self._pt_model = pt_model

        self.timer = QTime()
        self.elapsed_time = None

        self.is_running = True
        self._progress_count = 0
        self._abort_flg = False
        self._cancel_flg = False
        self._main_dir = os.getcwd()

        self.src_price_cnt = 0
        self.temp_price_cnt = 0
        self.src_scales_cnt = 0
        self.temp_scales_cnt = 0
        self.src_minf_cnt = 0
        self.temp_minf_cnt = 0

        self.start_row = self._pt_model._config['StartRow']

    def run(self):
        ''' 
        Read source file to DataFrame and Excel file (for validation)
        Filter dataframe per Usage Type
        Perform Mappings
        Populate the validated dataframe to template
        '''

        # Read source files and load to dataframe

        # Start timer

        self.timer.start()

        self.txtProgress.emit('Loading source files to dataframes.')

        success = False
        while not success:
            try:

                self.df_price_all = self._pt_model.read_source_to_DF(
                    self._keyword, self._src_folder, 'Pricing')
                df_scales_all = self._pt_model.read_source_to_DF(
                    self._keyword, self._src_folder, 'Scales')
                df_minf_all = self._pt_model.read_source_to_DF(
                    self._keyword, self._src_folder, 'MINF')

                success = True
            except Exception as e:

                self.currStatus.emit([self._keyword, 'Load Source', str(e)])

                response = None
                while response is None:
                    response = self._pt_model.replyBtn
                    time.sleep(1)

                if response == QMessageBox.Close:
                    self._abort_flg = True
                    self._pt_model.replyBtn = None
                    success = True

        if not self._abort_flg:

            #Loop on the templates found

            for i in self._l_templates:

                usage_type = i[0]
                ''' 
                Get current status
                c = Completed
                i = Ignored
                NULL = Not started (default)
                '''

                if self._cancel_flg: break

                status = self._pt_model.get_template_status(usage_type)

                if status == '':

                    self.txtProgress.emit('Processing ' + usage_type)

                    # Get template worksheets

                    template_file = self._pt_model.get_template_filename(
                        usage_type)
                    template_filename = template_file.split('\\')[-1]

                    # Load Template Workbook

                    self.txtProgress.emit(
                        'Loading Pricing Template to dataframe.')

                    success = False
                    while not success:
                        try:
                            temp_workbook = self._pt_model.load_workbook(
                                template_file)
                            temp_worksheets = self._pt_model.get_worksheets(
                                temp_workbook)
                            success = True
                        except Exception as e:

                            self.currStatus.emit(
                                [usage_type, 'Load Template',
                                 str(e)])

                            response = None
                            while response is None:
                                response = self._pt_model.replyBtn
                                time.sleep(1)

                            if response == QMessageBox.Abort:
                                self._abort_flg = True
                                self._pt_model.replyBtn = None
                                break
                            elif response == QMessageBox.Retry:
                                self._pt_model.replyBtn = None
                            elif response == QMessageBox.Ignore:
                                self._pt_model.update_template_status(
                                    usage_type, 'i')
                                self._pt_model.replyBtn = None
                                continue
                            elif response == QMessageBox.Close:
                                self._abort_flg = True
                                self._pt_model.replyBtn = None
                                break

                    # Filter & Validate Usage type

                    df_price = self._pt_model.filter_df(
                        usage_type, self.df_price_all)
                    df_scales = self._pt_model.filter_df(
                        usage_type, df_scales_all)
                    df_minf = self._pt_model.filter_df(usage_type, df_minf_all)

                    # Prep Source data frame

                    # Drop column fld_Contract_Type

                    df_price.drop('fld_Contract_Type', axis=1, inplace=True)

                    # Rename Column names in dataframe

                    df_price.rename(
                        columns={
                            'Partner_Number': 'fld_Business_Partner',
                            'BillingMaterial_ID_ToBe':
                            'fld_OTC_Billing_Material_ID',
                            'fld_Requestor': 'fld_Requester',
                            'fld_Price': 'fld_Price_Amount',
                            'fld_Pricing_Bundle_ID': 'fld_Bundle_ID',
                            'fld_Pricing_Contract_Type': 'fld_Contract_Type',
                            'fld_Pricing_Contract_SubType':
                            'fld_Contract_Sub_Type',
                            'fld_SSCALE_ID': 'fld_Shared_Scale_ID',
                            'fld_SSCALE_BP': 'fld_Shared_Scale_BP',
                            #'fld_Reach_Indicator': 'fld_Reach_Ind',
                            'fld_Flight_Range_Code': 'fld_Flight_Range'
                        },
                        inplace=True)

                    # Add columns to dataframe
                    # Common Audit Fields

                    df_price['fld_Created_By'] = ''
                    df_price['fld_Last_Upd'] = ''
                    df_price['fld_Last_Upd_By'] = 'DATA MIG'
                    df_price['fld_Created'] = ''

                    self.txtProgress.emit(
                        'Processing ' + usage_type +
                        ' - Filtering and Validating dataframe.')

                    #Loop on the template worksheet

                    for sheet in temp_worksheets:

                        success = False
                        while not success:

                            try:

                                if ('price' in sheet.title.lower()
                                        and 'scale' not in sheet.title.lower()
                                    ) or ('minq' in sheet.title.lower()
                                          or 'caps' in sheet.title.lower()
                                          or 'flight' in sheet.title.lower()):

                                    self.src_price_cnt = df_price.shape[0]

                                    if not df_price.empty and not self._cancel_flg:

                                        # Mappings for CAP, Flight range and MINQ

                                        if 'minq' in sheet.title.lower(
                                        ) or 'caps' in sheet.title.lower(
                                        ) or 'flight' in sheet.title.lower():

                                            self.txtProgress.emit(
                                                'Started: Processing ' +
                                                usage_type +
                                                ' - Additional mappings for ' +
                                                sheet.title + '.')

                                            df_price['fld_Counter_ID'] = '*'
                                            df_price['fld_Frequency'] = '*'
                                            df_price[
                                                'fld_Type_of_Calendar'] = '*'
                                            df_price['fld_Min_Quantity'] = '*'
                                            df_price[
                                                'fld_Scale_Frequency'] = '*'
                                            df_price[
                                                'fld_Reference_Date'] = df_price[
                                                    'fld_Start_Date']
                                            df_price['fld_Range'] = '*'
                                            df_price['fld_Scale_Price'] = '*'
                                            df_price['fld_Unit_Price'] = '*'
                                            df_price['fld_CAP'] = '*'
                                            df_price[
                                                'fld_Billing_Material'] = df_price[
                                                    'fld_OTC_Billing_Material_ID']

                                            df_price['fld_ID'] = '*'
                                            df_price['fld_Lower_Bound'] = '*'
                                            df_price['fld_Upper_Bound'] = '*'
                                            df_price[
                                                'fld_Flight_Range_Label'] = '*'

                                            self.txtProgress.emit(
                                                'Finished: Processing ' +
                                                usage_type +
                                                ' - Additional mappings for ' +
                                                sheet.title + '.')
                                            time.sleep(3)

                                        # Get Mappings

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Getting mappings for ' +
                                            sheet.title + '.')

                                        l_mapping = self._pt_model.get_template_mappings(
                                            usage_type, sheet, df_price,
                                            'Price')

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Getting mappings for ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                        if 'flight' in sheet.title.lower():
                                            start_row = 3
                                        else:
                                            start_row = self.start_row

                                        # Prepare the worksheet

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Preparing worksheet ' +
                                            sheet.title + '.')

                                        #self._pt_model.prepare_worksheet(sheet, start_row, self.src_price_cnt)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Preparing worksheet ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                        # Populate data from dataframe to worksheet

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Populating worksheet ' +
                                            sheet.title + '.')

                                        #self.temp_price_cnt = self._pt_model.populate_worksheet(sheet, df_price, l_mapping, start_row)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Populating worksheet ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                        # Format worksheet

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Formatting worksheet ' +
                                            sheet.title + '.')

                                        #self._pt_model.format_worksheet(sheet, start_row)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Formatting worksheet ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                    else:

                                        if 'flight' in sheet.title.lower():
                                            start_row = 3
                                        else:
                                            start_row = self.start_row

                                        # Prepare the worksheet

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Preparing worksheet ' +
                                            sheet.title + '.')

                                        self._pt_model.prepare_worksheet(
                                            sheet, start_row, 0)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Preparing worksheet ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                        #Insert empty mapping logs

                                        key_tab = 'Price' + '-' + sheet.title

                                        self._pt_model.append_template_logs(
                                            usage_type, 2, key_tab, [])

                                        if self._cancel_flg: return

                                elif 'scale' in sheet.title.lower():

                                    if not df_scales.empty and not self._cancel_flg:

                                        #Merge DataFrame with Price DataFrame

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Merging scales dataframe to Price.'
                                        )

                                        merged_price_scale_df = self._pt_model.merge_scale_price_df(
                                            df_scales, df_price)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Merging scales dataframe to Price.'
                                        )
                                        time.sleep(3)

                                        # Mapping logic for Type of calendar and reference_date

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Applying additional scales logic.'
                                        )

                                        conditions = [
                                            (merged_price_scale_df[
                                                'Condition_Type'] == 'ZCUY') |
                                            (merged_price_scale_df[
                                                'Condition_Type'] == 'ZCUA'),
                                            (merged_price_scale_df[
                                                'Condition_Type'] == 'ZCUM') |
                                            (merged_price_scale_df[
                                                'Condition_Type'] == 'ZCUX')
                                        ]

                                        choices = ['Yearly', 'Monthly']
                                        merged_price_scale_df[
                                            'fld_Scale_Frequency'] = np.select(
                                                conditions,
                                                choices,
                                                default='*')

                                        merged_price_scale_df[
                                            'fld_Type_of_Calendar'] = merged_price_scale_df[
                                                [
                                                    'Condition_Type',
                                                    'fld_Start_Date'
                                                ]].apply(lambda x: 'Natural'
                                                         if x['Condition_Type'
                                                              ] == 'ZCUM' or
                                                         x['Condition_Type'
                                                           ] == 'ZCUM' else
                                                         ('Natural' if
                                                          (x['Condition_Type'
                                                             ] == 'ZCUY' or
                                                           x['Condition_Type'
                                                             ] == 'ZCUA') and
                                                          x['fld_Start_Date'
                                                            ][:8][4:] == '0101'
                                                          else 'Rolling'),
                                                         axis=1)

                                        merged_price_scale_df[
                                            'fld_Reference_Date'] = merged_price_scale_df[
                                                [
                                                    'fld_Type_of_Calendar',
                                                    'fld_Start_Date'
                                                ]].apply(lambda x: x[
                                                    'fld_Start_Date'] if x[
                                                        'fld_Type_of_Calendar'
                                                    ] == 'Rolling' else 'NA',
                                                         axis=1)

                                        #Add/rename columns to dataframe

                                        merged_price_scale_df[
                                            'fld_Minimum_Fee'] = '*'
                                        merged_price_scale_df[
                                            'fld_Minimum_Fee_BM'] = '*'

                                        merged_price_scale_df.rename(
                                            columns={
                                                'MAPPING_TABLE':
                                                'fld_Mapping_Table',
                                                'RANGE': 'fld_Range',
                                                'SCALE_PRICE':
                                                'fld_Scale_Price',
                                            },
                                            inplace=True)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Applying additional scales logic.'
                                        )
                                        time.sleep(3)

                                        # Get Mappings

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Getting mappings for ' +
                                            sheet.title + '.')

                                        l_mapping = self._pt_model.get_template_mappings(
                                            usage_type, sheet,
                                            merged_price_scale_df, 'Scales')

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Getting mappings for ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                        # Prepare the worksheet

                                        self.src_scales_cnt = merged_price_scale_df.shape[
                                            0]

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Preparing worksheet ' +
                                            sheet.title + '.')

                                        #self._pt_model.prepare_worksheet(sheet, self.start_row, self.src_scales_cnt)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Preparing worksheet ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                        # Populate data from dataframe to worksheet

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Populating worksheet ' +
                                            sheet.title + '.')

                                        #self.temp_scales_cnt = self._pt_model.populate_worksheet(sheet, merged_price_scale_df, l_mapping, self.start_row)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Populating worksheet ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                        # Format worksheet

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Formatting worksheet ' +
                                            sheet.title + '.')

                                        #self._pt_model.format_worksheet(sheet, self.start_row)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Formatting worksheet ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                    else:

                                        # Prepare the worksheet

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Preparing worksheet ' +
                                            sheet.title + '.')

                                        self._pt_model.prepare_worksheet(
                                            sheet, self.start_row, 0)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Preparing worksheet ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                        #Insert empty mapping logs

                                        key_tab = 'Scales' + '-' + sheet.title

                                        self._pt_model.append_template_logs(
                                            usage_type, 2, key_tab, [])

                                        if self._cancel_flg: return

                                elif 'minf' in sheet.title.lower():

                                    if not df_minf.empty and not self._cancel_flg:

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Preparing MINQ dataframe ' +
                                            sheet.title + '.')

                                        # Drop not needed columns added on price dataframe

                                        df_price.drop([
                                            'fld_Counter_ID', 'fld_Frequency',
                                            'fld_Type_of_Calendar',
                                            'fld_Reference_Date',
                                            'fld_Billing_Material'
                                        ],
                                                      axis=1,
                                                      inplace=True)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Preparing MINQ dataframe ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                        #Merge DataFrame with Price DataFrame

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Merging MINF dataframe to Price.'
                                        )

                                        df_price_req = df_price[[
                                            'Short_Text_Key',
                                            'fld_Business_Partner',
                                            'HybrisProduct_ID',
                                            'fld_OTC_Billing_Material_ID',
                                            'fld_MF_Counter', 'fld_Discount',
                                            'fld_Discount_Type',
                                            'fld_Discount_Description',
                                            'fld_Item_Category'
                                        ]]

                                        #Merge DataFrame with Price DataFrame

                                        merged_price_minf_df = self._pt_model.merge_minf_price_df(
                                            df_minf, df_price_req)

                                        #Rename columns
                                        merged_price_minf_df.rename(
                                            columns={
                                                'Start_Date':
                                                'fld_Reference_Date',
                                                'Frequency': 'fld_Frequency',
                                                'Currency': 'fld_Currency',
                                                'fld_OTC_Billing_Material_ID':
                                                'fld_Billing_Material',
                                                'Minimum_Fee': 'fld_Min_Fee',
                                                'fld_MF_Counter':
                                                'fld_Counter_ID',
                                            },
                                            inplace=True)

                                        merged_price_minf_df[
                                            'fld_Type_of_Calendar'] = '*'

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Merging MINF dataframe to Price.'
                                        )
                                        time.sleep(3)

                                        # Get Mappings

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Getting mappings for ' +
                                            sheet.title + '.')

                                        l_mapping = self._pt_model.get_template_mappings(
                                            usage_type, sheet,
                                            merged_price_minf_df, 'MINF')

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Getting mappings for ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                        # Prepare the worksheet

                                        self.src_minf_cnt = merged_price_minf_df.shape[
                                            0]

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Preparing worksheet ' +
                                            sheet.title + '.')

                                        #self._pt_model.prepare_worksheet(sheet, self.start_row, self.src_minf_cnt)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Preparing worksheet ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                        # Populate data from dataframe to worksheet

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Populating worksheet ' +
                                            sheet.title + '.')

                                        #self.temp_minf_cnt = self._pt_model.populate_worksheet(sheet, merged_price_minf_df, l_mapping, self.start_row)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Populating worksheet ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                        # Format worksheet

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Preparing worksheet ' +
                                            sheet.title + '.')

                                        #self._pt_model.format_worksheet(sheet, self.start_row)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Preparing worksheet ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                    else:

                                        # Prepare the worksheet

                                        self.txtProgress.emit(
                                            'Started: Processing ' +
                                            usage_type +
                                            ' - Preparing worksheet ' +
                                            sheet.title + '.')

                                        #self._pt_model.prepare_worksheet(sheet, self.start_row, 0)

                                        self.txtProgress.emit(
                                            'Finished: Processing ' +
                                            usage_type +
                                            ' - Preparing worksheet ' +
                                            sheet.title + '.')
                                        time.sleep(3)

                                        #Insert empty mapping logs

                                        key_tab = 'MINF' + '-' + sheet.title

                                        self._pt_model.append_template_logs(
                                            usage_type, 2, key_tab, [])

                                        if self._cancel_flg: return

                                success = True

                            except Exception as e:

                                self.currStatus.emit([
                                    usage_type, 'Populate Worksheet',
                                    sheet.title,
                                    str(e)
                                ])

                                response = None
                                while response is None:
                                    response = self._pt_model.replyBtn
                                    time.sleep(1)

                                    if response == QMessageBox.Abort:
                                        self._abort_flg = True
                                        self._pt_model.replyBtn = None
                                        return
                                    elif response == QMessageBox.Retry:
                                        self._pt_model.replyBtn = None
                                    elif response == QMessageBox.Ignore:
                                        self._pt_model.update_template_status(
                                            usage_type, 'i')
                                        self._pt_model.replyBtn = None
                                        success = True
                                    elif response == QMessageBox.Close:
                                        self._abort_flg = True
                                        self._pt_model.replyBtn = None
                                        return

                    if self._cancel_flg: break

                    #Update Status
                    self._pt_model.update_template_status(usage_type, 'c')

                    #Price Counts

                    self.txtProgress.emit('Started: Processing ' + usage_type +
                                          ' - Generating Data Counts.')

                    if not df_price.empty and not self._abort_flg:

                        data = {
                            'Source': self.src_price_cnt,
                            'Template': self.temp_price_cnt
                        }
                        self._pt_model.append_template_logs(
                            usage_type, 3, 'Price', data)

                    else:

                        data = {'Source': 0, 'Template': 0}
                        self._pt_model.append_template_logs(
                            usage_type, 3, 'Price', data)

                    #Scales Counts

                    if not df_scales.empty and not self._abort_flg:

                        data = {
                            'Source': self.src_scales_cnt,
                            'Template': self.temp_scales_cnt
                        }
                        self._pt_model.append_template_logs(
                            usage_type, 3, 'Scales', data)

                    else:
                        data = {'Source': 0, 'Template': 0}
                        self._pt_model.append_template_logs(
                            usage_type, 3, 'Scales', data)

                    #MinFee Counts

                    if not df_minf.empty and not self._abort_flg:

                        data = {
                            'Source': self.src_minf_cnt,
                            'Template': self.temp_minf_cnt
                        }
                        self._pt_model.append_template_logs(
                            usage_type, 3, 'MINF', data)

                    else:
                        data = {'Source': 0, 'Template': 0}
                        self._pt_model.append_template_logs(
                            usage_type, 3, 'MINF', data)

                    if self._cancel_flg: break

                    self.txtProgress.emit('Finished: Processing ' +
                                          usage_type +
                                          ' - Generating Data Counts.')
                    time.sleep(3)

                    #Save to workbook in output folder

                    status = self._pt_model.get_template_status(usage_type)

                    if status == 'c':

                        success = False
                        while not success:
                            try:
                                self.txtProgress.emit(
                                    'Started: Processing ' + usage_type +
                                    ' - Saving Workbook to Output Folder.')

                                output_filename = self._tgt_folder + "\\" + template_filename

                                temp_workbook.save(output_filename)

                                self.txtProgress.emit(
                                    'Started: Processing ' + usage_type +
                                    ' - Saving Workbook to Output Folder.')
                                time.sleep(3)

                                success = True
                            except Exception as e:

                                self.currStatus.emit([
                                    usage_type, 'Save Template',
                                    output_filename,
                                    str(e)
                                ])

                                response = None
                                while response is None:
                                    response = self._pt_model.replyBtn
                                    time.sleep(1)

                                if response == QMessageBox.Abort:
                                    self._abort_flg = True
                                    self._pt_model.replyBtn = None
                                    success = True
                                elif response == QMessageBox.Retry:
                                    self._pt_model.replyBtn = None
                                elif response == QMessageBox.Ignore:
                                    self._pt_model.update_template_status(
                                        usage_type, 'i')
                                    self._pt_model.replyBtn = None
                                    success = True
                                elif response == QMessageBox.Close:
                                    self._abort_flg = True
                                    self._pt_model.replyBtn = None
                                    success = True

                self._progress_count += 1
                self.countProgress.emit(self._progress_count)

            ####### Program End #########

            ### Display Elapsed Time ###

            self.update_elapsed_time()

            self.txtProgress.emit('Finished')

    def stop(self):
        self.is_running = False

    def update_elapsed_time(self):

        secs = self.timer.elapsed() / 1000
        mins = (secs / 60) % 60
        hours = (secs / 3600)
        seconds = secs % 60

        self.elapsed_time = str(hours).split('.')[0] + ' Hours ' + str(
            mins).split('.')[0] + ' Minutes ' + str(seconds).split(
                '.')[0] + ' Seconds'

    def get_all_usage_types(self):
        return list(self.df_price_all.USAGE_TYPE_CD.unique())[1:]
예제 #28
0
class DownloadItem(QWidget, Ui_DownloadItem):
    """
    Class implementing a widget controlling a download.
    
    @signal statusChanged() emitted upon a status change of a download
    @signal downloadFinished() emitted when a download finished
    @signal progress(int, int) emitted to signal the download progress
    """
    statusChanged = pyqtSignal()
    downloadFinished = pyqtSignal()
    progress = pyqtSignal(int, int)
    
    Downloading = 0
    DownloadSuccessful = 1
    DownloadCancelled = 2
    
    def __init__(self, reply=None, requestFilename=False, webPage=None,
                 download=False, parent=None, mainWindow=None):
        """
        Constructor
        
        @keyparam reply reference to the network reply object (QNetworkReply)
        @keyparam requestFilename flag indicating to ask the user for a
            filename (boolean)
        @keyparam webPage reference to the web page object the download
            originated from (QWebPage)
        @keyparam download flag indicating a download operation (boolean)
        @keyparam parent reference to the parent widget (QWidget)
        @keyparam mainWindow reference to the main window (HelpWindow)
        """
        super(DownloadItem, self).__init__(parent)
        self.setupUi(self)
        
        p = self.infoLabel.palette()
        p.setColor(QPalette.Text, Qt.darkGray)
        self.infoLabel.setPalette(p)
        
        self.progressBar.setMaximum(0)
        
        self.__isFtpDownload = reply is not None and \
            reply.url().scheme() == "ftp"
        
        self.tryAgainButton.setIcon(UI.PixmapCache.getIcon("restart.png"))
        self.tryAgainButton.setEnabled(False)
        self.tryAgainButton.setVisible(False)
        self.stopButton.setIcon(UI.PixmapCache.getIcon("stopLoading.png"))
        self.pauseButton.setIcon(UI.PixmapCache.getIcon("pause.png"))
        self.openButton.setIcon(UI.PixmapCache.getIcon("open.png"))
        self.openButton.setEnabled(False)
        self.openButton.setVisible(False)
        if self.__isFtpDownload:
            self.stopButton.setEnabled(False)
            self.stopButton.setVisible(False)
            self.pauseButton.setEnabled(False)
            self.pauseButton.setVisible(False)
        
        self.__state = DownloadItem.Downloading
        
        icon = self.style().standardIcon(QStyle.SP_FileIcon)
        self.fileIcon.setPixmap(icon.pixmap(48, 48))
        
        self.__mainWindow = mainWindow
        self.__reply = reply
        self.__requestFilename = requestFilename
        self.__page = webPage
        self.__pageUrl = webPage and webPage.mainFrame().url() or QUrl()
        self.__toDownload = download
        self.__bytesReceived = 0
        self.__bytesTotal = -1
        self.__downloadTime = QTime()
        self.__output = QFile()
        self.__fileName = ""
        self.__originalFileName = ""
        self.__startedSaving = False
        self.__finishedDownloading = False
        self.__gettingFileName = False
        self.__canceledFileSelect = False
        self.__autoOpen = False
        
        self.__sha1Hash = QCryptographicHash(QCryptographicHash.Sha1)
        self.__md5Hash = QCryptographicHash(QCryptographicHash.Md5)
        
        if not requestFilename:
            self.__requestFilename = \
                Preferences.getUI("RequestDownloadFilename")
        
        self.__initialize()
    
    def __initialize(self, tryAgain=False):
        """
        Private method to (re)initialize the widget.
        
        @param tryAgain flag indicating a retry (boolean)
        """
        if self.__reply is None:
            return
        
        self.__startedSaving = False
        self.__finishedDownloading = False
        self.__bytesReceived = 0
        self.__bytesTotal = -1
        
        self.__sha1Hash.reset()
        self.__md5Hash.reset()
        
        # start timer for the download estimation
        self.__downloadTime.start()
        
        # attach to the reply object
        self.__url = self.__reply.url()
        self.__reply.setParent(self)
        self.__reply.setReadBufferSize(16 * 1024 * 1024)
        self.__reply.readyRead.connect(self.__readyRead)
        self.__reply.error.connect(self.__networkError)
        self.__reply.downloadProgress.connect(self.__downloadProgress)
        self.__reply.metaDataChanged.connect(self.__metaDataChanged)
        self.__reply.finished.connect(self.__finished)
        
        # reset info
        self.infoLabel.clear()
        self.progressBar.setValue(0)
        self.__getFileName()
        
        if self.__reply.error() != QNetworkReply.NoError:
            self.__networkError()
            self.__finished()
    
    def __getFileName(self):
        """
        Private method to get the file name to save to from the user.
        """
        if self.__gettingFileName:
            return
        
        import Helpviewer.HelpWindow
        downloadDirectory = Helpviewer.HelpWindow.HelpWindow\
            .downloadManager().downloadDirectory()
        
        if self.__fileName:
            fileName = self.__fileName
            originalFileName = self.__originalFileName
            self.__toDownload = True
            ask = False
        else:
            defaultFileName, originalFileName = \
                self.__saveFileName(downloadDirectory)
            fileName = defaultFileName
            self.__originalFileName = originalFileName
            ask = True
        self.__autoOpen = False
        if not self.__toDownload:
            from .DownloadAskActionDialog import DownloadAskActionDialog
            url = self.__reply.url()
            dlg = DownloadAskActionDialog(
                QFileInfo(originalFileName).fileName(),
                self.__reply.header(QNetworkRequest.ContentTypeHeader),
                "{0}://{1}".format(url.scheme(), url.authority()),
                self)
            if dlg.exec_() == QDialog.Rejected or dlg.getAction() == "cancel":
                self.progressBar.setVisible(False)
                self.__reply.close()
                self.on_stopButton_clicked()
                self.filenameLabel.setText(
                    self.tr("Download canceled: {0}").format(
                        QFileInfo(defaultFileName).fileName()))
                self.__canceledFileSelect = True
                return
            
            if dlg.getAction() == "scan":
                self.__mainWindow.requestVirusTotalScan(url)
                
                self.progressBar.setVisible(False)
                self.__reply.close()
                self.on_stopButton_clicked()
                self.filenameLabel.setText(
                    self.tr("VirusTotal scan scheduled: {0}").format(
                        QFileInfo(defaultFileName).fileName()))
                self.__canceledFileSelect = True
                return
            
            self.__autoOpen = dlg.getAction() == "open"
            if PYQT_VERSION_STR >= "5.0.0":
                from PyQt5.QtCore import QStandardPaths
                tempLocation = QStandardPaths.standardLocations(
                    QStandardPaths.TempLocation)[0]
            else:
                from PyQt5.QtGui import QDesktopServices
                tempLocation = QDesktopServices.storageLocation(
                    QDesktopServices.TempLocation)
            fileName = tempLocation + '/' + \
                QFileInfo(fileName).completeBaseName()
        
        if ask and not self.__autoOpen and self.__requestFilename:
            self.__gettingFileName = True
            fileName = E5FileDialog.getSaveFileName(
                None,
                self.tr("Save File"),
                defaultFileName,
                "")
            self.__gettingFileName = False
            if not fileName:
                self.progressBar.setVisible(False)
                self.__reply.close()
                self.on_stopButton_clicked()
                self.filenameLabel.setText(
                    self.tr("Download canceled: {0}")
                        .format(QFileInfo(defaultFileName).fileName()))
                self.__canceledFileSelect = True
                return
        
        fileInfo = QFileInfo(fileName)
        Helpviewer.HelpWindow.HelpWindow.downloadManager()\
            .setDownloadDirectory(fileInfo.absoluteDir().absolutePath())
        self.filenameLabel.setText(fileInfo.fileName())
        
        self.__output.setFileName(fileName + ".part")
        self.__fileName = fileName
        
        # check file path for saving
        saveDirPath = QFileInfo(self.__fileName).dir()
        if not saveDirPath.exists():
            if not saveDirPath.mkpath(saveDirPath.absolutePath()):
                self.progressBar.setVisible(False)
                self.on_stopButton_clicked()
                self.infoLabel.setText(self.tr(
                    "Download directory ({0}) couldn't be created.")
                    .format(saveDirPath.absolutePath()))
                return
        
        self.filenameLabel.setText(QFileInfo(self.__fileName).fileName())
        if self.__requestFilename:
            self.__readyRead()
    
    def __saveFileName(self, directory):
        """
        Private method to calculate a name for the file to download.
        
        @param directory name of the directory to store the file into (string)
        @return proposed filename and original filename (string, string)
        """
        path = parseContentDisposition(self.__reply)
        info = QFileInfo(path)
        baseName = info.completeBaseName()
        endName = info.suffix()
        
        origName = baseName
        if endName:
            origName += '.' + endName
        
        name = directory + baseName
        if endName:
            name += '.' + endName
            if not self.__requestFilename:
                # do not overwrite, if the user is not being asked
                i = 1
                while QFile.exists(name):
                    # file exists already, don't overwrite
                    name = directory + baseName + ('-{0:d}'.format(i))
                    if endName:
                        name += '.' + endName
                    i += 1
        return name, origName
    
    def __open(self):
        """
        Private slot to open the downloaded file.
        """
        info = QFileInfo(self.__output)
        url = QUrl.fromLocalFile(info.absoluteFilePath())
        QDesktopServices.openUrl(url)
    
    @pyqtSlot()
    def on_tryAgainButton_clicked(self):
        """
        Private slot to retry the download.
        """
        self.retry()
    
    def retry(self):
        """
        Public slot to retry the download.
        """
        if not self.tryAgainButton.isEnabled():
            return
        
        self.tryAgainButton.setEnabled(False)
        self.tryAgainButton.setVisible(False)
        self.openButton.setEnabled(False)
        self.openButton.setVisible(False)
        if not self.__isFtpDownload:
            self.stopButton.setEnabled(True)
            self.stopButton.setVisible(True)
            self.pauseButton.setEnabled(True)
            self.pauseButton.setVisible(True)
        self.progressBar.setVisible(True)
        
        if self.__page:
            nam = self.__page.networkAccessManager()
        else:
            import Helpviewer.HelpWindow
            nam = Helpviewer.HelpWindow.HelpWindow.networkAccessManager()
        reply = nam.get(QNetworkRequest(self.__url))
        if self.__output.exists():
            self.__output.remove()
        self.__output = QFile()
        self.__reply = reply
        self.__initialize(tryAgain=True)
        self.__state = DownloadItem.Downloading
        self.statusChanged.emit()
    
    @pyqtSlot(bool)
    def on_pauseButton_clicked(self, checked):
        """
        Private slot to pause the download.
        
        @param checked flag indicating the state of the button (boolean)
        """
        if checked:
            self.__reply.readyRead.disconnect(self.__readyRead)
            self.__reply.setReadBufferSize(16 * 1024)
        else:
            self.__reply.readyRead.connect(self.__readyRead)
            self.__reply.setReadBufferSize(16 * 1024 * 1024)
            self.__readyRead()
    
    @pyqtSlot()
    def on_stopButton_clicked(self):
        """
        Private slot to stop the download.
        """
        self.cancelDownload()
    
    def cancelDownload(self):
        """
        Public slot to stop the download.
        """
        self.setUpdatesEnabled(False)
        if not self.__isFtpDownload:
            self.stopButton.setEnabled(False)
            self.stopButton.setVisible(False)
            self.pauseButton.setEnabled(False)
            self.pauseButton.setVisible(False)
        self.tryAgainButton.setEnabled(True)
        self.tryAgainButton.setVisible(True)
        self.openButton.setEnabled(False)
        self.openButton.setVisible(False)
        self.setUpdatesEnabled(True)
        self.__state = DownloadItem.DownloadCancelled
        self.__reply.abort()
        self.downloadFinished.emit()
    
    @pyqtSlot()
    def on_openButton_clicked(self):
        """
        Private slot to open the downloaded file.
        """
        self.openFile()
    
    def openFile(self):
        """
        Public slot to open the downloaded file.
        """
        info = QFileInfo(self.__fileName)
        url = QUrl.fromLocalFile(info.absoluteFilePath())
        QDesktopServices.openUrl(url)
    
    def openFolder(self):
        """
        Public slot to open the folder containing the downloaded file.
        """
        info = QFileInfo(self.__fileName)
        url = QUrl.fromLocalFile(info.absolutePath())
        QDesktopServices.openUrl(url)
    
    def __readyRead(self):
        """
        Private slot to read the available data.
        """
        if self.__requestFilename and not self.__output.fileName():
            return
        
        if not self.__output.isOpen():
            # in case someone else has already put a file there
            if not self.__requestFilename:
                self.__getFileName()
            if not self.__output.open(QIODevice.WriteOnly):
                self.infoLabel.setText(
                    self.tr("Error opening save file: {0}")
                    .format(self.__output.errorString()))
                self.on_stopButton_clicked()
                self.statusChanged.emit()
                return
            self.statusChanged.emit()
        
        buffer = self.__reply.readAll()
        self.__sha1Hash.addData(buffer)
        self.__md5Hash.addData(buffer)
        bytesWritten = self.__output.write(buffer)
        if bytesWritten == -1:
            self.infoLabel.setText(
                self.tr("Error saving: {0}")
                    .format(self.__output.errorString()))
            self.on_stopButton_clicked()
        else:
            self.__startedSaving = True
            if self.__finishedDownloading:
                self.__finished()
    
    def __networkError(self):
        """
        Private slot to handle a network error.
        """
        self.infoLabel.setText(
            self.tr("Network Error: {0}")
                .format(self.__reply.errorString()))
        self.tryAgainButton.setEnabled(True)
        self.tryAgainButton.setVisible(True)
        self.downloadFinished.emit()
    
    def __metaDataChanged(self):
        """
        Private slot to handle a change of the meta data.
        """
        locationHeader = self.__reply.header(QNetworkRequest.LocationHeader)
        if locationHeader and locationHeader.isValid():
            self.__url = QUrl(locationHeader)
            import Helpviewer.HelpWindow
            self.__reply = Helpviewer.HelpWindow.HelpWindow\
                .networkAccessManager().get(QNetworkRequest(self.__url))
            self.__initialize()
    
    def __downloadProgress(self, bytesReceived, bytesTotal):
        """
        Private method to show the download progress.
        
        @param bytesReceived number of bytes received (integer)
        @param bytesTotal number of total bytes (integer)
        """
        self.__bytesReceived = bytesReceived
        self.__bytesTotal = bytesTotal
        currentValue = 0
        totalValue = 0
        if bytesTotal > 0:
            currentValue = bytesReceived * 100 / bytesTotal
            totalValue = 100
        self.progressBar.setValue(currentValue)
        self.progressBar.setMaximum(totalValue)
        
        self.progress.emit(currentValue, totalValue)
        self.__updateInfoLabel()
    
    def bytesTotal(self):
        """
        Public method to get the total number of bytes of the download.
        
        @return total number of bytes (integer)
        """
        if self.__bytesTotal == -1:
            self.__bytesTotal = self.__reply.header(
                QNetworkRequest.ContentLengthHeader)
            if self.__bytesTotal is None:
                self.__bytesTotal = -1
        return self.__bytesTotal
    
    def bytesReceived(self):
        """
        Public method to get the number of bytes received.
        
        @return number of bytes received (integer)
        """
        return self.__bytesReceived
    
    def remainingTime(self):
        """
        Public method to get an estimation for the remaining time.
        
        @return estimation for the remaining time (float)
        """
        if not self.downloading():
            return -1.0
        
        if self.bytesTotal() == -1:
            return -1.0
        
        cSpeed = self.currentSpeed()
        if cSpeed != 0:
            timeRemaining = (self.bytesTotal() - self.bytesReceived()) / cSpeed
        else:
            timeRemaining = 1
        
        # ETA should never be 0
        if timeRemaining == 0:
            timeRemaining = 1
        
        return timeRemaining
    
    def currentSpeed(self):
        """
        Public method to get an estimation for the download speed.
        
        @return estimation for the download speed (float)
        """
        if not self.downloading():
            return -1.0
        
        return self.__bytesReceived * 1000.0 / self.__downloadTime.elapsed()
    
    def __updateInfoLabel(self):
        """
        Private method to update the info label.
        """
        if self.__reply.error() != QNetworkReply.NoError:
            return
        
        bytesTotal = self.bytesTotal()
        running = not self.downloadedSuccessfully()
        
        speed = self.currentSpeed()
        timeRemaining = self.remainingTime()
        
        info = ""
        if running:
            remaining = ""
            
            if bytesTotal > 0:
                remaining = timeString(timeRemaining)
            
            info = self.tr("{0} of {1} ({2}/sec)\n{3}")\
                .format(
                    dataString(self.__bytesReceived),
                    bytesTotal == -1 and self.tr("?")
                    or dataString(bytesTotal),
                    dataString(int(speed)),
                    remaining)
        else:
            if self.__bytesReceived == bytesTotal or bytesTotal == -1:
                info = self.tr("{0} downloaded\nSHA1: {1}\nMD5: {2}")\
                    .format(dataString(self.__output.size()),
                            str(self.__sha1Hash.result().toHex(),
                                encoding="ascii"),
                            str(self.__md5Hash.result().toHex(),
                                encoding="ascii")
                            )
            else:
                info = self.tr("{0} of {1} - Stopped")\
                    .format(dataString(self.__bytesReceived),
                            dataString(bytesTotal))
        self.infoLabel.setText(info)
    
    def downloading(self):
        """
        Public method to determine, if a download is in progress.
        
        @return flag indicating a download is in progress (boolean)
        """
        return self.__state == DownloadItem.Downloading
    
    def downloadedSuccessfully(self):
        """
        Public method to check for a successful download.
        
        @return flag indicating a successful download (boolean)
        """
        return self.__state == DownloadItem.DownloadSuccessful
    
    def downloadCanceled(self):
        """
        Public method to check, if the download was cancelled.
        
        @return flag indicating a canceled download (boolean)
        """
        return self.__state == DownloadItem.DownloadCancelled
    
    def __finished(self):
        """
        Private slot to handle the download finished.
        """
        self.__finishedDownloading = True
        if not self.__startedSaving:
            return
        
        noError = self.__reply.error() == QNetworkReply.NoError
        
        self.progressBar.setVisible(False)
        if not self.__isFtpDownload:
            self.stopButton.setEnabled(False)
            self.stopButton.setVisible(False)
            self.pauseButton.setEnabled(False)
            self.pauseButton.setVisible(False)
        self.openButton.setEnabled(noError)
        self.openButton.setVisible(noError)
        self.__output.close()
        if QFile.exists(self.__fileName):
            QFile.remove(self.__fileName)
        self.__output.rename(self.__fileName)
        self.__updateInfoLabel()
        self.__state = DownloadItem.DownloadSuccessful
        self.statusChanged.emit()
        self.downloadFinished.emit()
        
        if self.__autoOpen:
            self.__open()
    
    def canceledFileSelect(self):
        """
        Public method to check, if the user canceled the file selection.
        
        @return flag indicating cancellation (boolean)
        """
        return self.__canceledFileSelect
    
    def setIcon(self, icon):
        """
        Public method to set the download icon.
        
        @param icon reference to the icon to be set (QIcon)
        """
        self.fileIcon.setPixmap(icon.pixmap(48, 48))
    
    def fileName(self):
        """
        Public method to get the name of the output file.
        
        @return name of the output file (string)
        """
        return self.__fileName
    
    def absoluteFilePath(self):
        """
        Public method to get the absolute path of the output file.
        
        @return absolute path of the output file (string)
        """
        return QFileInfo(self.__fileName).absoluteFilePath()
    
    def getData(self):
        """
        Public method to get the relevant download data.
        
        @return tuple of URL, save location, flag and the
            URL of the related web page (QUrl, string, boolean,QUrl)
        """
        return (self.__url, QFileInfo(self.__fileName).filePath(),
                self.downloadedSuccessfully(), self.__pageUrl)
    
    def setData(self, data):
        """
        Public method to set the relevant download data.
        
        @param data tuple of URL, save location, flag and the
            URL of the related web page (QUrl, string, boolean, QUrl)
        """
        self.__url = data[0]
        self.__fileName = data[1]
        self.__pageUrl = data[3]
        self.__isFtpDownload = self.__url.scheme() == "ftp"
        
        self.filenameLabel.setText(QFileInfo(self.__fileName).fileName())
        self.infoLabel.setText(self.__fileName)
        
        self.stopButton.setEnabled(False)
        self.stopButton.setVisible(False)
        self.pauseButton.setEnabled(False)
        self.pauseButton.setVisible(False)
        self.openButton.setEnabled(data[2])
        self.openButton.setVisible(data[2])
        self.tryAgainButton.setEnabled(not data[2])
        self.tryAgainButton.setVisible(not data[2])
        if data[2]:
            self.__state = DownloadItem.DownloadSuccessful
        else:
            self.__state = DownloadItem.DownloadCancelled
        self.progressBar.setVisible(False)
    
    def getInfoData(self):
        """
        Public method to get the text of the info label.
        
        @return text of the info label (string)
        """
        return self.infoLabel.text()
    
    def getPageUrl(self):
        """
        Public method to get the URL of the download page.
        
        @return URL of the download page (QUrl)
        """
        return self.__pageUrl
예제 #29
0
class CaptureThread(QThread):
    updateStatisticsInGUI = pyqtSignal(ThreadStatisticsData)
    end = pyqtSignal()

    def __init__(self,
                 sharedImageBuffer,
                 deviceUrl,
                 dropFrameIfBufferFull,
                 apiPreference,
                 width,
                 height,
                 setting,
                 parent=None):
        super(CaptureThread, self).__init__(parent)
        self.t = QTime()
        self.doStopMutex = QMutex()
        self.fps = Queue()
        # Save passed parameters
        self.sharedImageBuffer = sharedImageBuffer
        self.dropFrameIfBufferFull = dropFrameIfBufferFull
        self.deviceUrl = deviceUrl
        self._deviceUrl = int(deviceUrl) if deviceUrl.isdigit() else deviceUrl
        self.localVideo = True if os.path.exists(self._deviceUrl) else False
        self.apiPreference = apiPreference
        self.width = width
        self.height = height
        # Initialize variables(s)
        self.captureTime = 0
        self.doStop = False
        self.sampleNumber = 0
        self.fpsSum = 0.0
        self.statsData = ThreadStatisticsData()
        self.defaultTime = 0
        t = datetime.strptime(setting.skip_duration, '%H:%M:%S')
        self.skip_duration = timedelta(hours=t.hour,
                                       minutes=t.minute,
                                       seconds=t.second)
        self.video_date_time = datetime.strptime(
            "{} {}".format(setting.video_date, setting.video_time),
            '%d/%m/%Y %H:%M:%S')
        self.starting_time = self.video_date_time
        self.remain_video = None
        self.pause = False

    def update(self):
        current_frame = self.cap.get(1)
        process_time_second = round(current_frame / self.videofps, 0)
        self.video_date_time = self.starting_time + timedelta(
            seconds=process_time_second)
        if round(current_frame % self.videofps) == 0:
            self.remain_video = self.video_date_time - self.starting_time

        self.sharedImageBuffer.video_date_time = self.video_date_time
        self.sharedImageBuffer.remain_video = self.remain_video

    def run(self):
        pause = False
        while True:
            if self.pause:
                continue
            ################################
            # Stop thread if doStop = TRUE #
            ################################
            self.doStopMutex.lock()
            if self.doStop:
                self.doStop = False
                self.doStopMutex.unlock()
                break
            self.doStopMutex.unlock()
            ################################
            ################################

            # Synchronize with other streams (if enabled for this stream)
            self.sharedImageBuffer.sync(self.deviceUrl)

            # Capture frame ( if available)
            if not self.cap.grab():
                if pause or not self.localVideo:
                    continue
                # Video End
                pause = True
                self.end.emit()
                continue

            # Retrieve frame
            _, self.grabbedFrame = self.cap.retrieve()
            self.update()
            # Add frame to buffer
            self.sharedImageBuffer.getByDeviceUrl(self.deviceUrl).add(
                self.grabbedFrame, self.dropFrameIfBufferFull)

            self.statsData.nFramesProcessed += 1
            # Inform GUI of updated statistics
            self.updateStatisticsInGUI.emit(self.statsData)

            # Limit fps
            delta = self.defaultTime - self.t.elapsed()
            # delta = self.defaultTime - self.captureTime
            if delta > 0:
                self.msleep(delta)
            # Save capture time
            self.captureTime = self.t.elapsed()

            # Update statistics
            self.updateFPS(self.captureTime)

            # Start timer (used to calculate capture rate)
            self.t.start()

        qDebug("Stopping capture thread...")

    def stop(self):
        with QMutexLocker(self.doStopMutex):
            self.doStop = True

    def connectToCamera(self):
        # Open camera
        self.cap = cv2.cudacodec.createVideoReader(self._deviceUrl,
                                                   self.apiPreference)
        self.videofps = self.cap.get(5)
        if self.skip_duration:
            self.cap.set(cv2.CAP_PROP_POS_FRAMES,
                         self.videofps * self.skip_duration.total_seconds())
            self.video_date_time = self.video_date_time + self.skip_duration

        # Set resolution
        if self.width != -1:
            self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.width)
        if self.height != -1:
            self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.height)

        if camOpenResult:
            try:
                self.defaultTime = int(1000 / self.cap.get(cv2.CAP_PROP_FPS))
            except:
                self.defaultTime = 40
        # Return result
        return camOpenResult

    def disconnectCamera(self):
        # Camera is connected
        if self.cap.isOpened():
            # Disconnect camera
            self.cap.release()
            return True
        # Camera is NOT connected
        else:
            return False

    def isCameraConnected(self):
        return self.cap.isOpened()

    def getInputSourceWidth(self):
        return self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)

    def getInputSourceHeight(self):
        return self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)

    def updateFPS(self, timeElapsed):
        # Add instantaneous FPS value to queue
        if timeElapsed > 0:
            self.fps.put(1000 / timeElapsed)
            # Increment sample Number
            self.sampleNumber += 1

        # Maximum size of queue is DEFAULT_CAPTURE_FPS_STAT_QUEUE_LENGTH
        if self.fps.qsize() > CAPTURE_FPS_STAT_QUEUE_LENGTH:
            self.fps.get()
        # Update FPS value every DEFAULT_CAPTURE_FPS_STAT_QUEUE_LENGTH samples
        if self.fps.qsize(
        ) == CAPTURE_FPS_STAT_QUEUE_LENGTH and self.sampleNumber == CAPTURE_FPS_STAT_QUEUE_LENGTH:
            # Empty queue and store sum
            while not self.fps.empty():
                self.fpsSum += self.fps.get()
            # Calculate average FPS
            self.statsData.averageFPS = self.fpsSum / CAPTURE_FPS_STAT_QUEUE_LENGTH
            # Reset sum
            self.fpsSum = 0.0
            # Reset sample Number
            self.sampleNumber = 0
예제 #30
0
class Example(QMainWindow):
    def __init__(self, pipe):
        super().__init__()

        self.pipe = pipe

        self.gameConfig = GameConfig()
        self.playing = False
        self.game_over = []
        self.all_die = 0
        self.currentPlayer = 0

        self.timer = QBasicTimer(
        )  # Used for controlling the game speed, and the canvas update
        self.speed = 100
        self.timeCounter = 0
        self.playtime = QTime()
        self.counter = []

        self.rectangles_to_draw = []
        self.playerLabels = []
        self.scoreLabels = []
        self.sec_counter = 1
        self.special_food_border = False
        self.special_food = False
        self.score = [0, 0, 0, 0]
        self.initUI()

    # definise izgled glavnog prozora
    def initUI(self):
        self.setGeometry(200, 200, 900, 600)
        self.setWindowTitle("TurnSnakeGdxGame")
        self.setWindowIcon(QIcon('snake.png'))
        self.setStyleSheet("background-image : url(rsz_snake_background.png);")

        self.timerLabel = QLabel(self)
        self.timeElapsed = "Time Elapsed:"
        self.timerLabel.setText(str(self.timeElapsed))
        self.timerLabel.resize(100, 50)
        self.timerLabel.move(600, 450)
        self.timerLabel.setStyleSheet("color: black;")

        self.timerCounterLabel = QLabel(self)
        self.timeCounter = 0
        self.timerCounterLabel.setText(str(self.timeCounter))
        self.timerCounterLabel.resize(50, 50)
        self.timerCounterLabel.move(700, 450)
        self.timerCounterLabel.setStyleSheet("color: black;")

        # next player button
        self.btn = QPushButton('Next Player', self)
        self.btn.setStyleSheet("background-color: purple; color: white;")
        self.btn.clicked.connect(self.next_player)
        self.btn.setGeometry(600, 520, 270, 50)

        menu = self.menuBar().addMenu("New game")
        self.menuBar().setStyleSheet("color: black;")
        self.hostAct = QAction("&Start Game", self)
        self.hostAct.triggered.connect(self.start)
        menu.addAction(self.hostAct)
        self.show()

    # metoda koja poziva metode za crtanje svih elemenata na terenu
    def paintEvent(self, e):
        qp = QPainter()
        qp.begin(self)
        self.draw_rectangles(qp)

        if self.playing is True:
            if self.special_food_border is False:
                if self.sec_counter % 17 == 0:
                    self.draw_border()
                    self.special_food_border = True
        qp.end()

        painter = QPainter(self)

        painter.setPen(QPen(Qt.darkGreen, 20, Qt.SolidLine))
        painter.drawRect(20, 40, 520, 540)

    # iscrtava hranu i zmije
    def draw_rectangles(self, qp):
        col = QColor(0, 0, 0)
        col.setNamedColor('#d4d4d4')
        qp.setPen(col)

        for rect in self.rectangles_to_draw:
            qp.setBrush(rect['color'])
            qp.drawRect(rect['x'], rect['y'], rect['width'], rect['height'])

    ## crta granicu terena
    def draw_border(self):
        painter = QPainter(self)

        painter.setPen(QPen(Qt.darkGreen, 5, Qt.SolidLine))
        painter.drawRect(450, 500, 60, 60)

    ## postavljanje labela za rezultat igraca
    def set_labels(self):
        for i in range(self.gameConfig.playerNumber):
            space = 15 + i * 50
            self.playerLabels.append(QLabel(self))
            self.player = "Player {}:".format(i + 1)
            self.playerLabels[i].setText(str(self.player))
            self.playerLabels[i].setGeometry(600, space, 100, 50)
            self.playerLabels[i].setStyleSheet("color: black;")
            self.playerLabels[i].show()

            self.scoreLabels.append(QLabel(self))
            self.score[i] = 0
            self.scoreLabels[i].setText(str(self.score[3]))
            self.scoreLabels[i].setGeometry(660, space, 200, 50)
            self.scoreLabels[i].setStyleSheet("color: black;")
            self.scoreLabels[i].show()

    # sakrivanje labela ukoliko je broj igraca manji od 4
    def hide_labels(self):
        for i in range(self.gameConfig.playerNumber):
            self.playerLabels[i].hide()
            self.scoreLabels[i].hide()

    # promena boje teksta u labelama kao indikator aktivnosti trenutnog igraca
    def change_label_color(self):
        for i in range(self.gameConfig.playerNumber):
            self.playerLabels[i].setStyleSheet("color: black;")

        if self.currentPlayer == 0:
            self.playerLabels[0].setStyleSheet("color: red;")
        elif self.currentPlayer == 1:
            self.playerLabels[1].setStyleSheet("color: green;")
        elif self.currentPlayer == 2:
            self.playerLabels[2].setStyleSheet("color: blue;")
        elif self.currentPlayer == 3:
            self.playerLabels[3].setStyleSheet("color: purple;")

    # signalizira izmenu igraca
    def next_player(self):
        if self.playing is True:
            self.pipe.send({
                'event_type': 'next_player',
                'data': 'next_player'
            })
            time.sleep(0.1)

    # registruje da je tipka pritisnuta i salje informaciju u pajp
    def keyPressEvent(self, e):
        if self.playing is True:
            self.pipe.send({'event_type': 'key_pressed', 'data': e.key()})
            time.sleep(0.2)

    # thread
    def listen(self):
        while True:
            try:
                receive = self.pipe.recv()

                if receive['event_type'] == 'rectangles':
                    self.rectangles_to_draw = receive['data']
                    self.update()

                elif receive['event_type'] == 'score':
                    self.update_score(receive['data'], 1)
                elif receive['event_type'] == 'special_score':
                    self.update_score(receive['data'], receive['score_type'])
                    self.update_spec_food_value()
                elif receive['event_type'] == 'end_game':
                    self.all_die += 1
                    self.set_game_over(receive['data'])

                elif receive['event_type'] == 'current_player':
                    self.gameConfig.turnPlanTime = self.timeCounter
                    self.timerCounterLabel.setText(str(self.timeCounter))
                    self.currentPlayer = receive['data']
                    self.change_label_color()

            except BrokenPipeError as e:
                print(e)
                print('Broken pipe error')
                break
            except EOFError as e:
                print(e)
                print('EOFError')
                break

    # resetuje brojac za specijalnu hranu
    def update_spec_food_value(self):
        self.special_food = False
        self.special_food_border = False
        self.sec_counter = 1

    # slanje podataka u pajp i startovanje treda koji konstantno osluskuje da li ima pristiglih podataka
    def do_action(self, config: GameConfig):
        self.pipe.send({'event_type': 'start_game', 'data': config})
        # start thread which listens on the child_connection
        t = Thread(target=self.listen)
        t.start()

    def start(self):
        dialog = StartDialog(self)
        dialog.exec()

    # pokrece tajmer
    def reset_value(self):
        for i in range(self.gameConfig.playerNumber):
            self.game_over.append(1)
        for i in range(self.gameConfig.playerNumber):
            self.counter.append(0)

        self.playing = True

        self.timeCounter = self.gameConfig.turnPlanTime
        self.speed = 100
        self.playtime.start()
        self.timer.start(self.speed, Qt.PreciseTimer, self)

    # definise akciju posle pritisnutog start game dugmeta
    def start_game_pressed(self, gameConfig: GameConfig):
        self.menuBar().setDisabled(True)
        self.gameConfig = gameConfig
        if self.gameConfig.playerNumber > 4 or self.gameConfig.playerNumber < 2:
            dialog = ErrorDialog(self)
            dialog.exec()
            self.start()
        else:
            self.reset_value()
            self.set_labels()
            self.change_label_color()

            self.do_action(self.gameConfig)

    # prikazuje dijalog na ekranu
    def show_dialog(self, player: int):
        end_dialog = EndGameDialog(self, player)
        end_dialog.exec()

    # prikazuje specijalnu hranu
    def show_special_food(self):
        self.pipe.send({'event_type': 'special_food', 'data': 'next_player'})
        time.sleep(0.1)
        self.special_food = True

    def timerEvent(self, event: QTimerEvent) -> None:
        """
        In charge of, in this case, update the game and check the
        conditions to continue playing, grow, spawn food and special item
        """
        if self.playtime.elapsed() > 1000:
            self.sec_counter += 1
            self.gameConfig.turnPlanTime -= 1.0
            self.timerCounterLabel.setText(str(self.gameConfig.turnPlanTime))
            self.playtime.restart()
            if self.gameConfig.turnPlanTime == 0:
                self.next_player()
                self.gameConfig.turnPlanTime = self.timeCounter
                self.timerCounterLabel.setText(str(self.timeCounter))

        if self.sec_counter % 17 == 0:
            self.update()

        if self.sec_counter % 19 == 0 and self.special_food is False:
            self.show_special_food()

        # Check if the event if from the self.timer
        if event.timerId() is self.timer.timerId():
            if self.playing is True:
                if self.all_die == self.gameConfig.playerNumber - 1:
                    winner = self.winner()
                    self.playing = False
                    self.show_dialog(winner)
                    self.timer.stop()
                    return

        else:
            super(Example, self).timerEvent(event)

    # odredjuje koji igrac je pobedio
    def winner(self):
        for i in range(len(self.game_over)):
            if self.game_over[i] == 1:
                return i + 1

    # salje signal da je igra gotova u pajp
    def end_game(self, winner: int):
        self.pipe.send({'event_type': 'delete_all', 'data': winner})
        self.hide_labels()

    # salje signal da je za odredjenog igraca igra gotova
    def set_game_over(self, player: int):
        for i in range(self.gameConfig.playerNumber):
            if player == i:
                self.score[i] = "Game over"
                self.scoreLabels[i].setText(str(self.score[i]))
                self.game_over[i] = 0

    # menja rezultat u labelama za rezultat
    def update_score(self, player: int, points: int):
        for i in range(self.gameConfig.playerNumber):
            if player == i:
                self.score[i] = self.score[i] + points
                self.scoreLabels[i].setText(str(self.score[i]))

    def closeEvent(self, event):
        self.pipe.send({'event_type': 'close_app'})
예제 #31
0
class GLWidget(QOpenGLWidget):
    """
    OpenGL widget that shows a static 3D scene, allowing the observer to
    freely move and look around.
    """

    background_color = gl_array([1, 1, 1]) * 0.6
    ambient_color = gl_array([1, 1, 1]) * 0.1
    diffuse_color = gl_array([1, 1, 1])

    camera_speed = 1  # [m/s]
    zoom_speed = 1 / 10  # [1/deg]
    mouse_sensitivity = 1 / 100  # [rad/px]
    update_interval = 25  # [ms]

    shader_program = None
    update_timer = None

    def __init__(self, create_items, *args, **kwargs):
        """Create from a callable ``create_items: Camera -> [Object3D]``."""
        super().__init__(*args, **kwargs)
        self._create_items = create_items
        self.items = []
        self._key_state = {}
        self._update_time = QTime()
        self.resize(800, 600)
        self.camera = Camera()
        self.camera.updated.connect(self.update)
        surface_format = self.format()
        # Enable multisampling (for antialiasing):
        # (must be set before initializeGL)
        surface_format.setSamples(6)
        # Technically, we require only 3.0, but we request 3.2 because that
        # allows enforcing CoreProfile. Note that there is no guarantee that
        # we get the requested version, but let's at least improve our chances:
        surface_format.setVersion(3, 2)
        surface_format.setProfile(QSurfaceFormat.CoreProfile)
        self.setFormat(surface_format)

    def free(self):
        """Free all items."""
        for item in self.items:
            item.delete()
        self.items.clear()

    def closeEvent(self, event):
        """Free items."""
        self.free()
        super().closeEvent(event)

    def showEvent(self, event):
        """Start scene updates (camera movement)."""
        super().showEvent(event)
        if self.update_timer is None:
            self.update_timer = QTimer(self)
            self.update_timer.setInterval(self.update_interval)
            self.update_timer.timeout.connect(self.update_event)
            self.update_timer.start()
            self._update_time.start()

    def hideEvent(self, event):
        """Stop scene updates (camera movement)."""
        super().hideEvent(event)
        if self.update_timer is not None:
            self.update_timer.timeout.disconnect(self.update_event)
            self.update_timer.stop()
            self.update_timer = None

    # def GL(self):
    #     from PyQt5.QtGui import QOpenGLVersionProfile
    #     version = QOpenGLVersionProfile()
    #     version.setVersion(2, 0)
    #     return self.context().versionFunctions(version)

    def initializeGL(self):
        """Called after first creating a valid OpenGL context. Creates shader
        program, sets up camera and creates an initial scene."""
        logging.info('Initializing OpenGL')
        self.show_gl_info(GL.GL_VERSION, '  version:  ')
        self.show_gl_info(GL.GL_VENDOR, '  vendor:   ')
        self.show_gl_info(GL.GL_RENDERER, '  renderer: ')
        self.show_gl_info(GL.GL_SHADING_LANGUAGE_VERSION, '  shader:   ')
        logging.info(
            '  context:  {}.{}'.format(*self.context().format().version()))
        # We currently require modern OpenGL API for use of shaders etc. We
        # could ship a fallback implementation based on the deprecated API
        # (glBegin, etc) to be compatible with older devices, but that's
        # probably overkill.
        if not check_opengl_context(self.context(), (3, 0)):
            logging.error(
                "Cannot create shader with this version of OpenGL.\n"
                "This implementation uses the modern OpenGL API (>=3.0).")
            QTimer.singleShot(0, lambda: self.window().close())
            return
        self.create_shader_program()
        self.create_scene()
        # Activate wireframe:
        # GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE)
        camera = self.camera
        camera.look_from(camera.theta, camera.phi, camera.psi)

    def show_gl_info(self, spec, text):
        """Show GL version info."""
        try:
            string = GL.glGetString(spec).decode('utf-8')
        except GL.GLError:
            string = None
        if string:
            logging.info(text + string)
        else:
            logging.error(text + 'N/A')
        return string

    def create_scene(self):
        """Fetch new items from the given callable."""
        self.free()
        if self.shader_program is not None:
            self.items = self._create_items(self.camera)
            self.update()

    def paintGL(self):
        """Handle paint event by drawing the items returned by the creator
        function."""
        if not check_opengl_context(self.context(), (3, 0)):
            return
        program = self.shader_program
        projection = self.camera.projection(self.width(), self.height())
        set_uniform_matrix(program, "view", self.camera.view_matrix)
        set_uniform_matrix(program, "projection", projection)

        set_uniform_vector(program, "ambient_color", self.ambient_color)
        set_uniform_vector(program, "diffuse_color", self.diffuse_color)
        set_uniform_vector(program, "diffuse_position", self.camera.position)

        GL.glClearColor(*self.background_color, 0)
        GL.glEnable(GL.GL_DEPTH_TEST)
        GL.glEnable(GL.GL_MULTISAMPLE)
        GL.glEnable(GL.GL_BLEND)
        GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA)
        GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)

        # Draw transparent items after opaque ones, and sorted by distance to
        # the observer (far to near). Note that this is only an approximation
        # that is correct only for point-like items; a 100% correct blending
        # order would have to be decided on the level of fragments (based on
        # the interpolated depth value).
        items = sorted(
            self.items,
            key=lambda item: (
                item.opaque(),
                np.linalg.norm(self.camera.position - item.position()),
            ),
            reverse=True)
        for item in items:
            item.draw()

    def create_shader_program(self):
        """Create simple program with generic fragment/vertex shaders used to
        render objects with a simple ambient+diffuse lighting model."""
        self.shader_program = create_shader_program([
            load_shader(GL.GL_VERTEX_SHADER, 'shader_vertex.glsl'),
            load_shader(GL.GL_FRAGMENT_SHADER, 'shader_fragment.glsl'),
        ])

    def minimumSizeHint(self):
        return QSize(50, 50)

    def sizeHint(self):
        return QSize(400, 400)

    def wheelEvent(self, event):
        """Handle mouse wheel as zoom."""
        self.camera.zoom(self.zoom_speed * event.angleDelta().y())

    def mousePressEvent(self, event):
        """Handle camera look around."""
        self.last_mouse_position = event.pos()
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        """Handle camera look around."""
        camera = self.camera
        delta = event.pos() - self.last_mouse_position
        if event.buttons() == Qt.RightButton:
            dx = delta.x() * self.mouse_sensitivity
            dy = delta.y() * self.mouse_sensitivity
            if event.modifiers() & Qt.ShiftModifier:
                camera.look_from(camera.theta + dx, camera.phi - dy,
                                 camera.psi)
            else:
                camera.look_toward(camera.theta + dx, camera.phi - dy,
                                   camera.psi)
        elif event.buttons() == Qt.RightButton | Qt.LeftButton:
            camera.zoom(-delta.y())
        else:
            return super().mouseMoveEvent(event)
        self.last_mouse_position = event.pos()
        event.accept()

    def keyPressEvent(self, event):
        """Maintain a list of pressed keys for camera movement."""
        key = event.key()
        if key in (Qt.Key_Escape, Qt.Key_Q):
            self.window().close()
        if not event.isAutoRepeat():
            self._key_state[key] = True
        super().keyPressEvent(event)

    def keyReleaseEvent(self, event):
        """Maintain a list of pressed keys for camera movement."""
        if not event.isAutoRepeat():
            self._key_state[event.key()] = False

    def update_event(self):
        """Implement camera movement. Called regularly."""
        pressed = lambda k: self._key_state.get(k, 0)
        upward = pressed(Qt.Key_Space) - pressed(Qt.Key_Control)
        forward = ((pressed(Qt.Key_Up) or pressed(Qt.Key_W)) -
                   (pressed(Qt.Key_Down) or pressed(Qt.Key_S)))
        leftward = ((pressed(Qt.Key_Left) or pressed(Qt.Key_A)) -
                    (pressed(Qt.Key_Right) or pressed(Qt.Key_D)))

        # we use this "update time" (a.k.a. "game time") to maintain a
        # somewhat framerate independent movement speed:
        ms_elapsed = self._update_time.elapsed()
        self._update_time.start()

        if forward or upward or leftward:
            direction = np.array([-leftward, upward, -forward])
            direction = direction / np.linalg.norm(direction)
            translate = direction * self.camera_speed * (ms_elapsed / 1000)
            self.camera.translate(*translate)
예제 #32
0
class MainWindow(QMainWindow, Ui_MainWindow):
    """
    Class documentation goes here.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget (QWidget)
        """
        super(MainWindow, self).__init__(parent)
        self.regdialog=DialogRegister()
        self.setupUi(self)
        self.arith=None
        self.preference=DialogPreference()
        self.timer=QTimer()
        self.timer.setInterval(10)
        self.caseIsOpen=False
        self.labelTotalMark.setText("")
        self.labelTime.setText("")
        self.createConnections()
        self.qtime=QTime()
        self.timeStart=0
        self.timeElapsed=0
        self.modeModel=None
        self.diffiModel=None

    def createConnections(self):
        # self.actionNew_Test.triggered.connect(self.on_btnNew_clicked)
        # self.actionSave.triggered.connect(self.on_actionSave_triggered)
        # self.btnSave.clicked.connect(self.on_btnSave_clicked)
        self.tableTestpaper.itemChanged.connect(self.on_tableTestPaper_itemChanged)
        self.cmbDifficulty.currentIndexChanged.connect(self.on_cmbDifficulty_currentIndexChanged)
        self.cmbMode.currentIndexChanged.connect(self.on_cmbMode_currentIndexChanged)

        return

    def setArith(self,arith):
        self.arith=arith
        self.answers=np.zeros(arith.getnTest())+self.arith.smallest

        self.setDifficulty()
        self.setMode()
        if arith.timerOn==False:
            self.labelTimeName.hide()
            self.labelTime.hide()
        self.preference.setArith(arith)
        return

    def setMode(self): # only called once for initialization of main window
        if self.modeModel is None:
            self.modeModel = QStringListModel()
            self.cmbMode.setModel(self.modeModel)
        self.modeModel.setStringList(self.arith.modeTexts[self.arith.diffiLevel])
        self.cmbMode.setCurrentIndex(self.arith.mode)
        return

    def setDifficulty(self):
        if self.diffiModel is None:
            self.diffiModel=QStringListModel()
            self.cmbDifficulty.setModel(self.diffiModel)
        self.diffiModel.setStringList(self.arith.difficulties)
        self.cmbDifficulty.setCurrentIndex(self.arith.diffiLevel)
        return

    def on_cmbMode_currentIndexChanged(self):
        if self.arith:
            if self.cmbMode.currentIndex()>=0:
                self.arith.mode=self.cmbMode.currentIndex()
            else:
                if self.arith.mode>=len(self.arith.modeTexts[self.arith.diffiLevel]):
                    self.arith.mode=0
                self.cmbMode.setCurrentIndex(self.arith.mode)
        return
    def on_cmbDifficulty_currentIndexChanged(self):
        if self.arith:
            self.arith.diffiLevel=self.cmbDifficulty.currentIndex()
            if self.modeModel:
                self.modeModel.setStringList(self.arith.modeTexts[self.arith.diffiLevel])
        return

    @pyqtSlot()
    def on_tableTestPaper_itemChanged(self):
        self.caseIsOpen=True
        return
    @pyqtSlot()
    def on_btnNew_clicked(self):
        """
        Slot documentation goes here.
        """
        self.arith.new()
        self.resetWidgets()
        return

    def resetWidgets(self):
        self.newTestTable()
        self.updateWindow()
        self.caseIsOpen=True

        if self.arith.timerOn:
            # self.timer.start()
            self.qtime.restart()
        return
    def newTestTable(self):
        self.tableTestpaper.clear()

        ncolumn=3*self.arith.nDataColumn
        self.tableTestpaper.setColumnCount(ncolumn)
        nTest=self.arith.getnTest()
        nrow=ceil(nTest/self.arith.nDataColumn)
        self.tableTestpaper.setRowCount(nrow)
        self.tableTestpaper.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
        headerLabels=[]
        for i in range(0,self.arith.nDataColumn):
            labels=['Expression', 'Answer','Y/N']
            headerLabels+=labels
        self.tableTestpaper.setHorizontalHeaderLabels(headerLabels)
        self.tableTestpaper.resizeColumnsToContents()
        self.tableTestpaper.horizontalHeader().setStretchLastSection(True)
        self.tableTestpaper.horizontalHeader().resizeSections(QHeaderView.Stretch)

        for k in range(0,3,2):
            icol=0
            for j in range(0,self.arith.nDataColumn):
                irow=0
                for i in range(j,nTest,int(ncolumn/3)):
                    item=QTableWidgetItem()
                    flags=Qt.ItemIsSelectable | Qt.ItemIsEnabled
                    item.setFlags(flags)
                    self.tableTestpaper.setItem(irow,icol+k,item)
                    irow+=1
                icol+=3
        k=1
        icol=0
        for j in range(0,self.arith.nDataColumn):
            irow=0
            for i in range(j,nTest,int(ncolumn/3)):
                # item = QLineEdit()
                # item.setValidator(QIntValidator(item))
                # self.tableTestpaper.setCellWidget(irow, icol+k, item)
                item=QTableWidgetItem()
                flags=Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsEnabled
                item.setFlags(flags)
                self.tableTestpaper.setItem(irow,icol+k,item)
                irow+=1
            icol+=3
        return

    def updateTestPaper(self):
        ncolumn=3*self.arith.nDataColumn
        nTest=self.arith.getnTest()
        icol=0
        for j in range(0,self.arith.nDataColumn):
            irow=0
            for i in range(j,nTest,int(ncolumn/3)):
                self.tableTestpaper.item(irow,icol).setText(self.arith.texts[i])
                irow+=1
            icol+=3
        return

    def updateWindow(self):
        self.updateTestPaper()
        self.updateResultWindow()

        self.cmbDifficulty.setCurrentIndex(self.arith.diffiLevel)
        self.cmbMode.setCurrentIndex(self.arith.mode)
        return

    def updateResultWindow(self):
        # TODO:
        return

    def getAnswers(self):
        """
        read answer from self.tableTestPaper
        """
        ncolumn=3*self.arith.nDataColumn
        nTest=self.arith.getnTest()
        nrow=ceil(nTest/self.arith.nDataColumn)

        nsp=NumericStringParser()
        ok=False
        icol=1
        for j in range(0,self.arith.nDataColumn):
            irow=0
            for i in range(j,nTest,int(ncolumn/3)):
                text=self.tableTestpaper.item(irow,icol).text()
                # text=self.tableTestpaper.cellWidget(irow,icol).text()
                if not (text.strip()==str('')):
                    itext=int(text.strip(),10)
                    self.answers[i]=int(text.strip(),10)
                # goodanswers=nsp.eval(self.tableTestpaper.item(irow,icol-1).text())
                # print("%d, %d: %d, %d\n" % (irow,icol,self.answers[i], goodanswers))
                irow+=1
            icol+=3
        return

    def outputMarkReport(self):
        self.totalMarks=self.arith.getTotalMark()
        self.marks=self.arith.getMarks()
        self.labelTotalMark.setText(str(self.totalMarks))

        ncolumn=3*self.arith.nDataColumn
        nTest=self.arith.getnTest()
        nrow=ceil(nTest/self.arith.nDataColumn)

        icol=2
        for j in range(0,self.arith.nDataColumn):
            irow=0
            for i in range(j,nTest,int(ncolumn/3)):
                text=self.tableTestpaper.item(irow,icol-1).text()
                if (text.strip()==str('')):
                    mark='?'
                    color=Qt.gray
                elif self.marks[i]==1:
                    mark='Y' #'√'
                    color=Qt.green
                elif self.marks[i]==0:
                    mark='X'
                    color=Qt.red

                # item=self.tableTestpaper.item(0,0).s
                # self.tableTestpaper.item(irow,icol).setBackgroundColor(color)
                # self.tableTestpaper.item(irow,icol).setBackground(QColor(100,100,150))
                self.tableTestpaper.item(irow,icol).setBackground(color)
                self.tableTestpaper.item(irow,icol).setText(mark)
                # self.tableTestpaper.item(irow,icol).setWidth(80)

                irow+=1
            icol+=3

        if self.arith.timerOn:
            self.labelTimeName.show()
            self.labelTime.show()
            self.labelTime.setText(str(self.timeElapsed)+' sec')
        return

    def openFile(self):
        fname,  _ = (QFileDialog.getOpenFileName(self, \
            "Open File", "./", \
            "CSV File (*.csv);;Text file (*.txt);;All Files (*)"))
        if not fname:
            # QMessageBox.information(self, "Unable to open file",
            #         "There was an error opening \"%s\"" % fname)
            return
        with open(fname, 'rt',encoding='utf8') as stream:
            reader = csv.reader(stream,delimiter=',')
            i=0
            for row in reader:
                if (i==1):
                    self.arith.diffiLevel=int(row[1])
                    self.arith.mode=int(row[3])
                if (i==2):
                    ncol=len(row)
                    self.arith.nDataColumn=int(ncol/3)
                i+=1
            nrowfile=i
            nrow=i-2
            stream.seek(0)
            i=0
            for row in reader:
                if (i==nrowfile-1):
                    ncol=int(len(row)/3)
                    self.arith.nTest=(nrow-1)*self.arith.nDataColumn+ncol
                i+=1

            self.arith.new()

            irow=0
            i=0
            stream.seek(0)
            for row in reader:
                if (irow>=2):
                    if irow<nrowfile-1:
                        ncol1=self.arith.nDataColumn
                    else:
                        ncol1=int(len(row)/3)
                    icol=0
                    for j in range(icol,len(row),3):
                        text=row[j]
                        self.arith.texts[i]=text
                        i+=1
                irow+=1
            self.arith.calcResults()
            self.resetWidgets()
        return
    def saveFile(self):
        fname,  _ = (QFileDialog.getSaveFileName(self, \
            "Save File As", "./", \
            "CSV File (*.csv);;Text file (*.txt);;All Files (*)")) #???
        if not fname:
            # QMessageBox.information(self, "Unable to open file",
            #         "There was an error opening \"%s\"" % fname)
            return
        with open((fname), 'wt',encoding='utf8') as stream:
            writer = csv.writer(stream)
            writer.writerow(['Marks:', str(self.totalMarks), 'Elapsed time(sec): ', str(self.timeElapsed)])
            writer.writerow(['Difficulty: ',self.arith.diffiLevel,'Mode: ', self.arith.mode])
            for row in range(0,self.tableTestpaper.rowCount()):
                rowdata = []
                for column in range(self.tableTestpaper.columnCount()):
                    item = self.tableTestpaper.item(row, column)
                    # item is not None or
                    if item.text() is not str(''):
                        rowdata.append(
                            (item.text()))#.encode('utf8'))
                    else:
                        rowdata.append(str('N/A'))
                writer.writerow(rowdata)
        self.caseIsOpen=False
        return
    @pyqtSlot()
    def on_btnReset_clicked(self):
        """
        Slot documentation goes here.
        """
        self.arith.reset()
        self.updateWindow()
        return

    @pyqtSlot()
    def on_btnSave_clicked(self):
        """
        Slot documentation goes here.
        """
        if not self.arith.empty:
            self.saveFile()
        else:
            QMessageBox.information(self, "Unable to save file",
                    "The test paper is still empty" )
        return

    @pyqtSlot()
    def on_btnMark_clicked(self):
        """
        Slot documentation goes here.
        """
        if self.arith.timerOn:
            # self.timer.stop()
            self.timeElapsed=float(self.qtime.elapsed())/1000.0
        self.getAnswers()
        self.arith.mark(self.answers)
        self.outputMarkReport()
        return

    @pyqtSlot()
    def on_btnStop_clicked(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        self.timer.stop()
        return

    @pyqtSlot()
    def on_btnQuit_clicked(self):
        """
        Slot documentation goes here.
        """
        if(self.caseIsOpen==False):
            QCoreApplication.instance().quit()
        else:
            reply = QMessageBox.question(self, 'Warning',
                "Test not saved. Are you sure to quit?", QMessageBox.Yes |
                QMessageBox.No, QMessageBox.No)
            if reply == QMessageBox.Yes:
                QCoreApplication.instance().quit()
            # else:
            #     event.ignore()
        return

    @pyqtSlot()
    def on_btnOpen_clicked(self):
        """
        Slot documentation goes here.
        """
        self.openFile()
        return

    @pyqtSlot()
    def on_actionOpen_triggered(self):
        """
        Slot documentation goes here.
        """
        self.openFile()
        return

    @pyqtSlot()
    def on_actionSave_triggered(self):
        """
        Slot documentation goes here.
        """
        if not self.arith.empty:
            self.saveFile()
        else:
            QMessageBox.information(self, "Unable to save file",
                    "The test paper is still empty" )
        return

    @pyqtSlot()
    def on_actionPreferences_triggered(self):
        """
        Slot documentation goes here.
        """
        self.preference.showArith()
        if self.preference.exec_()==QDialog.Accepted:
            self.answers=np.zeros(self.arith.getnTest())+self.arith.smallest
            if not self.arith.timerOn:
                self.labelTimeName.hide()
                self.labelTime.hide()
            else:
                self.labelTimeName.show()
        return

    @pyqtSlot()
    def on_actionAbout_triggered(self):
        """
        Slot documentation goes here.
        """
        QMessageBox.information(self, "About Arith",
                    __arith_title__)
        return

    @pyqtSlot()
    def on_actionNew_Test_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        self.on_btnNew_clicked()
        return

    @pyqtSlot()
    def on_actionQuit_triggered(self):
        """
        Slot documentation goes here.
        """
        QCoreApplication.instance().quit()
        return

    @pyqtSlot()
    def on_actionReset_triggered(self):
        """
        Slot documentation goes here.
        """
        self.arith.reset()
        self.updateWindow()
        return

    @pyqtSlot()
    def on_actionMark_triggered(self):
        """
        Slot documentation goes here.
        """
        self.on_btnMark_clicked()
        return

    @pyqtSlot()
    def on_actionRegister_triggered(self):
        if self.regdialog.exec_()==QDialog.Accepted:
            print('reg OK')
        # else:
        return
예제 #33
0
파일: qtdemo.py 프로젝트: Axel-Erfurt/pyqt5
def artisticSleep(sleepTime):
    time = QTime()
    time.restart()
    while time.elapsed() < sleepTime:
        QApplication.processEvents(QEventLoop.AllEvents, 50)
예제 #34
0
class TrackWidget(QWidget):
    def __init__(self, track, scale, parent=None):
        super(TrackWidget, self).__init__(parent)

        self.antialiased = False
        self.frameNo = 0

        self.setBackgroundRole(QPalette.Base)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.point_pen = QPen(QColor(0, 0, 0), 4)
        self.segment_pen = QPen(QColor(0, 0, 0), 2)
        self.base_poly_curve_pen = QPen(QColor(127, 127, 127), 1)
        self.current_point_pen = QPen(QColor(200, 0, 0), 5)
        self.tangent_line_pen = QPen(QColor(200, 0, 0), 1)

        self.time = QTime()
        self.time.start()

    def set_track(self, track):
        self.track = track

    def setAntialiased(self, antialiased):
        self.antialiased = antialiased
        self.update()

    def nextAnimationFrame(self):
        self.frameNo += 1
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing, self.antialiased)

        for i in range(len(self.track.points) - 1):
            painter.setPen(self.base_poly_curve_pen)
            painter.drawLine(
                QLineF(self.track.points[i].point.x * scale,
                       self.track.points[i].point.y * scale,
                       self.track.points[i + 1].point.x * scale,
                       self.track.points[i + 1].point.y * scale))

        for segment in self.track.segments:
            if type(segment) == LineSegment:
                painter.setPen(self.point_pen)
                painter.drawPoint(
                    QPointF(segment.start.x * scale, segment.start.y * scale))
                painter.drawPoint(
                    QPointF(segment.finish.x * scale,
                            segment.finish.y * scale))

                painter.setPen(self.segment_pen)
                painter.drawLine(segment.start.x * scale,
                                 segment.start.y * scale,
                                 segment.finish.x * scale,
                                 segment.finish.y * scale)
            elif type(segment) == ArcSegment:
                painter.setPen(self.point_pen)
                painter.drawPoint(
                    QPointF(segment.start.x * scale, segment.start.y * scale))
                painter.drawPoint(
                    QPointF(segment.finish.x * scale,
                            segment.finish.y * scale))
                painter.setPen(self.segment_pen)
                painter.drawEllipse(
                    QPointF(segment.M.x * scale, segment.M.y * scale),
                    segment.smooth_radius * scale,
                    segment.smooth_radius * scale)

            current_time = self.time.elapsed()
            current_point = Track.get_track_point(track, current_time)
            painter.setPen(self.current_point_pen)
            painter.drawPoint(
                QPointF(current_point.x * scale, current_point.y * scale))

            painter.setPen(self.tangent_line_pen)
            painter.drawLine(
                QLineF(current_point.x * scale, current_point.y * scale,
                       current_point.x * scale + 20 * cos(current_point.angle),
                       current_point.y * scale +
                       20 * sin(current_point.angle)))
예제 #35
0
class Example(QWidget):
    def __init__(self, vehicles_N, vehicles_W, vehicles_E, sendData_1, sendData_3):
        super().__init__()
        self.vehicles_N = vehicles_N
        self.vehicles_W = vehicles_W
        self.vehicles_E = vehicles_E
        self.sendData_1 = sendData_1
        self.sendData_3 = sendData_3
        self.my_result = 0
        self.t_t = 0

        self.initUI()

        self.timer = QTimer(self)
        self.timer.timeout.connect(self.update)
        self.timer.start(1000/60)#一秒間隔で更新

        self.t = QTime()
        self.t.start()
        self.show()

    def initUI(self):
        self.setGeometry(300, 300, 600, 600)
        self.setWindowTitle("Koku's Simulation")

        self.ti = 0
        self.beze_t = []
        self.r = []
        self.up_left_x = []
        self.up_left_y = []
        self.down_left_x = []
        self.down_left_y = []
        self.up_right_x = []
        self.up_right_y = []
        self.down_right_x = []
        self.down_right_y = []

        for i in range(10):
            self.beze_t.append(0)
            self.r.append(0)
            self.up_left_x.append(0)
            self.up_left_y.append(0)
            self.down_left_x.append(0)
            self.down_left_y.append(0)
            self.up_right_x.append(0)
            self.up_right_y.append(0)
            self.down_right_x.append(0)
            self.down_right_y.append(0)

        self.single_0_0 = True
        self.single_0_1 = True

        self.collision_check = []
        self.collision_check_N = []
        self.collision_check_S = []
        self.collision_check_W = []
        self.collision_check_E = []


        self.grid = {}

        for i in range(270, 330, 10):
            for j in range(270, 330, 10):
                self.grid[(i, j)] = True

    def paintEvent(self, e):
        self.t_t += 1
        qp = QPainter(self)

        self.drawLines(qp)
        #self.drawSignals_0(qp)
        self.drawVehicles(qp)

    def drawLines(self, qp):

        # print(self.t.elapsed())

        pen = QPen(Qt.black, 2, Qt.SolidLine)
        pen_dash = QPen(Qt.black, 2, Qt.DotLine)

        # Vertical
        qp.setPen(pen)
        qp.drawLine(270, 0, 270, 600)

        # with grids ##################
        # qp.drawLine(280, 0, 280, 600)
        # qp.drawLine(290, 0, 290, 600)
        # qp.drawLine(300, 0, 300, 600)
        # qp.drawLine(310, 0, 310, 600)
        # qp.drawLine(320, 0, 320, 600)
        # with grids ##################

        qp.drawLine(330, 0, 330, 600)
        qp.drawLine(300, 0, 300, 270)
        qp.drawLine(300, 330, 300, 600)

        qp.setPen(pen_dash)
        qp.drawLine(280, 330, 280, 600)
        qp.drawLine(290, 330, 290, 600)
        qp.drawLine(310, 330, 310, 600)
        qp.drawLine(320, 330, 320, 600)

        qp.drawLine(280, 0, 280, 270)
        qp.drawLine(290, 0, 290, 270)
        qp.drawLine(310, 0, 310, 270)
        qp.drawLine(320, 0, 320, 270)

        # Tropical
        qp.setPen(pen)
        qp.drawLine(0, 270, 600, 270)

        # with grids ##################
        # qp.drawLine(0, 280, 600, 280)
        # qp.drawLine(0, 290, 600, 290)
        # qp.drawLine(0, 300, 600, 300)
        # qp.drawLine(0, 310, 600, 310)
        # qp.drawLine(0, 320, 600, 320)
        # with grids ##################

        qp.drawLine(0, 330, 600, 330)
        qp.drawLine(0, 300, 270, 300)

        qp.drawLine(330, 300, 600, 300)

        qp.setPen(pen_dash)
        qp.drawLine(0, 280, 270, 280)
        qp.drawLine(0, 290, 270, 290)
        qp.drawLine(0, 310, 270, 310)
        qp.drawLine(0, 320, 270, 320)

        qp.drawLine(330, 280, 600, 280)
        qp.drawLine(330, 290, 600, 290)
        qp.drawLine(330, 310, 600, 310)
        qp.drawLine(330, 320, 600, 320)


    def drawSignals_0(self, qp):
        #print(self.t.elapsed())

        if 1000 < self.t.elapsed() < 2000:
            qp.setPen(Qt.black)
            qp.setBrush(Qt.red)

            qp.drawEllipse(272, 262, 6, 6)
            qp.drawEllipse(282, 262, 6, 6)
            qp.drawEllipse(292, 262, 6, 6)

            qp.setBrush(Qt.green)
            qp.drawEllipse(332, 272, 6, 6)
            qp.drawEllipse(332, 282, 6, 6)
            qp.drawEllipse(332, 292, 6, 6)

            qp.setBrush(Qt.red)
            qp.drawEllipse(302, 332, 6, 6)
            qp.drawEllipse(312, 332, 6, 6)
            qp.drawEllipse(322, 332, 6, 6)

            qp.setBrush(Qt.green)
            qp.drawEllipse(262, 302, 6, 6)
            qp.drawEllipse(262, 312, 6, 6)
            qp.drawEllipse(262, 322, 6, 6)

            self.single_0_0 = False
            self.single_0_1 = True

        else:
            qp.setPen(Qt.black)
            qp.setBrush(Qt.green)

            qp.drawEllipse(272, 262, 6, 6)
            qp.drawEllipse(282, 262, 6, 6)
            qp.drawEllipse(292, 262, 6, 6)

            qp.setBrush(Qt.red)
            qp.drawEllipse(332, 272, 6, 6)
            qp.drawEllipse(332, 282, 6, 6)
            qp.drawEllipse(332, 292, 6, 6)

            qp.setBrush(Qt.green)
            qp.drawEllipse(302, 332, 6, 6)
            qp.drawEllipse(312, 332, 6, 6)
            qp.drawEllipse(322, 332, 6, 6)

            qp.setBrush(Qt.red)
            qp.drawEllipse(262, 302, 6, 6)
            qp.drawEllipse(262, 312, 6, 6)
            qp.drawEllipse(262, 322, 6, 6)

            self.single_0_0 = True
            self.single_0_1 = False

    def coordinate_up_left_x(self, po_x, r):
        return po_x - 5 * math.cos(math.radians(r))

    def coordinate_up_left_y(self, po_y):
        return po_y

    def coordinate_up_right_x(self, po_x, r):
        return po_x + 10 * math.cos(math.radians(r))

    def coordinate_up_right_y(self, po_y):
        return po_y

    def coordinate_down_left_x(self, po_x, r):
        return po_x - 5 * math.cos(math.radians(r))

    def coordinate_down_left_y(self, po_y, r):
        return po_y + 5 * math.sin(math.radians(r)) + 10 * math.cos(math.radians(r))

    def coordinate_down_right_x(self, po_x, r):
        return po_x + 10 * math.cos(math.radians(r))

    def coordinate_down_right_y(self, po_y, r):
        return po_y + 10 * math.sin(math.radians(r)) + 5 * math.cos(math.radians(r))

    def propose_pattern_1(self, veh_id, current, origin, destination, speed, current_time, pattern):
        server_address = ('localhost', 6789)
        max_size = 4096

        print('Starting the client at', datetime.now())

        client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

        self.sendData_1["pattern"] = 3
        #self.sendData_1["position"] = list(current)
        current_position = list(current)
        print('++++++++++++++++++++++++++++++++++++++')
        print(self.sendData_1)
        self.sendData_1["origin"] = list(origin)
        self.sendData_1["destination"] = list(destination)
        self.sendData_1["speed"] = speed
        #self.sendData_1["current_time"] = current_time

        # sendData_1: veh info and current Total_time
        #mes = bytes(json.dumps(dict({"time_step": self.t_t}, **self.sendData_1["vehicle"][veh_id])), encoding='utf-8')
        dictMerge = dict({"time_step": self.t_t}, **self.sendData_1["vehicle"][veh_id])
        dictMerge = dict({"position": current_position}, **dictMerge)
        mes = bytes(json.dumps(dictMerge), encoding='utf-8')

        #print(mes)

        client.sendto(mes, server_address)
        data, server = client.recvfrom(max_size)

        data = data.decode('utf-8')
        recData = json.loads(data)
        print('At', datetime.now(), server, 'said', recData)
        client.close()
        #print('!!!!!!!', recData['result'])
        self.my_result = recData['result']

        return self.my_result

    def propose_pattern_3(self, veh_id, current, origin, destination, speed, current_time):
        server_address = ('localhost', 6789)
        max_size = 4096

        print('Starting the client at', datetime.now())

        client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

        self.sendData_3["pattern"] = 3
        self.sendData_3["position"] = list(current)
        self.sendData_3["origin"] = list(origin)
        self.sendData_3["destination"] = list(destination)
        self.sendData_3["speed"] = speed
        self.sendData_3["current_time"] = current_time

        # sendData_3: veh info and current Total_time
        mes = bytes(json.dumps(dict({"time_step": self.t_t}, **self.sendData_3["vehicle"][veh_id])), encoding='utf-8')

        print(mes)

        client.sendto(mes, server_address)
        data, server = client.recvfrom(max_size)

        data = data.decode('utf-8')
        recData = json.loads(data)
        print('At', datetime.now(), server, 'said', recData)
        client.close()
        #print('!!!!!!!', recData['result'])
        self.my_result = recData['result']

        return self.my_result

    def drawVehicles(self, qp):

        qp.setPen(Qt.black)
        qp.setBrush(Qt.green)
        #qp.drawRect(310, 310, 5, 10)

        #self.propose(1, [262, 273], [270, 273], [330, 330], 2)

        # for i in range(10):
        #     if self.propose(i):
        #         print('?????????????')
        #         qp.drawRect(322, 330, 5, 10)
        #     else:
        #         print('!!!!!!!!!!!!!')
        #         qp.drawRect(400, 400, 5, 10)

        # Vehicles from North
        # for i, veh in enumerate(vehicles_N):
        #     if (veh.getPosition().x + veh.getSpeed().x, veh.getPosition().y + veh.getSpeed().y) in self.collision_check_N:
        #         qp.drawRect(veh.getPosition().x, veh.getPosition().y, veh.getSize().x, veh.getSize().y)
        #         for i in range(11):
        #             self.collision_check_N.append((veh.getPosition().x, veh.getPosition().y - i))
        #     else:
        #         if veh.getPosition().y + veh.getSpeed().y > 260 and veh.getPosition().y <= 260:
        #             if self.single_0_1:
        #                 qp.drawRect(veh.getPosition().x, veh.getPosition().y, veh.getSize().x, veh.getSize().y)
        #                 for i in range(11):
        #                     self.collision_check_N.append((veh.getPosition().x, veh.getPosition().y - i))
        #             else:
        #                 if veh.getPosition().y <= 270:
        #                     if self.grid[((veh.getPosition().x + veh.getSpeed().x) // 10 * 10,
        #                                   (veh.getPosition().y + veh.getSpeed().y + veh.getSize().y) // 10 * 10)] and \
        #                             self.grid[((veh.getPosition().x + veh.getSpeed().x + veh.getSize().x) // 10 * 10,
        #                                        (veh.getPosition().y + veh.getSpeed().y + veh.getSize().y) // 10 * 10)]:
        #
        #                         veh.getPosition().y += veh.getSpeed().y
        #                         qp.drawRect(veh.getPosition().x, veh.getPosition().y, 5, 10)
        #                         for i in range(11):
        #                             self.collision_check_N.append((veh.getPosition().x, veh.getPosition().y - i))
        #                         self.grid[(veh.getPosition().x // 10 * 10, (veh.getPosition().y + veh.getSize().y) // 10 * 10)] = False
        #                         self.grid[((veh.getPosition().x + veh.getSize().x) // 10 * 10, (veh.getPosition().y + veh.getSize().y) // 10 * 10)] = False
        #                 else:
        #                     try:
        #                         if self.grid[((veh.getPosition().x + veh.getSpeed().x) // 10 * 10,
        #                                       (veh.getPosition().y + veh.getSpeed().y) // 10 * 10)] and \
        #                                 self.grid[((veh.getPosition().x + veh.getSpeed().x + veh.getSize().x) // 10 * 10,
        #                                            (veh.getPosition().y + veh.getSpeed().y) // 10 * 10)] and \
        #                                 self.grid[((veh.getPosition().x + veh.getSpeed().x) // 10 * 10,
        #                                            (veh.getPosition().y + veh.getSpeed().y + veh.getSize().y) // 10 * 10)] and \
        #                                 self.grid[((veh.getPosition().x + veh.getSpeed().x + veh.getSize().x) // 10 * 10,
        #                                            (veh.getPosition().y + veh.getSpeed().y + veh.getSize().y) // 10 * 10)]:
        #
        #                             self.vehicles_N[i].getPosition().y += veh.getSpeed().y
        #
        #                             self.grid[((veh.getPosition().x + veh.getSpeed().x) // 10 * 10,
        #                                        (veh.getPosition().y + veh.getSpeed().y) // 10 * 10)] = False
        #                             self.grid[((veh.getPosition().x + veh.getSpeed().x + veh.getSize().x) // 10 * 10,
        #                                        (veh.getPosition().y + veh.getSpeed().y) // 10 * 10)] = False
        #                             self.grid[((veh.getPosition().x + veh.getSpeed().x) // 10 * 10,
        #                                        (veh.getPosition().y + veh.getSpeed().y + veh.getSize().y) // 10 * 10)] = False
        #                             self.grid[((veh.getPosition().x + veh.getSpeed().x + veh.getSize().x) // 10 * 10,
        #                                        (veh.getPosition().y + veh.getSpeed().y + veh.getSize().y) // 10 * 10)] = False
        #
        #                             if self.vehicles_N[i].getPosition().y > 600:
        #                                 self.vehicles_N[i].getPosition().y = 0
        #                                 qp.drawRect(veh.getPosition().x, veh.getPosition().y, 5, 10)
        #                                 for i in range(11):
        #                                     self.collision_check_N.append((veh.getPosition().x, veh.getPosition().y - i))
        #
        #                     except KeyError:
        #                         self.vehicles_N[i].getPosition().y += veh.getSpeed().y
        #
        #                         if self.vehicles_N[i].getPosition().y > 600:
        #                             self.vehicles_N[i].getPosition().y = 0
        #
        #                         qp.drawRect(self.vehicles_N[i].getPosition().x, self.vehicles_N[i].getPosition().y, 5, 10)
        #
        #         else:
        #             # print(self.single_0_1)
        #             veh.getPosition().y += veh.getSpeed().y
        #             if veh.getPosition().y > 600:
        #                 veh.getPosition().y = 0
        #                 # print(self.t.elapsed())
        #             qp.drawRect(veh.getPosition().x, veh.getPosition().y, 5, 10)
        #             for i in range(11):
        #                 self.collision_check_N.append((veh.getPosition().x, veh.getPosition().y - i))

            #print(self.collision_check)



        # Vehicles from West
        for i, veh in enumerate(vehicles_W):
            # Check if there are vehicles ahead. If true, stop
            if (veh.getPosition().x + veh.getSpeed().x, veh.getPosition().y + veh.getSpeed().y) in self.collision_check_W:
                qp.drawRect(veh.getPosition().x, veh.getPosition().y, veh.getSize().x, veh.getSize().y)
                # Make the room not available for other vehicles
                for j in range(11):
                    self.collision_check_W.append((veh.getPosition().x - j, veh.getPosition().y))
            # Move forward
            else:
                # Just before the intersection
                if veh.getPosition().x + 10 + 2 > 270 and veh.getPosition().x <= 270 - 10:
                      #+++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    # Check traffic signal. True, then stop before entering.
                    #print(veh.getPosition())
                    if not self.propose_pattern_1(i, (veh.getPosition().x, veh.getPosition().y), (270, 273), (330, 330), veh.getSpeed().x, self.t_t, 1):
                    # if True:
                        qp.drawRect(veh.getPosition().x, veh.getPosition().y, 10, 5)
                        for j in range(11):
                            self.collision_check_W.append((veh.getPosition().x - j, veh.getPosition().y))
                    # Enter intersection
                    else:
                        veh.getPosition().x += 2
                        qp.drawRect(veh.getPosition().x, veh.getPosition().y, 10, 5)
                        for j in range(11):
                            self.collision_check_W.append((veh.getPosition().x - j, veh.getPosition().y))

                        # # Light up the grids in the intersection
                        # # Up left
                        # if (veh.getPosition().x // 10 * 10, veh.getPosition().y // 10 * 10) in self.grid:
                        #     self.grid[(veh.getPosition().x // 10 * 10, veh.getPosition().y // 10 * 10)] = False
                        #     #print('success, x:', veh.getPosition().x)
                        #
                        # # Up right
                        # if ((veh.getPosition().x + 10) // 10 * 10, veh.getPosition().y // 10 * 10) in self.grid:
                        #     self.grid[((veh.getPosition().x + 10) // 10 * 10, veh.getPosition().y // 10 * 10)] = False
                        #     #print('success, x:', veh.getPosition().x)
                        #
                        # # Down left
                        # if (veh.getPosition().x // 10 * 10, (veh.getPosition().y) // 10 * 10) in self.grid:
                        #     self.grid[(veh.getPosition().x // 10 * 10, (veh.getPosition().y + 5) // 10 * 10)] = False
                        #     #print('success, x:', veh.getPosition().x)
                        #
                        # # Down right
                        # if ((veh.getPosition().x + 10) // 10 * 10, (veh.getPosition().y) // 10 * 10) in self.grid:
                        #     self.grid[((veh.getPosition().x + 10) // 10 * 10, (veh.getPosition().y + 5) // 10 * 10)] = False
                        #     #print('success, x:', veh.getPosition().x)

                # Already in the intersection
                else:
                    if 270 < veh.getPosition().x < 328 and veh.getPosition().y < 330:
                        qp.save()
                        qp.translate(veh.getPosition().x, veh.getPosition().y)

                        # Calculate rotation angle
                        if (((veh.getPosition().x - 270 + 3) / 60) * 90 > 15):
                            self.r[i] = ((veh.getPosition().x - 270 + 3) / 60) * 90
                            qp.rotate(self.r[i])
                        else:
                            self.r[i] = 0
                            qp.rotate(self.r[i])
                        qp.translate(-veh.getPosition().x, -veh.getPosition().y)

                        # Calculate trajectory by using Bezier Curve
                        x = pow(1 - (self.beze_t[i] / 60), 2) * 273 + 2 * (self.beze_t[i] / 60) * (
                        1 - self.beze_t[i] / 60) * 332 + pow(
                            self.beze_t[i] / 60, 2) * 332
                        y = pow(1 - (self.beze_t[i] / 60), 2) * 273 + 2 * (self.beze_t[i] / 60) * (
                        1 - self.beze_t[i] / 60) * 273 + pow(
                            self.beze_t[i] / 60, 2) * 332
                        veh.setPosition(Position(x, y))

                        self.beze_t[i] += 2
                        qp.drawRect(veh.getPosition().x, veh.getPosition().y, 10, 5)
                        for j in range(11):
                            self.collision_check_W.append((veh.getPosition().x - j, veh.getPosition().y))
                        qp.restore()

                        # Calculate the big Square's coordinate
                        self.up_left_x[i] = self.coordinate_up_left_x(veh.getPosition().x, self.r[i])
                        self.up_left_y[i] = self.coordinate_up_left_y(veh.getPosition().y)
                        self.down_left_x[i] = self.coordinate_down_left_x(veh.getPosition().x, self.r[i])
                        self.down_left_y[i] = self.coordinate_down_left_y(veh.getPosition().y, self.r[i])
                        self.up_right_x[i] = self.coordinate_up_right_x(veh.getPosition().x, self.r[i])
                        self.up_right_y[i] = self.coordinate_up_right_y(veh.getPosition().y)
                        self.down_right_x[i] = self.coordinate_down_right_x(veh.getPosition().x, self.r[i])
                        self.down_right_y[i] = self.coordinate_down_right_y(veh.getPosition().y, self.r[i])

                        # # Up left
                        # if (self.up_left_x[i] // 10 * 10, self.up_left_y[i] // 10 * 10) in self.grid:
                        #     self.grid[(self.up_left_x[i] // 10 * 10, self.up_left_y[i] // 10 * 10)] = False
                        #     # print('success')
                        #
                        # # Up right
                        # if ((self.up_right_x[i]) // 10 * 10, self.up_right_y[i] // 10 * 10) in self.grid:
                        #     self.grid[((self.up_right_x[i]) // 10 * 10, self.up_right_y[i] // 10 * 10)] = False
                        #     # print('success')
                        #
                        # # Down left
                        # if (self.down_left_x[i] // 10 * 10, (self.down_left_y[i]) // 10 * 10) in self.grid:
                        #     self.grid[(self.down_left_x[i] // 10 * 10, (self.down_left_y[i]) // 10 * 10)] = False
                        #     # print('success')
                        #
                        # # Down right
                        # if ((self.down_right_x[i]) // 10 * 10, (self.down_right_y[i]) // 10 * 10) in self.grid:
                        #     self.grid[((self.down_right_x[i]) // 10 * 10, (self.down_right_y[i]) // 10 * 10)] = False
                        #     # print('success')

                    # Already left intersection
                    elif 328 <= veh.getPosition().x and veh.getPosition().y < 600:
                        qp.save()
                        qp.translate(veh.getPosition().x, veh.getPosition().y)
                        qp.rotate(90)
                        qp.translate(-veh.getPosition().x, -veh.getPosition().y)
                        veh.getPosition().y += 2
                        qp.drawRect(veh.getPosition().x, veh.getPosition().y, 10, 5)
                        for j in range(11):
                            self.collision_check_W.append((veh.getPosition().x, veh.getPosition().y - j))
                        qp.restore()

                    # Already left screen
                    elif veh.getPosition().y >= 600:
                        veh.getPosition().x = 0
                        veh.getPosition().y = 273
                        self.beze_t[i] = 0
                        qp.drawRect(veh.getPosition().x, veh.getPosition().y, 10, 5)
                        for j in range(11):
                            self.collision_check_W.append((veh.getPosition().x, veh.getPosition().y - j))

                    # Move horizontal direction(across X_axis)
                    else:
                        veh.getPosition().x += 2
                        qp.drawRect(veh.getPosition().x, veh.getPosition().y, 10, 5)
                        for j in range(11):
                            self.collision_check_W.append((veh.getPosition().x - j, veh.getPosition().y))

        # Vehicle2
        # if self.single_0_0:
        #     qp.drawRect(self.vehicles_E[0].getPosition().x, self.vehicles_E[0].getPosition().y, 10, 5)
        # else:


        if 330 <= (vehicles_E[0].getPosition().x) and (vehicles_E[0].getPosition().x - vehicles_E[0].getSpeed().x) < 330:
            #if self.propose_pattern_3(0, (veh.getPosition().x, veh.getPosition().y), (330, 272), (260, 272), veh.getSpeed().x, self.t_t):
            if True:
                self.vehicles_E[0].getPosition().x -= self.vehicles_E[0].getSpeed().x

                if self.vehicles_E[0].getPosition().x < 0:
                    self.vehicles_E[0].getPosition().x = 600

                qp.drawPoint(self.vehicles_E[0].getPosition().x + 1, self.vehicles_E[0].getPosition().y - 1)
                qp.drawRect(self.vehicles_E[0].getPosition().x, self.vehicles_E[0].getPosition().y, 10, 5)
            else:
                qp.drawRect(self.vehicles_E[0].getPosition().x, self.vehicles_E[0].getPosition().y, 10, 5)
        else:
            self.vehicles_E[0].getPosition().x -= self.vehicles_E[0].getSpeed().x

            if self.vehicles_E[0].getPosition().x < 0:
                self.vehicles_E[0].getPosition().x = 600

            qp.drawRect(self.vehicles_E[0].getPosition().x, self.vehicles_E[0].getPosition().y, 10, 5)

        ###############################################################################################
        # Just for seminar0920
        # if 492 < self.t_t and self.t_t < 523:
        #     qp.drawRect(self.vehicles_E[0].getPosition().x, self.vehicles_E[0].getPosition().y, 10, 5)
        # else:
        #     self.vehicles_E[0].getPosition().x -= self.vehicles_E[0].getSpeed().x
        #     qp.drawRect(self.vehicles_E[0].getPosition().x, self.vehicles_E[0].getPosition().y, 10, 5)
        #
        #     if self.vehicles_E[0].getPosition().x < 0:
        #         self.vehicles_E[0].getPosition().x = 600
        ###############################################################################################


        # try:
        #     if self.grid[((self.vehicles_E[0].getPosition().x - 5) // 10 * 10, self.vehicles_E[0].getPosition().y // 10 * 10)] and \
        #             self.grid[((self.vehicles_E[0].getPosition().x + 10 - 5) // 10 * 10, self.vehicles_E[0].getPosition().y // 10 * 10)] and \
        #             self.grid[((self.vehicles_E[0].getPosition().x - 5) // 10 * 10, (self.vehicles_E[0].getPosition().y + 5) // 10 * 10)] and \
        #             self.grid[((self.vehicles_E[0].getPosition().x + 10 - 5) // 10 * 10, (self.vehicles_E[0].getPosition().y + 5) // 10 * 10)]:
        #
        #         self.vehicles_E[0].getPosition().x -= 3
        #
        #         if self.vehicles_E[0].getPosition().x < 0:
        #             self.vehicles_E[0].getPosition().x = 600
        #
        #         qp.drawPoint(self.vehicles_E[0].getPosition().x + 1, self.vehicles_E[0].getPosition().y - 1)
        #         qp.drawRect(self.vehicles_E[0].getPosition().x, self.vehicles_E[0].getPosition().y, 10, 5)
        #
        #     else:
        #         qp.drawPoint(self.vehicles_E[0].getPosition().x + 1, self.vehicles_E[0].getPosition().y - 1)
        #         qp.drawRect(self.vehicles_E[0].getPosition().x, self.vehicles_E[0].getPosition().y, 10, 5)
        #
        # except KeyError:
        #     self.vehicles_E[0].getPosition().x -= 3
        #
        #     if self.vehicles_E[0].getPosition().x < 0:
        #         self.vehicles_E[0].getPosition().x = 600
        #
        #     qp.drawPoint(self.vehicles_E[0].getPosition().x + 1, self.vehicles_E[0].getPosition().y - 1)
        #     qp.drawRect(self.vehicles_E[0].getPosition().x, self.vehicles_E[0].getPosition().y, 10, 5)

        self.collision_check = []
        self.collision_check_N = []
        self.collision_check_S = []
        self.collision_check_W = []
        self.collision_check_E = []
        #
        #
        # for i in range(270, 330, 10):
        #     for j in range(270, 330, 10):
        #         self.grid[(i, j)] = True
        #
        #
        self.ti += 10
        if self.ti > 700:
            self.ti = 0
            # print(self.t.elapsed())
            self.t.restart()
예제 #36
0
class Connection(QTcpSocket):
    """
    Class representing a peer connection.
    
    @signal readyForUse() emitted when the connection is ready for use
    @signal newMessage(user, message) emitted after a new message has
        arrived (string, string)
    @signal getParticipants() emitted after a get participants message has
        arrived
    @signal participants(participants) emitted after the list of participants
        has arrived (list of strings of "host:port")
    """
    WaitingForGreeting = 0
    ReadingGreeting = 1
    ReadyForUse = 2
    
    PlainText = 0
    Ping = 1
    Pong = 2
    Greeting = 3
    GetParticipants = 4
    Participants = 5
    Editor = 6
    Undefined = 99
    
    ProtocolMessage = "MESSAGE"
    ProtocolPing = "PING"
    ProtocolPong = "PONG"
    ProtocolGreeting = "GREETING"
    ProtocolGetParticipants = "GET_PARTICIPANTS"
    ProtocolParticipants = "PARTICIPANTS"
    ProtocolEditor = "EDITOR"
    
    readyForUse = pyqtSignal()
    newMessage = pyqtSignal(str, str)
    getParticipants = pyqtSignal()
    participants = pyqtSignal(list)
    editorCommand = pyqtSignal(str, str, str)
    rejected = pyqtSignal(str)
    
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent referenec to the parent object (QObject)
        """
        super(Connection, self).__init__(parent)
        
        self.__greetingMessage = self.tr("undefined")
        self.__username = self.tr("unknown")
        self.__serverPort = 0
        self.__state = Connection.WaitingForGreeting
        self.__currentDataType = Connection.Undefined
        self.__numBytesForCurrentDataType = -1
        self.__transferTimerId = 0
        self.__isGreetingMessageSent = False
        self.__pingTimer = QTimer(self)
        self.__pingTimer.setInterval(PingInterval)
        self.__pongTime = QTime()
        self.__buffer = QByteArray()
        self.__client = None
        
        self.readyRead.connect(self.__processReadyRead)
        self.disconnected.connect(self.__disconnected)
        self.__pingTimer.timeout.connect(self.__sendPing)
        self.connected.connect(self.__sendGreetingMessage)
    
    def name(self):
        """
        Public method to get the connection name.
        
        @return connection name (string)
        """
        return self.__username
    
    def serverPort(self):
        """
        Public method to get the server port.
        
        @return server port (integer)
        """
        return self.__serverPort
    
    def setClient(self, client):
        """
        Public method to set the reference to the cooperation client.
        
        @param client reference to the cooperation client (CooperationClient)
        """
        self.__client = client
    
    def setGreetingMessage(self, message, serverPort):
        """
        Public method to set the greeting message.
        
        @param message greeting message (string)
        @param serverPort port number to include in the message (integer)
        """
        self.__greetingMessage = "{0}:{1}".format(message, serverPort)
    
    def sendMessage(self, message):
        """
        Public method to send a message.
        
        @param message message to be sent (string)
        @return flag indicating a successful send (boolean)
        """
        if message == "":
            return False
        
        msg = QByteArray(message.encode("utf-8"))
        data = QByteArray("{0}{1}{2}{1}".format(
            Connection.ProtocolMessage, SeparatorToken, msg.size())
            .encode("utf-8")) + msg
        return self.write(data) == data.size()
    
    def timerEvent(self, evt):
        """
        Protected method to handle timer events.
        
        @param evt reference to the timer event (QTimerEvent)
        """
        if evt.timerId() == self.__transferTimerId:
            self.abort()
            self.killTimer(self.__transferTimerId)
            self.__transferTimerId = 0
    
    def __processReadyRead(self):
        """
        Private slot to handle the readyRead signal.
        """
        if self.__state == Connection.WaitingForGreeting:
            if not self.__readProtocolHeader():
                return
            if self.__currentDataType != Connection.Greeting:
                self.abort()
                return
            self.__state = Connection.ReadingGreeting
        
        if self.__state == Connection.ReadingGreeting:
            if not self.__hasEnoughData():
                return
            
            self.__buffer = QByteArray(
                self.read(self.__numBytesForCurrentDataType))
            if self.__buffer.size() != self.__numBytesForCurrentDataType:
                self.abort()
                return
            
            try:
                user, serverPort = \
                    str(self.__buffer, encoding="utf-8").split(":")
            except ValueError:
                self.abort()
                return
            self.__serverPort = int(serverPort)
            
            hostInfo = QHostInfo.fromName(self.peerAddress().toString())
            self.__username = "******".format(
                user,
                hostInfo.hostName(),
                self.peerPort()
            )
            self.__currentDataType = Connection.Undefined
            self.__numBytesForCurrentDataType = 0
            self.__buffer.clear()
            
            if not self.isValid():
                self.abort()
                return
            
            bannedName = "{0}@{1}".format(
                user,
                hostInfo.hostName(),
            )
            Preferences.syncPreferences()
            if bannedName in Preferences.getCooperation("BannedUsers"):
                self.rejected.emit(self.tr(
                    "* Connection attempted by banned user '{0}'.")
                    .format(bannedName))
                self.abort()
                return
            
            if self.__serverPort != self.peerPort() and \
               not Preferences.getCooperation("AutoAcceptConnections"):
                # don't ask for reverse connections or
                # if we shall accept automatically
                res = E5MessageBox.yesNo(
                    None,
                    self.tr("New Connection"),
                    self.tr("""<p>Accept connection from """
                            """<strong>{0}@{1}</strong>?</p>""").format(
                        user, hostInfo.hostName()),
                    yesDefault=True)
                if not res:
                    self.abort()
                    return

            if self.__client is not None:
                chatWidget = self.__client.chatWidget()
                if chatWidget is not None and not chatWidget.isVisible():
                    e5App().getObject(
                        "UserInterface").activateCooperationViewer()
            
            if not self.__isGreetingMessageSent:
                self.__sendGreetingMessage()
            
            self.__pingTimer.start()
            self.__pongTime.start()
            self.__state = Connection.ReadyForUse
            self.readyForUse.emit()
        
        while self.bytesAvailable():
            if self.__currentDataType == Connection.Undefined:
                if not self.__readProtocolHeader():
                    return
            
            if not self.__hasEnoughData():
                return
            
            self.__processData()
    
    def __sendPing(self):
        """
        Private slot to send a ping message.
        """
        if self.__pongTime.elapsed() > PongTimeout:
            self.abort()
            return
        
        self.write("{0}{1}1{1}p".format(
            Connection.ProtocolPing, SeparatorToken))
    
    def __sendGreetingMessage(self):
        """
        Private slot to send a greeting message.
        """
        greeting = QByteArray(self.__greetingMessage.encode("utf-8"))
        data = QByteArray("{0}{1}{2}{1}".format(
            Connection.ProtocolGreeting, SeparatorToken, greeting.size())
            .encode("utf-8")) + greeting
        if self.write(data) == data.size():
            self.__isGreetingMessageSent = True
    
    def __readDataIntoBuffer(self, maxSize=MaxBufferSize):
        """
        Private method to read some data into the buffer.
        
        @param maxSize maximum size of data to read (integer)
        @return size of data read (integer)
        """
        if maxSize > MaxBufferSize:
            return 0
        
        numBytesBeforeRead = self.__buffer.size()
        if numBytesBeforeRead == MaxBufferSize:
            self.abort()
            return 0
        
        while self.bytesAvailable() and self.__buffer.size() < maxSize:
            self.__buffer.append(self.read(1))
            if self.__buffer.endsWith(SeparatorToken):
                break
        
        return self.__buffer.size() - numBytesBeforeRead
    
    def __dataLengthForCurrentDataType(self):
        """
        Private method to get the data length for the current data type.
        
        @return data length (integer)
        """
        if self.bytesAvailable() <= 0 or \
           self.__readDataIntoBuffer() <= 0 or \
           not self.__buffer.endsWith(SeparatorToken):
            return 0
        
        self.__buffer.chop(len(SeparatorToken))
        number = self.__buffer.toInt()[0]
        self.__buffer.clear()
        return number
    
    def __readProtocolHeader(self):
        """
        Private method to read the protocol header.
        
        @return flag indicating a successful read (boolean)
        """
        if self.__transferTimerId:
            self.killTimer(self.__transferTimerId)
            self.__transferTimerId = 0
        
        if self.__readDataIntoBuffer() <= 0:
            self.__transferTimerId = self.startTimer(TransferTimeout)
            return False
        
        self.__buffer.chop(len(SeparatorToken))
        if self.__buffer == Connection.ProtocolPing:
            self.__currentDataType = Connection.Ping
        elif self.__buffer == Connection.ProtocolPong:
            self.__currentDataType = Connection.Pong
        elif self.__buffer == Connection.ProtocolMessage:
            self.__currentDataType = Connection.PlainText
        elif self.__buffer == Connection.ProtocolGreeting:
            self.__currentDataType = Connection.Greeting
        elif self.__buffer == Connection.ProtocolGetParticipants:
            self.__currentDataType = Connection.GetParticipants
        elif self.__buffer == Connection.ProtocolParticipants:
            self.__currentDataType = Connection.Participants
        elif self.__buffer == Connection.ProtocolEditor:
            self.__currentDataType = Connection.Editor
        else:
            self.__currentDataType = Connection.Undefined
            self.abort()
            return False
        
        self.__buffer.clear()
        self.__numBytesForCurrentDataType = \
            self.__dataLengthForCurrentDataType()
        return True
    
    def __hasEnoughData(self):
        """
        Private method to check, if enough data is available.
        
        @return flag indicating availability of enough data (boolean)
        """
        if self.__transferTimerId:
            self.killTimer(self.__transferTimerId)
            self.__transferTimerId = 0
        
        if self.__numBytesForCurrentDataType <= 0:
            self.__numBytesForCurrentDataType = \
                self.__dataLengthForCurrentDataType()
        
        if self.bytesAvailable() < self.__numBytesForCurrentDataType or \
           self.__numBytesForCurrentDataType <= 0:
            self.__transferTimerId = self.startTimer(TransferTimeout)
            return False
        
        return True
    
    def __processData(self):
        """
        Private method to process the received data.
        """
        self.__buffer = QByteArray(
            self.read(self.__numBytesForCurrentDataType))
        if self.__buffer.size() != self.__numBytesForCurrentDataType:
            self.abort()
            return
        
        if self.__currentDataType == Connection.PlainText:
            self.newMessage.emit(
                self.__username, str(self.__buffer, encoding="utf-8"))
        elif self.__currentDataType == Connection.Ping:
            self.write("{0}{1}1{1}p".format(
                Connection.ProtocolPong, SeparatorToken))
        elif self.__currentDataType == Connection.Pong:
            self.__pongTime.restart()
        elif self.__currentDataType == Connection.GetParticipants:
            self.getParticipants.emit()
        elif self.__currentDataType == Connection.Participants:
            msg = str(self.__buffer, encoding="utf-8")
            if msg == "<empty>":
                participantsList = []
            else:
                participantsList = msg.split(SeparatorToken)
            self.participants.emit(participantsList[:])
        elif self.__currentDataType == Connection.Editor:
            hash, fn, msg = \
                str(self.__buffer, encoding="utf-8").split(SeparatorToken)
            self.editorCommand.emit(hash, fn, msg)
        
        self.__currentDataType = Connection.Undefined
        self.__numBytesForCurrentDataType = 0
        self.__buffer.clear()
    
    def sendGetParticipants(self):
        """
        Public method to request a list of participants.
        """
        self.write(
            "{0}{1}1{1}l".format(
                Connection.ProtocolGetParticipants, SeparatorToken)
        )
    
    def sendParticipants(self, participants):
        """
        Public method to send the list of participants.
        
        @param participants list of participants (list of strings of
            "host:port")
        """
        if participants:
            message = SeparatorToken.join(participants)
        else:
            message = "<empty>"
        msg = QByteArray(message.encode("utf-8"))
        data = QByteArray("{0}{1}{2}{1}".format(
            Connection.ProtocolParticipants, SeparatorToken, msg.size())
            .encode("utf-8")) + msg
        self.write(data)
    
    def sendEditorCommand(self, projectHash, filename, message):
        """
        Public method to send an editor command.
        
        @param projectHash hash of the project (string)
        @param filename project relative universal file name of
            the sending editor (string)
        @param message editor command to be sent (string)
        """
        msg = QByteArray("{0}{1}{2}{1}{3}".format(
            projectHash, SeparatorToken, filename, message).encode("utf-8"))
        data = QByteArray("{0}{1}{2}{1}".format(
            Connection.ProtocolEditor, SeparatorToken, msg.size())
            .encode("utf-8")) + msg
        self.write(data)
    
    def __disconnected(self):
        """
        Private slot to handle the connection being dropped.
        """
        self.__pingTimer.stop()
        if self.__state == Connection.WaitingForGreeting:
            self.rejected.emit(self.tr(
                "* Connection to {0}:{1} refused.").format(
                self.peerName(), self.peerPort()))