class Window(QMainWindow): def __init__(self,parent = None): QMainWindow.__init__(self,parent) self.resize(1024,768) self.setWindowTitle("Sabel") self.setWindowIcon(Icons.sabel) self.centralwidget = QWidget(self) self.horizontalLayout = QHBoxLayout(self.centralwidget) self.horizontalLayout.setMargin(0) self.cmdList = config.cmds() self.paramList = config.params() '''A.Editor TabWidget''' '''This parent is for findbar and vertical layout''' self.editorLayoutWidget = QWidget(self) self.editorLayoutWidget.setMinimumWidth(800) self.tabWidget = EditorTab(self) self.editorLayout = QVBoxLayout(self.editorLayoutWidget) self.editorLayout.setMargin(0) self.editorLayout.addWidget(self.tabWidget) "0.Style Layout" self.styleLayoutWidget = QFrame() self.styleLayoutWidget.setFrameShape(QFrame.StyledPanel) self.styleLayout = QHBoxLayout(self.styleLayoutWidget) self.styleTest = QPushButton(self.styleLayoutWidget) self.styleTest.setText("Change Styles") self.styleTest.clicked.connect(self.changeStyleSheet) self.popWidget = Popup(self.styleLayoutWidget) self.styleLayout.addWidget(self.styleTest) self.styleLayout.addWidget(self.popWidget) self.styleLayout.setMargin(0) self.editorLayout.addWidget(self.styleLayoutWidget) self.styleLayoutWidget.hide() "1.Find Layout" self.findLayoutWidget = QFrame() self.findLayoutWidget.setFrameShape(QFrame.StyledPanel) self.findLayout = QHBoxLayout(self.findLayoutWidget) self.lineEdit = QLineEdit(self.findLayoutWidget) self.lineEdit_2 = QLineEdit(self.findLayoutWidget) self.findClose = QPushButton(self.findLayoutWidget) self.findClose.setIcon(Icons.close_view) self.findClose.setFlat(True) self.findClose.clicked.connect(self.findBarShow) self.find = QPushButton(self.findLayoutWidget) self.find.setText("Find") self.find.clicked.connect(self.findCurrentText) self.replacefind = QPushButton(self.findLayoutWidget) self.replacefind.setText("Replace/Find") self.replacefind.clicked.connect(self.replaceFindText) self.replace = QPushButton(self.findLayoutWidget) self.replace.setText("Replace") self.replace.clicked.connect(self.replaceCurrentText) self.replaceAll = QPushButton(self.findLayoutWidget) self.replaceAll.setText("Replace All") self.replaceAll.clicked.connect(self.replaceAllText) self.caseSensitive = QToolButton(self.findLayoutWidget) self.caseSensitive.setIcon(Icons.font) self.caseSensitive.setCheckable(True) self.wholeWord = QToolButton(self.findLayoutWidget) self.wholeWord.setText("ww") self.wholeWord.setCheckable(True) self.regex = QToolButton(self.findLayoutWidget) self.regex.setText("re") self.regex.setCheckable(True) self.backward = QToolButton(self.findLayoutWidget) self.backward.setText("bk") self.backward.setCheckable(True) self.backward.setDisabled(True) self.findLayout.addWidget(self.findClose) self.findLayout.addWidget(self.find) self.findLayout.addWidget(self.lineEdit) self.findLayout.addWidget(self.lineEdit_2) self.findLayout.addWidget(self.caseSensitive) self.findLayout.addWidget(self.wholeWord) self.findLayout.addWidget(self.regex) self.findLayout.addWidget(self.backward) self.findLayout.addWidget(self.replacefind) self.findLayout.addWidget(self.replace) self.findLayout.addWidget(self.replaceAll) self.findLayout.setMargin(0) self.findLayoutWidget.setMaximumHeight(25) self.editorLayout.addWidget(self.findLayoutWidget) self.findLayoutWidget.hide() '''B.Designer''' '''This parent is for widgetsbar and design layout''' self.designerLayoutWidget = QWidget(self) self.designerLayoutWidget.setMinimumWidth(800) self.designerWidget = Screen(self) self.designerLayoutWidget.hide() self.designerLayout = QVBoxLayout(self.designerLayoutWidget) self.designerLayout.setMargin(0) self.designerLayout.addWidget(self.designerWidget) '''C.Level Editor''' '''This parent is for spritesheets and level layout''' self.levelLayoutWidget = QWidget(self) self.levelLayoutWidget.setMinimumWidth(800) self.levelWidget = Level(self) self.levelLayoutWidget.hide() self.levelLayout = QVBoxLayout(self.levelLayoutWidget) self.levelLayout.setMargin(0) self.levelLayout.addWidget(self.levelWidget) '''D.Explorer TabWidget''' self.explorerTabWidget = TreeTab(self) #self.explorerTabWidget.setMaximumWidth(200) '''1.Project Tree''' self.tab_5 = QWidget() #self.tab_5.setMaximumWidth(200) self.VerticalLayout_2 = QVBoxLayout(self.tab_5)#QHBoxLayout(self.tab_5) self.VerticalLayout_2.setMargin(0) self.treeWidget = ProjectTree(self.tab_5) #self.treeWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) #self.treeWidget.horizontalScrollBar().show() self.VerticalLayout_2.addWidget(self.treeWidget) '''2.Outline Tree''' self.tab_2 = QWidget() #self.tab_2.setMaximumWidth(200) self.VerticalLayout_3 = QVBoxLayout(self.tab_2) self.VerticalLayout_3.setMargin(0) self.outlineWidget = OutlineTree(self.tab_2) self.outlineWidget.itemDoubleClicked.connect(self.gotoLine) self.VerticalLayout_3.addWidget(self.outlineWidget) '''E.Output TabWidget''' self.outputTabWidget = OutputTab(self) self.tabWidget.currentChanged.connect(self.fileChanged) self.explorerTabWidget.currentChanged.connect(self.closeExplorer) self.outputTabWidget.currentChanged.connect(self.closeConsole) self.tabWidget.setTabsClosable(True) self.tabWidget.setTabShape(0) '''1.Output layout''' #must check self.tab_6 = QWidget() self.horizontalLayout_2 = QVBoxLayout(self.tab_6) self.horizontalLayout_2.setMargin(0) self.textEdit = QTextEdit() self.inputLayout = QHBoxLayout() self.inputLayout.setMargin(0) self.fileButton = QPushButton() self.fileButton.setText("File") self.fileButton.clicked.connect(self.getFile) self.runButton = QPushButton() self.runButton.setFlat(True) self.runButton.setIcon(Icons.go) self.combo = QComboBox() self.combo.setFixedWidth(100) self.comboAdd = QPushButton() self.comboAdd.setIcon(Icons.add) self.comboAdd.setFlat(True) self.comboAdd.clicked.connect(self.addCmd) self.comboDel = QPushButton() self.comboDel.setIcon(Icons.close_view) self.comboDel.setFlat(True) self.comboDel.clicked.connect(self.delCmd) self.combo2 = QComboBox() self.combo2.setFixedWidth(500) self.combo2Add = QPushButton() self.combo2Add.setIcon(Icons.add) self.combo2Add.setFlat(True) self.combo2Add.clicked.connect(self.addParam) self.combo2Del = QPushButton() self.combo2Del.setIcon(Icons.close_view) self.combo2Del.setFlat(True) self.combo2Del.clicked.connect(self.delParam) if(self.checkHasValue(self.cmdList)): for cmd in self.cmdList: self.combo.addItem(cmd) else: self.cmdList = [] if(self.checkHasValue(self.paramList)): for param in self.paramList: self.combo2.addItem(param) else: self.paramList = [] self.horizontalLayout_2.addWidget(self.textEdit) self.inputLayout.addWidget(QLabel("<b>Command:</b>")) self.inputLayout.addWidget(self.combo) self.inputLayout.addWidget(self.comboAdd) self.inputLayout.addWidget(self.comboDel) self.inputLayout.addWidget(QLabel("<b>Parameters:</b>")) self.inputLayout.addWidget(self.combo2) self.inputLayout.addWidget(self.combo2Add) self.inputLayout.addWidget(self.combo2Del) self.inputLayout.addWidget(self.fileButton) self.inputLayout.addWidget(self.runButton) self.horizontalLayout_2.addLayout(self.inputLayout) '''2.Error Layout''' self.tab_7 = QWidget() self.horizontalLayout_4 = QHBoxLayout(self.tab_7) self.horizontalLayout_4.setMargin(0) self.errorTree = ErrorTree(self.tab_7) self.errorTree.itemDoubleClicked.connect(self.errorLine) self.horizontalLayout_4.addWidget(self.errorTree) '''TabWidgets tabs''' #self.designerWidget.addTab(QWidget(self),"") #self.designerWidget.setTabIcon(0,Icons.close_view) #self.levelWidget.addTab(QWidget(self),"") #self.levelWidget.setTabIcon(0,Icons.close_view) self.explorerTabWidget.addTab(self.tab_5,"Projects") self.explorerTabWidget.addTab(self.tab_2,"Outline") self.explorerTabWidget.addTab(QWidget(self),"") self.explorerTabWidget.setTabIcon(0,Icons.cprj) self.explorerTabWidget.setTabIcon(1,Icons.envvar) self.explorerTabWidget.setTabIcon(2,Icons.close_view) self.outputTabWidget.addTab(self.tab_7,"Error") self.outputTabWidget.addTab(self.tab_6,"Output") self.outputTabWidget.addTab(QWidget(self),"") self.outputTabWidget.setTabIcon(0,Icons.error) self.outputTabWidget.setTabIcon(1,Icons.console_view) self.outputTabWidget.setTabIcon(2,Icons.close_view) '''Splitters''' self.split1 = QSplitter(Qt.Horizontal) self.split1.addWidget(self.explorerTabWidget) self.split1.addWidget(self.editorLayoutWidget) self.split1.addWidget(self.designerLayoutWidget) self.split1.addWidget(self.levelLayoutWidget) #self.split1.addWidget(self.tab_5) self.split2 = QSplitter(Qt.Vertical) self.split2.addWidget(self.split1) self.split2.addWidget(self.outputTabWidget) self.horizontalLayout.addWidget(self.split2) '''Status Bar''' self.statusbar = QStatusBar(self) self.aboutButton = QPushButton(self) self.aboutButton.setFlat(True) self.aboutButton.setIcon(Icons.anchor) self.aboutButton.clicked.connect(self.about) self.expButton = QPushButton(self) self.expButton.setFlat(True) self.expButton.setIcon(Icons.prj) self.expButton.clicked.connect(self.exp) self.cmdButton = QPushButton(self) self.cmdButton.setFlat(True) self.cmdButton.setIcon(Icons.console_view) self.cmdButton.clicked.connect(self.cmd) self.cmdButton.setShortcut('Ctrl+D') self.imgButton = QPushButton(self) self.imgButton.setFlat(True) self.imgButton.setIcon(Icons.color_palette) self.imgButton.clicked.connect(self.design) self.imgButton.setShortcut('Ctrl+I') self.findButton = QPushButton(self) self.findButton.setFlat(True) self.findButton.setIcon(Icons.find) self.findButton.setShortcut("Ctrl+F") self.findButton.clicked.connect(self.findBarShow) ''' self.zoominButton = QPushButton(self) self.zoominButton.setFlat(True) self.zoominButton.setIcon(Icons.zoomplus) self.zoominButton.clicked.connect(self.zoomin) self.zoomoutButton = QPushButton(self) self.zoomoutButton.setFlat(True) self.zoomoutButton.setIcon(Icons.zoomminus) self.zoomoutButton.clicked.connect(self.zoomout) ''' '''Status Text,Line Text, Progress Bar and Stop Button''' self.statusText = QLabel("Writable") #self.statusText.setAlignment(Qt.AlignCenter) self.statusText.setFixedWidth(200) self.lineText = QLabel("") self.lineText.setFixedWidth(50) self.progressbar = QProgressBar() self.progressbar.setMinimum(0) self.progressbar.setMaximum(100) self.stopButton = QPushButton(self) self.stopButton.setFlat(True) self.stopButton.setIcon(Icons.stop) self.stopButton.clicked.connect(self.forceStop) self.progressbar.hide() self.stopButton.hide() self.temp = False self.progress = False self.counter = 0 '''Adding all widgets to Status Bar''' self.statusbar.addWidget(self.aboutButton) self.statusbar.addWidget(self.expButton) self.statusbar.addWidget(self.cmdButton) self.statusbar.addWidget(self.imgButton) self.statusbar.addWidget(self.findButton) #self.statusbar.addWidget(QWidget(self)) #self.statusbar.addWidget(self.zoominButton) #self.statusbar.addWidget(self.zoomoutButton) self.statusbar.addWidget(self.statusText) self.statusbar.addWidget(self.lineText) self.statusbar.addWidget(self.progressbar) self.statusbar.addWidget(self.stopButton) #self.statusbar.setFixedHeight(18) ''''Initializing Coloring Style''' self.initEditorStyle() self.initStyleSheet() '''Adding Cental Widget and Status Bar''' self.setCentralWidget(self.centralwidget) self.setStatusBar(self.statusbar) self.textEdit.setReadOnly(True) def initStyleSheet(self): import stylesheet self.setStyleSheet(stylesheet.mainstyl) self.tabWidget.tabBar().setStyleSheet(stylesheet.stletabb) self.explorerTabWidget.tabBar().setStyleSheet(stylesheet.stletabb) self.outputTabWidget.tabBar().setStyleSheet(stylesheet.stletabb) self.popWidget.setStyleSheet(stylesheet.popbg) self.popWidget.hide() ''' This is for changing the palette/window colors to Theme ''' def initEditorStyle(self): pass #editStyle = config.readStyle() #print editStyle #pal = QPalette(self.explorerTabWidget.palette()) #print pal.color(QPalette.Base).name() #print pal.color(QPalette.Window).name() #pal.setColor(QPalette.Base,self.colorStyle.paper) #pal.setColor(QPalette.Text,self.colorStyle.color) #self.explorerTabWidget.setPalette(pal) #self.outputTabWidget.setPalette(pal) ''' This is only for testing dont know if it works for builds ''' def changeStyleSheet(self): ''' Dynamically load the changed stylesheet.py and load the modules and change the style at runtime saves countless deploys ''' import imp foo = imp.load_source('stletabb', workDir+"/stylesheet.py") #print foo.stletabb #self.setStyleSheet(stylesheet.mainstyl) self.tabWidget.tabBar().setStyleSheet(foo.stletabb) self.popWidget.setStyleSheet(foo.popbg) if(self.popWidget.isHidden()): self.popWidget.showPopup() def build_project(self): #current_file = self.files[self.tabWidget.currentIndex()] prj = self.treeWidget.getProject() if(prj != None): self.treeWidget.build(prj) def run_project(self): #current_file = self.files[self.tabWidget.currentIndex()] prj = self.treeWidget.getProject()#current_file) if(prj != None): self.treeWidget.run(prj) def forceStop(self): self.ant.kill() self.progressStop() def kill(self): self.deleteLater() #-----------------------------------------------------------------------------------# # Menu Actions Functions # #-----------------------------------------------------------------------------------# def run(self): if(config.mode() == 0): self.sq.run() elif(config.mode() == 1): self.adb.run() elif(config.mode() == 2): self.ios.run() elif(config.mode() == 3): self.c.run() def setMode(self, action): if(action.text() == "Squ"): config.setMode(0) self.toolBar.action_Build.setEnabled(False) self.toolBar.action_Run.setEnabled(False) elif(action.text() == "Emo"): config.setMode(1) self.toolBar.action_Build.setEnabled(True) self.toolBar.action_Run.setEnabled(True) elif(action.text() == "Android"): config.setMode(2) self.toolBar.action_Build.setEnabled(True) self.toolBar.action_Run.setEnabled(True) elif(action.text() == "ios"): config.setMode(3) self.toolBar.action_Build.setEnabled(False) self.toolBar.action_Run.setEnabled(False) def openCommand(self): text, ok = QInputDialog.getText(self, 'Run Command', 'Command:') cmd = str(text) if ok and cmd != "": import subprocess subprocess.Popen(cmd) def about(self): form = DialogAbout(self) def todo(self): form = DialogTodo(self) form.show() def help(self): QMessageBox.about(self,"Help","This is about all The Help that i can Give you now") def full(self): if not self.isFull: self.setWindowState(Qt.WindowFullScreen) self.isFull = True else: self.setWindowState(Qt.WindowMaximized) self.isFull = False def android(self): form = DialogAndroid(self) form.show() def antt(self): form = DialogAnt(self) form.show() def squirrel(self): form = DialogSquirrel(self) form.show() def findBarShow(self): if(self.findLayoutWidget.isHidden()): self.findLayoutWidget.show() else: self.findLayoutWidget.hide() def exp(self): if(self.explorerTabWidget.isHidden()): self.explorerTabWidget.show() else: self.explorerTabWidget.hide() def cmd(self): if(self.outputTabWidget.isHidden()): self.outputTabWidget.show() else: self.outputTabWidget.hide() def editor(self): if(self.editorLayoutWidget.isHidden()): self.editorLayoutWidget.show() self.levelLayoutWidget.hide() self.designerLayoutWidget.hide() def design(self): if(self.designerLayoutWidget.isHidden()): self.designerLayoutWidget.show() self.editorLayoutWidget.hide() self.levelLayoutWidget.hide() else: self.designerLayoutWidget.hide() self.editorLayoutWidget.show() def level(self): if(self.levelLayoutWidget.isHidden()): self.levelLayoutWidget.show() self.editorLayoutWidget.hide() self.designerLayoutWidget.hide() else: self.levelLayoutWidget.hide() self.editorLayoutWidget.show() def closeDesigner(self,no): pass ''' if(no == self.tiler.closeIndex()): if(self.tiler.isHidden()): self.tiler.show() else: self.tiler.setCurrentIndex(1) self.tiler.hide() ''' '''The current Changed idx of outputTabWidget is passed to this a param''' def closeConsole(self,no = 2): if(no == 2): if(self.outputTabWidget.isHidden()): self.outputTabWidget.show() else: self.outputTabWidget.setCurrentIndex(1) self.outputTabWidget.hide() def popOutput(self): if(self.outputTabWidget.isHidden()): self.outputTabWidget.show() self.outputTabWidget.setCurrentIndex(1) def popError(self): if(self.outputTabWidget.isHidden()): self.outputTabWidget.show() self.outputTabWidget.setCurrentIndex(0) '''The current Changed idx of explorerTabWidget is passed to this a param''' def closeExplorer(self,no = 2): if(no == 2): if(self.explorerTabWidget.isHidden()): self.explorerTabWidget.show() else: self.explorerTabWidget.setCurrentIndex(0) self.explorerTabWidget.hide() elif(no == 1): self.fileChanged(no) ''' This is to refresh the outline widget''' def fileChanged(self,no): if(self.explorerTabWidget.currentIndex() == 1): edt = self.tabWidget.widget(self.tabWidget.currentIndex()) source = edt.text() self.outlineWidget.parseText(source) def statusSaving(self): self.statusText.setText("Saving") def statusParsing(self): self.statusText.setText("Parsing") def statusWriting(self): self.statusText.setText("Writable") def statusRunning(self): self.statusText.setText("Running") def statusStopping(self): self.statusText.setText("Stopping") def statusCommand(self): self.statusText.setText("Command") def statusBuilding(self): self.statusText.setText("Building") def statusInstalling(self): self.statusText.setText("Installing") def statusCleaning(self): self.statusText.setText("Cleaning") def statusCreating(self): self.statusText.setText("Creating") def progressStart(self): self.progress == True self.temp == True if(self.progressbar.isHidden()): self.progressbar.show() if(self.stopButton.isHidden()): self.stopButton.show() self.progressbar.setValue(1) def progressStop(self): self.progress == False self.temp == False self.progressbar.setValue(100) if not(self.progressbar.isHidden()): self.progressbar.hide() if not(self.stopButton.isHidden()): self.stopButton.hide() def progressUpdate(self): if(self.progress): if(self.temp): self.counter += 1 self.progressbar.setValue(self.counter) if(self.counter == 100): self.temp = False else: self.counter -= 1 self.progressbar.setValue(self.counter) if(self.counter == 0): self.temp = True #-----------------------------------------------------------------------------------# # Editor Functions # #-----------------------------------------------------------------------------------# '''Search and Replace Functions''' def findCurrentText(self): edt = self.tabWidget.widget(self.tabWidget.currentIndex()) edt.findText(self.lineEdit.text(),self.regex.isChecked(),self.caseSensitive.isChecked(),self.wholeWord.isChecked(),self.backward.isChecked()) def replaceCurrentText(self): edt = self.tabWidget.widget(self.tabWidget.currentIndex()) edt.replaceText(self.lineEdit_2.text()) def replaceFindText(self): edt = self.tabWidget.widget(self.tabWidget.currentIndex()) edt.replaceText(self.lineEdit_2.text()) self.findCurrentText() def replaceAllText(self): edt = self.tabWidget.widget(self.tabWidget.currentIndex()) while(edt.findText(self.lineEdit.text(),self.regex.isChecked(),self.caseSensitive.isChecked(),self.wholeWord.isChecked(),self.backward.isChecked())): edt.replaceText(self.lineEdit_2.text()) def errorLine(self,error): index = self.tabWidget.currentIndex() edt = self.tabWidget.widget(index) '''To prevent File item double clicking''' if(error.isFile() == False): edt.setLine(error.line) '''Font Functions''' def zoomin(self): pass #for i in range(len(self.files)): # self.tabWidget.widget(i).zoomin() def zoomout(self): pass #for i in range(len(self.files)): # self.tabWidget.widget(i).zoomout() ''' Must implement Lexer ''' def setLexer(self, action): pass #print action.text() def setApi(self, action): #print action.text() for i in range(len(self.files)): #not QString self.tabWidget.widget(i).setApi(str(action.text())) def setFont(self,font): config.setFontName(str(font.family())) for i in range(len(self.files)): self.tabWidget.widget(i).setNewFont(font) def setFontSize(self,idx): fontSize = idx+1 config.setFontSize(fontSize) for i in range(len(self.files)): self.tabWidget.widget(i).setFontSize() def gotoLine(self,item): edt = self.tabWidget.widget(self.tabWidget.currentIndex()) edt.setLine(item.line) def updateLine(self,no,col): self.lineText.setText(str(no)+" : "+str(col)) def setMargin(self): mar = config.margin() if(mar == 0): config.setMargin(1) for i in range(len(self.files)): self.tabWidget.widget(i).setMargin(1) else: config.setMargin(0) for i in range(len(self.files)): self.tabWidget.widget(i).setMargin(0) ''' Toggle ''' def setIndent(self): indent = config.indent() if(indent == 0): config.setIndent(1) for i in range(len(self.files)): self.tabWidget.widget(i).setIndent(1) else: config.setIndent(0) for i in range(len(self.files)): self.tabWidget.widget(i).setIndent(0) ''' Toggle ''' def setWhiteSpace(self): white = config.whiteSpace() if(white == 0): config.setWhiteSpace(1) for i in range(len(self.files)): self.tabWidget.widget(i).setWhitespaceVisibility(True) else: config.setWhiteSpace(0) for i in range(len(self.files)): self.tabWidget.widget(i).setWhitespaceVisibility(False) ''' Toggle ''' def setEndLine(self): for i in range(len(self.files)): edt = self.tabWidget.widget(i) edt.setEolVisibility(not edt.eolVisibility()) def setEncoding(self, action): if(action.text() == "Ascii"): config.setAscii() for i in range(len(self.files)): self.tabWidget.widget(i).setUtf8(False) elif(action.text() == "Unicode"): config.setUnicode() for i in range(len(self.files)): self.tabWidget.widget(i).setUtf8(True) def setThreshold(self,val): config.setThresh(val) for i in range(len(self.files)): #print i self.tabWidget.widget(i).setThreshold(val) def setTabWidth(self,val): config.setTabWidth(val) for i in range(len(self.files)): #print i self.tabWidget.widget(i).setTabWidth(val) '''style Functions''' #-----------------------------------------------------------------------------------# # Command Functions # #-----------------------------------------------------------------------------------# def getFile(self): self.browsedialog = DialogBrowse(self) self.browsedialog.tree.itemDoubleClicked.connect(self.getName) self.browsedialog.show() def getName(self,item): if(item.isFile()): self.browsedialog.accept() fname = item.getPath() if not (fname == ""): index = self.combo2.currentIndex() text = str(self.combo2.itemText(index))+" "+fname self.combo2.setItemText(index,text) self.paramList.pop(index) self.paramList.insert(index,text) config.setParam(self.paramList) def addCmd(self,index): text, ok = QInputDialog.getText(self, 'Add Command', 'Command:') if(ok): if(str(text) != ''): cmd = str(text).upper() self.cmdList.append(cmd) #print self.cmdList self.combo.addItem(cmd) config.setCmd(self.cmdList) config.setParam(self.paramList) def delCmd(self): index = self.combo.currentIndex() self.combo.removeItem(index) self.cmdList.pop(index) #print self.cmdList config.setCmd(self.cmdList) def addParam(self,index): text, ok = QInputDialog.getText(self, 'Add Parameters', 'Params:') if(ok): if(str(text) != ''): param = str(text) self.paramList.append(param) self.combo2.addItem(param) config.setParam(self.paramList) def delParam(self): index = self.combo2.currentIndex() self.combo2.removeItem(index) self.paramList.pop(index) config.setParam(self.paramList) def checkHasValue(self,list): if(list != None and len(list) != 0): return True else: return False
class TabDownloads(QWidget): instance = None def __init__(self, search, parent=None): QWidget.__init__(self, parent) # Load de l'UI PyQt4.uic.loadUi('ui/downloads.ui', self) # Ajout de la progressBar self.progressBar = QProgressBar() self.progressBar.setMinimum(0) self.progressBar.setMaximum(100) self.progressBar.hide() self.HLayout = QBoxLayout(QBoxLayout.LeftToRight) self.HLayout.addWidget(self.progress_label) self.HLayout.addWidget(self.progressBar) self.formLayout_3.addRow(self.HLayout) # Vars TabDownloads.instance = self self.downloads = Downloads() self.pos = None self.download_looked = None # Affichage custom #self.downloads_table.setStyleSheet(\ # "QTableView::item{ \ # border-right-style:solid; \ # border-width:0.5; \ # border-color: #9B9B9B; \ # }") # On autorise la creation de menu contextuel self.setContextMenuPolicy(Qt.CustomContextMenu) # Signaux self.customContextMenuRequested.connect(self.contextMenu) self.downloads_table.itemClicked.connect(self.show_info_download) # Init self.load_downloads() # On remove les finis et en erreur si Config.clean_dl_list = 1 if Configuration.clean_dl_list == 1: self.clean_list_Action() ######################################################### # On désactive les boutons qui sont pas encore implantés self.button_stop_all.setEnabled(False) self.button_resume_all.setEnabled(False) ######################################################### def load_downloads(self): import xml.sax parser = xml.sax.make_parser() parser.setContentHandler(AnalyseDownloads(self.add_downloads)) try: for line in open(os.path.expanduser("~") + '/.pyrex/downloads.xml'): parser.feed(line) self.downloads.save() except: pass def add_download(self, download): # Avant de filtrer on écrit le download #self.downloads.append(download) #TODO : pour quand on pourra resume, décommenter la ligne et ramener le save ici if download.state == 4 or download.progress == 0: rows = self.downloads_table.rowCount() self.downloads_table.insertRow(rows) self.downloads_table.setItem(rows, 0, MyQTableWidgetItem(download.file_share.name, download)) self.downloads_table.setItem(rows, 1, QTableWidgetItem(download.get_progress())) self.downloads_table.setItem(rows, 2, QTableWidgetItem(download.state_str)) self.downloads_table.setItem(rows, 3, QTableWidgetItem("0 ko/s")) self.downloads_table.setItem(rows, 5, QTableWidgetItem(download.date.strftime('%d/%m/%y'))) self.downloads.append(download) # TODO : à modifier probablement quand on aura le resume pour les downloads if download.state != 4 and download.progress == 0: # Signaux download.progressModified.connect(self.update_progress) download.stateChanged.connect(self.update_state) download.downloadFinished.connect(self.download_finished) download.speedModified.connect(self.update_speed) # On save self.downloads.save() def add_downloads(self, downloads): for download in downloads: self.add_download(download) def update_progress(self, download): item = self.downloads_table.findItems(download.file_share.name, Qt.MatchExactly)[0] row = self.downloads_table.row(item) self.downloads_table.item(row, 1).setText(download.get_progress()) # On update la barre de progression si on est en train de regarder un download if self.download_looked == download: self.progressBar.setValue(int(download.progress)) def update_speed(self, download): item = self.downloads_table.findItems(download.file_share.name, Qt.MatchExactly)[0] row = self.downloads_table.row(item) self.downloads_table.item(row, 3).setText(convert_speed_str(download.speed)) def update_state(self, download): item = self.downloads_table.findItems(download.file_share.name, Qt.MatchExactly)[0] row = self.downloads_table.row(item) self.downloads_table.item(row, 2).setText(download.state_str) # On save self.downloads.save() def download_finished(self, download): if download.read_bytes == download.file_share.size: item = self.downloads_table.findItems(download.file_share.name, Qt.MatchExactly)[0] row = self.downloads_table.row(item) self.downloads_table.item(row, 2).setText("Finished!") self.downloads_table.item(row, 3).setText("") # On save self.downloads.save() else: print "Erreur dans le téléchargement" item = self.downloads_table.findItems(download.file_share.name, Qt.MatchExactly)[0] row = self.downloads_table.row(item) self.downloads_table.item(row, 2).setText("Error : invalid size :(") self.downloads_table.item(row, 3).setText("") # On save self.downloads.save() def contextMenu(self, pos): self.pos = pos menu = QMenu() # Actions forceAction = menu.addAction("Forcer la reprise") continueAction = menu.addAction("Reprise") pauseAction = menu.addAction("Pause") openAction = menu.addAction("Ouvrir") abortAction = menu.addAction("Annuler") supprListeAction = menu.addAction("Supprimer de la liste") supprDiskAction = menu.addAction("Supprimer de la liste et du disque") copyAction = menu.addAction("Copier l'URL") searchAction = menu.addAction("Rechercher des fichiers similaires") # On désactive les actions s'il n'y a pas de downloads if self.downloads == [] or self.downloads_table.currentRow() < 0: forceAction.setEnabled(False) continueAction.setEnabled(False) pauseAction.setEnabled(False) openAction.setEnabled(False) abortAction.setEnabled(False) supprListeAction.setEnabled(False) supprDiskAction.setEnabled(False) copyAction.setEnabled(False) searchAction.setEnabled(False) ######################################################### # On désactive les boutons qui sont pas encore implantés forceAction.setEnabled(False) #continueAction.setEnabled(False) #pauseAction.setEnabled(False) searchAction.setEnabled(False) ######################################################### # Signaux self.connect(forceAction, SIGNAL('triggered()'), self.force_Action) self.connect(continueAction, SIGNAL('triggered()'), self.continue_Action) self.connect(pauseAction, SIGNAL('triggered()'), self.pause_Action) self.connect(openAction, SIGNAL('triggered()'), self.open_Action) self.connect(abortAction, SIGNAL('triggered()'), self.abort_Action) self.connect(supprListeAction, SIGNAL('triggered()'), self.suppr_liste_Action) self.connect(supprDiskAction, SIGNAL('triggered()'), self.suppr_disk_Action) self.connect(copyAction, SIGNAL('triggered()'), self.copy_Action) self.connect(searchAction, SIGNAL('triggered()'), self.search_Action) # On affiche le menu menu.exec_(self.mapToGlobal(pos)) def getDownloads(self): rows = self.downloads_table.selectionModel().selectedRows() return [self.downloads_table.item(row.row(), 0).download for row in rows] def force_Action(self): print "TODO" def continue_Action(self): for download in self.getDownloads(): print "Resuming download" download.resume() self.display_resume_pause() def pause_Action(self): for download in self.getDownloads(): print "Pausing download" download.pause() self.display_resume_pause() def open_Action(self): for download in self.getDownloads(): open_file(download.local_path) def abort_Action(self): for download in self.getDownloads(): download.stop() row = self.downloads_table.currentRow() self.downloads_table.item(row, 2).setText(u"Annulé!") self.downloads_table.item(row, 3).setText("") def remove_download(self, download, erase): download.stop() row = self.downloads_table.currentRow() # On supprime la ligne self.downloads_table.removeRow(row) # On supprime de la liste self.downloads.remove(download) # On save self.downloads.save() if erase: try: os.remove(download.local_path) except OSError: try: shutil.rmtree(download.local_path) except: print "Erreur dans la suppression du fichier" def suppr_liste_Action(self): for download in self.getDownload(): self.remove_download(download, False) def suppr_disk_Action(self): for download in self.getDownloads(): self.remove_download(download, True) def copy_Action(self): pressPaper = QApplication.clipboard() text = '\n'.join([dl.local_path for dl in self.getDownloads()]) pressPaper.setText(text) def search_Action(self): print "TODO" def show_info_download(self): download = self.getDownloads()[0] self.name_label.setText(u"Nom : {}".format(download.file_share.name)) self.path_label.setText(u"Chemin local : {}".format(download.local_path)) self.url_label.setText(u"URL : {}".format(download.file_share.url)) self.size_label.setText(u"Taille : {}".format(download.file_share.str_size)) self.progressBar.show() self.progressBar.setValue(int(download.progress)) self.download_looked = download def clean_list_Action(self): remove_list = [] for download in self.downloads: if download.state == 4 or download.state == 7: # On trouve la ligne item = self.downloads_table.findItems(download.file_share.name, Qt.MatchExactly)[0] row = self.downloads_table.row(item) # On la supprime self.downloads_table.removeRow(row) # On save pour après la boucle for remove_list.append(download) # On supprime de la liste for download in remove_list: self.downloads.remove(download) # On save self.downloads.save() def double_clicked(self, row, col): download = self.getDownloads()[0] if download: open_file(download.local_path) def display_resume_pause(self): downloads = self.getDownloads() pause = False resume = False if downloads: for download in downloads: if download.state == 5: pause = True else: resume = True self.button_pause.setEnabled(resume) self.button_resume.setEnabled(pause) def clicked(self, row, col): self.display_resume_pause() def resizeEvent(self, event): maxSize = self.downloads_table.size().width() # Nom Ficher : 24% self.downloads_table.horizontalHeader().resizeSection(0, maxSize*.24) # Avancement : 22% self.downloads_table.horizontalHeader().resizeSection(1, maxSize*.22) # Etat : 17% self.downloads_table.horizontalHeader().resizeSection(2, maxSize*.17) # Vitesse : 13% self.downloads_table.horizontalHeader().resizeSection(3, maxSize*.13) # Fin : 12% self.downloads_table.horizontalHeader().resizeSection(4, maxSize*.12) event.accept()
class MainWindow(KXmlGuiWindow): "Class which displays the main Danbooru Client window." def __init__(self, *args): "Initialize a new main window." super(MainWindow, self).__init__(*args) self.cache = KPixmapCache("danbooru") self.preferences = preferences.Preferences() self.api = None self.__ratings = None self.__step = 0 self.url_list = self.preferences.boards_list self.max_retrieve = self.preferences.thumbnail_no self.statusbar = self.statusBar() self.progress = QProgressBar() self.thumbnailarea = None self.tag_dock = None self.pool_dock = None self.first_fetch_widget = None self.progress.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) # FIXME: Hackish, but how to make it small otherwise? self.progress.setMinimumSize(100, 1) self.statusbar.addPermanentWidget(self.progress) self.progress.hide() self.setup_welcome_widget() self.setup_actions() def reload_config(self): """Reload configuration after a change""" urls = self.preferences.boards_list if self.first_fetch_widget is not None: self.first_fetch_widget.setup_urls(urls) if self.thumbnailarea is not None: max_thumbnail = self.preferences.thumbnail_no max_rating = self.preferences.max_allowed_rating self.thumbnailarea.fetchwidget.limit = max_thumbnail self.thumbnailarea.fetchwidget.rating = max_rating self.thumbnailarea.fetchwidget.update_values() self.thumbnailarea.connectwidget.setup_urls(urls) self.url_list = self.preferences.boards_list self.max_retrieve = self.preferences.thumbnail_no def setup_welcome_widget(self): """Load the welcome widget at startup.""" widget = QWidget() layout = QVBoxLayout() welcome = QLabel(parent=self) pix = QPixmap(KStandardDirs.locate("appdata","logo.png")) welcome.setPixmap(pix) welcome.setAlignment(Qt.AlignCenter) self.first_fetch_widget = connectwidget.ConnectWidget( self.preferences.boards_list, self) self.statusbar.addPermanentWidget(self.first_fetch_widget, 300) self.first_fetch_widget.connectionEstablished.connect( self.handle_connection) self.first_fetch_widget.rejected.connect( self.first_fetch_widget.hide) self.first_fetch_widget.hide() self.first_fetch_widget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) layout.addWidget(self.first_fetch_widget) layout.addWidget(welcome) widget.setLayout(layout) self.setCentralWidget(widget) def setup_tooltips(self): """Set tooltips for the actions.""" self.connect_action.setToolTip(i18n("Connect to a Danbooru board")) self.fetch_action.setToolTip( i18n("Fetch thumbnails from a Danbooru board") ) self.batch_download_action.setToolTip(i18n("Batch download images")) def create_actions(self): """Create actions for the main window.""" self.connect_action = KAction(KIcon("document-open-remote"), i18n("Connect"), self) self.fetch_action = KAction(KIcon("download"), i18n("Download"), self) self.clean_action = KAction(KIcon("trash-empty"), i18n("Clear thumbnail cache"), self) self.batch_download_action = KAction(KIcon("download"), i18n("Batch download"), self) self.pool_toggle_action = KToggleAction(KIcon("image-x-generic"), i18n("Pools"), self) self.tag_display_action = KDualAction(i18n("Show tags"), i18n("Hide tags"), self) self.tag_display_action.setIconForStates(KIcon("image-x-generic")) self.tag_display_action.setEnabled(False) # Shortcuts connect_default = KAction.ShortcutTypes(KAction.DefaultShortcut) connect_active = KAction.ShortcutTypes(KAction.ActiveShortcut) self.connect_action.setShortcut(KStandardShortcut.open()) self.fetch_action.setShortcut(KStandardShortcut.find()) self.fetch_action.setEnabled(False) self.batch_download_action.setEnabled(False) self.pool_toggle_action.setEnabled(False) def setup_action_collection(self): """Set up the action collection by adding the actions.""" action_collection = self.actionCollection() # Addition to the action collection action_collection.addAction("connect", self.connect_action) action_collection.addAction("fetch", self.fetch_action) action_collection.addAction("clean", self.clean_action) action_collection.addAction("batchDownload", self.batch_download_action) action_collection.addAction("poolDownload", self.pool_toggle_action) action_collection.addAction("tagDisplay", self.tag_display_action) KStandardAction.quit (self.close, action_collection) KStandardAction.preferences(self.show_preferences, action_collection) action_collection.removeAction( action_collection.action("help_contents")) action_collection.actionHovered.connect(self.setup_action_tooltip) def setup_actions(self): """Set up the relevant actions, tooltips, and load the RC file.""" self.create_actions() self.setup_tooltips() self.setup_action_collection() # Connect signals self.connect_action.triggered.connect(self.connect) self.fetch_action.triggered.connect(self.get_posts) self.clean_action.triggered.connect(self.clean_cache) self.batch_download_action.triggered.connect(self.batch_download) self.pool_toggle_action.toggled.connect(self.pool_toggle) self.tag_display_action.activeChanged.connect(self.tag_display) window_options = self.StandardWindowOption(self.ToolBar| self.Keys | self.Create | self.Save | self.StatusBar) setupGUI_args = [ QSize(500, 400), self.StandardWindowOption(window_options) ] #Check first in standard locations for danbooruui.rc rc_file = KStandardDirs.locate("appdata", "danbooruui.rc") if rc_file.isEmpty(): setupGUI_args.append(os.path.join(sys.path [0], "danbooruui.rc")) else: setupGUI_args.append(rc_file) self.setupGUI(*setupGUI_args) def setup_action_tooltip(self, action): "Show statusbar help when actions are hovered." if action.isEnabled(): self.statusBar().showMessage(action.toolTip(), 2000) def setup_connections(self): """Set up connections for post and tag retrieval.""" if self.api is None: return self.api.postRetrieved.connect(self.update_progress) self.api.postDownloadFinished.connect(self.download_finished) self.api.tagRetrieved.connect(self.tag_dock.widget().add_tags) self.tag_dock.widget().itemDoubleClicked.connect( self.fetch_tagged_items) def show_preferences(self): "Show the preferences dialog." if KConfigDialog.showDialog("Preferences dialog"): return else: dialog = preferences.PreferencesDialog(self, "Preferences dialog", self.preferences) dialog.show() dialog.settingsChanged.connect(self.reload_config) def connect(self, ok): "Connect to a Danbooru board." if self.thumbnailarea is None: self.first_fetch_widget.show() else: self.thumbnailarea.connectwidget.show() def restore(self): self.statusbar.removeWidget(self.connect_widget) def handle_connection(self, connection): self.api = None self.api = connection self.api.cache = self.cache if self.pool_dock is not None: self.pool_dock.hide() self.pool_dock.widget().clear() self.pool_toggle_action.setChecked(False) if self.thumbnailarea is not None: #TODO: Investigate usability self.clear(clear_pool=True) self.thumbnailarea.clear() self.thumbnailarea.api_data = self.api self.setup_connections() else: self.first_fetch_widget.connectionEstablished.disconnect() self.first_fetch_widget.rejected.disconnect() self.statusbar.removeWidget(self.first_fetch_widget) self.setup_area() self.api.cache = self.cache self.statusBar().showMessage(i18n("Connected to %s" % self.api.url), 3000) self.fetch_action.setEnabled(True) # Set up pool widget pool_widget = poolwidget.DanbooruPoolWidget(self.api) self.pool_dock = QDockWidget("Pools", self) self.pool_dock.setObjectName("PoolDock") self.pool_dock.setAllowedAreas(Qt.BottomDockWidgetArea) self.pool_dock.setWidget(pool_widget) #self.pool_dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.addDockWidget(Qt.BottomDockWidgetArea, self.pool_dock) self.pool_dock.widget().poolDownloadRequested.connect( self.pool_prepare) self.pool_dock.hide() self.pool_toggle_action.setEnabled(True) self.clear() # Needed to show properly the stuff after connecting self.api.get_post_list(tags="", limit=self.thumbnailarea.post_limit, rating=self.preferences.max_allowed_rating, blacklist=list(self.preferences.tag_blacklist)) self.api.get_tag_list(name="",blacklist=list(self.preferences.tag_blacklist), limit=20) def get_posts(self, ok): "Get posts from the connected Danbooru board." if not self.api: return self.thumbnailarea.fetchwidget.show() def handle_fetching(self, tags, max_rating, limit): """Slot connected to the dataSent signal of the fetch widget. The widgets are set up if they don't exist, and the API is queried to do the actual downloading of tags and """ self.clear() self.thumbnailarea.fetchwidget.hide() if self.tag_dock is not None: self.tag_dock.widget().clear() self.thumbnailarea.post_limit = limit blacklist= list(self.preferences.tag_blacklist) self.api.get_post_list(tags=tags, limit=limit, rating=max_rating, blacklist=blacklist) tags = [item for item in tags if item] if not tags: # No related tags, fetch the most recent 20 tags = "" self.api.get_tag_list(name=tags,blacklist=blacklist, limit=20) else: self.api.get_related_tags(tags=tags, blacklist=blacklist) def fetch_tagged_items(self, item): """Fetch items found in the tag list widget.""" tag_name = unicode(item.text()) self.clear() blacklist = self.preferences.tag_blacklist limit = self.preferences.thumbnail_no rating = self.preferences.max_allowed_rating self.api.get_post_list(page=1, tags=[tag_name], blacklist=blacklist, limit=limit, rating=rating) self.api.get_related_tags(tags=[tag_name], blacklist=blacklist) def pool_toggle(self, checked): "Toggle the presence/absence of the pool dock." if not self.api: return if not checked: self.pool_dock.hide() else: self.pool_dock.show() def pool_prepare(self, pool_id): """Prepare the central area for pool image loading.""" if self.thumbnailarea is None: self.setup_area() else: self.clear(clear_pool=False) self.api.get_pool(pool_id, blacklist=self.preferences.tag_blacklist, rating=self.preferences.max_allowed_rating) def batch_download(self, ok): "Download images in batch." selected_items = self.thumbnailarea.selected_images() if not selected_items: return start_url = KUrl("kfiledialog:///danbooru") caption = i18n("Select a directory to save the images to") directory = KFileDialog.getExistingDirectoryUrl(start_url, self, caption) if directory.isEmpty(): return for item in selected_items: file_url = item.url_label.url() tags = item.data.tags # Make a local copy to append paths as addPath works in-place destination = KUrl(directory) file_name = KUrl(file_url).fileName() destination.addPath(file_name) job = KIO.file_copy(KUrl(file_url), destination, -1) job.setProperty("tags", QVariant(tags)) job.result.connect(self.batch_download_slot) def setup_area(self): "Set up the central widget to display thumbnails." self.thumbnailarea = thumbnailarea.DanbooruTabWidget(self.api, self.preferences, self.preferences.thumbnail_no, self) self.setCentralWidget(self.thumbnailarea) self.thumbnailarea.connectwidget.connectionEstablished.connect( self.handle_connection, type=Qt.UniqueConnection) self.thumbnailarea.connectwidget.rejected.connect( self.thumbnailarea.connectwidget.hide, type=Qt.UniqueConnection) self.thumbnailarea.fetchwidget.dataSent.connect( self.handle_fetching, type=Qt.UniqueConnection) self.thumbnailarea.fetchwidget.rejected.connect( self.thumbnailarea.fetchwidget.hide, type=Qt.UniqueConnection) # Set up tag widget blacklist = self.preferences.tag_blacklist tag_widget = tagwidget.DanbooruTagWidget(blacklist, self) self.tag_display_action.setActive(True) self.tag_display_action.setEnabled(True) self.tag_dock = QDockWidget("Similar tags", self) self.tag_dock.setObjectName("TagDock") self.tag_dock.setAllowedAreas(Qt.RightDockWidgetArea) self.tag_dock.setWidget(tag_widget) #self.tag_dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.addDockWidget(Qt.RightDockWidgetArea, self.tag_dock) self.tag_dock.hide() # Container signal-slot connections self.setup_connections() def download_finished(self): """Slot called when all the data has been completed. Clears the progress bar and resets it to 0.""" if not self.batch_download_action.isEnabled(): self.batch_download_action.setEnabled(True) self.__step = 0 self.progress.hide() def update_progress(self): "Update the progress bar." if not self.progress.isVisible(): self.progress.show() self.__step += 1 self.progress.setValue(self.__step) def clear(self, clear_pool=True): "Clear the central widget." if self.thumbnailarea is None: return self.thumbnailarea.clear() self.tag_dock.widget().clear() if clear_pool: self.pool_dock.widget().clear() self.batch_download_action.setEnabled(False) def clean_cache(self): "Purge the thumbnail cache." self.cache.discard() self.statusBar().showMessage(i18n("Thumbnail cache cleared.")) def batch_download_slot(self, job): """Slot called when doing batch download, for each file retrieved. If Nepomuk tagging is enabled, each file is tagged using the item's respective tags. """ if job.error(): job.ui().showErrorMessage() else: if self.preferences.nepomuk_enabled: tags = job.property("tags").toPyObject() #danbooru2nepomuk.tag_danbooru_item(job.destUrl().path(), # tags) def tag_display(self, state): """Display or hide the tag dock.""" if self.tag_dock is None: self.tag_display_action.setActive(False) return if state: self.tag_dock.show() else: self.tag_dock.hide()
class MainWindow(KXmlGuiWindow): "Class which displays the main Danbooru Client window." def __init__(self, *args): "Initialize a new main window." super(MainWindow, self).__init__(*args) self.cache = KPixmapCache("danbooru") self.preferences = preferences.Preferences() self.api = None self.__ratings = None self.__step = 0 self.url_list = self.preferences.boards_list self.max_retrieve = self.preferences.thumbnail_no self.statusbar = self.statusBar() self.progress = QProgressBar() self.thumbnailarea = None self.tag_dock = None self.pool_dock = None self.first_fetch_widget = None self.progress.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) # FIXME: Hackish, but how to make it small otherwise? self.progress.setMinimumSize(100, 1) self.statusbar.addPermanentWidget(self.progress) self.progress.hide() self.setup_welcome_widget() self.setup_actions() def reload_config(self): """Reload configuration after a change""" urls = self.preferences.boards_list if self.first_fetch_widget is not None: self.first_fetch_widget.setup_urls(urls) if self.thumbnailarea is not None: max_thumbnail = self.preferences.thumbnail_no max_rating = self.preferences.max_allowed_rating self.thumbnailarea.fetchwidget.limit = max_thumbnail self.thumbnailarea.fetchwidget.rating = max_rating self.thumbnailarea.fetchwidget.update_values() self.thumbnailarea.connectwidget.setup_urls(urls) self.url_list = self.preferences.boards_list self.max_retrieve = self.preferences.thumbnail_no def setup_welcome_widget(self): """Load the welcome widget at startup.""" widget = QWidget() layout = QVBoxLayout() welcome = QLabel(parent=self) pix = QPixmap(KStandardDirs.locate("appdata", "logo.png")) welcome.setPixmap(pix) welcome.setAlignment(Qt.AlignCenter) self.first_fetch_widget = connectwidget.ConnectWidget( self.preferences.boards_list, self) self.statusbar.addPermanentWidget(self.first_fetch_widget, 300) self.first_fetch_widget.connectionEstablished.connect( self.handle_connection) self.first_fetch_widget.rejected.connect(self.first_fetch_widget.hide) self.first_fetch_widget.hide() self.first_fetch_widget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) layout.addWidget(self.first_fetch_widget) layout.addWidget(welcome) widget.setLayout(layout) self.setCentralWidget(widget) def setup_tooltips(self): """Set tooltips for the actions.""" self.connect_action.setToolTip(i18n("Connect to a Danbooru board")) self.fetch_action.setToolTip( i18n("Fetch thumbnails from a Danbooru board")) self.batch_download_action.setToolTip(i18n("Batch download images")) def create_actions(self): """Create actions for the main window.""" self.connect_action = KAction(KIcon("document-open-remote"), i18n("Connect"), self) self.fetch_action = KAction(KIcon("download"), i18n("Download"), self) self.clean_action = KAction(KIcon("trash-empty"), i18n("Clear thumbnail cache"), self) self.batch_download_action = KAction(KIcon("download"), i18n("Batch download"), self) self.pool_toggle_action = KToggleAction(KIcon("image-x-generic"), i18n("Pools"), self) self.tag_display_action = KDualAction(i18n("Show tags"), i18n("Hide tags"), self) self.tag_display_action.setIconForStates(KIcon("image-x-generic")) self.tag_display_action.setEnabled(False) # Shortcuts connect_default = KAction.ShortcutTypes(KAction.DefaultShortcut) connect_active = KAction.ShortcutTypes(KAction.ActiveShortcut) self.connect_action.setShortcut(KStandardShortcut.open()) self.fetch_action.setShortcut(KStandardShortcut.find()) self.fetch_action.setEnabled(False) self.batch_download_action.setEnabled(False) self.pool_toggle_action.setEnabled(False) def setup_action_collection(self): """Set up the action collection by adding the actions.""" action_collection = self.actionCollection() # Addition to the action collection action_collection.addAction("connect", self.connect_action) action_collection.addAction("fetch", self.fetch_action) action_collection.addAction("clean", self.clean_action) action_collection.addAction("batchDownload", self.batch_download_action) action_collection.addAction("poolDownload", self.pool_toggle_action) action_collection.addAction("tagDisplay", self.tag_display_action) KStandardAction.quit(self.close, action_collection) KStandardAction.preferences(self.show_preferences, action_collection) action_collection.removeAction( action_collection.action("help_contents")) action_collection.actionHovered.connect(self.setup_action_tooltip) def setup_actions(self): """Set up the relevant actions, tooltips, and load the RC file.""" self.create_actions() self.setup_tooltips() self.setup_action_collection() # Connect signals self.connect_action.triggered.connect(self.connect) self.fetch_action.triggered.connect(self.get_posts) self.clean_action.triggered.connect(self.clean_cache) self.batch_download_action.triggered.connect(self.batch_download) self.pool_toggle_action.toggled.connect(self.pool_toggle) self.tag_display_action.activeChanged.connect(self.tag_display) window_options = self.StandardWindowOption(self.ToolBar | self.Keys | self.Create | self.Save | self.StatusBar) setupGUI_args = [ QSize(500, 400), self.StandardWindowOption(window_options) ] #Check first in standard locations for danbooruui.rc rc_file = KStandardDirs.locate("appdata", "danbooruui.rc") if rc_file.isEmpty(): setupGUI_args.append(os.path.join(sys.path[0], "danbooruui.rc")) else: setupGUI_args.append(rc_file) self.setupGUI(*setupGUI_args) def setup_action_tooltip(self, action): "Show statusbar help when actions are hovered." if action.isEnabled(): self.statusBar().showMessage(action.toolTip(), 2000) def setup_connections(self): """Set up connections for post and tag retrieval.""" if self.api is None: return self.api.postRetrieved.connect(self.update_progress) self.api.postDownloadFinished.connect(self.download_finished) self.api.tagRetrieved.connect(self.tag_dock.widget().add_tags) self.tag_dock.widget().itemDoubleClicked.connect( self.fetch_tagged_items) def show_preferences(self): "Show the preferences dialog." if KConfigDialog.showDialog("Preferences dialog"): return else: dialog = preferences.PreferencesDialog(self, "Preferences dialog", self.preferences) dialog.show() dialog.settingsChanged.connect(self.reload_config) def connect(self, ok): "Connect to a Danbooru board." if self.thumbnailarea is None: self.first_fetch_widget.show() else: self.thumbnailarea.connectwidget.show() def restore(self): self.statusbar.removeWidget(self.connect_widget) def handle_connection(self, connection): self.api = None self.api = connection self.api.cache = self.cache if self.pool_dock is not None: self.pool_dock.hide() self.pool_dock.widget().clear() self.pool_toggle_action.setChecked(False) if self.thumbnailarea is not None: #TODO: Investigate usability self.clear(clear_pool=True) self.thumbnailarea.clear() self.thumbnailarea.api_data = self.api self.setup_connections() else: self.first_fetch_widget.connectionEstablished.disconnect() self.first_fetch_widget.rejected.disconnect() self.statusbar.removeWidget(self.first_fetch_widget) self.setup_area() self.api.cache = self.cache self.statusBar().showMessage(i18n("Connected to %s" % self.api.url), 3000) self.fetch_action.setEnabled(True) # Set up pool widget pool_widget = poolwidget.DanbooruPoolWidget(self.api) self.pool_dock = QDockWidget("Pools", self) self.pool_dock.setObjectName("PoolDock") self.pool_dock.setAllowedAreas(Qt.BottomDockWidgetArea) self.pool_dock.setWidget(pool_widget) #self.pool_dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.addDockWidget(Qt.BottomDockWidgetArea, self.pool_dock) self.pool_dock.widget().poolDownloadRequested.connect( self.pool_prepare) self.pool_dock.hide() self.pool_toggle_action.setEnabled(True) self.clear() # Needed to show properly the stuff after connecting self.api.get_post_list(tags="", limit=self.thumbnailarea.post_limit, rating=self.preferences.max_allowed_rating, blacklist=list(self.preferences.tag_blacklist)) self.api.get_tag_list(name="", blacklist=list(self.preferences.tag_blacklist), limit=20) def get_posts(self, ok): "Get posts from the connected Danbooru board." if not self.api: return self.thumbnailarea.fetchwidget.show() def handle_fetching(self, tags, max_rating, limit): """Slot connected to the dataSent signal of the fetch widget. The widgets are set up if they don't exist, and the API is queried to do the actual downloading of tags and """ self.clear() self.thumbnailarea.fetchwidget.hide() if self.tag_dock is not None: self.tag_dock.widget().clear() self.thumbnailarea.post_limit = limit blacklist = list(self.preferences.tag_blacklist) self.api.get_post_list(tags=tags, limit=limit, rating=max_rating, blacklist=blacklist) tags = [item for item in tags if item] if not tags: # No related tags, fetch the most recent 20 tags = "" self.api.get_tag_list(name=tags, blacklist=blacklist, limit=20) else: self.api.get_related_tags(tags=tags, blacklist=blacklist) def fetch_tagged_items(self, item): """Fetch items found in the tag list widget.""" tag_name = unicode(item.text()) self.clear() blacklist = self.preferences.tag_blacklist limit = self.preferences.thumbnail_no rating = self.preferences.max_allowed_rating self.api.get_post_list(page=1, tags=[tag_name], blacklist=blacklist, limit=limit, rating=rating) self.api.get_related_tags(tags=[tag_name], blacklist=blacklist) def pool_toggle(self, checked): "Toggle the presence/absence of the pool dock." if not self.api: return if not checked: self.pool_dock.hide() else: self.pool_dock.show() def pool_prepare(self, pool_id): """Prepare the central area for pool image loading.""" if self.thumbnailarea is None: self.setup_area() else: self.clear(clear_pool=False) self.api.get_pool(pool_id, blacklist=self.preferences.tag_blacklist, rating=self.preferences.max_allowed_rating) def batch_download(self, ok): "Download images in batch." selected_items = self.thumbnailarea.selected_images() if not selected_items: return start_url = KUrl("kfiledialog:///danbooru") caption = i18n("Select a directory to save the images to") directory = KFileDialog.getExistingDirectoryUrl( start_url, self, caption) if directory.isEmpty(): return for item in selected_items: file_url = item.url_label.url() tags = item.data.tags # Make a local copy to append paths as addPath works in-place destination = KUrl(directory) file_name = KUrl(file_url).fileName() destination.addPath(file_name) job = KIO.file_copy(KUrl(file_url), destination, -1) job.setProperty("tags", QVariant(tags)) job.result.connect(self.batch_download_slot) def setup_area(self): "Set up the central widget to display thumbnails." self.thumbnailarea = thumbnailarea.DanbooruTabWidget( self.api, self.preferences, self.preferences.thumbnail_no, self) self.setCentralWidget(self.thumbnailarea) self.thumbnailarea.connectwidget.connectionEstablished.connect( self.handle_connection, type=Qt.UniqueConnection) self.thumbnailarea.connectwidget.rejected.connect( self.thumbnailarea.connectwidget.hide, type=Qt.UniqueConnection) self.thumbnailarea.fetchwidget.dataSent.connect( self.handle_fetching, type=Qt.UniqueConnection) self.thumbnailarea.fetchwidget.rejected.connect( self.thumbnailarea.fetchwidget.hide, type=Qt.UniqueConnection) # Set up tag widget blacklist = self.preferences.tag_blacklist tag_widget = tagwidget.DanbooruTagWidget(blacklist, self) self.tag_display_action.setActive(True) self.tag_display_action.setEnabled(True) self.tag_dock = QDockWidget("Similar tags", self) self.tag_dock.setObjectName("TagDock") self.tag_dock.setAllowedAreas(Qt.RightDockWidgetArea) self.tag_dock.setWidget(tag_widget) #self.tag_dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.addDockWidget(Qt.RightDockWidgetArea, self.tag_dock) self.tag_dock.hide() # Container signal-slot connections self.setup_connections() def download_finished(self): """Slot called when all the data has been completed. Clears the progress bar and resets it to 0.""" if not self.batch_download_action.isEnabled(): self.batch_download_action.setEnabled(True) self.__step = 0 self.progress.hide() def update_progress(self): "Update the progress bar." if not self.progress.isVisible(): self.progress.show() self.__step += 1 self.progress.setValue(self.__step) def clear(self, clear_pool=True): "Clear the central widget." if self.thumbnailarea is None: return self.thumbnailarea.clear() self.tag_dock.widget().clear() if clear_pool: self.pool_dock.widget().clear() self.batch_download_action.setEnabled(False) def clean_cache(self): "Purge the thumbnail cache." self.cache.discard() self.statusBar().showMessage(i18n("Thumbnail cache cleared.")) def batch_download_slot(self, job): """Slot called when doing batch download, for each file retrieved. If Nepomuk tagging is enabled, each file is tagged using the item's respective tags. """ if job.error(): job.ui().showErrorMessage() else: if self.preferences.nepomuk_enabled: tags = job.property("tags").toPyObject() #danbooru2nepomuk.tag_danbooru_item(job.destUrl().path(), # tags) def tag_display(self, state): """Display or hide the tag dock.""" if self.tag_dock is None: self.tag_display_action.setActive(False) return if state: self.tag_dock.show() else: self.tag_dock.hide()
class frmReportes( QPrintPreviewDialog ): """ Este es un formulario generico que muestra los reportes web generados para las """ def __init__( self, web, printer , parent = None ): """ @param web: La dirección web a la que apunta el reporte @param printer: El objeto QPrinter en el que se imprime, esto es usado por si se desea alguna configuración especifica del reporte """ super( frmReportes, self ).__init__( printer, parent ) base = Reports.url if base == "": raise UserWarning( u"No existe una configuración para el servidor de reportes" ) self.report = base + web + "&uname=" + user.LoggedUser.user + "&hash=" + user.LoggedUser.hash self.webview = QWebView() self.setWindowFlags( self.windowFlags() | Qt.WindowMaximizeButtonHint ) self.txtSearch = QLineEdit() self.loaded = False self.webview.load( QUrl( self.report ) ) self.progressbar = QProgressBar( self ) self.paintRequested[QPrinter].connect( self.reprint ) self.webview.loadFinished[bool].connect( self.on_webview_loadFinished ) self.webview.loadProgress[int].connect( self.on_webview_loadProgress ) def reprint( self, printer ): self.webview.print_( printer ) def on_webview_loadProgress( self, progress ): self.progressbar.setValue( progress ) def showEvent( self, _event ): if not self.loaded: self.progressbar.show() def on_webview_loadFinished( self, status ): if self.progressbar.isVisible(): self.progressbar.hide() if not status: QMessageBox.critical( self, qApp.organizationName(), "El reporte no se pudo cargar" ) logging.error( "No se pudo cargar el reporte: %s" % self.report ) self.accept() self.loaded = True w = self.findChild( QPrintPreviewWidget ) w.updatePreview()
def __init__(self, parent=None): QWidget.__init__(self, parent) self.home_url = None self.zoom_factor = 1.0 self.webview = WebView(self) self.connect(self.webview, SIGNAL("loadFinished(bool)"), self.load_finished) self.connect(self.webview, SIGNAL("titleChanged(QString)"), self.setWindowTitle) self.connect(self.webview, SIGNAL("urlChanged(QUrl)"), self.url_changed) previous_button = create_toolbutton( self, get_icon("previous.png"), tip=self.tr("Previous"), triggered=self.webview.back ) next_button = create_toolbutton(self, get_icon("next.png"), tip=self.tr("Next"), triggered=self.webview.forward) home_button = create_toolbutton(self, get_icon("home.png"), tip=self.tr("Home"), triggered=self.go_home) zoom_out_button = create_toolbutton( self, get_icon("zoom_out.png"), tip=self.tr("Zoom out"), triggered=self.zoom_out ) zoom_in_button = create_toolbutton( self, get_icon("zoom_in.png"), tip=self.tr("Zoom in"), triggered=self.zoom_in ) refresh_button = create_toolbutton(self, get_icon("reload.png"), tip=self.tr("Reload"), triggered=self.reload) stop_button = create_toolbutton(self, get_icon("stop.png"), tip=self.tr("Stop"), triggered=self.webview.stop) stop_button.setEnabled(False) self.connect(self.webview, SIGNAL("loadStarted()"), lambda: stop_button.setEnabled(True)) self.connect(self.webview, SIGNAL("loadFinished(bool)"), lambda: stop_button.setEnabled(False)) progressbar = QProgressBar(self) progressbar.setTextVisible(False) progressbar.hide() self.connect(self.webview, SIGNAL("loadStarted()"), progressbar.show) self.connect(self.webview, SIGNAL("loadProgress(int)"), progressbar.setValue) self.connect(self.webview, SIGNAL("loadFinished(bool)"), progressbar.hide) label = QLabel(self.get_label()) self.url_combo = UrlComboBox(self) self.connect(self.url_combo, SIGNAL("valid(bool)"), self.url_combo_activated) self.connect(self.webview, SIGNAL("iconChanged()"), self.icon_changed) self.find_widget = FindReplace(self) self.find_widget.set_editor(self.webview) self.find_widget.hide() find_button = create_toolbutton( self, icon="find.png", tip=translate("FindReplace", "Find text"), toggled=self.toggle_find_widget ) self.connect(self.find_widget, SIGNAL("visibility_changed(bool)"), find_button.setChecked) hlayout = QHBoxLayout() for widget in ( previous_button, next_button, home_button, find_button, label, self.url_combo, zoom_out_button, zoom_in_button, refresh_button, progressbar, stop_button, ): hlayout.addWidget(widget) layout = QVBoxLayout() layout.addLayout(hlayout) layout.addWidget(self.webview) layout.addWidget(self.find_widget) self.setLayout(layout)
class RipperWidget(SmoothWidget, ripper.Ripper): """ One-button multi-track ripper. """ def __init__(self, parent=None): SmoothWidget.__init__(self, parent) ripper.Ripper.__init__(self) Layout = QVBoxLayout(self) self.discLabel = QLabel(self) Layout.addWidget(self.discLabel) # ONLY ONE BUTTON! self.button = QPushButton('Cancel', self) self.button.setEnabled(True) self.button.hide() QObject.connect(self.button, SIGNAL('clicked()'), self.cancel) Layout.addWidget(self.button) self.catFrame = QFrame(self) self.catFrame.setFrameStyle(QFrame.StyledPanel) self.catFrame.hide() QHBoxLayout(self.catFrame) self.categories = CategoryButtons(self.catFrame) QObject.connect(self.categories, SIGNAL('selected(QString &)'), self.start) self.catFrame.layout().addWidget(self.categories) Layout.addWidget(self.catFrame) self.progress = QProgressBar(self) self.progress.setRange(0, 100) self.progress.hide() Layout.addWidget(self.progress) def start(self, category): """ Should already have the track info. """ self.genre = str(category) self._progress_data = {} self.disc_length = 0.0 for i in range(self.count): sec = cd_logic.get_track_time_total(i) self._progress_data[i] = {'rip' : 0, 'enc' : 0, 'length' : sec} self.disc_length += sec self.rip_n_encode() text = '%s - %s' % (self.artist, self.album) self.discLabel.setText('Copying "'+text+'"...') self.button.show() self.progress.show() self.catFrame.hide() def cancel(self): self.stop_request = True path = os.path.join(ripper.LIBRARY, self.genre, self.artist+' - '+self.album) os.system('rm -rf \"%s\"' % path) self.discLabel.setText('Canceled') self.button.hide() self.progress.hide() self.progress.setValue(0) self.emit(SIGNAL('canceled()')) def read_disc_info(self): self.discLabel.setText('Getting disc info...') ripper.Ripper.read_disc_info(self) def ripper_event(self, e): """ """ event = QEvent(event_type(e.type)) event.data = e.__dict__ QApplication.instance().postEvent(self, event) def customEvent(self, e): if e.type() == event_type(ripper.CDDB_DONE): self.button.setEnabled(True) text = '%s - %s' % (self.artist, self.album) text += ' ( Select a category... )' self.discLabel.setText(text) self.catFrame.show() self.emit(SIGNAL('foundDiscInfo()')) elif e.type() == event_type(ripper.STATUS_UPDATE): self.updateProgress(e.data) self.emit(SIGNAL('status(QEvent *)'), e) def updateProgress(self, data): """ assume rip and enc are equal in time. """ state = data['state'] tracknum = data['tracknum'] percent = data['percent'] goal_percents = self.count * 200 item = self._progress_data[tracknum] if state == 'rip': item['rip'] = percent elif state == 'enc': item['enc'] = percent else: # err, etc... item['rip'] = 0 item['enc'] = 0 total = 0 for i, v in self._progress_data.items(): seconds = v['length'] rip_perc = v['rip'] enc_perc = v['enc'] worth = seconds / self.disc_length rip_perc *= worth enc_perc *= worth total += rip_perc + enc_perc #print i, worth, rip_perc, enc_perc, total percent = total / 2 self.progress.setValue(percent) if percent == 100: if self.is_ripping: print 'percent == 100 but still ripping?' if self.is_encoding: print 'percent == 100 but still encoding?' else: print 'percent == 100 and ripper finished' self.button.hide() self.progress.hide() text = 'Finished copying \"%s - %s\"' % (self.artist, self.album) self.discLabel.setText(text) self.emit(SIGNAL('doneRipping()'))
class Form(QMainWindow, Ui_MainWindow): """IT Query Main Window.""" def __init__(self, initIds, initErrIds, parent=None): """Setup main window and populate with data(if given).""" super(Form, self).__init__(parent) self.setupUi(self) self.setWindowTitle("IT Query {0}".format(__version__)) self.selectedIds = initIds self.errorIds = initErrIds LOG_LEVEL = logging.INFO currTime = time.localtime() runDate = time.strftime("%Y-%m-%d", currTime) self.dbPath = DB.Db.Info.Path LOG_FNAME = "{0}\{1}-{2}.{3}".format(self.dbPath, "itquery", runDate, "txt") if LOG_LEVEL == logging.INFO: LOG_FORMAT = "%(asctime)s\t%(message)s" else: LOG_FORMAT = ("%(asctime)s - %(levelname)s - %(funcName)s " " - %(message)s") self.logger = logging.getLogger("itquery") self.logger.setLevel(LOG_LEVEL) self.handler = logging.FileHandler(LOG_FNAME) formatter = logging.Formatter(LOG_FORMAT) self.handler.setFormatter(formatter) self.logger.addHandler(self.handler) for action, slot in ((self.updateButton, self.updateSelection), (self.bionumericsButton, self.bnSelectFields), (self.itemTrackerButton, self.itSelectFields)): action.clicked.connect(slot) for action, slot in ((self.actionCollapseAll, self.collapseAll), (self.actionExpandAll, self.expandAll), (self.actionCollapseItem, self.collapseItem), (self.actionCherryPicking, self.cherryPicking), (self.actionExpandItem, self.expandItem), (self.actionSelectAll, self.selectAll), (self.actionSelectDNA, self.selectDNA), (self.actionSelectFrozenStock, self.selectFrozenStock), (self.actionSelectInvert, self.selectInvert), (self.actionSelectNone, self.selectNone), (self.actionGetAllSelected, self.getAllSelected), (self.actionRefresh, self.refresh), (self.actionAbout, self.about), (self.actionViewTree, self.viewTree), (self.actionClearLog, self.clearLog), (self.actionLegend, self.legend), (self.actionExportTraceList, self.exportTraceList), (self.actionExportDNAList, self.exportDNAList), (self.actionClose, self.close)): action.triggered.connect(slot) self.treeWidget.itemSelectionChanged.connect(self.updateInfo) self.viewMenu.addAction(self.logDockWidget.toggleViewAction()) icon = QIcon(":/text-x-log.png") self.logDockWidget.toggleViewAction().setIcon(icon) self.actionSelectInBionumerics.toggled.connect(self.selectInBionumerics) self.userComboBox.currentIndexChanged.connect(self.userChanged) self.statusComboBox.currentIndexChanged.connect(self.statusChanged) self.treeActions = QActionGroup(self) self.treeActions.addAction(self.actionExpandItem) self.treeActions.addAction(self.actionCollapseItem) self.treeActions.addAction(self.actionExpandAll) self.treeActions.addAction(self.actionCollapseAll) self.selectActions = QActionGroup(self) self.selectActions.addAction(self.actionSelectAll) self.selectActions.addAction(self.actionSelectNone) self.selectActions.addAction(self.actionSelectInvert) self.selectActions.addAction(self.actionSelectDNA) self.selectActions.addAction(self.actionSelectFrozenStock) self.exportActions = QActionGroup(self) self.exportActions.addAction(self.actionExportDNAList) self.exportActions.addAction(self.actionExportTraceList) self.statusbar.setSizeGripEnabled(True) # user label at the right end of status bar # db = lims.DATABASE db = "No information" dbLabel = QLabel("Database: <b>{0}</b>".format(db)) self.statusbar.addPermanentWidget(dbLabel) user = os.environ.get("USERNAME") or "Demo user" label = QLabel("Logged in as: <b>{0}</b>".format(user)) self.statusbar.addPermanentWidget(label) # restore main window state settings = QSettings() size = settings.value("MainWindow/Size", QVariant(QSize(600, 500))).toSize() self.resize(size) position = settings.value("MainWindow/Position", QVariant(QPoint(0, 0))).toPoint() self.move(position) self.restoreState(settings.value("MainWindow/State").toByteArray()) splitterState = settings.value("MainWindow/SplitState").toByteArray() self.splitter.restoreState(splitterState) # selected fields self.dbName = bns.ConnectedDb.ConnectDb.GetList() regKey = "Bionumerics/{0}/SelFields".format(self.dbName) regBnFields = settings.value(regKey).toStringList() self.bnSelectedFields = [unicode(item) for item in regBnFields] regItFields = settings.value("ItemTracker/SelFields").toStringList() self.itSelectedFields = [unicode(item) for item in regItFields] # progress bar self.progressBar = QProgressBar(self) self.progressBar.setMaximumWidth(200) self.statusbar.insertPermanentWidget(0, self.progressBar) self.progressBar.hide() # initialize variables self.itemIds = {} self.itemNames = {} # bnFields - bionumerics information in the info panel self.bnFields = {} self.strainInfo = {} # maintains list of keys that are updated self.updatedStrains = [] self.selectRadioButton.setChecked(True) self.itemProperties = {} self.tableResults = [] self.getBnFields() self.mkInfo("{0}. Log: {1}".format(time.asctime(), LOG_FNAME)) self.populatedTree = False self.populatedTable = False self.populatedCherry = False idField = "ItemTracker ID" # Field with ItemTracker ID self.itemIdsAll, errors = bn.getItemIds(idField, DB.Db.Entries) if len(errors): for key, message in errors.iteritems(): self.mkError("Key: {0}, {1}".format(key, message)) self.database = None self.updateUi() self.proxyModel = SortFilterProxyModel(self) self.proxyModel.setDynamicSortFilter(True) self.cherryView.setModel(self.proxyModel) self.cherryView.setAlternatingRowColors(True) self.cherryView.setSortingEnabled(True) self.cherryView.verticalHeader().setVisible(False) self.cherryView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.cherryView.horizontalHeader().setStretchLastSection(True) #self.populateTree() # testing QTimer.singleShot(0, self.populateTree) def bnSelectFields(self): """Bionumerics field selection dialog.""" try: fieldNames = bn.getFieldNames() except RuntimeError as e: self.mkError("Failed to get Bionumerics field names: {0}".format(e)) dialog = selectfieldsdlg.selectFieldsDialog(fieldNames, self) if self.bnSelectedFields is not None: dialog.setSelected(self.bnSelectedFields) if dialog.exec_(): self.bnSelectedFields = dialog.getSelected() self.updateInfo() def addCherryData(self, model, row): """Inserts row into model""" model.insertRow(0) for position, value in enumerate(row): model.setData(model.index(0, position), value) def createCherryModel(self, data, parent): """Creates a model for the tableview using data retrieved from the cherry picking database. """ total = len(data) self.progressBar.setMaximum(total) self.progressBar.show() model = QStandardItemModel(0, len(CHERRY_COLUMNS), parent) for position, column in enumerate(CHERRY_COLUMNS): model.setHeaderData(position, Qt.Horizontal, column) # get additional data for each item keys = [item[CHERRY_COLUMNS.index("Key")] for item in data] itemIds = [] missing = [] itemIdsAll = dict((v, k) for k, v in self.itemIdsAll.iteritems()) for key in keys: if key in itemIdsAll: itemIds.append(itemIdsAll[key]) else: missing.append(key) if len(missing): msg = ("Keys exist in cherry picking database but absent " "in Bionumerics {0}".format(", ".join(missing))) self.mkWarn(msg) if not len(itemIds): msg = "No entries in cherry picking database" self.statusBar().showMessage(msg, 5000) self.mkInfo(msg) return None itemIds = list(set(itemIds)) (dnaData, noData, errors) = lims.GetNewestDNAForCherryPicking(itemIds) if len(noData): msg = ", ".join(str(item) for item in noData) self.mkWarn("{0}: {1}".format("No DNA's for these strains", msg)) if len(errors): msg = ", ".join(errors) self.mkError(msg) for count, result in enumerate(data): result = list(result) key = result[0] if key in itemIdsAll: self.progressBar.setValue(count) #QApplication.processEvents() parentID = itemIdsAll[key] if parentID in dnaData: properties = dnaData[parentID] for value in ("ItemName", "DNA concentration", "Volume", "Freezer", "Rack", "Shelf", "PlateRack", "Position"): if value in properties: result.append(properties[value]) else: result.append("") self.addCherryData(model, result) return model def cherryPicking(self): """Populate the cherry picking table""" if self.populatedCherry: if not self.stackedWidget.currentIndex() == 2: self.stackedWidget.setCurrentIndex(2) self.updateUi() return self.statusbar.showMessage("Getting data from cherry picking database") db = DB.Db.Info.Name cherryData = pgdb.get_data(db) if not len(cherryData): msg = "No cherry picking entries for this database" self.statusbar.showMessage(msg, 5000) self.mkInfo(msg) self.stackedWidget.setCurrentIndex(2) self.updateUi() return self.userComboBox.clear() self.statusComboBox.clear() # filter combo boxes for label, combo in (("Username", self.userComboBox), ("Status", self.statusComboBox)): position = CHERRY_COLUMNS.index(label) comboItems = set([item[position] for item in cherryData]) combo.addItem("All") combo.addItems(list(comboItems)) self.proxyModel.traceStatus = self.statusComboBox.currentText() self.cherryView.reset() self.cherryView.setDisabled(True) self.statusbar.showMessage("Getting data from ItemTracker") model = self.createCherryModel(cherryData, self) if not model: self.cherryView.setEnabled(False) self.filterGroupBox.setDisabled(True) else: self.proxyModel.setSourceModel(model) self.cherryView.setEnabled(True) self.filterGroupBox.setEnabled(True) self.cherryView.resizeColumnsToContents() self.updateCounts() self.stackedWidget.setCurrentIndex(2) # switch view to table self.statusbar.clearMessage() self.progressBar.setValue(len(cherryData)) self.progressBar.hide() self.populatedCherry = True self.updateUi() def statusChanged(self): """Filter cherry picking based on current trace status from combo box.""" self.proxyModel.setTraceStatus(self.statusComboBox.currentText()) self.updateCounts() def userChanged(self): """Filter cherry picking based on current user from combo box.""" user = self.userComboBox.currentText() if user == "All": user = "******" regExp = QRegExp(user, Qt.CaseInsensitive, QRegExp.RegExp2) self.proxyModel.setFilterRegExp(regExp) self.updateCounts() def updateCounts(self): """Update counts of strains, traces and DNA in cherry picking""" strains = [] traces = self.proxyModel.rowCount() dna = [] for i in range(traces): for field, totals in (("Key", strains), ("DNA", dna)): index = self.proxyModel.index(i, CHERRY_COLUMNS.index(field)) data = self.proxyModel.data(index).toString().trimmed() if len(data) and data not in totals: totals.append(data) self.strainsLcdNumber.display(len(strains)) self.tracesLcdNumber.display(traces) self.dnaLcdNumber.display(len(dna)) def getSaveFile(self, caption=""): """Opens the save file dialog and returns the file name.""" if not len(caption): caption = "Save File As" fn = QFileDialog.getSaveFileName(self, caption, self.dbPath, "Text files (*.txt);;All Files (*.*)") if fn: if QFileInfo(fn).suffix().isEmpty(): fn += ".txt" return fn def exportTextFile(self, fh=None, header=None, data=None): """Writes data to the given file. Accepts column names and the data as arguments """ if not fh: self.mkError("Could not open file for writing") return if not data: data = [] if not len(data): self.mkWarn("No data to write") return fname = QFile(fh) if fname.open(QFile.WriteOnly | QFile.Text): txt = QTextStream(fname) if header: txt << ", ".join(col for col in header) txt << "\n" txt << "\n".join(", ".join(item) for item in data) msg = "File export complete: {0}".format(str(fname.fileName())) self.mkSuccess(msg) def exportDNAList(self): """Export list of DNA's displayed in cherry picking.""" data = [] keys = [] columns = CHERRY_COLUMNS[:] excludeColumns = ["Gene", "Orientation"] exclude = [] for item in excludeColumns: exclude.append(CHERRY_COLUMNS.index(item)) columns.remove(item) keyIndex = CHERRY_COLUMNS.index("Key") dnaIndex = CHERRY_COLUMNS.index("DNA") for i in range(0, self.proxyModel.rowCount()): # continue if key exists in keys index = self.proxyModel.index(i, keyIndex) key = self.proxyModel.data(index).toString() if key in keys: continue # continue if DNA column is empty index = self.proxyModel.index(i, dnaIndex) dna = self.proxyModel.data(index).toString() if dna.isEmpty(): continue row = [] for j in range(self.proxyModel.columnCount()): if j in exclude: continue index = self.proxyModel.index(i, j) value = self.proxyModel.data(index).toString() if not value.isEmpty(): row.append(str(value)) else: row.append("") data.append(row) keys.append(key) fh = self.getSaveFile("Export DNA List") self.exportTextFile(fh, columns, data) def exportTraceList(self): """Export list of traces displayed in cherry picking.""" data = [] for i in range(0, self.proxyModel.rowCount()): row = [] for j in range(self.proxyModel.columnCount()): index = self.proxyModel.index(i, j) value = self.proxyModel.data(index).toString() if not value.isEmpty(): row.append(str(value)) else: row.append("") data.append(row) fh = self.getSaveFile("Export Trace List") columns = CHERRY_COLUMNS[:] self.exportTextFile(fh, columns, data) def clearLog(self): """Clears the log window""" self.logBrowser.clear() def closeEvent(self, event): """Called on closing the window. Save settings and exit.""" self.handler.close() self.logger.removeHandler(self.handler) if self.okToContinue(): settings = QSettings() settings.setValue("MainWindow/Size", QVariant(self.size())) settings.setValue("MainWindow/Position", QVariant(self.pos())) settings.setValue("MainWindow/State", QVariant(self.saveState())) settings.setValue("MainWindow/SplitState", self.splitter.saveState()) bnSelectedFields = QVariant(self.bnSelectedFields) \ if self.bnSelectedFields else QVariant() regkey = "Bionumerics/{0}/SelFields".format(self.dbName) settings.setValue(regkey, bnSelectedFields) itSelectedFields = QVariant(self.itSelectedFields) \ if self.itSelectedFields else QVariant() settings.setValue("ItemTracker/SelFields", itSelectedFields) else: event.ignore() def collapseItem(self): """Collapse selected item.""" try: selected = self.treeWidget.selectedItems()[0] except IndexError: selected = None self.statusbar.showMessage("No item selected", 2000) if selected: self.treeWidget.collapseItem(selected) def collapseAll(self): """Collapse all items.""" self.treeWidget.collapseAll() def disableWidgets(self, widgets): """Disable group of widgets. Does not change visibility.""" for widget in widgets: if widget.isEnabled(): widget.setDisabled(True) def enableWidgets(self, widgets): """Enable group of widgets. Set visible if not visible.""" for widget in widgets: if not widget.isEnabled(): widget.setEnabled(True) if not widget.isVisible(): widget.setVisible(True) def expandItem(self): """Expand selected item.""" try: selected = self.treeWidget.selectedItems()[0] except IndexError: selected = None self.statusbar.showMessage("No item selected", 2000) if selected: self.treeWidget.expandItem(selected) def expandAll(self): """Expands all items.""" self.treeWidget.expandAll() def getBnFields(self): """Get bionumerics field information required for the info panel.""" bnFields = bn.getFieldNames() strainFields = ["Strain", "STRAIN"] for field in strainFields: if (field in bnFields) and (field not in self.bnSelectedFields): self.bnSelectedFields.append(field) for key in self.selectedIds.values(): if not self.bnFields.get(key): self.bnFields[key] = bn.getSelectedFields(key, bnFields) def getParent(self, item): """Returns the top level parent of an item.""" parentItem = None while item.parent(): parentItem = item.parent() item = parentItem return parentItem def getData(self, items, itemid): """Returns parent and children for data received from GetDictionary.""" if len(items): children = items[itemid].keys() yield itemid, children items = items[itemid] for child in children: for res in self.getData(items, child): yield res return def getAllItemIds(self): """Gets all ItemTracker IDs in the current Bionumerics database.""" itemIds = {} field = "ItemTracker ID" value = None for i in range(len(DB.Db.Entries)): value = DB.Db.Entries[i].Field(field).Content # bugfix: don't display if ItemTracker ID contains spaces value = value.strip() if not len(value): continue key = DB.Db.Entries[i].Key key = key.strip() if key in itemIds: itemIds.pop(key) msg = "Duplicate keys in database: {0}. Not processed".format(key) self.mkWarn(msg) continue try: value = int(value) except (ValueError, TypeError): self.mkWarn("Invalid ItemTracker ID {0} for entry " "{1} in Bionumerics".format(value, key)) if isinstance(value, int): if value in itemIds.values(): msg = ("Duplicate ItemTracker ID: {0}. " "Keys: {1}, ".format(value, key)) for k, v in itemIds.items(): if v == value: itemIds.pop(k) msg += k self.mkWarn(msg) else: itemIds[key] = value return itemIds def getAllSelected(self): """Get all selected items by user.""" if self.populatedTable: self.stackedWidget.setCurrentIndex(1) self.updateUi() return msg = "Getting all selected entries from ItemTracker. Please wait..." self.statusbar.showMessage(msg) if len(self.itemIdsAll): try: self.tableResults = \ lims.SelectAllselectedEntries(self.itemIdsAll.keys()) except: raise RuntimeError else: self.mkInfo("No ItemTracker IDs to process") if not len(self.tableResults): user = os.environ.get("USERNAME") msg = "No selected entries for user {0}".format(user) self.statusbar.showMessage(msg, 5000) self.mkInfo(msg) self.stackedWidget.setCurrentIndex(1) self.populatedTable = False self.updateUi() else: QTimer.singleShot(0, self.populateTable) def getItemtrackerFields(self): """Returns all ItemTracker fields returned from GetDictionary.""" fields = [] alwaysFields = ["ItemID", "ItemName", "Position"] for item in self.itemProperties: for field in self.itemProperties[item].keys(): if (field not in fields) and (field not in alwaysFields): fields.append(field) return fields def getWidget(self): """Returns the current active widget.""" index = self.stackedWidget.currentIndex() if index == 0: widget = self.treeWidget elif index == 1: widget = self.selectedWidget elif index == 2: widget = self.cherryView return widget def about(self): """About box.""" import platform msg = """\ <b>IT Query</b> version {0} <p>An interface to query ItemTracker from Bionumerics</p>Python {1} - Qt {2} - PyQt {3} on {4}\ """.format(__version__, platform.python_version(), QT_VERSION_STR, PYQT_VERSION_STR, platform.system()) msg += """<br>Icons from the <a href="http://www.oxygen-icons.org/">Oxygen project</a> </p>""" QMessageBox.about(self, "About IT Query", msg) def legend(self): """A simple dialog displaying the color legend used in treeview.""" dialog = legenddlg.legendDialog(self) dialog.exec_() def itSelectFields(self): """ItemTracker field selection dialog.""" fieldNames = self.getItemtrackerFields() dialog = selectfieldsdlg.selectFieldsDialog(fieldNames, self) if self.itSelectedFields is not None: dialog.setSelected(self.itSelectedFields) if dialog.exec_(): self.itSelectedFields = dialog.getSelected() self.updateInfo() def mkWarn(self, msg): """Orange color""" bgColor = "235,115,49" self.mkTable(bgColor, "WARNING", msg) def mkError(self, msg): """Red color""" bgColor = "226,8,0" self.mkTable(bgColor, "ERROR", msg) def mkSuccess(self, msg): """Green color""" bgColor = "55,164,44" self.mkTable(bgColor, "SUCCESS", msg) def mkInfo(self, msg): """Blue color""" bgColor = "0,87,174" self.mkTable(bgColor, "INFO", msg) def mkTable(self, bgColor, status, msg): """Formats message displayed in the log window.""" formatStatus = ('<font style="color:rgb({0})"><strong>{1}</strong>' '</font>'.format(bgColor, status)) self.logBrowser.append("{0}: {1}".format(formatStatus, msg)) def okToContinue(self): """Check before closing.""" if len(self.updatedStrains): reply = QMessageBox(QMessageBox.Question, "Selection", "Entry selection in Bionumerics", QMessageBox.NoButton, self) originalButton = QPushButton("Keep Original Selection") updatedButton = QPushButton("Updated Items Only") cancelButton = QPushButton("Cancel") reply.addButton(originalButton, QMessageBox.ActionRole) reply.addButton(updatedButton, QMessageBox.ActionRole) reply.addButton(cancelButton, QMessageBox.RejectRole) reply.exec_() if reply.clickedButton() == cancelButton: return False elif reply.clickedButton() == originalButton: bn.selectEntries(self.selectedIds.values() +\ self.errorIds.keys()) elif reply.clickedButton() == updatedButton: bn.selectEntries(self.updatedStrains) return True def populateTable(self): """Populates table with data from ItemTracker.""" self.selectedWidget.clear() self.selectedWidget.setSortingEnabled(False) numRows = len(self.tableResults) self.mkInfo("Selected items in ItemTracker: {0}".format(numRows)) self.selectedWidget.setAlternatingRowColors(True) header = ["ItemID", "StrainID", "ItemType", "ItemName", "BacteriaItemID"] self.selectedWidget.setColumnCount(len(header)) self.selectedWidget.setHeaderLabels(header) # use result and populate table for result in self.tableResults: properties = [unicode(i) for i in result] item = QTreeWidgetItem(self.selectedWidget, properties) item.setCheckState(0, Qt.Unchecked) self.selectedWidget.setSortingEnabled(True) for i in range(len(header)): self.selectedWidget.resizeColumnToContents(i) self.stackedWidget.setCurrentIndex(1) # switch view to table self.statusbar.clearMessage() self.populatedTable = True self.updateUi() def populateTree(self): """Populates tree view with information from ItemTracker.""" if len(self.errorIds): self.mkError("{0} entries do not have valid " "ItemTracker IDs in Bionumerics.".format(len(self.errorIds))) for key, msg in self.errorIds.iteritems(): self.mkError("KEY: {0} {1}".format(key, msg)) if not len(self.selectedIds): self.statusbar.showMessage("No items to process", 5000) return parents = {} headers = ["Items", "Selected", "SelectedBy", "Viability", "Volume", "DNA concentration", "UserName", "TubePresent", "InputDate", "AlternID", "Status"] self.treeWidget.setItemsExpandable(True) self.treeWidget.setAlternatingRowColors(True) self.treeWidget.setColumnCount(len(headers)) self.treeWidget.setHeaderLabels(headers) msg = "Getting information from ItemTracker. Please wait..." self.statusbar.showMessage(msg) self.progressBar.setMinimum(0) self.progressBar.setMaximum(0) self.progressBar.show() (treeData, self.itemProperties, message) = lims.GetDictionary((self.selectedIds.keys())) if len(message): for msg in message: self.mkError("ItemTracker error: {0}".format(msg)) if not len(treeData): self.mkError("Could not get data from ItemTracker for" "selected entries") self.statusBar().clearMessage() self.progressBar.hide() self.updateUi() return # bugfix: If ItemType property does not exist for the first item # self.database is not set and tree view is not updated. db = None if not self.database: for item in self.itemProperties.values(): try: db = item["ItemType"] except KeyError: pass if db == "Salmonella": self.database = db break elif db == "Listeria": self.database = db break self.progressBar.setMaximum(len(treeData)) count = 0 for key, value in treeData.iteritems(): count += 1 self.progressBar.setValue(count) if not(value and isinstance(value, dict)): self.mkWarn("No data returned for key {0}".format(key)) continue items = {} items[key] = value for results in self.getData(items, key): parent = parents.get(results[0]) if not parent: parent_id = self.selectedIds[results[0]] self.strainInfo[parent_id] = {self.database:[], "Frozen Stock":[], "DNA":[]} parent = QTreeWidgetItem(self.treeWidget, [unicode(parent_id)]) brush = QBrush() brush.setColor(Qt.blue) parent.setForeground(0, brush) parent.setIcon(0, QIcon(":/branch-closed.png")) parent.setData(0, Qt.CheckStateRole, QVariant()) parents[results[0]] = parent for children in results[1]: itemName = self.itemProperties[children]["ItemName"] if not self.itemIds.get(itemName): self.itemIds[itemName] = children childprops = [] childprops.append(unicode(itemName)) for header in headers[1:]: try: childprop = self.itemProperties[children][header] if childprop is None or childprop == "": childprops.append(unicode("")) else: childprops.append(unicode(childprop)) except KeyError: childprops.append(unicode("")) continue childs = parents.get(children) if not childs: childs = QTreeWidgetItem(parent, childprops) if self.itemProperties[children]["TubePresent"] == "-": childs.setBackgroundColor(0, QColor(232, 87, 82)) childs.setForeground(0, QColor(255, 255, 255)) if self.itemProperties[children]["Selected"] == "yes": childs.setBackgroundColor(0, QColor(119, 183, 83)) childs.setForeground(0, QColor(255, 255, 255)) itype = self.itemProperties[children]["ItemType"] if itype: self.strainInfo[parent_id][itype].append(itemName) parents[children] = childs childs.setCheckState(0, Qt.Unchecked) self.treeWidget.expandAll() for i in range(len(headers)): self.treeWidget.resizeColumnToContents(i) if not self.treeWidget.isEnabled(): self.treeWidget.setEnabled(True) self.mkInfo("Processed <b>{0}</b> entries".format(len(treeData))) self.progressBar.setValue(len(treeData)) self.progressBar.hide() self.populatedTree = True self.updateUi() self.statusbar.showMessage("Ready", 5000) def selectAll(self): """All items are selected (checked).""" index = self.stackedWidget.currentIndex() widget = self.getWidget() it = QTreeWidgetItemIterator(widget, QTreeWidgetItemIterator.NotChecked) count = 0 if index == 0: while it.value(): if it.value().parent(): it.value().setCheckState(0, Qt.Checked) count += 1 it += 1 elif index == 1: while it.value(): it.value().setCheckState(0, Qt.Checked) count += 1 it += 1 if count: self.statusbar.showMessage("Selected {0} items".format(count), 3000) def selectDNA(self): """Select all DNA items.""" self.selectItems("DNA") def selectFrozenStock(self): """Select all Frozen Stock items.""" self.selectItems("Frozen Stock") def selectNone(self): """Clears the selection.""" widget = self.getWidget() it = QTreeWidgetItemIterator(widget, QTreeWidgetItemIterator.Checked) while it.value(): it.value().setCheckState(0, Qt.Unchecked) it += 1 def selectInvert(self): """Inverts the selection.""" index = self.stackedWidget.currentIndex() widget = self.getWidget() it = QTreeWidgetItemIterator(widget) if index == 0: while it.value(): if it.value().parent(): if it.value().checkState(0) == Qt.Checked: it.value().setCheckState(0, Qt.Unchecked) else: it.value().setCheckState(0, Qt.Checked) it += 1 else: while it.value(): if it.value().checkState(0) == Qt.Checked: it.value().setCheckState(0, Qt.Unchecked) else: it.value().setCheckState(0, Qt.Checked) it += 1 def selectItems(self, itemType): """Select all items of a given ItemType.""" self.statusbar.showMessage("Selecting all {0}'s. " "Please wait...".format(itemType)) items = [] itemsAll = [] index = self.stackedWidget.currentIndex() if index == 0: position = 0 items = [item[itemType] for item in self.strainInfo.values()] for item in items: if len(item): itemsAll += item else: position = 3 for item in self.tableResults: if item[2] == itemType: itemsAll.append(item[3]) if not len(itemsAll): self.statusbar.showMessage("No {0}'s in list".format(itemType), 5000) return self.selectNone() widget = self.getWidget() it = QTreeWidgetItemIterator(widget) while it.value(): if it.value().text(position) in itemsAll: it.value().setCheckState(0, Qt.Checked) it += 1 self.statusbar.showMessage("Selected {0} {1}'s".format(len(itemsAll), itemType), 3000) def selectInBionumerics(self, on): """Selects Bionumerics entries with checked items from table view (get all selected) """ actionGroup = QActionGroup(self) actionGroup.addAction(self.actionViewTree) actionGroup.addAction(self.refresh_action) actionGroup.addAction(self.actionSelectAll) actionGroup.addAction(self.actionSelectInvert) actionGroup.addAction(self.actionSelectNone) actionGroup.addAction(self.actionSelectDNA) actionGroup.addAction(self.actionSelectFrozenStock) if on: actionGroup.setEnabled(False) if not len(self.itemNames): self.itemNames = bn.createIdMap() it = QTreeWidgetItemIterator(self.selectedWidget, QTreeWidgetItemIterator.Checked) checkedItems = [] while it.value(): parentCode = unicode(it.value().text(4)) bnStrain = self.itemNames[int(parentCode)] if bnStrain not in checkedItems: checkedItems.append(bnStrain) it += 1 if len(checkedItems): bn.selectEntries(checkedItems) else: self.statusbar.showMessage("No items checked", 3000) else: actionGroup.setEnabled(True) bn.selectEntries(self.selectedIds.values() + self.errorIds.keys()) def updateSelection(self): """Updates selection status in ItemTracker.""" if self.actionSelectInBionumerics.isChecked(): self.selectInBionumerics(False) self.actionSelectInBionumerics.setChecked(False) self.updateButton.setEnabled(False) self.statusbar.showMessage("Updating selection. Please wait...") if self.selectRadioButton.isChecked(): selectedAction = "SELECT" elif self.deselectRadioButton.isChecked(): selectedAction = "DESELECT" checkedItems = {} updatedItems = [] failedItems = [] index = self.stackedWidget.currentIndex() widget = self.getWidget() it = QTreeWidgetItemIterator(widget, QTreeWidgetItemIterator.Checked) if index == 0: while it.value(): itemName = unicode(it.value().text(0)) itemId = self.itemIds[itemName] checkedItems[itemName] = itemId parentItem = self.getParent(it.value()) strain = unicode(parentItem.text(0)) if strain not in self.updatedStrains: self.updatedStrains.append(strain) it += 1 elif index == 1: if not len(self.itemNames): self.itemNames = bn.createIdMap() while it.value(): itemId = unicode(it.value().text(0)) itemName = unicode(it.value().text(3)) checkedItems[itemName] = int(itemId) parentCode = unicode(it.value().text(4)) strain = self.itemNames[int(parentCode)] if strain not in self.updatedStrains: self.updatedStrains.append(strain) it += 1 if not len(checkedItems): self.statusbar.showMessage("No items checked", 5000) self.updateButton.setEnabled(True) return for itemName, itemId in checkedItems.iteritems(): if selectedAction == "SELECT": result = lims.SelectItem(itemId) elif selectedAction == "DESELECT": result = lims.UnselectItem(itemId) if not len(result): updatedItems.append(itemName) else: failedItems.append(itemName) if len(updatedItems): self.mkSuccess("{0}ED {1} items".format(selectedAction, len(updatedItems))) self.logBrowser.append("{0}".format(", ".join(updatedItems))) self.logger.info("{0}\t{1}".format(selectedAction, ", ".join(updatedItems))) if len(failedItems): self.mkError("{0} failed for {1} items".format(selectedAction, len(failedItems))) self.logBrowser.append("{0}".format(", ".join(failedItems))) self.logger.info("{0}\t{1}".format(selectedAction, ", ".join(failedItems))) self.updateButton.setEnabled(True) if len(updatedItems) or len(failedItems): self.populatedTree = False self.populatedTable = False self.refresh() def updateUi(self): """Updates interface based on the view.""" index = self.stackedWidget.currentIndex() # only show export actions in cherry picking if index != 2: widgets = [self.exportToolBar, self.exportActions] self.disableWidgets(widgets) for widget in widgets: widget.setVisible(False) # disable select menu in cherry picking (not implemented) if index == 2: self.selectMenu.setEnabled(False) else: self.selectMenu.setEnabled(True) if index == 0: # Tree View self.disableWidgets([self.actionViewTree, self.actionSelectInBionumerics]) self.enableWidgets([self.actionGetAllSelected, self.actionCherryPicking]) for widget in [self.actionSelectInBionumerics, self.getSelectedToolBar]: widget.setVisible(False) #self.fieldsGroupBox.setVisible(True) widgets = [self.widget, self.treeWidget, self.selectGroupBox, self.fieldsGroupBox, self.actionLegend, self.treeToolBar, self.treeActions, self.selectActions] for widget in widgets: if not widget.isVisible(): widget.setVisible(True) if self.populatedTree: self.enableWidgets(widgets) else: self.disableWidgets(widgets) try: self.treeWidget.selectedItems()[0] except IndexError: self.infoBrowser.setDisabled(True) self.fieldsGroupBox.setEnabled(self.infoBrowser.isEnabled()) elif index == 1: self.widget.setVisible(True) self.enableWidgets([self.actionViewTree, self.actionCherryPicking]) self.actionSelectInBionumerics.setVisible(True) self.getSelectedToolBar.setVisible(True) for widget in [self.actionLegend, self.fieldsGroupBox, self.treeToolBar, self.treeActions]: widget.setVisible(False) self.disableWidgets([self.actionGetAllSelected, self.actionLegend, self.treeToolBar, self.treeActions]) widgets = [self.widget, self.selectedWidget, self.selectGroupBox, self.actionSelectInBionumerics, self.getSelectedToolBar, self.selectActions] if self.populatedTable: self.enableWidgets(widgets) else: self.disableWidgets(widgets) elif index == 2: self.widget.setVisible(False) # ItemTracker and field selection self.actionCherryPicking.setEnabled(False) self.exportToolBar.setVisible(True) self.exportActions.setVisible(True) for action in [self.actionViewTree, self.actionGetAllSelected]: action.setEnabled(True) widgets = [self.selectActions, self.actionSelectInBionumerics, self.actionLegend, self.treeActions, self.treeToolBar, self.getSelectedToolBar] self.disableWidgets(widgets) for widget in widgets: widget.setVisible(False) widgets = [self.cherryView, self.filterGroupBox, self.lcdGroupBox, self.exportActions, self.exportToolBar] if self.populatedCherry: self.enableWidgets(widgets) else: self.disableWidgets(widgets) def updateInfo(self): """Infobar displaying ItemTracker and Bionumerics fields.""" content = ('<table border="0" cellspacing="0" ' 'cellpadding="5" width="100%">') self.infoBrowser.clear() try: selected = self.treeWidget.selectedItems()[0] except IndexError: return else: self.infoBrowser.setEnabled(True) self.fieldsGroupBox.setEnabled(True) try: parentName = self.getParent(selected).text(0) except AttributeError: parentName = None if parentName: itemName = unicode(selected.text(0)) itemId = self.itemIds[itemName] if itemId: content += """\ <tr bgcolor="#85026C"> <th colspan="2" align="left"> <font color="white">ITEMTRACKER</font> </th> </tr>\ """ count = 0 for field, value in (("Strain", parentName), ("Item Name", itemName), ("Item ID", itemId)): if count % 2 == 0: content += """\ <tr> <td>{0}</td> <td>{1}</td> </tr>\ """.format(field, value) else: content += """\ <tr bgcolor="#eee"> <td>{0}</td> <td>{1}</td> </tr>\ """.format(field, value) count += 1 try: properties = self.itemProperties[int(itemId)] except KeyError: self.mkWarn("Could not get properties for " "ItemTracker ID {0}".format(itemId)) if len(properties): try: location = properties["Position"] except KeyError: location = [] if len(location): for field, value in (("Freezer", location[0]), ("Rack", location[1]), ("Shelf", location[2]), ("Plate Rack", location[3]), ("Position", location[4])): if count % 2 == 0: content += """\ <tr> <td>{0}</td> <td>{1}</td> </tr>\ """.format(field, value) else: content += """\ <tr bgcolor="#eee"> <td>{0}</td> <td>{1}</td> </tr>\ """.format(field, value) count += 1 if len(self.itSelectedFields): for itField in self.itSelectedFields: try: itemProperty = properties[itField] except KeyError: itemProperty = "" if count % 2 == 0: content += """\ <tr> <td>{0}</td> <td>{1}</td> </tr>\ """.format(itField, itemProperty) else: content += """\ <tr bgcolor="#eee"> <td>{0}</td> <td>{1}</td> </tr>\ """.format(itField, itemProperty) count += 1 else: content += """\ <tr> <td colspan="2">No information</td> </tr>""" self.infoBrowser.setHtml(QString(content)) content += """\ <tr bgcolor="#CF4913"> <th colspan="2" align="left"> <font color="white">BIONUMERICS</font> </th> </tr>\ """ strainInfo = {} try: strainInfo = self.bnFields.get(unicode(parentName)) except KeyError: self.mkWarn("Could not get information for {0}".format(parentName)) if len(strainInfo): count = 0 for field in self.bnSelectedFields: if count % 2 == 0: content += """\ <tr> <td>{0}</td> <td>{1}</td> </tr>\ """.format(field, strainInfo[field]) else: content += """\ <tr bgcolor="#eee"> <td>{0}</td> <td>{1}</td> </tr>\ """.format(field, strainInfo[field]) count += 1 else: self.mkWarn("No information for {0}".format(parentName)) content += "</table>" else: strainName = unicode(selected.text(0)) itemId = None for ids, keys in self.selectedIds.iteritems(): if keys == strainName: itemId = ids break if not itemId: self.infoBrowser.setHtml(QString(content)) return content = """\ <table border="0" cellpadding="5" cellspacing="0" width="100%"> <tr bgcolor="#85026C"> <th colspan="2" align="left"> <font color="white">ITEMTRACKER</font> </th> </tr> <tr bgcolor="#eee"> <td>AlternID</td> <td>{0}</td> </tr> <tr> <td>OriginalID</td> <td>{1}</td> </tr>\ """.format(self.itemProperties[itemId]["AlternID"], self.itemProperties[itemId]["OriginalID"]) content += "</table>" content += """\ <table border="0" cellpadding="5" cellspacing="0" width="100%"> <tr bgcolor="#BF0361"> <th align="left"> <font color="white">{0}</font> </th> <th align="right"> <font color="white">{1}</font> </th> </tr> <tr> <td colspan="2">{2}</td> </tr>\ """.format(self.database.upper(), len(self.strainInfo[strainName][self.database]), ", ".join(self.strainInfo[strainName][self.database])) content += """\ <tr bgcolor="#00438A"> <th align="left"> <font color="white">FROZEN STOCK</font> </th> <th align="right"> <font color="white">{0}</font> </th> </tr> <tr> <td colspan="2">{1}</td> </tr>\ """.format(len(self.strainInfo[strainName]["Frozen Stock"]), ", ".join(self.strainInfo[strainName]["Frozen Stock"])) content += """\ <tr bgcolor="#00734D"> <th align="left"> <font color="white">DNA</font> </th> <th align="right"> <font color="white">{0}</font> </th> </tr> <tr> <td colspan="2">{1}</td> </tr>\ """.format(len(self.strainInfo[strainName]["DNA"]), ", ".join(self.strainInfo[strainName]["DNA"])) content += "</table>" self.infoBrowser.setHtml(QString(content)) def viewTree(self): """Toolbar button/action to switch to tree view.""" self.selectRadioButton.setChecked(True) if not self.populatedTree: self.stackedWidget.setCurrentIndex(0) self.refresh() self.stackedWidget.setCurrentIndex(0) self.updateUi() def refresh(self): """Updates view(s).""" index = self.stackedWidget.currentIndex() if index == 1: self.populatedTable = False self.selectedWidget.clear() self.getAllSelected() elif index == 0: self.populatedTree = False self.treeWidget.clear() self.treeWidget.setDisabled(True) bnField = "ItemTracker ID" self.selectedIds = {} self.errorIds = {} selection = DB.Db.Selection self.selectedIds, self.errorIds = bn.getItemIds(bnField, selection) if len(self.selectedIds): self.strainInfo = {} self.itemIds = {} self.getBnFields() # self.populateTree() QTimer.singleShot(0, self.populateTree) elif index == 2: self.populatedCherry = False QTimer.singleShot(0, self.cherryPicking) self.updateUi()
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.setWindowTitle('%s %s' % (QApplication.applicationName(), QApplication.applicationVersion())); self.config = ConfigHandler(os.path.join(os.path.expanduser('~'), '.pywv/pywv.cfg'), self) self.setStyle(QStyleFactory.create(self.config.loadStyle())) if self.config.loadStyleSheet(): self.setStyleSheet(self.config.loadStyleSheet()) else: self.setStyleSheet("* {}") # without any stylesheet, windowstyles won't apply self.setDockOptions(QMainWindow.AnimatedDocks | QMainWindow.AllowNestedDocks | QMainWindow.AllowTabbedDocks | QMainWindow.VerticalTabs); # self.dummy = QWidget(self) self.setCentralWidget(QWidget(self)) self.pBar = QProgressBar(self) self.pBar.setRange(0, self.config.loadReloadInterval()) self.pBar.setFormat("%v Sekunden") if not self.config.loadAutoload(): self.pBar.hide() self.statusBar = QStatusBar(self) self.setStatusBar(self.statusBar) self.statusBar.addWidget(self.pBar) self.reloadTimer = QTimer(self); self.reloadTimer.setInterval(self.config.loadReloadInterval() * 1000) self.connect(self.reloadTimer, SIGNAL('timeout()'), self.reload_) if self.config.loadAutoload(): self.reloadTimer.start() self.autoloadStatusTimer = QTimer(self) self.autoloadStatusTimer.setInterval(1000) # 1 sec self.connect(self.autoloadStatusTimer, SIGNAL('timeout()'), self.onAutoloadStatus) self.autoloadStatusTimer.start() self.mAction = self.menuBar().addMenu(self.tr("&Action")) self.mAction.addAction(self.tr("&update"), self.reload_, QKeySequence('F5')) self.mAction.addAction(self.tr("e&xit"), self.onExit, 'Ctrl+Q') self.mStyle = QMenu(self.tr("&Style"), self) for s in list(QStyleFactory.keys()):# // fill in all available Styles self.mStyle.addAction(s) self.connect(self.mStyle, SIGNAL('triggered(QAction*)'), self.onStyleMenu) self.mOption = self.menuBar().addMenu(self.tr("&Options")) self.mOption.addAction(self.tr("reloadinterval") , self.onReloadTime , 'F8') self.mOption.addAction(self.tr("manage links") , self.onNewLink , 'F6') self.mOption.addSeparator() self.ontopAction = QAction(self.tr("always on &top") , self) self.showTrayAction = QAction(self.tr("show tray &icon") , self) self.closeToTrayAction = QAction(self.tr("close to &tray") , self) self.autoloadAction = QAction(self.tr("auto&load") , self) self.ontopAction.setCheckable(True) self.showTrayAction.setCheckable(True) self.closeToTrayAction.setCheckable(True) self.autoloadAction.setCheckable(True) self.showTrayAction.setChecked (self.config.loadShowTray() ) self.ontopAction.setChecked (self.config.loadOntop() ) self.closeToTrayAction.setChecked(self.config.loadCloseToTray()) self.autoloadAction.setChecked (self.config.loadAutoload() ) self.connect(self.ontopAction , SIGNAL('toggled(bool)') , self.onOntopAction) self.connect(self.showTrayAction , SIGNAL('toggled(bool)') , self.onShowTrayAction) self.connect(self.closeToTrayAction , SIGNAL('toggled(bool)') , self.onCloseToTrayAction) self.connect(self.autoloadAction , SIGNAL('toggled(bool)') , self.onAutoloadAction) self.mOption.addAction(self.ontopAction) self.mOption.addAction(self.showTrayAction) self.mOption.addAction(self.closeToTrayAction) self.mOption.addAction(self.autoloadAction) self.mOption.addSeparator() self.mOption.addMenu(self.mStyle) self.trayIcon = QSystemTrayIcon(QIcon(':/appicon'), self); self.trayMgr = TrayManager(self.config, self.trayIcon) self.connect(self.trayIcon, SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), self.onTrayIcon) if self.config.loadShowTray(): self.trayIcon.show() self.trayIconMenu = QMenu() self.trayIconMenu.addAction(self.tr("e&xit"), self.onExit) self.trayIcon.setContextMenu(self.trayIconMenu) self.mAbout = self.menuBar().addMenu(self.tr("&about")) self.mAbout.addAction(QApplication.applicationName(), self.onAboutAppAction) self.mAbout.addAction("Qt", self.onAboutQtAction) self.createWidgets() self.resize(self.config.loadWindowSize()) self.restoreState(self.config.loadWindowState()) if self.config.loadIsVisible(): self.show() self.reload_() def __del__(self): self.config.saveWindowState(self.saveState()) def createSingleWidget(self, name): # print 'crt', name, type(name), '\n', self.widgets # print 'crt', name, type(name) links = self.config.loadLinks() if links[name]['type'] == 'generic': self.widgets[name] = GenericWidget(name, self.config, self) else: pluginsAvail = classdirPlugins().all_() for plugin in pluginsAvail: if links[name]['type'] == plugin['class']: pluginClass = plugin['class'] break else: continue exec('self.widgets[name] = %s(name, self.config, self)' % pluginClass) # print(('loaded plugin', self.widgets[name])) self.addDockWidget(0x4, self.widgets[name]) self.widgets[name].reload_() def delWidget(self, name): #print 'del', name, type(name), '\n', self.widgets self.removeDockWidget(self.widgets[name]) self.widgets[name].deleteLater() self.widgets[name] = None del self.widgets[name] def createWidgets(self): self.widgets = {} for name in self.config.loadLinks(): self.createSingleWidget(name) @pyqtSlot() def onExit(self): self.config.saveWindowSize(self.size()) QApplication.exit(); def closeEvent(self, event): self.config.saveWindowSize(self.size()) # QApplication.exit() # tray is visible -> close to tray # else close app if self.trayIcon.isVisible(): event.accept() else: QApplication.exit() return # if close-to-tray is set, do so if self.config.loadCloseToTray(): event.accept() else: QApplication.exit() return; # save this state if self.trayIcon.isVisible(): self.config.saveIsVisible(False) else: self.config.saveIsVisible(True); @pyqtSlot() def reload_(self): for name in self.widgets: self.widgets[name].reload_() self.pBar.setValue(self.config.loadReloadInterval()) self.reloadTimer.start(self.config.loadReloadInterval()*1000) @pyqtSlot() def onAutoloadStatus(self): self.pBar.setValue(self.pBar.value()-1) # print([idx for idx in self.widgets]) def onStyleMenu(self, a): QApplication.setStyle(QStyleFactory.create(a.text())) self.setStyle(QStyleFactory.create(a.text())) self.config.saveStyle(a.text()) def onReloadTime(self): ok = False value, ok = QInputDialog.getInteger(self, self.tr("reloadinterval"), # title self.tr("insert time in s"), # text self.config.loadReloadInterval(), # default 10, # minimum 86400, # maximum (at least once a day) 1, # step ) if ok: self.config.saveReloadInterval(value) self.pBar.setRange(0,self.config.loadReloadInterval()) self.reload_() def onAutoloadAction(self, b): if b: self.reloadTimer.start() self.pBar.show() self.reload_() else: self.reloadTimer.stop() self.pBar.hide() self.config.saveAutoload(b) def onNewLink(self): inp = LinkInput(self.config, self) if inp.exec_(): # sync active widgets for name in inp.modifiedWidgets(): if name in self.widgets: self.delWidget(name) self.createSingleWidget(name) else: self.createSingleWidget(name) # remove deleted # for name in self.widgets: print 'shown', name # for name in self.config.loadLinks(): print 'conf', name todel = [] for name in self.widgets: if name not in self.config.loadLinks(): todel.append(name) for widget in todel: self.delWidget(widget) def onOntopAction(self, b): if b: self.setWindowFlags(Qt.Dialog | Qt.WindowStaysOnTopHint) else: self.setWindowFlags(Qt.Dialog) self.setWindowIcon(QIcon(':/appicon')) self.show(); self.config.saveOntop(b) def onShowTrayAction(self, b): if b: self.trayIcon.show() else: self.trayIcon.hide() self.config.saveShowTray(b) def onCloseToTrayAction(self, b): self.config.saveCloseToTray(b) def onTrayIcon(self, reason): if reason == QSystemTrayIcon.Trigger: if(self.isVisible()): self.config.saveWindowSize(self.size()) self.hide() self.config.saveIsVisible(False) else: self.show() self.resize(self.config.loadWindowSize()) self.config.saveIsVisible(True) def onAboutAppAction(self): QMessageBox.about(self, self.tr("&about"), self.tr("name %1 version %2").arg(QApplication.applicationName()).arg(QApplication.applicationVersion())) def onAboutQtAction(self): QMessageBox.aboutQt(self, self.tr("&about"))
class GUI(QWidget): def __init__(self, parent=None): super(GUI, self).__init__(parent) self.create_ui_components() self.compose_ui() # Initializing: window composition, it's contents and event handlers self.init_composition() self.init_contents() self.init_actions() self.on_start() def create_ui_components(self): """ Create layouts and qt controls. """ self.layout = QGridLayout() self.kanjiGroup = QGroupBox() self.kanjiLayout = QGridLayout() # Kanji ui group self.day, self.week, self.month, self.year = \ QLabel(KANJI), QLabel(KANJI), QLabel(KANJI), QLabel(KANJI) self.dayLabel, self.weekLabel, self.monthLabel, self.yearLabel = \ QLabel('<b>Day</b>'), QLabel('<b>Week</b>'), \ QLabel('<b>Month</b>'), QLabel('<b>Year</b>') # Main layout self.showAbout = QPushButton('A&bout') # DB controls (top) self.showDB, self.availableDB, self.changeDB = \ QPushButton('&Change DB (active:)'), QComboBox(), QPushButton('&Remap') # General controls (bottom) self.getAll, self.showStats, self.quitApp, self.authGen, self.methodCombo = \ QPushButton('&Get all'), QPushButton('&Stats'), QPushButton('&Quit'), \ QPushButton('&Auth'), QComboBox() # Notifications self.progressBar = QProgressBar() self.statusMessage = QLabel() # About self.aboutBox = QMessageBox() def compose_ui(self): """ Fill layouts and groups, initialize filters. """ self.kanjiLayout.addWidget(self.day, 0, 0) self.kanjiLayout.addWidget(self.week, 0, 1) self.kanjiLayout.addWidget(self.dayLabel, 1, 0) self.kanjiLayout.addWidget(self.weekLabel, 1, 1) self.kanjiLayout.addWidget(self.month, 2, 0) self.kanjiLayout.addWidget(self.year, 2, 1) self.kanjiLayout.addWidget(self.monthLabel, 3, 0) self.kanjiLayout.addWidget(self.yearLabel, 3, 1) self.kanjiGroup.setLayout(self.kanjiLayout) self.layout.addWidget(self.showDB, 0, 0, 1, 2) self.layout.addWidget(self.availableDB, 1, 0) self.layout.addWidget(self.changeDB, 1, 1) self.layout.addWidget(self.kanjiGroup, 2, 0, 1, 2) self.layout.addWidget(self.getAll, 3, 0) self.layout.addWidget(self.showStats, 3, 1) self.layout.addWidget(self.methodCombo, 4, 0) self.layout.addWidget(self.authGen, 4, 1) #self.layout.addWidget(self.quitApp, 5, 0, 1, 2) self.layout.addWidget(self.quitApp, 5, 0) self.layout.addWidget(self.showAbout, 5, 1) self.layout.addWidget(self.progressBar, 6, 0, 1, 2) self.layout.addWidget(self.statusMessage, 7, 0, 1, 2) self.setLayout(self.layout) self.eFilter = LabelEventFilter() def on_start(self): """ Additional procedures run on application start. """ # Let's initialize even some stuff! self.al = None self.auth_thread = None self.init_backend() choose_db(str(self.availableDB.currentText())) self.showDB.setText("&Change DB (active: %s)" % self.availableDB.currentText()) self.stats = StatsUI(self.al, self) def init_composition(self): """ Window composition and general params. """ self.setWindowTitle(NAME + ' ' + __version__) desktop = QApplication.desktop() self.setGeometry((desktop.width() - WIDTH) / 2, (desktop.height() - HEIGHT) / 2, WIDTH, HEIGHT) def init_contents(self): """ Setting up qt controls. """ self.changeDB.hide() self.availableDB.hide() self.availableDB.addItems(dbs.keys()) self.kanjiGroup.setAlignment(Qt.AlignCenter) self.kanjiGroup.setStyleSheet( "QGroupBox { border: 1px solid gray; border-radius: 3px; }") self.day.setAlignment(Qt.AlignCenter) self.week.setAlignment(Qt.AlignCenter) self.month.setAlignment(Qt.AlignCenter) self.year.setAlignment(Qt.AlignCenter) self.dayLabel.setAlignment(Qt.AlignCenter) self.weekLabel.setAlignment(Qt.AlignCenter) self.monthLabel.setAlignment(Qt.AlignCenter) self.yearLabel.setAlignment(Qt.AlignCenter) self.day.setFont(QFont(PRETTY_FONT, KANJI_SIZE)) self.week.setFont(QFont(PRETTY_FONT, KANJI_SIZE)) self.month.setFont(QFont(PRETTY_FONT, KANJI_SIZE)) self.year.setFont(QFont(PRETTY_FONT, KANJI_SIZE)) self.methodCombo.addItems(RandomMess.algs.keys()) self.methodCombo.setCurrentIndex(1) self.statusMessage.setAlignment(Qt.AlignCenter) self.statusMessage.hide() self.statusMessage.setMaximumHeight(MESSAGE_HEIGHT) self.statusMessage.setStyleSheet(WARNING_STYLE) self.progressBar.setMaximum(0) self.progressBar.setMaximumHeight(PROGRESS_HEIGHT) self.progressBar.hide() QToolTip.setFont(QFont(PRETTY_FONT, TOOLTIP_FONT_SIZE)) self.getAll.setToolTip('Randomly select all 4 kanji') self.methodCombo.setToolTip('Choose algorithm for randomness') self.authGen.setToolTip('Authorize on remote RNG services') self.showStats.setToolTip( 'Show/hide dialog with comprehensive statistics') self.quitApp.setToolTip('Close application') self.showDB.setToolTip('Show/hide available databases') self.availableDB.setToolTip('Available kanji frequency charts db') self.changeDB.setToolTip('Pick new kanji from currently selected db') # About dialog self.aboutBox.layout().itemAt(1).widget().setAlignment(Qt.AlignLeft) self.aboutBox.setTextFormat(Qt.RichText) self.aboutBox.setText('Version:\t<b>' + __version__ + '</b><br/>Python:\t<b>' + platform.python_version() + '</b>' + '<br/>Platform:\t<b>' + platform.system() + ' ' + platform.release() + '</b>' + '<br/>Author:\t<b>' + __author__ + '</b>' + app_about) self.aboutBox.setWindowTitle('About ' + app_name) self.aboutBox.setIconPixmap(QPixmap(paths['icon'])) def init_actions(self): """ Binding events/handlers. """ self.showDB.clicked.connect(self.show_available_db) self.changeDB.clicked.connect(self.change_db) self.quitApp.clicked.connect(self.close) self.getAll.clicked.connect(self.get_all) self.authGen.clicked.connect(self.auth_task) self.showStats.clicked.connect(self.show_stats) self.methodCombo.currentIndexChanged.connect(self.update_alg) self.showAbout.clicked.connect(self.app_help) # Mouse events for labels self.day.setAttribute(Qt.WA_Hover, True) self.week.setAttribute(Qt.WA_Hover, True) self.month.setAttribute(Qt.WA_Hover, True) self.year.setAttribute(Qt.WA_Hover, True) self.day.installEventFilter(self.eFilter) self.week.installEventFilter(self.eFilter) self.month.installEventFilter(self.eFilter) self.year.installEventFilter(self.eFilter) ##### actions ##### def show_stats(self): if self.stats.isVisible(): self.stats.hide() else: self.stats.show() def show_available_db(self): if self.availableDB.isVisible(): self.availableDB.hide() self.changeDB.hide() else: self.availableDB.show() self.changeDB.show() def change_db(self): try: choose_db(str(self.availableDB.currentText())) self.availableDB.hide() self.changeDB.hide() self.show_message_then_hide("DB successfully remaped!", False) self.showDB.setText("&Change DB (active: %s)" % self.availableDB.currentText()) self.stats.update_stat_info() self.stats.refresh_plot() except NoDbException as e: self.show_message_then_hide(e.message) def get_all(self): self.random_kanji_task = RandomKanjiTask(self.al) self.random_kanji_task.done.connect(self.update_kanji) self.show_progress('Selecting kanji...') self.random_kanji_task.start() def update_kanji(self, results): if results['success']: kanji_set = results['kanji_set'] for_a_day = kanji_set.pop() for_a_week = kanji_set.pop() for_a_month = kanji_set.pop() for_a_year = kanji_set.pop() self.day.setText(for_a_day.character) self.dayLabel.setText('<b>Day:</b> ' + str(for_a_day.frequency) + ' | ' + str(for_a_day.dominance) + '%') self.week.setText(for_a_week.character) self.weekLabel.setText('<b>Week:</b> ' + str(for_a_week.frequency) + ' | ' + str(for_a_week.dominance) + '%') self.month.setText(for_a_month.character) self.monthLabel.setText('<b>Month:</b> ' + str(for_a_month.frequency) + ' | ' + str(for_a_month.dominance) + '%') self.year.setText(for_a_year.character) self.yearLabel.setText('<b>Year:</b> ' + str(for_a_year.frequency) + ' | ' + str(for_a_year.dominance) + '%') self.kanji_tooltip(self.day) self.kanji_tooltip(self.week) self.kanji_tooltip(self.month) self.kanji_tooltip(self.year) if self.stats.isVisible(): self.stats.update_stat_info() self.stats.refresh_plot() self.hide_message() else: self.show_message_then_hide(results['message']) self.hide_progress() def pretty_font(self): pass def update_alg(self): self.al.set_active(str(self.methodCombo.currentText())) def init_backend(self): self.al = RandomMess() self.update_alg() def auth_task(self): self.auth_thread = AuthorizationTask(self.al) self.auth_thread.done.connect(self.auth_complete) #self.auth_thread.run() # IT DOESN't work on windows as it should! self.auth_thread.start() self.show_progress('Authorizing on RNG services...') def auth_complete(self, success): self.hide_message() self.hide_progress() if success: self.show_message_then_hide("Successfully authenticated!", False) else: self.show_message_then_hide("Sorry, could not authenticate.") def show_message_then_hide(self, message, error=True): if error: self.statusMessage.setStyleSheet(WARNING_STYLE) else: self.statusMessage.setStyleSheet(NOTE_STYLE) self.statusMessage.setText(message) self.statusMessage.show() QTimer.singleShot(MESSAGE_TIMEOUT, self.hide_message) def show_progress(self, message): self.statusMessage.setStyleSheet(NOTE_STYLE) self.statusMessage.setText(message) self.statusMessage.show() self.progressBar.show() def hide_message(self): self.statusMessage.setText('') self.statusMessage.hide() def hide_progress(self): self.progressBar.hide() def toggle_kanji_info(self, label, info): label.setToolTip(info.info()) def kanji_tooltip(self, label): found = JDIC.search(label.text()) if found: label.setToolTip(found.info()) else: label.setToolTip('No such kanji in kanjidic2!') def kanji_info(self, kanji): pass def app_help(self): self.aboutBox.show() #### Utility events #### def resizeEvent(self, QResizeEvent): self.updateStatsPosition() self.updateStatsSize() def moveEvent(self, QMoveEvent): self.updateStatsPosition() self.updateStatsSize() def updateStatsPosition(self): self.stats.move(self.x() + self.width() + 20, self.y()) def updateStatsSize(self): self.stats.resize(QSize(self.stats.width(), self.height()))
class FeedLol(QMainWindow): def __init__(self, parent = None): QMainWindow.__init__(self, parent) self.setWindowTitle("FeedLol") self.aboutAction = QAction(QIcon("data/icons/help-about.svg"), "&About FeedLol...", self) self.connect(self.aboutAction, SIGNAL("triggered()"), self.slotAbout) self.reloadAction = QAction(QIcon("data/icons/view-refresh.svg"), "&Reload", self) self.reloadAction.setShortcut(QKeySequence.Refresh) self.homeAction = QAction(QIcon("data/icons/go-home.svg"), "Go &Home", self) self.homeAction.setShortcut("Alt+Home") self.userAction = QAction(QIcon("data/icons/user-identity.svg"), "&Me", self) self.userAction.setShortcut("Ctrl+M") self.logoutAction = QAction(QIcon("data/icons/dialog-close.svg"), "Log&out", self) self.logoutAction.setShortcut(QKeySequence.Close) self.settingsAction = QAction(QIcon("data/icons/configure.svg"), "&Preferences...", self) self.connect(self.settingsAction, SIGNAL("triggered()"), self.slotSettings) self.toolbar = QToolBar("Toolbar", self) self.toolbar.setObjectName("toolbar") self.toolbar.addAction(self.homeAction) self.toolbar.addAction(self.userAction) self.toolbar.addAction(self.reloadAction) self.toolbar.addSeparator() self.toolbar.addAction(self.logoutAction) self.toolbar.addSeparator() self.toolbar.addAction(self.settingsAction) self.toolbar.addAction(self.aboutAction) self.addToolBar(self.toolbar) self.loadStatus = QProgressBar(self) self.loadStatus.setRange(0, 100) self.loadStatus.setMaximumWidth(200) self.loadStatus.setTextVisible(False) self.loadStatus.hide() self.statusBar().addPermanentWidget(self.loadStatus) self.feedView = FeedView(self) self.setCentralWidget(self.feedView) self.connect(self.feedView, SIGNAL("titleChanged(const QString&)"), self.slotSetTitle) self.connect(self.feedView, SIGNAL("statusBarMessage(const QString&)"), self.statusBar(), SLOT("showMessage(const QString&)")) self.connect(self.feedView, SIGNAL("loadStarted()"), self.loadStart) self.connect(self.feedView, SIGNAL("loadFinished(bool)"), self.loadStop) self.connect(self.feedView, SIGNAL("loadProgress(int)"), self.loadProgress) self.connect(self.reloadAction, SIGNAL("triggered()"), self.feedView.reload) self.connect(self.homeAction, SIGNAL("triggered()"), self.feedView.goHome) self.connect(self.userAction, SIGNAL("triggered()"), self.feedView.goToUserPage) self.connect(self.logoutAction, SIGNAL("triggered()"), self.feedView.logout) self.connect(self.feedView.page(), SIGNAL("linkHovered(const QString&, const QString&, const QString&)"), self.linkHovered) self.settingsDialog = SettingsDialog(self.feedView, self) settings = QSettings() if settings.contains("proxy/type"): proxy = QNetworkProxy() proxyType = settings.value("proxy/type").toInt()[0] proxy.setType( (proxyType == 2) and QNetworkProxy.Socks5Proxy or ( (proxyType == 1) and QNetworkProxy.HttpProxy or QNetworkProxy.NoProxy ) ) if proxy.type() != QNetworkProxy.NoProxy: proxy.setHostName(settings.value("proxy/host").toString()) proxy.setPort(settings.value("proxy/port").toInt()[0]) if settings.value("proxy/user").toString(): proxy.setUser(settings.value("proxy/user").toString()) proxy.setPassword(settings.value("proxy/password").toString()) QNetworkProxy.setApplicationProxy(proxy) if settings.contains("mainWindow/geometry"): self.restoreGeometry(settings.value("mainWindow/geometry").toByteArray()) else: self.resize(320,480) if settings.contains("mainWindow/state"): self.restoreState(settings.value("mainWindow/state").toByteArray()) self.feedView.goHome() def saveConfig(self): settings = QSettings() settings.setValue("mainWindow/geometry", QVariant(self.saveGeometry())) settings.setValue("mainWindow/state", QVariant(self.saveState())) session = self.feedView.siteServer.session from cPickle import dumps session = dumps(session) settings.setValue("session", QVariant(session)) proxy = QNetworkProxy.applicationProxy() proxyType = (proxy.type() == QNetworkProxy.Socks5Proxy) and 2 or ( (proxy.type() == QNetworkProxy.HttpProxy) and 1 or 0 ) settings.setValue("proxy/type", QVariant(proxyType)) settings.setValue("proxy/host", QVariant(proxy.hostName())) settings.setValue("proxy/port", QVariant(proxy.port())) settings.setValue("proxy/user", QVariant(proxy.user())) settings.setValue("proxy/password", QVariant(proxy.password())) def slotAbout(self): from PyQt4.QtGui import QMessageBox QMessageBox.about(self, "FeedLol", "<h2>FeedLol 0.1</h2><p>Copyright © 2008 <a href=\"mailto:[email protected]\">Bodil Stokke</a></p>") def slotSettings(self): self.settingsDialog.updateSettings() if self.settingsDialog.exec_() == QDialog.Accepted: self.settingsDialog.applySettings() def slotSetTitle(self, title): self.setWindowTitle("FeedLol: " + title) def loadStart(self): self.loadStatus.show() def loadStop(self): self.loadStatus.hide() def loadProgress(self, progress): self.loadStatus.setValue(progress) def linkHovered(self, url, title, text): if url and QUrl(url).scheme() != "chrome": self.statusBar().showMessage(url) else: self.statusBar().clearMessage()
class BrowserWindow(QMainWindow): def retranslateUi(self): self.setWindowTitle( QApplication.translate("self", "self", None, QApplication.UnicodeUTF8)) self.menuFile.setTitle( QApplication.translate("self", "&File", None, QApplication.UnicodeUTF8)) self.menuView.setTitle( QApplication.translate("self", "&View", None, QApplication.UnicodeUTF8)) self.menuEdit.setTitle( QApplication.translate("self", "&Edit", None, QApplication.UnicodeUTF8)) self.menuHelp.setTitle( QApplication.translate("self", "&Help", None, QApplication.UnicodeUTF8)) self.toolBar.setWindowTitle( QApplication.translate("self", "toolBar", None, QApplication.UnicodeUTF8)) self.actionHome.setText( QApplication.translate("self", "&Home", None, QApplication.UnicodeUTF8)) self.actionHome.setToolTip( QApplication.translate("self", "Go Home", None, QApplication.UnicodeUTF8)) self.actionShowMenu.setText( QApplication.translate("self", "Show &Menu", None, QApplication.UnicodeUTF8)) self.actionShowToolbar.setText( QApplication.translate("self", "Show &Toolbar", None, QApplication.UnicodeUTF8)) self.actionClose.setText( QApplication.translate("self", "&Close", None, QApplication.UnicodeUTF8)) self.actionModifyWebapp.setText( QApplication.translate("self", "Modify &Webapp", None, QApplication.UnicodeUTF8)) self.actionEditPreferences.setText( QApplication.translate("self", "Edit &Preferences", None, QApplication.UnicodeUTF8)) self.actionPrint.setText( QApplication.translate("self", "&Print", None, QApplication.UnicodeUTF8)) self.actionAbout.setText( QApplication.translate("self", "&About", None, QApplication.UnicodeUTF8)) def __init__(self, appid, base, name): super(BrowserWindow, self).__init__() self.appid = appid self.name = name self.original_name = name self.base = base # Main widgets self.centralwidget = QWidget(self) self.gridLayout_2 = QGridLayout(self.centralwidget) self.setCentralWidget(self.centralwidget) self.urlLineEdit = QLineEdit(self) self.progressBar = QProgressBar(self) # Custom webview self.page = LocalWebPage() self.page.setFeaturePermission(self.page.mainFrame(), LocalWebPage.Notifications, LocalWebPage.PermissionGrantedByUser) self.webkitNotifications = WebkitNotifications(self) self.webViewMain = LocalWebView(self.centralwidget) self.webViewMain.setPage(self.page) self.gridLayout_2.addWidget(self.webViewMain, 0, 0, 1, 1) self.webViewMain.setContentsMargins(0, 0, 0, 0) self.gridLayout_2.setContentsMargins(0, 0, 0, 0) self.menubar = QMenuBar(self) self.menuFile = QMenu(self.menubar) self.menuView = QMenu(self.menubar) self.menuEdit = QMenu(self.menubar) self.menuHelp = QMenu(self.menubar) self.setMenuBar(self.menubar) self.statusbar = QStatusBar(self) self.setStatusBar(self.statusbar) self.toolBar = QToolBar(self) self.toolBar.setMovable(False) self.toolBar.setFloatable(False) self.addToolBar(Qt.TopToolBarArea, self.toolBar) # Create actions self.actionOpenLinkInNewWindow = self.page.action( self.page.OpenLinkInNewWindow) self.actionOpenLinkInNewWindow.setText( tr('BrowserWindow', 'Open in &Browser')) self.actionBack = self.page.action(self.page.Back) self.actionForward = self.page.action(self.page.Forward) self.actionStop = self.page.action(self.page.Stop) self.actionReload = self.page.action(self.page.Reload) self.actionHome = QAction(self) self.actionShowMenu = QAction(self) self.actionShowMenu.setCheckable(True) self.actionShowToolbar = QAction(self) self.actionShowToolbar.setCheckable(True) self.actionClose = QAction(self) self.actionModifyWebapp = QAction(self) self.actionEditPreferences = QAction(self) self.actionPrint = QAction(self) self.actionSaveLink = self.page.action(self.page.DownloadLinkToDisk) self.actionSaveLink.setEnabled(False) self.actionAbout = QAction(self) # Populate menu and toolbars self.menuFile.addAction(self.actionHome) self.menuFile.addAction(self.actionBack) self.menuFile.addAction(self.actionForward) self.menuFile.addAction(self.actionStop) self.menuFile.addAction(self.actionReload) self.menuFile.addSeparator() self.menuFile.addAction(self.actionPrint) self.menuFile.addSeparator() self.menuFile.addAction(self.actionClose) self.menuView.addAction(self.actionShowMenu) self.menuView.addAction(self.actionShowToolbar) self.menuView.addSeparator() self.menuEdit.addAction(self.actionModifyWebapp) #self.menuEdit.addAction(self.actionEditPreferences) self.menuHelp.addAction(self.actionAbout) self.menubar.addAction(self.menuFile.menuAction()) self.menubar.addAction(self.menuEdit.menuAction()) self.menubar.addAction(self.menuView.menuAction()) self.menubar.addAction(self.menuHelp.menuAction()) self.toolBar.addAction(self.actionHome) self.toolBar.addAction(self.actionBack) self.toolBar.addAction(self.actionForward) self.toolBar.addWidget(self.urlLineEdit) self.toolBar.addAction(self.actionStop) self.toolBar.addAction(self.actionReload) self.retranslateUi() QMetaObject.connectSlotsByName(self) self.setWindowTitle(self.name) # Set up cookie jar that persists sessions self.cookieJar = PersistableCookieJar(self, identifier=self.appid) self.cookieJar.load() self.webViewMain.page().networkAccessManager().setCookieJar( self.cookieJar) # Set up link delegation so that external links open in web browser. self.webViewMain.page().setLinkDelegationPolicy( QWebPage.DelegateExternalLinks) self.desktopEntry = desktop.getEntry(self.appid) # Set icons for actions; this can't be done in the designer, AFAICT self.actionHome.setIcon(QIcon.fromTheme('go-home')) self.actionAbout.setIcon(QIcon.fromTheme('help-about')) # Set up shortcuts self.actionStop.setShortcut(Qt.Key_Escape) self.actionBack.setShortcut(QKeySequence.Back) self.actionForward.setShortcut(QKeySequence.Forward) self.actionReload.setShortcut(QKeySequence.Refresh) self.actionHome.setShortcut('Ctrl+Home') self.actionShowMenu.setShortcut('Ctrl+m') self.actionShowToolbar.setShortcut('Ctrl+t') self.actionPrint.setShortcut(QKeySequence.Print) self.backShortcut = QShortcut(self) self.backShortcut.setKey(Qt.Key_Back) self.backShortcut.activated.connect(self.webViewMain.back) self.forwardShortcut = QShortcut(self) self.forwardShortcut.setKey(Qt.Key_Forward) self.forwardShortcut.activated.connect(self.webViewMain.forward) # Set up context menu self.webViewMain.setContextMenuPolicy(Qt.CustomContextMenu) self.webViewMain.customContextMenuRequested.connect(self.showMenu) # Setup statusbar and toolbar for c in self.statusBar().children()[0].children(): c.removeWidget(c) self.statusBar().addPermanentWidget(self.progressBar, 1) self.actionShowToolbar.setChecked(True) self.actionShowMenu.setChecked(True) # Icon if self.desktopEntry.hasKey('Icon'): self.icon = QIcon(self.desktopEntry.get('Icon')) self.setWindowIcon(self.icon) else: self.webViewMain.iconChanged.connect(self.setWindowIcon) # Set up events if self.desktopEntry.get('X-%s-menu-enabled' % APP_NAME) == '0': self.actionShowMenu.setChecked(False) else: self.actionShowMenu.setChecked(True) if self.desktopEntry.get('X-%s-toolbar-enabled' % APP_NAME) == '0': self.actionShowToolbar.setChecked(False) else: self.actionShowToolbar.setChecked(True) self.webViewMain.linkClicked.connect(self._onLinkClick) self.webViewMain.titleChanged.connect(self.setWindowTitle) self.webViewMain.loadProgress.connect(self._setLoadingStatus) self.webViewMain.urlChanged.connect( lambda x: self.urlLineEdit.setText(x.toString())) self.page.printRequested.connect(self._onPrint) self.page.loadFinished.connect(self._loadingFinished) self.actionHome.triggered.connect( lambda x: self.webViewMain.load(QUrl(self.base))) self.actionClose.triggered.connect(self.close) self.actionPrint.triggered.connect(self._onPrint) self.urlLineEdit.returnPressed.connect(self._onUrlEdit) self.actionShowToolbar.triggered.connect(self._onShowToolbar) self.actionShowMenu.triggered.connect(self._onShowMenu) self.actionAbout.triggered.connect(lambda x: about.show(self)) self.actionModifyWebapp.triggered.connect(self._onModify) self._onShowMenu() self._onShowToolbar() try: self.resize(int(self.desktopEntry.getWindowWidth()), int(self.desktopEntry.getWindowHeight())) except (ValueError, TypeError): self.resize(800, 600) # Load first page self.webViewMain.load(QUrl(base)) self.editor = SiteEditorWindow(self.desktopEntry, isNew=False) def _onModify(self): self.editor.show() def closeEvent(self, qCloseEvent): self.desktopEntry.setWindowWidth(self.width()) self.desktopEntry.setWindowHeight(self.height()) self.desktopEntry.write() def _onPrint(self): printer = QPrinter() dialog = QPrintDialog(printer, self) if dialog.exec_() != QDialog.Accepted: return self.page.mainFrame().print_(printer) def _loadingFinished(self): # TODO: Add user scripts here # TODO: Add user styles here # Override window.webkitNotifications self.page.mainFrame().addToJavaScriptWindowObject( "_x_webplier_webkitNotifications", self.webkitNotifications) self.page.mainFrame().evaluateJavaScript( WebkitNotifications.JAVASCRIPT) def _setLoadingStatus(self, value): if value < 100: self.progressBar.setValue(value) self.progressBar.show() self.statusBar().show() self.actionReload.setVisible(False) self.actionStop.setVisible(True) else: self.page.setFeaturePermission( self.page.mainFrame(), LocalWebPage.Notifications, LocalWebPage.PermissionGrantedByUser) self.progressBar.hide() self.statusBar().hide() self.actionReload.setVisible(True) self.actionStop.setVisible(False) def _onUrlEdit(self): url = unicode(self.urlLineEdit.text()) qurl = QUrl(url) if not qurl.scheme(): qurl.setScheme('http') self.webViewMain.load(qurl) def _onLinkClick(self, qurl): url = unicode(qurl.toString()) if not unicode(url).startswith(self.base): webbrowser.open(url, 1) else: self.webViewMain.load(qurl) def _onShowToolbar(self): if self.actionShowToolbar.isChecked(): self.toolBar.show() self.desktopEntry.set('X-%s-toolbar-enabled' % APP_NAME, '1') else: self.toolBar.hide() self.desktopEntry.set('X-%s-toolbar-enabled' % APP_NAME, '0') def _onShowMenu(self): if self.actionShowMenu.isChecked(): self.menubar.show() self.desktopEntry.set('X-%s-menu-enabled' % APP_NAME, '1') else: self.menubar.hide() self.desktopEntry.set('X-%s-menu-enabled' % APP_NAME, '0') def showMenu(self, point): m = self.webViewMain.page().createStandardContextMenu() # TODO: Make this less awful and fragile for a in m.actions(): if a == self.actionSaveLink: m.removeAction(a) m.addSeparator() m.addAction(self.actionShowMenu) m.addAction(self.actionShowToolbar) globalpos = self.mapToParent(point) m.exec_(globalpos)
class Entity(QWidget): def __init__(self, base_image, size, hp=100, pos=(0, 0), parent=None): super().__init__(parent) self._base_label = QLabel(self) self._base_image = base_image self._size = size self._decor_label = None self._decor_pixmap = None self._hp_max = hp self.__pixmap = None """:type: PyQt4.QtGui.QPixmap""" self.__cord_x = pos[0] self.__cord_y = pos[1] self.__angle = 0 self.__hp_bar = QProgressBar(self) self.__hp_bar.setMaximum(self._hp_max) self.__hp_bar.setValue(self._hp_max) self.__hp_bar.setTextVisible(False) self.__hp_bar.setMaximumSize(size[0], 5) self.setAlignment(Qt.AlignCenter) self.updatePixmap() if _debugging: self.setStyleSheet("border: 1px solid black") @property def health(self): return self.__hp_bar.value() @health.setter def health(self, hp): if hp > self._hp_max: hp = self._hp_max elif hp < 0: hp = 0 self.__hp_bar.setValue(hp) @property def angle(self): return self.__angle @angle.setter def angle(self, angle): self.__angle = angle self.updatePixmap() @property def cord_x(self): return self.__cord_x @cord_x.setter def cord_x(self, cord): self.__cord_x = cord self.move(self.cord_x, self.cord_y) @property def cord_y(self): return self.__cord_y @cord_y.setter def cord_y(self, cord): self.__cord_y = cord self.move(self.cord_x, self.cord_y) def hide_hp_bar(self, bool=False): if bool: self.__hp_bar.hide() else: self.__hp_bar.show() def add_decoration(self, path): if path is None: self._decor_label.deleteLater() self._decor_label = None else: self._decor_label = QLabel(self) self._decor_pixmap = QPixmap(path) # self._decor_pixmap = self._decor_pixmap.scaled(self._size[0], self._size[1]) self._decor_pixmap = self._decor_pixmap.transformed(QTransform().rotate(self.angle)) self._decor_label.setPixmap(self._decor_pixmap) self._decor_label.setAlignment(Qt.AlignCenter) self._decor_label.show() def updatePixmap(self): path = get_asset_path(self._base_image) self.__pixmap = QPixmap(path) self.__pixmap = self.__pixmap.scaled(self._size[0], self._size[1]) self.__pixmap = self.__pixmap.transformed(QTransform().rotate(self.angle)) self._base_label.setPixmap(self.__pixmap) self._base_label.show() # self.setFixedSize(self.__pixmap.width(), self.__pixmap.height()) def setFixedSize(self, x, y): super().setFixedSize(x, y) self._base_label.setFixedSize(x, y) def setAlignment(self, alignment): self._base_label.setAlignment(alignment)
class LabelAssistDialog(QDialog): """ A simple UI for showing bookmarks and navigating to them. FIXME: For now, this window is tied to a particular lane. If your project has more than one lane, then each one will have it's own bookmark window, which is kinda dumb. """ def __init__(self, parent, topLevelOperatorView): super(LabelAssistDialog, self).__init__(parent) # Create thread router to populate table on main thread self.threadRouter = ThreadRouter(self) # Set object classification operator view self.topLevelOperatorView = topLevelOperatorView self.setWindowTitle("Label Assist") self.setMinimumWidth(500) self.setMinimumHeight(700) layout = QGridLayout() layout.setContentsMargins(10, 10, 10, 10) # Show variable importance table rows = 0 columns = 4 self.table = QTableWidget(rows, columns) self.table.setHorizontalHeaderLabels( ['Frame', 'Max Area', 'Min Area', 'Labels']) self.table.verticalHeader().setVisible(False) # Select full row on-click and call capture double click self.table.setSelectionBehavior(QTableView.SelectRows) self.table.doubleClicked.connect(self._captureDoubleClick) layout.addWidget(self.table, 1, 0, 3, 2) # Create progress bar self.progressBar = QProgressBar() self.progressBar.setMinimum(0) self.progressBar.setMaximum(0) self.progressBar.hide() layout.addWidget(self.progressBar, 4, 0, 1, 2) # Create button to populate table self.computeButton = QPushButton('Compute object info') self.computeButton.clicked.connect(self._triggerTableUpdate) layout.addWidget(self.computeButton, 5, 0) # Create close button closeButton = QPushButton('Close') closeButton.clicked.connect(self.close) layout.addWidget(closeButton, 5, 1) # Set dialog layout self.setLayout(layout) def _triggerTableUpdate(self): # Check that object area is included in selected features featureNames = self.topLevelOperatorView.SelectedFeatures.value if 'Standard Object Features' not in featureNames or 'Count' not in featureNames[ 'Standard Object Features']: box = QMessageBox( QMessageBox.Warning, 'Warning', 'Object area is not a selected feature. Please select this feature on: \"Standard Object Features > Shape > Size in pixels\"', QMessageBox.NoButton, self) box.show() return # Clear table self.table.clearContents() self.table.setRowCount(0) self.table.setSortingEnabled(False) self.progressBar.show() self.computeButton.setEnabled(False) # Compute object features and number of labels per frame def compute_features(): features = self.topLevelOperatorView.ObjectFeatures([]).wait() labels = self.topLevelOperatorView.LabelInputs([]).wait() return features, labels req = Request(compute_features) req.notify_finished(self._populateTable) req.submit() @threadRouted def _populateTable(self, features_and_labels): features, labels = features_and_labels self.progressBar.hide() self.computeButton.setEnabled(True) for frame, objectFeatures in features.iteritems(): # Insert row rowNum = self.table.rowCount() self.table.insertRow(self.table.rowCount()) # Get max and min object areas areas = objectFeatures['Standard Object Features']['Count'] maxObjArea = numpy.max(areas[numpy.nonzero(areas)]) minObjArea = numpy.min(areas[numpy.nonzero(areas)]) # Get number of labeled objects labelNum = numpy.count_nonzero(labels[frame]) # Load fram number item = QTableWidgetItem(str(frame)) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.table.setItem(rowNum, 0, item) # Load max object areas item = QTableWidgetItemWithFloatSorting( str("{: .02f}".format(maxObjArea))) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.table.setItem(rowNum, 1, item) # Load min object areas item = QTableWidgetItemWithFloatSorting( str("{: .02f}".format(minObjArea))) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.table.setItem(rowNum, 2, item) # Load label numbers item = QTableWidgetItemWithFloatSorting( str("{: .01f}".format(labelNum))) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.table.setItem(rowNum, 3, item) # Resize column size to fit dialog size self.table.horizontalHeader().setResizeMode(QHeaderView.Stretch) # Sort by max object area self.table.setSortingEnabled(True) self.table.sortByColumn(1) def _captureDoubleClick(self): # Navigate to selected frame index = self.table.selectedIndexes()[0] frameStr = self.table.model().data(index).toString() if frameStr: frameNum = int(frameStr) self.parent().editor.posModel.time = frameNum
def __init__(self, parent=None): QWidget.__init__(self, parent) self.home_url = None self.webview = WebView(self) self.connect(self.webview, SIGNAL("loadFinished(bool)"), self.load_finished) self.connect(self.webview, SIGNAL("titleChanged(QString)"), self.setWindowTitle) self.connect(self.webview, SIGNAL("urlChanged(QUrl)"), self.url_changed) home_button = create_toolbutton(self, icon=get_icon('home.png'), tip=_("Home"), triggered=self.go_home) zoom_out_button = action2button(self.webview.zoom_out_action) zoom_in_button = action2button(self.webview.zoom_in_action) pageact2btn = lambda prop: action2button(self.webview.pageAction(prop), parent=self.webview) refresh_button = pageact2btn(QWebPage.Reload) stop_button = pageact2btn(QWebPage.Stop) previous_button = pageact2btn(QWebPage.Back) next_button = pageact2btn(QWebPage.Forward) stop_button.setEnabled(False) self.connect(self.webview, SIGNAL("loadStarted()"), lambda: stop_button.setEnabled(True)) self.connect(self.webview, SIGNAL("loadFinished(bool)"), lambda: stop_button.setEnabled(False)) progressbar = QProgressBar(self) progressbar.setTextVisible(False) progressbar.hide() self.connect(self.webview, SIGNAL("loadStarted()"), progressbar.show) self.connect(self.webview, SIGNAL("loadProgress(int)"), progressbar.setValue) self.connect(self.webview, SIGNAL("loadFinished(bool)"), lambda _state: progressbar.hide()) label = QLabel(self.get_label()) self.url_combo = UrlComboBox(self) self.connect(self.url_combo, SIGNAL('valid(bool)'), self.url_combo_activated) self.connect(self.webview, SIGNAL("iconChanged()"), self.icon_changed) self.find_widget = FindReplace(self) self.find_widget.set_editor(self.webview) self.find_widget.hide() find_button = create_toolbutton(self, icon='find.png', tip=_("Find text"), toggled=self.toggle_find_widget) self.connect(self.find_widget, SIGNAL("visibility_changed(bool)"), find_button.setChecked) hlayout = QHBoxLayout() for widget in (previous_button, next_button, home_button, find_button, label, self.url_combo, zoom_out_button, zoom_in_button, refresh_button, progressbar, stop_button): hlayout.addWidget(widget) layout = QVBoxLayout() layout.addLayout(hlayout) layout.addWidget(self.webview) layout.addWidget(self.find_widget) self.setLayout(layout)
class Base(QMainWindow): """ Esta clase sirve de base para todos aquellos formularios que siguen el estandar de dos pestañas, una para navegación y otra para edición """ orientation = QPrinter.Portrait pageSize = QPrinter.Letter web = "" def __init__(self, parent, own_toolbar=False): """ @param parent: El widget padre de esta ventana @param own_toolbar: Si este widget dibujara su toolbar en el padre o en el mismo @type parent: QWidget @type own_toolbar: bool """ super(Base, self).__init__(parent) self.user = user.LoggedUser self._status = True self.parentWindow = parent self.own_toolbar = own_toolbar self.database = QSqlDatabase.database() """ @type: QSqlDatabase @ivar: La base de datos a la cual se conecta el sistema """ self.mapper = QDataWidgetMapper(self) u""" @type: QDataWidgetMapper @ivar: El mapper que se encarga de asignar los datos del modelo de navegación a los distintos widgets """ self.printProgressBar = QProgressBar(self) self.webview = QWebView() """ @ivar: EL objeto webview usado para cargar los reportes @type: QWebView """ self.loaded = False """ @ivar: Si se pudo o no cargar un reporte @type: bool """ self.startUi() self.editmodel = None self.printer = QPrinter() self._status = False def startUi(self): """ Iniciar todos los elementos graficos """ self.setupUi(self) if not self.own_toolbar: self.parent().addToolBar(self.toolBar) self.removeToolBar(self.toolBar) settings = QSettings() self.restoreState(settings.value(self.windowTitle() + "/State").toByteArray()) """ @ivar: El MainWindow al que pertenece este widget """ self.createActions() self.printProgressBar.setVisible(False) _tab1shortcut = QShortcut(QKeySequence("Ctrl+1"), self, functools.partial(self.tabWidget.setCurrentIndex, 0)) _tab2shortcut = QShortcut(QKeySequence("Ctrl+2"), self, functools.partial(self.tabWidget.setCurrentIndex, 1)) self.mapper.currentIndexChanged[int].connect(self.updateDetailFilter) self.actionCut.setVisible(False) self.actionPaste.setVisible(False) self.actionCopy.setVisible(False) def closeEvent(self, event): u""" Guardar el tamaño, la posición en la pantalla y la posición de la barra de tareas Preguntar si realmente se desea cerrar la pestaña cuando se esta en modo edición """ if not self.status: if ( not QMessageBox.question( self, qApp.organizationName(), u"¿Está seguro que desea salir?", QMessageBox.Yes | QMessageBox.No ) == QMessageBox.Yes ): event.ignore() # Guardar el tamaño y la posición settings = QSettings() settings.setValue(self.windowTitle() + "/Geometry", self.saveGeometry()) if not self.own_toolbar: self.parent().mdiArea().parent().parent().removeToolBar(self.toolBar) def editCell(self): """ Editar la celda actualmente seleccionada de self.tableedit """ self.tabledetails.edit(self.tabledetails.selectionModel().currentIndex()) @pyqtSlot(QDateTime) @if_edit_model def on_dtPicker_dateTimeChanged(self, datetime): """ Cambiar el tipo de cambio del modelo de edición si cambia la fecha @param datetime: La fecha contenida en self.dtPicker @type datetime: QDateTime """ query = QSqlQuery() try: if not self.database.isOpen(): if not self.database.open(): raise Exception( "No se pudo conectar a la base de " + "datos para recuperar los tipos " + "de cambio" ) q = """ SELECT idtc, tasa FROM tiposcambio WHERE fecha = %s LIMIT 1 """ % datetime.toString( "yyyyMMdd" ) if not query.exec_(q): raise UserWarning("No se pudieron recuperar los tipos de " + "cambio") if not query.size() == 1: logging.critical(u"La consulta para obtener tipos de " + "cambio no devolvio exactamente un valor") raise UserWarning(u"Hubo un error al obtener los tipos " + "de cambio") query.first() self.editmodel.exchangeRateId = query.value(0).toInt()[0] self.editmodel.exchangeRate = Decimal(query.value(1).toString()) # self.editmodel.setData( self.editmodel.index( 0, 0 ), self.editmodel.index( 0, 0 ).data() ) self.editmodel.datetime = datetime except UserWarning as inst: QMessageBox.critical(self, qApp.organizationName(), unicode(inst)) self.dtPicker.setDateTime(self.editmodel.datetime) logging.error(inst) logging.error(query.lastError().text()) except Exception as inst: QMessageBox.critical(self, qApp.organizationName(), u"Hubo un error al obtener los tipos de" + " cambio") logging.critical(query.lastError().text()) logging.critical(inst) self.dtPicker.setDateTime(self.editmodel.datetime) def navigate(self, to): """ Esta funcion se encarga de navegar entro los distintos documentos @param to: es una string que puede tomar los valores 'next' 'previous' 'first' 'last' """ if self.mapper.currentIndex != -1: row = self.mapper.currentIndex() if to == "next": row += 1 if row >= self.navproxymodel.rowCount(): row = self.navproxymodel.rowCount() - 1 self.mapper.setCurrentIndex(row) elif to == "previous": if row <= 1: row = 0 else: row = row - 1 self.mapper.setCurrentIndex(row) elif to == "first": self.mapper.toFirst() elif to == "last": self.mapper.toLast() else: self.mapper.toLast()() if self.tabledetails != None: self.tabledetails.resizeColumnsToContents() self.tabledetails.horizontalHeader().setStretchLastSection(True) self.tablenavigation.selectRow(self.mapper.currentIndex()) def updateDetailFilter(self, _index): """ Esta función se debe implementar en los formularios para que al navegar se actualize el filtro de la tabla detalles @param index: Este es el indice del mapper en el que actualmente se encuentra navegando @type index: int """ QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha " + "sido implementada") raise NotImplementedError() def loadModels(self): """ Esta función se ejecuta en el constructor del formulario mediante un QTimer, carga los formularios por primera vez """ self.updateModels() self.navigate("last") self.status = True def _setStatus(self, stat): """ @param stat: False = editando, True = navegando @type stat: bool """ self._status = stat self.setControls(self._status) def _getStatus(self): """ esta propiedad cambia entre navegar y editar """ return self._status status = property(_getStatus, _setStatus) @pyqtSlot(unicode) def on_txtSearch_textChanged(self, searchstring): """ Cambiar el filtro para el navigation model @param searchstring: Es el contenido por el cual se va a filtrar el modelo de navegación @type searchstring: string """ self.navproxymodel.setFilterFixedString(searchstring) @pyqtSlot(QModelIndex) def on_tablenavigation_doubleClicked(self, index): """ Al hacer doble click en la tabla de navegación el se cambia a la pestaña detalles mostrando el documento seleccionado @param index: El indice de la tabla en la que se dio doble click @type index: QModelIndex """ self.mapper.setCurrentIndex(index.row()) self.tabWidget.setCurrentIndex(0) @pyqtSlot(QModelIndex) def on_tablenavigation_clicked(self, index): self.mapper.setCurrentIndex(index.row()) def save(self, ask=True): """ Guardar el documento actual @param ask: Si se deberia o no preguntar al usuario si esta seguro antes de proceder @type ask: bool """ if ( ask == False or QMessageBox.question( self, qApp.organizationName(), u"¿Esta seguro que desea guardar?", QMessageBox.Yes | QMessageBox.No ) == QMessageBox.Yes ): if self.editmodel.valid: if self.editmodel.save(): QMessageBox.information(self, qApp.organizationName(), u"El documento se ha guardado con éxito") self.editmodel = None self.updateModels() self.navigate("last") self.status = True else: QMessageBox.critical(self, qApp.organizationName(), "Ha ocurrido un error al guardar el documento") else: try: QMessageBox.warning(self, qApp.organizationName(), self.editmodel.validError) except AttributeError: QMessageBox.warning( self, qApp.organizationName(), u"El documento no puede guardarse" + " ya que la información no esta" + " completa", ) def setControls(self, unused_status): """ Habilitar o deshabilitar los controles según status @param status: @type status: bool """ QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha sido implementada") raise NotImplementedError() def addLine(self): """ añadir una linea a table edit, solo se llama directamente en una ocasion, al comenzar la edicion de un documento """ row = self.editmodel.rowCount() self.editmodel.insertRows(row) def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered"): """ Crear un objeto acción @param text: El texto de la acción @type text: string @param slot: El slot que se ejecutara cuando se dispare esta acción @type slot: callable @param shortcut: El acceso directo que tiene asignada esta acción @type shortcut: QKeySequence @param icon: El icono de esta acción @type icon: string @param tip: El tooltip que tendra esta acción @type tip: string @param checkable: Si esta acción es checkable o no @type checkable: bool @param signal: La señal en la que esta acción ejecutara el slot @type signal: string @rtype: QAction """ action = QAction(text, self) if icon is not None: if type(icon) == QIcon: action.setIcon(icon) else: action.setIcon(QIcon(icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: getattr(action, signal).connect(slot) if checkable: action.setCheckable(True) return action def newDocument(self): """ Empezar la edición de un nuevo documento """ QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha sido implementada") raise NotImplementedError() def cancel(self): """ Cancelar la edición del nuevo documento """ QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha sido implementada") raise NotImplementedError() @property def printIdentifier(self): """ La identificación de este documento para reporte, normalmente sera el iddocumento o el ndocimpreso @rtype:string """ raise NotImplementedError(u"printIdentifier debe implementarse para " + "poder imprimir") def preview(self): """ Muestra el dialogo de vista previa de impresión """ try: printer = QPrinter() printer.setOrientation(self.orientation) printer.setPageSize(self.pageSize) web = self.web + self.printIdentifier report = reports.frmReportes(web, printer, self) report.exec_() except NotImplementedError as inst: QMessageBox.information( self, qApp.organizationName(), u"No se ha implementado la función de impresión para este modulo" ) logging.error(unicode(inst)) except UserWarning as inst: QMessageBox.critical(self, qApp.organizationName(), unicode(inst)) logging.error(unicode(inst)) except Exception as inst: QMessageBox.critical(self, qApp.organizationName(), "Hubo un error al intentar mostrar su reporte") logging.critical(unicode(inst)) def printDocument(self): """ Imprime el documento actual """ try: base = reports.Reports.url if base == "": raise UserWarning(u"No existe una configuración para el " + "servidor de reportes") self.printer.setOrientation(self.orientation) self.printer.setPageSize(self.pageSize) web = base + self.web + self.printIdentifier + "&uname=" + self.user.user + "&hash=" + self.user.hash self.loaded = False self.webview.load(QUrl(web)) self.webview.loadFinished[bool].connect(self.on_webview_loadFinished) self.webview.loadProgress[int].connect(self.on_webview_loadProgress) except NotImplementedError as inst: logging.error(unicode(inst)) QMessageBox.information( self, qApp.organizationName(), u"La función de impresión no se ha " + "implementado para este modulo" ) except UserWarning as inst: logging.error(unicode(inst)) QMessageBox.critical(self, qApp.organizationName(), unicode(inst)) except Exception as inst: logging.critical(unicode(inst)) QMessageBox.critical(self, qApp.organizationName(), "Hubo un problema al intentar imprimir" + " su reporte") def on_webview_loadProgress(self, progress): """ Muestra el progreso de la carga del reporte en un progressBar """ self.printProgressBar.setValue(progress) def on_webview_loadFinished(self, status): if self.printProgressBar.isVisible(): self.printProgressBar.hide() if not status: QMessageBox.critical(self, qApp.organizationName(), "El reporte no se pudo cargar") logging.error("No se pudo cargar el reporte") self.loaded = True printdialog = QPrintDialog(self.printer, self) if printdialog.exec_() == QDialog.Accepted: self.webview.print_(self.printer) del self.webview def deleteRow(self): """ Funcion usada para borrar lineas de la tabla """ index = self.tabledetails.currentIndex() if not index.isValid(): return row = index.row() self.editmodel.removeRows(row, 1) self.updateLabels() def updateLabels(self): """ Este metodo se llama para actualizar las etiquetas de totales en el formulario """ raise NotImplementedError() def createActions(self): """ Crea las acciones predefinidas del sistema """ self.actionNew = self.createAction( text="Nuevo", tip="Crear un nuevo documento", icon=QIcon.fromTheme("document-new", QIcon(":/icons/res/document-new.png")), shortcut="Ctrl+n", slot=self.newDocument, ) self.actionPreview = self.createAction( text="Previsualizar", tip=u"Vista de impresión del documento", icon=QIcon.fromTheme("document-preview", QIcon(":/icons/res/document-preview.png")), shortcut="Ctrl+p", slot=self.preview, ) self.actionPrint = self.createAction( text="Imprimir", tip="Imprimir el documento", icon=QIcon.fromTheme("document-print", QIcon(":/icons/res/document-print.png")), slot=self.printDocument, ) self.actionSave = self.createAction( text="Guardar", tip="Guardar el documento", icon=QIcon.fromTheme("document-save", QIcon(":/icons/res/document-save.png")), shortcut="Ctrl+g", slot=self.save, ) self.actionCancel = self.createAction( text="Cancelar", tip=u"Cancelar la creación del nuevo documento", icon=QIcon.fromTheme("dialog-cancel", QIcon(":/icons/res/dialog-cancel.png")), shortcut="Esc", slot=self.cancel, ) # edicion, TODO: QUE FUNCIONEN ESTAS ACCIONES self.actionCopy = self.createAction( text="Copiar", icon=QIcon.fromTheme("edit-copy", QIcon(":/icons/res/edit-copy.png")), shortcut="Ctrl+c" ) self.actionCut = self.createAction( text="Cortar", icon=QIcon.fromTheme("edit-cut", QIcon(":/icons/res/edit-cut.png")), shortcut="Ctrl+x" ) self.actionPaste = self.createAction(text="Pegar", icon=":/icons/res/edit-paste.png", shortcut="Ctrl+v") # navegación self.actionGoFirst = self.createAction( text="Primer documento", tip="Ir al primer documento", icon=QIcon.fromTheme("go-first", QIcon(":/icons/res/go-first.png")), slot=functools.partial(self.navigate, "first"), ) self.actionGoPrevious = self.createAction( text="Documento anterior", tip="Ir al documento anterior", icon=QIcon.fromTheme("go-previous", QIcon(":/icons/res/go-previous.png")), slot=functools.partial(self.navigate, "previous"), ) self.actionGoLast = self.createAction( text="Ultimo documento", tip="Ir al ultimo documento", icon=QIcon.fromTheme("go-last", QIcon(":/icons/res/go-last.png")), slot=functools.partial(self.navigate, "last"), ) self.actionGoNext = self.createAction( text="Documento siguiente", tip="Ir al siguiente documento", icon=QIcon.fromTheme("go-next", QIcon(":/icons/res/go-next.png")), slot=functools.partial(self.navigate, "next"), ) self.actionDeleteRow = self.createAction( text="Borrar la fila", icon=QIcon.fromTheme("edit-delete", QIcon(":/icons/res/edit-delete.png")), slot=self.deleteRow, ) self.addActionsToToolBar() def addActionsToToolBar(self): """ Añade las acciones predefinidas a la barra de tareas """ self.toolBar.addActions( [self.actionNew, self.actionPreview, self.actionPrint, self.actionSave, self.actionCancel] ) self.toolBar.addSeparator() self.toolBar.addActions( [self.actionGoFirst, self.actionGoPrevious, self.actionGoLast, self.actionGoNext, self.actionGoLast] ) @pyqtSlot() @if_edit_model def on_txtObservations_textChanged(self): """ Asignar las observaciones al editmodel """ self.editmodel.observations = self.txtObservations.toPlainText().strip()
class Entity(QWidget): def __init__(self, base_image, size, hp=100, pos=(0, 0), parent=None): super().__init__(parent) self._base_label = QLabel(self) self._base_image = base_image self._size = size self._decor_label = None self._decor_pixmap = None self._hp_max = hp self.__pixmap = None """:type: PyQt4.QtGui.QPixmap""" self.__cord_x = pos[0] self.__cord_y = pos[1] self.__angle = 0 self.__hp_bar = QProgressBar(self) self.__hp_bar.setMaximum(self._hp_max) self.__hp_bar.setValue(self._hp_max) self.__hp_bar.setTextVisible(False) self.__hp_bar.setMaximumSize(size[0], 5) self.setAlignment(Qt.AlignCenter) self.updatePixmap() if _debugging: self.setStyleSheet("border: 1px solid black") @property def health(self): return self.__hp_bar.value() @health.setter def health(self, hp): if hp > self._hp_max: hp = self._hp_max elif hp < 0: hp = 0 self.__hp_bar.setValue(hp) @property def angle(self): return self.__angle @angle.setter def angle(self, angle): self.__angle = angle self.updatePixmap() @property def cord_x(self): return self.__cord_x @cord_x.setter def cord_x(self, cord): self.__cord_x = cord self.move(self.cord_x, self.cord_y) @property def cord_y(self): return self.__cord_y @cord_y.setter def cord_y(self, cord): self.__cord_y = cord self.move(self.cord_x, self.cord_y) def hide_hp_bar(self, bool=False): if bool: self.__hp_bar.hide() else: self.__hp_bar.show() def add_decoration(self, path): if path is None: self._decor_label.deleteLater() self._decor_label = None else: self._decor_label = QLabel(self) self._decor_pixmap = QPixmap(path) # self._decor_pixmap = self._decor_pixmap.scaled(self._size[0], self._size[1]) self._decor_pixmap = self._decor_pixmap.transformed( QTransform().rotate(self.angle)) self._decor_label.setPixmap(self._decor_pixmap) self._decor_label.setAlignment(Qt.AlignCenter) self._decor_label.show() def updatePixmap(self): path = get_asset_path(self._base_image) self.__pixmap = QPixmap(path) self.__pixmap = self.__pixmap.scaled(self._size[0], self._size[1]) self.__pixmap = self.__pixmap.transformed(QTransform().rotate( self.angle)) self._base_label.setPixmap(self.__pixmap) self._base_label.show() # self.setFixedSize(self.__pixmap.width(), self.__pixmap.height()) def setFixedSize(self, x, y): super().setFixedSize(x, y) self._base_label.setFixedSize(x, y) def setAlignment(self, alignment): self._base_label.setAlignment(alignment)
class GUI(QWidget): def __init__(self, parent=None): super(GUI, self).__init__(parent) self.create_ui_components() self.compose_ui() # Initializing: window composition, it's contents and event handlers self.init_composition() self.init_contents() self.init_actions() self.on_start() def create_ui_components(self): """ Create layouts and qt controls. """ self.layout = QGridLayout() self.kanjiGroup = QGroupBox() self.kanjiLayout = QGridLayout() # Kanji ui group self.day, self.week, self.month, self.year = \ QLabel(KANJI), QLabel(KANJI), QLabel(KANJI), QLabel(KANJI) self.dayLabel, self.weekLabel, self.monthLabel, self.yearLabel = \ QLabel('<b>Day</b>'), QLabel('<b>Week</b>'), \ QLabel('<b>Month</b>'), QLabel('<b>Year</b>') # Main layout self.showAbout = QPushButton('A&bout') # DB controls (top) self.showDB, self.availableDB, self.changeDB = \ QPushButton('&Change DB (active:)'), QComboBox(), QPushButton('&Remap') # General controls (bottom) self.getAll, self.showStats, self.quitApp, self.authGen, self.methodCombo = \ QPushButton('&Get all'), QPushButton('&Stats'), QPushButton('&Quit'), \ QPushButton('&Auth'), QComboBox() # Notifications self.progressBar = QProgressBar() self.statusMessage = QLabel() # About self.aboutBox = QMessageBox() def compose_ui(self): """ Fill layouts and groups, initialize filters. """ self.kanjiLayout.addWidget(self.day, 0, 0) self.kanjiLayout.addWidget(self.week, 0, 1) self.kanjiLayout.addWidget(self.dayLabel, 1, 0) self.kanjiLayout.addWidget(self.weekLabel, 1, 1) self.kanjiLayout.addWidget(self.month, 2, 0) self.kanjiLayout.addWidget(self.year, 2, 1) self.kanjiLayout.addWidget(self.monthLabel, 3, 0) self.kanjiLayout.addWidget(self.yearLabel, 3, 1) self.kanjiGroup.setLayout(self.kanjiLayout) self.layout.addWidget(self.showDB, 0, 0, 1, 2) self.layout.addWidget(self.availableDB, 1, 0) self.layout.addWidget(self.changeDB, 1, 1) self.layout.addWidget(self.kanjiGroup, 2, 0, 1, 2) self.layout.addWidget(self.getAll, 3, 0) self.layout.addWidget(self.showStats, 3, 1) self.layout.addWidget(self.methodCombo, 4, 0) self.layout.addWidget(self.authGen, 4, 1) #self.layout.addWidget(self.quitApp, 5, 0, 1, 2) self.layout.addWidget(self.quitApp, 5, 0) self.layout.addWidget(self.showAbout, 5, 1) self.layout.addWidget(self.progressBar, 6, 0, 1, 2) self.layout.addWidget(self.statusMessage, 7, 0, 1, 2) self.setLayout(self.layout) self.eFilter = LabelEventFilter() def on_start(self): """ Additional procedures run on application start. """ # Let's initialize even some stuff! self.al = None self.auth_thread = None self.init_backend() choose_db(str(self.availableDB.currentText())) self.showDB.setText("&Change DB (active: %s)" % self.availableDB.currentText()) self.stats = StatsUI(self.al, self) def init_composition(self): """ Window composition and general params. """ self.setWindowTitle(NAME + ' ' + __version__) desktop = QApplication.desktop() self.setGeometry((desktop.width() - WIDTH)/2, (desktop.height() - HEIGHT)/2, WIDTH, HEIGHT) def init_contents(self): """ Setting up qt controls. """ self.changeDB.hide() self.availableDB.hide() self.availableDB.addItems(dbs.keys()) self.kanjiGroup.setAlignment(Qt.AlignCenter) self.kanjiGroup.setStyleSheet("QGroupBox { border: 1px solid gray; border-radius: 3px; }") self.day.setAlignment(Qt.AlignCenter) self.week.setAlignment(Qt.AlignCenter) self.month.setAlignment(Qt.AlignCenter) self.year.setAlignment(Qt.AlignCenter) self.dayLabel.setAlignment(Qt.AlignCenter) self.weekLabel.setAlignment(Qt.AlignCenter) self.monthLabel.setAlignment(Qt.AlignCenter) self.yearLabel.setAlignment(Qt.AlignCenter) self.day.setFont(QFont(PRETTY_FONT, KANJI_SIZE)) self.week.setFont(QFont(PRETTY_FONT, KANJI_SIZE)) self.month.setFont(QFont(PRETTY_FONT, KANJI_SIZE)) self.year.setFont(QFont(PRETTY_FONT, KANJI_SIZE)) self.methodCombo.addItems(RandomMess.algs.keys()) self.methodCombo.setCurrentIndex(1) self.statusMessage.setAlignment(Qt.AlignCenter) self.statusMessage.hide() self.statusMessage.setMaximumHeight(MESSAGE_HEIGHT) self.statusMessage.setStyleSheet(WARNING_STYLE) self.progressBar.setMaximum(0) self.progressBar.setMaximumHeight(PROGRESS_HEIGHT) self.progressBar.hide() QToolTip.setFont(QFont(PRETTY_FONT, TOOLTIP_FONT_SIZE)) self.getAll.setToolTip('Randomly select all 4 kanji') self.methodCombo.setToolTip('Choose algorithm for randomness') self.authGen.setToolTip('Authorize on remote RNG services') self.showStats.setToolTip('Show/hide dialog with comprehensive statistics') self.quitApp.setToolTip('Close application') self.showDB.setToolTip('Show/hide available databases') self.availableDB.setToolTip('Available kanji frequency charts db') self.changeDB.setToolTip('Pick new kanji from currently selected db') # About dialog self.aboutBox.layout().itemAt(1).widget().setAlignment(Qt.AlignLeft) self.aboutBox.setTextFormat(Qt.RichText) self.aboutBox.setText('Version:\t<b>' + __version__ + '</b><br/>Python:\t<b>' + platform.python_version() + '</b>' + '<br/>Platform:\t<b>' + platform.system() + ' ' + platform.release() + '</b>' + '<br/>Author:\t<b>' + __author__ + '</b>' + app_about) self.aboutBox.setWindowTitle('About ' + app_name) self.aboutBox.setIconPixmap(QPixmap(paths['icon'])) def init_actions(self): """ Binding events/handlers. """ self.showDB.clicked.connect(self.show_available_db) self.changeDB.clicked.connect(self.change_db) self.quitApp.clicked.connect(self.close) self.getAll.clicked.connect(self.get_all) self.authGen.clicked.connect(self.auth_task) self.showStats.clicked.connect(self.show_stats) self.methodCombo.currentIndexChanged.connect(self.update_alg) self.showAbout.clicked.connect(self.app_help) # Mouse events for labels self.day.setAttribute(Qt.WA_Hover, True) self.week.setAttribute(Qt.WA_Hover, True) self.month.setAttribute(Qt.WA_Hover, True) self.year.setAttribute(Qt.WA_Hover, True) self.day.installEventFilter(self.eFilter) self.week.installEventFilter(self.eFilter) self.month.installEventFilter(self.eFilter) self.year.installEventFilter(self.eFilter) ##### actions ##### def show_stats(self): if self.stats.isVisible(): self.stats.hide() else: self.stats.show() def show_available_db(self): if self.availableDB.isVisible(): self.availableDB.hide() self.changeDB.hide() else: self.availableDB.show() self.changeDB.show() def change_db(self): try: choose_db(str(self.availableDB.currentText())) self.availableDB.hide() self.changeDB.hide() self.show_message_then_hide("DB successfully remaped!", False) self.showDB.setText("&Change DB (active: %s)" % self.availableDB.currentText()) self.stats.update_stat_info() self.stats.refresh_plot() except NoDbException as e: self.show_message_then_hide(e.message) def get_all(self): self.random_kanji_task = RandomKanjiTask(self.al) self.random_kanji_task.done.connect(self.update_kanji) self.show_progress('Selecting kanji...') self.random_kanji_task.start() def update_kanji(self, results): if results['success']: kanji_set = results['kanji_set'] for_a_day = kanji_set.pop() for_a_week = kanji_set.pop() for_a_month = kanji_set.pop() for_a_year = kanji_set.pop() self.day.setText(for_a_day.character) self.dayLabel.setText('<b>Day:</b> ' + str(for_a_day.frequency) + ' | ' + str(for_a_day.dominance) + '%') self.week.setText(for_a_week.character) self.weekLabel.setText('<b>Week:</b> ' + str(for_a_week.frequency) + ' | ' + str(for_a_week.dominance) + '%') self.month.setText(for_a_month.character) self.monthLabel.setText('<b>Month:</b> ' + str(for_a_month.frequency) + ' | ' + str(for_a_month.dominance) + '%') self.year.setText(for_a_year.character) self.yearLabel.setText('<b>Year:</b> ' + str(for_a_year.frequency) + ' | ' + str(for_a_year.dominance) + '%') self.kanji_tooltip(self.day) self.kanji_tooltip(self.week) self.kanji_tooltip(self.month) self.kanji_tooltip(self.year) if self.stats.isVisible(): self.stats.update_stat_info() self.stats.refresh_plot() self.hide_message() else: self.show_message_then_hide(results['message']) self.hide_progress() def pretty_font(self): pass def update_alg(self): self.al.set_active(str(self.methodCombo.currentText())) def init_backend(self): self.al = RandomMess() self.update_alg() def auth_task(self): self.auth_thread = AuthorizationTask(self.al) self.auth_thread.done.connect(self.auth_complete) #self.auth_thread.run() # IT DOESN't work on windows as it should! self.auth_thread.start() self.show_progress('Authorizing on RNG services...') def auth_complete(self, success): self.hide_message() self.hide_progress() if success: self.show_message_then_hide("Successfully authenticated!", False) else: self.show_message_then_hide("Sorry, could not authenticate.") def show_message_then_hide(self, message, error=True): if error: self.statusMessage.setStyleSheet(WARNING_STYLE) else: self.statusMessage.setStyleSheet(NOTE_STYLE) self.statusMessage.setText(message) self.statusMessage.show() QTimer.singleShot(MESSAGE_TIMEOUT, self.hide_message) def show_progress(self, message): self.statusMessage.setStyleSheet(NOTE_STYLE) self.statusMessage.setText(message) self.statusMessage.show() self.progressBar.show() def hide_message(self): self.statusMessage.setText('') self.statusMessage.hide() def hide_progress(self): self.progressBar.hide() def toggle_kanji_info(self, label, info): label.setToolTip(info.info()) def kanji_tooltip(self, label): found = JDIC.search(label.text()) if found: label.setToolTip(found.info()) else: label.setToolTip('No such kanji in kanjidic2!') def kanji_info(self, kanji): pass def app_help(self): self.aboutBox.show() #### Utility events #### def resizeEvent(self, QResizeEvent): self.updateStatsPosition() self.updateStatsSize() def moveEvent(self, QMoveEvent): self.updateStatsPosition() self.updateStatsSize() def updateStatsPosition(self): self.stats.move(self.x() + self.width() + 20, self.y()) def updateStatsSize(self): self.stats.resize(QSize(self.stats.width(), self.height()))
class LabelAssistDialog(QDialog): """ A simple UI for showing bookmarks and navigating to them. FIXME: For now, this window is tied to a particular lane. If your project has more than one lane, then each one will have it's own bookmark window, which is kinda dumb. """ def __init__(self, parent, topLevelOperatorView): super(LabelAssistDialog, self).__init__(parent) # Create thread router to populate table on main thread self.threadRouter = ThreadRouter(self) # Set object classification operator view self.topLevelOperatorView = topLevelOperatorView self.setWindowTitle("Label Assist") self.setMinimumWidth(500) self.setMinimumHeight(700) layout = QGridLayout() layout.setContentsMargins(10, 10, 10, 10) # Show variable importance table rows = 0 columns = 4 self.table = QTableWidget(rows, columns) self.table.setHorizontalHeaderLabels(['Frame', 'Max Area', 'Min Area', 'Labels']) self.table.verticalHeader().setVisible(False) # Select full row on-click and call capture double click self.table.setSelectionBehavior(QTableView.SelectRows); self.table.doubleClicked.connect(self._captureDoubleClick) layout.addWidget(self.table, 1, 0, 3, 2) # Create progress bar self.progressBar = QProgressBar() self.progressBar.setMinimum(0) self.progressBar.setMaximum(0) self.progressBar.hide() layout.addWidget(self.progressBar, 4, 0, 1, 2) # Create button to populate table self.computeButton = QPushButton('Compute object info') self.computeButton.clicked.connect(self._triggerTableUpdate) layout.addWidget(self.computeButton, 5, 0) # Create close button closeButton = QPushButton('Close') closeButton.clicked.connect(self.close) layout.addWidget(closeButton, 5, 1) # Set dialog layout self.setLayout(layout) def _triggerTableUpdate(self): # Check that object area is included in selected features featureNames = self.topLevelOperatorView.SelectedFeatures.value if 'Standard Object Features' not in featureNames or 'Count' not in featureNames['Standard Object Features']: box = QMessageBox(QMessageBox.Warning, 'Warning', 'Object area is not a selected feature. Please select this feature on: \"Standard Object Features > Shape > Size in pixels\"', QMessageBox.NoButton, self) box.show() return # Clear table self.table.clearContents() self.table.setRowCount(0) self.table.setSortingEnabled(False) self.progressBar.show() self.computeButton.setEnabled(False) def compute_features_for_frame(tIndex, t, features): # Compute features and labels (called in parallel from request pool) roi = [slice(None) for i in range(len(self.topLevelOperatorView.LabelImages.meta.shape))] roi[tIndex] = slice(t, t+1) roi = tuple(roi) frame = self.topLevelOperatorView.SegmentationImages(roi).wait() frame = frame.squeeze().astype(numpy.uint32, copy=False) # Dirty trick: We don't care what we're passing here for the 'image' parameter, # but vigra insists that we pass *something*, so we'll cast the label image as float32. features[t] = vigra.analysis.extractRegionFeatures(frame.view(numpy.float32), frame, ['Count'], ignoreLabel=0) tIndex = self.topLevelOperatorView.SegmentationImages.meta.axistags.index('t') tMax = self.topLevelOperatorView.SegmentationImages.meta.shape[tIndex] features = {} labels = {} def compute_all_features(): # Compute features in parallel pool = RequestPool() for t in range(tMax): pool.add( Request( partial(compute_features_for_frame, tIndex, t, features) ) ) pool.wait() # Compute labels labels = self.topLevelOperatorView.LabelInputs([]).wait() req = Request(compute_all_features) req.notify_finished( partial(self._populateTable, features, labels) ) req.submit() @threadRouted def _populateTable(self, features, labels, *args): self.progressBar.hide() self.computeButton.setEnabled(True) for time, feature in features.iteritems(): # Insert row rowNum = self.table.rowCount() self.table.insertRow(self.table.rowCount()) # Get max and min object areas areas = feature['Count']#objectFeatures['Standard Object Features']['Count'] maxObjArea = numpy.max(areas[numpy.nonzero(areas)]) minObjArea = numpy.min(areas[numpy.nonzero(areas)]) # Get number of labeled objects labelNum = numpy.count_nonzero(labels[time]) # Load fram number item = QTableWidgetItem(str(time)) item.setFlags( Qt.ItemIsSelectable | Qt.ItemIsEnabled ) self.table.setItem(rowNum, 0, item) # Load max object areas item = QTableWidgetItemWithFloatSorting(str("{: .02f}".format(maxObjArea))) item.setFlags( Qt.ItemIsSelectable | Qt.ItemIsEnabled ) self.table.setItem(rowNum, 1, item) # Load min object areas item = QTableWidgetItemWithFloatSorting(str("{: .02f}".format(minObjArea))) item.setFlags( Qt.ItemIsSelectable | Qt.ItemIsEnabled ) self.table.setItem(rowNum, 2, item) # Load label numbers item = QTableWidgetItemWithFloatSorting(str("{: .01f}".format(labelNum))) item.setFlags( Qt.ItemIsSelectable | Qt.ItemIsEnabled ) self.table.setItem(rowNum, 3, item) # Resize column size to fit dialog size self.table.horizontalHeader().setResizeMode(QHeaderView.Stretch) # Sort by max object area self.table.setSortingEnabled(True) self.table.sortByColumn(1) def _captureDoubleClick(self): # Navigate to selected frame index = self.table.selectedIndexes()[0] frameStr = self.table.model().data(index).toString() if frameStr: frameNum = int(frameStr) self.parent().editor.posModel.time = frameNum
class SCJProgress(QHBoxLayout): def __init__(self, parent=None, file=None, format=None, createDir=False ): super(SCJProgress, self).__init__(parent) self.format = format self.filename = file self.createDir = createDir self.process = SCJ(self.filename, self.format, createDir) self.output = QString(self.process.output) self.command = QStringList(self.process.command) self.log = QStringList() self.label = QLabel(self.output) self.label.setToolTip(self.trUtf8("Destination: %s" % self.output)) self.bar = QProgressBar(parent) self.bar.setToolTip(self.trUtf8("Source: %s" % self.filename)) self.bar.setValue(0) self.startbtn = QPushButton(parent) self.stopbtn = QPushButton(parent) self.cancelbtn = QPushButton(parent) self.logbtn = QPushButton(parent) self.cancelbtn.setMinimumSize(32,32) self.cancelbtn.setFlat(True) self.startbtn.setMinimumSize(32,32) self.startbtn.setFlat(True) self.stopbtn.setMinimumSize(32,32) self.stopbtn.setFlat(True) self.label.setMinimumSize(200,32) self.bar.setMinimumSize(100,16) self.bar.setMaximumHeight(16) self.addWidget(self.logbtn) self.logbtn.hide() self.addWidget(self.label) self.addWidget(self.bar) self.addWidget(self.startbtn) self.addWidget(self.stopbtn) self.addWidget(self.cancelbtn) self.retranslateUi() self.connect(self.startbtn, SIGNAL("clicked()"), self.start) self.connect(self.stopbtn, SIGNAL("clicked()"), self.stop) self.connect(self.cancelbtn, SIGNAL("clicked()"), self.remove) self.connect(self.logbtn, SIGNAL('clicked()'), self.showLog) self.connect(self.process, SIGNAL('progress(int)'), self.bar.setValue) self.connect(self.process, SIGNAL('error(QString)'), self.addLog) self.connect(self.process, SIGNAL('finished()'), self.enable) def retranslateUi(self): self.startbtn.setIcon(QIcon(u"images/play.png")) self.startbtn.setToolTip(self.trUtf8("Demarrer")) self.stopbtn.setIcon(QIcon(u"images/stop.png")) self.stopbtn.setToolTip(self.trUtf8("Stopper")) self.cancelbtn.setIcon(QIcon(u"images/remove.png")) self.cancelbtn.setToolTip(self.trUtf8("Annuler")) self.logbtn.setIcon(QIcon(u"images/log.png")) self.logbtn.setToolTip(self.trUtf8("Voir les details")) def start(self): self.log.clear() self.logbtn.hide() self.disable() self.process.start() self.process.resume() def stop(self): self.process.cancel() self.process.terminate() self.enable() def remove(self): self.removeWidget(self.label) self.removeWidget(self.bar) self.removeWidget(self.startbtn) self.removeWidget(self.stopbtn) self.removeWidget(self.cancelbtn) self.removeWidget(self.logbtn) self.label.hide() self.bar.hide() self.startbtn.hide() self.stopbtn.hide() self.cancelbtn.hide() self.logbtn.hide() self.emit(SIGNAL("void removed(QString)"), self.output) def showLog(self): QMessageBox.critical(None, u"Ooops", self.log.join("\n")) def addLog(self, log): self.log.append(log) self.logbtn.show() palette = QPalette() brush = QBrush(QColor(240, 100, 100)) brush.setStyle(Qt.SolidPattern) palette.setBrush(QPalette.Normal, QPalette.Background, brush) self.label.setPalette(palette) self.label.setAutoFillBackground(True) def enable(self): self.process = SCJ(self.filename, self.format, self.createDir) self.output = QString(self.process.output) self.command = QStringList(self.process.output) self.connect(self.process, SIGNAL('progress(int)'), self.bar.setValue) self.connect(self.process, SIGNAL('error(QString)'), self.addLog) self.connect(self.process, SIGNAL('finished()'), self.enable) self.cancelbtn.setEnabled(True) self.startbtn.setEnabled(True) def disable(self): self.cancelbtn.setEnabled(False) self.startbtn.setEnabled(False) self.label.setAutoFillBackground(False)
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setCentralWidget(self.ui.mangaTableView) self.newMangaDialog = NewMangaDialog() self.mangaDownloadDialog = MangaDownloadDialog() self.mangaTableModel = QStandardItemModel(0, 3, self) self.mangaTableModel.setHorizontalHeaderItem(0, QStandardItem(QString("Manga"))) self.mangaTableModel.setHorizontalHeaderItem(1, QStandardItem(QString("Latest Chapter"))) self.mangaTableModel.setHorizontalHeaderItem(2, QStandardItem(QString("Status"))) self.ui.mangaTableView.setModel(self.mangaTableModel) newMangaAction = QAction(QIcon("./icon/add.ico"),'New Manga', self) newMangaAction.setShortcut('Ctrl+N') newMangaAction.triggered.connect(self.newMangaDialog.show) removeMangaAction = QAction(QIcon("./icon/delete.ico"),'Remove Manga', self) removeMangaAction.setShortcut('Delete') preferencesAction = QAction(QIcon("./icon/preferences.ico"),'Preferences', self) aboutAction = QAction(QIcon("./icon/about.ico"),'About', self) self.ui.toolBar.addAction(newMangaAction) self.ui.toolBar.addAction(removeMangaAction) self.ui.toolBar.addSeparator() self.ui.toolBar.addAction(preferencesAction) self.ui.toolBar.addSeparator() self.ui.toolBar.addAction(aboutAction) self.progressBar = QProgressBar(self.ui.statusbar) self.ui.statusbar.addPermanentWidget(self.progressBar) self.progressBar.hide() def closeEvent(self, QCloseEvent): mangaList = [] for i in range(self.mangaTableModel.rowCount()): mangaList.append({ "name" : str(self.mangaTableModel.item(i, 0).text()), "latestChapter" : str(self.mangaTableModel.item(i, 1).text()), "status" : "Updated", "link" : "/trial.html" }) self.emit(SIGNAL("applicationClosed"),mangaList) def initializeProgressBar(self, size): self.progressBar.setRange(0, size) self.progressBar.setValue(0) self.progressBar.show() def updateProgressBar(self, value): self.progressBar.setValue(value) def updateStatusBar(self, msg): self.ui.statusbar.showMessage(msg) def updateMangaTable(self, chapter): isFound = False for i in range(self.mangaTableModel.rowCount()): mangaItem = self.mangaTableModel.item(i) if mangaItem.text() == chapter["name"]: self.mangaTableModel.item(i, 1).setText(chapter["latestChapter"]) self.mangaTableModel.item(i, 2).setText(chapter["status"]) isFound = True break if not isFound: self.addRowToMangaTable(chapter) def addMangaListToMangaTable(self, mangaList): for i in range(len(mangaList)): self.addRowToMangaTable(mangaList[i]) def addRowToMangaTable(self, manga): i = self.mangaTableModel.rowCount() mangaItem = QStandardItem(QString(manga["name"])) latestChapterItem = QStandardItem(QString(manga["latestChapter"])) statusItem = QStandardItem(QString(manga["status"])) brush = QBrush(QColor(255, 255, 255)) if i%2==0 else QBrush(QColor(200, 200, 200)) mangaItem.setBackground(brush) latestChapterItem.setBackground(brush) statusItem.setBackground(brush) self.mangaTableModel.setItem(i, 0, mangaItem) self.mangaTableModel.setItem(i, 1, latestChapterItem) self.mangaTableModel.setItem(i, 2, statusItem)
class InputForm(QWidget): __instance = None @staticmethod def instance(): return InputForm.__instance def __init__(self): if not InputForm.__instance: InputForm.__instance = self super(InputForm, self).__init__() Global.event.task_started.connect(self._on_task_started) Global.event.task_completed.connect(self._on_task_completed) Global.event.task_progressed.connect(self._on_task_progressed) Global.event.task_range_progressed.connect(self._on_task_range_progressed) Global.event.interface_load_task_params.connect(self._on_interface_load_task_params) self.vl = QVBoxLayout() self.vl.setContentsMargins(0,0,0,0) self.setLayout(self.vl) self.setFixedWidth(290) self.tab = QTabWidget() self.vl.addWidget(self.tab) self.input_parameters = InputParameters() self.input_parameters.ranges_state_changed.connect(self._on_ranges_state_changed) self.tab.addTab(self.input_parameters, 'Parameters') self.import_parameters = ImportParameters() self.tab.addTab(self.import_parameters, 'Observation') control_buttons = QWidget() control_buttons.setLayout(QVBoxLayout()) control_buttons.layout().setContentsMargins(0, 0, 0, 0) control_buttons.layout().setAlignment(Qt.AlignBottom) self._progress = QProgressBar() self._progress.setValue(0) self._progress.setTextVisible(True) self._progress.setAlignment(Qt.AlignCenter) self._progress.hide() control_buttons.layout().addWidget(self._progress) self._range_progress = QProgressBar() self._range_progress.setValue(0) self._range_progress.setTextVisible(True) self._range_progress.setAlignment(Qt.AlignCenter) self._range_progress.hide() control_buttons.layout().addWidget(self._range_progress) self._calculate = QPushButton('Calculate') self._calculate.clicked.connect(self._on_calculate) control_buttons.layout().addWidget(self._calculate) self._cancel = QPushButton('Cancel') self._cancel.hide() self._cancel.clicked.connect(self._on_cancel) control_buttons.layout().addWidget(self._cancel) self.vl.addWidget(control_buttons) if exists("./config/last-session.ini") : self.load_params("./config/last-session.ini") def _on_ranges_state_changed(self, parameters): Global.task_range().reset() if len(parameters): keys = parameters.keys() for key in parameters: Global.task_range().set_range(key, copy(parameters[key].range.values)) self._calculate.setText('Calculate ' + str(Global.task_range()._total_count) + ' variations') else: self._calculate.setText('Calculate') def _on_calculate(self): self.import_parameters.import_observation() combination = Global.task_range().get_next_combination() Global.task().input.semi_major_axis = self.input_parameters.semi_major_axis.getValue() Global.task().input.star_radius = self.input_parameters.star_radius.getValue() Global.task().input.planet_radius = self.input_parameters.planet_radius.getValue() Global.task().input.star_temperature = self.input_parameters.star_temperature.getValue() Global.task().input.planet_temperature = self.input_parameters.planet_temperature.getValue() Global.task().input.darkening_law = self.input_parameters.darkening_law.value.itemData(self.input_parameters.darkening_law.value.currentIndex()).toString() Global.task().input.darkening_1 = self.input_parameters.darkening_coefficient_1.getValue() Global.task().input.darkening_2 = self.input_parameters.darkening_coefficient_2.getValue() Global.task().input.inclination = self.input_parameters.inclination.getValue() Global.task().input.phase_start = 0 Global.task().input.phase_end = self.input_parameters.phase_end.getValue() Global.task().input.phase_step = self.input_parameters.phase_step.getValue() Global.task().input.precision = 10**self.input_parameters.integration_precision.getValue() if combination: for param in combination: setattr(Global.task().input, param[0], param[1]) Global.task().start() def _on_task_range_progressed(self, progress): self._range_progress.setFormat( str(Global.task_range().completed_count()) + ' of ' + str(Global.task_range().total_count())) self._range_progress.setValue(math.ceil(((float(Global.task_range().completed_count()))/Global.task_range().total_count())*100)) self._on_calculate() def _on_task_started(self, task): self._calculate.hide() self._progress.show() self._progress.setValue(0) self._cancel.show() self.tab.setDisabled(True) if Global.task_range().total_count(): self._range_progress.show() if Global.task_range().completed_count() == 0: self._range_progress.setFormat('0 of ' + str(Global.task_range().total_count())) self._range_progress.setValue(0) def _on_task_progressed(self, task, progress): self._progress.setValue(progress) def _on_task_completed(self, task): if Global.task_range().total_count() and Global.task_range().completed_count(): return self._calculate.show() self._progress.hide() self._progress.setValue(0) self._cancel.hide() self.tab.setDisabled(False) self._range_progress.hide() self._range_progress.setValue(0) def _on_cancel(self): Global.task().stop() self._calculate.show() self._progress.hide() self._progress.setValue(0) self._range_progress.hide() self._range_progress.setValue(0) self._cancel.hide() self.tab.setDisabled(False) def _on_interface_load_task_params(self, task): self.input_parameters.semi_major_axis.value.setValue(task.input.semi_major_axis) self.input_parameters.star_radius.value.setValue(task.input.star_radius) self.input_parameters.planet_radius.value.setValue(task.input.planet_radius) self.input_parameters.star_temperature.value.setValue(task.input.star_temperature) self.input_parameters.planet_temperature.value.setValue(task.input.planet_temperature) self.input_parameters.inclination.value.setValue(task.input.inclination) darkening_law_index = 0 for item in DarkeningLaw.items: if item[1] == task.input.darkening_law: break darkening_law_index += 1 self.input_parameters.darkening_law.value.setCurrentIndex(darkening_law_index) self.input_parameters.darkening_coefficient_1.value.setValue(task.input.darkening_1) self.input_parameters.darkening_coefficient_2.value.setValue(task.input.darkening_2) self.input_parameters.phase_end.value.setValue(task.input.phase_end) self.input_parameters.phase_step.value.setValue(task.input.phase_step) self.input_parameters.integration_precision.value.setValue(log10(task.input.precision)) for parameter_name in copy(self.input_parameters.range_parameters): parameter = getattr(self.input_parameters, parameter_name) if parameter.range: parameter.range.set_active(False) self.repaint() def load_params(self, filename): config = ConfigParser() config.read(filename) self._normalize_config(config) # Input Parameters self._load_config_param(config, 'input', 'semi_major_axis') self._load_config_param(config, 'input', 'star_radius') self._load_config_param(config, 'input', 'planet_radius') self._load_config_param(config, 'input', 'star_temperature') self._load_config_param(config, 'input', 'planet_temperature') self._load_config_param(config, 'input', 'inclination') self._load_config_param(config, 'input', 'darkening_law') self._load_config_param(config, 'input', 'darkening_coefficient_1') self._load_config_param(config, 'input', 'darkening_coefficient_2') self._load_config_param(config, 'input', 'phase_end') self._load_config_param(config, 'input', 'phase_step') self._load_config_param(config, 'input', 'integration_precision') # Import Parameters if config.has_option('import', 'filename') and config.get('import', 'filename'): if '/data/' in config.get('import', 'filename') and config.get('import', 'filename').index('/data/') == 0: self.import_parameters.filename = os.getcwd().replace('\\', '/') + config.get('import', 'filename') else: self.import_parameters.filename = config.get('import', 'filename') self.import_parameters.update_file_label() if config.has_option('import', 'jd2phase') and config.getboolean('import', 'jd2phase') == True : self.import_parameters.hjd_to_phases.setCheckState(Qt.Checked) if config.has_option('import', 'jd2phase_tzero') : self.import_parameters.time_zero.setValue(config.getfloat('import', 'jd2phase_tzero')) if config.has_option('import', 'jd2phase_period') : self.import_parameters.period.setValue(config.getfloat('import', 'jd2phase_period')) if config.has_option('import', 'mag2flux') and config.getboolean('import', 'mag2flux') == True : self.import_parameters.magnitude_to_flux.setCheckState(Qt.Checked) if config.has_option('import', 'mag2flux_mag') : self.import_parameters.magnitude_max.setValue(config.getfloat('import', 'mag2flux_mag')) # Fixes painting bug with range buttons when loading new file # the active ranges stayed active even if they are inactive self.repaint() def _normalize_config(self, config): if config.has_option('input', 'darkening_1'): config.set('input', 'darkening_coefficient_1', config.get('input', 'darkening_1')) config.remove_option('input', 'darkening_1') if config.has_option('input', 'darkening_2'): config.set('input', 'darkening_coefficient_2', config.get('input', 'darkening_2')) config.remove_option('input', 'darkening_2') if config.has_option('input', 'precision'): config.set('input', 'integration_precision', config.get('input', 'precision')) config.remove_option('input', 'precision') def _load_config_param(self, config, section, name): param = getattr(self.input_parameters, name) if config.has_option(section, name): if type(param.value) is QComboBox: param.value.setCurrentIndex(config.getint(section, name)) else: param.value.setValue(literal_eval(config.get(section, name))) if param.range: _from = _to = _step = _values = None _active = False if config.has_option(section, name + '_range_from'): _from = literal_eval(config.get(section, name + '_range_from')) if config.has_option(section, name + '_range_to'): _to = literal_eval(config.get(section, name + '_range_to')) if config.has_option(section, name + '_range_step'): _step = literal_eval(config.get(section, name + '_range_step')) if config.has_option(section, name + '_range_values'): _values = literal_eval(config.get(section, name + '_range_values')) if config.has_option(section, name + '_range_active'): _active = config.getboolean(section, name + '_range_active') if _values: param.range.set_range(_values) elif _from and _to and _step: param.range.set_range(_from, _to, _step) param.range.set_active(_active) def _save_config_param(self, config, section, name): param = getattr(self.input_parameters, name) if type(param.value) is QComboBox: config.set(section, name, param.value.currentIndex()) else: config.set(section, name, param.getValue()) if param.range: if param.range.range_from and param.range.range_to and param.range.range_step: config.set(section, name + '_range_from', param.range.range_from) config.set(section, name + '_range_to', param.range.range_to) config.set(section, name + '_range_step', param.range.range_step) elif param.range.values: config.set(section, name + '_range_values', param.range.values) if param.range.is_active(): config.set(section, name + '_range_active', param.range.is_active()) def save_params(self, filename): config = ConfigParser() config.add_section('input') # Input Parameters self._save_config_param(config, 'input', 'semi_major_axis') self._save_config_param(config, 'input', 'star_radius') self._save_config_param(config, 'input', 'planet_radius') self._save_config_param(config, 'input', 'star_temperature') self._save_config_param(config, 'input', 'planet_temperature') self._save_config_param(config, 'input', 'inclination') self._save_config_param(config, 'input', 'darkening_law') self._save_config_param(config, 'input', 'darkening_coefficient_1') self._save_config_param(config, 'input', 'darkening_coefficient_2') self._save_config_param(config, 'input', 'phase_end') self._save_config_param(config, 'input', 'phase_step') self._save_config_param(config, 'input', 'integration_precision') config.add_section('import') if os.getcwd().replace('\\', '/') in str(self.import_parameters.filename) and str(self.import_parameters.filename).index(os.getcwd().replace('\\', '/')) == 0 : save_file_path = str(self.import_parameters.filename).replace(os.getcwd().replace('\\', '/'), '') else: save_file_path = str(self.import_parameters.filename) config.set('import', 'filename', save_file_path) config.set('import', 'jd2phase', self.import_parameters.hjd_to_phases.checkState() == Qt.Checked) config.set('import', 'jd2phase_tzero', self.import_parameters.time_zero.value()) config.set('import', 'jd2phase_period', self.import_parameters.period.value()) config.set('import', 'mag2flux', self.import_parameters.magnitude_to_flux.checkState() == Qt.Checked) config.set('import', 'mag2flux_mag', self.import_parameters.magnitude_max.value()) with open(filename, 'wb') as configfile: config.write(configfile) pass