Beispiel #1
0
Datei: main.py Projekt: 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()
class MyApplication(QtGui.QApplication):
    def __init__(self, *args, **kwargs):
        super(MyApplication, self).__init__(*args, **kwargs)
        self.t = QTime()
        self.t.start()
        maxlen = 200
        self.data_x = deque(maxlen=maxlen)
        self.data_y = deque(maxlen=maxlen)
        self.win = pg.GraphicsWindow(title="Basic plotting examples")
        self.win.resize(1000, 600)
        tai = TimeAxisItem(orientation='bottom')
        self.plot = self.win.addPlot(
            title='Timed data',
            axisItems={'bottom': TimeAxisItem(orientation='bottom')})
        # self.plot.setYRange(0, 150)
        self.curve = self.plot.plot()
        self.tmr = QTimer()
        self.tmr.timeout.connect(self.update)
        self.tmr.start(100)
        self.y = 100

    def update(self):
        # self.data.append({'x': self.t.elapsed(), 'y': np.random.randint(0, 100)})
        x = now_timestamp()
        self.y = self.y + np.random.uniform(-1, 1)
        self.data_x.append(x)
        self.data_y.append(self.y)
        self.curve.setData(x=list(self.data_x), y=list(self.data_y))
Beispiel #3
0
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()
Beispiel #4
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)
Beispiel #5
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
Beispiel #6
0
    def __evaluate(self, query):
        """

        :type query: str
        :return: bool
        """
        t = QTime()
        t.start()

        # QgsMessageLog.logMessage("(VFK) SQL: {}\n".format(query))
        self.setQuery(query, QSqlDatabase.database(self.__mConnectionName))

        while self.canFetchMore():
            self.fetchMore()

        # if t.elapsed() > 500:
        #     QgsMessageLog.logMessage("(VFK) Time elapsed: {} ms\n".format(t.elapsed()))

        if self.lastError().isValid():
            iface.messageBar().pushWarning(
                u'ERROR', u'SQL ({}): {}'.format(query,
                                                 self.lastError().text()))
            return False

        return True
    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)
Beispiel #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()
Beispiel #9
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()
Beispiel #10
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())
Beispiel #11
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
Beispiel #12
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
Beispiel #13
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())
Beispiel #14
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())
Beispiel #15
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)
Beispiel #16
0
    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
Beispiel #17
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()
Beispiel #18
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())
Beispiel #19
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())
Beispiel #20
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)
Beispiel #21
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
Beispiel #22
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("请选择要传送的文件")
Beispiel #23
0
class Contract_Preval_Step3_Main(QThread):

	"""
	Runs in thread.
	"""

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

	def __init__(self, keyword, temp_file, tgt_folder, l_details, ct_model, com_model):
		super(Contract_Preval_Step3_Main, self).__init__()

		self._keyword = keyword
		self._temp_file = temp_file
		self._tgt_folder = tgt_folder
		self._l_details = l_details
		self._ct_model = ct_model
		self._common_mod =com_model
		
		self.timer = QTime()
		self.elapsed_time = None
		self._progress_count = 0

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

	def run(self):

		''' 
		Read source file to DataFrame 
		Populate Contract Type Template
		'''

		# Start timer
		
		self.timer.start()


		self._progress_count += 1
		self.countProgress.emit(self._progress_count)
		self.txtProgress.emit('Initializing Contract PreVal Step 3 Template.')
		time.sleep(3)

		self.temp_workbook = self._ct_model.load_workbook(self._temp_file)


		for worksheet,src_file in self._l_details:
			
			if not self._abort_flg :

				success = False
				while not success:
					try:
						
						temp_sheet = self.temp_workbook.sheets[worksheet]

						if self._cancel_flg: self.cancel_program(); break;break;
						self.txtProgress.emit('Started : Loading source file for {} to dataframe.'.format(worksheet))
						time.sleep(3)
						self._progress_count += 1
						self.countProgress.emit(self._progress_count)

						temp_df = self._ct_model.readSourceFiletoDF(src_file, self._ct_model._cv3_config['Delimeter'])
						success = True

						self.txtProgress.emit('Finished : Loading source file for {} to dataframe.'.format(worksheet))
						time.sleep(3)
						self._progress_count += 1
						self.countProgress.emit(self._progress_count)

						if self._cancel_flg: self.cancel_program(); break;break;
						self.txtProgress.emit('Started : Writing dataframe to {}.'.format(worksheet))
						time.sleep(3)

						df_cnt = self._ct_model.write_DF_to_Excel(temp_df, temp_sheet ,'A3')

						self.txtProgress.emit('Finished : Writing dataframe to {}.'.format(worksheet))
						time.sleep(3)
						self._progress_count += 1
						self.countProgress.emit(self._progress_count)

						if self._cancel_flg: self.cancel_program(); break;break;
						self.txtProgress.emit('Started : Formatting {}.'.format(worksheet))
						time.sleep(3)

						self._ct_model.format_range(temp_sheet, df_cnt, 3, 2, 1, 'Center')

						self.txtProgress.emit('Finished : Formatting {}.'.format(worksheet))
						time.sleep(3)
						self._progress_count += 1
						self.countProgress.emit(self._progress_count)

						success = True

					except Exception as e:

						self.currStatus.emit([temp_sheet.name,'Populate Worksheet',str(e)])

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

						if response == QMessageBox.Abort:
							self._abort_flg = True
							self._ct_model.replyBtn = None
							break;
						elif response == QMessageBox.Retry:
							self._ct_model.replyBtn = None
						elif response == QMessageBox.Close:
							self._abort_flg = True
							self._ct_model.replyBtn = None
							break;
			else: break;

		if not self._abort_flg:

			success = False
			while not success:
				try:

					wb_name = 'OTC_TST_Contracts_Step3_After_Transformation_Report_{}.xlsx'.format(self._keyword.upper())
					self.output_filenm = self._tgt_folder + "\\" + wb_name

					if self._cancel_flg: self.cancel_program(); break;
					self.txtProgress.emit('Started : Saving Contract Preval Step 3 Template.')
					time.sleep(3)

					self.temp_workbook.save(self.output_filenm)
					self.temp_workbook.close()

					self.txtProgress.emit('Finished : Saving Contract Preval Step 3 Template.')
					time.sleep(3)

					success = True

				except Exception as e:

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

					response = None
					while response is None:
						response = self._ct_model.replyBtn
						time.sleep(1)
					if response == QMessageBox.Abort:
						self._cancel_flg = True
						self._ct_model.replyBtn = None
						break;
					elif response == QMessageBox.Retry:
						self._ct_model.replyBtn = None
					elif response == QMessageBox.Close:
						self._cancel_flg = True
						self._ct_model.replyBtn = None
						break;

			#Set successful flag

			self.is_successful = True
	

	def cancel_program(self):

		self.txtProgress.emit('Cancelling program...')
		time.sleep(3)

		self.isCancel.emit(self._cancel_flg)
