class VMWidget(QWidget): def __init__(self,parent = None): super(VMWidget,self).__init__(parent) #self.setStyleSheet("QToolTip{background-color:white;color:black;font-size:12px;}") #self.setFont(QFont(u"微软雅黑",12)) self.vmInfoList = [] self.oldVmInfoList = [] self.vmOffInfoList = [] self.threadMap = {} self.processMap = {} self.parent = parent self.domainManager = DomainManager() self.progressMonitor = ProgressThread() self.vmstatusTimer = QTimer() #self.vmstatusTimer.start(7000) self.connect(self.vmstatusTimer, SIGNAL("timeout()"),self.postStatusToServer) self.startVmInfo = None if common.SCROLL_TYPE != "slider": self.scrollArea = QScrollArea(self) self.scrollArea.setStyleSheet("background-color:transparent;border:0px") self.vmButtonList = [] self.vmTableWidget = QTableWidget() self.setTableWidgetStyle() self.mainLayout = QVBoxLayout() self.mainLayout.setMargin(0) self.mainLayout.setSpacing(0) self.mainLayout.addWidget(self.scrollArea) self.mainLayout.addSpacing(10) self.setLayout(self.mainLayout) self.downloadingList = [] if common.SCROLL_TYPE == "slider": #三个自定义button,用于显示相应的虚拟机 self.firstVM = CustomVMButton(self) self.secondVM = CustomVMButton(self) self.thirdVM = CustomVMButton(self) self.vmButtonList = [self.firstVM, self.secondVM, self.thirdVM] for i in range(len(self.vmButtonList)): self.vmButtonList[i].setIcon(QIcon("images/windows.png")) self.vmButtonList[i].setIconSize(QSize(100,100)) self.vmButtonList[i].setFlat(True) self.vmButtonList[i].setFont(QFont("Times", 15, QFont.Bold)) #设置滑动条的样式 self.slider = QSlider(Qt.Vertical,self) self.slider.setStyleSheet( "QSlider::groove:vertical { " "border: 1px solid #4A708B; " "background: #C0C0C0; " "width: 5px; " "border-radius: 1px; " "padding-left:-1px; " "padding-right:-1px; " "padding-top:-1px; " "padding-bottom:-1px; " "}" "QSlider::handle:vertical {" "height: 100px;" "background: white;" "margin: 0 -4px;" "}" ) self.btnLayout = QHBoxLayout(self) self.btnLayout.addStretch() self.btnLayout.addWidget(self.firstVM) self.btnLayout.addWidget(self.secondVM) self.btnLayout.addWidget(self.thirdVM) self.btnLayout.addStretch() self.btnLayout.addSpacing(10) self.btnLayout.addWidget(self.slider) self.btnLayout.setSpacing(10) self.btnLayout.setMargin(10) self.setLayout(self.btnLayout) def setTableWidgetStyle(self): #self.vmTableWidget.setColumnCount(3) #self.vmTableWidget.setRowCount(1) self.vmTableWidget.setFrameShape(QFrame.NoFrame) self.vmTableWidget.setEditTriggers(QTableWidget.NoEditTriggers)#不能编辑 self.vmTableWidget.setSelectionMode(QAbstractItemView.NoSelection) self.vmTableWidget.verticalHeader().setVisible(False)#设置垂直头不可见 self.vmTableWidget.horizontalHeader().setVisible(False)#设置垂直头不可见 self.vmTableWidget.setShowGrid(False) self.vmTableWidget.setFocusPolicy(Qt.NoFocus) self.vmTableWidget.setStyleSheet("QTableWidget{background-color: rgb(235, 235, 235,0);}") def getVmList(self): vmList = [] vmInfo = {} vmInfo["name"] = "15615123021654541" vmInfo["status"] = "offline" vmInfo["name"] = "offline" vmInfo["os_distro"] = "windows_7" vmInfo1 = {} vmInfo1["name"] = "1561545421654541" vmInfo1["status"] = "offline" vmInfo1["name"] = "offline" vmInfo2 = {} vmInfo2["name"] = "1561afew21654541" vmInfo2["status"] = "offline" vmInfo2["name"] = "windows_7" vmInfo3 = {} vmInfo3["name"] = "afewfdsafewfa" vmInfo3["status"] = "offline" vmInfo3["name"] = "windows_7" vmList.append(vmInfo) vmList.append(vmInfo1) vmList.append(vmInfo2) vmList.append(vmInfo3) vmList.append(vmInfo1) vmList.append(vmInfo2) vmList.append(vmInfo3) return vmList def postStatusToServer(self): '''serverState = VMInfoManager.instance().getCurCloudServerState() if serverState != "enable": return''' postInfo = {} state = self.domainManager.getStatus() if self.vmOffInfoList == [] or len(self.downloadingList) != 0: #self.processMap.clear() #self.threadMap.clear() return if len(state) == 0: postInfo["state"] = "shutdown" postInfo["vmname"] = self.vmOffInfoList[0]["vmname"] else: for item in state: postInfo["state"] = "running" if state[item].has_key("disk_io"): postInfo["io_throughput"] = state[item]["disk_io"] if state[item].has_key("max_disk_io"): postInfo["io_throughput_peak"] = state[item]["max_disk_io"] if state[item].has_key("net_io"): postInfo["net_throughput"] = state[item]["net_io"] if state[item].has_key("max_net_io"): postInfo["net_throughput_peak"] = state[item]["max_net_io"] if state[item].has_key("memory_size"): postInfo["memory"] = state[item]["memory_size"]*1024 if state[item].has_key("vmname"): postInfo["vmname"] = state[item]["vmname"] if state[item].has_key("name"): postInfo["coursename"] = state[item]["name"] if state[item].has_key("cpu"): postInfo["cpu_utilization"] = state[item]["cpu"] self.emit(SIGNAL("vmstateinfo"),postInfo) def showVmList(self): subWidget = QWidget() if self.vmstatusTimer.isActive(): pass else: #if globalvariable.CLASS_STATUS: self.vmstatusTimer.start(7000) #self.connect(self.vmstatusTimer, SIGNAL("timeout()"),self.postStatusToServer) if self.scrollArea.widget(): self.scrollArea.takeWidget() self.vmTableWidget = QTableWidget() self.setTableWidgetStyle() #if self.vmTableWidget self.vmTableWidget.clear() #self.vmInfoList = self.getVmList() num = len(self.vmInfoList) columnCount = 1 rowCount = 1 if num == 0: return if num <=3: #self.scrollArea.verticalScrollBar().hide() rowCount = 1 if num == 1: columnCount = 1 elif num == 2: columnCount = 2 elif num == 3: columnCount = 3 else: rowCount = num/3 rest = num%3 if (rowCount == 2 and rest == 0) or rowCount == 1 : pass if rest > 0: rowCount+=1 columnCount = 3 parentWidth = self.parent.width() resolutionValue = StoreInfoParser.instance().getResolutionValue() if resolutionValue: if len(resolutionValue.split("x")) >= 2: parentWidth = int(resolutionValue.split("x")[0])*5/9.0 ratio = parentWidth/800.0 tableWidth = (parentWidth - 20*2 -50*2*ratio)/3 + 5 if len(self.vmInfoList) > 3: tableWidth = (parentWidth - 20*2 -50*2*ratio)/3 - 20*(1 - ratio) + 5 self.vmTableWidget.setColumnCount(columnCount) self.vmTableWidget.setRowCount(rowCount) self.vmTableWidget.setFixedWidth(parentWidth-100) self.vmTableWidget.setFixedHeight((tableWidth+10)*rowCount) self.vmTableWidget.verticalHeader().setDefaultSectionSize(tableWidth+10) self.vmTableWidget.horizontalHeader().setDefaultSectionSize((parentWidth-100)/columnCount) #self.setWidget("status") if columnCount <= 3 and rowCount == 1: for i in range(columnCount): self.setRowColumnWidget(0,i,self.vmInfoList[i]["name"]) else: for i in range(rowCount): for j in range(3): if i*3 + j <= num-1: self.setRowColumnWidget(i, j, self.vmInfoList[i*3+j]["name"]) mainLayout = QHBoxLayout() mainLayout.setMargin(0) mainLayout.addWidget(self.vmTableWidget) subWidget.setLayout(mainLayout) #if self.scrollArea.widget(): #self.scrollArea.takeWidget() self.scrollArea.setWidget(subWidget) self.scrollArea.setWidgetResizable(True) #self.scrollArea.horizontalScrollBar().hide() def setRowColumnWidget(self,row,column,vmid): status = "sfw" #self.vmTableWidget.clear() mainWidget = QWidget() #self.vmTableWidget.hideColumn() #vmRowButtonList = [] parentWidth = self.parent.width() resolutionValue = StoreInfoParser.instance().getResolutionValue() if resolutionValue: if len(resolutionValue.split("x")) >= 2: parentWidth = int(resolutionValue.split("x")[0])*5/9.0 ratio = parentWidth/800.0 vmWidth = (parentWidth - 20*2 -50*2*ratio)/3 if len(self.vmInfoList) > 3: vmWidth = (parentWidth - 20*2 -50*2*ratio)/3 - 20*(1 - ratio) vmButton = CustomVMButton() vmButton.setFixedSize(QSize(vmWidth, vmWidth + 5)) vmButton.setIconSize(QSize(vmWidth - 60*ratio,vmWidth - 30*ratio)) vmButton.setText(self.vmInfoList[row*3 + column]["name"]) vmButton.setFlat(True) vmButton.setFont(QFont("Times", 15, QFont.Bold)) vmInfo = self.vmInfoList[row*3 + column] vmButton.setVMInfo(vmInfo) imageName = "other.png" if self.vmInfoList[row*3 + column].has_key("os_distro"): if common.imageMap.has_key(self.vmInfoList[row*3 + column]["os_distro"]): imageName = common.imageMap[self.vmInfoList[row*3 + column]["os_distro"]] else: LogRecord.instance().logger.info(u'common.imageMap中未找到键值%s' % self.vmInfoList[row*3 + column]["os_distro"]) vmButton.setIcon(QIcon("images/systemImage/%s" % imageName)) # if globalvariable.CLASS_STATUS and not globalvariable.TICHU_STATUS: # self.connect(vmButton, SIGNAL("clicked()"),self.slotOpenVMLesson) # self.connect(vmButton, SIGNAL("controlvm"),self.slotControlVM) # else: # self.connect(vmButton, SIGNAL("clicked()"),self.slotCreateVMLesson) #vmRowButtonList.append(vmButton) self.vmButtonList.append(vmButton) #firMybutton.setStatus("undownload") vmButton.setObjectName(vmid + ":" + QString.number(row) + ":" + QString.number(column)) self.connect(vmButton, SIGNAL("clicked()"),self.startDomain) progressBar = WidgetProgress() progressBar.setFixedSize(vmWidth, vmWidth + 5) #progressBar.progressBar.setValue(0) progressBar.setVmName(self.vmInfoList[row*3 + column]["name"]) progressBar.setObjectName(vmid + ":" + QString.number(row) + ":" + QString.number(column)) #progressBar.objectName() #self.firMybutton.setText(self.tr("确萨")) #progressBar = QProgressBar() myLayout = QHBoxLayout() myLayout.setMargin(0) myLayout.addStretch() myLayout.addWidget(vmButton) myLayout.addWidget(progressBar) myLayout.addStretch() if vmid in self.downloadingList: vmButton.hide() else: progressBar.hide() #firMybutton.hide() mainWidget.setLayout(myLayout) self.vmTableWidget.setCellWidget(row, column, mainWidget) #self.mainLayout.addWidget(mainWidget) def setVMInfoList(self, vmInfoList, vmOffInfoList): self.oldVmInfoList = LocalImgManager.instance().getCompleteList() self.vmInfoList = vmInfoList self.vmOffInfoList = vmOffInfoList self.domainManager.deleteImgList(vmOffInfoList) # needDeleteList = self.compareDelete(self.oldVmInfoList, vmOffInfoList) if self.vmOffInfoList == []: #self.progressMonitor.stop() #self.threadMap.clear() for item in self.processMap: self.processMap[item].stop() if self.processMap[item].isRunning(): self.processMap[item].exit() for item in self.threadMap: if self.threadMap[item].isRunning(): self.threadMap[item].exit() self.processMap.clear() self.threadMap.clear() #self.killRsyncThread() # if len(needDeleteList) == 0: # return # else: # self.domainManager.deleteImgList(needDeleteList) def stopAllDownload(self): for item in self.processMap: self.processMap[item].stop() if self.processMap[item].isRunning(): self.processMap[item].exit() self.killScpThread() for item in self.threadMap: #self.threadMap[item].stop() if self.threadMap[item].isRunning(): self.threadMap[item].exit() self.downloadingList = [] self.processMap.clear() self.threadMap.clear() def killScpThread(self): pidList = self.getScpsProcessId() #sshPidList = self.getSshProcessId() for item in pidList: self.killVmId(item) '''for mtem in sshPidList: self.killVmId(mtem)''' def killVmId(self,killid): cmd = "kill -9 " + killid os.system(str(cmd)) def getScpsProcessId(self):#得到运行虚拟机的进程号序列,可用于关闭某个虚拟机 idList = [] cmd = "ps aux | grep scp" output = "" statusOutput = [] statusOutput = commands.getstatusoutput(cmd) if statusOutput[0] == 0: output = statusOutput[1] else: output = "" result = output.split("\n") for i in range(len(result)): if QString(result[i]).contains("scp"): idList.append(QString(result[i]).simplified().split(" ")[1]) return idList def getSshProcessId(self):#得到运行虚拟机的进程号序列,可用于关闭某个虚拟机 idList = [] cmd = "ps aux | grep /usr/bin/ssh" output = "" statusOutput = [] statusOutput = commands.getstatusoutput(cmd) if statusOutput[0] == 0: output = statusOutput[1] else: output = "" result = output.split("\n") for i in range(len(result)): if QString(result[i]).contains("/usr/bin/ssh"): idList.append(QString(result[i]).simplified().split(" ")[1]) return idList def compareDelete(self,oldList,newList): nameList = [] deleteList = [] for item in newList: nameList.append(item["name"]) for name in oldList: if name not in nameList: deleteList.append(name) return deleteList def autoStartDownload(self): #return num = len(self.vmInfoList) if num == 0: return else: #self.progressMonitor.setVmInfoList(self.vmInfoList) #self.progressMonitor.start() #self.connect(self.progressMonitor, SIGNAL("downloadover"),self.slotDownloadOver) imgMap = LocalImgManager.instance().getCompliteListSize() for i in range(len(self.vmInfoList)): mark = 0 for item in imgMap: if item == self.vmInfoList[i]["name"] and imgMap[item] == self.vmInfoList[i]["img_file_size"]: mark = 1 if mark == 1: continue row = i/3 column = i%3 self.downloadingList.append(self.vmInfoList[i]["name"]) # self.downloadThread = DownloadThread() # self.progressThread = ProgressThread() threadid = self.vmInfoList[i]["name"] + ":" + QString.number(row) + ":" + QString.number(column) # self.downloadThread.setProcessId(threadid + ":" + QString.number(self.vmInfoList[i]["img_file_size"])) # self.progressThread.setProcessId(threadid + ":" + QString.number(self.vmInfoList[i]["img_file_size"])) # self.connect(self.progressThread, SIGNAL("currentprogress"),self.updateProgressBar) # self.connect(self.progressThread, SIGNAL("downloadover"),self.slotDownloadOver) # self.downloadThread.start() # self.progressThread.start() self.setRowColumnWidget(int(row), int(column), self.vmInfoList[i]["name"]) self.createThread(threadid,self.vmInfoList[i]) #time.sleep(1) #return self.startFirstThread() def startFirstThread(self): for item in self.threadMap: self.threadMap[item].start() self.processMap[item].start() self.connect(self.processMap[item], SIGNAL("currentprogress"),self.updateProgressBar) #self.connect(self.processMap[item], SIGNAL("downloadover"),self.slotDownloadOver) self.connect(self.threadMap[item], SIGNAL("downloadover"),self.slotDownloadOver) self.connect(self.threadMap[item], SIGNAL("downloaderror"),self.slotDownloadError) return def slotDownloadError(self,signalid): pass def createThread(self,threadid,vmInfo): if self.threadMap.has_key(threadid): if self.threadMap[threadid].isRunning(): self.threadMap[threadid].exit() self.threadMap.pop(threadid) if self.processMap.has_key(threadid): if self.processMap[threadid].isRunning(): self.processMap[threadid].exit() self.processMap.pop(threadid) downloadThread = DownloadThread() progressThread = ProgressThread() self.threadMap[threadid] = downloadThread self.processMap[threadid] = progressThread self.threadMap[threadid].setProcessId(threadid + ":" + str(vmInfo["img_file_size"])) self.processMap[threadid].setProcessId(threadid + ":" + str(vmInfo["img_file_size"])) #self.threadMap[threadid].start() #self.processMap[threadid].start() #self.connect(self.processMap[threadid], SIGNAL("currentprogress"),self.updateProgressBar) #self.connect(self.processMap[threadid], SIGNAL("downloadover"),self.slotDownloadOver) def checkAddDownload(self): #return num = len(self.vmInfoList) #existImgList = LocalImgManager.instance().getCompleteList() existImgList = LocalImgManager.instance().getCompliteListSize() if num == 0: return else: count = 0 for i in range(len(self.vmInfoList)): row = i/3 column = i%3 if existImgList.has_key(self.vmInfoList[i]["name"]) and existImgList.get(self.vmInfoList[i]["name"]) == self.vmInfoList[i]["img_file_size"]: pass elif self.vmInfoList[i]["name"] in self.downloadingList: pass elif existImgList.has_key(self.vmInfoList[i]["name"]) and self.domainManager.getDom() != None and self.startVmInfo != None and self.startVmInfo == self.domainManager.getDomainInfo(): pass else: if self.vmInfoList[i]["name"] not in self.downloadingList: self.downloadingList.append(self.vmInfoList[i]["name"]) threadid = self.vmInfoList[i]["name"] + ":" + QString.number(row) + ":" + QString.number(column) self.createThread(threadid, self.vmInfoList[i]) self.setRowColumnWidget(int(row), int(column), self.vmInfoList[i]["name"]) count+= 1 if len(self.threadMap) == count: self.startFirstThread() if count > 0: self.emit(SIGNAL("startadddownload")) def startDomain(self): pbp = CustomVMButton().sender() buttonName = pbp.objectName() vmInfo = pbp.vmInfo for item in self.vmOffInfoList: if item["name"] == vmInfo["name"]: self.startVmInfo = item #return vmid = buttonName.split(":")[0] row = buttonName.split(":")[1] column = buttonName.split(":")[2] self.domainManager.setDomainInfo(self.startVmInfo) LogRecord.instance().logger.info(u"开始开启虚拟机-----------------------------------------------00") self.domainManager.startDomainByName() LogRecord.instance().logger.info(u"结束开启虚拟机-----------------------------------------------11") def updateProgressBar(self,count,objectname): #if self.threadMap[objectname].isRunning(): # for i in range(len(self.downloadingList)): # if objectname == self.downloadingList[i]: # progress=self.vmTableWidget.findChild((WidgetProgress, ),objectname) # progress.progressBar.setValue(count) progress=self.vmTableWidget.findChild((WidgetProgress, ),objectname) if not progress: return progress.progressBar.setValue(count) def slotDownloadOver(self,count,name): serverState = VMInfoManager.instance().getCurCloudServerState() if serverState != "enable": return if self.processMap.has_key(name): self.processMap[name].stop() #self.processMap.pop(name) #self.threadMap.pop(name) vmid = name.split(":")[0] row = name.split(":")[1] column = name.split(":")[2] self.downloadingList = [] self.setRowColumnWidget(int(row), int(column), vmid) time.sleep(4) if self.processMap.has_key(name) and self.processMap[name].isRunning: self.processMap[name].exit() if self.threadMap.has_key(name) and self.threadMap[name].isRunning: self.threadMap[name].exit() self.processMap.pop(name) self.threadMap.pop(name) self.emit(SIGNAL("avmdownloadover")) # for item in self.threadMap: # self.threadMap[item].start() # self.processMap[item].start() # self.connect(self.processMap[item], SIGNAL("currentprogress"),self.updateProgressBar) # self.connect(self.processMap[item], SIGNAL("downloadover"),self.slotDownloadOver) # return def getDownloadingList(self): return self.downloadingList def updateVMList(self): language = StoreInfoParser.instance().getLanguage() m_pTranslator = QTranslator() exePath = "./" if language == "chinese": QmName = "zh_CN.qm" StoreInfoParser.instance().setLanguage("chinese") else: QmName = "en_US.qm" if(m_pTranslator.load(QmName, exePath)): QCoreApplication.instance().installTranslator(m_pTranslator) if self.vmstatusTimer.isActive(): self.vmstatusTimer.stop() else: pass subWidget = QWidget() vmNum = len(self.vmInfoList) rowNum = 0 subMainLayout = QVBoxLayout() subMainLayout.setMargin(0) #subMainLayout.addStretch() #subMainLayout.addSpacing(10) #subMainLayout.setSpacing(10) self.vmButtonList = [] if vmNum % 3 != 0: rowNum = vmNum / 3 + 1 else: rowNum = vmNum / 3 for i in range(rowNum): indexEnd = 3 if i == rowNum - 1: indexEnd = vmNum - (i*3) parentWidth = self.parent.width() resolutionValue = StoreInfoParser.instance().getResolutionValue() if resolutionValue: if len(resolutionValue.split("x")) >= 2: parentWidth = int(resolutionValue.split("x")[0])*5/9.0 ratio = parentWidth/800.0 vmWidth = (parentWidth - 20*2 -50*2*ratio)/3 if vmNum > 3: vmWidth = (parentWidth - 20*2 -50*2*ratio)/3 - 20*(1 - ratio) vmRowButtonList = [] for j in range(indexEnd): vmButton = CustomVMButton(self) vmButton.setFixedSize(QSize(vmWidth, vmWidth + 5)) vmButton.setIconSize(QSize(vmWidth - 60*ratio,vmWidth - 30*ratio)) vmButton.setText(self.vmInfoList[i*3 + j]["name"]) vmButton.setToolTip(self.tr("course: ") + self.vmInfoList[i*3 + j]["name"]) vmButton.setStyleSheet(u"QToolTip{border-radius:5px;background-color:white;color:black;font-size:20px;font-family:微软雅黑;}") vmButton.setFlat(True) vmButton.setFont(QFont("Times", 15, QFont.Bold)) vmInfo = self.vmInfoList[i*3 + j] vmButton.setVMInfo(vmInfo) imageName = "other.png" if self.vmInfoList[i*3 + j].has_key("os_distro"): if common.imageMap.has_key(self.vmInfoList[i*3 + j]["os_distro"]): imageName = common.imageMap[self.vmInfoList[i*3 + j]["os_distro"]] else: LogRecord.instance().logger.info(u'common.imageMap中未找到键值%s' % self.vmInfoList[i*3 + j]["os_distro"]) vmButton.setIcon(QIcon("images/systemImage/%s" % imageName)) if globalvariable.CLASS_STATUS and not globalvariable.TICHU_STATUS: self.connect(vmButton, SIGNAL("clicked()"),self.slotOpenVMLesson) self.connect(vmButton, SIGNAL("controlvm"),self.slotControlVM) else: self.connect(vmButton, SIGNAL("clicked()"),self.slotCreateVMLesson) vmRowButtonList.append(vmButton) self.vmButtonList.append(vmButton) btnLayout = QHBoxLayout() if vmNum > 3: btnLayout.setSpacing(10) #btnLayout.setMargin(10) btnLayout.addSpacing(30) for vmbtn in vmRowButtonList: btnLayout.addWidget(vmbtn) btnLayout.addStretch() subMainLayout.addLayout(btnLayout) #subMainLayout.addStretch() subWidget.setLayout(subMainLayout) if self.scrollArea.widget(): self.scrollArea.takeWidget() self.scrollArea.setWidgetResizable(False) self.scrollArea.setWidget(subWidget) def startVM(self): return def autoOpenVMLesson(self, vmName, allflag = False): LogRecord.instance().logger.info(u'自动打开相应的虚拟机') if self.vmButtonList: vmInfo = self.vmButtonList[0].getVMInfo() VMOperation.instance().setCurrentVMInfo(vmInfo) #thread.start_new_thread(VMOperation.instance().openVM,()) if allflag == True: if VMOperation.instance().openVM(): LogRecord.instance().logger.info(u'start the lesson') else: if VMOperation.instance().openVM(): LogRecord.instance().logger.info(u'start the lesson') else: LogRecord.instance().logger.info(u'未监测到虚拟机%s的信息' % vmName) def autoOpenOffVMLesson(self): LogRecord.instance().logger.info(u'自动打开相应的虚拟机') if len(self.vmInfoList) == 1: if self.vmInfoList[0]["name"] in self.downloadingList: return else: self.startVmInfo = self.vmInfoList[0] self.domainManager.setDomainInfo(self.startVmInfo) self.domainManager.startDomainByName() else: return def checkDownloadOver(self): if self.autoCourse in self.downloadingList: pass else: self.courseTimer.stop() #self.autoCourse = "" for item in self.vmOffInfoList: if self.autoCourse == item["name"]: vmInfo = item self.domainManager.setDomainInfo(vmInfo) self.domainManager.startDomainByName() return def autoOpenCourse(self,name,classid = None): LogRecord.instance().logger.info(u'自动打开相应的虚拟机') self.autoCourse = name if name in self.downloadingList: self.courseTimer = QTimer() self.courseTimer.start(1000) self.connect(self.courseTimer, SIGNAL("timeout()"),self.checkDownloadOver) else: for item in self.vmOffInfoList: if name == item["name"]: vmInfo = item if classid != None: vmInfo["classid"] = classid self.domainManager.setDomainInfo(vmInfo) self.domainManager.startDomainByName() return def slotCreateVMLesson(self): vmBtn = self.sender() if vmBtn: LogRecord.instance().logger.info(u'开始创建虚拟机') if globalvariable.VM_IS_CREATE_STATUS: LogRecord.instance().logger.info(u'重复点击!') return else: globalvariable.VM_IS_CREATE_STATUS = True LogRecord.instance().logger.info(u'准备获取虚拟机信息!') paramInfo = vmBtn.getVMInfo() LogRecord.instance().logger.info(u'准备获取虚拟机信息完成!') try: vmName = VMOperation.instance().createVMLesson(paramInfo) except: LogRecord.instance().logger.info(u'创建虚拟机异常.........!') LogRecord.instance().logger.info(u'得到创建的虚拟机信息!') if vmName: LogRecord.instance().logger.info(u'创建虚拟机%s成功' % vmName) vmInfo = NetworkManager.instance().getVMInfo(vmName) if vmInfo == None: globalvariable.VM_IS_CREATE_STATUS = False return if len(vmInfo) == 0: globalvariable.VM_IS_CREATE_STATUS = False return vmInfo[0]["vmname"] = vmInfo[0]["name"] if vmInfo: VMOperation.instance().setCurrentVMInfo(vmInfo[0]) if VMOperation.instance().openVM(True): #保存开启虚拟机的名称 #globalvariable.VM_IS_CREATE_STATUS = False WindowMonitor.instance().insertVmId(vmName) else: globalvariable.VM_IS_CREATE_STATUS = False #删除没有成功运行的虚拟机 if VMOperation.instance().removeVMLesson(vmName): LogRecord.instance().logger.info(u"删除后台相应的虚拟机成功") else: LogRecord.instance().logger.info(u'未查询到相应的虚拟机:%s' % vmName) globalvariable.VM_IS_CREATE_STATUS = False else: LogRecord.instance().logger.info(u'创建虚拟机失败') globalvariable.VM_IS_CREATE_STATUS = False #刷新虚拟机界面 self.emit(SIGNAL("refreshVMS")) def slotControlVM(self, action): vmBtn = self.sender() if vmBtn: vmInfo = vmBtn.getVMInfo() VMOperation.instance().setCurrentVMInfo(vmInfo) VMOperation.instance().controlVM(action) vmInfos = globalvariable.VM_INFO self.setVMInfoList(vmInfos,[]) self.updateVMList() def slotOpenVMLesson(self): #vmInfo = [] vmBtn = self.sender() if vmBtn: btnVMInfo = vmBtn.getVMInfo() VMOperation.instance().setCurrentVMInfo(btnVMInfo) VMOperation.instance().openVM(True) # if globalvariable.CLASS_STATUS: # vmInfo = globalvariable.VM_INFO # else: # vmInfo = VMInfoManager.instance().getLessonListInfo() # #self.setVMInfoList(vmInfo,[]) #self.updateVMList() #slider def setSliderMaxValue(self, value): """设在滑动条的最大值""" maxValue = 1 if value % 3 == 0: maxValue = (value / 3) else: maxValue = (value / 3 + 1) maxValue = maxValue - 1 self.slider.setMinimum(1) self.slider.setMaximum(maxValue*3) self.slider.setValue(self.slider.maximum()) self.currentIndex = maxValue self.maxValue = maxValue self.updateVMList() def paintEvent(self,event): if common.SCROLL_TYPE == "slider": self.setNodeSize(QSize(self.geometry().width()*4/15,self.geometry().height()*4/9)) elif len(self.vmInfoList) <= 6: subWidget = self.scrollArea.widget() if subWidget != None: if len(self.vmInfoList) <= 3: subWidget.move((self.geometry().width() - subWidget.width())/2, (self.geometry().height() - subWidget.height())/2 - 20) else: subWidget.move((self.geometry().width() - subWidget.width())/2 - 15, (self.geometry().height() - subWidget.height())/2) QWidget.paintEvent(self, event) #slider def setNodeSize(self,size): self.btnLayout.setSpacing(size.width()/20) self.btnLayout.setMargin(size.width()*3/20) self.firstVM.setIconSize(size) self.secondVM.setIconSize(size) self.thirdVM.setIconSize(size) self.slider.resize(QSize(self.slider.frameGeometry().width(),self.height()-100)) def wheelEvent(self,event): """鼠标滚轮滚动事件,显示对应的虚拟机""" if common.SCROLL_TYPE == "slider": if event.delta() < 0 and self.currentIndex > 0: self.currentIndex -= 1 self.updateVMListSlider() elif event.delta() > 0 and self.currentIndex < self.maxValue: self.currentIndex += 1 self.updateVMListSlider() self.slider.wheelEvent(event) else: maxValue = self.scrollArea.verticalScrollBar().maximum() minValue = self.scrollArea.verticalScrollBar().minimum() currentValue = self.scrollArea.verticalScrollBar().value() if event.delta() < 0 and currentValue < maxValue: self.scrollArea.wheelEvent(event) elif event.delta() > 0 and currentValue > minValue: self.scrollArea.wheelEvent(event) #slider def updateVMListSlider(self): """更新虚拟机列表""" for i in range(len(self.vmButtonList)): self.vmButtonList[i].hide() vmsInfoList = VMInfoManager.instance().getVMSInfo() if vmsInfoList: self.slider.show() startIndex = (self.maxValue - self.currentIndex) * 3 if startIndex/3 == (self.maxValue): endIndex = len(vmsInfoList) else: endIndex = startIndex + 3 for i in range(startIndex, endIndex): self.vmButtonList[i - startIndex].setText(vmsInfoList[i]) self.vmButtonList[i - startIndex].show() else: self.slider.hide() """ echo <graphics type='sdl display='$DISPLAY' xauth='$XAUTHORITY'/>
class K800IRec(QWidget, mfso): def __init__(self): mfso.__init__(self, "K800i-Recover") self.name = "K800i-Recover" self.icon = None self.__disown__() def start(self, args): self.vfs = vfs.vfs() self.dumpnumber = 1 try : self.nor = args['nor'].value() self.nand = args['nand'].value() except IndexError: return try: self.spareSize = args["spare-size"].value() except IndexError: self.spareSize = 16 try: self.pageSize = args["page-size"].value() except IndexError: self.pageSize = 512 self.k800n = Node("k800-base") self.k800n.__disown__() self.boot = SEBootBlock(self.nor, self.pageSize) self.blockSize = self.boot.blockSize self.nandClean = SpareNode(self, self.nand, "nandfs", self.pageSize, self.spareSize, self.k800n) self.norFs = NorFs(self, self.k800n, self.nor, "norfs", self.boot) self.fullFs = FullFs(self, self.k800n, self.norFs, self.nandClean, "fullfs", self.boot) self.gdfs = GDFS(self, self.k800n, self.nor, "gdfs", self.boot) self.firmware = Firmware(self, self.k800n, self.nor, "firmware", self.boot.norfsoffset) self.tables = Tables(self.fullFs, self.blockSize) self.registerTree(self.nand, self.k800n) def createDump(self): text, ok = QInputDialog.getText(self, "Create dump", "dump name:", QLineEdit.Normal, "k800-restore-" + str(self.dumpnumber)) if ok and text != "": if (self.vfs.getnode(self.nand.absolute() + "/" + str(text)) == None): self.dumpnumber += 1 newroot = Node(str(text)) newroot.__disown__() for id in range(0, len(self.tables.tablesIdWriteMap) - 1): write = int(str(self.gtable.cellWidget(id, 0).currentText()), 16) self.tables.map[id] = self.tables.tablesIdWriteMap[id][write] virtual = VirtualMap(self, newroot, self.fullFs, self.tables, "virtual", self.blockSize) separt = SEPartitionBlock(virtual, self.boot.partitionblock, self.blockSize) self.createPart(separt, newroot, virtual) self.registerTree(self.nand, newroot) else : box = QMessageBox(QMessageBox.Warning, "Error", "Error node already exists", QMessageBox.NoButton, self) box.exec_() self.createDump() def createPart(self, separt, newroot, virtual): for part in separt.partTable: if part.start > 0: p = Partition(self, newroot, virtual, part, self.blockSize) def g_display(self): QWidget.__init__(self, None) self.layout = QVBoxLayout(self) self.hlayout = QSplitter(self) self.layout.insertWidget(0, self.hlayout) self.layout.setStretchFactor(self.hlayout, 1) self.gTable() self.viewTable() self.button = QPushButton("&Create dump") self.connect(self.button, SIGNAL("clicked()"), self.createDump) self.layout.addWidget(self.button) def viewTable(self): self.vtable = QTableWidget() self.vtable.setColumnCount(20) self.vtable.setRowCount(48) self.hlayout.addWidget(self.vtable) def viewTableUpdate(self, id): write = int(str(self.gtable.cellWidget(id, 0).currentText()), 16) t = self.tables.tablesIdWriteMap[id][write] l = t.blockList for x in xrange(0, len(t.blockList[0])): block = t.blockList[0][x] c = ((x) % 20) r = ((x) / 20) item = QTableWidgetItem(QString(hex(block))) tipBlock = (id * 960) + x item.setToolTip(QString(hex(tipBlock))) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.vtable.setItem(r ,c, item) def gTable(self): self.gtable = QTableWidget() self.gtable.setColumnCount(1) self.gtable.setRowCount(len(self.tables.tablesIdWriteMap)) self.gtable.setHorizontalHeaderItem(0, QTableWidgetItem(QString("version"))) self.hlayout.addWidget(self.gtable) self.sigMapper = QSignalMapper(self) for id in self.tables.tablesIdWriteMap: wlist = self.tables.tablesIdWriteMap[id] cbox = QComboBox(self.gtable) self.connect(cbox, SIGNAL("activated(QString)"), self.sigMapper, SLOT("map()")) self.sigMapper.setMapping(cbox, id) l = [] for write in wlist: l.append(write) l.sort() l.reverse() for write in l: cbox.addItem(QString(hex(write))) self.gtable.setCellWidget(id, 0, cbox) self.gtable.setVerticalHeaderItem(id, QTableWidgetItem(QString(hex(id)))) self.connect(self.sigMapper, SIGNAL("mapped(int)"), self.viewTableUpdate) self.gtable.setMaximumWidth(self.gtable.columnWidth(0) + self.gtable.verticalHeader().sectionSize(0) + 30) def updateWidget(self): pass
class PvTunerDlg(QDialog): COL = 6 COL_ELEMENT = 0 COL_FIELD = 1 COL_PV = 2 COL_STEPSIZE = 3 COL_READBACK = 4 COL_SETPOINT = 5 FMT_READBACK = "%.4e" def __init__(self, parent=None): super(PvTunerDlg, self).__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) #self.inputBox = QLineEdit("PL2G2C01A.x") #self.inputBox = QLineEdit("CXH2G6C01B.x") self.inputBox = QLineEdit("PL2G2C01A") addPvBtn = QPushButton("add") self.table = QTableWidget(0, PvTunerDlg.COL) self.table.setHorizontalHeaderLabels( ["Element", "Field", "PV", "Stepsize", "Readback", "setpoint"]) #self.table.horizontalHeader().setStretchLastSection(True) #self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) buttonBox = QDialogButtonBox(QDialogButtonBox.Ok) box = QGridLayout() box.addWidget(self.inputBox, 0, 0) box.addWidget(addPvBtn, 0, 1) box.addWidget(self.table, 1, 0, 1, 2) box.addWidget(buttonBox, 2, 0) self.setLayout(box) self.pvs_rb = [] self.pvs_rb_val_flat = [] self.pvs_sp = [] self.pvmoni = [] self.spinbox = [] self.connect(addPvBtn, SIGNAL("clicked()"), self.addPv) self.connect(buttonBox, SIGNAL("accepted()"), self.accept) #self.connect(self.table, SIGNAL("cellChanged"), self.updatePv) self.connect(buttonBox.button(QDialogButtonBox.Ok), SIGNAL("clicked()"), self.close) self.connect(self.table, SIGNAL("cellClicked(int, int)"), self._cell_clicked) def _cell_clicked(self, row, column): #print row, column if column in [self.COL_PV, self.COL_STEPSIZE]: item = self.table.item(row, column) if not item: return item.setFlags(item.flags() | Qt.ItemIsEditable) def _appendRecord(self, name): vec = name.split('.') if len(vec) > 2: QMessageBox.critical(None, "ERROR", "format is wrong") return if len(vec) == 1: elem, field = vec[0], 'value' elif len(vec) == 2: elem, field = vec elemobj = hla.getElements(elem) if elemobj: # pvsrb is a list pvsrb = elemobj.pv(field=field, handle='readback') self.pvs_rb.append(pvsrb) pvssp = elemobj.pv(field=field, handle='setpoint') self.pvs_sp.append(pvssp) else: QMessageBox.critical(None, "ERROR", "element %s not found" % elem) return # expand one row m, n = self.table.rowCount(), self.table.columnCount() self.table.insertRow(m) # add cells item = QTableWidgetItem(elem) item.setFlags(item.flags() & (~Qt.ItemIsEditable)) self.table.setItem(m, self.COL_ELEMENT, item) item = QTableWidgetItem(field) item.setFlags(item.flags() & (~Qt.ItemIsEditable)) self.table.setItem(m, self.COL_FIELD, item) item = QTableWidgetItem(', '.join(pvsrb)) #item.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled) self.table.setItem(m, self.COL_PV, item) readval = ['%.4e' % v for v in caget(pvsrb)] item = QTableWidgetItem(', '.join(readval)) item.setFlags(item.flags() & (~Qt.ItemIsEditable)) self.table.setItem(m, self.COL_READBACK, item) # set the stepsize of PV stepsize = 0.00001 if pvssp: item = QTableWidgetItem('%f' % stepsize) item.setFlags(item.flags() & (~Qt.ItemIsEditable)) self.table.setItem(m, self.COL_STEPSIZE, item) self.spinbox.append(QDoubleSpinBox(self.table)) self.spinbox[-1].setRange(-100, 100) #self.spinbox[-1].setValue(float(10.0)) self.spinbox[-1].setSingleStep(stepsize) self.spinbox[-1].setDecimals(10) self.spinbox[-1].valueChanged.connect(self._writePv) self.table.setCellWidget(m, self.COL_SETPOINT, self.spinbox[-1]) sp = float(caget(pvssp)[0]) #print "setpoint:", pvssp, sp, type(sp) self.spinbox[-1].setValue(-1e-5) #print "connected", self.spinbox[-1].value() else: item = self.table.item(m, self.COL_STEPSIZE) if item: item.setFlags(item.flags() & (~Qt.ItemIsEditable)) item = self.table.item(m, self.COL_SETPOINT) if item: item.setFlags(item.flags() & (~Qt.ItemIsEditable)) self.spinbox.append(None) self.table.resizeColumnsToContents() def addPv(self): self._appendRecord(str(self.inputBox.text())) self._updateMonitors() def minimalSizeHint(self): return QSize(800, 600) def _writePv(self, v): """ """ c = QObject.sender(self) i = self.spinbox.index(c) #print i, c.text(), "changed" #print self.pvs_sp[i], v caput(self.pvs_sp[i], v) def _updateMonitors(self): """ prepare the PV list for camonitor """ #print "Updating monitors" pvs = [] self.pvs_rb_val = [] for i in range(self.table.rowCount()): for j in range(len(self.pvs_rb[i])): self.pvs_rb_val.append([i, 0.0]) pvs.extend(self.pvs_rb[i]) for p in self.pvmoni: p.close() self.pvmoni = camonitor(pvs, self._updatePvValues) #print self.pvmoni #print pvs #print self.pvs_rb_val def _updatePvValues(self, val, idx): #print idx, val s = [] for i, v in enumerate(self.pvs_rb_val): if v[0] == self.pvs_rb_val[idx][0]: s.append(self.FMT_READBACK % val) #print s item = self.table.item(self.pvs_rb_val[idx][0], self.COL_READBACK) item.setText(','.join(s)) def closePvMonitors(self): #print "Closing PV Monitors" for p in self.pvmoni: p.close() pass def closeEvent(self, event): self.closePvMonitors() event.accept() def close(self): self.closePvMonitors() return True
class Widget(QWidget): def __init__(self, parent=None): super(Widget, self).__init__(parent) buttonHelp1 = QPushButton('help') buttonHelp1.setEnabled(False) buttonHelp1.setToolTip('The table below, with the exception of the last row and column, describe the network\n' + 'in terms of the weight coefficient values. The value of a cell in the n-th row and m-th\n' + 'column is the weight of the n-th feature for the m-th animal class.\n\n' + 'As you can see, each animal class has its own neuron that recognizes it, and each of\n' + 'these neurons has inputs that receive individual feature values.\n\n' + 'The last column represents the input vector, and the last row contains the network\n' + 'output values.') buttonHelp2 = QPushButton('help') buttonHelp2.setEnabled(False) buttonHelp2.setToolTip('If you show the winner, you will see the neuron whose response was the strongest.\n' + 'This neuron indicates the animal class the examined object will most probably fall into.\n' + 'The table below, with the exception of the last row and column, describe the network\n' + 'in terms of the weight coefficient values. The value of a cell in the n-th row and m-th\n' + 'column is the weight of the n-th feature for the m-th animal class.\n\n' + 'As you can see, each animal class has its own neuron that recognizes it, and each of\n' + 'these neurons has inputs that receive individual feature values.\n\n' + 'The last column represents the input vector, and the last row contains the network\n' + 'output values.') hBoxLayout1 = QHBoxLayout() hBoxLayout1.addWidget(QLabel('The neural network in this example uses five features to recognize\n' + 'three classes of animals. Its weight coefficients are predefined and shown in the table below.\n\n' + 'To test the network behavior, enter the input signals in the rightmost column and read the output\n' + 'values from the bottom row.')) hBoxLayout1.addWidget(buttonHelp1) self.checkBoxWinner = QCheckBox() self.checkBoxWinner.setText('Show the winner') hBoxLayout2 = QHBoxLayout() hBoxLayout2.addWidget(self.checkBoxWinner) hBoxLayout2.addWidget(buttonHelp2) self.tableWidget = QTableWidget() self.labelNeuron = QLabel('(There is no winner.)') self.labelType = QLabel('This is something strange!') self.spinBoxThreshold = QDoubleSpinBox() self.spinBoxThreshold.setValue(5.0) self.groupBox = QGroupBox('Show the winner') gridLayout = QGridLayout() gridLayout.addWidget(QLabel('And the winner is...'), 0, 0) gridLayout.addWidget(self.labelNeuron, 0, 1) gridLayout.addWidget(QLabel('Because of this, the network claims:'), 1, 0) gridLayout.addWidget(self.labelType, 1, 1) gridLayout.addWidget(QLabel('Threshold:'), 2, 0) gridLayout.addWidget(self.spinBoxThreshold, 2, 1) self.groupBox.setLayout(gridLayout) self.groupBox.setVisible(False) vBoxLayout = QVBoxLayout() vBoxLayout.addLayout(hBoxLayout1) vBoxLayout.addWidget(self.tableWidget) vBoxLayout.addLayout(hBoxLayout2) vBoxLayout.addWidget(self.groupBox) self.setLayout(vBoxLayout) self.setWindowTitle('Simple linear neural network (example2)') self.classNames = ['mammal', 'bird', 'fish'] self.tableWidget.setColumnCount(5) self.tableWidget.setRowCount(6) self.tableWidget.verticalHeader().hide() self.tableWidget.setHorizontalHeaderLabels(['Feature'] + self.classNames + ['Input vector']) self.tableWidget.setCellWidget(0, 0, QLabel('number of legs')) self.tableWidget.setCellWidget(1, 0, QLabel('lives in water')) self.tableWidget.setCellWidget(2, 0, QLabel('can fly')) self.tableWidget.setCellWidget(3, 0, QLabel('has feathers')) self.tableWidget.setCellWidget(4, 0, QLabel('egg-laying')) self.tableWidget.setCellWidget(5, 0, QLabel('Output')) weights = [ [ 4, 0.01, 0.01, -1, -1.5 ], [ 2, -1, 2, 2.5, 2 ], [ -1, 3.5, 0.01, -2, 1.5 ] ] for i in xrange(len(weights)): for j in xrange(len(weights[i])): self.tableWidget.setCellWidget(j, i + 1, QLabel(' ' + str(weights[i][j]))) for i in xrange(len(weights)): self.tableWidget.setCellWidget(5, i + 1, QLabel('')) for i in xrange(len(weights[0])): doubleSpinBox = QDoubleSpinBox() doubleSpinBox.setValue(0.0) doubleSpinBox.setRange(-15.0, 15.0) self.tableWidget.setCellWidget(i, 4, doubleSpinBox) self.tableWidget.setCellWidget(5, 4, QPushButton('Calculate')) self.linearNetwork = LinearNetwork(initialWeights=weights) self.connect(self.checkBoxWinner, SIGNAL('stateChanged(int)'), self.visibleGrid) self.connect(self.tableWidget.cellWidget(5, 4), SIGNAL('clicked()'), self.updateResult) self.resize(600, 400) def visibleGrid(self, state): if state == 0: self.groupBox.setVisible(False) else: self.groupBox.setVisible(True) self.updateResult() def updateResult(self): inputColumn0 = self.tableWidget.cellWidget(0, 4).value() # number of legs inputColumn1 = self.tableWidget.cellWidget(1, 4).value() # lives in water inputColumn2 = self.tableWidget.cellWidget(2, 4).value() # can fly inputColumn3 = self.tableWidget.cellWidget(3, 4).value() # has feathers inputColumn4 = self.tableWidget.cellWidget(4, 4).value() # egg-laying outputVector = self.linearNetwork.response([inputColumn0, inputColumn1, inputColumn2, inputColumn3, inputColumn4]) if self.checkBoxWinner.checkState() == Qt.Checked: winner = LinearNetwork.winner(outputVector, self.spinBoxThreshold.value()) for i in xrange(len(outputVector)): self.tableWidget.setCellWidget(5, i + 1, QLabel()) if winner != -1: cellWinner = self.tableWidget.cellWidget(5, winner + 1) cellWinner.setStyleSheet('background-color: red;') self.labelNeuron.setText('Neuron ' + str(winner + 1)) self.labelType.setText('This is a ' + self.classNames[winner]) else: self.labelNeuron.setText('(There is no winner.)') self.labelType.setText('Thiss is something strange!') for i in xrange(len(outputVector)): self.tableWidget.cellWidget(5, i + 1).setText(str(outputVector[i]))
class PvTunerDlg(QDialog): COL = 6 COL_ELEMENT = 0 COL_FIELD = 1 COL_PV = 2 COL_STEPSIZE = 3 COL_READBACK = 4 COL_SETPOINT = 5 FMT_READBACK = "%.4e" def __init__(self, parent=None): super(PvTunerDlg, self).__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) #self.inputBox = QLineEdit("PL2G2C01A.x") #self.inputBox = QLineEdit("CXH2G6C01B.x") self.inputBox = QLineEdit("PL2G2C01A") addPvBtn = QPushButton("add") self.table = QTableWidget(0, PvTunerDlg.COL) self.table.setHorizontalHeaderLabels(["Element", "Field", "PV", "Stepsize", "Readback", "setpoint"]) #self.table.horizontalHeader().setStretchLastSection(True) #self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) buttonBox = QDialogButtonBox(QDialogButtonBox.Ok) box = QGridLayout() box.addWidget(self.inputBox, 0, 0) box.addWidget(addPvBtn, 0, 1) box.addWidget(self.table, 1, 0, 1, 2) box.addWidget(buttonBox, 2, 0) self.setLayout(box) self.pvs_rb = [] self.pvs_rb_val_flat = [] self.pvs_sp = [] self.pvmoni = [] self.spinbox = [] self.connect(addPvBtn, SIGNAL("clicked()"), self.addPv) self.connect(buttonBox, SIGNAL("accepted()"), self.accept) #self.connect(self.table, SIGNAL("cellChanged"), self.updatePv) self.connect(buttonBox.button(QDialogButtonBox.Ok), SIGNAL("clicked()"), self.close) self.connect(self.table, SIGNAL("cellClicked(int, int)"), self._cell_clicked) def _cell_clicked(self, row, column): #print row, column if column in [self.COL_PV, self.COL_STEPSIZE]: item = self.table.item(row, column) if not item: return item.setFlags(item.flags() | Qt.ItemIsEditable) def _appendRecord(self, name): vec = name.split('.') if len(vec) > 2: QMessageBox.critical(None, "ERROR", "format is wrong") return if len(vec) == 1: elem, field = vec[0], 'value' elif len(vec) == 2: elem, field = vec elemobj = hla.getElements(elem) if elemobj: # pvsrb is a list pvsrb = elemobj.pv(field=field, handle='readback') self.pvs_rb.append(pvsrb) pvssp = elemobj.pv(field=field, handle='setpoint') self.pvs_sp.append(pvssp) else: QMessageBox.critical(None, "ERROR", "element %s not found" % elem) return # expand one row m, n = self.table.rowCount(), self.table.columnCount() self.table.insertRow(m) # add cells item = QTableWidgetItem(elem) item.setFlags(item.flags() & (~Qt.ItemIsEditable)) self.table.setItem(m, self.COL_ELEMENT, item) item = QTableWidgetItem(field) item.setFlags(item.flags() & (~Qt.ItemIsEditable)) self.table.setItem(m, self.COL_FIELD, item) item = QTableWidgetItem(', '.join(pvsrb)) #item.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled) self.table.setItem(m, self.COL_PV, item) readval = ['%.4e' % v for v in caget(pvsrb)] item = QTableWidgetItem(', '.join(readval)) item.setFlags(item.flags() & (~Qt.ItemIsEditable)) self.table.setItem(m, self.COL_READBACK, item) # set the stepsize of PV stepsize = 0.00001 if pvssp: item = QTableWidgetItem('%f' % stepsize) item.setFlags(item.flags() & (~Qt.ItemIsEditable)) self.table.setItem(m, self.COL_STEPSIZE, item) self.spinbox.append(QDoubleSpinBox(self.table)) self.spinbox[-1].setRange(-100, 100) #self.spinbox[-1].setValue(float(10.0)) self.spinbox[-1].setSingleStep(stepsize) self.spinbox[-1].setDecimals(10) self.spinbox[-1].valueChanged.connect(self._writePv) self.table.setCellWidget(m, self.COL_SETPOINT, self.spinbox[-1]) sp = float(caget(pvssp)[0]) #print "setpoint:", pvssp, sp, type(sp) self.spinbox[-1].setValue(-1e-5) #print "connected", self.spinbox[-1].value() else: item = self.table.item(m, self.COL_STEPSIZE) if item: item.setFlags(item.flags() & (~Qt.ItemIsEditable)) item = self.table.item(m, self.COL_SETPOINT) if item: item.setFlags(item.flags() & (~Qt.ItemIsEditable)) self.spinbox.append(None) self.table.resizeColumnsToContents() def addPv(self): self._appendRecord(str(self.inputBox.text())) self._updateMonitors() def minimalSizeHint(self): return QSize(800, 600) def _writePv(self, v): """ """ c = QObject.sender(self) i = self.spinbox.index(c) #print i, c.text(), "changed" #print self.pvs_sp[i], v caput(self.pvs_sp[i], v) def _updateMonitors(self): """ prepare the PV list for camonitor """ #print "Updating monitors" pvs = [] self.pvs_rb_val = [] for i in range(self.table.rowCount()): for j in range(len(self.pvs_rb[i])): self.pvs_rb_val.append([i, 0.0]) pvs.extend(self.pvs_rb[i]) for p in self.pvmoni: p.close() self.pvmoni = camonitor(pvs, self._updatePvValues) #print self.pvmoni #print pvs #print self.pvs_rb_val def _updatePvValues(self, val, idx): #print idx, val s = [] for i, v in enumerate(self.pvs_rb_val): if v[0] == self.pvs_rb_val[idx][0]: s.append(self.FMT_READBACK % val) #print s item = self.table.item(self.pvs_rb_val[idx][0], self.COL_READBACK) item.setText(','.join(s)) def closePvMonitors(self): #print "Closing PV Monitors" for p in self.pvmoni: p.close() pass def closeEvent(self, event): self.closePvMonitors() event.accept() def close(self): self.closePvMonitors() return True
class MainWidget(QMainWindow): def __init__(self, parent=None): super(MainWidget, self).__init__( parent, windowTitle='GithubRemote', windowIcon=QIcon(image_path('git.png')), geometry=QRect(300, 300, 600, 372)) self.repo_pixmap = QPixmap(image_path('book_16.png')) self.big_repo_pixmap = QPixmap(image_path('book_32.png')) self.repo_fork_pixmap = QPixmap(image_path('book_fork_16.png')) self.star_pixmap = QPixmap(image_path('star_16.png')) self.big_star_pixmap = QPixmap(image_path('star_32.png')) self.fork_pixmap = QPixmap(image_path('fork_16.png')) self.eye_pixmap = QPixmap(image_path('eye_16.png')) self.github = None # Actions self.repoAddAction = QAction( QIcon(image_path('plus_48.png')), '&Add Repo', self, statusTip='Add a new repo') self.repoAddAction.triggered.connect(self.repoAdd) self.repoRemoveAction = QAction( QIcon(image_path('minus.png')), '&Remove Repo', self, statusTip='Remove repo') self.repoRemoveAction.triggered.connect(self.repoRemove) self.repoRefreshAction = QAction( QIcon(image_path('refresh.png')), 'Refresh', self, statusTip='Refresh list of repos') self.repoRefreshAction.triggered.connect(self.reposRefresh) self.repoRefreshAction.triggered.connect(self.starsRefresh) self.addAccountAction = QAction( 'Add Account', self, statusTip='Add Account') self.addAccountAction.triggered.connect(self.addAccount) # userPushButton - Displays the current active username and # image on the top right of the toolbar. self.userButtonMenu = UserButtonMenu(32,32) # ToolBar self.toolBar = self.addToolBar('Main') self.toolBar.setMovable(False) self.toolBar.setFloatable(False) spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.toolBar.addAction(self.repoAddAction) self.toolBar.addAction(self.repoRemoveAction) self.toolBar.addAction(self.repoRefreshAction) self.toolBar.addWidget(spacer) self.toolBar.addWidget(self.userButtonMenu) # Menu menuBar = self.menuBar() fileMenu = menuBar.addMenu('&File') actionMenu = menuBar.addMenu('&Action') fileMenu.addAction(self.addAccountAction) actionMenu.addAction(self.repoAddAction) actionMenu.addAction(self.repoRemoveAction) actionMenu.addAction(self.repoRefreshAction) # StatusBar statusBar = self.statusBar() self.setStatusBar(statusBar) # reposTableWidget - Displays a list of the users repositories self.reposTableWidget = QTableWidget(0, 5, selectionBehavior = QAbstractItemView.SelectRows, selectionMode = QAbstractItemView.SingleSelection, editTriggers = QAbstractItemView.NoEditTriggers, itemSelectionChanged = self.actionsUpdate) self.reposTableWidget.horizontalHeader().setResizeMode( QHeaderView.ResizeToContents) self.reposTableWidget.horizontalHeader().setResizeMode(1, QHeaderView.Stretch) self.reposTableWidget.horizontalHeader().setVisible(False) self.reposTableWidget.verticalHeader().setVisible(False) self.reposTableWidget.setShowGrid(False) self.reposTableWidget.verticalHeader().setMinimumSectionSize(25) # repoTab - Layout reposTab = QWidget() reposTabLayout = QVBoxLayout(reposTab) reposTabLayout.addWidget(self.reposTableWidget) reposTab.setLayout(reposTabLayout) # starsTableWidget - Displays a list of the users repositories self.starsTableWidget = QTableWidget(0, 5, selectionBehavior = QAbstractItemView.SelectRows, selectionMode = QAbstractItemView.SingleSelection, editTriggers = QAbstractItemView.NoEditTriggers, itemSelectionChanged = self.actionsUpdate) self.starsTableWidget.horizontalHeader().setResizeMode( QHeaderView.ResizeToContents) self.starsTableWidget.horizontalHeader().setResizeMode(1, QHeaderView.Stretch) self.starsTableWidget.horizontalHeader().setVisible(False) self.starsTableWidget.verticalHeader().setVisible(False) self.starsTableWidget.setShowGrid(False) self.starsTableWidget.verticalHeader().setMinimumSectionSize(25) # repoTab - Layout starsTab = QWidget() starsTabLayout = QVBoxLayout(starsTab) starsTabLayout.addWidget(self.starsTableWidget) starsTab.setLayout(starsTabLayout) # Tab Widget self.tabs = QTabWidget() self.tabs.setTabBar(FlippedTabBar(self)) self.tabs.addTab(reposTab, QIcon(self.big_repo_pixmap), "repos") self.tabs.addTab(starsTab, QIcon(self.big_star_pixmap), "stars") self.tabs.setTabPosition(QTabWidget.West) # Layout self.setCentralWidget(self.tabs) self.actionsUpdate() self.show() # Update self.loadUserMenu() if self.activeUserAction: self.activeUserAction.setVisible(False) self.authenticate() self.actionsUpdate() self.reposRefresh() self.starsRefresh() self.updateImage() @waiting_effects def updateImage(self): try: url = self.github.get_user().avatar_url except (GithubException, AttributeError): return data = urllib.urlopen(url).read() pixmap = QPixmap() pixmap.loadFromData(data) self.activeUserAction.setIcon(QIcon(pixmap)) self.userButtonMenu.setPixmap(pixmap) self.userButtonMenu.setText(self.github.get_user().login) @waiting_effects def loadUserMenu(self): action = None for _, username, token in generate_tokens(CONFIG_PATH, 'github'): try: url = Github(token).get_user().avatar_url except (GithubException, AttributeError): action = QAction(username, self, triggered=self.changeActive) self.userButtonMenu.addAction(action) continue data = urllib.urlopen(url).read() pixmap = QPixmap() pixmap.loadFromData(data) action = QAction(QIcon(pixmap), username, self, triggered=self.changeActive) action.setIconVisibleInMenu(True) self.userButtonMenu.addAction(action) self.activeUserAction = action def changeActive(self): sender = self.sender() self.activeUserAction.setVisible(True) self.activeUserAction = sender self.activeUserAction.setVisible(False) self.authenticate() self.actionsUpdate() self.reposRefresh() self.starsRefresh() self.updateImage() @waiting_effects def reposRefresh(self): self.reposTableWidget.clearContents() try: repos = self.github.get_user().get_repos() self.reposTableWidget.setRowCount(self.github.get_user().public_repos) except (GithubException, AttributeError): return for row, repo in enumerate(repos): imageLabel = QLabel() if repo.fork: imageLabel.setPixmap(self.repo_fork_pixmap) else: imageLabel.setPixmap(self.repo_pixmap) imageLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) imageLabel.setMargin(5) self.reposTableWidget.setCellWidget(row, 0, imageLabel) label = QLabel('<b>{}</b><br />{}'.format( str(repo.name), str(repo.description))) label.setAlignment(Qt.AlignVCenter) label.setMargin(5) label.setWordWrap(True) self.reposTableWidget.setCellWidget(row, 1, label) self.reposTableWidget.setItem(row, 2, QTableWidgetItem(QIcon(self.star_pixmap), str(repo.stargazers_count))) self.reposTableWidget.setItem(row, 3, QTableWidgetItem(QIcon(self.eye_pixmap), str(repo.watchers_count))) self.reposTableWidget.setItem(row, 4, QTableWidgetItem(QIcon(self.fork_pixmap), str(repo.forks_count))) self.reposTableWidget.resizeRowsToContents() @waiting_effects def starsRefresh(self): self.starsTableWidget.clearContents() try: starred = self.github.get_user().get_starred() self.starsTableWidget.setRowCount(self.github.get_user().public_repos) except (GithubException, AttributeError): return for row, repo in enumerate(starred): imageLabel = QLabel() if repo.fork: imageLabel.setPixmap(self.repo_fork_pixmap) else: imageLabel.setPixmap(self.repo_pixmap) imageLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) imageLabel.setMargin(5) self.starsTableWidget.setCellWidget(row, 0, imageLabel) label = QLabel(u'<b>{}/{}</b><br />{}'.format( unicode(repo.owner.login), unicode(repo.name), unicode(repo.description))) label.setAlignment(Qt.AlignVCenter) label.setMargin(5) label.setWordWrap(True) self.starsTableWidget.setCellWidget(row, 1, label) self.starsTableWidget.setItem(row, 2, QTableWidgetItem(QIcon(self.star_pixmap), '0')) self.starsTableWidget.setItem(row, 3, QTableWidgetItem(QIcon(self.eye_pixmap), str(repo.watchers_count))) self.starsTableWidget.setItem(row, 4, QTableWidgetItem(QIcon(self.fork_pixmap), str(repo.forks_count))) self.starsTableWidget.resizeRowsToContents() @waiting_effects def authenticate(self): if self.activeUserAction: username = str(self.activeUserAction.text()) token = load_token(CONFIG_PATH, 'github', username) self.github = Github(token) else: self.github = None def actionsUpdate(self): # TODO disable if no user is logged in if self.github is None: self.repoAddAction.setEnabled(False) self.repoRemoveAction.setEnabled(False) self.repoRefreshAction.setEnabled(False) else: self.repoAddAction.setEnabled(True) self.repoRefreshAction.setEnabled(True) if self._isARepoSelected(): self.repoRemoveAction.setEnabled(True) else: self.repoRemoveAction.setEnabled(False) def addAccount(self): wizard = AddAccountWizard(self) if wizard.exec_(): username = str(wizard.field('username').toString()) token = str(wizard.field('token').toString()) store_token(CONFIG_PATH, 'github', username, token) self.authenticate() self.reposRefresh() self.updateImage() self.actionsUpdate() def repoAdd(self): wizard = AddRepoWizard(self.github, self) if wizard.exec_(): self.github.get_user().create_repo( str(wizard.field('name').toString()), description=str(wizard.field('description').toString()), private=bool(wizard.field('private').toBool()), auto_init=bool(wizard.field('auto_init').toBool()), gitignore_template=str(wizard.field('gitignore').toString()), homepage=str(wizard.field('homepage').toString()), has_wiki=bool(wizard.field('has_wiki').toBool()), has_downloads=bool(wizard.field('has_downloads').toBool()), has_issues=bool(wizard.field('has_issues').toBool())) self.reposRefresh() def repoRemove(self): row = self._selectedRepoRow() name = self.reposTableWidget.item(row, 0).text() dialog = RepoRemoveDialog(self.github, name) if dialog.exec_(): self.github.get_user().get_repo(str(name)).delete() self.reposRefresh() def _isARepoSelected(self): """ Return True if a repo is selected else False """ if len(self.reposTableWidget.selectedItems()) > 0: return True else: return False def _selectedRepoRow(self): """ Return the currently select repo """ # TODO - figure out what happens if no repo is selected selectedModelIndexes = \ self.reposTableWidget.selectionModel().selectedRows() for index in selectedModelIndexes: return index.row()
def make_widget(main, show=True): id = main.persistant['id'] table = QTableWidget() table.controller = ROITableController(table, main) table.setGeometry(QRect(20, 33, 496, 296)) table.setWindowTitle('ceilingfaan - ROI Table - Work in progress') analysis = s.query(Analysis).order_by(Analysis.date.desc()).all() table.setRowCount(len(analysis)) table.setColumnCount(4) table.setHorizontalHeaderLabels( QString('CONTROL,DATE,MOUSE,FILENAME').split(',')) current_analysis = None on_render = table.controller.on('render') on_import = table.controller.on('import') for nrow, entity in enumerate(analysis): if entity.id == id: print 'Found matching analysis data', id, 'at nrow:', nrow current_analysis = entity current_nrow = nrow continue for ncol, attr in enumerate('date mouse_id filename'.split()): field = getattr(entity, attr) item = QTableWidgetItem(str(field)) item.setFlags(Qt.ItemIsEnabled) table.setItem(nrow, ncol + 1, item) render_btn = QPushButton('Render', checkable=True) render_btn.setStyleSheet('font-size: 9px; background-color: skyblue;') import_btn = QPushButton('Import') import_btn.setStyleSheet('font-size: 9px;') btn_layout = QHBoxLayout() btn_layout.setContentsMargins(5, 0, 5, 0) btn_layout.addWidget(render_btn) btn_layout.addWidget(import_btn) btn_widget = QWidget() btn_widget.nrow = nrow btn_widget.analysis_id = entity.id btn_widget.ext_roi_set = None btn_widget.setLayout(btn_layout) table.setCellWidget(nrow, 0, btn_widget) render_btn.clicked.connect(on_render) import_btn.clicked.connect(on_import) if current_analysis: table.removeRow(current_nrow) table.insertRow(0) item = QTableWidgetItem('Current Analysis') item.setFlags(Qt.ItemIsEnabled) item.setTextAlignment(Qt.AlignCenter) table.setItem(0, 0, item) for ncol, attr in enumerate('date mouse_id filename'.split()): field = getattr(current_analysis, attr) item = QTableWidgetItem(str(field)) item.setFlags(Qt.ItemIsEnabled) table.setItem(0, ncol + 1, item) # debug.enter() table.setSelectionBehavior(QTableWidget.SelectRows) table.setSelectionMode(QTableWidget.NoSelection) table.resizeColumnsToContents() table.horizontalHeader().setStretchLastSection(True) if show: table.show() return table
class MainWidget(QMainWindow): def __init__(self, parent=None): super(MainWidget, self).__init__(parent, windowTitle='GithubRemote', windowIcon=QIcon(image_path('git.png')), geometry=QRect(300, 300, 600, 372)) self.repo_pixmap = QPixmap(image_path('book_16.png')) self.big_repo_pixmap = QPixmap(image_path('book_32.png')) self.repo_fork_pixmap = QPixmap(image_path('book_fork_16.png')) self.star_pixmap = QPixmap(image_path('star_16.png')) self.big_star_pixmap = QPixmap(image_path('star_32.png')) self.fork_pixmap = QPixmap(image_path('fork_16.png')) self.eye_pixmap = QPixmap(image_path('eye_16.png')) self.github = None # Actions self.repoAddAction = QAction(QIcon(image_path('plus_48.png')), '&Add Repo', self, statusTip='Add a new repo') self.repoAddAction.triggered.connect(self.repoAdd) self.repoRemoveAction = QAction(QIcon(image_path('minus.png')), '&Remove Repo', self, statusTip='Remove repo') self.repoRemoveAction.triggered.connect(self.repoRemove) self.repoRefreshAction = QAction(QIcon(image_path('refresh.png')), 'Refresh', self, statusTip='Refresh list of repos') self.repoRefreshAction.triggered.connect(self.reposRefresh) self.repoRefreshAction.triggered.connect(self.starsRefresh) self.addAccountAction = QAction('Add Account', self, statusTip='Add Account') self.addAccountAction.triggered.connect(self.addAccount) # userPushButton - Displays the current active username and # image on the top right of the toolbar. self.userButtonMenu = UserButtonMenu(32, 32) # ToolBar self.toolBar = self.addToolBar('Main') self.toolBar.setMovable(False) self.toolBar.setFloatable(False) spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.toolBar.addAction(self.repoAddAction) self.toolBar.addAction(self.repoRemoveAction) self.toolBar.addAction(self.repoRefreshAction) self.toolBar.addWidget(spacer) self.toolBar.addWidget(self.userButtonMenu) # Menu menuBar = self.menuBar() fileMenu = menuBar.addMenu('&File') actionMenu = menuBar.addMenu('&Action') fileMenu.addAction(self.addAccountAction) actionMenu.addAction(self.repoAddAction) actionMenu.addAction(self.repoRemoveAction) actionMenu.addAction(self.repoRefreshAction) # StatusBar statusBar = self.statusBar() self.setStatusBar(statusBar) # reposTableWidget - Displays a list of the users repositories self.reposTableWidget = QTableWidget( 0, 5, selectionBehavior=QAbstractItemView.SelectRows, selectionMode=QAbstractItemView.SingleSelection, editTriggers=QAbstractItemView.NoEditTriggers, itemSelectionChanged=self.actionsUpdate) self.reposTableWidget.horizontalHeader().setResizeMode( QHeaderView.ResizeToContents) self.reposTableWidget.horizontalHeader().setResizeMode( 1, QHeaderView.Stretch) self.reposTableWidget.horizontalHeader().setVisible(False) self.reposTableWidget.verticalHeader().setVisible(False) self.reposTableWidget.setShowGrid(False) self.reposTableWidget.verticalHeader().setMinimumSectionSize(25) # repoTab - Layout reposTab = QWidget() reposTabLayout = QVBoxLayout(reposTab) reposTabLayout.addWidget(self.reposTableWidget) reposTab.setLayout(reposTabLayout) # starsTableWidget - Displays a list of the users repositories self.starsTableWidget = QTableWidget( 0, 5, selectionBehavior=QAbstractItemView.SelectRows, selectionMode=QAbstractItemView.SingleSelection, editTriggers=QAbstractItemView.NoEditTriggers, itemSelectionChanged=self.actionsUpdate) self.starsTableWidget.horizontalHeader().setResizeMode( QHeaderView.ResizeToContents) self.starsTableWidget.horizontalHeader().setResizeMode( 1, QHeaderView.Stretch) self.starsTableWidget.horizontalHeader().setVisible(False) self.starsTableWidget.verticalHeader().setVisible(False) self.starsTableWidget.setShowGrid(False) self.starsTableWidget.verticalHeader().setMinimumSectionSize(25) # repoTab - Layout starsTab = QWidget() starsTabLayout = QVBoxLayout(starsTab) starsTabLayout.addWidget(self.starsTableWidget) starsTab.setLayout(starsTabLayout) # Tab Widget self.tabs = QTabWidget() self.tabs.setTabBar(FlippedTabBar(self)) self.tabs.addTab(reposTab, QIcon(self.big_repo_pixmap), "repos") self.tabs.addTab(starsTab, QIcon(self.big_star_pixmap), "stars") self.tabs.setTabPosition(QTabWidget.West) # Layout self.setCentralWidget(self.tabs) self.actionsUpdate() self.show() # Update self.loadUserMenu() if self.activeUserAction: self.activeUserAction.setVisible(False) self.authenticate() self.actionsUpdate() self.reposRefresh() self.starsRefresh() self.updateImage() @waiting_effects def updateImage(self): try: url = self.github.get_user().avatar_url except (GithubException, AttributeError): return data = urllib.urlopen(url).read() pixmap = QPixmap() pixmap.loadFromData(data) self.activeUserAction.setIcon(QIcon(pixmap)) self.userButtonMenu.setPixmap(pixmap) self.userButtonMenu.setText(self.github.get_user().login) @waiting_effects def loadUserMenu(self): action = None for _, username, token in generate_tokens(CONFIG_PATH, 'github'): try: url = Github(token).get_user().avatar_url except (GithubException, AttributeError): action = QAction(username, self, triggered=self.changeActive) self.userButtonMenu.addAction(action) continue data = urllib.urlopen(url).read() pixmap = QPixmap() pixmap.loadFromData(data) action = QAction(QIcon(pixmap), username, self, triggered=self.changeActive) action.setIconVisibleInMenu(True) self.userButtonMenu.addAction(action) self.activeUserAction = action def changeActive(self): sender = self.sender() self.activeUserAction.setVisible(True) self.activeUserAction = sender self.activeUserAction.setVisible(False) self.authenticate() self.actionsUpdate() self.reposRefresh() self.starsRefresh() self.updateImage() @waiting_effects def reposRefresh(self): self.reposTableWidget.clearContents() try: repos = self.github.get_user().get_repos() self.reposTableWidget.setRowCount( self.github.get_user().public_repos) except (GithubException, AttributeError): return for row, repo in enumerate(repos): imageLabel = QLabel() if repo.fork: imageLabel.setPixmap(self.repo_fork_pixmap) else: imageLabel.setPixmap(self.repo_pixmap) imageLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) imageLabel.setMargin(5) self.reposTableWidget.setCellWidget(row, 0, imageLabel) label = QLabel('<b>{}</b><br />{}'.format(str(repo.name), str(repo.description))) label.setAlignment(Qt.AlignVCenter) label.setMargin(5) label.setWordWrap(True) self.reposTableWidget.setCellWidget(row, 1, label) self.reposTableWidget.setItem( row, 2, QTableWidgetItem(QIcon(self.star_pixmap), str(repo.stargazers_count))) self.reposTableWidget.setItem( row, 3, QTableWidgetItem(QIcon(self.eye_pixmap), str(repo.watchers_count))) self.reposTableWidget.setItem( row, 4, QTableWidgetItem(QIcon(self.fork_pixmap), str(repo.forks_count))) self.reposTableWidget.resizeRowsToContents() @waiting_effects def starsRefresh(self): self.starsTableWidget.clearContents() try: starred = self.github.get_user().get_starred() self.starsTableWidget.setRowCount( self.github.get_user().public_repos) except (GithubException, AttributeError): return for row, repo in enumerate(starred): imageLabel = QLabel() if repo.fork: imageLabel.setPixmap(self.repo_fork_pixmap) else: imageLabel.setPixmap(self.repo_pixmap) imageLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) imageLabel.setMargin(5) self.starsTableWidget.setCellWidget(row, 0, imageLabel) label = QLabel(u'<b>{}/{}</b><br />{}'.format( unicode(repo.owner.login), unicode(repo.name), unicode(repo.description))) label.setAlignment(Qt.AlignVCenter) label.setMargin(5) label.setWordWrap(True) self.starsTableWidget.setCellWidget(row, 1, label) self.starsTableWidget.setItem( row, 2, QTableWidgetItem(QIcon(self.star_pixmap), '0')) self.starsTableWidget.setItem( row, 3, QTableWidgetItem(QIcon(self.eye_pixmap), str(repo.watchers_count))) self.starsTableWidget.setItem( row, 4, QTableWidgetItem(QIcon(self.fork_pixmap), str(repo.forks_count))) self.starsTableWidget.resizeRowsToContents() @waiting_effects def authenticate(self): if self.activeUserAction: username = str(self.activeUserAction.text()) token = load_token(CONFIG_PATH, 'github', username) self.github = Github(token) else: self.github = None def actionsUpdate(self): # TODO disable if no user is logged in if self.github is None: self.repoAddAction.setEnabled(False) self.repoRemoveAction.setEnabled(False) self.repoRefreshAction.setEnabled(False) else: self.repoAddAction.setEnabled(True) self.repoRefreshAction.setEnabled(True) if self._isARepoSelected(): self.repoRemoveAction.setEnabled(True) else: self.repoRemoveAction.setEnabled(False) def addAccount(self): wizard = AddAccountWizard(self) if wizard.exec_(): username = str(wizard.field('username').toString()) token = str(wizard.field('token').toString()) store_token(CONFIG_PATH, 'github', username, token) self.authenticate() self.reposRefresh() self.updateImage() self.actionsUpdate() def repoAdd(self): wizard = AddRepoWizard(self.github, self) if wizard.exec_(): self.github.get_user().create_repo( str(wizard.field('name').toString()), description=str(wizard.field('description').toString()), private=bool(wizard.field('private').toBool()), auto_init=bool(wizard.field('auto_init').toBool()), gitignore_template=str(wizard.field('gitignore').toString()), homepage=str(wizard.field('homepage').toString()), has_wiki=bool(wizard.field('has_wiki').toBool()), has_downloads=bool(wizard.field('has_downloads').toBool()), has_issues=bool(wizard.field('has_issues').toBool())) self.reposRefresh() def repoRemove(self): row = self._selectedRepoRow() name = self.reposTableWidget.item(row, 0).text() dialog = RepoRemoveDialog(self.github, name) if dialog.exec_(): self.github.get_user().get_repo(str(name)).delete() self.reposRefresh() def _isARepoSelected(self): """ Return True if a repo is selected else False """ if len(self.reposTableWidget.selectedItems()) > 0: return True else: return False def _selectedRepoRow(self): """ Return the currently select repo """ # TODO - figure out what happens if no repo is selected selectedModelIndexes = \ self.reposTableWidget.selectionModel().selectedRows() for index in selectedModelIndexes: return index.row()
class K800IRec(QWidget, mfso): def __init__(self): mfso.__init__(self, "K800i-Recover") self.name = "K800i-Recover" self.icon = None self.__disown__() def start(self, args): self.vfs = vfs.vfs() self.dumpnumber = 1 try: self.nor = args['nor'].value() self.nand = args['nand'].value() except IndexError: return try: self.spareSize = args["spare-size"].value() except IndexError: self.spareSize = 16 try: self.pageSize = args["page-size"].value() except IndexError: self.pageSize = 512 self.k800n = Node("k800-base") self.k800n.__disown__() self.boot = SEBootBlock(self.nor, self.pageSize) self.blockSize = self.boot.blockSize self.nandClean = SpareNode(self, self.nand, "nandfs", self.pageSize, self.spareSize, self.k800n) self.norFs = NorFs(self, self.k800n, self.nor, "norfs", self.boot) self.fullFs = FullFs(self, self.k800n, self.norFs, self.nandClean, "fullfs", self.boot) self.gdfs = GDFS(self, self.k800n, self.nor, "gdfs", self.boot) self.firmware = Firmware(self, self.k800n, self.nor, "firmware", self.boot.norfsoffset) self.tables = Tables(self.fullFs, self.blockSize) self.registerTree(self.nand, self.k800n) def createDump(self): text, ok = QInputDialog.getText(self, "Create dump", "dump name:", QLineEdit.Normal, "k800-restore-" + str(self.dumpnumber)) if ok and text != "": if (self.vfs.getnode(self.nand.absolute() + "/" + str(text)) == None): self.dumpnumber += 1 newroot = Node(str(text)) newroot.__disown__() for id in range(0, len(self.tables.tablesIdWriteMap) - 1): write = int( str(self.gtable.cellWidget(id, 0).currentText()), 16) self.tables.map[id] = self.tables.tablesIdWriteMap[id][ write] virtual = VirtualMap(self, newroot, self.fullFs, self.tables, "virtual", self.blockSize) separt = SEPartitionBlock(virtual, self.boot.partitionblock, self.blockSize) self.createPart(separt, newroot, virtual) self.registerTree(self.nand, newroot) else: box = QMessageBox(QMessageBox.Warning, "Error", "Error node already exists", QMessageBox.NoButton, self) box.exec_() self.createDump() def createPart(self, separt, newroot, virtual): for part in separt.partTable: if part.start > 0: p = Partition(self, newroot, virtual, part, self.blockSize) def g_display(self): QWidget.__init__(self, None) self.layout = QVBoxLayout(self) self.hlayout = QSplitter(self) self.layout.insertWidget(0, self.hlayout) self.layout.setStretchFactor(self.hlayout, 1) self.gTable() self.viewTable() self.button = QPushButton("&Create dump") self.connect(self.button, SIGNAL("clicked()"), self.createDump) self.layout.addWidget(self.button) def viewTable(self): self.vtable = QTableWidget() self.vtable.setColumnCount(20) self.vtable.setRowCount(48) self.hlayout.addWidget(self.vtable) def viewTableUpdate(self, id): write = int(str(self.gtable.cellWidget(id, 0).currentText()), 16) t = self.tables.tablesIdWriteMap[id][write] l = t.blockList for x in xrange(0, len(t.blockList[0])): block = t.blockList[0][x] c = ((x) % 20) r = ((x) / 20) item = QTableWidgetItem(QString(hex(block))) tipBlock = (id * 960) + x item.setToolTip(QString(hex(tipBlock))) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.vtable.setItem(r, c, item) def gTable(self): self.gtable = QTableWidget() self.gtable.setColumnCount(1) self.gtable.setRowCount(len(self.tables.tablesIdWriteMap)) self.gtable.setHorizontalHeaderItem( 0, QTableWidgetItem(QString("version"))) self.hlayout.addWidget(self.gtable) self.sigMapper = QSignalMapper(self) for id in self.tables.tablesIdWriteMap: wlist = self.tables.tablesIdWriteMap[id] cbox = QComboBox(self.gtable) self.connect(cbox, SIGNAL("activated(QString)"), self.sigMapper, SLOT("map()")) self.sigMapper.setMapping(cbox, id) l = [] for write in wlist: l.append(write) l.sort() l.reverse() for write in l: cbox.addItem(QString(hex(write))) self.gtable.setCellWidget(id, 0, cbox) self.gtable.setVerticalHeaderItem( id, QTableWidgetItem(QString(hex(id)))) self.connect(self.sigMapper, SIGNAL("mapped(int)"), self.viewTableUpdate) self.gtable.setMaximumWidth( self.gtable.columnWidth(0) + self.gtable.verticalHeader().sectionSize(0) + 30) def updateWidget(self): pass
class daq_window(QMainWindow): """Window to control and visualise DAQ measurements. Set up the desired channels with a given sampling rate. Start an acquisition after a trigger. Display the acquired data on a trace, and accumulated data on a graph. Arguments: n -- run number for synchronisation rate -- max sample rate in samples / second dt -- desired acquisition period in seconds config_file -- path to file storing default settings port -- the port number to open for TCP connections """ def __init__(self, n=0, rate=250, dt=500, config_file='monitor\\daqconfig.dat', port=8622): super().__init__() self.types = OrderedDict([('n', int), ('config_file', str), ('trace_file', str), ('graph_file', str), ('save_dir', str), ('Sample Rate (kS/s)',float), ('Duration (ms)', float), ('Trigger Channel', str), ('Trigger Level (V)', float), ('Trigger Edge', str), ('channels',channel_stats)]) self.stats = OrderedDict([('n', n), ('config_file', config_file), ('trace_file', 'DAQtrace.csv'), ('graph_file', 'DAQgraph.csv'),('save_dir', '.'), ('Sample Rate (kS/s)', rate), ('Duration (ms)', dt), ('Trigger Channel', 'Dev2/ai1'), # /Dev2/PFI0 ('Trigger Level (V)', 1.0), ('Trigger Edge', 'rising'), ('channels', channel_stats("[['Dev2/ai0', '0', '1.0', '0.0', '5', '1', '1']]"))]) self.trigger_toggle = True # whether to trigger acquisition or just take a measurement self.slave = worker(rate*1e3, dt/1e3, self.stats['Trigger Channel'], self.stats['Trigger Level (V)'], self.stats['Trigger Edge'], list(self.stats['channels'].keys()), [ch['range'] for ch in self.stats['channels'].values()]) # this controls the DAQ self.dc = daqCollection(param=[], channels=list(self.stats['channels'].keys())) self.init_UI() self.load_config(config_file) # load default settings self.n_samples = int(self.stats['Duration (ms)'] * self.stats['Sample Rate (kS/s)']) # number of samples per acquisition self.last_path = './' self.x = [] # run numbers for graphing collections of acquired data self.y = [] # average voltages in slice of acquired trace self.slave.acquired.connect(self.update_graph) # take average of slices self.slave.acquired.connect(self.update_trace) # plot new data when it arrives self.tcp = PyClient(port=port) remove_slot(self.tcp.dxnum, self.set_n, True) remove_slot(self.tcp.textin, self.respond, True) self.tcp.start() def init_UI(self): """Produce the widgets and buttons.""" self.centre_widget = QWidget() self.tabs = QTabWidget() # make tabs for each main display self.centre_widget.layout = QVBoxLayout() self.centre_widget.layout.addWidget(self.tabs) self.centre_widget.setLayout(self.centre_widget.layout) self.setCentralWidget(self.centre_widget) # change font size font = QFont() font.setPixelSize(18) #### menubar at top gives options #### menubar = self.menuBar() # file menubar allows you to save/load data file_menu = menubar.addMenu('File') for label, function in [['Load Config', self.load_config], ['Save Config', self.save_config], ['Load Trace', self.load_trace], ['Save Trace', self.save_trace], ['Save Graph', self.save_graph]]: action = QAction(label, self) action.triggered.connect(function) file_menu.addAction(action) #### tab for settings #### settings_tab = QWidget() settings_grid = QGridLayout() settings_tab.setLayout(settings_grid) self.tabs.addTab(settings_tab, "Settings") self.settings = QTableWidget(1, 6) self.settings.setHorizontalHeaderLabels(['Duration (ms)', 'Sample Rate (kS/s)', 'Trigger Channel', 'Trigger Level (V)', 'Trigger Edge', 'Use Trigger?']) settings_grid.addWidget(self.settings, 0,0, 1,1) defaults = [str(self.stats['Duration (ms)']), str(self.stats['Sample Rate (kS/s)']), self.stats['Trigger Channel'], str(self.stats['Trigger Level (V)']), self.stats['Trigger Edge'], '1'] validators = [double_validator, double_validator, None, double_validator, None, bool_validator] for i in range(6): table_item = QLineEdit(defaults[i]) # user can edit text to change the setting if defaults[i] == 'Sample Rate (kS/s)': table_item.setEnabled(False) table_item.setValidator(validators[i]) # validator limits the values that can be entered self.settings.setCellWidget(0,i, table_item) self.settings.resizeColumnToContents(1) self.settings.setFixedHeight(70) # make it take up less space self.settings.cellWidget(0,0).textChanged.connect(self.check_slice_duration) # start/stop: start waiting for a trigger or taking an acquisition self.toggle = QPushButton('Start', self) self.toggle.setCheckable(True) self.toggle.clicked.connect(self.activate) settings_grid.addWidget(self.toggle, 1,0, 1,1) # channels self.channels = QTableWidget(8, 7) # make table self.channels.setHorizontalHeaderLabels(['Channel', 'Label', 'Scale (X/V)', 'Offset (V)', 'Range', 'Acquire?', 'Plot?']) settings_grid.addWidget(self.channels, 2,0, 1,1) validators = [None, double_validator, double_validator, None, bool_validator, bool_validator] for i in range(8): chan = 'Dev2/ai'+str(i) # name of virtual channel table_item = QLabel(chan) self.channels.setCellWidget(i,0, table_item) if chan in self.stats['channels']: # load values from previous defaults = self.stats['channels'][chan] else: # default values when none are loaded defaults = channel_stats("[dummy, "+str(i)+", 1.0, 0.0, 5.0, 0, 0]")['dummy'] for j, key in zip([0,1,2,4,5], ['label', 'scale', 'offset', 'acquire', 'plot']): table_item = QLineEdit(str(defaults[key])) if 'acquire' in key: table_item.textChanged.connect(self.check_slice_channels) elif 'plot' in key: table_item.textChanged.connect(self.set_acquire) table_item.setValidator(validators[j]) self.channels.setCellWidget(i,j+1, table_item) vrange = QComboBox() # only allow certain values for voltage range vrange.text = vrange.currentText # overload function so it's same as QLabel vrange.addItems(['%.1f'%x for x in self.slave.vrs]) try: vrange.setCurrentIndex(self.slave.vrs.index(defaults['range'])) except Exception as e: logger.error('Invalid channel voltage range\n'+str(e)) self.channels.setCellWidget(i,4, vrange) #### Plot for most recently acquired trace #### trace_tab = QWidget() trace_grid = QGridLayout() trace_tab.setLayout(trace_grid) self.tabs.addTab(trace_tab, "Trace") # button activates horizontal line self.hline_toggle = QPushButton('Horizontal line', self, checkable=True) self.hline_toggle.clicked.connect(self.add_horizontal) trace_grid.addWidget(self.hline_toggle, 0,0, 1,1) self.hline_label = QLabel() trace_grid.addWidget(self.hline_label, 0,1, 1,1) fadeline_button = QPushButton('Persist', self) fadeline_button.clicked.connect(self.set_fadelines) trace_grid.addWidget(fadeline_button, 0,2, 1,1) # plot the trace self.trace_canvas = pg.PlotWidget() self.trace_legend = self.trace_canvas.addLegend() self.trace_canvas.getAxis('bottom').tickFont = font self.trace_canvas.getAxis('left').tickFont = font self.trace_canvas.setLabel('bottom', 'Time', 's', **{'font-size':'18pt'}) self.trace_canvas.setLabel('left', 'Voltage', 'V', **{'font-size':'18pt'}) self.lines = [] # handles for lines plotting the last measurement self.fadelines = [] # handles for previous measurement lines for i in range(8): chan = self.channels.cellWidget(i,1).text() self.lines.append(self.trace_canvas.plot([1], name=chan, pen=pg.mkPen(pg.intColor(i), width=3))) self.lines[i].hide() self.fadelines.append(self.trace_canvas.plot([1], pen=pg.mkPen(pg.intColor(i, alpha=50), width=2))) self.fadelines[i].hide() self.hline = pg.InfiniteLine(1., angle=0, pen='k', movable=True) self.trace_canvas.addItem(self.hline) self.hline.sigPositionChanged.connect(self.update_hline) self.hline.hide() trace_grid.addWidget(self.trace_canvas, 1,0, 1,3) #### Settings for slices of the trace accumulating into the graph #### slice_tab = QWidget() slice_grid = QGridLayout() slice_tab.setLayout(slice_grid) self.tabs.addTab(slice_tab, "Slice") # Buttons to add/remove slices and reset graph for i, (label, func) in enumerate([['Add slice', self.add_slice], ['Remove slice', self.del_slice], ['Reset graph', self.reset_graph]]): button = QPushButton(label, self) button.clicked.connect(func) slice_grid.addWidget(button, 0,i, 1,1) # parameters for slices self.slices = QTableWidget(0, 4) # make table self.slices.setHorizontalHeaderLabels(['Slice name', 'Start (ms)', 'End (ms)', 'Channels']) slice_grid.addWidget(self.slices, 1,0, 1,3) #### Plot for graph of accumulated data #### graph_tab = QWidget() graph_grid = QGridLayout() graph_tab.setLayout(graph_grid) self.tabs.addTab(graph_tab, "Graph") self.mean_graph = pg.PlotWidget() # for plotting means self.stdv_graph = pg.PlotWidget() # for plotting standard deviations self.graph_legends = [] for i, g in enumerate([self.mean_graph, self.stdv_graph]): g.getAxis('bottom').tickFont = font g.getAxis('bottom').setFont(font) g.getAxis('left').tickFont = font g.getAxis('left').setFont(font) graph_grid.addWidget(g, i,0, 1,1) self.reset_lines() # make a line for every slice channel self.stdv_graph.setLabel('bottom', 'Shot', '', **{'font-size':'18pt'}) self.stdv_graph.setLabel('left', 'Standard Deviation', 'V', **{'font-size':'18pt'}) self.mean_graph.setLabel('left', 'Mean', 'V', **{'font-size':'18pt'}) #### tab for TCP message settings #### tcp_tab = QWidget() tcp_grid = QGridLayout() tcp_tab.setLayout(tcp_grid) self.tabs.addTab(tcp_tab, "Sync") label = QLabel('Run number: ') tcp_grid.addWidget(label, 0,0, 1,1) self.n_edit = QLineEdit(str(self.stats['n'])) self.n_edit.setValidator(int_validator) self.n_edit.textEdited[str].connect(self.set_n) tcp_grid.addWidget(self.n_edit, 0,1, 1,1) label = QLabel('Save directory: ') tcp_grid.addWidget(label, 1,0, 1,1) self.save_edit = QLineEdit(self.stats['save_dir']) self.save_edit.textEdited[str].connect(self.set_save_dir) tcp_grid.addWidget(self.save_edit, 1,1, 1,1) label = QLabel('Trace file name: ') tcp_grid.addWidget(label, 2,0, 1,1) self.trace_edit = QLineEdit(self.stats['trace_file']) self.trace_edit.textEdited[str].connect(self.set_trace_file) tcp_grid.addWidget(self.trace_edit, 2,1, 1,1) label = QLabel('Graph file name: ') tcp_grid.addWidget(label, 3,0, 1,1) self.graph_edit = QLineEdit(self.stats['graph_file']) self.graph_edit.textEdited[str].connect(self.set_graph_file) tcp_grid.addWidget(self.graph_edit, 3,1, 1,1) reset = QPushButton('Reset TCP client', self) reset.clicked.connect(self.reset_client) tcp_grid.addWidget(reset, 4,0, 1,1) #### Title and icon #### self.setWindowTitle('- NI DAQ Controller -') self.setWindowIcon(QIcon('docs/daqicon.png')) self.setGeometry(200, 200, 800, 600) #### user input functions #### def set_acquire(self): """If the user chooses to plot, set the same channel to acquire.""" for i in range(self.channels.rowCount()): if BOOL(self.channels.cellWidget(i,6).text()): # plot self.channels.cellWidget(i,5).setText('1') # only plot if acquiring def check_settings(self): """Coerce the settings into allowed values.""" statstr = "[[" # dictionary of channel names and properties for i in range(self.channels.rowCount()): self.trace_legend.items[i][1].setText(self.channels.cellWidget(i,1).text()) # label if BOOL(self.channels.cellWidget(i,5).text()): # acquire statstr += ', '.join([self.channels.cellWidget(i,j).text() for j in range(self.channels.columnCount())]) + '],[' self.stats['channels'] = channel_stats(statstr[:-2] + ']') self.dc.channels = self.stats['channels'].keys() # acquisition settings self.stats['Duration (ms)'] = float(self.settings.cellWidget(0,0).text()) # check that the requested rate is valid rate = float(self.settings.cellWidget(0,1).text()) if len(self.stats['channels']) > 1 and rate > 245 / len(self.stats['channels']): rate = 245 / len(self.stats['channels']) elif len(self.stats['channels']) < 2 and rate > 250: rate = 250 self.stats['Sample Rate (kS/s)'] = rate self.settings.cellWidget(0,1).setText('%.2f'%(rate)) self.n_samples = int(self.stats['Duration (ms)'] * self.stats['Sample Rate (kS/s)']) # check the trigger channel is valid trig_chan = self.settings.cellWidget(0,2).text() if 'Dev2/PFI' in trig_chan or 'Dev2/ai' in trig_chan: self.stats['Trigger Channel'] = trig_chan else: self.stats['Trigger Channel'] = 'Dev2/ai0' self.settings.cellWidget(0,2).setText(str(self.stats['Trigger Channel'])) self.stats['Trigger Level (V)'] = float(self.settings.cellWidget(0,3).text()) self.stats['Trigger Edge'] = self.settings.cellWidget(0,4).text() self.trigger_toggle = BOOL(self.settings.cellWidget(0,5).text()) def set_table(self): """Display the acquisition and channel settings in the table.""" x = self.stats.copy() # prevent it getting overwritten for i in range(5): self.settings.cellWidget(0,i).setText(str(x[ self.settings.horizontalHeaderItem(i).text()])) for i in range(8): ch = self.channels.cellWidget(i,0).text() if ch in x['channels']: for j, key in zip([0,1,2,4,5], ['label', 'scale', 'offset', 'acquire', 'plot']): self.channels.cellWidget(i,j+1).setText(str(x['channels'][ch][key])) self.channels.cellWidget(i,4).setCurrentText('%.1f'%x['channels'][ch]['range']) else: self.channels.cellWidget(i,5).setText('0') # don't acquire self.channels.cellWidget(i,6).setText('0') # don't plot #### slice settings functions #### def add_slice(self, param=[]): """Add a row to the slice table and append it to the daqCollection instance for analysis. param -- [name, start (ms), end (ms), channels]""" try: name, start, end, channels = param except TypeError: name = 'Slice' + str(self.slices.rowCount()) start = 0 end = self.stats['Duration (ms)'] channels = list(self.stats['channels'].keys()) i = self.slices.rowCount() # index to add row at self.slices.insertRow(i) # add row to table validator = QDoubleValidator(0.,float(self.stats['Duration (ms)']),3) for j, text in enumerate([name, str(start), str(end)]): item = QLineEdit(text) item.pos = (i, j) if j > 0: item.setValidator(validator) item.textChanged.connect(self.update_slices) self.slices.setCellWidget(i, j, item) chanbox = QListWidget(self) chanbox.setSelectionMode(3) # extended selection, allows multiple selection chanbox.itemSelectionChanged.connect(self.update_slices) chanbox.pos = (i, 3) chanbox.text = chanbox.objectName chanlist = list(self.stats['channels'].keys()) chanbox.addItems(chanlist) self.slices.setCellWidget(i, j+1, chanbox) self.slices.resizeRowToContents(i) # add to the dc list of slices t = np.linspace(0, self.stats['Duration (ms)']/1000, self.n_samples) self.dc.add_slice(name, np.argmin(np.abs(t-start)), np.argmin(np.abs(t-end)), OrderedDict([(chan, chanlist.index(chan)) for chan in channels])) self.reset_lines() def del_slice(self, toggle=True): """Remove the slice at the selected row of the slice table.""" index = self.slices.currentRow() self.slices.removeRow(index) if index >= 0: self.dc.slices.pop(index) def check_slice_duration(self, newtxt): """If the acquisition duration is changed, make sure the slices can't use times beyond this.""" self.check_settings() # update DAQ acquisition settings first for i in range(self.slices.rowCount()): for j in [1,2]: # force slice to be within max duration validator = QDoubleValidator(0.,float(self.stats['Duration (ms)']),3) self.slices.cellWidget(i, j).setValidator(validator) def check_slice_channels(self, newtxt): """If the channels that can be used for the acquisition are changed, change the list widgets in the slice settings to match.""" self.check_settings() # update DAQ acquisition settings first for i in range(self.slices.rowCount()): w = self.slices.cellWidget(i, 3) # widget shorthand selected = [w.row(x) for x in w.selectedItems()] # make record of selected channels w.clear() w.addItems(list(self.stats['channels'].keys())) for r in selected: try: w.setCurrentRow(r, QItemSelectionModel.SelectCurrent) except Exception as e: pass def update_slices(self, newtxt=''): """Use the current item from the table to update the parameter for the slices.""" try: w = self.sender() i, j = w.pos t = np.linspace(0, self.stats['Duration (ms)'], self.n_samples) x = self.dc.slices[i] # shorthand if j == 0: # name x.name = w.text() elif j == 1: # start (ms) x.i0 = np.argmin(np.abs(t-float(w.text()))) elif j == 2: # end (ms) x.i1 = np.argmin(np.abs(t-float(w.text()))) elif j == 3: x.channels = OrderedDict([(x.text(), w.row(x)) for x in w.selectedItems()]) x.stats = OrderedDict([(chan, OrderedDict([ ('mean',[]), ('stdv',[])])) for chan in x.channels.keys()]) self.reset_lines() self.reset_graph() x.inds = slice(x.i0, x.i1+1) x.size = x.i1 - x.i0 except IndexError as e: pass # logger.error("Couldn't update slice.\n"+str(e)) #### TCP functions #### def set_n(self, num): """Receive the new run number to update to""" self.stats['n'] = int(num) self.n_edit.setText(str(num)) def set_save_dir(self, directory): """Set the directory to save results to""" self.stats['save_dir'] = directory self.save_edit.setText(directory) def set_trace_file(self, fname): """Set the default name for trace files when they're saved.""" self.stats['trace_file'] = fname self.trace_edit.setText(fname) def set_graph_file(self, fname): """Set the default name for graph files when they're saved.""" self.stats['graph_file'] = fname self.graph_edit.setText(fname) def reset_client(self, toggle=True): """Stop the TCP client thread then restart it.""" self.tcp.stop = True for i in range(100): # wait til it's stopped if not self.tcp.isRunning(): break else: time.sleep(0.001) self.tcp.start() # restart def respond(self, msg=''): """Interpret a TCP message. For setting properties, the syntax is: value=property. E.g. 'Z:\Tweezer=save_dir'.""" if 'save_dir' in msg: self.set_save_dir(msg.split('=')[0]) elif 'trace_file' in msg: self.set_trace_file(msg.split('=')[0]) elif 'graph_file' in msg: self.set_graph_file(msg.split('=')[0]) elif 'start' in msg and not self.toggle.isChecked(): self.toggle.setChecked(True) self.activate() elif 'stop' in msg and self.toggle.isChecked(): self.toggle.setChecked(False) self.activate() elif 'save trace' in msg: self.save_trace(os.path.join(self.stats['save_dir'], self.stats['trace_file'])) elif 'save graph' in msg: self.save_graph(os.path.join(self.stats['save_dir'], self.stats['graph_file'])) elif 'set fadelines' in msg: self.set_fadelines() #### acquisition functions #### def activate(self, toggle=0): """Prime the DAQ task for acquisition if it isn't already running. Otherwise, stop the task running.""" if self.toggle.isChecked(): self.check_settings() self.slave = worker(self.stats['Sample Rate (kS/s)']*1e3, self.stats['Duration (ms)']/1e3, self.stats['Trigger Channel'], self.stats['Trigger Level (V)'], self.stats['Trigger Edge'], list(self.stats['channels'].keys()), [ch['range'] for ch in self.stats['channels'].values()]) remove_slot(self.slave.acquired, self.update_trace, True) remove_slot(self.slave.acquired, self.update_graph, True) if self.trigger_toggle: # remove_slot(self.slave.finished, self.activate, True) self.slave.start() self.toggle.setText('Stop') else: self.toggle.setChecked(False) self.slave.analogue_acquisition() else: # remove_slot(self.slave.finished, self.activate, False) self.slave.stop = True self.slave.quit() self.toggle.setText('Start') #### plotting functions #### def update_trace(self, data): """Plot the supplied data with labels on the trace canvas.""" t = np.linspace(0, self.stats['Duration (ms)']/1000, self.n_samples) i = 0 # index to keep track of which channels have been plotted for j in range(8): ch = self.channels.cellWidget(j,0).text() l = self.lines[j] # shorthand if ch in self.stats['channels'] and self.stats['channels'][ch]['plot']: try: l.setData(t, data[i]) except Exception as e: logger.error('DAQ trace could not be plotted.\n'+str(e)) self.fadelines[j].show() l.show() self.trace_legend.items[j][0].show() self.trace_legend.items[j][1].show() i += 1 else: l.hide() self.fadelines[j].hide() self.trace_legend.items[j][0].hide() self.trace_legend.items[j][1].hide() self.trace_legend.resize(0,0) def set_fadelines(self): """Take the data from the current lines and sets it to the fadelines.""" for j in range(8): ch = self.channels.cellWidget(j,0).text() l = self.lines[j] # shorthand if ch in self.stats['channels'] and self.stats['channels'][ch]['plot']: try: self.fadelines[j].setData(l.xData, l.yData) except Exception as e: logger.error('DAQ trace could not be plotted.\n'+str(e)) self.fadelines[j].show() else: self.fadelines[j].hide() def reset_lines(self): """Clear the mean and stdv graphs, reset the legends, then make new lines for each of the slice channels.""" for legend in self.graph_legends: # reset the legends try: legend.scene().removeItem(legend) except AttributeError: pass for g in [self.mean_graph, self.stdv_graph]: g.clear() g.lines = OrderedDict([]) self.graph_legends.append(g.addLegend()) i = 0 for s in self.dc.slices: for chan, val in s.stats.items(): g.lines[s.name+'/'+chan] = g.plot([1], name=s.name+'/'+chan, pen=None, symbol='o', symbolPen=pg.mkPen(pg.intColor(i)), symbolBrush=pg.intColor(i)) i += 1 def reset_graph(self): """Reset the collection of slice data, then replot the graph.""" self.dc.reset_arrays() self.update_graph() def update_graph(self, data=[]): """Extract averages from slices of the data. Replot the stored data accumulated from averages in slices of the measurements.""" if np.size(data): self.dc.process(data, self.stats['n']) for s in self.dc.slices: for chan, val in s.stats.items(): self.mean_graph.lines[s.name+'/'+chan].setData(self.dc.runs, val['mean']) self.stdv_graph.lines[s.name+'/'+chan].setData(self.dc.runs, val['stdv']) def add_horizontal(self, toggle=True): """Display a horizontal line on the trace""" if toggle: self.hline.show() else: self.hline.hide() self.hline_label.setText('') def update_hline(self): """Display the value of the horizontal line in the label""" self.hline_label.setText(str(self.hline.value())) #### save/load functions #### def try_browse(self, title='Select a File', file_type='all (*)', open_func=QFileDialog.getOpenFileName, default_path=''): """Open a file dialog and retrieve a file name from the browser. title: String to display at the top of the file browser window default_path: directory to open first file_type: types of files that can be selected open_func: the function to use to open the file browser""" default_path = default_path if default_path else os.path.dirname(self.last_path) try: if 'PyQt4' in sys.modules: file_name = open_func(self, title, default_path, file_type) elif 'PyQt5' in sys.modules: file_name, _ = open_func(self, title, default_path, file_type) if type(file_name) == str: self.last_path = file_name return file_name except OSError: return '' # probably user cancelled def save_config(self, file_name='daqconfig.dat'): """Save the current acquisition settings to the config file.""" self.stats['config_file'] = file_name if file_name else self.try_browse( 'Save Config File', 'dat (*.dat);;all (*)', QFileDialog.getSaveFileName) try: with open(self.stats['config_file'], 'w+') as f: for key, val in self.stats.items(): if key == 'channels': f.write(key+'='+channel_str(val)+'\n') else: f.write(key+'='+str(val)+'\n') logger.info('DAQ config saved to '+self.stats['config_file']) except Exception as e: logger.error('DAQ settings could not be saved to config file.\n'+str(e)) def load_config(self, file_name='daqconfig.dat'): """Load the acquisition settings from the config file.""" self.stats['config_file'] = file_name if file_name else self.try_browse(file_type='dat (*.dat);;all (*)') try: with open(self.stats['config_file'], 'r') as f: for line in f: if len(line.split('=')) == 2: key, val = line.replace('\n','').split('=') # there should only be one = per line try: self.stats[key] = self.types[key](val) except KeyError as e: logger.warning('Failed to load DAQ default config line: '+line+'\n'+str(e)) self.set_table() # make sure the updates are displayed self.set_n(self.stats['n']) self.set_save_dir(self.stats['save_dir']) self.set_trace_file(self.stats['trace_file']) self.set_graph_file(self.stats['graph_file']) self.dc.channels = list(self.stats['channels'].keys()) logger.info('DAQ config loaded from '+self.stats['config_file']) except FileNotFoundError as e: logger.warning('DAQ settings could not find the config file.\n'+str(e)) def save_trace(self, file_name=''): """Save the data currently displayed on the trace to a csv file.""" file_name = file_name if file_name else self.try_browse( 'Save File', 'csv (*.csv);;all (*)', QFileDialog.getSaveFileName) if file_name: # metadata header = ', '.join(list(self.stats.keys())) + '\n' header += ', '.join(list(map(str, self.stats.values()))[:-1] ) + ', ' + channel_str(self.stats['channels']) + '\n' # determine which channels are in the plot header += 'Time (s)' data = [] for key, d in self.stats['channels'].items(): if d['plot']: header += ', ' + key # column headings if len(data) == 0: # time (s) data.append(self.lines[int(key[-1])].xData) data.append(self.lines[int(key[-1])].yData) # voltage # data converted to the correct type out_arr = np.array(data).T try: np.savetxt(file_name, out_arr, fmt='%s', delimiter=',', header=header) logger.info('DAQ trace saved to '+file_name) except (PermissionError, FileNotFoundError) as e: logger.error('DAQ controller denied permission to save file: \n'+str(e)) def load_trace(self, file_name=''): """Load data for the current trace from a csv file.""" file_name = file_name if file_name else self.try_browse(file_type='csv(*.csv);;all (*)') if file_name: head = [[],[],[]] # get metadata with open(file_name, 'r') as f: for i in range(3): row = f.readline() if row[:2] == '# ': head[i] = row[2:].replace('\n','').split(', ') # apply the acquisition settings from the file labels = [self.settings.horizontalHeaderItem(i).text() for i in range(self.settings.columnCount())] for i in range(len(head[0])): try: j = labels.index(head[0][i]) self.settings.cellWidget(0,j).setText(head[1][i]) except ValueError: pass self.stats['channels'] = channel_stats(', '.join(head[1][7:])) for i in range(8): # whether to plot or not ch = self.channels.cellWidget(i,0).text() if ch in head[2]: self.channels.cellWidget(i,6).setText('1') self.channels.cellWidget(i,1).setText(self.stats['channels'][ch]['label']) else: self.channels.cellWidget(i,6).setText('0') self.check_settings() # plot the data data = np.genfromtxt(file_name, delimiter=',', dtype=float) if np.size(data) < 2: return 0 # insufficient data to load self.update_trace(data.T[1:]) def save_graph(self, file_name=''): """Save the data accumulated from several runs that's displayed in the graph into a csv file.""" file_name = file_name if file_name else self.try_browse( 'Save File', 'csv (*.csv);;all (*)', QFileDialog.getSaveFileName) if file_name: self.dc.save(file_name, list(self.stats.keys()), list(map(str, self.stats.values()))[:-1] + [channel_str(self.stats['channels'])]) logger.info('DAQ graph saved to '+file_name) def closeEvent(self, event): """Before closing, try to save the config settings to file.""" statstr = "[[" # dictionary of channel names and properties for i in range(self.channels.rowCount()): statstr += ', '.join([self.channels.cellWidget(i,j).text() for j in range(self.channels.columnCount())]) + '],[' self.stats['channels'] = channel_stats(statstr[:-2] + ']') # add all channels to stats self.save_config(self.stats['config_file']) event.accept()
def setupTabs(self): #self.tabs.currentChanged.disconnect(self.currentTabChanged) while(self.tabs.count() > 0): self.tabs.removeTab(0) self.tables = {} allcounters = Counter.findAll() for c in allcounters: tab = QWidget(self.tabs) hl = QHBoxLayout() tab.setLayout(hl) recordings = Recording.findByIdCounter(c.id) tw = QTableWidget(len(recordings), 5) self.tables["%i"%c.id] = tw column_names = ("Id","Counter", "Date", "Value", "Remove ?") tw.setHorizontalHeaderLabels(column_names) # Fill the table with the recordings for i, r in enumerate(recordings): # The id of the recording in the table of recordings item = QTableWidgetItem("{}".format(r.id)) item.setFlags(QtCore.Qt.NoItemFlags) tw.setItem (i, 0, item) # The id of the associated counter item = QTableWidgetItem("{}".format(r.idcounter)) item.setFlags(QtCore.Qt.NoItemFlags) tw.setItem (i, 1, item) # The date when the recording has been made item = QTableWidgetItem(r.date.strftime("%Y-%m-%d %H:%M:%S")) item.setFlags(QtCore.Qt.NoItemFlags) tw.setItem (i, 2, item) # The value can be edited item = QTableWidgetItem("{}".format(r.value)) item.setFlags(QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled) tw.setItem (i, 3, item) but = QPushButton("Remove") but.clicked.connect(partial(self.on_removeClicked, counter_id=c.id, recording_id=r.id)) #item = QTableWidgetItem(but) #tw.setItem(i, 4, but) #tw.setIndexWidget() tw.setCellWidget(i, 4, but) tw.cellChanged.connect(partial(self.on_cellChanged, counter_id=c.id)) # We allow sorting and we sort by decreasing date # to get the most recent recordings at the top tw.setSortingEnabled(True) tw.sortByColumn(2, QtCore.Qt.DescendingOrder) # Ajust the width of the columns to better see the contents tw.resizeColumnsToContents() tw.setFixedWidth(600) hl.addWidget(tw) #### Plot the data canvas = self.plot_data(recordings) hl.addWidget(canvas) self.tabs.addTab(tab,str(c.id) + "-" + c.name)
class TableCatalogOTF(QObject): runCatalog = pyqtSignal(str) def __init__(self): def initGui(): self.tableWidget.setWindowTitle("Catalog OTF") self.tableWidget.setSortingEnabled(False) msgtrans = QCoreApplication.translate("CatalogOTF", "Layer,Total") headers = msgtrans.split(',') self.tableWidget.setColumnCount(len(headers)) self.tableWidget.setHorizontalHeaderLabels(headers) self.tableWidget.resizeColumnsToContents() super(TableCatalogOTF, self).__init__() self.tableWidget = QTableWidget() initGui() def _getRowLayerID(self, layerID): for row in range(self.tableWidget.rowCount()): if layerID == self.tableWidget.cellWidget(row, 0).objectName(): return row return -1 def _changedText(self, layerID, name, column): row = self._getRowLayerID(layerID) if row != -1: wgt = self.tableWidget.cellWidget( row, column) if column == 0 else self.tableWidget.item( row, column) wgt.setText(name) wgt.setToolTip(name) self.tableWidget.resizeColumnsToContents() @pyqtSlot() def _onRunCatalog(self): btn = self.sender() icon = QIcon(joinPath(dirname(__file__), 'cancel_red.svg')) btn.setIcon(icon) layerID = btn.objectName() self.runCatalog.emit(layerID) @pyqtSlot() def _onSelectionChanged(self): layer = self.sender() row = self._getRowLayerID(layer.id()) if row != -1: wgt = self.tableWidget.cellWidget(row, 0) nameIcon = 'check_green.svg' if layer.selectedFeatureCount( ) == 0 else 'check_yellow.svg' icon = QIcon(joinPath(dirname(__file__), nameIcon)) wgt.setIcon(icon) @pyqtSlot("QgsVectorLayer") def insertRow(self, layer): row = self.tableWidget.rowCount() self.tableWidget.insertRow(row) column = 0 # Layer layerName = layer.name() nameIcon = 'check_green.svg' if layer.selectedFeatureCount( ) == 0 else 'check_yellow.svg' icon = QIcon(joinPath(dirname(__file__), nameIcon)) btn = QPushButton(icon, layerName, self.tableWidget) btn.setObjectName(layer.id()) btn.setToolTip(layerName) btn.clicked.connect(self._onRunCatalog) layer.selectionChanged.connect(self._onSelectionChanged) self.tableWidget.setCellWidget(row, column, btn) column = 1 # Total msgtrans = QCoreApplication.translate("CatalogOTF", "None") item = QTableWidgetItem(msgtrans) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.tableWidget.setItem(row, column, item) self.tableWidget.resizeColumnsToContents() @pyqtSlot(str) def removeRow(self, layerID): row = self._getRowLayerID(layerID) if row != -1: self.tableWidget.removeRow(row) @pyqtSlot(str, str) def changedNameLayer(self, layerID, name): self._changedText(layerID, name, 0) @pyqtSlot(str, str) def changedTotal(self, layerID, value): self._changedText(layerID, value, 1) @pyqtSlot(str, bool) def changedIconRun(self, layerID, selected): row = self._getRowLayerID(layerID) if row != -1: btn = self.tableWidget.cellWidget(row, 0) nameIcon = 'check_green.svg' if not selected else 'check_yellow.svg' icon = QIcon(joinPath(dirname(__file__), nameIcon)) btn.setIcon(icon) btn.setEnabled(True) @pyqtSlot(str) def killed(self, layerID): row = self._getRowLayerID(layerID) if row != -1: btn = self.tableWidget.cellWidget(row, 0) btn.setEnabled(False) def widget(self): return self.tableWidget
class ThirdPart(QWizardPage): def __init__(self): super(ThirdPart, self).__init__() self.completed = False self.setTitle(u'第三方库设置') self.setSubTitle(u'需要设置的第三方库') rootLayout = QVBoxLayout() rootLayout.setContentsMargins(14, 20, 10, 20) self.tw_interface = QTableWidget(0, 3) headerLabels = QStringList() headerLabels.append(u'库名') headerLabels.append(u'库路径') headerLabels.append(u'打开') self.tw_interface.setHorizontalHeaderLabels(headerLabels) self.tw_interface.setSelectionBehavior(1) self.tw_interface.setRowCount(0) self.tw_interface.setColumnWidth(0, 200) self.tw_interface.setColumnWidth(1, 280) self.tw_interface.horizontalHeader().setStretchLastSection(True) self.mhlayout = QHBoxLayout() on_new_btn = QPushButton() on_new_btn.setText(u'添加类库') on_new_btn.clicked.connect(self.on_new) on_delete_btn = QPushButton() on_delete_btn.setText(u'删除类库') on_delete_btn.clicked.connect(self.on_delete) space = QSpacerItem(40, 28, QSizePolicy.Expanding) self.mhlayout.addSpacerItem(space) self.mhlayout.addWidget(on_new_btn) self.mhlayout.addWidget(on_delete_btn) rootLayout.addWidget(self.tw_interface) rootLayout.addLayout(self.mhlayout) self.setLayout(rootLayout) self.setStyleSheet(sheetstyle) self.alloneEnv = os.getenv('ALLONEDIR', '../..').replace('\\', '/') def on_new(self): rowIndex = self.tw_interface.rowCount() self.tw_interface.setRowCount(rowIndex + 1) ptn = self.add_button(rowIndex) self.tw_interface.setCellWidget(rowIndex, 2, ptn) def on_delete(self): rowIndex = self.tw_interface.currentRow() if rowIndex != -1: self.tw_interface.removeRow(rowIndex) def updateTable(self, id): filePath = QFileDialog.getOpenFileName(self, "请选择库", self.alloneEnv, "Library(*.lib)") if filePath.isEmpty(): return fileinfo = QFileInfo(filePath) libPath = fileinfo.absoluteDir().absolutePath() libName = fileinfo.baseName() # 支持选择文件后与系统ALLONEDIR比较一下变成相对路径 # 并且能够手动输入相对路径或包含$(ALLONEDIR)的相对路径 env = QString(os.getenv('ALLONEDIR', '../..').replace('\\', '/')) if env.endsWith('/'): env.remove(env.lastIndexOf('/'), 1) if libPath.contains(env): libPath.replace(env, QString('$$ALLONEDIR')) self.tw_interface.setItem(id, 1, QTableWidgetItem(libPath)) self.tw_interface.setItem(id, 0, QTableWidgetItem(libName)) def add_button(self, id): widget = QWidget() fileBtn = QPushButton() fileBtn.setText(u'浏览...') fileBtn.clicked.connect(lambda: self.updateTable(id)) hLayout = QHBoxLayout() hLayout.addWidget(fileBtn) hLayout.setAlignment(Qt.AlignHCenter) hLayout.setContentsMargins(0, 0, 0, 0) widget.setLayout(hLayout) return widget def initializePage(self): super(ThirdPart, self).initializePage() self.tw_interface.setRowCount(len(app.g_configurations.thirdpart_lib)) row = 0 for libinfo in app.g_configurations.thirdpart_lib: twitem0 = QTableWidgetItem(QString(libinfo["libname"])) twitem1 = QTableWidgetItem(QString(libinfo["libpath"])) self.tw_interface.setItem(row, 0, twitem0) self.tw_interface.setItem(row, 1, twitem1) ptn = self.add_button(row) self.tw_interface.setCellWidget(row, 2, ptn) row += 1 def validatePage(self): thirdpart_libs = [] if self.tw_interface.rowCount() > 0: for i in range(self.tw_interface.rowCount()): libinfo = {"libname": "", "libpath": ""} libname = self.tw_interface.item(i, 0).text() libpath = self.tw_interface.item(i, 1).text() #print unicode(libname) #print unicode(libpath) libinfo["libname"] = unicode(libname) libinfo["libpath"] = unicode(libpath) thirdpart_libs.append(libinfo) print thirdpart_libs app.g_configurations.thirdpart_lib = thirdpart_libs return True
class AccessFrontend(ScrollArea): COMPONENT = 'access' LABEL = tr('Access to services') REQUIREMENTS = ('access',) STYLE_ALLOW = "color: white; background-color: white; border: none;" STYLE_DISALLOW = "color: lightGray; background-color: lightGray; border: none;" ICON = ':/icons/Acl.png' def __init__(self, client, parent): ScrollArea.__init__(self) self.client = client self.mainwindow = parent self._modified = False self.__disabled = False self.net_object = QNetObject.getInitializedInstance(self.client) if EDENWALL: self.vpn_object = QOpenVpnObject.getInstance() self.setupWidgets() self.getConfigs() self.getNetworks() # vpn_config is used to check if the VPN config changed or not self.vpn_config = self.getVPNConfig() self.fillTable() self.net_object.registerCallbacks(self.validateNetCfg, self.updateWithNetCfg) if EDENWALL: self.vpn_object.registerCallbacks(self.validateVpnCfg, self.updateWithVpnCfg) self.mainwindow.addToInfoArea(tr("Access interface enabled")) @staticmethod def get_calls(): """ services called at startup (self.mainwindow.init_call) """ return (('access', 'getConfig'),) def getVPNConfig(self): if not EDENWALL: return None vpn = self.vpn_object.getCfg() if not vpn: return None return (vpn.enabled, vpn.protocol, vpn.port, vpn.client_network) def setupWidgets(self): layout = QVBoxLayout(self) self.setLayout(layout) self.icon = QIcon() ALLOW = QPixmap(":/icons-20/status_on.png") self.icon.addPixmap(ALLOW, QIcon.Normal, QIcon.On) DISALLOW = QPixmap(":/icons-20/status_off.png") self.icon.addPixmap(DISALLOW, QIcon.Normal, QIcon.Off) title = QLabel(u"<H1>%s</H1>" % tr("Access to services")) layout.addWidget(title) self.table = QTableWidget() self.table.setSelectionMode(QAbstractItemView.NoSelection) layout.addWidget(self.table) def isModified(self): return self._modified def isValid(self): if self.__disabled: return True valid, errmsg = self.access_cfg.isValidWithMsg() if not valid: self.error_message = errmsg return valid def setModified(self, modif=True): if self.__disabled: self._modified = False return self._modified = modif if modif: self.mainwindow.setModified(self, True) def resetConf(self): if self.__disabled: return self.getConfigs() self.getNetworks() self.fillTable() def __disable(self, reason): if self.__disabled: return self.__disabled = True self.mainwindow.addToInfoArea( tr("The Access to services interface is disabled."), COLOR_ERROR) self.mainwindow.addToInfoArea(reason, COLOR_ERROR) self.close() raise NuConfModuleDisabled(reason) def getConfigs(self): if self.__disabled: return try: data = self.mainwindow.init_call('access', 'getConfig') except RpcdError: self.__disable(tr("Could not get Access to services configuration.")) return if data is None: self.access_cfg = AccessConf.defaultConf() else: self.access_cfg = AccessConf.deserialize(data) def _getNetworks(self, netcfg): return [(interface.system_name, network) for interface, network in netcfg.iterKnownNetworks()] def getNetworks(self): if self.__disabled: return netcfg = QNetObject.getInstance().netcfg if netcfg is None: self.networks = () self.mainwindow.addToInfoArea( tr("The access interface could not load the network configuration"), COLOR_ERROR ) return # list of (interface, network) where interface (str) is the system # name, and network (IPy.IP object) is the network address # (eg. IP('192.168.0.0/24') self.networks = self._getNetworks(netcfg) self.networks += list(self.access_cfg.custom_networks) self.networks.sort() def fillTable(self): if self.__disabled: self.table.clear() return services = list(self.access_cfg.permissions) self.table.clear() # (interface (str), network (IPy), ip version (int)) => row (int) # Don't use (interface, network) because of a bug in IPy < 0.70: # IP('0.0.0.0/0') and IP('::/0') are considered as equal self.net_to_row = {} component_to_name = ComponentToName() self.table.setSortingEnabled(False) self.table.setRowCount(len(self.networks)) self.setVerticalHeaders() self.table.setColumnCount(len(services)) self.table.setHorizontalHeaderLabels([component_to_name.display_name(service) for service in services]) self.table.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents) for irow, interface_network in enumerate(self.networks): self.setRow(interface_network, irow) for icol, service in enumerate(self.access_cfg.permissions): allow = interface_network in self.access_cfg.permissions[service] self.createService(irow, icol, service, interface_network, allow) def getRow(self, interface_network, pop=False): interface, network = interface_network key = (interface, network, network.version()) if pop: return self.net_to_row.pop(key) else: return self.net_to_row[key] def setRow(self, interface_network, row): interface, network = interface_network key = (interface, network, network.version()) self.net_to_row[key] = row def setVerticalHeaders(self): labels = [self.netLabel(interface, network) for interface, network in self.networks] self.table.setVerticalHeaderLabels(labels) def saveConf(self, message): data = self.access_cfg.serialize(downgrade=True) self.client.call("access", 'setConfig', message, data) self.setModified(False) def changeService(self, col, service, interface_network): row = self.getRow(interface_network) self.setModified(True) button = self.table.cellWidget(row, col) if button.isChecked(): self.access_cfg.permissions[service].add(interface_network) button.setStyleSheet(self.STYLE_ALLOW) else: try: self.access_cfg.permissions[service].remove(interface_network) except KeyError: pass button.setStyleSheet(self.STYLE_DISALLOW) def appendNetwork(self, interface_network, close_all_ports=False): row = self.table.rowCount() self.table.insertRow(row) self.networks.append(interface_network) self.setRow(interface_network, row) interface, network = interface_network for icol, service in enumerate(self.access_cfg.permissions): if (not close_all_ports) \ and (service in OPEN_BY_DEFAULT) \ and (network not in CLOSED_NETWORKS): allow = True self.access_cfg.permissions[service].add(interface_network) else: allow = interface_network in self.access_cfg.permissions[service] self.createService(row, icol, service, interface_network, allow) def removeNetwork(self, interface_network): index = self.getRow(interface_network, pop=True) self.table.removeRow(index) network = self.networks[index] for service, networks in self.access_cfg.permissions.iteritems(): try: networks.remove(network) except KeyError: pass del self.networks[index] for key, row in self.net_to_row.iteritems(): if row > index: self.net_to_row[key] -= 1 # callback used to update the table on network modification def updateWithNetCfg(self, deleted_nets, added_nets): if not(deleted_nets or added_nets): return # delete for key in deleted_nets: self.removeNetwork(key) # add new for interface_network in added_nets: self.appendNetwork(interface_network, close_all_ports=True) # modify and update self.setVerticalHeaders() self.setModified(True) def createService(self, row, col, service, interface_network, allow): button = QPushButton(self.icon, u'') button.setCheckable(True) button.setFlat(True) button.setAutoFillBackground(True) if allow: style = self.STYLE_ALLOW else: style = self.STYLE_DISALLOW button.setStyleSheet(style) button.setFocusPolicy(Qt.NoFocus) self.mainwindow.writeAccessNeeded(button) self.connect(button, SIGNAL('clicked()'), partial(self.changeService, col, service, interface_network)) self.table.setCellWidget(row, col, button) # with PyQt 4.4.2, table.setCellWidget(button) changes # the button's state (bug fixed in PyQt 4.4.4) button.setChecked(allow) # callback used when the networks are modified def validateNetCfg(self): netcfg = QNetObject.getInstance().netcfg previous_nets = set(self.networks) - set(self.access_cfg.custom_networks) new_networks = self._getNetworks(netcfg) new_networks = set(new_networks) not_in_both = previous_nets ^ new_networks deleted_nets = not_in_both & previous_nets added_nets = not_in_both & new_networks return True, deleted_nets, added_nets def validateVpnCfg(self): """ always accept modifications """ return True, self.getVPNConfig() def updateWithVpnCfg(self, new_config): if self.vpn_config == new_config: return # anything changed, access has to reapply the new config self.setModified() self.vpn_config = new_config # get old/new key config = self.vpn_object.getCfg() if self.access_cfg.custom_networks: old_key = self.access_cfg.custom_networks[0] else: old_key = None if config.enabled: network = config.client_network try: network = IP(network) except ValueError: # ignore invalid network: vpn check will raise an error return new_key = (OPENVPN_INTERFACE, network) else: new_key = None # no change? exit if old_key == new_key: return # create/delete vpn custom network if old_key: self.removeNetwork(old_key) if new_key: self.access_cfg.custom_networks = [new_key] self.appendNetwork(new_key) else: self.access_cfg.custom_networks = [] self.setVerticalHeaders() def netLabel(self, interface, network): """ return label for network """ interface_label = interface network_label = str(network) network = IP(network) netcfg = QNetObject.getInstance().netcfg try: interface = netcfg.getInterfaceBySystemName(interface) interface_label = interface.user_label network = netcfg.getNet(network) network_label = network.displayName() except NoMatch: pass return tr("%s: %s") % (interface_label, network_label)