class QuickWatch(QToolBar): def __init__(self, parent, distributedObjects): QToolBar.__init__(self, "QuickWatch") self.config = QuickWatchConfig() distributedObjects.configStore.registerConfigSet(self.config) self.setObjectName("QuickWatch") parent.addToolBar(self) self.watchedit = QComboBox() self.watchedit.setFixedHeight(28) self.watchedit.setInsertPolicy(QComboBox.NoInsert) self.watchedit.setEditable(True) self.watchedit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.addWidget(self.watchedit) self.distributedObjects = distributedObjects self.addAction(Icons.watch, "Add to Watch", self.addToWatch) self.addAction(Icons.datagraph, "Add to Data Graph", self.addToDG) self.watchedit.lineEdit().returnPressed.connect(self.returnPressed) def __addCurrentText(self): text = self.watchedit.lineEdit().text() idx = self.watchedit.findText(text) if idx == -1: self.watchedit.addItem(text) self.watchedit.setEditText("") def returnPressed(self): if self.config.addTo.value == "Watch View": self.addToWatch() elif self.config.addTo.value == "Data Graph View": self.addToDG() def addToWatch(self): self.distributedObjects.watchModel.addVar( self.watchedit.lineEdit().text()) self.__addCurrentText() def addToDG(self): self.distributedObjects.datagraphController.addWatch( self.watchedit.lineEdit().text()) self.__addCurrentText()
class QuickWatch(QToolBar): def __init__(self, parent, distributedObjects): QToolBar.__init__(self, "QuickWatch") self.config = QuickWatchConfig() distributedObjects.configStore.registerConfigSet(self.config) self.setObjectName("QuickWatch") parent.addToolBar(self) self.watchedit = QComboBox() self.watchedit.setFixedHeight(28) self.watchedit.setInsertPolicy(QComboBox.NoInsert) self.watchedit.setEditable(True) self.watchedit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.addWidget(self.watchedit) self.distributedObjects = distributedObjects self.addAction(Icons.watch, "Add to Watch", self.addToWatch) self.addAction(Icons.datagraph, "Add to Data Graph", self.addToDG) self.watchedit.lineEdit().returnPressed.connect(self.returnPressed) def __addCurrentText(self): text = self.watchedit.lineEdit().text() idx = self.watchedit.findText(text) if idx == -1: self.watchedit.addItem(text) self.watchedit.setEditText("") def returnPressed(self): if self.config.addTo.value == "Watch View": self.addToWatch() elif self.config.addTo.value == "Data Graph View": self.addToDG() def addToWatch(self): self.distributedObjects.watchModel.addVar(self.watchedit.lineEdit().text()) self.__addCurrentText() def addToDG(self): self.distributedObjects.datagraphController.addWatch(self.watchedit.lineEdit().text()) self.__addCurrentText()
class FindInFilesDialog(QDialog, object): """ find in files dialog implementation """ inProject = 0 inDirectory = 1 inOpenFiles = 2 def __init__(self, where, what="", dirPath="", filters=[], parent=None): QDialog.__init__(self, parent) mainWindow = GlobalData().mainWindow self.editorsManager = mainWindow.editorsManagerWidget.editorsManager self.__cancelRequest = False self.__inProgress = False self.searchRegexp = None self.searchResults = [] # Avoid pylint complains self.findCombo = None self.caseCheckBox = None self.wordCheckBox = None self.regexpCheckBox = None self.projectRButton = None self.openFilesRButton = None self.dirRButton = None self.dirEditCombo = None self.dirSelectButton = None self.filterCombo = None self.fileLabel = None self.progressBar = None self.findButton = None self.__createLayout() self.setWindowTitle("Find in files") # Restore the combo box values project = GlobalData().project if project.fileName != "": self.findFilesWhat = project.findFilesWhat self.findFilesDirs = project.findFilesDirs self.findFilesMasks = project.findFilesMasks else: settings = Settings() self.findFilesWhat = settings.findFilesWhat self.findFilesDirs = settings.findFilesDirs self.findFilesMasks = settings.findFilesMasks self.findCombo.addItems(self.findFilesWhat) self.findCombo.setEditText("") self.dirEditCombo.addItems(self.findFilesDirs) self.dirEditCombo.setEditText("") self.filterCombo.addItems(self.findFilesMasks) self.filterCombo.setEditText("") if where == self.inProject: self.setSearchInProject(what, filters) elif where == self.inDirectory: self.setSearchInDirectory(what, dirPath, filters) else: self.setSearchInOpenFiles(what, filters) return def __createLayout(self): """ Creates the dialog layout """ self.resize(600, 300) self.setSizeGripEnabled(True) verticalLayout = QVBoxLayout(self) gridLayout = QGridLayout() # Combo box for the text to search findLabel = QLabel(self) findLabel.setText("Find text:") self.findCombo = QComboBox(self) self.__tuneCombo(self.findCombo) self.findCombo.lineEdit().setToolTip( "Regular expression to search for") self.findCombo.editTextChanged.connect(self.__someTextChanged) gridLayout.addWidget(findLabel, 0, 0, 1, 1) gridLayout.addWidget(self.findCombo, 0, 1, 1, 1) verticalLayout.addLayout(gridLayout) # Check boxes horizontalCBLayout = QHBoxLayout() self.caseCheckBox = QCheckBox(self) self.caseCheckBox.setText("Match &case") horizontalCBLayout.addWidget(self.caseCheckBox) self.wordCheckBox = QCheckBox(self) self.wordCheckBox.setText("Match whole &word") horizontalCBLayout.addWidget(self.wordCheckBox) self.regexpCheckBox = QCheckBox(self) self.regexpCheckBox.setText("Regular &expression") horizontalCBLayout.addWidget(self.regexpCheckBox) verticalLayout.addLayout(horizontalCBLayout) # Files groupbox filesGroupbox = QGroupBox(self) filesGroupbox.setTitle("Find in") sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( filesGroupbox.sizePolicy().hasHeightForWidth()) filesGroupbox.setSizePolicy(sizePolicy) gridLayoutFG = QGridLayout(filesGroupbox) self.projectRButton = QRadioButton(filesGroupbox) self.projectRButton.setText("&Project") gridLayoutFG.addWidget(self.projectRButton, 0, 0) self.projectRButton.clicked.connect(self.__projectClicked) self.openFilesRButton = QRadioButton(filesGroupbox) self.openFilesRButton.setText("&Opened files only") gridLayoutFG.addWidget(self.openFilesRButton, 1, 0) self.openFilesRButton.clicked.connect(self.__openFilesOnlyClicked) self.dirRButton = QRadioButton(filesGroupbox) self.dirRButton.setText("&Directory tree") gridLayoutFG.addWidget(self.dirRButton, 2, 0) self.dirRButton.clicked.connect(self.__dirClicked) self.dirEditCombo = QComboBox(filesGroupbox) self.__tuneCombo(self.dirEditCombo) self.dirEditCombo.lineEdit().setToolTip("Directory to search in") gridLayoutFG.addWidget(self.dirEditCombo, 2, 1) self.dirEditCombo.editTextChanged.connect(self.__someTextChanged) self.dirSelectButton = QPushButton(filesGroupbox) self.dirSelectButton.setText("...") gridLayoutFG.addWidget(self.dirSelectButton, 2, 2) self.dirSelectButton.clicked.connect(self.__selectDirClicked) filterLabel = QLabel(filesGroupbox) filterLabel.setText("Files filter:") gridLayoutFG.addWidget(filterLabel, 3, 0) self.filterCombo = QComboBox(filesGroupbox) self.__tuneCombo(self.filterCombo) self.filterCombo.lineEdit().setToolTip("File names regular expression") gridLayoutFG.addWidget(self.filterCombo, 3, 1) self.filterCombo.editTextChanged.connect(self.__someTextChanged) verticalLayout.addWidget(filesGroupbox) # File label self.fileLabel = FitPathLabel(self) self.fileLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) verticalLayout.addWidget(self.fileLabel) # Progress bar self.progressBar = QProgressBar(self) self.progressBar.setValue(0) self.progressBar.setOrientation(Qt.Horizontal) verticalLayout.addWidget(self.progressBar) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Cancel) self.findButton = buttonBox.addButton("Find", QDialogButtonBox.AcceptRole) self.findButton.setDefault(True) self.findButton.clicked.connect(self.__process) verticalLayout.addWidget(buttonBox) buttonBox.rejected.connect(self.__onClose) return @staticmethod def __tuneCombo(comboBox): " Sets the common settings for a combo box " sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( \ comboBox.sizePolicy().hasHeightForWidth() ) comboBox.setSizePolicy(sizePolicy) comboBox.setEditable(True) comboBox.setInsertPolicy(QComboBox.InsertAtTop) comboBox.setAutoCompletion(False) comboBox.setDuplicatesEnabled(False) return def __onClose(self): " Triggered when the close button is clicked " self.__cancelRequest = True if not self.__inProgress: self.close() return def setSearchInProject(self, what="", filters=[]): " Set search ready for the whole project " if GlobalData().project.fileName == "": # No project loaded, fallback to opened files self.setSearchInOpenFiles(what, filters) return # Select the project radio button self.projectRButton.setEnabled(True) self.projectRButton.setChecked(True) self.dirEditCombo.setEnabled(False) self.dirSelectButton.setEnabled(False) openedFiles = self.editorsManager.getTextEditors() self.openFilesRButton.setEnabled(len(openedFiles) != 0) self.setFilters(filters) self.findCombo.setEditText(what) self.findCombo.lineEdit().selectAll() self.findCombo.setFocus() # Check searchability self.__testSearchability() return def setSearchInOpenFiles(self, what="", filters=[]): " Sets search ready for the opened files " openedFiles = self.editorsManager.getTextEditors() if len(openedFiles) == 0: # No opened files, fallback to search in dir self.setSearchInDirectory(what, "", filters) return # Select the radio buttons self.projectRButton.setEnabled(GlobalData().project.fileName != "") self.openFilesRButton.setEnabled(True) self.openFilesRButton.setChecked(True) self.dirEditCombo.setEnabled(False) self.dirSelectButton.setEnabled(False) self.setFilters(filters) self.findCombo.setEditText(what) self.findCombo.lineEdit().selectAll() self.findCombo.setFocus() # Check searchability self.__testSearchability() return def setSearchInDirectory(self, what="", dirPath="", filters=[]): " Sets search ready for the given directory " # Select radio buttons self.projectRButton.setEnabled(GlobalData().project.fileName != "") openedFiles = self.editorsManager.getTextEditors() self.openFilesRButton.setEnabled(len(openedFiles) != 0) self.dirRButton.setEnabled(True) self.dirRButton.setChecked(True) self.dirEditCombo.setEnabled(True) self.dirSelectButton.setEnabled(True) self.dirEditCombo.setEditText(dirPath) self.setFilters(filters) self.findCombo.setEditText(what) self.findCombo.lineEdit().selectAll() self.findCombo.setFocus() # Check searchability self.__testSearchability() return def setFilters(self, filters): " Sets up the filters " # Set filters if provided if filters: self.filterCombo.setEditText(";".join(filters)) else: self.filterCombo.setEditText("") return def __testSearchability(self): " Tests the searchability and sets the Find button status " startTime = time.time() if self.findCombo.currentText().strip() == "": self.findButton.setEnabled(False) self.findButton.setToolTip("No text to search") return if self.dirRButton.isChecked(): dirname = self.dirEditCombo.currentText().strip() if dirname == "": self.findButton.setEnabled(False) self.findButton.setToolTip("No directory path") return if not os.path.isdir(dirname): self.findButton.setEnabled(False) self.findButton.setToolTip("Path is not a directory") return # Now we need to match file names if there is a filter filtersText = self.filterCombo.currentText().strip() if filtersText == "": self.findButton.setEnabled(True) self.findButton.setToolTip("Find in files") return # Need to check the files match try: filterRe = re.compile(filtersText, re.IGNORECASE) except: self.findButton.setEnabled(False) self.findButton.setToolTip( "Incorrect files " \ "filter regular expression" ) return matched = False tooLong = False if self.projectRButton.isChecked(): # Whole project for fname in GlobalData().project.filesList: if fname.endswith(sep): continue matched = filterRe.match(fname) if matched: break # Check the time, it might took too long if time.time() - startTime > 0.1: tooLong = True break elif self.openFilesRButton.isChecked(): # Opened files openedFiles = self.editorsManager.getTextEditors() for record in openedFiles: matched = filterRe.match(record[1]) if matched: break # Check the time, it might took too long if time.time() - startTime > 0.1: tooLong = True break else: # Search in the dir if not dirname.endswith(sep): dirname += sep matched, tooLong = self.__matchInDir(dirname, filterRe, startTime) if matched: self.findButton.setEnabled(True) self.findButton.setToolTip("Find in files") else: if tooLong: self.findButton.setEnabled(True) self.findButton.setToolTip("Find in files") else: self.findButton.setEnabled(False) self.findButton.setToolTip("No files matched to search in") return @staticmethod def __matchInDir(path, filterRe, startTime): " Provides the 'match' and 'too long' statuses " matched = False tooLong = False for item in os.listdir(path): if time.time() - startTime > 0.1: tooLong = True return matched, tooLong if os.path.isdir(path + item): dname = path + item + sep matched, tooLong = FindInFilesDialog.__matchInDir( dname, filterRe, startTime) if matched or tooLong: return matched, tooLong continue if filterRe.match(path + item): matched = True return matched, tooLong return matched, tooLong def __projectClicked(self): " project radio button clicked " self.dirEditCombo.setEnabled(False) self.dirSelectButton.setEnabled(False) self.__testSearchability() return def __openFilesOnlyClicked(self): " open files only radio button clicked " self.dirEditCombo.setEnabled(False) self.dirSelectButton.setEnabled(False) self.__testSearchability() return def __dirClicked(self): " dir radio button clicked " self.dirEditCombo.setEnabled(True) self.dirSelectButton.setEnabled(True) self.dirEditCombo.setFocus() self.__testSearchability() return def __someTextChanged(self, text): " Text to search, filter or dir name has been changed " self.__testSearchability() return def __selectDirClicked(self): " The user selects a directory " dirName = QFileDialog.getExistingDirectory( self, "Select directory to search in", self.dirEditCombo.currentText(), QFileDialog.Options(QFileDialog.ShowDirsOnly)) if dirName: self.dirEditCombo.setEditText(os.path.normpath(dirName)) self.__testSearchability() return def __projectFiles(self, filterRe): " Project files list respecting the mask " mainWindow = GlobalData().mainWindow files = [] for fname in GlobalData().project.filesList: if fname.endswith(sep): continue if filterRe is None or filterRe.match(fname): widget = mainWindow.getWidgetForFileName(fname) if widget is None: # Do not check for broken symlinks if isFileSearchable(fname, False): files.append(ItemToSearchIn(fname, "")) else: if widget.getType() in \ [ MainWindowTabWidgetBase.PlainTextEditor ]: files.append(ItemToSearchIn(fname, widget.getUUID())) QApplication.processEvents() if self.__cancelRequest: raise Exception("Cancel request") return files def __openedFiles(self, filterRe): " Currently opened editor buffers " files = [] openedFiles = self.editorsManager.getTextEditors() for record in openedFiles: uuid = record[0] fname = record[1] if filterRe is None or filterRe.match(fname): files.append(ItemToSearchIn(fname, uuid)) QApplication.processEvents() if self.__cancelRequest: raise Exception("Cancel request") return files def __dirFiles(self, path, filterRe, files): " Files recursively for the dir " for item in os.listdir(path): QApplication.processEvents() if self.__cancelRequest: raise Exception("Cancel request") if os.path.isdir(path + item): if item in [".svn", ".cvs"]: # It does not make sense to search in revision control dirs continue anotherDir, isLoop = resolveLink(path + item) if not isLoop: self.__dirFiles(anotherDir + sep, filterRe, files) continue if not os.path.isfile(path + item): continue realItem, isLoop = resolveLink(path + item) if isLoop: continue if filterRe is None or filterRe.match(realItem): found = False for itm in files: if itm.fileName == realItem: found = True break if not found: mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetForFileName(realItem) if widget is None: if isFileSearchable(realItem): files.append(ItemToSearchIn(realItem, "")) else: if widget.getType() in \ [ MainWindowTabWidgetBase.PlainTextEditor ]: files.append( ItemToSearchIn(realItem, widget.getUUID())) return def __buildFilesList(self): " Builds the list of files to search in " filtersText = self.filterCombo.currentText().strip() if filtersText != "": filterRe = re.compile(filtersText, re.IGNORECASE) else: filterRe = None if self.projectRButton.isChecked(): return self.__projectFiles(filterRe) if self.openFilesRButton.isChecked(): return self.__openedFiles(filterRe) dirname = os.path.realpath(self.dirEditCombo.currentText().strip()) files = [] self.__dirFiles(dirname + sep, filterRe, files) return files def __process(self): " Search process " # Add entries to the combo box if required regexpText = self.findCombo.currentText() if regexpText in self.findFilesWhat: self.findFilesWhat.remove(regexpText) self.findFilesWhat.insert(0, regexpText) if len(self.findFilesWhat) > 32: self.findFilesWhat = self.findFilesWhat[:32] self.findCombo.clear() self.findCombo.addItems(self.findFilesWhat) filtersText = self.filterCombo.currentText().strip() if filtersText in self.findFilesMasks: self.findFilesMasks.remove(filtersText) self.findFilesMasks.insert(0, filtersText) if len(self.findFilesMasks) > 32: self.findFilesMasks = self.findFilesMasks[:32] self.filterCombo.clear() self.filterCombo.addItems(self.findFilesMasks) if self.dirRButton.isChecked(): dirText = self.dirEditCombo.currentText().strip() if dirText in self.findFilesDirs: self.findFilesDirs.remove(dirText) self.findFilesDirs.insert(0, dirText) if len(self.findFilesDirs) > 32: self.findFilesDirs = self.findFilesDirs[:32] self.dirEditCombo.clear() self.dirEditCombo.addItems(self.findFilesDirs) # Save the combo values for further usage if GlobalData().project.fileName != "": GlobalData().project.setFindInFilesHistory(self.findFilesWhat, self.findFilesDirs, self.findFilesMasks) else: Settings().findFilesWhat = self.findFilesWhat Settings().findFilesDirs = self.findFilesDirs Settings().findFilesMasks = self.findFilesMasks self.__inProgress = True numberOfMatches = 0 self.searchResults = [] self.searchRegexp = None # Form the regexp to search if not self.regexpCheckBox.isChecked(): regexpText = re.escape(regexpText) if self.wordCheckBox.isChecked(): regexpText = "\\b%s\\b" % regexpText flags = re.UNICODE | re.LOCALE if not self.caseCheckBox.isChecked(): flags |= re.IGNORECASE try: self.searchRegexp = re.compile(regexpText, flags) except: logging.error("Invalid search expression") self.close() return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) self.fileLabel.setPath('Building list of files to search in...') QApplication.processEvents() try: files = self.__buildFilesList() except Exception, exc: if "Cancel request" in str(exc): QApplication.restoreOverrideCursor() self.close() return else: QApplication.restoreOverrideCursor() logging.error(str(exc)) self.close() return QApplication.restoreOverrideCursor() QApplication.processEvents() if len(files) == 0: self.fileLabel.setPath('No files to search in') return self.progressBar.setRange(0, len(files)) index = 1 for item in files: if self.__cancelRequest: self.__inProgress = False self.close() return self.fileLabel.setPath( 'Matches: ' + str( numberOfMatches ) + \ ' Processing: ' + item.fileName ) item.search(self.searchRegexp) found = len(item.matches) if found > 0: numberOfMatches += found self.searchResults.append(item) self.progressBar.setValue(index) index += 1 QApplication.processEvents() if numberOfMatches == 0: if len(files) == 1: self.fileLabel.setPath("No matches in 1 file.") else: self.fileLabel.setPath( "No matches in " + \ str( len( files ) ) + " files." ) self.__inProgress = False else: self.close() return
class LDSControls(QFrame): STATIC_IMG = ('error_static.png','linz_static.png','busy_static.png','clean_static.png') ANIM_IMG = ('error.gif','linz.gif','layer.gif','clean.gif') IMG_SPEED = 100 IMG_WIDTH = 64 IMG_HEIGHT = 64 MAX_WD = 450 GD_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../../bin/gdal/gdal-data')) STATUS = LU.enum('ERROR','IDLE','BUSY','CLEAN') def __init__(self,parent): super(LDSControls, self).__init__() self.parent = parent self.initConf() self.initEPSG() self.initUI() def initConf(self): '''Read files in conf dir ending in conf''' self.cflist = ConfigInitialiser.getConfFiles() #self.imgset = self.STATIC_IMG if ConfigWrapper().readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG #self.imgset = self.STATIC_IMG if self.parent.confconn.tp.src.confwrap.readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG sep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.SRCNAME,self.parent.confconn.uconf) self.imgset = self.STATIC_IMG if sep.confwrap.readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG self.parent.confconn.reg.closeEndPoint(self.parent.confconn.SRCNAME) def initEPSG(self): '''Read GDAL EPSG files, splitting by NZ(RSR) and RestOfTheWorld''' gcsf = gdal.FindFile('gdal','gcs.csv') if not gcsf: gcsf = os.path.join(self.GD_PATH,'gcs.csv') pcsf = gdal.FindFile('gdal','pcs.csv') if not pcsf: pcsf = os.path.join(self.GD_PATH,'pcs.csv') gcs = ConfigInitialiser.readCSV(gcsf) pcs = ConfigInitialiser.readCSV(pcsf) self.nzlsr = [(e[0],e[0]+' - '+e[3]) for e in gcs if 'NZGD' in e[1] or 'RSRGD' in e[1]] \ + [(e[0],e[0]+' - '+e[1]) for e in pcs if 'NZGD' in e[1] or 'RSRGD' in e[1]] self.rowsr = [(e[0],e[0]+' - '+e[3]) for e in gcs if 'NZGD' not in e[1] and 'RSRGD' not in e[1]] \ + [(e[0],e[0]+' - '+e[1]) for e in pcs if 'NZGD' not in e[1] and 'RSRGD' not in e[1]] def initUI(self): # 0 1 2 3 4 5 6 7 8 #'destname','lgselect','layer','uconf','group','epsg','fd','td','int' #self.rdest,rlgselect,self.rlayer,ruconf,self.rgroup,repsg,rfd,rtd,rint = readlist QToolTip.setFont(QFont('SansSerif', 10)) #labels destLabel = QLabel('Destination') lgLabel = QLabel('Group/Layer') epsgLabel = QLabel('EPSG') fromDateLabel = QLabel('From Date') toDateLabel = QLabel('To Date') confLabel = QLabel('User Config') self.view = QLabel() self.view.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.view.setAlignment(Qt.AlignCenter) self.confcombo = QComboBox(self) self.confcombo.setToolTip('Enter your user config name (file) here') self.confcombo.addItems(self.cflist) self.confcombo.setEditable(False) #self.confcombo.currentIndexChanged.connect(self.doLGEditUpdate) #combos self.lgcombo = QComboBox(self) self.lgcombo.setMaximumWidth(self.MAX_WD) self.lgcombo.setDuplicatesEnabled(False) #self.lgcombo.setInsertPolicy(QComboBox.InsertAlphabetically)#?doesnt seem to work self.lgcombo.setToolTip('Select either Layer or Group entry') self.lgcombo.setEditable(False) self.sepindex = None #self.updateLGValues() self.epsgcombo = QComboBox(self) self.epsgcombo.setMaximumWidth(self.MAX_WD) self.epsgcombo.setToolTip('Setting an EPSG number here determines the output SR of the layer') self.epsgcombo.addItems([i[1] for i in self.nzlsr]) self.epsgcombo.insertSeparator(len(self.nzlsr)) self.epsgcombo.addItems([i[1] for i in self.rowsr]) self.epsgcombo.setEditable(True) self.epsgcombo.setEnabled(False) self.destlist = self.getConfiguredDestinations() self.destcombo = QComboBox(self) self.destcombo.setToolTip('Choose the desired output type') self.destcombo.setEditable(False) self.destcombo.addItems(self.destlist) #date selection self.fromdateedit = QDateEdit() self.fromdateedit.setCalendarPopup(True) self.fromdateedit.setEnabled(False) self.todateedit = QDateEdit() self.todateedit.setCalendarPopup(True) self.todateedit.setEnabled(False) #check boxes self.epsgenable = QCheckBox() self.epsgenable.setCheckState(False) self.epsgenable.clicked.connect(self.doEPSGEnable) self.fromdateenable = QCheckBox() self.fromdateenable.setCheckState(False) self.fromdateenable.clicked.connect(self.doFromDateEnable) self.todateenable = QCheckBox() self.todateenable.setCheckState(False) self.todateenable.clicked.connect(self.doToDateEnable) self.progressbar = QProgressBar() self.progressbar.setRange(0,100) self.progressbar.setVisible(True) self.progressbar.setMinimumWidth(self.MAX_WD) #buttons self.initbutton = QPushButton("waiting") self.initbutton.setToolTip('Initialise the Layer Configuration') self.initbutton.clicked.connect(self.doInitClickAction) self.cleanbutton = QPushButton("Clean") self.cleanbutton.setToolTip('Clean the selected layer/group from local storage') self.cleanbutton.clicked.connect(self.doCleanClickAction) self.replicatebutton = QPushButton("Replicate") self.replicatebutton.setToolTip('Execute selected replication') self.replicatebutton.clicked.connect(self.doReplicateClickAction) self.cancelbutton = QPushButton("Close") self.cancelbutton.setToolTip('Close the LDS Replicate application') self.cancelbutton.clicked.connect(self.parent.close) #set dialog values using GPR self.updateGUIValues(self.parent.gvs) #set onchange here otherwise we get circular initialisation self.destcombo.currentIndexChanged.connect(self.doDestChanged) self.confcombo.currentIndexChanged.connect(self.doConfChanged) self.lgcombo.currentIndexChanged.connect(self.doLGComboChanged) self.setStatus(self.STATUS.IDLE) #grid grid = QGridLayout() grid.setSpacing(10) #placement section ------------------------------------ #---------+---------+--------+---------+-------- # dest LB | | dest DD # grp LB | | grp DD # conf LB | | conf DD # epsg L | epsg CB | epsg DD # f dt L | f dt CB | f dt DD # t td L | t td CB | t td DD # icon | <- progress -> # layer B | <- . -> |repl B | clean B | close B #---------+---------+--------+---------+-------- grid.addWidget(destLabel, 1, 0) grid.addWidget(self.destcombo, 1, 2) #grid.addWidget(layerLabel, 2, 0) grid.addWidget(lgLabel, 2, 0) grid.addWidget(self.lgcombo, 2, 2) grid.addWidget(confLabel, 3, 0) grid.addWidget(self.confcombo, 3, 2) #grid.addWidget(groupLabel, 4, 0) #grid.addWidget(self.groupEdit, 4, 2) grid.addWidget(epsgLabel, 5, 0) grid.addWidget(self.epsgenable, 5, 1) grid.addWidget(self.epsgcombo, 5, 2) grid.addWidget(fromDateLabel, 6, 0) grid.addWidget(self.fromdateenable, 6, 1) grid.addWidget(self.fromdateedit, 6, 2) grid.addWidget(toDateLabel, 7, 0) grid.addWidget(self.todateenable, 7, 1) grid.addWidget(self.todateedit, 7, 2) hbox3 = QHBoxLayout() hbox3.addWidget(self.view) hbox3.addStretch(1) hbox3.addWidget(self.progressbar) #hbox3.addLayout(vbox2) #hbox3.addLayout(vbox3) hbox4 = QHBoxLayout() hbox4.addWidget(self.initbutton) hbox4.addStretch(1) hbox4.addWidget(self.replicatebutton) hbox4.addWidget(self.cleanbutton) hbox4.addWidget(self.cancelbutton) vbox = QVBoxLayout() #vbox.addStretch(1) vbox.addLayout(grid) vbox.addLayout(hbox3) vbox.addLayout(hbox4) self.setLayout(vbox) #def setProgress(self,pct): # self.progressbar.setValue(pct) def setStatus(self,status,message='',tooltip=None): '''Sets indicator icon and statusbar message''' self.parent.statusbar.showMessage(message) self.parent.statusbar.setToolTip(tooltip if tooltip else '') #progress loc = os.path.abspath(os.path.join(IMG_LOC,self.imgset[status])) #loc = os.path.abspath(os.path.join(os.path.dirname(__file__),self.parent.IMG_LOC,self.imgset[status])) self.progressbar.setVisible(status in (self.STATUS.BUSY, self.STATUS.CLEAN)) #icon anim = QMovie(loc, QByteArray(), self) anim.setScaledSize(QSize(self.IMG_WIDTH,self.IMG_HEIGHT)) anim.setCacheMode(QMovie.CacheAll) anim.setSpeed(self.IMG_SPEED) self.view.clear() self.view.setMovie(anim) anim.start() self.view.repaint() QApplication.processEvents(QEventLoop.AllEvents) def mainWindowEnable(self,enable=True): cons = (self.lgcombo, self.confcombo, self.destcombo, self.initbutton, self.replicatebutton, self.cleanbutton, self.cancelbutton, self.epsgenable,self.fromdateenable,self.todateenable, self.parent.menubar) for c in cons: c.setEnabled(enable) if enable: self.epsgcombo.setEnabled(self.epsgenable.checkState()) self.fromdateedit.setEnabled(self.fromdateenable.checkState()) self.todateedit.setEnabled(self.todateenable.checkState()) else: self.epsgcombo.setEnabled(False) self.fromdateedit.setEnabled(False) self.todateedit.setEnabled(False) QApplication.restoreOverrideCursor() if enable else QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) def refreshLGCombo(self): '''Re index LG combobox since a refreshLG call (new dest?) will usually mean new groups''' self.lgcombo.clear() self.lgcombo.addItems([i[2] for i in self.parent.confconn.lglist]) #NOTE the separator consumes an index, if not clearing the combobox selectively remove the old sepindex (assumes g preceeds l) #if self.sepindex: # self.lgcombo.removeItem(self.sepindex) self.sepindex = [i[0] for i in self.parent.confconn.lglist].count(LORG.GROUP) self.lgcombo.insertSeparator(self.sepindex) def updateLGValues(self,uconf,lgval,dest): '''Sets the values displayed in the Layer/Group combo''' #because we cant seem to sort combobox entries and want groups at the top, clear and re-add #TRACE# #pdb.set_trace() sf = None try: self.parent.confconn.initConnections(uconf,lgval,dest) except Exception as e: sf=1 ldslog.error('Error Updating UC Values. '+str(e)) if sf: self.setStatus(self.STATUS.ERROR,'Error Updating UC Values', str(e)) else: self.setStatus(self.STATUS.IDLE) self.refreshLGCombo() def centre(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def gprParameters(self,rdest): '''Zip default and GPR values''' return [x if LU.assessNone(x) else y for x,y in zip(self.parent.gpr.readsec(rdest),self.parent.DEF_RVALS[1:])] def getLCE(self,ln): '''Read layer parameters''' dep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.destname,self.parent.confconn.uconf) #sep = self.parent.confconn.reg.openEndPoint('WFS',self.parent.confconn.uconf) self.parent.confconn.reg.setupLayerConfig(self.parent.confconn.tp,None,dep,initlc=False) lce = dep.getLayerConf().readLayerParameters(ln) #self.parent.confconn.reg.closeEndPoint('WFS') self.parent.confconn.reg.closeEndPoint(self.parent.confconn.destname) sep,dep = None,None return lce def doDestChanged(self): '''Read the destname parameter and fill dialog with matching GPR values''' rdest = str(self.destlist[self.destcombo.currentIndex()]) rvals = self.gprParameters(rdest) self.updateGUIValues([rdest]+rvals) def doConfChanged(self): '''Read the user conf parameter and fill dialog with matching GPR values''' rdest = str(self.destlist[self.destcombo.currentIndex()]) rlg,_,rep,rfd,rtd = self.gprParameters(rdest) ruc = str(self.cflist[self.confcombo.currentIndex()]) self.updateGUIValues((rdest,rlg,ruc,rep,rfd,rtd)) def doLGComboChanged(self): '''Read the layer/group value and change epsg to layer or gpr match''' #get a matching LG entry and test whether its a layer or group #lgi = self.parent.confconn.getLayerGroupIndex(self.lgcombo.currentText().toUtf8().data()) lgi = self.parent.confconn.getLayerGroupIndex(LQ.readWidgetText(self.lgcombo.currentText())) #lgi can be none if we init a new group, in which case we use the GPR value if lgi: lge = self.parent.confconn.lglist[lgi] lce = self.getLCE(lge[1]) if lge[0]==LORG.LAYER else None else: lce = None #look for filled layer conf epsg OR use prefs stored in gpr if lce and LU.assessNone(lce.epsg): epsgval = lce.epsg else: rdest = str(self.destlist[self.destcombo.currentIndex()]) _,_,epsgval,_,_ = self.gprParameters(rdest) epsgindex = [i[0] for i in self.nzlsr+[(0,0)]+self.rowsr].index(epsgval) if self.epsgcombo.currentIndex() != epsgindex: self.epsgcombo.setCurrentIndex(int(epsgindex)) def updateGUIValues(self,readlist): '''Fill dialog values from provided list''' #TODO. Remove circular references when setCurrentIndex() triggers do###Changed() #Read user input rdest,self.rlgval,ruconf,repsg,rfd,rtd = readlist #-------------------------------------------------------------------- #Destination Menu selecteddest = LU.standardiseDriverNames(rdest) if selecteddest not in self.destlist: self.destlist = self.getConfiguredDestinations() self.destcombo.addItem(selecteddest) destindex = self.destlist.index(selecteddest) if selecteddest else 0 if self.destcombo.currentIndex() != destindex: self.destcombo.setCurrentIndex(destindex) #InitButton self.initbutton.setText('Layer Select') #Config File confindex = 0 if LU.assessNone(ruconf): ruconf = ruconf.split('.')[0] if ruconf not in self.cflist: self.cflist += [ruconf,] self.confcombo.addItem(ruconf) confindex = self.cflist.index(ruconf) if self.confcombo.currentIndex() != confindex: self.confcombo.setCurrentIndex(confindex) #self.confEdit.setText(ruconf if LU.assessNone(ruconf) else '') #Layer/Group Selection self.updateLGValues(ruconf,self.rlgval,rdest) lgindex = None if LU.assessNone(self.rlgval): #index of list value lgindex = self.parent.confconn.getLayerGroupIndex(self.rlgval,col=1) if LU.assessNone(lgindex): #advance by 1 for sep lgindex += 1 if lgindex>self.sepindex else 0 else: #using the separator index sets the combo to blank lgindex = self.sepindex if self.lgcombo.currentIndex() != lgindex: self.lgcombo.setCurrentIndex(lgindex) #self.doLGEditUpdate() #EPSG # user > layerconf #useepsg = LU.precedence(repsg, lce.epsg if lce else None, None) epsgindex = [i[0] for i in self.nzlsr+[(None,None)]+self.rowsr].index(repsg) if self.epsgcombo.currentIndex() != epsgindex: self.epsgcombo.setCurrentIndex(epsgindex) #epsgedit = self.epsgcombo.lineEdit() #epsgedit.setText([e[1] for e in self.nzlsr+self.rowsr if e[0]==repsg][0]) #epsgedit.setText([e for e in self.nzlsr+self.rowsr if re.match('^\s*(\d+).*',e).group(1)==repsg][0]) #To/From Dates if LU.assessNone(rfd): self.fromdateedit.setDate(QDate(int(rfd[0:4]),int(rfd[5:7]),int(rfd[8:10]))) else: early = DataStore.EARLIEST_INIT_DATE self.fromdateedit.setDate(QDate(int(early[0:4]),int(early[5:7]),int(early[8:10]))) if LU.assessNone(rtd): self.todateedit.setDate(QDate(int(rtd[0:4]),int(rtd[5:7]),int(rtd[8:10]))) else: today = DataStore.getCurrent() self.todateedit.setDate(QDate(int(today[0:4]),int(today[5:7]),int(today[8:10]))) #Internal/External CheckBox # if LU.assessNone(rint): # self.internalTrigger.setChecked(rint.lower()==DataStore.CONF_INT) # else: # self.internalTrigger.setChecked(DataStore.DEFAULT_CONF==DataStore.CONF_INT) def getConfiguredDestinations(self): defml = ['',]+DataStore.DRIVER_NAMES.values() return [d for d in self.parent.gpr.getDestinations() if d in defml] def doEPSGEnable(self): self.epsgcombo.setEnabled(self.epsgenable.isChecked()) def doFromDateEnable(self): self.fromdateedit.setEnabled(self.fromdateenable.isChecked()) def doToDateEnable(self): self.todateedit.setEnabled(self.todateenable.isChecked()) def readParameters(self): '''Read values out of dialogs''' destination = LU.assessNone(str(self.destlist[self.destcombo.currentIndex()])) #lgindex = self.parent.confconn.getLayerGroupIndex(self.lgcombo.currentText().toUtf8().data()) lgindex = self.parent.confconn.getLayerGroupIndex(LQ.readWidgetText(self.lgcombo.currentText())) #NB need to test for None explicitly since zero is a valid index lgval = self.parent.confconn.lglist[lgindex][1] if LU.assessNone(lgindex) else None #uconf = LU.standardiseUserConfigName(str(self.confcombo.lineEdit().text())) #uconf = str(self.confcombo.lineEdit().text()) uconf = str(self.cflist[self.confcombo.currentIndex()]) ee = self.epsgenable.isChecked() epsg = None if ee is False else re.match('^\s*(\d+).*',str(self.epsgcombo.lineEdit().text())).group(1) fe = self.fromdateenable.isChecked() te = self.todateenable.isChecked() fd = None if fe is False else str(self.fromdateedit.date().toString('yyyy-MM-dd')) td = None if te is False else str(self.todateedit.date().toString('yyyy-MM-dd')) return destination,lgval,uconf,epsg,fe,te,fd,td def doInitClickAction(self): '''Initialise the LC on LC-button-click, action''' try: try: self.setStatus(self.STATUS.BUSY,'Opening Layer-Config Editor') self.progressbar.setValue(0) self.parent.runLayerConfigAction() finally: self.setStatus(self.STATUS.IDLE,'Ready') except Exception as e: self.setStatus(self.STATUS.ERROR,'Error in Layer-Config',str(sys.exc_info()))#e)) def doCleanClickAction(self): '''Set clean anim and run clean''' #lgo = self.lgcombo.currentText().toUtf8().data() lgo = LQ.readWidgetText(self.lgcombo.currentText()) try: self.setStatus(self.STATUS.CLEAN,'Running Clean '+lgo) self.progressbar.setValue(0) self.runReplicationScript(True) except Exception as e: self.setStatus(self.STATUS.ERROR,'Failed Clean of '+lgo,str(sys.exc_info()))#e)) def doReplicateClickAction(self): '''Set busy anim and run repl''' lgo = self.lgcombo.currentText()#.toUtf8().data()#only used for error messages try: self.setStatus(self.STATUS.BUSY,'Running Replicate '+lgo) self.progressbar.setValue(0) self.runReplicationScript(False) except Exception as e: self.setStatus(self.STATUS.ERROR,'Failed Replication of '+lgo,str(sys.exc_info()))#e)) def runReplicationScript(self,clean=False): '''Run the layer/group repliction script''' destination,lgval,uconf,epsg,fe,te,fd,td = self.readParameters() uconf_path = LU.standardiseUserConfigName(uconf) destination_path = LU.standardiseLayerConfigName(destination) destination_driver = LU.standardiseDriverNames(destination) if not os.path.exists(uconf_path): self.userConfMessage(uconf_path) return elif not MainFileReader(uconf_path).hasSection(destination_driver): self.userConfMessage(uconf_path,destination_driver) return #----------------------------------------------------- #'destname','layer','uconf','group','epsg','fd','td','int' self.parent.gpr.write((destination_driver,lgval,uconf,epsg,fd,td)) ldslog.info(u'dest={0}, lg={1}, conf={2}, epsg={3}'.format(destination_driver,lgval,uconf,epsg)) ldslog.info('fd={0}, td={1}, fe={2}, te={3}'.format(fd,td,fe,te)) lgindex = self.parent.confconn.getLayerGroupIndex(lgval,col=1) #lorg = self.parent.confconn.lglist[lgindex][0] #----------don't need lorg in TP anymore but it is useful for sorting/counting groups #self.parent.confconn.tp.setLayerOrGroup(lorg) self.parent.confconn.tp.setLayerGroupValue(lgval) if self.fromdateenable.isChecked(): self.parent.confconn.tp.setFromDate(fd) if self.todateenable.isChecked(): self.parent.confconn.tp.setToDate(td) self.parent.confconn.tp.setUserConf(uconf) if self.epsgenable: self.parent.confconn.tp.setEPSG(epsg) #because clean state persists in TP if clean: self.parent.confconn.tp.setCleanConfig() else: self.parent.confconn.tp.clearCleanConfig() #(re)initialise the data source since uconf may have changed #>>#self.parent.confconn.tp.src = self.parent.confconn.initSourceWrapper() #-------------------------- ###ep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.destname,self.parent.confconn.uconf) ###self.parent.confconn.reg.closeEndPoint(self.parent.confconn.destname) ###ep = None #Open ProcessRunner and run with TP(proc)/self(gui) instances #HACK temp add of dest_drv to PR call try: #TODO. Test for valid LC first self.tpr = ProcessRunner(self,destination_driver) except Exception as e: ldslog.error('Cannot create ProcessRunner {}. NB Possible missing Layer Config {}'.format(str(e),destination_path)) self.layerConfMessage(destination_path) return #If PR has been successfully created we must vave a valid dst self.tpr.start() def quitProcessRunner(self): self.tpr.join() self.tpr.quit() self.trp = None def userConfMessage(self,uconf,secname=None): ucans = QMessageBox.warning(self, 'User Config Missing/Incomplete', 'Specified User-Config file, '+str(uconf)+' does not exist' if secname is None else 'User-Config file does not contain '+str(secname)+' section', 'Back','Initialise User Config') if not ucans: #Retry ldslog.warn('Retry specifying UC') #self.confcombo.setCurrentIndex(0) return #Init ldslog.warn('Reset User Config Wizard') self.parent.runWizardAction() def layerConfMessage(self,dest): lcans = QMessageBox.warning(self, 'Layer Config Missing', 'Required Layer-Config file, '+str(dest)+' does not exist', 'Back','Run Layer Select') if not lcans: #Retry ldslog.warn('Retry specifying LC') #self.destcombo.setCurrentIndex(0) return #Init ldslog.warn('Reset Layer Config') self.doInitClickAction()
class GearEntriesFrame(QFrame): read_block = pyqtSignal(int, int) # start_addr, num_bytes poke_block = pyqtSignal(int, QByteArray, bool) # start_addr, raw_bytes, is_ascii log = pyqtSignal(str, str) # msg, color MISSING_SKILL_NAME = '[NOT IN DB]' def __init__(self, addr_start, addr_end, class_label, skill2id, id2skill, parent=None): super(GearEntriesFrame, self).__init__(parent) self.addr_start = addr_start self.addr_end = addr_end self.max_num_slots = (addr_end - addr_start) / 6 / 4 + 1 self.class_label = class_label self.skill2id = skill2id self.id2skill = id2skill self.skill_names = self.skill2id.keys() self.skill_names.sort() self.slots_cache = [] # list of raw 6*4 bytes self.slots_txt = None self.cur_slot_idx = -1 self.cur_slot_bytes = None self.lbl_label = QLabel(self.class_label, self) self.btn_read_slots = QPushButton(' Cache Slots', self) self.btn_read_slots.setIcon(QIcon('img/flaticon/data110.png')) self.btn_read_slots.setStyleSheet('background-color: white') self.btn_read_slots.clicked.connect(self.onReadSlots) self.cmb_slots = QComboBox(self) self.cmb_slots.setToolTip('') self.cmb_slots.setStyleSheet('background-color: white') self.cmb_slots.currentIndexChanged[str].connect(self.onChangeSlot) self.cmb_slots.setDisabled(True) self.btn_read = QPushButton(self) self.btn_read.setIcon(QIcon('img/flaticon/open135.png')) self.btn_read.setToolTip('Read item slot value from memory') self.btn_read.setStyleSheet('background-color: white') self.btn_read.clicked.connect(self.onReadSlot) self.txt_raw = QLineEdit(self) self.txt_raw.setPlaceholderText('Raw hex data') self.txt_raw.setMaxLength(8 * 6 + 5) self.txt_raw.editingFinished.connect(self.onChangeRaw) self.btn_poke = QPushButton(self) self.btn_poke.setIcon(QIcon('img/flaticon/draw39.png')) self.btn_poke.setToolTip('Poke new value for item slot') self.btn_poke.setStyleSheet('background-color: white') self.btn_poke.clicked.connect(self.onPokeSlot) self.cmb_skills_a = QComboBox(self) self.cmb_skills_a.setEditable(True) self.cmb_skills_a.addItems(self.skill_names) self.cmb_skills_a.lineEdit().setText(GearEntriesFrame.MISSING_SKILL_NAME) self.cmb_skills_a.currentIndexChanged[str].connect(self.onChangeSkillA) self.cmb_skills_b = QComboBox(self) self.cmb_skills_b.setEditable(True) self.cmb_skills_b.addItems(self.skill_names) self.cmb_skills_b.lineEdit().setText(GearEntriesFrame.MISSING_SKILL_NAME) self.cmb_skills_b.currentIndexChanged[str].connect(self.onChangeSkillB) self.cmb_skills_c = QComboBox(self) self.cmb_skills_c.setEditable(True) self.cmb_skills_c.addItems(self.skill_names) self.cmb_skills_c.lineEdit().setText(GearEntriesFrame.MISSING_SKILL_NAME) self.cmb_skills_c.currentIndexChanged[str].connect(self.onChangeSkillC) incr_labels = [] for incr in xrange(16): incr_labels.append('+%d' % incr) self.cmb_incr_a = QComboBox(self) self.cmb_incr_a.addItems(incr_labels) self.cmb_incr_a.currentIndexChanged[int].connect(self.onChangeIncrA) self.cmb_incr_b = QComboBox(self) self.cmb_incr_b.addItems(incr_labels) self.cmb_incr_b.currentIndexChanged[int].connect(self.onChangeIncrB) self.cmb_incr_c = QComboBox(self) self.cmb_incr_c.addItems(incr_labels) self.cmb_incr_c.currentIndexChanged[int].connect(self.onChangeIncrC) slot_labels = [] for incr in xrange(4): slot_labels.append('%d Augment Slots' % incr) self.cmb_augments = QComboBox(self) self.cmb_augments.addItems(slot_labels) self.cmb_augments.currentIndexChanged[int].connect(self.onChangeAugments) self.layout = QGridLayout(self) self.layout.addWidget(self.lbl_label, 0, 0) self.layout.addWidget(self.btn_read_slots, 0, 1) self.layout.addWidget(self.cmb_slots, 0, 2) self.layout.addWidget(self.btn_read, 0, 3) self.layout.addWidget(self.txt_raw, 1, 0, 1, 3) self.layout.addWidget(self.btn_poke, 1, 3) self.layout.addWidget(self.cmb_skills_a, 2, 0) self.layout.addWidget(self.cmb_incr_a, 2, 1) self.layout.addWidget(self.cmb_skills_b, 3, 0) self.layout.addWidget(self.cmb_incr_b, 3, 1) self.layout.addWidget(self.cmb_skills_c, 4, 0) self.layout.addWidget(self.cmb_incr_c, 4, 1) self.layout.addWidget(self.cmb_augments, 2, 2) self.layout.setColumnStretch(0, 7) self.layout.setColumnStretch(1, 3) self.layout.setColumnStretch(2, 3) self.layout.setColumnStretch(3, 1) self.layout.setContentsMargins(0, 2, 0, 2) icon_height = self.lbl_label.height() * 8 / 15 icon_size = QSize(icon_height, icon_height) self.btn_read_slots.setIconSize(icon_size) self.btn_read.setIconSize(icon_size) self.btn_poke.setIconSize(icon_size) btn_size = QSize(icon_height * 1.5, icon_height * 1.5) self.btn_read.setFixedSize(btn_size) self.btn_poke.setFixedSize(btn_size) self.updateUI() def updateUI(self): # Disable editing if cache missing if not (0 <= self.cur_slot_idx < len(self.slots_cache)) or self.cur_slot_bytes is None: self.cur_slot_idx = -1 self.cur_slot_bytes = None self.cmb_slots.setDisabled(True) self.cmb_skills_a.setDisabled(True) self.cmb_skills_b.setDisabled(True) self.cmb_skills_c.setDisabled(True) self.cmb_incr_a.setDisabled(True) self.cmb_incr_b.setDisabled(True) self.cmb_incr_c.setDisabled(True) self.cmb_augments.setDisabled(True) self.txt_raw.setDisabled(True) return else: self.cmb_slots.setDisabled(False) self.cmb_skills_a.setDisabled(False) self.cmb_skills_b.setDisabled(False) self.cmb_skills_c.setDisabled(False) self.cmb_incr_a.setDisabled(False) self.cmb_incr_b.setDisabled(False) self.cmb_incr_c.setDisabled(False) self.cmb_augments.setDisabled(False) self.txt_raw.setDisabled(False) # Validate current slot's raw bytes try: (gear_id_bytes, index, post_index, skill_a_id, skill_a_incr, skill_b_id, skill_b_incr, skill_c_id, skill_c_incr, augment_a_id, augment_b_id, augment_c_id) = parse_gear_bytes(self.cur_slot_bytes) cur_slot_words = struct.unpack('>IIIIII', self.cur_slot_bytes) num_augments = (augment_a_id != 0xFFFF) + (augment_b_id != 0xFFFF) + (augment_c_id != 0xFFFF) except ValueError, e: self.log.emit('Gear parsing failed: %s' % e.what(), 'red') return # Update UI self.txt_raw.setDisabled(False) self.txt_raw.editingFinished.disconnect() self.txt_raw.setText('%08X %08X %08X %08X %08X %08X' % cur_slot_words) self.txt_raw.editingFinished.connect(self.onChangeRaw) self.cmb_skills_a.setDisabled(False) self.cmb_skills_a.currentIndexChanged[str].disconnect() try: skill_name = self.id2skill[skill_a_id] skill_idx = self.skill_names.index(skill_name) self.cmb_skills_a.setCurrentIndex(skill_idx) except (KeyError, ValueError): self.cmb_skills_a.lineEdit().setText(GearEntriesFrame.MISSING_SKILL_NAME) self.cmb_skills_a.currentIndexChanged[str].connect(self.onChangeSkillA) self.cmb_skills_b.setDisabled(False) self.cmb_skills_b.currentIndexChanged[str].disconnect() try: skill_name = self.id2skill[skill_b_id] skill_idx = self.skill_names.index(skill_name) self.cmb_skills_b.setCurrentIndex(skill_idx) except (KeyError, ValueError): self.cmb_skills_b.lineEdit().setText(GearEntriesFrame.MISSING_SKILL_NAME) self.cmb_skills_b.currentIndexChanged[str].connect(self.onChangeSkillB) self.cmb_skills_c.setDisabled(False) self.cmb_skills_c.currentIndexChanged[str].disconnect() try: skill_name = self.id2skill[skill_c_id] skill_idx = self.skill_names.index(skill_name) self.cmb_skills_c.setCurrentIndex(skill_idx) except (KeyError, ValueError): self.cmb_skills_c.lineEdit().setText(GearEntriesFrame.MISSING_SKILL_NAME) self.cmb_skills_c.currentIndexChanged[str].connect(self.onChangeSkillC) self.cmb_incr_a.setDisabled(False) self.cmb_incr_a.currentIndexChanged[int].disconnect() self.cmb_incr_a.setCurrentIndex(skill_a_incr) self.cmb_incr_a.currentIndexChanged[int].connect(self.onChangeIncrA) self.cmb_incr_b.setDisabled(False) self.cmb_incr_b.currentIndexChanged[int].disconnect() self.cmb_incr_b.setCurrentIndex(skill_b_incr) self.cmb_incr_b.currentIndexChanged[int].connect(self.onChangeIncrB) self.cmb_incr_c.setDisabled(False) self.cmb_incr_c.currentIndexChanged[int].disconnect() self.cmb_incr_c.setCurrentIndex(skill_c_incr) self.cmb_incr_c.currentIndexChanged[int].connect(self.onChangeIncrC) self.cmb_augments.setDisabled(False) self.cmb_augments.currentIndexChanged[int].disconnect() self.cmb_augments.setCurrentIndex(num_augments) self.cmb_augments.currentIndexChanged[int].connect(self.onChangeAugments)
class ItemEntriesFrame(QFrame): read_block = pyqtSignal(int, int) # start_addr, num_bytes poke_block = pyqtSignal(int, QByteArray, bool) # start_addr, raw_bytes, is_ascii log = pyqtSignal(str, str) # msg, color MISSING_ITEM_NAME = '[NOT IN DB]' def __init__(self, type_val, addr_start, addr_end, label, id2name, idx2id, names, parent=None): super(ItemEntriesFrame, self).__init__(parent) self.type_val = type_val self.code_offset = 0 self.addr_start = addr_start self.addr_end = addr_end self.max_num_slots = (addr_end - addr_start) / 3 / 4 + 1 self.label = label self.id2name = id2name self.idx2id = idx2id self.names = names self.slots_cache = [ ] # tuple: (addr_hex, addr_val, slot_number, cur_val) self.cur_slot_idx = -1 self.lbl_label = QLabel(self.label, self) self.btn_read_slots = QPushButton(' Cache Slots', self) self.btn_read_slots.setIcon(QIcon('img/flaticon/data110.png')) self.btn_read_slots.setStyleSheet('background-color: white') self.btn_read_slots.clicked.connect(self.onReadSlots) self.btn_search_cache = QPushButton(' Search ID', self) self.btn_search_cache.setIcon(QIcon('img/flaticon/magnifier13.png')) self.btn_search_cache.setToolTip( 'Find slot in cache with specified item ID') self.btn_search_cache.setStyleSheet('background-color: white') self.btn_search_cache.clicked.connect(self.onSearchCacheForID) self.btn_read = QPushButton(self) self.btn_read.setIcon(QIcon('img/flaticon/open135.png')) self.btn_read.setToolTip('Read item slot value from memory') self.btn_read.setStyleSheet('background-color: white') self.btn_read.clicked.connect(self.onReadSlot) self.cmb_slots = QComboBox(self) self.cmb_slots.setStyleSheet('background-color: white') self.cmb_slots.currentIndexChanged[int].connect(self.onChangeSlot) self.cmb_slots.setDisabled(True) self.cmb_names = QComboBox(self) self.cmb_names.setEditable(True) self.cmb_names.addItems(self.names) self.cmb_names.lineEdit().setText(ItemEntriesFrame.MISSING_ITEM_NAME) self.cmb_names.currentIndexChanged[int].connect(self.fetchID) self.txt_id = QLineEdit(self) self.txt_id.setPlaceholderText('ID (hex)') self.txt_id.setMaxLength(3) self.txt_id.textChanged.connect(self.fetchName) self.btn_rename = QPushButton(' Fix Name', self) self.btn_rename.setIcon(QIcon('img/flaticon/cloud-storage3.png')) self.btn_rename.setToolTip( 'Add/Correct Item Name for %s (type: %02X)' % (self.label, type_val)) self.btn_rename.setStyleSheet('background-color: white') self.btn_rename.clicked.connect(self.onRename) self.txt_amount = QLineEdit(self) self.txt_amount.setPlaceholderText('Amount') self.txt_amount.setMaxLength(3) self.btn_poke = QPushButton(self) self.btn_poke.setIcon(QIcon('img/flaticon/draw39.png')) self.btn_poke.setToolTip('Poke new value for item slot') self.btn_poke.setStyleSheet('background-color: white') self.btn_poke.clicked.connect(self.onPokeSlot) self.layout = QGridLayout(self) self.layout.addWidget(self.lbl_label, 0, 0) self.layout.addWidget(self.btn_read_slots, 0, 1) self.layout.addWidget(self.btn_search_cache, 0, 2) self.layout.addWidget(self.cmb_slots, 0, 3) self.layout.addWidget(self.btn_read, 0, 4) self.layout.addWidget(self.cmb_names, 1, 0) self.layout.addWidget(self.txt_id, 1, 1) self.layout.addWidget(self.btn_rename, 1, 2) self.layout.addWidget(self.txt_amount, 1, 3) self.layout.addWidget(self.btn_poke, 1, 4) self.layout.setColumnStretch(0, 7) self.layout.setColumnStretch(1, 3) self.layout.setColumnStretch(2, 3) self.layout.setColumnStretch(3, 3) self.layout.setColumnStretch(4, 1) self.layout.setContentsMargins(0, 2, 0, 2) icon_height = self.lbl_label.height() * 8 / 15 icon_size = QSize(icon_height, icon_height) self.btn_read_slots.setIconSize(icon_size) self.btn_search_cache.setIconSize(icon_size) self.btn_rename.setIconSize(icon_size) self.btn_read.setIconSize(icon_size) self.btn_poke.setIconSize(icon_size) btn_size = QSize(icon_height * 1.5, icon_height * 1.5) self.btn_read.setFixedSize(btn_size) self.btn_poke.setFixedSize(btn_size) self.updateUI() def updateUI(self): # Disable editing if cache missing if not (0 <= self.cur_slot_idx < len(self.slots_cache)): self.cmb_names.lineEdit().setText( ItemEntriesFrame.MISSING_ITEM_NAME) self.cmb_names.setDisabled(True) self.txt_id.setText('') self.txt_id.setDisabled(True) return # Validate current value cur_val = self.slots_cache[self.cur_slot_idx][3] (type_val, id_val, amount) = parse_item_word(cur_val) if type_val != self.type_val and type_val != 0: cur_addr = self.slots_cache[ self.cur_slot_idx][1] + self.code_offset self.log.emit( 'Cache error: val(0x%08X)=%08X, type (%02X) != expected (%02X)' % (cur_addr, cur_val, type_val, self.type_val), 'red') return # Update UI self.txt_id.setDisabled(False) self.txt_id.setText('%03X' % id_val) self.cmb_names.setDisabled(False) self.fetchName() self.txt_amount.setText(str(amount)) def setAlternateBGColor(self): self.setStyleSheet( 'ItemEntriesFrame { background-color:rgb(248,248,248) }') @pyqtSlot(int) def onSetCodeOffset(self, signed_offset): self.code_offset = signed_offset @pyqtSlot() def onRename(self): id_txt = str(self.txt_id.text()) if len(id_txt) != 3: return dialog = FixItemNameDialog('%02X' % self.type_val, id_txt, self) dialog.log.connect(self.log) dialog.exec_() @pyqtSlot() def onReadSlots(self): self.read_block.emit(self.addr_start + self.code_offset, self.max_num_slots * 4 * 3) @pyqtSlot(int, int, QByteArray) def onBlockRead(self, addr_start_w_code_offset, num_bytes, raw_bytes): # Determine whether block has cache or single slot if (addr_start_w_code_offset == (self.addr_start + self.code_offset) ) and (num_bytes == self.max_num_slots * 4 * 3): self.onCacheRead(addr_start_w_code_offset, raw_bytes) elif num_bytes == 4: # Assume read slot # Ignore if no cache if not (0 <= self.cur_slot_idx < len(self.slots_cache)): return self.onSlotRead(addr_start_w_code_offset, raw_bytes) def onCacheRead(self, addr_start_w_code_offset, raw_bytes): slot_bytes = str(raw_bytes) self.slots_cache = [] slots_txt = [] for slot_i in xrange(self.max_num_slots): byte_offset = slot_i * 3 * 4 cur_slot_bytes = slot_bytes[byte_offset:(byte_offset + 4)] if len(cur_slot_bytes) != 4: continue cur_slot_val = struct.unpack('>I', cur_slot_bytes)[0] (type_val, id_val, amount) = parse_item_word(cur_slot_val) if type_val == 0 or amount == 0: continue elif type_val != self.type_val: self.log.emit( 'val(%08X)=%08X, type_val(%02X) unexpected(%02X)' % (addr_start_w_code_offset + byte_offset, cur_slot_val, type_val, self.type_val), 'red') continue else: addr_val = addr_start_w_code_offset + byte_offset - self.code_offset # remove code_offset since it may change later addr_hex = '%08X' % addr_val slot_number = slot_i + 1 self.slots_cache.append( (addr_hex, addr_val, slot_number, cur_slot_val)) slots_txt.append('Slot %03d' % slot_number) # Update UI self.log.emit( 'Found %d %s slots in memory' % (len(self.slots_cache), self.label), 'black') self.cmb_slots.clear() if len(self.slots_cache) <= 0: self.cmb_slots.setDisabled(True) self.cur_slot_idx = -1 else: self.cmb_slots.setDisabled(False) self.cmb_slots.addItems(slots_txt) self.cur_slot_idx = 0 self.updateUI() def onSlotRead(self, addr_word_w_code_offset, raw_bytes): addr_cur_slot = self.slots_cache[ self.cur_slot_idx][1] + self.code_offset if addr_word_w_code_offset == addr_cur_slot: cur_cache = self.slots_cache[self.cur_slot_idx] new_val = struct.unpack('>I', str(raw_bytes))[0] new_cache = (cur_cache[0], cur_cache[1], cur_cache[2], new_val) self.slots_cache[self.cur_slot_idx] = new_cache self.updateUI() else: # Update cached value of other slots addr_first_slot = self.slots_cache[0][1] + self.code_offset addr_last_slot = self.slots_cache[-1][1] + self.code_offset if (addr_first_slot <= addr_word_w_code_offset <= addr_last_slot) and \ ((addr_word_w_code_offset - addr_first_slot) % 12 == 0): for slot_i in xrange(len(self.slots_cache)): addr_cur_slot = self.slots_cache[slot_i][ 1] + self.code_offset if addr_word_w_code_offset == addr_cur_slot: cur_cache = self.slots_cache[slot_i] new_val = struct.unpack('>I', str(raw_bytes))[0] new_cache = (cur_cache[0], cur_cache[1], cur_cache[2], new_val) self.slots_cache[slot_i] = new_cache return @pyqtSlot() def onSearchCacheForID(self): # Stop if no cache if not (0 <= self.cur_slot_idx < len(self.slots_cache)): self.log.emit('Must cache slots before searching', 'red') return # Fetch and validate target ID try: target_id_val = int(str(self.txt_id.text()), 16) if target_id_val < 0 or target_id_val > Item.MAX_ID_VAL: self.log.emit('Item ID out of [0, 0x%03X] range' % Item.MAX_ID_VAL) return except ValueError: self.log.emit('Failed to parse item ID, expecting XXX', 'red') return # Search ID in cache for cand_slot_idx in xrange(len(self.slots_cache)): (type_val, id_val, amount) = parse_item_word(self.slots_cache[cand_slot_idx][3]) if id_val == target_id_val and type_val == self.type_val: self.cur_slot_idx = cand_slot_idx self.cmb_slots.setCurrentIndex(self.cur_slot_idx) self.updateUI() return self.log.emit( 'Did not find ID=%03X in %d cached %s slots' % (target_id_val, len(self.slots_cache), self.label), 'red') @pyqtSlot(int) def onChangeSlot(self, new_slot_idx): # Validate new_slot_idx if not (0 <= new_slot_idx < len(self.slots_cache)): return # Update slot idx and read value from memory self.cur_slot_idx = new_slot_idx self.cmb_names.lineEdit().setText(ItemEntriesFrame.MISSING_ITEM_NAME) self.cmb_names.setDisabled(True) self.txt_id.setText('') self.txt_id.setDisabled(True) self.onReadSlot() @pyqtSlot() def fetchName(self): try: id_val = int(str(self.txt_id.text()), 16) except ValueError: return name = self.MISSING_ITEM_NAME if id_val in self.id2name: name = self.id2name[id_val] self.cmb_names.lineEdit().setText(name) @pyqtSlot(int) def fetchID(self, cmb_idx): if cmb_idx < 0 or cmb_idx >= len(self.idx2id): self.txt_id.setText('') else: self.txt_id.setText(self.idx2id[cmb_idx]) @pyqtSlot() def onReadSlot(self): try: if not (0 <= self.cur_slot_idx < len(self.slots_cache)): raise ValueError('must cache slots before reading') addr_cur_slot = self.slots_cache[ self.cur_slot_idx][1] + self.code_offset self.read_block.emit(addr_cur_slot, 4) except ValueError, e: cur_slot_num = self.slots_cache[self.cur_slot_idx][2] self.log.emit( 'READ %s Slot %03d failed: %s' % (self.label, cur_slot_num, str(e)), 'red') except BaseException, e: cur_slot_num = self.slots_cache[self.cur_slot_idx][2] self.log.emit( 'READ %s Slot %03d failed: %s' % (self.label, cur_slot_num, str(e)), 'red') traceback.print_exc()
class FindInFilesDialog( QDialog, object ): """ find in files dialog implementation """ inProject = 0 inDirectory = 1 inOpenFiles = 2 def __init__( self, where, what = "", dirPath = "", filters = [], parent = None ): QDialog.__init__( self, parent ) mainWindow = GlobalData().mainWindow self.editorsManager = mainWindow.editorsManagerWidget.editorsManager self.__cancelRequest = False self.__inProgress = False self.searchRegexp = None self.searchResults = [] # Avoid pylint complains self.findCombo = None self.caseCheckBox = None self.wordCheckBox = None self.regexpCheckBox = None self.projectRButton = None self.openFilesRButton = None self.dirRButton = None self.dirEditCombo = None self.dirSelectButton = None self.filterCombo = None self.fileLabel = None self.progressBar = None self.findButton = None self.__createLayout() self.setWindowTitle( "Find in files" ) # Restore the combo box values project = GlobalData().project if project.fileName != "": self.findFilesWhat = project.findFilesWhat self.findFilesDirs = project.findFilesDirs self.findFilesMasks = project.findFilesMasks else: settings = Settings() self.findFilesWhat = settings.findFilesWhat self.findFilesDirs = settings.findFilesDirs self.findFilesMasks = settings.findFilesMasks self.findCombo.addItems( self.findFilesWhat ) self.findCombo.setEditText( "" ) self.dirEditCombo.addItems( self.findFilesDirs ) self.dirEditCombo.setEditText( "" ) self.filterCombo.addItems( self.findFilesMasks ) self.filterCombo.setEditText( "" ) if where == self.inProject: self.setSearchInProject( what, filters ) elif where == self.inDirectory: self.setSearchInDirectory( what, dirPath, filters ) else: self.setSearchInOpenFiles( what, filters ) return def __createLayout( self ): """ Creates the dialog layout """ self.resize( 600, 300 ) self.setSizeGripEnabled( True ) verticalLayout = QVBoxLayout( self ) gridLayout = QGridLayout() # Combo box for the text to search findLabel = QLabel( self ) findLabel.setText( "Find text:" ) self.findCombo = QComboBox( self ) self.__tuneCombo( self.findCombo ) self.findCombo.lineEdit().setToolTip( "Regular expression to search for" ) self.findCombo.editTextChanged.connect( self.__someTextChanged ) gridLayout.addWidget( findLabel, 0, 0, 1, 1 ) gridLayout.addWidget( self.findCombo, 0, 1, 1, 1 ) verticalLayout.addLayout( gridLayout ) # Check boxes horizontalCBLayout = QHBoxLayout() self.caseCheckBox = QCheckBox( self ) self.caseCheckBox.setText( "Match &case" ) horizontalCBLayout.addWidget( self.caseCheckBox ) self.wordCheckBox = QCheckBox( self ) self.wordCheckBox.setText( "Match whole &word" ) horizontalCBLayout.addWidget( self.wordCheckBox ) self.regexpCheckBox = QCheckBox( self ) self.regexpCheckBox.setText( "Regular &expression" ) horizontalCBLayout.addWidget( self.regexpCheckBox ) verticalLayout.addLayout( horizontalCBLayout ) # Files groupbox filesGroupbox = QGroupBox( self ) filesGroupbox.setTitle( "Find in" ) sizePolicy = QSizePolicy( QSizePolicy.Expanding, QSizePolicy.Preferred ) sizePolicy.setHorizontalStretch( 0 ) sizePolicy.setVerticalStretch( 0 ) sizePolicy.setHeightForWidth( filesGroupbox.sizePolicy().hasHeightForWidth() ) filesGroupbox.setSizePolicy( sizePolicy ) gridLayoutFG = QGridLayout( filesGroupbox ) self.projectRButton = QRadioButton( filesGroupbox ) self.projectRButton.setText( "&Project" ) gridLayoutFG.addWidget( self.projectRButton, 0, 0 ) self.projectRButton.clicked.connect( self.__projectClicked ) self.openFilesRButton = QRadioButton( filesGroupbox ) self.openFilesRButton.setText( "&Opened files only" ) gridLayoutFG.addWidget( self.openFilesRButton, 1, 0 ) self.openFilesRButton.clicked.connect( self.__openFilesOnlyClicked ) self.dirRButton = QRadioButton( filesGroupbox ) self.dirRButton.setText( "&Directory tree" ) gridLayoutFG.addWidget( self.dirRButton, 2, 0 ) self.dirRButton.clicked.connect( self.__dirClicked ) self.dirEditCombo = QComboBox( filesGroupbox ) self.__tuneCombo( self.dirEditCombo ) self.dirEditCombo.lineEdit().setToolTip( "Directory to search in" ) gridLayoutFG.addWidget( self.dirEditCombo, 2, 1 ) self.dirEditCombo.editTextChanged.connect( self.__someTextChanged ) self.dirSelectButton = QPushButton( filesGroupbox ) self.dirSelectButton.setText( "..." ) gridLayoutFG.addWidget( self.dirSelectButton, 2, 2 ) self.dirSelectButton.clicked.connect( self.__selectDirClicked ) filterLabel = QLabel( filesGroupbox ) filterLabel.setText( "Files filter:" ) gridLayoutFG.addWidget( filterLabel, 3, 0 ) self.filterCombo = QComboBox( filesGroupbox ) self.__tuneCombo( self.filterCombo ) self.filterCombo.lineEdit().setToolTip( "File names regular expression" ) gridLayoutFG.addWidget( self.filterCombo, 3, 1 ) self.filterCombo.editTextChanged.connect( self.__someTextChanged ) verticalLayout.addWidget( filesGroupbox ) # File label self.fileLabel = FitPathLabel( self ) self.fileLabel.setSizePolicy( QSizePolicy.Ignored, QSizePolicy.Fixed ) verticalLayout.addWidget( self.fileLabel ) # Progress bar self.progressBar = QProgressBar( self ) self.progressBar.setValue( 0 ) self.progressBar.setOrientation( Qt.Horizontal ) verticalLayout.addWidget( self.progressBar ) # Buttons at the bottom buttonBox = QDialogButtonBox( self ) buttonBox.setOrientation( Qt.Horizontal ) buttonBox.setStandardButtons( QDialogButtonBox.Cancel ) self.findButton = buttonBox.addButton( "Find", QDialogButtonBox.AcceptRole ) self.findButton.setDefault( True ) self.findButton.clicked.connect( self.__process ) verticalLayout.addWidget( buttonBox ) buttonBox.rejected.connect( self.__onClose ) return @staticmethod def __tuneCombo( comboBox ): " Sets the common settings for a combo box " sizePolicy = QSizePolicy( QSizePolicy.Expanding, QSizePolicy.Fixed ) sizePolicy.setHorizontalStretch( 0 ) sizePolicy.setVerticalStretch( 0 ) sizePolicy.setHeightForWidth( \ comboBox.sizePolicy().hasHeightForWidth() ) comboBox.setSizePolicy( sizePolicy ) comboBox.setEditable( True ) comboBox.setInsertPolicy( QComboBox.InsertAtTop ) comboBox.setAutoCompletion( False ) comboBox.setDuplicatesEnabled( False ) return def __onClose( self ): " Triggered when the close button is clicked " self.__cancelRequest = True if not self.__inProgress: self.close() return def setSearchInProject( self, what = "", filters = [] ): " Set search ready for the whole project " if GlobalData().project.fileName == "": # No project loaded, fallback to opened files self.setSearchInOpenFiles( what, filters ) return # Select the project radio button self.projectRButton.setEnabled( True ) self.projectRButton.setChecked( True ) self.dirEditCombo.setEnabled( False ) self.dirSelectButton.setEnabled( False ) openedFiles = self.editorsManager.getTextEditors() self.openFilesRButton.setEnabled( len( openedFiles ) != 0 ) self.setFilters( filters ) self.findCombo.setEditText( what ) self.findCombo.lineEdit().selectAll() self.findCombo.setFocus() # Check searchability self.__testSearchability() return def setSearchInOpenFiles( self, what = "", filters = [] ): " Sets search ready for the opened files " openedFiles = self.editorsManager.getTextEditors() if len( openedFiles ) == 0: # No opened files, fallback to search in dir self.setSearchInDirectory( what, "", filters ) return # Select the radio buttons self.projectRButton.setEnabled( GlobalData().project.fileName != "" ) self.openFilesRButton.setEnabled( True ) self.openFilesRButton.setChecked( True ) self.dirEditCombo.setEnabled( False ) self.dirSelectButton.setEnabled( False ) self.setFilters( filters ) self.findCombo.setEditText( what ) self.findCombo.lineEdit().selectAll() self.findCombo.setFocus() # Check searchability self.__testSearchability() return def setSearchInDirectory( self, what = "", dirPath = "", filters = [] ): " Sets search ready for the given directory " # Select radio buttons self.projectRButton.setEnabled( GlobalData().project.fileName != "" ) openedFiles = self.editorsManager.getTextEditors() self.openFilesRButton.setEnabled( len( openedFiles ) != 0 ) self.dirRButton.setEnabled( True ) self.dirRButton.setChecked( True ) self.dirEditCombo.setEnabled( True ) self.dirSelectButton.setEnabled( True ) self.dirEditCombo.setEditText( dirPath ) self.setFilters( filters ) self.findCombo.setEditText( what ) self.findCombo.lineEdit().selectAll() self.findCombo.setFocus() # Check searchability self.__testSearchability() return def setFilters( self, filters ): " Sets up the filters " # Set filters if provided if filters: self.filterCombo.setEditText( ";".join( filters ) ) else: self.filterCombo.setEditText( "" ) return def __testSearchability( self ): " Tests the searchability and sets the Find button status " startTime = time.time() if self.findCombo.currentText().strip() == "": self.findButton.setEnabled( False ) self.findButton.setToolTip( "No text to search" ) return if self.dirRButton.isChecked(): dirname = self.dirEditCombo.currentText().strip() if dirname == "": self.findButton.setEnabled( False ) self.findButton.setToolTip( "No directory path" ) return if not os.path.isdir( dirname ): self.findButton.setEnabled( False ) self.findButton.setToolTip( "Path is not a directory" ) return # Now we need to match file names if there is a filter filtersText = self.filterCombo.currentText().strip() if filtersText == "": self.findButton.setEnabled( True ) self.findButton.setToolTip( "Find in files" ) return # Need to check the files match try: filterRe = re.compile( filtersText, re.IGNORECASE ) except: self.findButton.setEnabled( False ) self.findButton.setToolTip( "Incorrect files " \ "filter regular expression" ) return matched = False tooLong = False if self.projectRButton.isChecked(): # Whole project for fname in GlobalData().project.filesList: if fname.endswith( sep ): continue matched = filterRe.match( fname ) if matched: break # Check the time, it might took too long if time.time() - startTime > 0.1: tooLong = True break elif self.openFilesRButton.isChecked(): # Opened files openedFiles = self.editorsManager.getTextEditors() for record in openedFiles: matched = filterRe.match( record[ 1 ] ) if matched: break # Check the time, it might took too long if time.time() - startTime > 0.1: tooLong = True break else: # Search in the dir if not dirname.endswith( sep ): dirname += sep matched, tooLong = self.__matchInDir( dirname, filterRe, startTime ) if matched: self.findButton.setEnabled( True ) self.findButton.setToolTip( "Find in files" ) else: if tooLong: self.findButton.setEnabled( True ) self.findButton.setToolTip( "Find in files" ) else: self.findButton.setEnabled( False ) self.findButton.setToolTip( "No files matched to search in" ) return @staticmethod def __matchInDir( path, filterRe, startTime ): " Provides the 'match' and 'too long' statuses " matched = False tooLong = False for item in os.listdir( path ): if time.time() - startTime > 0.1: tooLong = True return matched, tooLong if os.path.isdir( path + item ): dname = path + item + sep matched, tooLong = FindInFilesDialog.__matchInDir( dname, filterRe, startTime ) if matched or tooLong: return matched, tooLong continue if filterRe.match( path + item ): matched = True return matched, tooLong return matched, tooLong def __projectClicked( self ): " project radio button clicked " self.dirEditCombo.setEnabled( False ) self.dirSelectButton.setEnabled( False ) self.__testSearchability() return def __openFilesOnlyClicked( self ): " open files only radio button clicked " self.dirEditCombo.setEnabled( False ) self.dirSelectButton.setEnabled( False ) self.__testSearchability() return def __dirClicked( self ): " dir radio button clicked " self.dirEditCombo.setEnabled( True ) self.dirSelectButton.setEnabled( True ) self.dirEditCombo.setFocus() self.__testSearchability() return def __someTextChanged( self, text ): " Text to search, filter or dir name has been changed " self.__testSearchability() return def __selectDirClicked( self ): " The user selects a directory " dirName = QFileDialog.getExistingDirectory( self, "Select directory to search in", self.dirEditCombo.currentText(), QFileDialog.Options( QFileDialog.ShowDirsOnly ) ) if dirName: self.dirEditCombo.setEditText( os.path.normpath( dirName ) ) self.__testSearchability() return def __projectFiles( self, filterRe ): " Project files list respecting the mask " mainWindow = GlobalData().mainWindow files = [] for fname in GlobalData().project.filesList: if fname.endswith( sep ): continue if filterRe is None or filterRe.match( fname ): widget = mainWindow.getWidgetForFileName( fname ) if widget is None: # Do not check for broken symlinks if isFileSearchable( fname, False ): files.append( ItemToSearchIn( fname, "" ) ) else: if widget.getType() in \ [ MainWindowTabWidgetBase.PlainTextEditor ]: files.append( ItemToSearchIn( fname, widget.getUUID() ) ) QApplication.processEvents() if self.__cancelRequest: raise Exception( "Cancel request" ) return files def __openedFiles( self, filterRe ): " Currently opened editor buffers " files = [] openedFiles = self.editorsManager.getTextEditors() for record in openedFiles: uuid = record[ 0 ] fname = record[ 1 ] if filterRe is None or filterRe.match( fname ): files.append( ItemToSearchIn( fname, uuid ) ) QApplication.processEvents() if self.__cancelRequest: raise Exception( "Cancel request" ) return files def __dirFiles( self, path, filterRe, files ): " Files recursively for the dir " for item in os.listdir( path ): QApplication.processEvents() if self.__cancelRequest: raise Exception( "Cancel request" ) if os.path.isdir( path + item ): if item in [ ".svn", ".cvs" ]: # It does not make sense to search in revision control dirs continue anotherDir, isLoop = resolveLink( path + item ) if not isLoop: self.__dirFiles( anotherDir + sep, filterRe, files ) continue if not os.path.isfile( path + item ): continue realItem, isLoop = resolveLink( path + item ) if isLoop: continue if filterRe is None or filterRe.match( realItem ): found = False for itm in files: if itm.fileName == realItem: found = True break if not found: mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetForFileName( realItem ) if widget is None: if isFileSearchable( realItem ): files.append( ItemToSearchIn( realItem, "" ) ) else: if widget.getType() in \ [ MainWindowTabWidgetBase.PlainTextEditor ]: files.append( ItemToSearchIn( realItem, widget.getUUID() ) ) return def __buildFilesList( self ): " Builds the list of files to search in " filtersText = self.filterCombo.currentText().strip() if filtersText != "": filterRe = re.compile( filtersText, re.IGNORECASE ) else: filterRe = None if self.projectRButton.isChecked(): return self.__projectFiles( filterRe ) if self.openFilesRButton.isChecked(): return self.__openedFiles( filterRe ) dirname = os.path.realpath( self.dirEditCombo.currentText().strip() ) files = [] self.__dirFiles( dirname + sep, filterRe, files ) return files def __process( self ): " Search process " # Add entries to the combo box if required regexpText = self.findCombo.currentText() if regexpText in self.findFilesWhat: self.findFilesWhat.remove( regexpText ) self.findFilesWhat.insert( 0, regexpText ) if len( self.findFilesWhat ) > 32: self.findFilesWhat = self.findFilesWhat[ : 32 ] self.findCombo.clear() self.findCombo.addItems( self.findFilesWhat ) filtersText = self.filterCombo.currentText().strip() if filtersText in self.findFilesMasks: self.findFilesMasks.remove( filtersText ) self.findFilesMasks.insert( 0, filtersText ) if len( self.findFilesMasks ) > 32: self.findFilesMasks = self.findFilesMasks[ : 32 ] self.filterCombo.clear() self.filterCombo.addItems( self.findFilesMasks ) if self.dirRButton.isChecked(): dirText = self.dirEditCombo.currentText().strip() if dirText in self.findFilesDirs: self.findFilesDirs.remove( dirText ) self.findFilesDirs.insert( 0, dirText ) if len( self.findFilesDirs ) > 32: self.findFilesDirs = self.findFilesDirs[ : 32 ] self.dirEditCombo.clear() self.dirEditCombo.addItems( self.findFilesDirs ) # Save the combo values for further usage if GlobalData().project.fileName != "": GlobalData().project.setFindInFilesHistory( self.findFilesWhat, self.findFilesDirs, self.findFilesMasks ) else: Settings().findFilesWhat = self.findFilesWhat Settings().findFilesDirs = self.findFilesDirs Settings().findFilesMasks = self.findFilesMasks self.__inProgress = True numberOfMatches = 0 self.searchResults = [] self.searchRegexp = None # Form the regexp to search if not self.regexpCheckBox.isChecked(): regexpText = re.escape( regexpText ) if self.wordCheckBox.isChecked(): regexpText = "\\b%s\\b" % regexpText flags = re.UNICODE | re.LOCALE if not self.caseCheckBox.isChecked(): flags |= re.IGNORECASE try: self.searchRegexp = re.compile( regexpText, flags ) except: logging.error( "Invalid search expression" ) self.close() return QApplication.setOverrideCursor( QCursor( Qt.WaitCursor ) ) self.fileLabel.setPath( 'Building list of files to search in...' ) QApplication.processEvents() try: files = self.__buildFilesList() except Exception, exc: if "Cancel request" in str( exc ): QApplication.restoreOverrideCursor() self.close() return else: QApplication.restoreOverrideCursor() logging.error( str( exc ) ) self.close() return QApplication.restoreOverrideCursor() QApplication.processEvents() if len( files ) == 0: self.fileLabel.setPath( 'No files to search in' ) return self.progressBar.setRange( 0, len( files ) ) index = 1 for item in files: if self.__cancelRequest: self.__inProgress = False self.close() return self.fileLabel.setPath( 'Matches: ' + str( numberOfMatches ) + \ ' Processing: ' + item.fileName ) item.search( self.searchRegexp ) found = len( item.matches ) if found > 0: numberOfMatches += found self.searchResults.append( item ) self.progressBar.setValue( index ) index += 1 QApplication.processEvents() if numberOfMatches == 0: if len( files ) == 1: self.fileLabel.setPath( "No matches in 1 file." ) else: self.fileLabel.setPath( "No matches in " + \ str( len( files ) ) + " files." ) self.__inProgress = False else: self.close() return
class Dialog(QDialog): def __init__(self, parent=None): super(Dialog, self).__init__(parent) self._filename = None self._page = None self._rect = None self.imageViewer = widgets.imageviewer.ImageViewer() self.dpiLabel = QLabel() self.dpiCombo = QComboBox(insertPolicy=QComboBox.NoInsert, editable=True) self.dpiCombo.lineEdit().setCompleter(None) self.dpiCombo.setValidator(QDoubleValidator(10.0, 1200.0, 4, self.dpiCombo)) self.dpiCombo.addItems([format(i) for i in (72, 100, 200, 300, 600, 1200)]) self.colorButton = widgets.colorbutton.ColorButton() self.colorButton.setColor(QColor(Qt.white)) self.crop = QCheckBox() self.antialias = QCheckBox(checked=True) self.dragfile = QPushButton(icons.get("image-x-generic"), None, None) self.fileDragger = FileDragger(self.dragfile) self.buttons = QDialogButtonBox(QDialogButtonBox.Close) self.copyButton = self.buttons.addButton('', QDialogButtonBox.ApplyRole) self.copyButton.setIcon(icons.get('edit-copy')) self.saveButton = self.buttons.addButton('', QDialogButtonBox.ApplyRole) self.saveButton.setIcon(icons.get('document-save')) layout = QVBoxLayout() self.setLayout(layout) layout.addWidget(self.imageViewer) controls = QHBoxLayout() layout.addLayout(controls) controls.addWidget(self.dpiLabel) controls.addWidget(self.dpiCombo) controls.addWidget(self.colorButton) controls.addWidget(self.crop) controls.addWidget(self.antialias) controls.addStretch() controls.addWidget(self.dragfile) layout.addWidget(widgets.Separator()) layout.addWidget(self.buttons) app.translateUI(self) self.readSettings() self.finished.connect(self.writeSettings) self.dpiCombo.editTextChanged.connect(self.drawImage) self.colorButton.colorChanged.connect(self.drawImage) self.antialias.toggled.connect(self.drawImage) self.crop.toggled.connect(self.cropImage) self.buttons.rejected.connect(self.reject) self.copyButton.clicked.connect(self.copyToClipboard) self.saveButton.clicked.connect(self.saveAs) qutil.saveDialogSize(self, "copy_image/dialog/size", QSize(480, 320)) def translateUI(self): self.setCaption() self.dpiLabel.setText(_("DPI:")) self.colorButton.setToolTip(_("Paper Color")) self.crop.setText(_("Auto-crop")) self.antialias.setText(_("Antialias")) self.dragfile.setText(_("Drag")) self.dragfile.setToolTip(_("Drag the image as a PNG file.")) self.copyButton.setText(_("&Copy to Clipboard")) self.saveButton.setText(_("&Save As...")) self.imageViewer.setWhatsThis(_( #xgettext:no-python-format "<p>\n" "Clicking toggles the display between 100% size and window size. " "Drag to copy the image to another application. " "Drag with Ctrl (or {command}) to scroll a large image.\n" "</p>\n" "<p>\n" "You can also drag the small picture icon in the bottom right, " "which drags the actual file on disk, e.g. to an e-mail message.\n" "</p>").format(command="\u2318")) def readSettings(self): s = QSettings() s.beginGroup('copy_image') self.dpiCombo.setEditText(s.value("dpi", "100", type(""))) self.colorButton.setColor(s.value("papercolor", QColor(Qt.white), QColor)) self.crop.setChecked(s.value("autocrop", False, bool)) self.antialias.setChecked(s.value("antialias", True, bool)) def writeSettings(self): s = QSettings() s.beginGroup('copy_image') s.setValue("dpi", self.dpiCombo.currentText()) s.setValue("papercolor", self.colorButton.color()) s.setValue("autocrop", self.crop.isChecked()) s.setValue("antialias", self.antialias.isChecked()) def setCaption(self): if self._filename: filename = os.path.basename(self._filename) else: filename = _("<unknown>") title = _("Image from {filename}").format(filename = filename) self.setWindowTitle(app.caption(title)) def setPage(self, page, rect): self._page = page self._rect = rect self._filename = documents.filename(page.document()) self.fileDragger.basename = os.path.splitext(os.path.basename(self._filename))[0] self.setCaption() self.drawImage() def drawImage(self): dpi = float(self.dpiCombo.currentText() or '100') dpi = max(dpi, self.dpiCombo.validator().bottom()) dpi = min(dpi, self.dpiCombo.validator().top()) options = qpopplerview.RenderOptions() options.setPaperColor(self.colorButton.color()) if self.antialias.isChecked(): if popplerqt4: options.setRenderHint( popplerqt4.Poppler.Document.Antialiasing | popplerqt4.Poppler.Document.TextAntialiasing) else: options.setRenderHint(0) self._image = self._page.image(self._rect, dpi, dpi, options) self.cropImage() def cropImage(self): image = self._image if self.crop.isChecked(): image = image.copy(autoCropRect(image)) self.imageViewer.setImage(image) self.fileDragger.setImage(image) def copyToClipboard(self): QApplication.clipboard().setImage(self.imageViewer.image()) def saveAs(self): if self._filename and not self.imageViewer.image().isNull(): filename = os.path.splitext(self._filename)[0] + ".png" else: filename = 'image.png' filename = QFileDialog.getSaveFileName(self, _("Save Image As"), filename) if filename: if not self.imageViewer.image().save(filename): QMessageBox.critical(self, _("Error"), _( "Could not save the image.")) else: self.fileDragger.currentFile = filename
class FindReplace(QWidget): """ Find replace widget bar """ NbReplaced = pyqtSignal(int) def __init__(self, parent=None): """ This class provides an graphical interface to find and replace text @param parent: @type parent: """ QWidget.__init__(self, parent) self.editor = None self.styleEdit = { False: "background-color:rgb(255, 175, 90);", True: "" } self.createButton() self.createWidgets() self.createConnections() def showEnhanced(self, textSelected=''): """ Show enhanced (focus and text selected) """ self.show() if len(textSelected): self.edit.setEditText(textSelected) self.edit.setFocus() self.edit.lineEdit().selectAll() def createButton(self): """ create qt buttons Buttons defined: * Previous * Next * Replace """ self.previousButton = QtHelper.createButton( self, text=self.tr("Find Previous"), triggered=self.findPrevious, icon=QIcon(":/find_previous.png")) self.nextButton = QtHelper.createButton(self, text=self.tr("Find Next"), triggered=self.findNext, icon=QIcon(":/find_next.png")) self.replaceButton = QtHelper.createButton(self, text=self.tr("Replace..."), triggered=self.replaceFind, icon=QIcon(":/replace.png")) def createWidgets(self): """ QtWidgets creation QHBoxLayout -------------------------------------------..... | QLabel: QLineEdit QButton QButton QCheckBox | -------------------------------------------..... ....-------------------------------------- QLabel: QLineEdit QButton QCheckBox | ....-------------------------------------- """ glayout = QGridLayout() self.edit = QLineEditMore(parent=self) self.edit.setEditable(1) self.edit.setMaxCount(10) self.edit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.edit.lineEdit().setPlaceholderText("Search text in your test?") self.edit.setMinimumWidth(200) self.replaceEdit = QComboBox(self) self.replaceEdit.setEditable(1) self.replaceEdit.setMaxCount(10) self.replaceEdit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.replaceEdit.lineEdit().setPlaceholderText( "Replace the text with?") self.replaceEdit.setMinimumWidth(200) self.caseCheck = QCheckBox(self.tr("Case Sensitive")) self.caseCheck.setChecked( QtHelper.str2bool(Settings.instance().readValue( key='Editor/find-case-sensitive'))) self.caseWordCheck = QCheckBox(self.tr("Whole word only")) self.caseWordCheck.setChecked( QtHelper.str2bool( Settings.instance().readValue(key='Editor/find-whole-word'))) self.allCheck = QCheckBox(self.tr("All occurences")) self.allCheck.setChecked( QtHelper.str2bool( Settings.instance().readValue(key='Editor/replace-all'))) self.caseRegexpCheck = QCheckBox(self.tr("Regular expression")) self.caseRegexpCheck.setChecked( QtHelper.str2bool( Settings.instance().readValue(key='Editor/find-regexp'))) self.caseWrapCheck = QCheckBox(self.tr("Wrap at the end")) self.caseWrapCheck.setChecked( QtHelper.str2bool( Settings.instance().readValue(key='Editor/find-wrap'))) glayout.addWidget(self.edit, 0, 1) glayout.addWidget(self.nextButton, 0, 3) glayout.addWidget(self.previousButton, 0, 2) glayout.addWidget(self.caseCheck, 2, 2) glayout.addWidget(self.caseWrapCheck, 2, 3) glayout.addWidget(self.caseWordCheck, 3, 2) glayout.addWidget(self.caseRegexpCheck, 3, 3) glayout.addWidget(self.replaceEdit, 1, 1) glayout.addWidget(self.replaceButton, 1, 2) glayout.addWidget(self.allCheck, 1, 3) self.previousButton.setDisabled(True) self.nextButton.setDisabled(True) self.setLayout(glayout) flags = Qt.WindowFlags() flags |= Qt.Window flags |= Qt.WindowTitleHint flags |= Qt.WindowCloseButtonHint flags |= Qt.MSWindowsFixedSizeDialogHint self.setWindowFlags(flags) self.setWindowIcon(QIcon(":/main.png")) self.setWindowTitle("Find And Replace") def createConnections(self): """ create qt connection """ self.edit.editTextChanged.connect(self.textHasChanged) self.edit.EnterPressed.connect(self.returnPressed) self.caseCheck.stateChanged.connect(self.find) def returnPressed(self): """ Return key pressed Find next in this case """ self.findNext() def setEditor(self, editor): """ Set the target to find the text @param editor: @type editor: """ self.editor = editor def textHasChanged(self, txt): """ Find text has changed """ text = self.edit.currentText() if len(text) > 0: self.previousButton.setEnabled(True) self.nextButton.setEnabled(True) self.find(changed=True, forward=True) else: self.previousButton.setDisabled(True) self.nextButton.setDisabled(True) def updateComboBox(self): """ Update combobox """ comboUpdated = False for i in range(self.edit.count()): if self.edit.itemText(i) == self.edit.currentText(): comboUpdated = True if not comboUpdated: self.edit.addItem(self.edit.currentText()) comboUpdated = False for i in range(self.replaceEdit.count()): if self.replaceEdit.itemText(i) == self.replaceEdit.currentText(): comboUpdated = True if not comboUpdated: self.replaceEdit.addItem(self.replaceEdit.currentText()) def clearText(self): """ Clear all QlineEdit """ self.edit.setStyleSheet("") self.edit.clearEditText() self.replaceEdit.clearEditText() def findPrevious(self): """ Find previous occurence """ # update combobox self.updateComboBox() # find previous self.find(changed=False, forward=False) def findNext(self, line=-1, index=-1): """ Find next occurence """ # update combobox self.updateComboBox() return self.find(changed=False, forward=True, line=line, index=index) def find(self, changed=True, forward=True, line=-1, index=-1): """ Call the find function @param changed: @type changed: boolean @param forward: @type forward: boolean """ text = self.edit.currentText() if len(text) == 0: self.edit.setStyleSheet("") return None else: found = self.editor.findText( text, changed, forward, case=self.caseCheck.isChecked(), words=self.caseWordCheck.isChecked(), regexp=self.caseRegexpCheck.isChecked(), wraps=self.caseWrapCheck.isChecked(), line=line, index=index) self.edit.setStyleSheet(self.styleEdit[found]) return found def replaceFind(self): """ Replace and find """ if (self.editor is None): return replaceText = self.replaceEdit.currentText() searchText = self.edit.currentText() if not self.caseCheck.isChecked(): searchText = searchText.lower() current = -1 nbReplaced = 0 # find the first occurence from the beginning of the doc or not if not self.allCheck.isChecked(): detected = self.findNext() else: detected = self.findNext(line=0, index=0) (line, _) = self.editor.getCursorPosition() while detected: previous = current selectedText = self.editor.selectedText() # normalize the text in lower case if the case sensitive is not activated if not self.caseCheck.isChecked(): selectedText = selectedText.lower() # replace the selection if self.editor.hasSelectedText() and selectedText == searchText: self.editor.replace(replaceText) nbReplaced += 1 # find the next occurence of the word detected = self.findNext() (current, _) = self.editor.getCursorPosition() # all doc readed ? break the loop if previous > current: break if current == line and previous != -1: break # just execute one replace if not self.allCheck.isChecked(): break self.allCheck.setCheckState(Qt.Unchecked) self.NbReplaced.emit(nbReplaced)
class GearEntriesFrame(QFrame): read_block = pyqtSignal(int, int) # start_addr, num_bytes poke_block = pyqtSignal(int, QByteArray, bool) # start_addr, raw_bytes, is_ascii log = pyqtSignal(str, str) # msg, color MISSING_SKILL_NAME = '[NOT IN DB]' def __init__(self, addr_start, addr_end, class_label, skill2id, id2skill, parent=None): super(GearEntriesFrame, self).__init__(parent) self.code_offset = 0 self.addr_start = addr_start self.addr_end = addr_end self.max_num_slots = (addr_end - addr_start) / 6 / 4 + 1 self.class_label = class_label self.skill2id = skill2id self.id2skill = id2skill self.skill_names = self.skill2id.keys() self.skill_names.sort() self.slots_cache = [] # list of raw 6*4 bytes self.slots_txt = None self.cur_slot_idx = -1 self.cur_slot_bytes = None self.lbl_label = QLabel(self.class_label, self) self.btn_read_slots = QPushButton(' Cache Slots', self) self.btn_read_slots.setIcon(QIcon('img/flaticon/data110.png')) self.btn_read_slots.setStyleSheet('background-color: white') self.btn_read_slots.clicked.connect(self.onReadSlots) self.cmb_slots = QComboBox(self) self.cmb_slots.setStyleSheet('background-color: white') self.cmb_slots.currentIndexChanged[str].connect(self.onChangeSlot) self.cmb_slots.setDisabled(True) self.btn_read = QPushButton(self) self.btn_read.setIcon(QIcon('img/flaticon/open135.png')) self.btn_read.setToolTip('Read item slot value from memory') self.btn_read.setStyleSheet('background-color: white') self.btn_read.clicked.connect(self.onReadSlot) self.txt_raw = QLineEdit(self) self.txt_raw.setPlaceholderText('Raw hex data') self.txt_raw.setMaxLength(8 * 6 + 5) self.txt_raw.editingFinished.connect(self.onChangeRaw) self.btn_poke = QPushButton(self) self.btn_poke.setIcon(QIcon('img/flaticon/draw39.png')) self.btn_poke.setToolTip('Poke new value for item slot') self.btn_poke.setStyleSheet('background-color: white') self.btn_poke.clicked.connect(self.onPokeSlot) self.cmb_skills_a = QComboBox(self) self.cmb_skills_a.setEditable(True) self.cmb_skills_a.addItems(self.skill_names) self.cmb_skills_a.lineEdit().setText( GearEntriesFrame.MISSING_SKILL_NAME) self.cmb_skills_a.currentIndexChanged[str].connect(self.onChangeSkillA) self.cmb_skills_b = QComboBox(self) self.cmb_skills_b.setEditable(True) self.cmb_skills_b.addItems(self.skill_names) self.cmb_skills_b.lineEdit().setText( GearEntriesFrame.MISSING_SKILL_NAME) self.cmb_skills_b.currentIndexChanged[str].connect(self.onChangeSkillB) self.cmb_skills_c = QComboBox(self) self.cmb_skills_c.setEditable(True) self.cmb_skills_c.addItems(self.skill_names) self.cmb_skills_c.lineEdit().setText( GearEntriesFrame.MISSING_SKILL_NAME) self.cmb_skills_c.currentIndexChanged[str].connect(self.onChangeSkillC) incr_labels = [] for incr in xrange(16): incr_labels.append('+%d' % incr) self.cmb_incr_a = QComboBox(self) self.cmb_incr_a.addItems(incr_labels) self.cmb_incr_a.currentIndexChanged[int].connect(self.onChangeIncrA) self.cmb_incr_b = QComboBox(self) self.cmb_incr_b.addItems(incr_labels) self.cmb_incr_b.currentIndexChanged[int].connect(self.onChangeIncrB) self.cmb_incr_c = QComboBox(self) self.cmb_incr_c.addItems(incr_labels) self.cmb_incr_c.currentIndexChanged[int].connect(self.onChangeIncrC) slot_labels = [] for incr in xrange(4): slot_labels.append('%d Augment Slots' % incr) self.cmb_augments = QComboBox(self) self.cmb_augments.addItems(slot_labels) self.cmb_augments.currentIndexChanged[int].connect( self.onChangeAugments) self.layout = QGridLayout(self) self.layout.addWidget(self.lbl_label, 0, 0) self.layout.addWidget(self.btn_read_slots, 0, 1) self.layout.addWidget(self.cmb_slots, 0, 2) self.layout.addWidget(self.btn_read, 0, 3) self.layout.addWidget(self.txt_raw, 1, 0, 1, 3) self.layout.addWidget(self.btn_poke, 1, 3) self.layout.addWidget(self.cmb_skills_a, 2, 0) self.layout.addWidget(self.cmb_incr_a, 2, 1) self.layout.addWidget(self.cmb_skills_b, 3, 0) self.layout.addWidget(self.cmb_incr_b, 3, 1) self.layout.addWidget(self.cmb_skills_c, 4, 0) self.layout.addWidget(self.cmb_incr_c, 4, 1) self.layout.addWidget(self.cmb_augments, 2, 2) self.layout.setColumnStretch(0, 7) self.layout.setColumnStretch(1, 3) self.layout.setColumnStretch(2, 3) self.layout.setColumnStretch(3, 1) self.layout.setContentsMargins(0, 2, 0, 2) icon_height = self.lbl_label.height() * 8 / 15 icon_size = QSize(icon_height, icon_height) self.btn_read_slots.setIconSize(icon_size) self.btn_read.setIconSize(icon_size) self.btn_poke.setIconSize(icon_size) btn_size = QSize(icon_height * 1.5, icon_height * 1.5) self.btn_read.setFixedSize(btn_size) self.btn_poke.setFixedSize(btn_size) self.updateUI() def updateUI(self): # Disable editing if cache missing if not (0 <= self.cur_slot_idx < len( self.slots_cache)) or self.cur_slot_bytes is None: self.cur_slot_idx = -1 self.cur_slot_bytes = None self.cmb_slots.setDisabled(True) self.cmb_skills_a.setDisabled(True) self.cmb_skills_b.setDisabled(True) self.cmb_skills_c.setDisabled(True) self.cmb_incr_a.setDisabled(True) self.cmb_incr_b.setDisabled(True) self.cmb_incr_c.setDisabled(True) self.cmb_augments.setDisabled(True) self.txt_raw.setDisabled(True) return else: self.cmb_slots.setDisabled(False) self.cmb_skills_a.setDisabled(False) self.cmb_skills_b.setDisabled(False) self.cmb_skills_c.setDisabled(False) self.cmb_incr_a.setDisabled(False) self.cmb_incr_b.setDisabled(False) self.cmb_incr_c.setDisabled(False) self.cmb_augments.setDisabled(False) self.txt_raw.setDisabled(False) # Validate current slot's raw bytes try: (gear_id_bytes, index, post_index, skill_a_id, skill_a_incr, skill_b_id, skill_b_incr, skill_c_id, skill_c_incr, augment_a_id, augment_b_id, augment_c_id) = parse_gear_bytes(self.cur_slot_bytes) cur_slot_words = struct.unpack('>IIIIII', self.cur_slot_bytes) num_augments = (augment_a_id != 0xFFFF) + ( augment_b_id != 0xFFFF) + (augment_c_id != 0xFFFF) except ValueError, e: self.log.emit('Gear parsing failed: %s' % e.what(), 'red') return # Update UI self.txt_raw.setDisabled(False) self.txt_raw.editingFinished.disconnect() self.txt_raw.setText('%08X %08X %08X %08X %08X %08X' % cur_slot_words) self.txt_raw.editingFinished.connect(self.onChangeRaw) self.cmb_skills_a.setDisabled(False) self.cmb_skills_a.currentIndexChanged[str].disconnect() try: skill_name = self.id2skill[skill_a_id] skill_idx = self.skill_names.index(skill_name) self.cmb_skills_a.setCurrentIndex(skill_idx) except (KeyError, ValueError): self.cmb_skills_a.lineEdit().setText( GearEntriesFrame.MISSING_SKILL_NAME) self.cmb_skills_a.currentIndexChanged[str].connect(self.onChangeSkillA) self.cmb_skills_b.setDisabled(False) self.cmb_skills_b.currentIndexChanged[str].disconnect() try: skill_name = self.id2skill[skill_b_id] skill_idx = self.skill_names.index(skill_name) self.cmb_skills_b.setCurrentIndex(skill_idx) except (KeyError, ValueError): self.cmb_skills_b.lineEdit().setText( GearEntriesFrame.MISSING_SKILL_NAME) self.cmb_skills_b.currentIndexChanged[str].connect(self.onChangeSkillB) self.cmb_skills_c.setDisabled(False) self.cmb_skills_c.currentIndexChanged[str].disconnect() try: skill_name = self.id2skill[skill_c_id] skill_idx = self.skill_names.index(skill_name) self.cmb_skills_c.setCurrentIndex(skill_idx) except (KeyError, ValueError): self.cmb_skills_c.lineEdit().setText( GearEntriesFrame.MISSING_SKILL_NAME) self.cmb_skills_c.currentIndexChanged[str].connect(self.onChangeSkillC) self.cmb_incr_a.setDisabled(False) self.cmb_incr_a.currentIndexChanged[int].disconnect() self.cmb_incr_a.setCurrentIndex(skill_a_incr) self.cmb_incr_a.currentIndexChanged[int].connect(self.onChangeIncrA) self.cmb_incr_b.setDisabled(False) self.cmb_incr_b.currentIndexChanged[int].disconnect() self.cmb_incr_b.setCurrentIndex(skill_b_incr) self.cmb_incr_b.currentIndexChanged[int].connect(self.onChangeIncrB) self.cmb_incr_c.setDisabled(False) self.cmb_incr_c.currentIndexChanged[int].disconnect() self.cmb_incr_c.setCurrentIndex(skill_c_incr) self.cmb_incr_c.currentIndexChanged[int].connect(self.onChangeIncrC) self.cmb_augments.setDisabled(False) self.cmb_augments.currentIndexChanged[int].disconnect() self.cmb_augments.setCurrentIndex(num_augments) self.cmb_augments.currentIndexChanged[int].connect( self.onChangeAugments)
class Printing(preferences.Group): def __init__(self, page): super(Printing, self).__init__(page) layout = QGridLayout(spacing=1) self.setLayout(layout) self.messageLabel = QLabel(wordWrap=True) self.printCommandLabel = QLabel() self.printCommand = widgets.urlrequester.UrlRequester() self.printCommand.setFileMode(QFileDialog.ExistingFile) self.printCommand.changed.connect(page.changed) self.printDialogCheck = QCheckBox(toggled=page.changed) self.resolutionLabel = QLabel() self.resolution = QComboBox(editable=True, editTextChanged=page.changed) self.resolution.addItems("300 600 1200".split()) self.resolution.lineEdit().setInputMask("9000") layout.addWidget(self.messageLabel, 0, 0, 1, 2) layout.addWidget(self.printCommandLabel, 1, 0) layout.addWidget(self.printCommand, 1, 1) layout.addWidget(self.printDialogCheck, 2, 0, 1, 2) layout.addWidget(self.resolutionLabel, 3, 0) layout.addWidget(self.resolution, 3, 1) app.translateUI(self) def translateUI(self): self.setTitle(_("Printing Music")) self.messageLabel.setText( _("Here you can enter a command to print a PDF or PostScript file. " "See the Help page for more information about printing music.")) self.printCommandLabel.setText(_("Printing command:")) self.printCommand.setToolTip('<qt>' + _( "The printing command is used to print a PostScript or PDF file. " "On Linux you don't need this, but on Windows and Mac OS X you can " "provide a command to avoid that PDF documents are being printed " "using raster images, which is less optimal.\n" "<code>$pdf</code> gets replaced with the PDF filename, or alternatively, " "<code>$ps</code> is replaced with the PostScript filename. " "<code>$printer</code> is replaced with the printer's name to use." )) self.printDialogCheck.setText(_("Use Frescobaldi's print dialog")) self.printDialogCheck.setToolTip('<qt>' + _( "If enabled, Frescobaldi will show the print dialog and create a " "PDF or PostScript document containing only the selected pages " "to print. Otherwise, the command is called directly and is expected " "to show a print dialog itself.")) self.resolutionLabel.setText(_("Resolution:")) self.resolution.setToolTip( _("Set the resolution if Frescobaldi prints using raster images.")) def loadSettings(self): s = QSettings() s.beginGroup("helper_applications") self.printCommand.setPath(s.value("printcommand", "", type(""))) self.printDialogCheck.setChecked( s.value("printcommand/dialog", False, bool)) with qutil.signalsBlocked(self.resolution): self.resolution.setEditText( format(s.value("printcommand/dpi", 300, int))) def saveSettings(self): s = QSettings() s.beginGroup("helper_applications") s.setValue("printcommand", self.printCommand.path()) s.setValue("printcommand/dialog", self.printDialogCheck.isChecked()) s.setValue("printcommand/dpi", int(self.resolution.currentText()))
class Widget(QWidget): def __init__(self, dockwidget): super(Widget, self).__init__(dockwidget) self._document = None self._fileSelector = QComboBox(editable=True, insertPolicy=QComboBox.NoInsert) widgets.drag.ComboDrag(self._fileSelector).role = Qt.UserRole self._fileSelector.lineEdit().setReadOnly(True) self._fileSelector.lineEdit().setFocusPolicy(Qt.NoFocus) self._stopButton = QToolButton() self._playButton = QToolButton() self._timeSlider = QSlider(Qt.Horizontal, tracking=False, singleStep=500, pageStep=5000, invertedControls=True) self._display = Display() self._tempoFactor = QSlider(Qt.Vertical, minimum=-50, maximum=50, singleStep=1, pageStep=5) grid = QGridLayout(spacing=0) self.setLayout(grid) grid.addWidget(self._fileSelector, 0, 0, 1, 3) grid.addWidget(self._stopButton, 1, 0) grid.addWidget(self._playButton, 1, 1) grid.addWidget(self._timeSlider, 1, 2) grid.addWidget(self._display, 2, 0, 1, 3) grid.addWidget(self._tempoFactor, 0, 3, 3, 1) # size policy of combo p = self._fileSelector.sizePolicy() p.setHorizontalPolicy(QSizePolicy.Ignored) self._fileSelector.setSizePolicy(p) # size policy of combo popup p = self._fileSelector.view().sizePolicy() p.setHorizontalPolicy(QSizePolicy.MinimumExpanding) self._fileSelector.view().setSizePolicy(p) self._player = player.Player() self._outputCloseTimer = QTimer(interval=60000, singleShot=True, timeout=self.closeOutput) self._timeSliderTicker = QTimer(interval=200, timeout=self.updateTimeSlider) self._fileSelector.activated[int].connect(self.slotFileSelected) self._tempoFactor.valueChanged.connect(self.slotTempoChanged) self._timeSlider.valueChanged.connect(self.slotTimeSliderChanged) self._timeSlider.sliderMoved.connect(self.slotTimeSliderMoved) self._player.beat.connect(self.updateDisplayBeat) self._player.time.connect(self.updateDisplayTime) self._player.stateChanged.connect(self.slotPlayerStateChanged) self.slotPlayerStateChanged(False) dockwidget.mainwindow().currentDocumentChanged.connect(self.loadResults) app.documentLoaded.connect(self.slotUpdatedFiles) app.jobFinished.connect(self.slotUpdatedFiles) app.aboutToQuit.connect(self.stop) midihub.aboutToRestart.connect(self.slotAboutToRestart) midihub.settingsChanged.connect(self.clearMidiSettings, -100) midihub.settingsChanged.connect(self.readMidiSettings) app.documentClosed.connect(self.slotDocumentClosed) app.translateUI(self) self.readMidiSettings() d = dockwidget.mainwindow().currentDocument() if d: self.loadResults(d) def translateUI(self): self._tempoFactor.setToolTip(_("Tempo")) def slotAboutToRestart(self): self.stop() self._player.set_output(None) def clearMidiSettings(self): """Called first when settings are changed.""" self.stop() self._outputCloseTimer.stop() self._player.set_output(None) def readMidiSettings(self): """Called after clearMidiSettings(), and on first init.""" pass def openOutput(self): """Called when playing starts. Ensures an output port is opened.""" self._outputCloseTimer.stop() if not self._player.output(): p = QSettings().value("midi/player/output_port", midihub.default_output(), type("")) o = midihub.output_by_name(p) if o: self._player.set_output(output.Output(o)) def closeOutput(self): """Called when the output close timer fires. Closes the output.""" self._player.set_output(None) def slotPlayerStateChanged(self, playing): ac = self.parentWidget().actionCollection # setDefaultAction also adds the action for b in self._stopButton, self._playButton: while b.actions(): b.removeAction(b.actions()[0]) if playing: self._timeSliderTicker.start() self._stopButton.setDefaultAction(ac.midi_stop) self._playButton.setDefaultAction(ac.midi_pause) else: self._timeSliderTicker.stop() self.updateTimeSlider() self._stopButton.setDefaultAction(ac.midi_restart) self._playButton.setDefaultAction(ac.midi_play) # close the output if the preference is set if QSettings().value("midi/close_outputs", False, bool): self._outputCloseTimer.start() def play(self): """Starts the MIDI player, opening an output if necessary.""" if not self._player.is_playing() and not self._player.has_events(): self.restart() self.openOutput() if not self._player.output(): self._display.statusMessage(_("No output found!")) self._player.start() def stop(self): """Stops the MIDI player.""" self._player.stop() def restart(self): """Restarts the MIDI player. If another file is in the file selector, or the file was updated, the new file is loaded. """ self._player.seek(0) self.updateTimeSlider() self._display.reset() if self._document: files = midifiles.MidiFiles.instance(self._document) index = self._fileSelector.currentIndex() if files and (files.song(index) is not self._player.song()): self.loadSong(index) def slotTempoChanged(self, value): """Called when the user drags the tempo.""" # convert -50 to 50 to 0.5 to 2.0 factor = 2 ** (value / 50.0) self._player.set_tempo_factor(factor) self._display.setTempo("{0}%".format(int(factor * 100))) def slotTimeSliderChanged(self, value): self._player.seek(value) self._display.setTime(value) if self._player.song(): self._display.setBeat(*self._player.song().beat(value)[1:]) def slotTimeSliderMoved(self, value): self._display.setTime(value) if self._player.song(): self._display.setBeat(*self._player.song().beat(value)[1:]) def updateTimeSlider(self): if not self._timeSlider.isSliderDown(): with qutil.signalsBlocked(self._timeSlider): self._timeSlider.setMaximum(self._player.total_time()) self._timeSlider.setValue(self._player.current_time()) def updateDisplayBeat(self, measnum, beat, num, den): if not self._timeSlider.isSliderDown(): self._display.setBeat(measnum, beat, num, den) def updateDisplayTime(self, time): if not self._timeSlider.isSliderDown(): self._display.setTime(time) def slotUpdatedFiles(self, document): """Called when there are new MIDI files.""" if document == self.parentWidget().mainwindow().currentDocument(): self.loadResults(document) def loadResults(self, document): self._document = document files = midifiles.MidiFiles.instance(document) self._fileSelector.setModel(files.model()) if files: self._fileSelector.setCurrentIndex(files.current) if not self._player.is_playing(): self.loadSong(files.current) def loadSong(self, index): files = midifiles.MidiFiles.instance(self._document) self._player.set_song(files.song(index)) m, s = divmod(self._player.total_time() // 1000, 60) name = self._fileSelector.currentText() self.updateTimeSlider() self._display.reset() self._display.statusMessage( _("midi lcd screen", "LOADED"), name, _("midi lcd screen", "TOTAL"), "{0}:{1:02}".format(m, s)) def slotFileSelected(self, index): if self._document: self._player.stop() files = midifiles.MidiFiles.instance(self._document) if files: files.current = index self.restart() def slotDocumentClosed(self, document): if document == self._document: self._document = None self._fileSelector.clear() self._player.stop() self._player.clear() self.updateTimeSlider() self._display.reset()
class LDSControls(QFrame): STATIC_IMG = ('error_static.png','linz_static.png','busy_static.png','clean_static.png') ANIM_IMG = ('error.gif','linz.gif','layer.gif','clean.gif') IMG_SPEED = 100 IMG_WIDTH = 64 IMG_HEIGHT = 64 MAX_WD = 450 GD_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../../bin/gdal/gdal-data')) STATUS = LU.enum('ERROR','IDLE','BUSY','CLEAN') def __init__(self,parent): super(LDSControls, self).__init__() self.parent = parent self.initConf() self.initEPSG() self.initUI() def initConf(self): '''Read files in conf dir ending in conf''' self.cflist = ConfigInitialiser.getConfFiles() #self.imgset = self.STATIC_IMG if ConfigWrapper().readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG #self.imgset = self.STATIC_IMG if self.parent.confconn.tp.src.confwrap.readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG sep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.SRCNAME,self.parent.confconn.uconf) self.imgset = self.STATIC_IMG if sep.confwrap.readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG self.parent.confconn.reg.closeEndPoint(self.parent.confconn.SRCNAME) def initEPSG(self): '''Read GDAL EPSG files, splitting by NZ(RSR) and RestOfTheWorld''' gcsf = gdal.FindFile('gdal','gcs.csv') if not gcsf: gcsf = os.path.join(self.GD_PATH,'gcs.csv') pcsf = gdal.FindFile('gdal','pcs.csv') if not pcsf: pcsf = os.path.join(self.GD_PATH,'pcs.csv') gcs = ConfigInitialiser.readCSV(gcsf) pcs = ConfigInitialiser.readCSV(pcsf) self.nzlsr = [(e[0],e[0]+' - '+e[3]) for e in gcs if 'NZGD' in e[1] or 'RSRGD' in e[1]] \ + [(e[0],e[0]+' - '+e[1]) for e in pcs if 'NZGD' in e[1] or 'RSRGD' in e[1]] self.rowsr = [(e[0],e[0]+' - '+e[3]) for e in gcs if 'NZGD' not in e[1] and 'RSRGD' not in e[1]] \ + [(e[0],e[0]+' - '+e[1]) for e in pcs if 'NZGD' not in e[1] and 'RSRGD' not in e[1]] def initUI(self): # 0 1 2 3 4 5 6 7 8 #'destname','lgselect','layer','uconf','group','epsg','fd','td','int' #self.rdest,rlgselect,self.rlayer,ruconf,self.rgroup,repsg,rfd,rtd,rint = readlist QToolTip.setFont(QFont('SansSerif', 10)) #labels destLabel = QLabel('Destination') lgLabel = QLabel('Group/Layer') epsgLabel = QLabel('EPSG') fromDateLabel = QLabel('From Date') toDateLabel = QLabel('To Date') confLabel = QLabel('User Config') self.view = QLabel() self.view.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.view.setAlignment(Qt.AlignCenter) self.confcombo = QComboBox(self) self.confcombo.setToolTip('Enter your user config name (file) here') self.confcombo.addItems(self.cflist) self.confcombo.setEditable(False) #self.confcombo.currentIndexChanged.connect(self.doLGEditUpdate) #combos self.lgcombo = QComboBox(self) self.lgcombo.setMaximumWidth(self.MAX_WD) self.lgcombo.setDuplicatesEnabled(False) #self.lgcombo.setInsertPolicy(QComboBox.InsertAlphabetically)#?doesnt seem to work self.lgcombo.setToolTip('Select either Layer or Group entry') self.lgcombo.setEditable(False) self.sepindex = None #self.updateLGValues() self.epsgcombo = QComboBox(self) self.epsgcombo.setMaximumWidth(self.MAX_WD) self.epsgcombo.setToolTip('Setting an EPSG number here determines the output SR of the layer') self.epsgcombo.addItems([i[1] for i in self.nzlsr]) self.epsgcombo.insertSeparator(len(self.nzlsr)) self.epsgcombo.addItems([i[1] for i in self.rowsr]) self.epsgcombo.setEditable(True) self.epsgcombo.setEnabled(False) self.destlist = self.getConfiguredDestinations() self.destcombo = QComboBox(self) self.destcombo.setToolTip('Choose the desired output type') self.destcombo.setEditable(False) self.destcombo.addItems(self.destlist) #date selection self.fromdateedit = QDateEdit() self.fromdateedit.setCalendarPopup(True) self.fromdateedit.setEnabled(False) self.todateedit = QDateEdit() self.todateedit.setCalendarPopup(True) self.todateedit.setEnabled(False) #check boxes self.epsgenable = QCheckBox() self.epsgenable.setCheckState(False) self.epsgenable.clicked.connect(self.doEPSGEnable) self.fromdateenable = QCheckBox() self.fromdateenable.setCheckState(False) self.fromdateenable.clicked.connect(self.doFromDateEnable) self.todateenable = QCheckBox() self.todateenable.setCheckState(False) self.todateenable.clicked.connect(self.doToDateEnable) self.progressbar = QProgressBar() self.progressbar.setRange(0,100) self.progressbar.setVisible(True) self.progressbar.setMinimumWidth(self.MAX_WD) #buttons self.initbutton = QPushButton("waiting") self.initbutton.setToolTip('Initialise the Layer Configuration') self.initbutton.clicked.connect(self.doInitClickAction) self.cleanbutton = QPushButton("Clean") self.cleanbutton.setToolTip('Clean the selected layer/group from local storage') self.cleanbutton.clicked.connect(self.doCleanClickAction) self.replicatebutton = QPushButton("Replicate") self.replicatebutton.setToolTip('Execute selected replication') self.replicatebutton.clicked.connect(self.doReplicateClickAction) self.cancelbutton = QPushButton("Close") self.cancelbutton.setToolTip('Close the LDS Replicate application') self.cancelbutton.clicked.connect(self.parent.close) #set dialog values using GPR self.updateGUIValues(self.parent.gvs) #set onchange here otherwise we get circular initialisation self.destcombo.currentIndexChanged.connect(self.doDestChanged) self.confcombo.currentIndexChanged.connect(self.doConfChanged) self.lgcombo.currentIndexChanged.connect(self.doLGComboChanged) self.setStatus(self.STATUS.IDLE) #grid grid = QGridLayout() grid.setSpacing(10) #placement section ------------------------------------ #---------+---------+--------+---------+-------- # dest LB | | dest DD # grp LB | | grp DD # conf LB | | conf DD # epsg L | epsg CB | epsg DD # f dt L | f dt CB | f dt DD # t td L | t td CB | t td DD # icon | <- progress -> # layer B | <- . -> |repl B | clean B | close B #---------+---------+--------+---------+-------- grid.addWidget(destLabel, 1, 0) grid.addWidget(self.destcombo, 1, 2) #grid.addWidget(layerLabel, 2, 0) grid.addWidget(lgLabel, 2, 0) grid.addWidget(self.lgcombo, 2, 2) grid.addWidget(confLabel, 3, 0) grid.addWidget(self.confcombo, 3, 2) #grid.addWidget(groupLabel, 4, 0) #grid.addWidget(self.groupEdit, 4, 2) grid.addWidget(epsgLabel, 5, 0) grid.addWidget(self.epsgenable, 5, 1) grid.addWidget(self.epsgcombo, 5, 2) grid.addWidget(fromDateLabel, 6, 0) grid.addWidget(self.fromdateenable, 6, 1) grid.addWidget(self.fromdateedit, 6, 2) grid.addWidget(toDateLabel, 7, 0) grid.addWidget(self.todateenable, 7, 1) grid.addWidget(self.todateedit, 7, 2) hbox3 = QHBoxLayout() hbox3.addWidget(self.view) hbox3.addStretch(1) hbox3.addWidget(self.progressbar) #hbox3.addLayout(vbox2) #hbox3.addLayout(vbox3) hbox4 = QHBoxLayout() hbox4.addWidget(self.initbutton) hbox4.addStretch(1) hbox4.addWidget(self.replicatebutton) hbox4.addWidget(self.cleanbutton) hbox4.addWidget(self.cancelbutton) vbox = QVBoxLayout() #vbox.addStretch(1) vbox.addLayout(grid) vbox.addLayout(hbox3) vbox.addLayout(hbox4) self.setLayout(vbox) #def setProgress(self,pct): # self.progressbar.setValue(pct) def setStatus(self,status,message='',tooltip=None): '''Sets indicator icon and statusbar message''' self.parent.statusbar.showMessage(message) self.parent.statusbar.setToolTip(tooltip if tooltip else '') #progress loc = os.path.abspath(os.path.join(IMG_LOC,self.imgset[status])) #loc = os.path.abspath(os.path.join(os.path.dirname(__file__),self.parent.IMG_LOC,self.imgset[status])) self.progressbar.setVisible(status in (self.STATUS.BUSY, self.STATUS.CLEAN)) #icon anim = QMovie(loc, QByteArray(), self) anim.setScaledSize(QSize(self.IMG_WIDTH,self.IMG_HEIGHT)) anim.setCacheMode(QMovie.CacheAll) anim.setSpeed(self.IMG_SPEED) self.view.clear() self.view.setMovie(anim) anim.start() self.view.repaint() QApplication.processEvents(QEventLoop.AllEvents) def mainWindowEnable(self,enable=True): cons = (self.lgcombo, self.confcombo, self.destcombo, self.initbutton, self.replicatebutton, self.cleanbutton, self.cancelbutton, self.epsgenable,self.fromdateenable,self.todateenable, self.parent.menubar) for c in cons: c.setEnabled(enable) if enable: self.epsgcombo.setEnabled(self.epsgenable.checkState()) self.fromdateedit.setEnabled(self.fromdateenable.checkState()) self.todateedit.setEnabled(self.todateenable.checkState()) else: self.epsgcombo.setEnabled(False) self.fromdateedit.setEnabled(False) self.todateedit.setEnabled(False) QApplication.restoreOverrideCursor() if enable else QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) def refreshLGCombo(self): '''Re index LG combobox since a refreshLG call (new dest?) will usually mean new groups''' self.lgcombo.clear() self.lgcombo.addItems([i[2] for i in self.parent.confconn.lglist]) #NOTE the separator consumes an index, if not clearing the combobox selectively remove the old sepindex (assumes g preceeds l) #if self.sepindex: # self.lgcombo.removeItem(self.sepindex) self.sepindex = [i[0] for i in self.parent.confconn.lglist].count(LORG.GROUP) self.lgcombo.insertSeparator(self.sepindex) def updateLGValues(self,uconf,lgval,dest): '''Sets the values displayed in the Layer/Group combo''' #because we cant seem to sort combobox entries and want groups at the top, clear and re-add #TRACE# #pdb.set_trace() sf = None try: self.parent.confconn.initConnections(uconf,lgval,dest) except Exception as e: sf=1 ldslog.error('Error Updating UC Values. '+str(e)) if sf: self.setStatus(self.STATUS.ERROR,'Error Updating UC Values', str(e)) else: self.setStatus(self.STATUS.IDLE) self.refreshLGCombo() def centre(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def gprParameters(self,rdest): '''Zip default and GPR values''' return [x if LU.assessNone(x) else y for x,y in zip(self.parent.gpr.readsec(rdest),self.parent.DEF_RVALS[1:])] def getLCE(self,ln): '''Read layer parameters''' dep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.destname,self.parent.confconn.uconf) #sep = self.parent.confconn.reg.openEndPoint('WFS',self.parent.confconn.uconf) self.parent.confconn.reg.setupLayerConfig(self.parent.confconn.tp,None,dep,initlc=False) lce = dep.getLayerConf().readLayerParameters(ln) #self.parent.confconn.reg.closeEndPoint('WFS') self.parent.confconn.reg.closeEndPoint(self.parent.confconn.destname) sep,dep = None,None return lce def doDestChanged(self): '''Read the destname parameter and fill dialog with matching GPR values''' rdest = str(self.destlist[self.destcombo.currentIndex()]) rvals = self.gprParameters(rdest) self.updateGUIValues([rdest]+rvals) def doConfChanged(self): '''Read the user conf parameter and fill dialog with matching GPR values''' rdest = str(self.destlist[self.destcombo.currentIndex()]) rlg,_,rep,rfd,rtd = self.gprParameters(rdest) ruc = str(self.cflist[self.confcombo.currentIndex()]) self.updateGUIValues((rdest,rlg,ruc,rep,rfd,rtd)) def doLGComboChanged(self): '''Read the layer/group value and change epsg to layer or gpr match''' #get a matching LG entry and test whether its a layer or group #lgi = self.parent.confconn.getLayerGroupIndex(self.lgcombo.currentText().toUtf8().data()) lgi = self.parent.confconn.getLayerGroupIndex(LQ.readWidgetText(self.lgcombo.currentText())) #lgi can be none if we init a new group, in which case we use the GPR value if lgi: lge = self.parent.confconn.lglist[lgi] lce = self.getLCE(lge[1]) if lge[0]==LORG.LAYER else None else: lce = None #look for filled layer conf epsg OR use prefs stored in gpr if lce and LU.assessNone(lce.epsg): epsgval = lce.epsg else: rdest = str(self.destlist[self.destcombo.currentIndex()]) _,_,epsgval,_,_ = self.gprParameters(rdest) epsgindex = [i[0] for i in self.nzlsr+[(0,0)]+self.rowsr].index(epsgval) if self.epsgcombo.currentIndex() != epsgindex: self.epsgcombo.setCurrentIndex(int(epsgindex)) def updateGUIValues(self,readlist): '''Fill dialog values from provided list''' #TODO. Remove circular references when setCurrentIndex() triggers do###Changed() #Read user input rdest,self.rlgval,ruconf,repsg,rfd,rtd = readlist #-------------------------------------------------------------------- #Destination Menu selecteddest = LU.standardiseDriverNames(rdest) if selecteddest not in self.destlist: self.destlist = self.getConfiguredDestinations() self.destcombo.addItem(selecteddest) destindex = self.destlist.index(selecteddest) if selecteddest else 0 if self.destcombo.currentIndex() != destindex: self.destcombo.setCurrentIndex(destindex) #InitButton self.initbutton.setText('Layer Select') #Config File confindex = 0 if LU.assessNone(ruconf): ruconf = ruconf.split('.')[0] if ruconf not in self.cflist: self.cflist += [ruconf,] self.confcombo.addItem(ruconf) confindex = self.cflist.index(ruconf) if self.confcombo.currentIndex() != confindex: self.confcombo.setCurrentIndex(confindex) #self.confEdit.setText(ruconf if LU.assessNone(ruconf) else '') #Layer/Group Selection self.updateLGValues(ruconf,self.rlgval,rdest) lgindex = None if LU.assessNone(self.rlgval): #index of list value lgindex = self.parent.confconn.getLayerGroupIndex(self.rlgval,col=1) if LU.assessNone(lgindex): #advance by 1 for sep lgindex += 1 if lgindex>self.sepindex else 0 else: #using the separator index sets the combo to blank lgindex = self.sepindex if self.lgcombo.currentIndex() != lgindex: self.lgcombo.setCurrentIndex(lgindex) #self.doLGEditUpdate() #EPSG # user > layerconf #useepsg = LU.precedence(repsg, lce.epsg if lce else None, None) epsgindex = [i[0] for i in self.nzlsr+[(None,None)]+self.rowsr].index(repsg) if self.epsgcombo.currentIndex() != epsgindex: self.epsgcombo.setCurrentIndex(epsgindex) #epsgedit = self.epsgcombo.lineEdit() #epsgedit.setText([e[1] for e in self.nzlsr+self.rowsr if e[0]==repsg][0]) #epsgedit.setText([e for e in self.nzlsr+self.rowsr if re.match('^\s*(\d+).*',e).group(1)==repsg][0]) #To/From Dates if LU.assessNone(rfd): self.fromdateedit.setDate(QDate(int(rfd[0:4]),int(rfd[5:7]),int(rfd[8:10]))) else: early = DataStore.EARLIEST_INIT_DATE self.fromdateedit.setDate(QDate(int(early[0:4]),int(early[5:7]),int(early[8:10]))) if LU.assessNone(rtd): self.todateedit.setDate(QDate(int(rtd[0:4]),int(rtd[5:7]),int(rtd[8:10]))) else: today = DataStore.getCurrent() self.todateedit.setDate(QDate(int(today[0:4]),int(today[5:7]),int(today[8:10]))) #Internal/External CheckBox # if LU.assessNone(rint): # self.internalTrigger.setChecked(rint.lower()==DataStore.CONF_INT) # else: # self.internalTrigger.setChecked(DataStore.DEFAULT_CONF==DataStore.CONF_INT) def getConfiguredDestinations(self): defml = ['',]+DataStore.DRIVER_NAMES.values() return [d for d in self.parent.gpr.getDestinations() if d in defml] def doEPSGEnable(self): self.epsgcombo.setEnabled(self.epsgenable.isChecked()) def doFromDateEnable(self): self.fromdateedit.setEnabled(self.fromdateenable.isChecked()) def doToDateEnable(self): self.todateedit.setEnabled(self.todateenable.isChecked()) def readParameters(self): '''Read values out of dialogs''' destination = LU.assessNone(str(self.destlist[self.destcombo.currentIndex()])) #lgindex = self.parent.confconn.getLayerGroupIndex(self.lgcombo.currentText().toUtf8().data()) lgindex = self.parent.confconn.getLayerGroupIndex(LQ.readWidgetText(self.lgcombo.currentText())) #NB need to test for None explicitly since zero is a valid index lgval = self.parent.confconn.lglist[lgindex][1] if LU.assessNone(lgindex) else None #uconf = LU.standardiseUserConfigName(str(self.confcombo.lineEdit().text())) #uconf = str(self.confcombo.lineEdit().text()) uconf = str(self.cflist[self.confcombo.currentIndex()]) ee = self.epsgenable.isChecked() epsg = None if ee is False else re.match('^\s*(\d+).*',str(self.epsgcombo.lineEdit().text())).group(1) fe = self.fromdateenable.isChecked() te = self.todateenable.isChecked() fd = None if fe is False else str(self.fromdateedit.date().toString('yyyy-MM-dd')) td = None if te is False else str(self.todateedit.date().toString('yyyy-MM-dd')) return destination,lgval,uconf,epsg,fe,te,fd,td def doInitClickAction(self): '''Initialise the LC on LC-button-click, action''' try: try: self.setStatus(self.STATUS.BUSY,'Opening Layer-Config Editor') self.progressbar.setValue(0) self.parent.runLayerConfigAction() finally: self.setStatus(self.STATUS.IDLE,'Ready') except Exception as e: self.setStatus(self.STATUS.ERROR,'Error in Layer-Config',str(sys.exc_info()))#e)) def doCleanClickAction(self): '''Set clean anim and run clean''' #lgo = self.lgcombo.currentText().toUtf8().data() lgo = LQ.readWidgetText(self.lgcombo.currentText()) try: self.setStatus(self.STATUS.CLEAN,'Running Clean '+lgo) self.progressbar.setValue(0) self.runReplicationScript(True) except Exception as e: self.setStatus(self.STATUS.ERROR,'Failed Clean of '+lgo,str(sys.exc_info()))#e)) def doReplicateClickAction(self): '''Set busy anim and run repl''' lgo = self.lgcombo.currentText()#.toUtf8().data()#only used for error messages try: self.setStatus(self.STATUS.BUSY,'Running Replicate '+lgo) self.progressbar.setValue(0) self.runReplicationScript(False) ldslog.debug('TRPfinish') except Exception as e: self.setStatus(self.STATUS.ERROR,'Failed Replication of '+lgo,str(sys.exc_info()))#e)) def runReplicationScript(self,clean=False): '''Run the layer/group repliction script''' destination,lgval,uconf,epsg,fe,te,fd,td = self.readParameters() uconf_path = LU.standardiseUserConfigName(uconf) destination_path = LU.standardiseLayerConfigName(destination) destination_driver = LU.standardiseDriverNames(destination) if not os.path.exists(uconf_path): self.userConfMessage(uconf_path) return elif not MainFileReader(uconf_path).hasSection(destination_driver): self.userConfMessage(uconf_path,destination_driver) return #----------------------------------------------------- #'destname','layer','uconf','group','epsg','fd','td','int' self.parent.gpr.write((destination_driver,lgval,uconf,epsg,fd,td)) ldslog.info(u'dest={0}, lg={1}, conf={2}, epsg={3}'.format(destination_driver,lgval,uconf,epsg)) ldslog.info('fd={0}, td={1}, fe={2}, te={3}'.format(fd,td,fe,te)) lgindex = self.parent.confconn.getLayerGroupIndex(lgval,col=1) #lorg = self.parent.confconn.lglist[lgindex][0] #----------don't need lorg in TP anymore but it is useful for sorting/counting groups #self.parent.confconn.tp.setLayerOrGroup(lorg) self.parent.confconn.tp.setLayerGroupValue(lgval) if self.fromdateenable.isChecked(): self.parent.confconn.tp.setFromDate(fd) if self.todateenable.isChecked(): self.parent.confconn.tp.setToDate(td) self.parent.confconn.tp.setUserConf(uconf) if self.epsgenable: self.parent.confconn.tp.setEPSG(epsg) #because clean state persists in TP if clean: self.parent.confconn.tp.setCleanConfig() else: self.parent.confconn.tp.clearCleanConfig() #(re)initialise the data source since uconf may have changed #>>#self.parent.confconn.tp.src = self.parent.confconn.initSourceWrapper() #-------------------------- ###ep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.destname,self.parent.confconn.uconf) ###self.parent.confconn.reg.closeEndPoint(self.parent.confconn.destname) ###ep = None #Open ProcessRunner and run with TP(proc)/self(gui) instances #HACK temp add of dest_drv to PR call try: #TODO. Test for valid LC first self.tpr = ProcessRunner(self,destination_driver) except Exception as e: ldslog.error('Cannot create ProcessRunner {}. NB Possible missing Layer Config {}'.format(str(e),destination_path)) self.layerConfMessage(destination_path) return #If PR has been successfully created we must vave a valid dst ldslog.debug('TRPstart') self.tpr.start() # def quitProcessRunner(self): # self.tpr.join() # self.tpr.quit() # self.trp = None def userConfMessage(self,uconf,secname=None): ucans = QMessageBox.warning(self, 'User Config Missing/Incomplete', 'Specified User-Config file, '+str(uconf)+' does not exist' if secname is None else 'User-Config file does not contain '+str(secname)+' section', 'Back','Initialise User Config') if not ucans: #Retry ldslog.warn('Retry specifying UC') #self.confcombo.setCurrentIndex(0) return #Init ldslog.warn('Reset User Config Wizard') self.parent.runWizardAction() def layerConfMessage(self,dest): lcans = QMessageBox.warning(self, 'Layer Config Missing', 'Required Layer-Config file, '+str(dest)+' does not exist', 'Back','Run Layer Select') if not lcans: #Retry ldslog.warn('Retry specifying LC') #self.destcombo.setCurrentIndex(0) return #Init ldslog.warn('Reset Layer Config') self.doInitClickAction()
class ItemEntriesFrame(QFrame): read_block = pyqtSignal(int, int) # start_addr, num_bytes poke_block = pyqtSignal(int, QByteArray, bool) # start_addr, raw_bytes, is_ascii log = pyqtSignal(str, str) # msg, color MISSING_ITEM_NAME = '[NOT IN DB]' def __init__(self, type_val, addr_start, addr_end, label, id2name, idx2id, names, parent=None): super(ItemEntriesFrame, self).__init__(parent) self.type_val = type_val self.addr_start = addr_start self.addr_end = addr_end self.max_num_slots = (addr_end - addr_start)/3/4 + 1 self.label = label self.id2name = id2name self.idx2id = idx2id self.names = names self.slots_cache = [] # tuple: (addr_hex, addr_val, slot_number, cur_val) self.cur_slot_idx = -1 self.lbl_label = QLabel(self.label, self) self.btn_read_slots = QPushButton(' Cache Slots', self) self.btn_read_slots.setIcon(QIcon('img/flaticon/data110.png')) self.btn_read_slots.setStyleSheet('background-color: white') self.btn_read_slots.clicked.connect(self.onReadSlots) self.btn_search_cache = QPushButton(' Search ID', self) self.btn_search_cache.setIcon(QIcon('img/flaticon/magnifier13.png')) self.btn_search_cache.setToolTip('Find slot in cache with specified item ID') self.btn_search_cache.setStyleSheet('background-color: white') self.btn_search_cache.clicked.connect(self.onSearchCacheForID) self.btn_read = QPushButton(self) self.btn_read.setIcon(QIcon('img/flaticon/open135.png')) self.btn_read.setToolTip('Read item slot value from memory') self.btn_read.setStyleSheet('background-color: white') self.btn_read.clicked.connect(self.onReadSlot) self.cmb_slots = QComboBox(self) self.cmb_slots.setToolTip('') self.cmb_slots.setStyleSheet('background-color: white') self.cmb_slots.currentIndexChanged[int].connect(self.onChangeSlot) self.cmb_slots.setDisabled(True) self.cmb_names = QComboBox(self) self.cmb_names.setEditable(True) self.cmb_names.addItems(self.names) self.cmb_names.lineEdit().setText(ItemEntriesFrame.MISSING_ITEM_NAME) self.cmb_names.currentIndexChanged[int].connect(self.fetchID) self.txt_id = QLineEdit(self) self.txt_id.setPlaceholderText('ID (hex)') self.txt_id.setMaxLength(3) self.txt_id.textChanged.connect(self.fetchName) self.btn_rename = QPushButton(' Fix Name', self) self.btn_rename.setIcon(QIcon('img/flaticon/cloud-storage3.png')) self.btn_rename.setToolTip('Add/Correct Item Name for %s (type: %02X)' % (self.label, type_val)) self.btn_rename.setStyleSheet('background-color: white') self.btn_rename.clicked.connect(self.onRename) self.txt_amount = QLineEdit(self) self.txt_amount.setPlaceholderText('Amount') self.txt_amount.setMaxLength(3) self.btn_poke = QPushButton(self) self.btn_poke.setIcon(QIcon('img/flaticon/draw39.png')) self.btn_poke.setToolTip('Poke new value for item slot') self.btn_poke.setStyleSheet('background-color: white') self.btn_poke.clicked.connect(self.onPokeSlot) self.layout = QGridLayout(self) self.layout.addWidget(self.lbl_label, 0, 0) self.layout.addWidget(self.btn_read_slots, 0, 1) self.layout.addWidget(self.btn_search_cache, 0, 2) self.layout.addWidget(self.cmb_slots, 0, 3) self.layout.addWidget(self.btn_read, 0, 4) self.layout.addWidget(self.cmb_names, 1, 0) self.layout.addWidget(self.txt_id, 1, 1) self.layout.addWidget(self.btn_rename, 1, 2) self.layout.addWidget(self.txt_amount, 1, 3) self.layout.addWidget(self.btn_poke, 1, 4) self.layout.setColumnStretch(0, 7) self.layout.setColumnStretch(1, 3) self.layout.setColumnStretch(2, 3) self.layout.setColumnStretch(3, 3) self.layout.setColumnStretch(4, 1) self.layout.setContentsMargins(0, 2, 0, 2) icon_height = self.lbl_label.height()*8/15 icon_size = QSize(icon_height, icon_height) self.btn_read_slots.setIconSize(icon_size) self.btn_search_cache.setIconSize(icon_size) self.btn_rename.setIconSize(icon_size) self.btn_read.setIconSize(icon_size) self.btn_poke.setIconSize(icon_size) btn_size = QSize(icon_height*1.5, icon_height*1.5) self.btn_read.setFixedSize(btn_size) self.btn_poke.setFixedSize(btn_size) self.updateUI() def updateUI(self): # Disable editing if cache missing if not (0 <= self.cur_slot_idx < len(self.slots_cache)): self.cmb_names.lineEdit().setText(ItemEntriesFrame.MISSING_ITEM_NAME) self.cmb_names.setDisabled(True) self.txt_id.setText('') self.txt_id.setDisabled(True) return # Validate current value cur_val = self.slots_cache[self.cur_slot_idx][3] (type_val, id_val, amount) = parse_item_word(cur_val) if type_val != self.type_val and type_val != 0: self.log.emit('Coding error: val(%s)=%08X, type (%02X) != expected (%02X)' % (self.cur_addr_str, cur_val, type_val, self.type_val), 'red') return # Update UI self.txt_id.setDisabled(False) self.txt_id.setText('%03X' % id_val) self.cmb_names.setDisabled(False) self.fetchName() self.txt_amount.setText(str(amount)) def setAlternateBGColor(self): self.setStyleSheet('ItemEntriesFrame { background-color:rgb(248,248,248) }') @pyqtSlot() def onRename(self): id_txt = str(self.txt_id.text()) if len(id_txt) != 3: return dialog = FixItemNameDialog('%02X' % self.type_val, id_txt, self) dialog.log.connect(self.log) dialog.exec_() @pyqtSlot() def onReadSlots(self): self.read_block.emit(self.addr_start, self.max_num_slots*4*3) @pyqtSlot(int, int, QByteArray) def onBlockRead(self, addr_start, num_bytes, raw_bytes): # Determine whether block has cache or single slot if addr_start == self.addr_start and num_bytes == self.max_num_slots*4*3: self.onCacheRead(addr_start, raw_bytes) elif num_bytes == 4: # Assume read slot # Ignore if no cache if not (0 <= self.cur_slot_idx < len(self.slots_cache)): return self.onSlotRead(addr_start, raw_bytes) def onCacheRead(self, addr_start, raw_bytes): slot_bytes = str(raw_bytes) self.slots_cache = [] slots_txt = [] for slot_i in xrange(self.max_num_slots): byte_offset = slot_i*3*4 cur_slot_bytes = slot_bytes[byte_offset:(byte_offset+4)] if len(cur_slot_bytes) != 4: continue cur_slot_val = struct.unpack('>I', cur_slot_bytes)[0] (type_val, id_val, amount) = parse_item_word(cur_slot_val) if type_val == 0 or amount == 0: continue elif type_val != self.type_val: self.log.emit('val(%08X)=%08X, type_val(%02X) unexpected(%02X)' % (addr_start+byte_offset, cur_slot_val, type_val, self.type_val), 'red') continue else: addr_val = addr_start + byte_offset addr_hex = '%08X' % addr_val slot_number = slot_i+1 self.slots_cache.append((addr_hex, addr_val, slot_number, cur_slot_val)) slots_txt.append('Slot %03d' % slot_number) # Update UI self.log.emit('Found %d %s slots in memory' % (len(self.slots_cache), self.label), 'black') self.cmb_slots.clear() if len(self.slots_cache) <= 0: self.cmb_slots.setDisabled(True) self.cur_slot_idx = -1 else: self.cmb_slots.setDisabled(False) self.cmb_slots.addItems(slots_txt) self.cur_slot_idx = 0 self.updateUI() def onSlotRead(self, addr_word, raw_bytes): addr_cur_slot = self.slots_cache[self.cur_slot_idx][1] if addr_word == addr_cur_slot: cur_cache = self.slots_cache[self.cur_slot_idx] new_val = struct.unpack('>I', str(raw_bytes))[0] new_cache = (cur_cache[0], cur_cache[1], cur_cache[2], new_val) self.slots_cache[self.cur_slot_idx] = new_cache self.updateUI() else: # Update cached value of other slots addr_first_slot = self.slots_cache[0][1] addr_last_slot = self.slots_cache[-1][1] if (addr_first_slot <= addr_word <= addr_last_slot) and \ ((addr_word - addr_first_slot) % 12 == 0): for slot_i in xrange(len(self.slots_cache)): addr_cur_slot = self.slots_cache[slot_i][1] if addr_word == addr_cur_slot: cur_cache = self.slots_cache[slot_i] new_val = struct.unpack('>I', str(raw_bytes))[0] new_cache = (cur_cache[0], cur_cache[1], cur_cache[2], new_val) self.slots_cache[slot_i] = new_cache return @pyqtSlot() def onSearchCacheForID(self): # Stop if no cache if not (0 <= self.cur_slot_idx < len(self.slots_cache)): self.log.emit('Must cache slots before searching', 'red') return # Fetch and validate target ID try: target_id_val = int(str(self.txt_id.text()), 16) if target_id_val < 0 or target_id_val > Item.MAX_ID_VAL: self.log.emit('Item ID out of [0, 0x%03X] range' % Item.MAX_ID_VAL) return except ValueError: self.log.emit('Failed to parse item ID, expecting XXX', 'red') return # Search ID in cache for cand_slot_idx in xrange(len(self.slots_cache)): (type_val, id_val, amount) = parse_item_word(self.slots_cache[cand_slot_idx][3]) if id_val == target_id_val and type_val == self.type_val: self.cur_slot_idx = cand_slot_idx self.cmb_slots.setCurrentIndex(self.cur_slot_idx) self.updateUI() return self.log.emit('Did not find ID=%03X in %d cached %s slots' % (target_id_val, len(self.slots_cache), self.label), 'red') @pyqtSlot(int) def onChangeSlot(self, new_slot_idx): # Validate new_slot_idx if not (0 <= new_slot_idx < len(self.slots_cache)): return # Update slot idx and read value from memory self.cur_slot_idx = new_slot_idx cur_addr_hex = self.slots_cache[self.cur_slot_idx][0] self.cmb_slots.setToolTip(cur_addr_hex) self.cmb_names.lineEdit().setText(ItemEntriesFrame.MISSING_ITEM_NAME) self.cmb_names.setDisabled(True) self.txt_id.setText('') self.txt_id.setDisabled(True) self.onReadSlot() @pyqtSlot() def fetchName(self): try: id_val = int(str(self.txt_id.text()), 16) except ValueError: return name = self.MISSING_ITEM_NAME if id_val in self.id2name: name = self.id2name[id_val] self.cmb_names.lineEdit().setText(name) @pyqtSlot(int) def fetchID(self, cmb_idx): if cmb_idx < 0 or cmb_idx >= len(self.idx2id): self.txt_id.setText('') else: self.txt_id.setText(self.idx2id[cmb_idx]) @pyqtSlot() def onReadSlot(self): try: if not (0 <= self.cur_slot_idx < len(self.slots_cache)): raise ValueError('must cache slots before reading') addr_cur_slot = self.slots_cache[self.cur_slot_idx][1] self.read_block.emit(addr_cur_slot, 4) except ValueError, e: cur_slot_num = self.slots_cache[self.cur_slot_idx][2] self.log.emit('READ %s Slot %03d failed: %s' % (self.label, cur_slot_num, str(e)), 'red') except BaseException, e: cur_slot_num = self.slots_cache[self.cur_slot_idx][2] self.log.emit('READ %s Slot %03d failed: %s' % (self.label, cur_slot_num, str(e)), 'red') traceback.print_exc()
class LayerSelectionPage(QFrame): #TODO. Filtering, (visible) row selection, multi selection colparams = ((0, 65, 'Name'), (1, 235, 'Title'), (2, 350, 'Keywords')) XFER_BW = 40 def __init__(self, parent=None): super(LayerSelectionPage, self).__init__(parent) self.parent = parent #convenience link self.confconn_link = self.parent.parent.confconn #flag top prevent read read action on keyword delete. New logic makes this redundant #self.keywordbypass = False QToolTip.setFont(QFont('SansSerif', 10)) #label filterlabel = QLabel('Filter') availablelabel = QLabel('Available Layers') selectionlabel = QLabel('Layer Selections') keywordlabel = QLabel('Keyword') explainlabel = QLabel( "Edit Group assignments using this dialog or to simply initialise the Layer-Config just click 'Finish'" ) #selection buttons chooseallbutton = QPushButton('>>') chooseallbutton.setFixedWidth(self.XFER_BW) chooseallbutton.clicked.connect(self.doChooseAllClickAction) choosebutton = QPushButton('>') choosebutton.setFixedWidth(self.XFER_BW) choosebutton.clicked.connect(self.doChooseClickAction) rejectbutton = QPushButton('<') rejectbutton.setFixedWidth(self.XFER_BW) rejectbutton.clicked.connect(self.doRejectClickAction) rejectallbutton = QPushButton('<<') rejectallbutton.setFixedWidth(self.XFER_BW) rejectallbutton.clicked.connect(self.doRejectAllClickAction) #operation buttons finishbutton = QPushButton('Finish') finishbutton.setToolTip('Finish and Close layer selection dialog') finishbutton.clicked.connect(self.parent.close) resetbutton = QPushButton('Reset') resetbutton.font() resetbutton.setToolTip( 'Read Layer from LDS GetCapabilities request. Overwrites current Layer Config' ) resetbutton.clicked.connect(self.doResetClickAction) self.available_sfpm = LDSSFPAvailableModel(self) self.selection_sfpm = LDSSFPSelectionModel(self) self.available_sfpm.setSourceModel(self.parent.available_model) self.selection_sfpm.setSourceModel(self.parent.selection_model) #textedits filteredit = QLineEdit('') filteredit.setToolTip( 'Filter Available-Layers pane (filter operates across Name and Title fields and accepts Regex expressions)' ) filteredit.textChanged.connect(self.available_sfpm.setActiveFilter) self.keywordcombo = QComboBox() self.keywordcombo.setToolTip( 'Select or Add a unique identifier to be saved in layer config (keyword)' ) self.keywordcombo.addItems(list(self.confconn_link.assigned)) self.keywordcombo.setEditable(True) self.keywordcombo.activated.connect(self.doKeyComboChangeAction) lgindex = self.confconn_link.getLayerGroupIndex( self.confconn_link.lgval, col=1) lgentry = self.confconn_link.lglist[lgindex] if LU.assessNone( lgindex) else None #keywordedit = self.keywordcombo.lineEdit().text().toUtf8().data().decode('utf8')# for writing #if no entry or layer indicated then blank self.keywordcombo.lineEdit().setText( '' if lgentry is None or lgentry[0] == LORG.LAYER else lgentry[1]) #self.confconn_link.lgval)#TODO. group only #header headmodel = QStandardItemModel() headmodel.setHorizontalHeaderLabels([ i[2] for i in self.colparams ][:self.parent.available_model.columnCount()]) headview1 = QHeaderView(Qt.Horizontal) headview1.setModel(headmodel) headview1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) headview2 = QHeaderView(Qt.Horizontal) headview2.setModel(headmodel) headview2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) #table self.available = QTableView() self.available.setSelectionBehavior(QAbstractItemView.SelectRows) self.available.setSelectionMode(QAbstractItemView.MultiSelection) self.selection = QTableView() self.selection.setSelectionBehavior(QAbstractItemView.SelectRows) self.selection.setSelectionMode(QAbstractItemView.MultiSelection) #interesting, must set model after selection attributes but before headers else row selections/headers don't work properly self.available.setModel(self.available_sfpm) self.selection.setModel(self.selection_sfpm) self.available.setSortingEnabled(True) self.available.setHorizontalHeader(headview1) self.selection.setSortingEnabled(True) self.selection.setHorizontalHeader(headview2) for cp in self.colparams: self.available.setColumnWidth(cp[0], cp[1]) self.selection.setColumnWidth(cp[0], cp[1]) self.available.verticalHeader().setVisible(False) self.available.horizontalHeader().setVisible(True) self.selection.verticalHeader().setVisible(False) self.selection.horizontalHeader().setVisible(True) #layout vbox00 = QVBoxLayout() vbox00.addWidget(availablelabel) vbox00.addWidget(self.available) vbox01 = QVBoxLayout() vbox01.addWidget(chooseallbutton) vbox01.addWidget(choosebutton) vbox01.addWidget(rejectbutton) vbox01.addWidget(rejectallbutton) vbox02 = QVBoxLayout() vbox02.addWidget(selectionlabel) vbox02.addWidget(self.selection) vbox10 = QVBoxLayout() vbox10.addWidget(filterlabel) vbox10.addWidget(filteredit) hbox12 = QHBoxLayout() hbox12.addWidget(keywordlabel) hbox12.addStretch(1) #hbox12.addWidget(inspbutton) #hbox12.addWidget(addbutton) #hbox12.addWidget(delbutton) vbox12 = QVBoxLayout() vbox12.addLayout(hbox12) vbox12.addWidget(self.keywordcombo) #00|01|02 #10|11|12 grid0 = QGridLayout() grid0.addLayout(vbox00, 1, 0) grid0.addLayout(vbox01, 1, 1) grid0.addLayout(vbox02, 1, 2) grid0.addLayout(vbox10, 0, 0) grid0.addLayout(vbox12, 0, 2) hbox2 = QHBoxLayout() hbox2.addWidget(resetbutton) hbox2.addStretch(1) hbox2.addWidget(explainlabel) hbox2.addWidget(finishbutton) #gbox1.setLayout(hbox2) vbox3 = QVBoxLayout() vbox3.addLayout(grid0) #vbox3.addLayout(hbox3) #vbox3.addWidget(line0) vbox3.addLayout(hbox2) self.setLayout(vbox3) def doChooseAllClickAction(self): '''Moves the lot to Selected''' #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode( LQ.readWidgetText(self.keywordcombo.lineEdit().text())) if not self.checkKeyword(ktext): return #------------------------------ self.parent.signalModels(self.parent.STEP.PRE) #self.parent.selection_model.mdata += self.parent.available_model.mdata self.parent.selection_model.initData(self.confconn_link.complete) self.parent.available_model.initData([]) self.parent.signalModels(self.parent.STEP.POST) #------------------------------ self.parent.writeKeysToLayerConfig(ktext) #self.confconn_link.setupAssignedLayerList() if self.keywordcombo.findText(ktext) == -1: self.keywordcombo.addItem(ktext) def doChooseClickAction(self): '''Takes available selected and moves to selection''' #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode( LQ.readWidgetText(self.keywordcombo.lineEdit().text())) #ktext = str(self.keywordcombo.lineEdit().text()) if not self.checkKeyword(ktext): return #------------------------------ select = self.available.selectionModel() if select.hasSelection(): self.transferSelectedRows(select.selectedRows(), self.available_sfpm, self.selection_sfpm) #------------------------------ self.parent.writeKeysToLayerConfig(ktext) #self.confconn_link.assigned = self.confconn_link.setupAssignedLayerList() # -1 to indicate no index since 0,1,... are valid if self.keywordcombo.findText(ktext) == -1: self.keywordcombo.addItem(ktext) else: ldslog.warn('L2R > Transfer action without selection') #TRACE# #pdb.set_trace() self.available.clearSelection() def transferSelectedRows(self, indices, from_model, to_model): tlist = [] for proxymodelindex in indices: transfer = from_model.getData(proxymodelindex) tlist.append((proxymodelindex, transfer), ) to_model.addData([t[1] for t in tlist]) from_model.delData([t[0] for t in tlist]) return tlist def doRejectClickAction(self): '''Takes available selected and moves to selection''' #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode( LQ.readWidgetText(self.keywordcombo.lineEdit().text())) if not self.checkKeyword(ktext): return #------------------------------ select = self.selection.selectionModel() if select.hasSelection(): tlist = self.transferSelectedRows(select.selectedRows(), self.selection_sfpm, self.available_sfpm) #------------------------------ kindex = self.keywordcombo.findText(ktext) remainder = self.parent.deleteKeysFromLayerConfig( [ll[1][0] for ll in tlist], ktext) if remainder > 0 and kindex == -1: #items+newkey -> add self.parent.writeKeysToLayerConfig(ktext) self.keywordcombo.addItem(ktext) elif remainder == 0 and kindex > -1: #empty+oldkey -> del self.keywordcombo.removeItem(kindex) self.keywordcombo.clearEditText() else: ldslog.warn('R2L < Transfer action without selection') #TRACE# #pdb.set_trace() self.selection.clearSelection() def doRejectAllClickAction(self): #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode( LQ.readWidgetText(self.keywordcombo.lineEdit().text())) if not self.checkKeyword(ktext): return #------------------------------ self.parent.deleteKeysFromLayerConfig( [ll[0] for ll in self.parent.selection_model.mdata], ktext) #------------------------------ self.parent.signalModels(self.parent.STEP.PRE) #self.parent.available_model.mdata += self.parent.selection_model.mdata self.parent.available_model.initData(self.confconn_link.complete) self.parent.selection_model.initData([]) self.parent.signalModels(self.parent.STEP.POST) #------------------------------ #self.confconn_link.setupAssignedLayerList() #self.keywordbypass = True self.keywordcombo.removeItem(self.keywordcombo.findText(ktext)) self.keywordcombo.clearEditText() def doKeyComboChangeAction(self): '''Reset the available pane and if there is anything in the keyword box use this to init the selection pane''' #HACK #if self.keywordbypass: # self.keywordbypass = False # return #------------------------------ #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode( LQ.readWidgetText(self.keywordcombo.lineEdit().text())) #------------------------------ av_sl = self.parent.splitData(ktext, self.confconn_link.complete) #av_sl = self.parent.splitData(ktext,self.confconn_link.complete) self.parent.signalModels(self.parent.STEP.PRE) self.parent.available_model.initData(av_sl[0]) self.parent.selection_model.initData(av_sl[1]) self.parent.signalModels(self.parent.STEP.POST) def doResetClickAction(self): '''Dumps the LC and rebuilds from a fresh read of the caps doc''' #int warning (QWidget parent, QString title, QString text, QString button0Text, QString button1Text = QString(), QString button2Text = QString(), int defaultButtonNumber = 0, int escapeButtonNumber = -1) ans = QMessageBox.warning( self, "Reset", "This action will overwrite your Layer Configuration using the current LDS settings (potentially adding new or removing layers). Continue?", "Continue", "Cancel") if ans: #Cancel ldslog.warn('Cancelling Reset operation') return #Continue ldslog.warn('Reset Layer Config') self.parent.resetLayers() self.keywordcombo.clear() def checkKeyword(self, ktext): '''Checks keyword isn't null and isn't part of the LDS supplied keywords''' if LU.assessNone(ktext) is None: QMessageBox.about(self, "Keyword Required", "Please enter a Keyword to assign Layer(s) to") return False if ktext in self.confconn_link.reserved: QMessageBox.about( self, "Reserved Keyword", "'{}' is a reserved keyword, please select again".format( ktext)) return False return True
def generate_gui(self): self.theme_boxes = [] self.themes = set(['']) dp = self.layer.dataProvider() fields = list(dp.fields()) numeric_fields = [field for field in fields if field.typeName() in NUMERIC_FIELD_TYPES] themes_list = [] indicators_list = {} if self.project_definition: themes = self.project_definition['children'][1]['children'] for theme in themes: themes_list.append(theme['name']) for indicator in theme['children']: indicators_list[indicator['field']] = (theme['name'], indicator['name']) # remove duplicates themes_list = list(set(themes_list)) themes_list.sort() themes_list.insert(0, '') attribute_label = QLabel('Attribute') theme_label = QLabel('Theme') name_label = QLabel('Name') sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) sizePolicy.setHorizontalStretch(5) theme_label.setSizePolicy(sizePolicy) name_label.setSizePolicy(sizePolicy) self.ui.grid_layout.addWidget(attribute_label, 0, 0) self.ui.grid_layout.addWidget(theme_label, 0, 1) self.ui.grid_layout.addWidget(name_label, 0, 2) for i, field in enumerate(numeric_fields, start=1): theme_name = '' indicator_name = '' if field.name() in indicators_list: theme_name = indicators_list[field.name()][0] indicator_name = indicators_list[field.name()][1] attribute_label = QLabel(field.name()) attribute_label.setTextInteractionFlags(Qt.TextSelectableByMouse) theme = QComboBox() theme.setEditable(True) theme.setDuplicatesEnabled(False) theme.setInsertPolicy(QComboBox.InsertAlphabetically) theme.addItems(themes_list) current_index = theme.findText(theme_name) current_index = current_index if current_index != -1 else 0 theme.setCurrentIndex(current_index) theme.currentIndexChanged.connect(self.check_status) theme.lineEdit().editingFinished.connect(self.update_themes) self.theme_boxes.append(theme) name = QLineEdit(indicator_name) name.textChanged.connect(self.check_status) self.ui.grid_layout.addWidget(attribute_label, i, 0) self.ui.grid_layout.addWidget(theme, i, 1) self.ui.grid_layout.addWidget(name, i, 2) self.check_status()
class QuestionDlg(QDialog): def __init__(self, parent=None): super(QuestionDlg,self).__init__(parent) # self.setStyleSheet("background-image:url('image/panelbg.jpg'); border: 2px; border-radius 2px;") # self.createDb() # return self.db = QSqlDatabase.addDatabase("QSQLITE"); self.db.setDatabaseName("studentNew.db") if not self.db.open(): QMessageBox.warning(None, "错误", "数据库连接失败: %s" % self.db.lastError().text()) sys.exit(1) self.g_curClassName = "" self.deleteTmpdata() self.setWindowFlags(Qt.CustomizeWindowHint) # self.setStyleSheet("border: 2px; border-radius 2px;") # self.setWindowFlags(Qt.FramelessWindowHint) self.setStyleSheet("background-color: rgba(132, 171, 208, 200);") self.tabWidget=QTabWidget(self) self.tabWidget.currentChanged.connect(self.changeTab) # tabWidget.setTabShape(QTabWidget.Triangular) self.tabWidget.setStyleSheet("QTabWidget::pane{border-width:1px;border-color:rgb(48, 104, 151);\ border-style: outset;background-color: rgb(132, 171, 208);\ background: transparent;} \ QTabWidget::tab-bar{border-width:0px;}\ QTabBar::tab { height: 60px; width: 260px; color:rgb(0, 0, 255); font-size:20px; font-weight:bold;} \ QTabBar::tab:hover{background:rgb(255,255, 255, 100);} \ QTabBar::tab:selected{border-color:green;background-color:white;color:green;}") # tabWidget.setStyleSheet("QTabBar::tab:hover{background:rgb(255,255, 255, 100);}") self.btngroup = QButtonGroup() self.popMenu = QMenu(self) entry1 = self.popMenu.addAction("正确") self.connect(entry1,SIGNAL('triggered()'), lambda : self.answerRight()) entry2 = self.popMenu.addAction("错误") self.connect(entry2,SIGNAL('triggered()'), lambda : self.answerWrong()) entry3 = self.popMenu.addAction("替换") self.connect(entry3,SIGNAL('triggered()'), lambda : self.resetStudent()) # Create the first tab page. self.w1=QWidget() self.w1.setAccessibleName("w1tab") self.genOneTab() # Create the second tab page. self.w2=QWidget() self.w2.setAccessibleName("w2tab") self.genTwoTab() self.tabWidget.addTab(self.w1,"") self.tabWidget.addTab(self.w2,"班级学生信息管理") self.tabWidget.resize(940,700) btnclose = QPushButton(self) btnclose.setToolTip("关闭") btnclose.setText("╳") btnclose.setGeometry(915, 5, 20, 20) btnclose.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255)") btnclose.clicked.connect(self.close) btnMinimized = QPushButton(self) btnMinimized.setToolTip("最小化") btnMinimized.setText("▁") btnMinimized.setGeometry(890, 5, 20, 20) btnMinimized.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255)") btnMinimized.clicked.connect(lambda: self.showMinimized()) self.btnSysMenu = QPushButton(self) # self.btnSysMenu.setText("▼") self.btnSysMenu.setGeometry(865, 5, 20, 20) self.btnSysMenu.setToolTip("系统设置") self.btnSysMenu.clicked.connect(lambda: self.showMinimized()) menufont = QFont("宋体", 10) popMenu = QMenu(self) entry1 = popMenu.addAction("所有学生提问信息清零") entry1.setFont(menufont) self.connect(entry1,SIGNAL('triggered()'), self.initStudent) entry2 = popMenu.addAction("清除本堂课提问人员") entry2.setFont(menufont) self.connect(entry2,SIGNAL('triggered()'), self.deleteTmpdata) entry3 = popMenu.addAction("关于...") entry3.setFont(menufont) self.connect(entry3,SIGNAL('triggered()'), self.aboutMe) entry4 = popMenu.addAction("导出...") entry4.setFont(menufont) self.connect(entry4,SIGNAL('triggered()'), self.exportNotice) self.btnSysMenu.setMenu(popMenu) self.btnSysMenu.setStyleSheet("QPushButton::menu-indicator {image: url('image/sysmenu.png');subcontrol-position: right center;} ") # self.btnSysMenu.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255);") authorinfo = QLabel(self.tabWidget) # authorinfo.setToolTip("关闭") authorinfo.setText("程序设计:汕头市大华路第一小学 赵小娜,有任何问题请反馈至[email protected]。") authorinfo.setGeometry(20, 665, 470, 26) authorinfo.setFont(QFont('Courier New')) authorinfo.setStyleSheet("background-color:rgba(255, 255, 255,160); font-size:12px;border: 1px solid rgb(60,200,255,200);color:rgba(0,0,0,220);border-radius:12px;") self.setWindowTitle("课堂随机提问") self.setWindowIcon(QIcon("image/start.ico")) self.setGeometry(100, 20, 940, 700) # self.changeTab() screen = QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2) self.btn_start.setMyarg('start') # print(self.btn_start.getMyarg()) self.connect(self.btn_start, SIGNAL("clicked()"), self.startChoice) # self.connect(self.w1title, SIGNAL("currentIndexChanged(int)"), self.changeTitle) # self.connect(self.btn_start2, SIGNAL("clicked()"), self.startChoice) # self.connect(self.w2title, SIGNAL("currentIndexChanged(int)"), self.changeTitle) self.btngroup.buttonClicked[int].connect(self.btns_click) # self.connect(self.btn_start, SIGNAL("myslot(PyQt_PyObject)"), self.myslot) # self.connect(self.btngroup, SIGNAL("buttonClicked(int)"), lambda:self.btns_click()) def myslot(self, text): # print(text, self.dict_choices) self.g_curbtn = text if self.g_curbtn not in self.dict_choices: self.btnSysMenu.setFocus() return # print(self.btngroup.button(int(self.g_curbtn)).parent()) # print(type(self.btngroup.button(int(self.g_curbtn)).parentWidget())) pos = self.btngroup.button(int(self.g_curbtn)).parent().mapToGlobal(self.btngroup.button(int(self.g_curbtn)).pos()) width = self.btngroup.button(int(self.g_curbtn)).rect().height() # print("-----", pos, width) pos.setY(pos.y()+width-5) indx = 0 for istate in self.dict_choices[self.g_curbtn]: if istate == '1': self.popMenu.actions()[indx].setEnabled(True) elif istate == '0': self.popMenu.actions()[indx].setEnabled(False) indx += 1 self.popMenu.exec_(pos) self.btnSysMenu.setFocus() # def on_context_menu(self, point): # print(point) # self.popMenu.exec_(self.button.mapToGlobal(point)) def btns_click(self, btnid): # curclassname = self.tabWidget.tabText(0) query = QSqlQuery(self.db) # cur = conn.cursor() today = datetime.date.today() self.g_curbtn = str(btnid).zfill(2) if self.g_curbtn not in self.dict_choices: self.btngroup.button(int(self.g_curbtn)).setStyleSheet(stylesheetstr_new) query.exec_("select count(*) from tmprecord where stusn='" + str(self.g_curbtn) + "'") query.next() if query.value(0) == 0: query.prepare("insert into tmprecord (classname, stusn, datequestion) values (:classname, :stusn, :datequestion)") query.bindValue(":classname", self.g_curClassName) query.bindValue(":stusn", self.g_curbtn) query.bindValue(":datequestion", today) query.exec_() self.dict_choices[self.g_curbtn] = "111" else: self.btngroup.button(int(self.g_curbtn)).setStyleSheet(stylesheetstr_old) self.btngroup.button(int(self.g_curbtn)).setIcon(QIcon()) query.exec_("delete from tmprecord where stusn='"+ str(self.g_curbtn) + "'") self.dict_choices.pop(self.g_curbtn) self.btnSysMenu.setFocus() def exportNotice(self): query = QSqlQuery(self.db) query.exec_("select stusn, stuname, classname, rightquestions, wrongquestions from student" ) lstInfo = [["学号","姓名", "班级", "回答正确次数", "回答错误次数"]] while(query.next()): lstInfo.append([query.value(0),query.value(1),query.value(2),query.value(3),query.value(4)]) from xlwt import Workbook,easyxf book = Workbook(encoding='ascii') # 'pattern: pattern solid, fore_colour white;' style = easyxf( 'font: height 280, name 黑体;' 'align: vertical center, horizontal center;' ) style2 = easyxf('font: height 260, name 仿宋_GB2312, bold True; align: vertical center, horizontal left;') style3 = easyxf('font: height 260, name 仿宋_GB2312, bold True; align: vertical center, horizontal left, wrap True;') sheet1 = book.add_sheet('学生提问情况汇总',cell_overwrite_ok=True) # sheet1.write(0,7,flagtxt, easyxf('font: height 200, name 黑体;align: vertical center, horizontal right;')) sheet1.write_merge(0,0,0,4, '学生提问情况汇总表',style) sheet1.row(0).height_mismatch = 1 sheet1.row(0).height = 5*256 sheet1.col(0).width = 10*256 sheet1.col(1).width = 25*256 sheet1.col(2).width = 25*256 sheet1.col(3).width = 20*256 sheet1.col(4).width = 20*256 tmprows = 1 for item in lstInfo: stusn = item[0] stuname = item[1] classname = item[2] rightquestions = item[3] wrongquestions = item[4] sheet1.write(tmprows,0,stusn, style2) sheet1.write(tmprows,1,stuname, style2) sheet1.write(tmprows,2,classname, style2) sheet1.write(tmprows,3,rightquestions, style2) sheet1.write(tmprows,4,wrongquestions, style2) tmprows += 1 # print(tmprows) sheet1.header_str = "".encode() sheet1.footer_str = "".encode() # book.save('d:/simple.xls') # print(QDir.home().dirName() , QDir.homePath ()) filename = QDir.homePath () + "\学生提问情况汇总表.xls" try: book.save(filename) except Exception as e: QMessageBox.warning(self, "写入错误", "错误号:"+str(e.errno)+"\n错误描述:"+e.strerror+"\n请关闭已经打开的%s文档!" % filename) QMessageBox.about (self, "导出成功", "请查看文档:%s" % filename) def aboutMe(self): strinfo = """本软件采用python3.4编写,界面采用qt4.8的python绑定。 \n版本所有:汕头市大华路第一小学赵小娜老师。 \n有任何问题请反馈至[email protected]。 """ QMessageBox.information(None, "关于", strinfo) def initStudent(self): query = QSqlQuery(self.db) ret = query.exec_("update student set wrongquestions=0") ret = query.exec_("update student set rightquestions=0") QMessageBox.information(None, "提示", "已清除所有学生的累计提问情况。") def deleteTmpdata(self): query = QSqlQuery(self.db) ret = query.exec_("delete from tmprecord where 1=1" ) if self.g_curClassName != "": QMessageBox.information(None, "提示", "已清除本次软件启动后的所有已提问过的学生。") def changeTab(self): # pass curtab = self.tabWidget.currentIndex() # print(curtab, "-") if curtab == 1: ## when click the second tab page ,then pass. return # cur = conn.cursor() query = QSqlQuery(self.db) ## if current classname is null, then set current tabpage display the first class of classtable if self.g_curClassName == "": ret = query.exec_("select classname from classtable") query.next() self.g_curClassName = query.value(0) self.tabWidget.setTabText(0, self.g_curClassName) # print(1) strwhere = " and classname like '" + self.g_curClassName + "' ORDER BY stusn" self.g_curbtn = "" self.dict_choices = {} self.studentSnlst = [] ## clearn the question data of temp record . ret= query.exec_("delete from tmprecord where 1=1") ret = query.exec_("select stusn, stuname from student where 1=1 " + strwhere) ## now update the global data "self.btngroup" for indx in range(0, 56): self.btngroup.button(indx+1).setText("") self.btngroup.button(indx+1).setMyarg(None) self.btngroup.button(indx+1).setStyleSheet(stylesheetstr_old) self.btngroup.button(indx+1).setIcon(QIcon()) self.btngroup.button(indx+1).setEnabled(False) self.studentSnlst.append([indx+1,]) inum = 0 while (query.next()): inum += 1 self.btngroup.button(inum).setText(query.value(1)) self.btngroup.button(inum).setMyarg(query.value(0)) self.btngroup.button(inum).setStyleSheet(stylesheetstr_old) self.btngroup.button(inum).setIcon(QIcon()) self.btngroup.button(inum).setEnabled(True) # print(inum, len(self.btngroup.buttons())) self.group_animation = groupAnimation(self.studentSnlst, self.btngroup) def mousePressEvent(self, event): # print('a') if event.button() == Qt.RightButton: QDialog.mousePressEvent(self,event) return # print(event.sender(), event.button()) self.offset = event.pos() # print(self.offset) def mouseMoveEvent(self, event): # print('sss') if hasattr(self, 'offset'): x=event.globalX() y=event.globalY() x_w = self.offset.x() y_w = self.offset.y() self.move(x-x_w, y-y_w) else: pass #######======= studentModel ============############### def newStudent(self): # Calc the missing number: row = self.StudentModel.rowCount() if row > 0: oldNumList = [] for i in range(0, row): oldNumList.append(int(self.StudentModel.index(i,2).data())) allNumberList = list(range(1, oldNumList[-1]+1)) for i in range(0, allNumberList[-1]): if oldNumList[i] != allNumberList[i]: missingNum = allNumberList[i] break if len(oldNumList) == len(allNumberList): missingNum = allNumberList[i] +1 else: missingNum = 1 self.StudentModel.insertRow(row) self.StudentView.scrollToBottom() self.StudentModel.setData(self.StudentModel.index(row, 1), self.g_curClassName) self.StudentModel.setData(self.StudentModel.index(row, 2), str(missingNum).zfill(2)) self.StudentModel.setData(self.StudentModel.index(row, 4), 0) self.StudentModel.setData(self.StudentModel.index(row, 5), 0) def removeStudent(self): index = self.StudentView.currentIndex() row = index.row() if QMessageBox.question(self, "删除确认", "是否要删除当前选中记录?", "确定", "取消") == 0: self.StudentModel.removeRows(row, 1) self.StudentModel.submitAll() self.StudentModel.database().commit() def revertStudent(self): self.StudentModel.revertAll() self.StudentModel.database().rollback() def saveStudent(self): self.StudentModel.database().transaction() if self.StudentModel.submitAll(): self.StudentModel.database().commit() # print("save success! ->commit") else: self.StudentModel.revertAll() self.StudentModel.database().rollback() #######======= classModel ============############### def newClass(self): row = self.ClassnameModel.rowCount() self.ClassnameModel.insertRow(row) def removeClass(self): index = self.ClassnameView.currentIndex() row = index.row() curClassname = index.sibling(index.row(),0).data() strwhere = "classname like '" + curClassname + "'" self.StudentModel.setFilter(strwhere) self.StudentModel.select() # print(self.StudentModel.rowCount(), "----", ) if QMessageBox.question(self, "删除确认", "删除班级意味着会删除本班所有人员信息。是否要删除当前选中记录?", "确定", "取消") == 0: self.ClassnameModel.removeRows(row, 1) self.ClassnameModel.submitAll() self.ClassnameModel.database().commit() self.StudentModel.removeRows(0, self.StudentModel.rowCount()) self.StudentModel.submitAll() self.StudentModel.database().commit() def revertClass(self): self.ClassnameModel.revertAll() self.ClassnameModel.database().rollback() def saveClass(self): query = QSqlQuery(self.db) # record the old class name lstOldClassName = {} lstOldClassid = [] query.exec_("select rowid, classname from classtable" ) while(query.next()): lstOldClassName[query.value(0)] = query.value(1) lstOldClassid.append(query.value(0)) # print(lstOldClassName) # Update the class Table self.ClassnameModel.database().transaction() if self.ClassnameModel.submitAll(): self.ClassnameModel.database().commit() # print("save success! ->commit") else: QMessageBox.warning(None, "错误", "请检查班级中名称,不能出现同名班级!") self.ClassnameModel.revertAll() self.ClassnameModel.database().rollback() # print(lstOldClassid) lstNewClassName = {} query.exec_("select rowid, classname from classtable where rowid in " + str(tuple(lstOldClassid)) ) while(query.next()): lstNewClassName[query.value(0)] = query.value(1) # print(lstOldClassName, '=========') # print(lstNewClassName, '~~~~~~~~~') for i in lstOldClassName: oldclassname = lstOldClassName[i] newclassname = lstNewClassName[i] if oldclassname != newclassname: # print(oldclassname, newclassname, '++++++++') # print("update student set classname=" + newclassname + " where classname='" + oldclassname + "'") query.exec_("update student set classname='" + newclassname + "' where classname='" + oldclassname + "'") self.StudentModel.setFilter("classname = '" + newclassname + "'") self.StudentModel.select() lstClassName = [] query.exec_("select classname from classtable" ) while(query.next()): lstClassName.append(query.value(0)) self.StudentView.setItemDelegateForColumn(1, ComboBoxDelegate(self, lstClassName, self.db)) def dbclick(self, indx): if type(indx.sibling(indx.row(),0).data()) != QPyNullVariant: classname = indx.sibling(indx.row(),0).data() strwhere = "classname like '" + classname + "'" self.StudentModel.setFilter(strwhere) self.StudentModel.setSort(2, Qt.AscendingOrder) self.StudentModel.select() self.g_curClassName = classname self.tabWidget.setTabText(0, self.g_curClassName) def dbclick2(self, indx): if indx.column() == 2: self.StudentView.setEditTriggers(QAbstractItemView.NoEditTriggers) else: self.StudentView.setEditTriggers(QAbstractItemView.DoubleClicked) def genTwoTab(self, tabtitle=""): # Create the tab title sytle. tabtitle = QLabel() tabtitle.setFont(QFont('Courier New', 20)) tabtitle.setText("班级学生信息管理") tabtitle.setStyleSheet("border: 1px solid blue; color:rgba(0,0,255, 220);\ background-color:rgba(201,201,201,60);\ border-radius: 6px; \ padding: 1px 18px 1px 20px;\ min-width: 8em;") tabtitle.setMinimumHeight(50); titleLayout = QHBoxLayout() titleLayout.addWidget(tabtitle) titleLayout.setAlignment(tabtitle, Qt.AlignCenter) # Create the classnameView self.ClassnameView = QTableView() self.ClassnameModel = QSqlTableModel(self.ClassnameView) self.ClassnameModel.setTable("classtable") # self.ClassnameModel.setRelation(2, QSqlRelation("mentalmodel", "id", "name")); self.ClassnameModel.setEditStrategy(QSqlTableModel.OnManualSubmit) self.ClassnameModel.select() self.ClassnameModel.setHeaderData(0, Qt.Horizontal, "班级名称") # for indx, iheader in enumerate(["classid", "classname"]): # self.ClassnameModel.setHeaderData(indx+1, Qt.Horizontal, iheader) self.ClassnameView.setModel(self.ClassnameModel) # self.ClassnameView.setColumnHidden(0, True) # self.ClassnameView.show() self.ClassnameView.verticalHeader().setFixedWidth(30) self.ClassnameView.verticalHeader().setStyleSheet("color: red;font-size:20px; "); self.ClassnameView.setStyleSheet("QTableView{background-color: rgb(250, 250, 200, 0);" "alternate-background-color: rgb(141, 163, 0);}" "QTableView::item:hover {background-color: rgba(100,200,220,100);} ") self.ClassnameView.setStyleSheet("font-size:16px; "); self.ClassnameView.setSelectionMode(QAbstractItemView.SingleSelection) # self.ClassnameView.dataChanged.connect(self.dataChanged) # self.ClassnameView.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # the second list self.StudentView = QTableView() self.StudentModel = QSqlTableModel(self.StudentView) self.StudentModel.setTable("student") # self.StudentModel.setRelation(2, QSqlRelation("mentalmodel", "id", "name")); self.StudentModel.setEditStrategy(QSqlTableModel.OnManualSubmit) # self.StudentModel.select() query = QSqlQuery(self.db) strwhere = " 1=1 " if self.g_curClassName == "": ret = query.exec_("select classname from classtable") query.next() firstClassName = query.value(0) strwhere += " and classname like '" + firstClassName + "'" self.StudentModel.setFilter(strwhere) self.StudentModel.select() for indx, iheader in enumerate(["班级名称", "学生编号", "学生姓名", "答对次数", "答错次数"]): self.StudentModel.setHeaderData(indx+1, Qt.Horizontal, iheader) self.StudentView.setModel(self.StudentModel) self.StudentView.setColumnHidden(0, True) # query = QSqlQuery(self.db) lstClassName = [] query.exec_("select classname from classtable" ) while(query.next()): lstClassName.append(query.value(0)) self.StudentView.setItemDelegateForColumn(1, ComboBoxDelegate(self, lstClassName, self.db)) # self.StudentView.show() self.StudentView.verticalHeader().setFixedWidth(30) self.StudentView.verticalHeader().setStyleSheet("color: red;font-size:20px; background-color: rgb(250, 250, 200, 100)"); self.StudentView.setStyleSheet("QTableView{background-color: rgb(250, 250, 200, 0);" "alternate-background-color: rgb(141, 163, 250);}" "QTableView::item:hover {background-color: rgba(10,200,100,200);} " ) self.StudentView.setStyleSheet("font-size:16px;") self.StudentView.setSelectionMode(QAbstractItemView.SingleSelection) self.StudentView.doubleClicked.connect(self.dbclick2) btn_lst1_layout = QGridLayout() newusrbtn = QPushButton("新增") savebtn = QPushButton("保存") revertbtn = QPushButton("撤销") removebtn = QPushButton("删除") btn_lst1_layout.addWidget(newusrbtn, 0, 0) btn_lst1_layout.addWidget(savebtn, 0, 1) btn_lst1_layout.addWidget(revertbtn, 1, 0) btn_lst1_layout.addWidget(removebtn, 1, 1) newusrbtn.clicked.connect(self.newClass) savebtn.clicked.connect(self.saveClass) revertbtn.clicked.connect(self.revertClass) removebtn.clicked.connect(self.removeClass) self.ClassnameView.doubleClicked.connect(self.dbclick) btnbox2 = QDialogButtonBox(Qt.Horizontal) newusrbtn2 = QPushButton("新增") savebtn2 = QPushButton("保存") revertbtn2 = QPushButton("撤销") removebtn2 = QPushButton("删除") btnbox2.addButton(newusrbtn2, QDialogButtonBox.ActionRole); btnbox2.addButton(savebtn2, QDialogButtonBox.ActionRole); btnbox2.addButton(revertbtn2, QDialogButtonBox.ActionRole); btnbox2.addButton(removebtn2, QDialogButtonBox.ActionRole); newusrbtn2.clicked.connect(self.newStudent) savebtn2.clicked.connect(self.saveStudent) revertbtn2.clicked.connect(self.revertStudent) removebtn2.clicked.connect(self.removeStudent) # left list layout lst_layout_1 = QVBoxLayout() lst_layout_1.addWidget(self.ClassnameView) lst_layout_1.addLayout(btn_lst1_layout) lst_layout_2 = QVBoxLayout() lst_layout_2.addWidget(self.StudentView) lst_layout_2.addWidget(btnbox2) lstlayout = QHBoxLayout() lstlayout.setMargin(5) # lstlayout.addLayout(findbox) lstlayout.addLayout(lst_layout_1, 2) lstlayout.setMargin(5) lstlayout.addLayout(lst_layout_2, 5) labelClass = QLabel("") labelClass.setStyleSheet("background-color:rgba(255, 255, 255,0); color:rgba(0,0,0,0);") labelClass.setFixedHeight(40) # labelClass.setFixedWidth(100) # labelClass.setFont(QFont('宋体', 10)) bottomlayout = QHBoxLayout() bottomlayout.addWidget(labelClass) tab2layout = QVBoxLayout() tab2layout.addLayout(titleLayout) tab2layout.addLayout(lstlayout) tab2layout.addLayout(bottomlayout) self.w2.setLayout(tab2layout) self.w2.setStyleSheet("background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #228888);") def genOneTab(self): tabtitle = QLabel() # tabtitle.setFixedHeight(40) # tabtitle.setFixedWidth(160) self.btn_start = MyButton("开始") self.choicenum_text = QComboBox() self.choicenum_text.setObjectName('w1combonums') # self.w1title.setStyleSheet("background-image:url('image/panelbg.jpg');") # Set the title style tabtitle.setFont(QFont('Courier New', 20)) tabtitle.setText("随堂提问演板") tabtitle.setStyleSheet("border: 1px solid blue; color:rgba(0,0,255, 220);\ background-color:rgba(201,201,201,60);\ border-radius: 6px; \ padding: 1px 18px 1px 20px;\ min-width: 8em;") tabtitle.setMinimumHeight(50); titleLayout = QHBoxLayout() titleLayout.addWidget(tabtitle) titleLayout.setAlignment(tabtitle, Qt.AlignCenter) btnlayout = QGridLayout() tmpnum = 0 for inum in range(0,56): irow = tmpnum // g_cols icol = tmpnum % g_cols tmpnum += 1 btnlayout.setRowMinimumHeight(irow, 80) tmpbtn = MyButton("") tmpbtn.setMyarg(None) # tmpbtn.setFixedHeight(20) tmpbtn.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)) tmpbtn.setStyleSheet("border: 1px solid rgb(55,55,255,100);background-color: rgba(255,255,255,20);font-size:16px;") self.connect(tmpbtn, SIGNAL("myslot(PyQt_PyObject)"), self.myslot) tmpbtn.setAutoDefault(False) self.btngroup.addButton(tmpbtn, inum+1) # stusn is from 1 start btnlayout.addWidget(tmpbtn, irow, icol) self.btn_start.setIcon(QIcon("image/start.png")) self.btn_start.setStyleSheet("border: 1px solid yellow;") self.btn_start.setFixedHeight(40) self.btn_start.setFixedWidth(100) self.btn_start.setFont(QFont('宋体', 18)) # self.choicenum_text.setFixedHeight(45) # self.choicenum_text.setFixedWidth(60) ## Set the combox number style self.choicenum_text.setFont(QFont('Courier New', 20)) self.choicenum_text.setFixedHeight(45) self.choicenum_text.setStyleSheet("border: 2px solid blue; color:red;font-weight:light;font-size:26px;\ border-radius: 6px; \ min-width: 2em; ") self.choicenum_text.setEditable(True) self.choicenum_text.lineEdit().setReadOnly(True); self.choicenum_text.lineEdit().setAlignment(Qt.AlignCenter); model = self.choicenum_text.model() for row in list(range(1, 7)): item = QStandardItem(str(row)) item.setTextAlignment(Qt.AlignCenter) item.setForeground(QColor('red')) item.setBackground(QColor(0,200,50, 130)) model.appendRow(item) self.choicenum_text.setCurrentIndex(2) # self.choicenum_text.setStyleSheet ("QComboBox::drop-down {border-width: 100px;}") # self.choicenum_text.setStyleSheet ("QComboBox::down-arrow {image: url(image/downarrow.png);top: 10px;left: 1px;}") bottomlayout = QHBoxLayout() bottomlayout.setSizeConstraint(QLayout.SetFixedSize) bottomlayout.addStretch(10) bottomlayout.addWidget(self.btn_start) bottomlayout.setSpacing(5) bottomlayout.addWidget(self.choicenum_text) tab1layout = QVBoxLayout() tab1layout.addLayout(titleLayout) tab1layout.addLayout(btnlayout) tab1layout.addLayout(bottomlayout) self.w1.setLayout(tab1layout) self.w1.setStyleSheet("background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #228888);") def startChoice(self, usernum="", oldbtn=""): # print(oldbtn, 1) if oldbtn == "": self.dict_choices = {} strwhere = " and classname like '" + self.g_curClassName + "'" allstudent = [] lstrecord = [] query = QSqlQuery(self.db) query.exec_("select stusn from tmprecord where 1=1 " + strwhere) while(query.next()): lstrecord.append(query.value(0)) # print(lstrecord, 'record', "select stusn from student where stusn not in " + str(tuple(lstrecord))) query.exec_("select stusn from student where stusn not in " + str(tuple(lstrecord)) + strwhere) while(query.next()): allstudent.append(query.value(0)) if usernum == "": nums = int(self.choicenum_text.currentText()) else: nums = usernum if nums >= len(allstudent): query.exec_("delete from tmprecord where 1=1 " + strwhere) #delete tmp date no today allstudent = [] query.exec_("select stusn from student where 1=1 " + strwhere) while(query.next()): allstudent.append(query.value(0)) if oldbtn == "": random.seed() lstchoices = random.sample(allstudent, nums) for ibtn in lstchoices: self.dict_choices[ibtn] = "111" self.group_animation.start() QTimer.singleShot(1200, self.stopmovie) else: random.seed() otherbtn = random.sample(allstudent, 1)[0] # self.btngroup.button(int(otherbtn)).setFocus() self.dict_choices.pop(oldbtn) self.dict_choices[otherbtn] = '111' self.stopmovie() self.btnSysMenu.setFocus() def stopmovie(self): self.group_animation.stop() for isn in self.studentSnlst: # print(isn) self.btngroup.button(int(isn[0])).setStyleSheet(stylesheetstr_old) self.btngroup.button(int(isn[0])).setIcon(QIcon()) classname = self.tabWidget.tabText(0) query = QSqlQuery(self.db) today = datetime.date.today() for ibtn in self.dict_choices: self.btngroup.button(int(ibtn)).setStyleSheet(stylesheetstr_new) query.exec_("select count(*) from tmprecord where stusn='" + str(ibtn) + "'") query.next() if query.value(0) == 0: query.prepare("insert into tmprecord (classname, stusn, datequestion) values (:classname, :stusn, :datequestion)") query.bindValue(":classname", classname) query.bindValue(":stusn", ibtn) query.bindValue(":datequestion", today) query.exec_() def answerRight(self): # print(self.g_curbtn) value = self.g_curbtn if value not in self.dict_choices: return self.btngroup.button(int(value)).setIcon(QIcon("image/smile.png")) self.btngroup.button(int(value)).setIconSize(QSize(20,20)) query = QSqlQuery(self.db) query.exec_("select rightquestions from student where stusn='" + value + "'") query.next() studentRightQuestions = query.value(0) + 1 query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'") ########### if self.dict_choices[value] == "101": query.exec_("select wrongquestions from student where stusn='" + value + "'") query.next() studentWrongQuestions = query.value(0) - 1 query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'") self.dict_choices[value] = "011" def answerWrong(self): value = self.g_curbtn if value not in self.dict_choices: return self.btngroup.button(int(value)).setIcon(QIcon("image/cry.png")) self.btngroup.button(int(value)).setIconSize(QSize(20,20)) # self.btngroup.button(int(value)).setStyleSheet("border-image: url(image/ex_stu.png);") query = QSqlQuery(self.db) query.exec_("select wrongquestions from student where stusn='" + value + "'") query.next() studentWrongQuestions = query.value(0) + 1 query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'") if self.dict_choices[value] == "011": query.exec_("select rightquestions from student where stusn='" + value + "'") query.next() studentRightQuestions = query.value(0) - 1 query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'") self.dict_choices[value] = "101" def resetStudent(self): value = self.g_curbtn if value not in self.dict_choices: return query = QSqlQuery(self.db) if self.dict_choices[value] == "011": query.exec_("select rightquestions from student where stusn='" + value + "'") query.next() studentRightQuestions = query.value(0) - 1 query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'") if self.dict_choices[value] == "101": query.exec_("select wrongquestions from student where stusn='" + value + "'") query.next() studentWrongQuestions = query.value(0) - 1 query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'") self.startChoice(usernum=1, oldbtn=value) # print("---reset___") # curmenu.actions()[0].setEnabled(True) # curmenu.actions()[1].setEnabled(True) # self.choiceOneStudent(value) def createDb(self): conn = sqlite3.connect("studentNew.db") cur = conn.cursor() sqlstr = 'create table student (id integer primary key, \ classname varchar(20), \ stusn varchar(20), \ stuname varchar(20), \ rightquestions integer, \ wrongquestions integer, \ FOREIGN KEY(classname) REFERENCES classtable(classname))' # print(sqlstr) sqlstr2 = 'create table tmprecord (id integer primary key, \ classname varchar(20), \ stusn varchar(20), \ datequestion date)' sqlstr3 = 'create table classtable (classname varchar(20) PRIMARY KEY)' cur.execute(sqlstr3) conn.commit() cur.execute(sqlstr2) conn.commit() cur.execute(sqlstr) conn.commit() strdelete = "delete from student where 1=1" cur.execute(strdelete) conn.commit() strdelete = "delete from tmprecord where 1=1" cur.execute(strdelete) conn.commit() # print(sqlstr2) # cur.execute(sqlstr) # conn.commit() # cur.execute(sqlstr2) # conn.commit() # insert example data strsql = "insert into classtable values (?)" cur.execute(strsql, ("三(3)班",)) conn.commit() cur.execute(strsql, ("三(4)班",)) conn.commit() a03lst = ["曾忆谊","赵佳泉","翁文秀","林珑","郑铭洁","林泽思","吴崇霖","陈思嘉","欧阳月孜","郭展羽","詹伟哲","黄佳仪","杨秋霞","周奕子","林楚杰","欧伊涵","许腾誉","陈唯凯","陈树凯","林彦君","张钰佳","高锴","杨博凯","林妙菲","林楚鸿","陈展烯","姚静茵","吴欣桐","范思杰","肖佳","马思广","许一帆","姚奕帆","陈海珣","吴黛莹","吴育桐","肖凯帆","林欣阳","叶茂霖","姚楷臻","陈嘉豪","陈琦","杨子楷","陈炎宏","陈幸仪","杨景畅","罗暖婷","郑馨"] a04lst = ["罗恩琪","王可","曾祥威","谢濡婷","温嘉凯","许洁仪","肖欣淇","陈凯佳","林天倩","李乐海","吴文慧","黄文婷","万誉","陈进盛","张裕涵","陈振嘉","王巧玲","林珮琪","陈炜楷","杨健","赵泽锴","张凤临","蔡子丹","陈烨杰","廖妍希","林树超","夏培轩","陈锦森","李星","蔡依婷","姚容创","姚凯扬","沈嘉克","周凡","张玉川","邱金迅","陈菲敏","陈星翰","朱煜楷","郑泽洪","钱剑非","罗奕丰","陈杜炜","林知钦"] strsql = "insert into student values (?, ?, ?, ?,?,?)" for i in list(range(0,len(a03lst))): cur.execute(strsql, (None, "三(3)班", str(i+1).zfill(2), a03lst[i], 0, 0)) conn.commit() strsql = "insert into student values (?, ?, ?, ?,?,?)" for i in list(range(0,len(a04lst))): cur.execute(strsql, (None, "三(4)班", str(i+1).zfill(2), a04lst[i], 0, 0)) conn.commit() cur.close()
class GotoLineWidget( QWidget ): " goto bar widget " maxHistory = 12 def __init__( self, editorsManager, parent = None ): QWidget.__init__( self, parent ) self.editorsManager = editorsManager self.__gotoHistory = [] # Common graphics items closeButton = QToolButton( self ) closeButton.setToolTip( "Click to close the dialog (ESC)" ) closeButton.setIcon( PixmapCache().getIcon( "close.png" ) ) closeButton.clicked.connect( self.hide ) lineLabel = QLabel( self ) lineLabel.setText( "Goto line:" ) self.linenumberEdit = QComboBox( self ) self.linenumberEdit.setEditable( True ) self.linenumberEdit.setInsertPolicy( QComboBox.InsertAtTop ) self.linenumberEdit.setAutoCompletion( False ) self.linenumberEdit.setDuplicatesEnabled( False ) sizePolicy = QSizePolicy( QSizePolicy.Expanding, QSizePolicy.Fixed ) sizePolicy.setHorizontalStretch( 0 ) sizePolicy.setVerticalStretch( 0 ) sizePolicy.setHeightForWidth( self.linenumberEdit.sizePolicy().hasHeightForWidth() ) self.linenumberEdit.setSizePolicy( sizePolicy ) self.validator = QIntValidator( 1, 100000, self ) self.linenumberEdit.setValidator( self.validator ) self.linenumberEdit.editTextChanged.connect( self.__onEditTextChanged ) self.linenumberEdit.lineEdit().returnPressed.connect( self.__onEnter ) self.goButton = QToolButton( self ) self.goButton.setToolTip( "Click to jump to the line (ENTER)" ) self.goButton.setIcon( PixmapCache().getIcon( "gotoline.png" ) ) self.goButton.setFocusPolicy( Qt.NoFocus ) self.goButton.setEnabled( False ) self.goButton.clicked.connect( self.__onGo ) spacer = QWidget() spacer.setFixedWidth( 1 ) horizontalLayout = QHBoxLayout( self ) horizontalLayout.setMargin( 0 ) horizontalLayout.addWidget( closeButton ) horizontalLayout.addWidget( lineLabel ) horizontalLayout.addWidget( self.linenumberEdit ) horizontalLayout.addWidget( self.goButton ) horizontalLayout.addWidget( spacer ) return def keyPressEvent( self, event ): """ Handles the key press events """ if event.key() == Qt.Key_Escape: activeWindow = self.editorsManager.currentWidget() if activeWindow: activeWindow.setFocus() event.accept() self.hide() return def __updateHistory( self, txt ): " Updates the combo history " while txt in self.__gotoHistory: self.__gotoHistory.remove( txt ) self.__gotoHistory = [ txt ] + self.__gotoHistory self.__gotoHistory = self.__gotoHistory[ : GotoLineWidget.maxHistory ] self.linenumberEdit.clear() self.linenumberEdit.addItems( self.__gotoHistory ) return def show( self ): " Overriden show() method " self.linenumberEdit.lineEdit().selectAll() QWidget.show( self ) self.activateWindow() return def setFocus( self ): " Overridded setFocus " self.linenumberEdit.setFocus() return def updateStatus( self ): " Triggered when the current tab is changed " currentWidget = self.editorsManager.currentWidget() status = currentWidget.getType() in \ [ MainWindowTabWidgetBase.PlainTextEditor, MainWindowTabWidgetBase.VCSAnnotateViewer ] self.linenumberEdit.setEnabled( status ) self.goButton.setEnabled( status and self.linenumberEdit.currentText() != "" ) return def __onGo( self ): " Triggered when the 'Go!' button is clicked " if self.linenumberEdit.currentText() == "": return currentWidget = self.editorsManager.currentWidget() if not currentWidget.getType() in \ [ MainWindowTabWidgetBase.PlainTextEditor, MainWindowTabWidgetBase.VCSAnnotateViewer ]: return txt = self.linenumberEdit.currentText() self.__updateHistory( txt ) editor = currentWidget.getEditor() line = min( int( txt ), editor.lines() ) - 1 editor.setCursorPosition( line, 0 ) editor.ensureLineVisible( line ) currentWidget.setFocus() return def __onEditTextChanged( self, text ): " Triggered when the text has been changed " self.goButton.setEnabled( text != "" ) return def __onEnter( self ): " Triggered when 'Enter' or 'Return' is clicked " self.__onGo() return def selectAll( self ): " Selects the line edit content " self.linenumberEdit.lineEdit().selectAll() return
class LayerSelectionPage(QFrame): #TODO. Filtering, (visible) row selection, multi selection colparams = ((0,65,'Name'), (1,235,'Title'), (2,350,'Keywords')) XFER_BW = 40 def __init__(self, parent=None): super(LayerSelectionPage, self).__init__(parent) self.parent = parent #convenience link self.confconn_link = self.parent.parent.confconn #flag top prevent read read action on keyword delete. New logic makes this redundant #self.keywordbypass = False QToolTip.setFont(QFont('SansSerif', 10)) #label filterlabel = QLabel('Filter') availablelabel = QLabel('Available Layers') selectionlabel = QLabel('Layer Selections') keywordlabel = QLabel('Keyword') explainlabel = QLabel("Edit Group assignments using this dialog or to simply initialise the Layer-Config just click 'Finish'") #selection buttons chooseallbutton = QPushButton('>>') chooseallbutton.setFixedWidth(self.XFER_BW) chooseallbutton.clicked.connect(self.doChooseAllClickAction) choosebutton = QPushButton('>') choosebutton.setFixedWidth(self.XFER_BW) choosebutton.clicked.connect(self.doChooseClickAction) rejectbutton = QPushButton('<') rejectbutton.setFixedWidth(self.XFER_BW) rejectbutton.clicked.connect(self.doRejectClickAction) rejectallbutton = QPushButton('<<') rejectallbutton.setFixedWidth(self.XFER_BW) rejectallbutton.clicked.connect(self.doRejectAllClickAction) #operation buttons finishbutton = QPushButton('Finish') finishbutton.setToolTip('Finish and Close layer selection dialog') finishbutton.clicked.connect(self.parent.close) resetbutton = QPushButton('Reset') resetbutton.font() resetbutton.setToolTip('Read Layer from LDS GetCapabilities request. Overwrites current Layer Config') resetbutton.clicked.connect(self.doResetClickAction) self.available_sfpm = LDSSFPAvailableModel(self) self.selection_sfpm = LDSSFPSelectionModel(self) self.available_sfpm.setSourceModel(self.parent.available_model) self.selection_sfpm.setSourceModel(self.parent.selection_model) #textedits filteredit = QLineEdit('') filteredit.setToolTip('Filter Available-Layers pane (filter operates across Name and Title fields and accepts Regex expressions)') filteredit.textChanged.connect(self.available_sfpm.setActiveFilter) self.keywordcombo = QComboBox() self.keywordcombo.setToolTip('Select or Add a unique identifier to be saved in layer config (keyword)') self.keywordcombo.addItems(list(self.confconn_link.assigned)) self.keywordcombo.setEditable(True) self.keywordcombo.activated.connect(self.doKeyComboChangeAction) lgindex = self.confconn_link.getLayerGroupIndex(self.confconn_link.lgval,col=1) lgentry = self.confconn_link.lglist[lgindex] if LU.assessNone(lgindex) else None #keywordedit = self.keywordcombo.lineEdit().text().toUtf8().data().decode('utf8')# for writing #if no entry or layer indicated then blank self.keywordcombo.lineEdit().setText('' if lgentry is None or lgentry[0]==LORG.LAYER else lgentry[1])#self.confconn_link.lgval)#TODO. group only #header headmodel = QStandardItemModel() headmodel.setHorizontalHeaderLabels([i[2] for i in self.colparams][:self.parent.available_model.columnCount()]) headview1 = QHeaderView(Qt.Horizontal) headview1.setModel(headmodel) headview1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) headview2 = QHeaderView(Qt.Horizontal) headview2.setModel(headmodel) headview2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) #table self.available = QTableView() self.available.setSelectionBehavior(QAbstractItemView.SelectRows) self.available.setSelectionMode(QAbstractItemView.MultiSelection) self.selection = QTableView() self.selection.setSelectionBehavior(QAbstractItemView.SelectRows) self.selection.setSelectionMode(QAbstractItemView.MultiSelection) #interesting, must set model after selection attributes but before headers else row selections/headers don't work properly self.available.setModel(self.available_sfpm) self.selection.setModel(self.selection_sfpm) self.available.setSortingEnabled(True) self.available.setHorizontalHeader(headview1) self.selection.setSortingEnabled(True) self.selection.setHorizontalHeader(headview2) for cp in self.colparams: self.available.setColumnWidth(cp[0],cp[1]) self.selection.setColumnWidth(cp[0],cp[1]) self.available.verticalHeader().setVisible(False) self.available.horizontalHeader().setVisible(True) self.selection.verticalHeader().setVisible(False) self.selection.horizontalHeader().setVisible(True) #layout vbox00 = QVBoxLayout() vbox00.addWidget(availablelabel) vbox00.addWidget(self.available) vbox01 = QVBoxLayout() vbox01.addWidget(chooseallbutton) vbox01.addWidget(choosebutton) vbox01.addWidget(rejectbutton) vbox01.addWidget(rejectallbutton) vbox02 = QVBoxLayout() vbox02.addWidget(selectionlabel) vbox02.addWidget(self.selection) vbox10 = QVBoxLayout() vbox10.addWidget(filterlabel) vbox10.addWidget(filteredit) hbox12 = QHBoxLayout() hbox12.addWidget(keywordlabel) hbox12.addStretch(1) #hbox12.addWidget(inspbutton) #hbox12.addWidget(addbutton) #hbox12.addWidget(delbutton) vbox12 = QVBoxLayout() vbox12.addLayout(hbox12) vbox12.addWidget(self.keywordcombo) #00|01|02 #10|11|12 grid0 = QGridLayout() grid0.addLayout(vbox00,1,0) grid0.addLayout(vbox01,1,1) grid0.addLayout(vbox02,1,2) grid0.addLayout(vbox10,0,0) grid0.addLayout(vbox12,0,2) hbox2 = QHBoxLayout() hbox2.addWidget(resetbutton) hbox2.addStretch(1) hbox2.addWidget(explainlabel) hbox2.addWidget(finishbutton) #gbox1.setLayout(hbox2) vbox3 = QVBoxLayout() vbox3.addLayout(grid0) #vbox3.addLayout(hbox3) #vbox3.addWidget(line0) vbox3.addLayout(hbox2) self.setLayout(vbox3) def doChooseAllClickAction(self): '''Moves the lot to Selected''' #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode(LQ.readWidgetText(self.keywordcombo.lineEdit().text())) if not self.checkKeyword(ktext): return #------------------------------ self.parent.signalModels(self.parent.STEP.PRE) #self.parent.selection_model.mdata += self.parent.available_model.mdata self.parent.selection_model.initData(self.confconn_link.complete) self.parent.available_model.initData([]) self.parent.signalModels(self.parent.STEP.POST) #------------------------------ self.parent.writeKeysToLayerConfig(ktext) #self.confconn_link.setupAssignedLayerList() if self.keywordcombo.findText(ktext) == -1: self.keywordcombo.addItem(ktext) def doChooseClickAction(self): '''Takes available selected and moves to selection''' #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode(LQ.readWidgetText(self.keywordcombo.lineEdit().text())) #ktext = str(self.keywordcombo.lineEdit().text()) if not self.checkKeyword(ktext): return #------------------------------ select = self.available.selectionModel() if select.hasSelection(): self.transferSelectedRows(select.selectedRows(),self.available_sfpm,self.selection_sfpm) #------------------------------ self.parent.writeKeysToLayerConfig(ktext) #self.confconn_link.assigned = self.confconn_link.setupAssignedLayerList() # -1 to indicate no index since 0,1,... are valid if self.keywordcombo.findText(ktext) == -1: self.keywordcombo.addItem(ktext) else: ldslog.warn('L2R > Transfer action without selection') #TRACE# #pdb.set_trace() self.available.clearSelection() def transferSelectedRows(self,indices,from_model,to_model): tlist = [] for proxymodelindex in indices: transfer = from_model.getData(proxymodelindex) tlist.append((proxymodelindex,transfer),) to_model.addData([t[1] for t in tlist]) from_model.delData([t[0] for t in tlist]) return tlist def doRejectClickAction(self): '''Takes available selected and moves to selection''' #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode(LQ.readWidgetText(self.keywordcombo.lineEdit().text())) if not self.checkKeyword(ktext): return #------------------------------ select = self.selection.selectionModel() if select.hasSelection(): tlist = self.transferSelectedRows(select.selectedRows(),self.selection_sfpm,self.available_sfpm) #------------------------------ kindex = self.keywordcombo.findText(ktext) remainder = self.parent.deleteKeysFromLayerConfig([ll[1][0] for ll in tlist],ktext) if remainder > 0 and kindex == -1: #items+newkey -> add self.parent.writeKeysToLayerConfig(ktext) self.keywordcombo.addItem(ktext) elif remainder == 0 and kindex > -1: #empty+oldkey -> del self.keywordcombo.removeItem(kindex) self.keywordcombo.clearEditText() else: ldslog.warn('R2L < Transfer action without selection') #TRACE# #pdb.set_trace() self.selection.clearSelection() def doRejectAllClickAction(self): #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode(LQ.readWidgetText(self.keywordcombo.lineEdit().text())) if not self.checkKeyword(ktext): return #------------------------------ self.parent.deleteKeysFromLayerConfig([ll[0] for ll in self.parent.selection_model.mdata],ktext) #------------------------------ self.parent.signalModels(self.parent.STEP.PRE) #self.parent.available_model.mdata += self.parent.selection_model.mdata self.parent.available_model.initData(self.confconn_link.complete) self.parent.selection_model.initData([]) self.parent.signalModels(self.parent.STEP.POST) #------------------------------ #self.confconn_link.setupAssignedLayerList() #self.keywordbypass = True self.keywordcombo.removeItem(self.keywordcombo.findText(ktext)) self.keywordcombo.clearEditText() def doKeyComboChangeAction(self): '''Reset the available pane and if there is anything in the keyword box use this to init the selection pane''' #HACK #if self.keywordbypass: # self.keywordbypass = False # return #------------------------------ #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode(LQ.readWidgetText(self.keywordcombo.lineEdit().text())) #------------------------------ av_sl = self.parent.splitData(ktext,self.confconn_link.complete) #av_sl = self.parent.splitData(ktext,self.confconn_link.complete) self.parent.signalModels(self.parent.STEP.PRE) self.parent.available_model.initData(av_sl[0]) self.parent.selection_model.initData(av_sl[1]) self.parent.signalModels(self.parent.STEP.POST) def doResetClickAction(self): '''Dumps the LC and rebuilds from a fresh read of the caps doc''' #int warning (QWidget parent, QString title, QString text, QString button0Text, QString button1Text = QString(), QString button2Text = QString(), int defaultButtonNumber = 0, int escapeButtonNumber = -1) ans = QMessageBox.warning(self, "Reset","This action will overwrite your Layer Configuration using the current LDS settings (potentially adding new or removing layers). Continue?","Continue","Cancel") if ans: #Cancel ldslog.warn('Cancelling Reset operation') return #Continue ldslog.warn('Reset Layer Config') self.parent.resetLayers() self.keywordcombo.clear() def checkKeyword(self,ktext): '''Checks keyword isn't null and isn't part of the LDS supplied keywords''' if LU.assessNone(ktext) is None: QMessageBox.about(self, "Keyword Required","Please enter a Keyword to assign Layer(s) to") return False if ktext in self.confconn_link.reserved: QMessageBox.about(self, "Reserved Keyword","'{}' is a reserved keyword, please select again".format(ktext)) return False return True
class Widget(QWidget): def __init__(self, dockwidget): super(Widget, self).__init__(dockwidget) self._document = None self._fileSelector = QComboBox(editable=True, insertPolicy=QComboBox.NoInsert) widgets.drag.ComboDrag(self._fileSelector).role = Qt.UserRole self._fileSelector.lineEdit().setReadOnly(True) self._fileSelector.lineEdit().setFocusPolicy(Qt.NoFocus) self._stopButton = QToolButton() self._playButton = QToolButton() self._timeSlider = QSlider(Qt.Horizontal, tracking=False, singleStep=500, pageStep=5000, invertedControls=True) self._display = Display() self._tempoFactor = QSlider(Qt.Vertical, minimum=-50, maximum=50, singleStep=1, pageStep=5) grid = QGridLayout(spacing=0) self.setLayout(grid) grid.addWidget(self._fileSelector, 0, 0, 1, 3) grid.addWidget(self._stopButton, 1, 0) grid.addWidget(self._playButton, 1, 1) grid.addWidget(self._timeSlider, 1, 2) grid.addWidget(self._display, 2, 0, 1, 3) grid.addWidget(self._tempoFactor, 0, 3, 3, 1) # size policy of combo p = self._fileSelector.sizePolicy() p.setHorizontalPolicy(QSizePolicy.Ignored) self._fileSelector.setSizePolicy(p) # size policy of combo popup p = self._fileSelector.view().sizePolicy() p.setHorizontalPolicy(QSizePolicy.MinimumExpanding) self._fileSelector.view().setSizePolicy(p) self._player = player.Player() self._outputCloseTimer = QTimer(interval=60000, singleShot=True, timeout=self.closeOutput) self._timeSliderTicker = QTimer(interval=200, timeout=self.updateTimeSlider) self._fileSelector.activated[int].connect(self.slotFileSelected) self._tempoFactor.valueChanged.connect(self.slotTempoChanged) self._timeSlider.valueChanged.connect(self.slotTimeSliderChanged) self._timeSlider.sliderMoved.connect(self.slotTimeSliderMoved) self._player.beat.connect(self.updateDisplayBeat) self._player.time.connect(self.updateDisplayTime) self._player.stateChanged.connect(self.slotPlayerStateChanged) self.slotPlayerStateChanged(False) dockwidget.mainwindow().currentDocumentChanged.connect( self.loadResults) app.documentLoaded.connect(self.slotUpdatedFiles) app.jobFinished.connect(self.slotUpdatedFiles) app.aboutToQuit.connect(self.stop) midihub.aboutToRestart.connect(self.slotAboutToRestart) midihub.settingsChanged.connect(self.clearMidiSettings, -100) midihub.settingsChanged.connect(self.readMidiSettings) app.documentClosed.connect(self.slotDocumentClosed) app.translateUI(self) self.readMidiSettings() d = dockwidget.mainwindow().currentDocument() if d: self.loadResults(d) def translateUI(self): self._tempoFactor.setToolTip(_("Tempo")) def slotAboutToRestart(self): self.stop() self._player.set_output(None) def clearMidiSettings(self): """Called first when settings are changed.""" self.stop() self._outputCloseTimer.stop() self._player.set_output(None) def readMidiSettings(self): """Called after clearMidiSettings(), and on first init.""" pass def openOutput(self): """Called when playing starts. Ensures an output port is opened.""" self._outputCloseTimer.stop() if not self._player.output(): p = QSettings().value("midi/player/output_port", midihub.default_output(), type("")) o = midihub.output_by_name(p) if o: self._player.set_output(output.Output(o)) def closeOutput(self): """Called when the output close timer fires. Closes the output.""" self._player.set_output(None) def slotPlayerStateChanged(self, playing): ac = self.parentWidget().actionCollection # setDefaultAction also adds the action for b in self._stopButton, self._playButton: while b.actions(): b.removeAction(b.actions()[0]) if playing: self._timeSliderTicker.start() self._stopButton.setDefaultAction(ac.midi_stop) self._playButton.setDefaultAction(ac.midi_pause) else: self._timeSliderTicker.stop() self.updateTimeSlider() self._stopButton.setDefaultAction(ac.midi_restart) self._playButton.setDefaultAction(ac.midi_play) # close the output if the preference is set if QSettings().value("midi/close_outputs", False, bool): self._outputCloseTimer.start() def play(self): """Starts the MIDI player, opening an output if necessary.""" if not self._player.is_playing() and not self._player.has_events(): self.restart() self.openOutput() if not self._player.output(): self._display.statusMessage(_("No output found!")) self._player.start() def stop(self): """Stops the MIDI player.""" self._player.stop() def restart(self): """Restarts the MIDI player. If another file is in the file selector, or the file was updated, the new file is loaded. """ self._player.seek(0) self.updateTimeSlider() self._display.reset() if self._document: files = midifiles.MidiFiles.instance(self._document) index = self._fileSelector.currentIndex() if files and (files.song(index) is not self._player.song()): self.loadSong(index) def slotTempoChanged(self, value): """Called when the user drags the tempo.""" # convert -50 to 50 to 0.5 to 2.0 factor = 2**(value / 50.0) self._player.set_tempo_factor(factor) self._display.setTempo("{0}%".format(int(factor * 100))) def slotTimeSliderChanged(self, value): self._player.seek(value) self._display.setTime(value) if self._player.song(): self._display.setBeat(*self._player.song().beat(value)[1:]) def slotTimeSliderMoved(self, value): self._display.setTime(value) if self._player.song(): self._display.setBeat(*self._player.song().beat(value)[1:]) def updateTimeSlider(self): if not self._timeSlider.isSliderDown(): with qutil.signalsBlocked(self._timeSlider): self._timeSlider.setMaximum(self._player.total_time()) self._timeSlider.setValue(self._player.current_time()) def updateDisplayBeat(self, measnum, beat, num, den): if not self._timeSlider.isSliderDown(): self._display.setBeat(measnum, beat, num, den) def updateDisplayTime(self, time): if not self._timeSlider.isSliderDown(): self._display.setTime(time) def slotUpdatedFiles(self, document): """Called when there are new MIDI files.""" if document == self.parentWidget().mainwindow().currentDocument(): self.loadResults(document) def loadResults(self, document): self._document = document files = midifiles.MidiFiles.instance(document) self._fileSelector.setModel(files.model()) if files: self._fileSelector.setCurrentIndex(files.current) if not self._player.is_playing(): self.loadSong(files.current) def loadSong(self, index): files = midifiles.MidiFiles.instance(self._document) self._player.set_song(files.song(index)) m, s = divmod(self._player.total_time() // 1000, 60) name = self._fileSelector.currentText() self.updateTimeSlider() self._display.reset() self._display.statusMessage(_("midi lcd screen", "LOADED"), name, _("midi lcd screen", "TOTAL"), "{0}:{1:02}".format(m, s)) def slotFileSelected(self, index): if self._document: self._player.stop() files = midifiles.MidiFiles.instance(self._document) if files: files.current = index self.restart() def slotDocumentClosed(self, document): if document == self._document: self._document = None self._fileSelector.clear() self._player.stop() self._player.clear() self.updateTimeSlider() self._display.reset()
class Printing(preferences.Group): def __init__(self, page): super(Printing, self).__init__(page) layout = QGridLayout(spacing=1) self.setLayout(layout) self.messageLabel = QLabel(wordWrap=True) self.printCommandLabel = QLabel() self.printCommand = widgets.urlrequester.UrlRequester() self.printCommand.setFileMode(QFileDialog.ExistingFile) self.printCommand.changed.connect(page.changed) self.printDialogCheck = QCheckBox(toggled=page.changed) self.resolutionLabel = QLabel() self.resolution = QComboBox(editable=True, editTextChanged=page.changed) self.resolution.addItems("300 600 1200".split()) self.resolution.lineEdit().setInputMask("9000") layout.addWidget(self.messageLabel, 0, 0, 1, 2) layout.addWidget(self.printCommandLabel, 1, 0) layout.addWidget(self.printCommand, 1, 1) layout.addWidget(self.printDialogCheck, 2, 0, 1, 2) layout.addWidget(self.resolutionLabel, 3, 0) layout.addWidget(self.resolution, 3, 1) app.translateUI(self) def translateUI(self): self.setTitle(_("Printing Music")) self.messageLabel.setText(_( "Here you can enter a command to print a PDF or PostScript file. " "See the Help page for more information about printing music.")) self.printCommandLabel.setText(_("Printing command:")) self.printCommand.setToolTip('<qt>' + _( "The printing command is used to print a PostScript or PDF file. " "On Linux you don't need this, but on Windows and Mac OS X you can " "provide a command to avoid that PDF documents are being printed " "using raster images, which is less optimal.\n" "<code>$pdf</code> gets replaced with the PDF filename, or alternatively, " "<code>$ps</code> is replaced with the PostScript filename. " "<code>$printer</code> is replaced with the printer's name to use.")) self.printDialogCheck.setText(_("Use Frescobaldi's print dialog")) self.printDialogCheck.setToolTip('<qt>' + _( "If enabled, Frescobaldi will show the print dialog and create a " "PDF or PostScript document containing only the selected pages " "to print. Otherwise, the command is called directly and is expected " "to show a print dialog itself.")) self.resolutionLabel.setText(_("Resolution:")) self.resolution.setToolTip(_( "Set the resolution if Frescobaldi prints using raster images.")) def loadSettings(self): s = QSettings() s.beginGroup("helper_applications") self.printCommand.setPath(s.value("printcommand", "", type(""))) self.printDialogCheck.setChecked(s.value("printcommand/dialog", False, bool)) with qutil.signalsBlocked(self.resolution): self.resolution.setEditText(format(s.value("printcommand/dpi", 300, int))) def saveSettings(self): s= QSettings() s.beginGroup("helper_applications") s.setValue("printcommand", self.printCommand.path()) s.setValue("printcommand/dialog", self.printDialogCheck.isChecked()) s.setValue("printcommand/dpi", int(self.resolution.currentText()))
class Dialog(QDialog): def __init__(self, parent=None): super(Dialog, self).__init__(parent) self._filename = None self._page = None self._rect = None self.imageViewer = widgets.imageviewer.ImageViewer() self.dpiLabel = QLabel() self.dpiCombo = QComboBox(insertPolicy=QComboBox.NoInsert, editable=True) self.dpiCombo.lineEdit().setCompleter(None) self.dpiCombo.setValidator( QDoubleValidator(10.0, 1200.0, 4, self.dpiCombo)) self.dpiCombo.addItems( [format(i) for i in (72, 100, 200, 300, 600, 1200)]) self.colorButton = widgets.colorbutton.ColorButton() self.colorButton.setColor(QColor(Qt.white)) self.crop = QCheckBox() self.antialias = QCheckBox(checked=True) self.dragfile = QPushButton(icons.get("image-x-generic"), None, None) self.fileDragger = FileDragger(self.dragfile) self.buttons = QDialogButtonBox(QDialogButtonBox.Close) self.copyButton = self.buttons.addButton('', QDialogButtonBox.ApplyRole) self.copyButton.setIcon(icons.get('edit-copy')) self.saveButton = self.buttons.addButton('', QDialogButtonBox.ApplyRole) self.saveButton.setIcon(icons.get('document-save')) layout = QVBoxLayout() self.setLayout(layout) layout.addWidget(self.imageViewer) controls = QHBoxLayout() layout.addLayout(controls) controls.addWidget(self.dpiLabel) controls.addWidget(self.dpiCombo) controls.addWidget(self.colorButton) controls.addWidget(self.crop) controls.addWidget(self.antialias) controls.addStretch() controls.addWidget(self.dragfile) layout.addWidget(widgets.Separator()) layout.addWidget(self.buttons) app.translateUI(self) self.readSettings() self.finished.connect(self.writeSettings) self.dpiCombo.editTextChanged.connect(self.drawImage) self.colorButton.colorChanged.connect(self.drawImage) self.antialias.toggled.connect(self.drawImage) self.crop.toggled.connect(self.cropImage) self.buttons.rejected.connect(self.reject) self.copyButton.clicked.connect(self.copyToClipboard) self.saveButton.clicked.connect(self.saveAs) qutil.saveDialogSize(self, "copy_image/dialog/size", QSize(480, 320)) def translateUI(self): self.setCaption() self.dpiLabel.setText(_("DPI:")) self.colorButton.setToolTip(_("Paper Color")) self.crop.setText(_("Auto-crop")) self.antialias.setText(_("Antialias")) self.dragfile.setText(_("Drag")) self.dragfile.setToolTip(_("Drag the image as a PNG file.")) self.copyButton.setText(_("&Copy to Clipboard")) self.saveButton.setText(_("&Save As...")) self.imageViewer.setWhatsThis( _( #xgettext:no-python-format "<p>\n" "Clicking toggles the display between 100% size and window size. " "Drag to copy the image to another application. " "Drag with Ctrl (or {command}) to scroll a large image.\n" "</p>\n" "<p>\n" "You can also drag the small picture icon in the bottom right, " "which drags the actual file on disk, e.g. to an e-mail message.\n" "</p>").format(command="\u2318")) def readSettings(self): s = QSettings() s.beginGroup('copy_image') self.dpiCombo.setEditText(s.value("dpi", "100", type(""))) self.colorButton.setColor( s.value("papercolor", QColor(Qt.white), QColor)) self.crop.setChecked(s.value("autocrop", False, bool)) self.antialias.setChecked(s.value("antialias", True, bool)) def writeSettings(self): s = QSettings() s.beginGroup('copy_image') s.setValue("dpi", self.dpiCombo.currentText()) s.setValue("papercolor", self.colorButton.color()) s.setValue("autocrop", self.crop.isChecked()) s.setValue("antialias", self.antialias.isChecked()) def setCaption(self): if self._filename: filename = os.path.basename(self._filename) else: filename = _("<unknown>") title = _("Image from {filename}").format(filename=filename) self.setWindowTitle(app.caption(title)) def setPage(self, page, rect): self._page = page self._rect = rect self._filename = documents.filename(page.document()) self.fileDragger.basename = os.path.splitext( os.path.basename(self._filename))[0] self.setCaption() self.drawImage() def drawImage(self): dpi = float(self.dpiCombo.currentText() or '100') dpi = max(dpi, self.dpiCombo.validator().bottom()) dpi = min(dpi, self.dpiCombo.validator().top()) options = qpopplerview.RenderOptions() options.setPaperColor(self.colorButton.color()) if self.antialias.isChecked(): if popplerqt4: options.setRenderHint( popplerqt4.Poppler.Document.Antialiasing | popplerqt4.Poppler.Document.TextAntialiasing) else: options.setRenderHint(0) self._image = self._page.image(self._rect, dpi, dpi, options) self.cropImage() def cropImage(self): image = self._image if self.crop.isChecked(): image = image.copy(autoCropRect(image)) self.imageViewer.setImage(image) self.fileDragger.setImage(image) def copyToClipboard(self): QApplication.clipboard().setImage(self.imageViewer.image()) def saveAs(self): if self._filename and not self.imageViewer.image().isNull(): filename = os.path.splitext(self._filename)[0] + ".png" else: filename = 'image.png' filename = QFileDialog.getSaveFileName(self, _("Save Image As"), filename) if filename: if not self.imageViewer.image().save(filename): QMessageBox.critical(self, _("Error"), _("Could not save the image.")) else: self.fileDragger.currentFile = filename