Beispiel #24
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'
Beispiel #25
0
class StatusBar(QWidget):
    """The statusbar at the bottom of the mainwindow.

    Attributes:
        txt: The Text widget in the statusbar.
        keystring: The KeyString widget in the statusbar.
        percentage: The Percentage widget in the statusbar.
        url: The UrlText widget in the statusbar.
        prog: The Progress widget in the statusbar.
        cmd: The Command widget in the statusbar.
        _hbox: The main QHBoxLayout.
        _stack: The QStackedLayout with cmd/txt widgets.
        _text_queue: A deque of (error, text) tuples to be displayed.
                     error: True if message is an error, False otherwise
        _text_pop_timer: A Timer displaying the error messages.
        _stopwatch: A QTime for the last displayed message.
        _timer_was_active: Whether the _text_pop_timer was active before hiding
                           the command widget.
        _previous_widget: A PreviousWidget member - the widget which was
                          displayed when an error interrupted it.
        _win_id: The window ID the statusbar is associated with.

    Class attributes:
        _severity: The severity of the current message, a Severity member.

                   For some reason we need to have this as class attribute so
                   pyqtProperty works correctly.

        _prompt_active: If we're currently in prompt-mode.

                        For some reason we need to have this as class attribute
                        so pyqtProperty works correctly.

        _insert_active: If we're currently in insert mode.

                        For some reason we need to have this as class attribute
                        so pyqtProperty works correctly.

        _command_active: If we're currently in command mode.

                         For some reason we need to have this as class
                         attribute so pyqtProperty works correctly.

        _caret_mode: The current caret mode (off/on/selection).

                     For some reason we need to have this as class attribute
                     so pyqtProperty works correctly.

    Signals:
        resized: Emitted when the statusbar has resized, so the completion
                 widget can adjust its size to it.
                 arg: The new size.
        moved: Emitted when the statusbar has moved, so the completion widget
               can move to the right position.
               arg: The new position.
    """

    resized = pyqtSignal('QRect')
    moved = pyqtSignal('QPoint')
    _severity = None
    _prompt_active = False
    _insert_active = False
    _command_active = False
    _caret_mode = CaretMode.off

    STYLESHEET = """

        QWidget#StatusBar,
        QWidget#StatusBar QLabel,
        QWidget#StatusBar QLineEdit {
            font: {{ font['statusbar'] }};
            background-color: {{ color['statusbar.bg'] }};
            color: {{ color['statusbar.fg'] }};
        }

        QWidget#StatusBar[caret_mode="on"],
        QWidget#StatusBar[caret_mode="on"] QLabel,
        QWidget#StatusBar[caret_mode="on"] QLineEdit {
            color: {{ color['statusbar.fg.caret'] }};
            background-color: {{ color['statusbar.bg.caret'] }};
        }

        QWidget#StatusBar[caret_mode="selection"],
        QWidget#StatusBar[caret_mode="selection"] QLabel,
        QWidget#StatusBar[caret_mode="selection"] QLineEdit {
            color: {{ color['statusbar.fg.caret-selection'] }};
            background-color: {{ color['statusbar.bg.caret-selection'] }};
        }

        QWidget#StatusBar[severity="error"],
        QWidget#StatusBar[severity="error"] QLabel,
        QWidget#StatusBar[severity="error"] QLineEdit {
            color: {{ color['statusbar.fg.error'] }};
            background-color: {{ color['statusbar.bg.error'] }};
        }

        QWidget#StatusBar[severity="warning"],
        QWidget#StatusBar[severity="warning"] QLabel,
        QWidget#StatusBar[severity="warning"] QLineEdit {
            color: {{ color['statusbar.fg.warning'] }};
            background-color: {{ color['statusbar.bg.warning'] }};
        }

        QWidget#StatusBar[prompt_active="true"],
        QWidget#StatusBar[prompt_active="true"] QLabel,
        QWidget#StatusBar[prompt_active="true"] QLineEdit {
            color: {{ color['statusbar.fg.prompt'] }};
            background-color: {{ color['statusbar.bg.prompt'] }};
        }

        QWidget#StatusBar[insert_active="true"],
        QWidget#StatusBar[insert_active="true"] QLabel,
        QWidget#StatusBar[insert_active="true"] QLineEdit {
            color: {{ color['statusbar.fg.insert'] }};
            background-color: {{ color['statusbar.bg.insert'] }};
        }

        QWidget#StatusBar[command_active="true"],
        QWidget#StatusBar[command_active="true"] QLabel,
        QWidget#StatusBar[command_active="true"] QLineEdit {
            color: {{ color['statusbar.fg.command'] }};
            background-color: {{ color['statusbar.bg.command'] }};
        }

    """

    def __init__(self, win_id, parent=None):
        super().__init__(parent)
        objreg.register('statusbar', self, scope='window', window=win_id)
        self.setObjectName(self.__class__.__name__)
        self.setAttribute(Qt.WA_StyledBackground)
        style.set_register_stylesheet(self)

        self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed)

        self._win_id = win_id
        self._option = None
        self._stopwatch = QTime()

        self._hbox = QHBoxLayout(self)
        self.set_hbox_padding()
        objreg.get('config').changed.connect(self.set_hbox_padding)
        self._hbox.setSpacing(5)

        self._stack = QStackedLayout()
        self._hbox.addLayout(self._stack)
        self._stack.setContentsMargins(0, 0, 0, 0)

        self.cmd = command.Command(win_id)
        self._stack.addWidget(self.cmd)
        objreg.register('status-command',
                        self.cmd,
                        scope='window',
                        window=win_id)

        self.txt = textwidget.Text()
        self._stack.addWidget(self.txt)
        self._timer_was_active = False
        self._text_queue = collections.deque()
        self._text_pop_timer = usertypes.Timer(self, 'statusbar_text_pop')
        self._text_pop_timer.timeout.connect(self._pop_text)
        self.set_pop_timer_interval()
        objreg.get('config').changed.connect(self.set_pop_timer_interval)

        self.prompt = prompt.Prompt(win_id)
        self._stack.addWidget(self.prompt)
        self._previous_widget = PreviousWidget.none

        self.cmd.show_cmd.connect(self._show_cmd_widget)
        self.cmd.hide_cmd.connect(self._hide_cmd_widget)
        self._hide_cmd_widget()
        prompter = objreg.get('prompter', scope='window', window=self._win_id)
        prompter.show_prompt.connect(self._show_prompt_widget)
        prompter.hide_prompt.connect(self._hide_prompt_widget)
        self._hide_prompt_widget()

        self.keystring = keystring.KeyString()
        self._hbox.addWidget(self.keystring)

        self.url = url.UrlText()
        self._hbox.addWidget(self.url)

        self.percentage = percentage.Percentage()
        self._hbox.addWidget(self.percentage)

        self.tabindex = tabindex.TabIndex()
        self._hbox.addWidget(self.tabindex)

        # We add a parent to Progress here because it calls self.show() based
        # on some signals, and if that happens before it's added to the layout,
        # it will quickly blink up as independent window.
        self.prog = progress.Progress(self)
        self._hbox.addWidget(self.prog)

        objreg.get('config').changed.connect(self.maybe_hide)
        QTimer.singleShot(0, self.maybe_hide)

    def __repr__(self):
        return utils.get_repr(self)

    @config.change_filter('ui', 'hide-statusbar')
    def maybe_hide(self):
        """Hide the statusbar if it's configured to do so."""
        hide = config.get('ui', 'hide-statusbar')
        if hide:
            self.hide()
        else:
            self.show()

    @config.change_filter('ui', 'statusbar-padding')
    def set_hbox_padding(self):
        padding = config.get('ui', 'statusbar-padding')
        self._hbox.setContentsMargins(padding.left, 0, padding.right, 0)

    @pyqtProperty(str)
    def severity(self):
        """Getter for self.severity, so it can be used as Qt property.

        Return:
            The severity as a string (!)
        """
        if self._severity is None:
            return ""
        else:
            return self._severity.name

    def _set_severity(self, severity):
        """Set the severity for the current message.

        Re-set the stylesheet after setting the value, so everything gets
        updated by Qt properly.

        Args:
            severity: A Severity member.
        """
        if self._severity == severity:
            # This gets called a lot (e.g. if the completion selection was
            # changed), and setStyleSheet is relatively expensive, so we ignore
            # this if there's nothing to change.
            return
        log.statusbar.debug("Setting severity to {}".format(severity))
        self._severity = severity
        self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))
        if severity != Severity.normal:
            # If we got an error while command/prompt was shown, raise the text
            # widget.
            self._stack.setCurrentWidget(self.txt)

    @pyqtProperty(bool)
    def prompt_active(self):
        """Getter for self.prompt_active, so it can be used as Qt property."""
        return self._prompt_active

    def _set_prompt_active(self, val):
        """Setter for self.prompt_active.

        Re-set the stylesheet after setting the value, so everything gets
        updated by Qt properly.
        """
        log.statusbar.debug("Setting prompt_active to {}".format(val))
        self._prompt_active = val
        self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))

    @pyqtProperty(bool)
    def command_active(self):
        """Getter for self.command_active, so it can be used as Qt property."""
        return self._command_active

    @pyqtProperty(bool)
    def insert_active(self):
        """Getter for self.insert_active, so it can be used as Qt property."""
        return self._insert_active

    @pyqtProperty(str)
    def caret_mode(self):
        """Getter for self._caret_mode, so it can be used as Qt property."""
        return self._caret_mode.name

    def set_mode_active(self, mode, val):
        """Setter for self.{insert,command,caret}_active.

        Re-set the stylesheet after setting the value, so everything gets
        updated by Qt properly.
        """
        if mode == usertypes.KeyMode.insert:
            log.statusbar.debug("Setting insert_active to {}".format(val))
            self._insert_active = val
        if mode == usertypes.KeyMode.command:
            log.statusbar.debug("Setting command_active to {}".format(val))
            self._command_active = val
        elif mode == usertypes.KeyMode.caret:
            webview = objreg.get('tabbed-browser',
                                 scope='window',
                                 window=self._win_id).currentWidget()
            log.statusbar.debug("Setting caret_mode - val {}, selection "
                                "{}".format(val, webview.selection_enabled))
            if val:
                if webview.selection_enabled:
                    self._set_mode_text("{} selection".format(mode.name))
                    self._caret_mode = CaretMode.selection
                else:
                    self._set_mode_text(mode.name)
                    self._caret_mode = CaretMode.on
            else:
                self._caret_mode = CaretMode.off
        self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))

    def _set_mode_text(self, mode):
        """Set the mode text."""
        text = "-- {} MODE --".format(mode.upper())
        self.txt.set_text(self.txt.Text.normal, text)

    def _pop_text(self):
        """Display a text in the statusbar and pop it from _text_queue."""
        try:
            severity, text = self._text_queue.popleft()
        except IndexError:
            self._set_severity(Severity.normal)
            self.txt.set_text(self.txt.Text.temp, '')
            self._text_pop_timer.stop()
            # If a previous widget was interrupted by an error, restore it.
            if self._previous_widget == PreviousWidget.prompt:
                self._stack.setCurrentWidget(self.prompt)
            elif self._previous_widget == PreviousWidget.command:
                self._stack.setCurrentWidget(self.cmd)
            elif self._previous_widget == PreviousWidget.none:
                self.maybe_hide()
            else:
                raise AssertionError("Unknown _previous_widget!")
            return
        self.show()
        log.statusbar.debug("Displaying message: {} (severity {})".format(
            text, severity))
        log.statusbar.debug("Remaining: {}".format(self._text_queue))
        self._set_severity(severity)
        self.txt.set_text(self.txt.Text.temp, text)

    def _show_cmd_widget(self):
        """Show command widget instead of temporary text."""
        self._set_severity(Severity.normal)
        self._previous_widget = PreviousWidget.command
        if self._text_pop_timer.isActive():
            self._timer_was_active = True
        self._text_pop_timer.stop()
        self._stack.setCurrentWidget(self.cmd)
        self.show()

    def _hide_cmd_widget(self):
        """Show temporary text instead of command widget."""
        log.statusbar.debug("Hiding cmd widget, queue: {}".format(
            self._text_queue))
        self._previous_widget = PreviousWidget.none
        if self._timer_was_active:
            # Restart the text pop timer if it was active before hiding.
            self._pop_text()
            self._text_pop_timer.start()
            self._timer_was_active = False
        self._stack.setCurrentWidget(self.txt)
        self.maybe_hide()

    def _show_prompt_widget(self):
        """Show prompt widget instead of temporary text."""
        if self._stack.currentWidget() is self.prompt:
            return
        self._set_severity(Severity.normal)
        self._set_prompt_active(True)
        self._previous_widget = PreviousWidget.prompt
        if self._text_pop_timer.isActive():
            self._timer_was_active = True
        self._text_pop_timer.stop()
        self._stack.setCurrentWidget(self.prompt)
        self.show()

    def _hide_prompt_widget(self):
        """Show temporary text instead of prompt widget."""
        self._set_prompt_active(False)
        self._previous_widget = PreviousWidget.none
        log.statusbar.debug("Hiding prompt widget, queue: {}".format(
            self._text_queue))
        if self._timer_was_active:
            # Restart the text pop timer if it was active before hiding.
            self._pop_text()
            self._text_pop_timer.start()
            self._timer_was_active = False
        self._stack.setCurrentWidget(self.txt)
        self.maybe_hide()

    def _disp_text(self, text, severity, immediately=False):
        """Inner logic for disp_error and disp_temp_text.

        Args:
            text: The message to display.
            severity: The severity of the messages.
            immediately: If set, message gets displayed immediately instead of
                         queued.
        """
        log.statusbar.debug("Displaying text: {} (severity={})".format(
            text, severity))
        mindelta = config.get('ui', 'message-timeout')
        if self._stopwatch.isNull():
            delta = None
            self._stopwatch.start()
        else:
            delta = self._stopwatch.restart()
        log.statusbar.debug("queue: {} / delta: {}".format(
            self._text_queue, delta))
        if not self._text_queue and (delta is None or delta > mindelta):
            # If the queue is empty and we didn't print messages for long
            # enough, we can take the short route and display the message
            # immediately. We then start the pop_timer only to restore the
            # normal state in 2 seconds.
            log.statusbar.debug("Displaying immediately")
            self._set_severity(severity)
            self.show()
            self.txt.set_text(self.txt.Text.temp, text)
            self._text_pop_timer.start()
        elif self._text_queue and self._text_queue[-1] == (severity, text):
            # If we get the same message multiple times in a row and we're
            # still displaying it *anyways* we ignore the new one
            log.statusbar.debug("ignoring")
        elif immediately:
            # This message is a reaction to a keypress and should be displayed
            # immediately, temporarily interrupting the message queue.
            # We display this immediately and restart the timer.to clear it and
            # display the rest of the queue later.
            log.statusbar.debug("Moving to beginning of queue")
            self._set_severity(severity)
            self.show()
            self.txt.set_text(self.txt.Text.temp, text)
            self._text_pop_timer.start()
        else:
            # There are still some messages to be displayed, so we queue this
            # up.
            log.statusbar.debug("queueing")
            self._text_queue.append((severity, text))
            self._text_pop_timer.start()

    @pyqtSlot(str, bool)
    def disp_error(self, text, immediately=False):
        """Display an error in the statusbar.

        Args:
            text: The message to display.
            immediately: If set, message gets displayed immediately instead of
                         queued.
        """
        self._disp_text(text, Severity.error, immediately)

    @pyqtSlot(str, bool)
    def disp_warning(self, text, immediately=False):
        """Display a warning in the statusbar.

        Args:
            text: The message to display.
            immediately: If set, message gets displayed immediately instead of
                         queued.
        """
        self._disp_text(text, Severity.warning, immediately)

    @pyqtSlot(str, bool)
    def disp_temp_text(self, text, immediately):
        """Display a temporary text in the statusbar.

        Args:
            text: The message to display.
            immediately: If set, message gets displayed immediately instead of
                         queued.
        """
        self._disp_text(text, Severity.normal, immediately)

    @pyqtSlot(str)
    def set_text(self, val):
        """Set a normal (persistent) text in the status bar."""
        self.txt.set_text(self.txt.Text.normal, val)

    @pyqtSlot(usertypes.KeyMode)
    def on_mode_entered(self, mode):
        """Mark certain modes in the commandline."""
        keyparsers = objreg.get('keyparsers',
                                scope='window',
                                window=self._win_id)
        if keyparsers[mode].passthrough:
            self._set_mode_text(mode.name)
        if mode in (usertypes.KeyMode.insert, usertypes.KeyMode.command,
                    usertypes.KeyMode.caret):
            self.set_mode_active(mode, True)

    @pyqtSlot(usertypes.KeyMode, usertypes.KeyMode)
    def on_mode_left(self, old_mode, new_mode):
        """Clear marked mode."""
        keyparsers = objreg.get('keyparsers',
                                scope='window',
                                window=self._win_id)
        if keyparsers[old_mode].passthrough:
            if keyparsers[new_mode].passthrough:
                self._set_mode_text(new_mode.name)
            else:
                self.txt.set_text(self.txt.Text.normal, '')
        if old_mode in (usertypes.KeyMode.insert, usertypes.KeyMode.command,
                        usertypes.KeyMode.caret):
            self.set_mode_active(old_mode, False)

    @config.change_filter('ui', 'message-timeout')
    def set_pop_timer_interval(self):
        """Update message timeout when config changed."""
        self._text_pop_timer.setInterval(config.get('ui', 'message-timeout'))

    def resizeEvent(self, e):
        """Extend resizeEvent of QWidget to emit a resized signal afterwards.

        Args:
            e: The QResizeEvent.
        """
        super().resizeEvent(e)
        self.resized.emit(self.geometry())

    def moveEvent(self, e):
        """Extend moveEvent of QWidget to emit a moved signal afterwards.

        Args:
            e: The QMoveEvent.
        """
        super().moveEvent(e)
        self.moved.emit(e.pos())

    def minimumSizeHint(self):
        """Set the minimum height to the text height plus some padding."""
        padding = config.get('ui', 'statusbar-padding')
        width = super().minimumSizeHint().width()
        height = self.fontMetrics().height() + padding.top + padding.bottom
        return QSize(width, height)
