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))
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()
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)
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
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)
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()
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())
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
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
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())
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())
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)
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
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()
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())
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())
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)
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
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("请选择要传送的文件")
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)
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'
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)
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)
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)))
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())
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
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)
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
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()
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
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()
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()))