def load(self, dataStream, metaStream, goodStream, badStream): # Load the document file into the editor self.setPlainText(dataStream.readAll()) # Initialize the hash value for the document, which will be equal unless # we read something different from the metadata file. self.cuisineart.reset() self.cuisineart.addData(self.toPlainText()) IMC.metaHash = IMC.documentHash = bytes(self.cuisineart.result()).__repr__() if metaStream is None: # load goodwords, badwords, and take census if goodStream is not None: IMC.goodWordList.load(goodStream) if badStream is not None: IMC.badWordList.load(badStream) self.rebuildMetadata(page=True) # build page table & vocab from scratch else: self.loadMetadata(metaStream) # If the metaData and document hashes now disagree, it is because the metadata # had a DOCHASH value for a different book or version. Warn the user. if IMC.metaHash != IMC.documentHash : pqMsgs.warningMsg(u"The document file and metadata file do not match!", u"Bookmarks, page breaks and other metadata will be wrong! Strongly recommend you not edit or save this book.") # restore hiliting if the user wanted it. Note this can cause a # serious delay if the new book is large. However the alternative is # to not set it on and then we are out of step with the View menu # toggles, so the user has to set it off before loading, or suffer. self.setHighlight(IMC.scannoHiliteSwitch or IMC.spellingHiliteSwitch) # set a different main dict if there was one in the metadata if IMC.bookMainDict is not None: IMC.spellCheck.setMainDict(IMC.bookMainDict)
def load(self, dataStream, metaStream, goodStream, badStream): # Load the document file into the editor self.setPlainText(dataStream.readAll()) # Initialize the hash value for the document, which will be equal unless # we read something different from the metadata file. self.cuisineart.reset() self.cuisineart.addData(self.toPlainText()) IMC.metaHash = IMC.documentHash = bytes( self.cuisineart.result()).__repr__() if metaStream is None: # load goodwords, badwords, and take census if goodStream is not None: IMC.goodWordList.load(goodStream) if badStream is not None: IMC.badWordList.load(badStream) self.rebuildMetadata( page=True) # build page table & vocab from scratch else: self.loadMetadata(metaStream) # If the metaData and document hashes now disagree, it is because the metadata # had a DOCHASH value for a different book or version. Warn the user. if IMC.metaHash != IMC.documentHash: pqMsgs.warningMsg( u"The document file and metadata file do not match!", u"Bookmarks, page breaks and other metadata will be wrong! Strongly recommend you not edit or save this book." ) # restore hiliting if the user wanted it. Note this can cause a # serious delay if the new book is large. However the alternative is # to not set it on and then we are out of step with the View menu # toggles, so the user has to set it off before loading, or suffer. self.setHighlight(IMC.scannoHiliteSwitch or IMC.spellingHiliteSwitch) # set a different main dict if there was one in the metadata if IMC.bookMainDict is not None: IMC.spellCheck.setMainDict(IMC.bookMainDict)
def loadEnds(self,bool): pqMsgs.endBar() if bool: # load was ok, reset scroll position now the rendering is finished. self.webPage.mainFrame().setScrollPosition(self.scrollPosition) # our panel is visible (else how was Refresh clicked?) but it may # not have the keyboard focus. Right after refresh one usually wants # to use keys like page-up/dn, so get the focus to our webview # widget (not the page in it because the webview has the scroll # bars and other mechanism.) self.preview.setFocus(Qt.MouseFocusReason) else: pqMsgs.warningMsg("Some problem loading html")
def loadEnds(self, bool): pqMsgs.endBar() if bool: # load was ok, reset scroll position now the rendering is finished. self.webPage.mainFrame().setScrollPosition(self.scrollPosition) # our panel is visible (else how was Refresh clicked?) but it may # not have the keyboard focus. Right after refresh one usually wants # to use keys like page-up/dn, so get the focus to our webview # widget (not the page in it because the webview has the scroll # bars and other mechanism.) self.preview.setFocus(Qt.MouseFocusReason) else: pqMsgs.warningMsg("Some problem loading html")
def loadDict(self,tag): p = self.listOfDicts.indexOf(tag) try: if p > -1 : # the tag is in our list of valid dicts fn = unicode(tag) # get qstring to python string aff_path = os.path.join(IMC.dictPath,fn+u'.aff') dic_path = os.path.join(IMC.dictPath,fn+u'.dic') obj = spellDict( dic_path, aff_path ) return obj # success else: raise LookupError('dictionary tag {0} not found'.format(tag)) except (LookupError, IOError, OSError) as err: if unicode(tag) not in self.errTags : pqMsgs.warningMsg(u'Could not open dictionary',str(err)) self.errTags.add(unicode(tag)) return None except : # some other error? print("unexpected error opening a spell dict") return None
def loadDict(self, tag): p = self.listOfDicts.indexOf(tag) try: if p > -1: # the tag is in our list of valid dicts fn = unicode(tag) # get qstring to python string aff_path = os.path.join(IMC.dictPath, fn + u'.aff') dic_path = os.path.join(IMC.dictPath, fn + u'.dic') obj = spellDict(dic_path, aff_path) return obj # success else: raise LookupError('dictionary tag {0} not found'.format(tag)) except (LookupError, IOError, OSError) as err: if unicode(tag) not in self.errTags: pqMsgs.warningMsg(u'Could not open dictionary', str(err)) self.errTags.add(unicode(tag)) return None except: # some other error? print("unexpected error opening a spell dict") return None
def insertMarkers(self): # Copy the text and if it is empty, complain and exit. qi = QString(self.insertText.text()) if qi.isEmpty(): pqMsgs.warningMsg("No insert text specified") return # See how many pages are involved: all the ones that aren't marked skip n = 0 for i in range(IMC.pageTable.size()): if IMC.pageTable.getAction(i) != IMC.FolioRuleSkip: n += 1 if n == 0: # page table empty or all rows marked skip pqMsgs.warningMsg("No pages to give folios to") return m = "Insert this string at the top of {0} pages?".format(n) b = pqMsgs.okCancelMsg(QString(m), pqMsgs.trunc(qi, 35)) if b: # Convert any '\n' in the text to the QT line delimiter char # we do this in the copy so the lineEdit text doesn't change qi.replace(QString(u'\\n'), QString(IMC.QtLineDelim)) # get a cursor on the edit document tc = QTextCursor(IMC.editWidget.textCursor()) tc.beginEditBlock() # start single undoable operation # Working from the end of the document backward, go to the # top of each page and insert the string for i in reversed(range(IMC.pageTable.size())): if IMC.pageTable.getAction(i) != IMC.FolioRuleSkip: # Note the page's start position and set our work cursor to it pos = IMC.pageTable.getCursor(i).position() tc.setPosition(pos) # Make a copy of the insert string replacing %f with this folio f = IMC.pageTable.getDisplay(i) qf = QString(qi) qf.replace(QString(u'%f'), f, Qt.CaseInsensitive) tc.insertText(qf) # The insertion goes in ahead of the saved cursor position so now # it points after the inserted string. Put it back where it was. IMC.pageTable.setPosition(i, pos) tc.endEditBlock() # wrap up the undo op
def insertMarkers(self): # Copy the text and if it is empty, complain and exit. qi = QString(self.insertText.text()) if qi.isEmpty() : pqMsgs.warningMsg("No insert text specified") return # See how many pages are involved: all the ones that aren't marked skip n = 0 for i in range(IMC.pageTable.size()): if IMC.pageTable.getAction(i) != IMC.FolioRuleSkip : n += 1 if n == 0 : # page table empty or all rows marked skip pqMsgs.warningMsg("No pages to give folios to") return m = "Insert this string at the top of {0} pages?".format(n) b = pqMsgs.okCancelMsg(QString(m),pqMsgs.trunc(qi,35)) if b : # Convert any '\n' in the text to the QT line delimiter char # we do this in the copy so the lineEdit text doesn't change qi.replace(QString(u'\\n'),QString(IMC.QtLineDelim)) # get a cursor on the edit document tc = QTextCursor(IMC.editWidget.textCursor()) tc.beginEditBlock() # start single undoable operation # Working from the end of the document backward, go to the # top of each page and insert the string for i in reversed( range( IMC.pageTable.size() ) ) : if IMC.pageTable.getAction(i) != IMC.FolioRuleSkip : # Note the page's start position and set our work cursor to it pos = IMC.pageTable.getCursor(i).position() tc.setPosition(pos) # Make a copy of the insert string replacing %f with this folio f = IMC.pageTable.getDisplay(i) qf = QString(qi) qf.replace(QString(u'%f'),f,Qt.CaseInsensitive) tc.insertText(qf) # The insertion goes in ahead of the saved cursor position so now # it points after the inserted string. Put it back where it was. IMC.pageTable.setPosition(i, pos) tc.endEditBlock() # wrap up the undo op
def checkForUpdates(): # Step one, read the code display for the master page = slurp('https://github.com/tallforasmurf/PPQT') if page is None: pqMsgs.warningMsg('Unable to contact Github', 'Perhaps try again later?') return # the embedded URLs usable. hit = reGetMasterSHA.search(page) if hit is None: pqMsgs.warningMsg('Github page format not as expected', 'Probable bug, update not available') return masterSHA = hit.group(1) page = re.sub(masterSHA, 'master', page) # Step three, make a list of all the "blobs" mentioned, which is just # all the committed modules, pqXXX.py and pqHelp.html. Ignoring the # extras -- the extras folder appears as a "tree" item and we could # follow it and list all the blobs extras/* but we are not. blobs = reBlobLine.findall(page) # blobs is a list of 4-tuples, the (/1, /2, /3, /4) from reBlobLine above # Now make a dict with 3-item values, # { modname:[ None, masterhash, masterURL] } where None will be filled # in with the local hash value shortly. blobTab = {} for blob in blobs: blobURL = u'https://raw.github.com' + blob[0] + u'/' + blob[1] blobName = blob[3] blobHash = blob[2] blobTab[blobName] = [None, blobHash, blobURL] # Look for the file modulehash.txt and if it exists, use it to fill # in the local hashes it lists. We do not distribute so it doesn't # show up in the github listing. We want the local hash to reflect # the actual local files, which might have been diddled locally. mhPath = os.path.join(IMC.appBasePath, 'modulehashes.txt') try: mhFile = open(mhPath, 'r') for line in mhFile: [modname, localhash] = line.split() if modname in blobTab: blobTab[modname][0] = localhash except: # presumably the file doesn't exist pass # Run through the blobTab and try to get hash values for any # modules that don't have a local hash yet (because modulehashes # didn't exist -- or didn't list them because they're new to us). for modName in blobTab: if blobTab[modName][0] is None: modPath = os.path.join(IMC.appBasePath, modName) try: modFile = open(modPath, 'r') modText = modFile.read() hasher = initializedSHA1.copy() hasher.update(str(len(modText))) hasher.update(b'\000') hasher.update(modText) blobTab[modName][0] = hasher.hexdigest() except: # presumably modname doesn't exist (new module?) pass # Run through the blobTab and make a new table, updaTab, listing # the members where localhash differs from master hash. updaTab = {} for modName in blobTab: if blobTab[modName][0] != blobTab[modName][1]: updaTab[modName] = blobTab[modName] # If there are no names left in the updaTab, the app is up to date! if len(updaTab) == 0: pqMsgs.infoMsg('PPQT is up to date.') return # There are one or more modules needing updating. Ask the user # if we should proceed. ans = pqMsgs.okCancelMsg( '{0} module(s) can be updated.'.format(len(updaTab)), 'Shall we proceed?') if not ans: pqMsgs.infoMsg('PPQT remains unchanged.') return # User said OK to do it. Read the text of the updated modules from # github and save it in the updaTab. for modName in updaTab: page = slurp(updaTab[modName][2]) if page is None: pqMsgs.warningMsg('Some problem reading update modules', 'PPQT is unchanged.') return updaTab[modName].append(page) # All update texts read correctly. Now open each for writing, # appending the file object to the updaTab entry. for modName in updaTab: try: modPath = os.path.join(IMC.appBasePath, modName) modFile = open(modPath, 'w') updaTab[modName].append(modFile) except Exception: pqMsgs.warningMsg('Updated modules are not writable' 'PPQT is unchanged.') return # All files open for writing and text is ready. Write them. for modName in updaTab: try: modFile = updaTab[modName][4] modFile.write(updaTab[modName][3]) modFile.flush() os.fsync(modFile.fileno()) modFile.close() except Exception as e: # This is the bad case: some amount of writing done but not # all of it complete. PPQT is in an inconsistent state. pqMsgs.warningMsg( 'Error writing updated module(s)!', 'PPQT is in an inconsistent state\nDownload a complete new copy' ) return # All updates complete. Record local hashes in modulehashes.txt try: mhFile = open(mhPath, 'w') for modName in blobTab: mhFile.write(modName + ' ' + blobTab[modName][1] + '\n') mhFile.close() except Exception as e: pass pqMsgs.infoMsg('Updates applied.', 'Changes take effect when PPQT is restarted.') return
def checkForUpdates(): # Step one, read the code display for the master page = slurp('https://github.com/tallforasmurf/PPQT') if page is None: pqMsgs.warningMsg('Unable to contact Github', 'Perhaps try again later?') return # the embedded URLs usable. hit = reGetMasterSHA.search(page) if hit is None: pqMsgs.warningMsg('Github page format not as expected', 'Probable bug, update not available') return masterSHA = hit.group(1) page = re.sub(masterSHA,'master',page) # Step three, make a list of all the "blobs" mentioned, which is just # all the committed modules, pqXXX.py and pqHelp.html. Ignoring the # extras -- the extras folder appears as a "tree" item and we could # follow it and list all the blobs extras/* but we are not. blobs = reBlobLine.findall(page) # blobs is a list of 4-tuples, the (/1, /2, /3, /4) from reBlobLine above # Now make a dict with 3-item values, # { modname:[ None, masterhash, masterURL] } where None will be filled # in with the local hash value shortly. blobTab = {} for blob in blobs: blobURL = u'https://raw.github.com' + blob[0] + u'/' + blob[1] blobName = blob[3] blobHash = blob[2] blobTab[blobName] =[None,blobHash,blobURL] # Look for the file modulehash.txt and if it exists, use it to fill # in the local hashes it lists. We do not distribute so it doesn't # show up in the github listing. We want the local hash to reflect # the actual local files, which might have been diddled locally. mhPath = os.path.join(IMC.appBasePath,'modulehashes.txt') try: mhFile = open(mhPath,'r') for line in mhFile: [modname, localhash] = line.split() if modname in blobTab: blobTab[modname][0] = localhash except: # presumably the file doesn't exist pass # Run through the blobTab and try to get hash values for any # modules that don't have a local hash yet (because modulehashes # didn't exist -- or didn't list them because they're new to us). for modName in blobTab: if blobTab[modName][0] is None: modPath = os.path.join(IMC.appBasePath,modName) try: modFile = open(modPath,'r') modText = modFile.read() hasher = initializedSHA1.copy() hasher.update(str(len(modText))) hasher.update(b'\000') hasher.update(modText) blobTab[modName][0] = hasher.hexdigest() except: # presumably modname doesn't exist (new module?) pass # Run through the blobTab and make a new table, updaTab, listing # the members where localhash differs from master hash. updaTab = {} for modName in blobTab: if blobTab[modName][0] != blobTab[modName][1] : updaTab[modName] = blobTab[modName] # If there are no names left in the updaTab, the app is up to date! if len(updaTab) == 0: pqMsgs.infoMsg('PPQT is up to date.') return # There are one or more modules needing updating. Ask the user # if we should proceed. ans = pqMsgs.okCancelMsg('{0} module(s) can be updated.'.format(len(updaTab)), 'Shall we proceed?') if not ans: pqMsgs.infoMsg('PPQT remains unchanged.') return # User said OK to do it. Read the text of the updated modules from # github and save it in the updaTab. for modName in updaTab: page = slurp(updaTab[modName][2]) if page is None: pqMsgs.warningMsg('Some problem reading update modules', 'PPQT is unchanged.') return updaTab[modName].append(page) # All update texts read correctly. Now open each for writing, # appending the file object to the updaTab entry. for modName in updaTab: try: modPath = os.path.join(IMC.appBasePath,modName) modFile = open(modPath, 'w') updaTab[modName].append(modFile) except Exception: pqMsgs.warningMsg('Updated modules are not writable' 'PPQT is unchanged.') return # All files open for writing and text is ready. Write them. for modName in updaTab: try: modFile = updaTab[modName][4] modFile.write(updaTab[modName][3]) modFile.flush() os.fsync(modFile.fileno()) modFile.close() except Exception as e: # This is the bad case: some amount of writing done but not # all of it complete. PPQT is in an inconsistent state. pqMsgs.warningMsg('Error writing updated module(s)!', 'PPQT is in an inconsistent state\nDownload a complete new copy') return # All updates complete. Record local hashes in modulehashes.txt try: mhFile = open(mhPath,'w') for modName in blobTab: mhFile.write(modName + ' ' + blobTab[modName][1] + '\n') mhFile.close() except Exception as e: pass pqMsgs.infoMsg('Updates applied.', 'Changes take effect when PPQT is restarted.') return