Beispiel #26
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)
        # 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)
Beispiel #27
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)))
Beispiel #28
0
class StatusBar(QWidget):

    """The statusbar at the bottom of the mainwindow.

    Attributes:
        txt: The Text widget in the statusbar.
        keystring: The KeyString widget in the statusbar.
        percentage: The Percentage widget in the statusbar.
        url: The UrlText widget in the statusbar.
        prog: The Progress widget in the statusbar.
        cmd: The Command widget in the statusbar.
        _hbox: The main QHBoxLayout.
        _stack: The QStackedLayout with cmd/txt widgets.
        _text_queue: A deque of (error, text) tuples to be displayed.
                     error: True if message is an error, False otherwise
        _text_pop_timer: A Timer displaying the error messages.
        _stopwatch: A QTime for the last displayed message.
        _timer_was_active: Whether the _text_pop_timer was active before hiding
                           the command widget.
        _previous_widget: A PreviousWidget member - the widget which was
                          displayed when an error interrupted it.
        _win_id: The window ID the statusbar is associated with.

    Class attributes:
        _error: If there currently is an error, accessed through the error
                property.

                For some reason we need to have this as class attribute so
                pyqtProperty works correctly.

        _prompt_active: If we're currently in prompt-mode.

                        For some reason we need to have this as class attribute
                        so pyqtProperty works correctly.

        _insert_active: If we're currently in insert mode.

                        For some reason we need to have this as class attribute
                        so pyqtProperty works correctly.

    Signals:
        resized: Emitted when the statusbar has resized, so the completion
                 widget can adjust its size to it.
                 arg: The new size.
        moved: Emitted when the statusbar has moved, so the completion widget
               can move the the right position.
               arg: The new position.
    """

    resized = pyqtSignal('QRect')
    moved = pyqtSignal('QPoint')
    _error = False
    _prompt_active = False
    _insert_active = False

    STYLESHEET = """
        QWidget#StatusBar {
            {{ color['statusbar.bg'] }}
        }

        QWidget#StatusBar[insert_active="true"] {
            {{ color['statusbar.bg.insert'] }}
        }

        QWidget#StatusBar[prompt_active="true"] {
            {{ color['statusbar.bg.prompt'] }}
        }

        QWidget#StatusBar[error="true"] {
            {{ color['statusbar.bg.error'] }}
        }

        QLabel, QLineEdit {
            {{ color['statusbar.fg'] }}
            {{ font['statusbar'] }}
        }
    """

    def __init__(self, win_id, parent=None):
        super().__init__(parent)
        objreg.register('statusbar', self, scope='window', window=win_id)
        self.setObjectName(self.__class__.__name__)
        self.setAttribute(Qt.WA_StyledBackground)
        style.set_register_stylesheet(self)

        self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed)

        self._win_id = win_id
        self._option = None
        self._stopwatch = QTime()

        self._hbox = QHBoxLayout(self)
        self._hbox.setContentsMargins(0, 0, 0, 0)
        self._hbox.setSpacing(5)

        self._stack = QStackedLayout()
        self._hbox.addLayout(self._stack)
        self._stack.setContentsMargins(0, 0, 0, 0)

        self.cmd = command.Command(win_id)
        self._stack.addWidget(self.cmd)
        objreg.register('status-command', self.cmd, scope='window',
                        window=win_id)

        self.txt = textwidget.Text()
        self._stack.addWidget(self.txt)
        self._timer_was_active = False
        self._text_queue = collections.deque()
        self._text_pop_timer = usertypes.Timer(self, 'statusbar_text_pop')
        self._text_pop_timer.timeout.connect(self._pop_text)
        self.set_pop_timer_interval()
        objreg.get('config').changed.connect(self.set_pop_timer_interval)

        self.prompt = prompt.Prompt(win_id)
        self._stack.addWidget(self.prompt)
        self._previous_widget = PreviousWidget.none

        self.cmd.show_cmd.connect(self._show_cmd_widget)
        self.cmd.hide_cmd.connect(self._hide_cmd_widget)
        self._hide_cmd_widget()
        prompter = objreg.get('prompter', scope='window', window=self._win_id)
        prompter.show_prompt.connect(self._show_prompt_widget)
        prompter.hide_prompt.connect(self._hide_prompt_widget)
        self._hide_prompt_widget()

        self.keystring = keystring.KeyString()
        self._hbox.addWidget(self.keystring)

        self.url = url.UrlText()
        self._hbox.addWidget(self.url)

        self.percentage = percentage.Percentage()
        self._hbox.addWidget(self.percentage)

        # We add a parent to Progress here because it calls self.show() based
        # on some signals, and if that happens before it's added to the layout,
        # it will quickly blink up as independent window.
        self.prog = progress.Progress(self)
        self._hbox.addWidget(self.prog)

    def __repr__(self):
        return utils.get_repr(self)

    @pyqtProperty(bool)
    def error(self):
        """Getter for self.error, so it can be used as Qt property."""
        # pylint: disable=method-hidden
        return self._error

    def _set_error(self, val):
        """Setter for self.error, so it can be used as Qt property.

        Re-set the stylesheet after setting the value, so everything gets
        updated by Qt properly.
        """
        if self._error == val:
            # This gets called a lot (e.g. if the completion selection was
            # changed), and setStyleSheet is relatively expensive, so we ignore
            # this if there's nothing to change.
            return
        log.statusbar.debug("Setting error to {}".format(val))
        self._error = val
        self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))
        if val:
            # If we got an error while command/prompt was shown, raise the text
            # widget.
            self._stack.setCurrentWidget(self.txt)

    @pyqtProperty(bool)
    def prompt_active(self):
        """Getter for self.prompt_active, so it can be used as Qt property."""
        # pylint: disable=method-hidden
        return self._prompt_active

    def _set_prompt_active(self, val):
        """Setter for self.prompt_active.

        Re-set the stylesheet after setting the value, so everything gets
        updated by Qt properly.
        """
        log.statusbar.debug("Setting prompt_active to {}".format(val))
        self._prompt_active = val
        self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))

    @pyqtProperty(bool)
    def insert_active(self):
        """Getter for self.insert_active, so it can be used as Qt property."""
        # pylint: disable=method-hidden
        return self._insert_active

    def _set_insert_active(self, val):
        """Setter for self.insert_active.

        Re-set the stylesheet after setting the value, so everything gets
        updated by Qt properly.
        """
        log.statusbar.debug("Setting insert_active to {}".format(val))
        self._insert_active = val
        self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))

    def _pop_text(self):
        """Display a text in the statusbar and pop it from _text_queue."""
        try:
            error, text = self._text_queue.popleft()
        except IndexError:
            self._set_error(False)
            self.txt.set_text(self.txt.Text.temp, '')
            self._text_pop_timer.stop()
            # If a previous widget was interrupted by an error, restore it.
            if self._previous_widget == PreviousWidget.prompt:
                self._stack.setCurrentWidget(self.prompt)
            elif self._previous_widget == PreviousWidget.command:
                self._stack.setCurrentWidget(self.command)
            elif self._previous_widget == PreviousWidget.none:
                pass
            else:
                raise AssertionError("Unknown _previous_widget!")
            return
        log.statusbar.debug("Displaying {} message: {}".format(
            'error' if error else 'text', text))
        log.statusbar.debug("Remaining: {}".format(self._text_queue))
        self._set_error(error)
        self.txt.set_text(self.txt.Text.temp, text)

    def _show_cmd_widget(self):
        """Show command widget instead of temporary text."""
        self._set_error(False)
        self._previous_widget = PreviousWidget.prompt
        if self._text_pop_timer.isActive():
            self._timer_was_active = True
        self._text_pop_timer.stop()
        self._stack.setCurrentWidget(self.cmd)

    def _hide_cmd_widget(self):
        """Show temporary text instead of command widget."""
        log.statusbar.debug("Hiding cmd widget, queue: {}".format(
            self._text_queue))
        self._previous_widget = PreviousWidget.none
        if self._timer_was_active:
            # Restart the text pop timer if it was active before hiding.
            self._pop_text()
            self._text_pop_timer.start()
            self._timer_was_active = False
        self._stack.setCurrentWidget(self.txt)

    def _show_prompt_widget(self):
        """Show prompt widget instead of temporary text."""
        if self._stack.currentWidget() is self.prompt:
            return
        self._set_error(False)
        self._set_prompt_active(True)
        self._previous_widget = PreviousWidget.prompt
        if self._text_pop_timer.isActive():
            self._timer_was_active = True
        self._text_pop_timer.stop()
        self._stack.setCurrentWidget(self.prompt)

    def _hide_prompt_widget(self):
        """Show temporary text instead of prompt widget."""
        self._set_prompt_active(False)
        self._previous_widget = PreviousWidget.none
        log.statusbar.debug("Hiding prompt widget, queue: {}".format(
            self._text_queue))
        if self._timer_was_active:
            # Restart the text pop timer if it was active before hiding.
            self._pop_text()
            self._text_pop_timer.start()
            self._timer_was_active = False
        self._stack.setCurrentWidget(self.txt)

    def _disp_text(self, text, error, immediately=False):
        """Inner logic for disp_error and disp_temp_text.

        Args:
            text: The message to display.
            error: Whether it's an error message (True) or normal text (False)
            immediately: If set, message gets displayed immediately instead of
                         queued.
        """
        log.statusbar.debug("Displaying text: {} (error={})".format(
            text, error))
        mindelta = config.get('ui', 'message-timeout')
        if self._stopwatch.isNull():
            delta = None
            self._stopwatch.start()
        else:
            delta = self._stopwatch.restart()
        log.statusbar.debug("queue: {} / delta: {}".format(
            self._text_queue, delta))
        if not self._text_queue and (delta is None or delta > mindelta):
            # If the queue is empty and we didn't print messages for long
            # enough, we can take the short route and display the message
            # immediately. We then start the pop_timer only to restore the
            # normal state in 2 seconds.
            log.statusbar.debug("Displaying immediately")
            self._set_error(error)
            self.txt.set_text(self.txt.Text.temp, text)
            self._text_pop_timer.start()
        elif self._text_queue and self._text_queue[-1] == (error, text):
            # If we get the same message multiple times in a row and we're
            # still displaying it *anyways* we ignore the new one
            log.statusbar.debug("ignoring")
        elif immediately:
            # This message is a reaction to a keypress and should be displayed
            # immediately, temporarily interrupting the message queue.
            # We display this immediately and restart the timer.to clear it and
            # display the rest of the queue later.
            log.statusbar.debug("Moving to beginning of queue")
            self._set_error(error)
            self.txt.set_text(self.txt.Text.temp, text)
            self._text_pop_timer.start()
        else:
            # There are still some messages to be displayed, so we queue this
            # up.
            log.statusbar.debug("queueing")
            self._text_queue.append((error, text))
            self._text_pop_timer.start()

    @pyqtSlot(str, bool)
    def disp_error(self, text, immediately=False):
        """Display an error in the statusbar.

        Args:
            text: The message to display.
            immediately: If set, message gets displayed immediately instead of
                         queued.
        """
        self._disp_text(text, True, immediately)

    @pyqtSlot(str, bool)
    def disp_temp_text(self, text, immediately):
        """Display a temporary text in the statusbar.

        Args:
            text: The message to display.
            immediately: If set, message gets displayed immediately instead of
                         queued.
        """
        self._disp_text(text, False, immediately)

    @pyqtSlot(str)
    def set_text(self, val):
        """Set a normal (persistent) text in the status bar."""
        self.txt.set_text(self.txt.Text.normal, val)

    @pyqtSlot(usertypes.KeyMode)
    def on_mode_entered(self, mode):
        """Mark certain modes in the commandline."""
        mode_manager = objreg.get('mode-manager', scope='window',
                                  window=self._win_id)
        if mode in mode_manager.passthrough:
            text = "-- {} MODE --".format(mode.name.upper())
            self.txt.set_text(self.txt.Text.normal, text)
        if mode == usertypes.KeyMode.insert:
            self._set_insert_active(True)

    @pyqtSlot(usertypes.KeyMode)
    def on_mode_left(self, mode):
        """Clear marked mode."""
        mode_manager = objreg.get('mode-manager', scope='window',
                                  window=self._win_id)
        if mode in mode_manager.passthrough:
            self.txt.set_text(self.txt.Text.normal, '')
        if mode == usertypes.KeyMode.insert:
            self._set_insert_active(False)

    @config.change_filter('ui', 'message-timeout')
    def set_pop_timer_interval(self):
        """Update message timeout when config changed."""
        self._text_pop_timer.setInterval(config.get('ui', 'message-timeout'))

    def resizeEvent(self, e):
        """Extend resizeEvent of QWidget to emit a resized signal afterwards.

        Args:
            e: The QResizeEvent.
        """
        super().resizeEvent(e)
        self.resized.emit(self.geometry())

    def moveEvent(self, e):
        """Extend moveEvent of QWidget to emit a moved signal afterwards.

        Args:
            e: The QMoveEvent.
        """
        super().moveEvent(e)
        self.moved.emit(e.pos())
Beispiel #29
0
class StatusBar(QWidget):

    """The statusbar at the bottom of the mainwindow.

    Attributes:
        txt: The Text widget in the statusbar.
        keystring: The KeyString widget in the statusbar.
        percentage: The Percentage widget in the statusbar.
        url: The UrlText widget in the statusbar.
        prog: The Progress widget in the statusbar.
        cmd: The Command widget in the statusbar.
        _hbox: The main QHBoxLayout.
        _stack: The QStackedLayout with cmd/txt widgets.
        _text_queue: A deque of (error, text) tuples to be displayed.
                     error: True if message is an error, False otherwise
        _text_pop_timer: A Timer displaying the error messages.
        _stopwatch: A QTime for the last displayed message.
        _timer_was_active: Whether the _text_pop_timer was active before hiding
                           the command widget.
        _previous_widget: A PreviousWidget member - the widget which was
                          displayed when an error interrupted it.
        _win_id: The window ID the statusbar is associated with.

    Class attributes:
        _severity: The severity of the current message, a Severity member.

                   For some reason we need to have this as class attribute so
                   pyqtProperty works correctly.

        _prompt_active: If we're currently in prompt-mode.

                        For some reason we need to have this as class attribute
                        so pyqtProperty works correctly.

        _insert_active: If we're currently in insert mode.

                        For some reason we need to have this as class attribute
                        so pyqtProperty works correctly.

        _command_active: If we're currently in command mode.

                         For some reason we need to have this as class
                         attribute so pyqtProperty works correctly.

        _caret_mode: The current caret mode (off/on/selection).

                     For some reason we need to have this as class attribute
                     so pyqtProperty works correctly.

    Signals:
        resized: Emitted when the statusbar has resized, so the completion
                 widget can adjust its size to it.
                 arg: The new size.
        moved: Emitted when the statusbar has moved, so the completion widget
               can move to the right position.
               arg: The new position.
    """

    resized = pyqtSignal('QRect')
    moved = pyqtSignal('QPoint')
    _severity = None
    _prompt_active = False
    _insert_active = False
    _command_active = False
    _caret_mode = CaretMode.off

    STYLESHEET = """

        QWidget#StatusBar,
        QWidget#StatusBar QLabel,
        QWidget#StatusBar QLineEdit {
            font: {{ font['statusbar'] }};
            background-color: {{ color['statusbar.bg'] }};
            color: {{ color['statusbar.fg'] }};
        }

        QWidget#StatusBar[caret_mode="on"],
        QWidget#StatusBar[caret_mode="on"] QLabel,
        QWidget#StatusBar[caret_mode="on"] QLineEdit {
            color: {{ color['statusbar.fg.caret'] }};
            background-color: {{ color['statusbar.bg.caret'] }};
        }

        QWidget#StatusBar[caret_mode="selection"],
        QWidget#StatusBar[caret_mode="selection"] QLabel,
        QWidget#StatusBar[caret_mode="selection"] QLineEdit {
            color: {{ color['statusbar.fg.caret-selection'] }};
            background-color: {{ color['statusbar.bg.caret-selection'] }};
        }

        QWidget#StatusBar[severity="error"],
        QWidget#StatusBar[severity="error"] QLabel,
        QWidget#StatusBar[severity="error"] QLineEdit {
            color: {{ color['statusbar.fg.error'] }};
            background-color: {{ color['statusbar.bg.error'] }};
        }

        QWidget#StatusBar[severity="warning"],
        QWidget#StatusBar[severity="warning"] QLabel,
        QWidget#StatusBar[severity="warning"] QLineEdit {
            color: {{ color['statusbar.fg.warning'] }};
            background-color: {{ color['statusbar.bg.warning'] }};
        }

        QWidget#StatusBar[prompt_active="true"],
        QWidget#StatusBar[prompt_active="true"] QLabel,
        QWidget#StatusBar[prompt_active="true"] QLineEdit {
            color: {{ color['statusbar.fg.prompt'] }};
            background-color: {{ color['statusbar.bg.prompt'] }};
        }

        QWidget#StatusBar[insert_active="true"],
        QWidget#StatusBar[insert_active="true"] QLabel,
        QWidget#StatusBar[insert_active="true"] QLineEdit {
            color: {{ color['statusbar.fg.insert'] }};
            background-color: {{ color['statusbar.bg.insert'] }};
        }

        QWidget#StatusBar[command_active="true"],
        QWidget#StatusBar[command_active="true"] QLabel,
        QWidget#StatusBar[command_active="true"] QLineEdit {
            color: {{ color['statusbar.fg.command'] }};
            background-color: {{ color['statusbar.bg.command'] }};
        }

    """

    def __init__(self, win_id, parent=None):
        super().__init__(parent)
        objreg.register('statusbar', self, scope='window', window=win_id)
        self.setObjectName(self.__class__.__name__)
        self.setAttribute(Qt.WA_StyledBackground)
        style.set_register_stylesheet(self)

        self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed)

        self._win_id = win_id
        self._option = None
        self._stopwatch = QTime()

        self._hbox = QHBoxLayout(self)
        self.set_hbox_padding()
        objreg.get('config').changed.connect(self.set_hbox_padding)
        self._hbox.setSpacing(5)

        self._stack = QStackedLayout()
        self._hbox.addLayout(self._stack)
        self._stack.setContentsMargins(0, 0, 0, 0)

        self.cmd = command.Command(win_id)
        self._stack.addWidget(self.cmd)
        objreg.register('status-command', self.cmd, scope='window',
                        window=win_id)

        self.txt = textwidget.Text()
        self._stack.addWidget(self.txt)
        self._timer_was_active = False
        self._text_queue = collections.deque()
        self._text_pop_timer = usertypes.Timer(self, 'statusbar_text_pop')
        self._text_pop_timer.timeout.connect(self._pop_text)
        self.set_pop_timer_interval()
        objreg.get('config').changed.connect(self.set_pop_timer_interval)

        self.prompt = prompt.Prompt(win_id)
        self._stack.addWidget(self.prompt)
        self._previous_widget = PreviousWidget.none

        self.cmd.show_cmd.connect(self._show_cmd_widget)
        self.cmd.hide_cmd.connect(self._hide_cmd_widget)
        self._hide_cmd_widget()
        prompter = objreg.get('prompter', scope='window', window=self._win_id)
        prompter.show_prompt.connect(self._show_prompt_widget)
        prompter.hide_prompt.connect(self._hide_prompt_widget)
        self._hide_prompt_widget()

        self.keystring = keystring.KeyString()
        self._hbox.addWidget(self.keystring)

        self.url = url.UrlText()
        self._hbox.addWidget(self.url)

        self.percentage = percentage.Percentage()
        self._hbox.addWidget(self.percentage)

        self.tabindex = tabindex.TabIndex()
        self._hbox.addWidget(self.tabindex)

        # We add a parent to Progress here because it calls self.show() based
        # on some signals, and if that happens before it's added to the layout,
        # it will quickly blink up as independent window.
        self.prog = progress.Progress(self)
        self._hbox.addWidget(self.prog)

        objreg.get('config').changed.connect(self.maybe_hide)
        QTimer.singleShot(0, self.maybe_hide)

    def __repr__(self):
        return utils.get_repr(self)

    @config.change_filter('ui', 'hide-statusbar')
    def maybe_hide(self):
        """Hide the statusbar if it's configured to do so."""
        hide = config.get('ui', 'hide-statusbar')
        if hide:
            self.hide()
        else:
            self.show()

    @config.change_filter('ui', 'statusbar-padding')
    def set_hbox_padding(self):
        padding = config.get('ui', 'statusbar-padding')
        self._hbox.setContentsMargins(padding.left, 0, padding.right, 0)

    @pyqtProperty(str)
    def severity(self):
        """Getter for self.severity, so it can be used as Qt property.

        Return:
            The severity as a string (!)
        """
        if self._severity is None:
            return ""
        else:
            return self._severity.name

    def _set_severity(self, severity):
        """Set the severity for the current message.

        Re-set the stylesheet after setting the value, so everything gets
        updated by Qt properly.

        Args:
            severity: A Severity member.
        """
        if self._severity == severity:
            # This gets called a lot (e.g. if the completion selection was
            # changed), and setStyleSheet is relatively expensive, so we ignore
            # this if there's nothing to change.
            return
        log.statusbar.debug("Setting severity to {}".format(severity))
        self._severity = severity
        self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))
        if severity != Severity.normal:
            # If we got an error while command/prompt was shown, raise the text
            # widget.
            self._stack.setCurrentWidget(self.txt)

    @pyqtProperty(bool)
    def prompt_active(self):
        """Getter for self.prompt_active, so it can be used as Qt property."""
        return self._prompt_active

    def _set_prompt_active(self, val):
        """Setter for self.prompt_active.

        Re-set the stylesheet after setting the value, so everything gets
        updated by Qt properly.
        """
        log.statusbar.debug("Setting prompt_active to {}".format(val))
        self._prompt_active = val
        self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))

    @pyqtProperty(bool)
    def command_active(self):
        """Getter for self.command_active, so it can be used as Qt property."""
        return self._command_active

    @pyqtProperty(bool)
    def insert_active(self):
        """Getter for self.insert_active, so it can be used as Qt property."""
        return self._insert_active

    @pyqtProperty(str)
    def caret_mode(self):
        """Getter for self._caret_mode, so it can be used as Qt property."""
        return self._caret_mode.name

    def set_mode_active(self, mode, val):
        """Setter for self.{insert,command,caret}_active.

        Re-set the stylesheet after setting the value, so everything gets
        updated by Qt properly.
        """
        if mode == usertypes.KeyMode.insert:
            log.statusbar.debug("Setting insert_active to {}".format(val))
            self._insert_active = val
        if mode == usertypes.KeyMode.command:
            log.statusbar.debug("Setting command_active to {}".format(val))
            self._command_active = val
        elif mode == usertypes.KeyMode.caret:
            webview = objreg.get('tabbed-browser', scope='window',
                                 window=self._win_id).currentWidget()
            log.statusbar.debug("Setting caret_mode - val {}, selection "
                                "{}".format(val, webview.selection_enabled))
            if val:
                if webview.selection_enabled:
                    self._set_mode_text("{} selection".format(mode.name))
                    self._caret_mode = CaretMode.selection
                else:
                    self._set_mode_text(mode.name)
                    self._caret_mode = CaretMode.on
            else:
                self._caret_mode = CaretMode.off
        self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))

    def _set_mode_text(self, mode):
        """Set the mode text."""
        text = "-- {} MODE --".format(mode.upper())
        self.txt.set_text(self.txt.Text.normal, text)

    def _pop_text(self):
        """Display a text in the statusbar and pop it from _text_queue."""
        try:
            severity, text = self._text_queue.popleft()
        except IndexError:
            self._set_severity(Severity.normal)
            self.txt.set_text(self.txt.Text.temp, '')
            self._text_pop_timer.stop()
            # If a previous widget was interrupted by an error, restore it.
            if self._previous_widget == PreviousWidget.prompt:
                self._stack.setCurrentWidget(self.prompt)
            elif self._previous_widget == PreviousWidget.command:
                self._stack.setCurrentWidget(self.cmd)
            elif self._previous_widget == PreviousWidget.none:
                self.maybe_hide()
            else:
                raise AssertionError("Unknown _previous_widget!")
            return
        self.show()
        log.statusbar.debug("Displaying message: {} (severity {})".format(
            text, severity))
        log.statusbar.debug("Remaining: {}".format(self._text_queue))
        self._set_severity(severity)
        self.txt.set_text(self.txt.Text.temp, text)

    def _show_cmd_widget(self):
        """Show command widget instead of temporary text."""
        self._set_severity(Severity.normal)
        self._previous_widget = PreviousWidget.command
        if self._text_pop_timer.isActive():
            self._timer_was_active = True
        self._text_pop_timer.stop()
        self._stack.setCurrentWidget(self.cmd)
        self.show()

    def _hide_cmd_widget(self):
        """Show temporary text instead of command widget."""
        log.statusbar.debug("Hiding cmd widget, queue: {}".format(
            self._text_queue))
        self._previous_widget = PreviousWidget.none
        if self._timer_was_active:
            # Restart the text pop timer if it was active before hiding.
            self._pop_text()
            self._text_pop_timer.start()
            self._timer_was_active = False
        self._stack.setCurrentWidget(self.txt)
        self.maybe_hide()

    def _show_prompt_widget(self):
        """Show prompt widget instead of temporary text."""
        if self._stack.currentWidget() is self.prompt:
            return
        self._set_severity(Severity.normal)
        self._set_prompt_active(True)
        self._previous_widget = PreviousWidget.prompt
        if self._text_pop_timer.isActive():
            self._timer_was_active = True
        self._text_pop_timer.stop()
        self._stack.setCurrentWidget(self.prompt)
        self.show()

    def _hide_prompt_widget(self):
        """Show temporary text instead of prompt widget."""
        self._set_prompt_active(False)
        self._previous_widget = PreviousWidget.none
        log.statusbar.debug("Hiding prompt widget, queue: {}".format(
            self._text_queue))
        if self._timer_was_active:
            # Restart the text pop timer if it was active before hiding.
            self._pop_text()
            self._text_pop_timer.start()
            self._timer_was_active = False
        self._stack.setCurrentWidget(self.txt)
        self.maybe_hide()

    def _disp_text(self, text, severity, immediately=False):
        """Inner logic for disp_error and disp_temp_text.

        Args:
            text: The message to display.
            severity: The severity of the messages.
            immediately: If set, message gets displayed immediately instead of
                         queued.
        """
        log.statusbar.debug("Displaying text: {} (severity={})".format(
            text, severity))
        mindelta = config.get('ui', 'message-timeout')
        if self._stopwatch.isNull():
            delta = None
            self._stopwatch.start()
        else:
            delta = self._stopwatch.restart()
        log.statusbar.debug("queue: {} / delta: {}".format(
            self._text_queue, delta))
        if not self._text_queue and (delta is None or delta > mindelta):
            # If the queue is empty and we didn't print messages for long
            # enough, we can take the short route and display the message
            # immediately. We then start the pop_timer only to restore the
            # normal state in 2 seconds.
            log.statusbar.debug("Displaying immediately")
            self._set_severity(severity)
            self.show()
            self.txt.set_text(self.txt.Text.temp, text)
            self._text_pop_timer.start()
        elif self._text_queue and self._text_queue[-1] == (severity, text):
            # If we get the same message multiple times in a row and we're
            # still displaying it *anyways* we ignore the new one
            log.statusbar.debug("ignoring")
        elif immediately:
            # This message is a reaction to a keypress and should be displayed
            # immediately, temporarily interrupting the message queue.
            # We display this immediately and restart the timer.to clear it and
            # display the rest of the queue later.
            log.statusbar.debug("Moving to beginning of queue")
            self._set_severity(severity)
            self.show()
            self.txt.set_text(self.txt.Text.temp, text)
            self._text_pop_timer.start()
        else:
            # There are still some messages to be displayed, so we queue this
            # up.
            log.statusbar.debug("queueing")
            self._text_queue.append((severity, text))
            self._text_pop_timer.start()

    @pyqtSlot(str, bool)
    def disp_error(self, text, immediately=False):
        """Display an error in the statusbar.

        Args:
            text: The message to display.
            immediately: If set, message gets displayed immediately instead of
                         queued.
        """
        self._disp_text(text, Severity.error, immediately)

    @pyqtSlot(str, bool)
    def disp_warning(self, text, immediately=False):
        """Display a warning in the statusbar.

        Args:
            text: The message to display.
            immediately: If set, message gets displayed immediately instead of
                         queued.
        """
        self._disp_text(text, Severity.warning, immediately)

    @pyqtSlot(str, bool)
    def disp_temp_text(self, text, immediately):
        """Display a temporary text in the statusbar.

        Args:
            text: The message to display.
            immediately: If set, message gets displayed immediately instead of
                         queued.
        """
        self._disp_text(text, Severity.normal, immediately)

    @pyqtSlot(str)
    def set_text(self, val):
        """Set a normal (persistent) text in the status bar."""
        self.txt.set_text(self.txt.Text.normal, val)

    @pyqtSlot(usertypes.KeyMode)
    def on_mode_entered(self, mode):
        """Mark certain modes in the commandline."""
        keyparsers = objreg.get('keyparsers', scope='window',
                                window=self._win_id)
        if keyparsers[mode].passthrough:
            self._set_mode_text(mode.name)
        if mode in (usertypes.KeyMode.insert,
                    usertypes.KeyMode.command,
                    usertypes.KeyMode.caret):
            self.set_mode_active(mode, True)

    @pyqtSlot(usertypes.KeyMode, usertypes.KeyMode)
    def on_mode_left(self, old_mode, new_mode):
        """Clear marked mode."""
        keyparsers = objreg.get('keyparsers', scope='window',
                                window=self._win_id)
        if keyparsers[old_mode].passthrough:
            if keyparsers[new_mode].passthrough:
                self._set_mode_text(new_mode.name)
            else:
                self.txt.set_text(self.txt.Text.normal, '')
        if old_mode in (usertypes.KeyMode.insert,
                        usertypes.KeyMode.command,
                        usertypes.KeyMode.caret):
            self.set_mode_active(old_mode, False)

    @config.change_filter('ui', 'message-timeout')
    def set_pop_timer_interval(self):
        """Update message timeout when config changed."""
        self._text_pop_timer.setInterval(config.get('ui', 'message-timeout'))

    def resizeEvent(self, e):
        """Extend resizeEvent of QWidget to emit a resized signal afterwards.

        Args:
            e: The QResizeEvent.
        """
        super().resizeEvent(e)
        self.resized.emit(self.geometry())

    def moveEvent(self, e):
        """Extend moveEvent of QWidget to emit a moved signal afterwards.

        Args:
            e: The QMoveEvent.
        """
        super().moveEvent(e)
        self.moved.emit(e.pos())

    def minimumSizeHint(self):
        """Set the minimum height to the text height plus some padding."""
        padding = config.get('ui', 'statusbar-padding')
        width = super().minimumSizeHint().width()
        height = self.fontMetrics().height() + padding.top + padding.bottom
        return QSize(width, height)
Beispiel #30
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
Beispiel #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)
Beispiel #32
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
Beispiel #33
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()
Beispiel #34
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
Beispiel #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()
Beispiel #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()))