def new_guess(self): self.key = None while not self.key or not biblemgr.bible.mod.hasEntry(self.key): randomnum = random.randint(1, 31102) self.key = VK("Gen 1:%d" % randomnum) self.user_key = UserVK(self.key) self.reference_frame.SetReference(self.key.getText())
def _get_document_parts_for_ref(self, module_name, ref, do_current_ref=True): t = default_timer() stylesheets = list(self.bible_stylesheets) scripts = self.standard_scripts + self.bible_scripts + ["highlight.js", "bpbible_html.js", "contrib/hyphenate.js", "columns.js"] book = biblemgr.get_module_book_wrapper(module_name) assert book, "Module wrapper not found for book " + module_name module = book.mod if book.chapter_view: scripts.append("bpbible_html_chapter_view.js") #stylesheets.append("bpbible_chapter_view.css") #stylesheets.append("bpbible://content/quotes_skin/") else: scripts.append("bpbible_html_page_view.js") stylesheets.append("bpbible_page_view.css") if is_debugging(): stylesheets.append("bpbible_html_debug.css") if book.is_verse_keyed: if book.chapter_view: if do_current_ref: c = book.GetChapter(ref, ref, config.current_verse_template) else: c = book.GetChapter(ref) ref_id = VK(ref).get_chapter_osis_ref() else: c = book.GetReference(ref, headings=True) ref_id = VK(ref).getOSISRef() elif book.is_dictionary: c = book.GetReference(ref) ref_id = ref elif book.is_genbook: c = book.GetReference(ref) ref_id = ref else: dprint(ERROR, "Book `%s' not found." % module_name) c = '' c = c.replace("<!P>", "</p><p>") clas = "" if not c: clas = " nocontent" lang = module.Lang() if module else "en", c = convert_language(c, lang) c = '<div class="segment%s" ref_id="%s">%s</div>' % (clas, urllib.quote(ref_id.encode("utf8")), c) return dict( module=module, content=c, bodyattrs=self._get_body_attrs(module), stylesheets=stylesheets, scripts=scripts, timer="<div class='timer'>Time taken: %.3f (ref_id %s)</div>" % (default_timer() - t, ref_id))
def replace_bible_links(match): ref = match.group(1) #print "Replacing bible link", ref vk = VK(ref) return "href='book_%s.html#%s_start'" % (vk.getOSISBookName(), vk.getOSISRef())
def has_chapter(self, ref, mod=None): assert self.is_verse_keyed, "Calling has_chapter for non-verse keyed module." module = mod or self.mod if module is None: return False vk = VK(ref) if module.hasEntry(vk): return True vk.setVerse(1) if module.hasEntry(vk): return True module.setKey(vk) try: old_mod_skiplinks = module.getSkipConsecutiveLinks() module.setSkipConsecutiveLinks(True) module.increment() next_vk = VK.castTo(module.getKey()) return (next_vk.Book() == vk.Book() and next_vk.Chapter() == vk.Chapter() and next_vk.Testament() == vk.Testament()) and not self.has_error(module) finally: module.setSkipConsecutiveLinks(old_mod_skiplinks)
def SetReference(self, ref, ref_to_scroll_to=None, settings_changed=False): """Sets reference. This is set up to be an observer of the main frame, so don't call internally. To set verse reference, use notify""" self.reference = GetVerseStr(ref) has_selected_new_verse = False # If the settings have changed we want to do a complete reload anyway # (since it could be something that requires a complete reload, such as changing version). if self.dom_loaded: if settings_changed: self.reference, ref_to_scroll_to = self.GetCurrentReferenceAndPosition( ) else: osisRef = VK(self.reference).getOSISRef() has_selected_new_verse = self.ExecuteScriptWithResult( 'select_new_verse("%s")' % osisRef) has_selected_new_verse = (has_selected_new_verse == "true") if has_selected_new_verse: self.NewReferenceLoaded() elif self.CheckChapterInBook(ref): self.OpenURIForCurrentBook("bpbible://content/page/%s/%s" % (self.book.version, self.reference)) if ref_to_scroll_to: self.scroll_to_osis_ref(ref_to_scroll_to) chapter = GetBookChapter(self.reference) self.header_bar.set_current_chapter(pysw.internal_to_user(chapter), chapter) self.update_title()
def _setupPassageLists(test): """Sets up the passage lists for the given test.""" test._verse_list1 = VerseList( [VK(("gen 2:3", "gen 2:5")), "gen 3:4", "gen 5:2"]) test._verse_list2 = VerseList( ["ex 2:2", "ex 3:5", VK(("ex 3:7", "ex 3:9"))]) test._verse_list3 = VerseList([VK(("lev 2:3", "lev 2:5")), "lev 2:7"]) test._verse_list4 = VerseList(["num 3:1", VK(("num 3:4", "num 3:5"))]) test._list = PassageList.create_from_verse_list("abc", test._verse_list1) test._list2 = PassageList.create_from_verse_list("def", test._verse_list2) test._list3 = PassageList.create_from_verse_list("ghi", test._verse_list3) test._list4 = PassageList.create_from_verse_list("jkl", test._verse_list4) test._list2.add_subtopic(test._list4) test._list.add_subtopic(test._list2) test._list.add_subtopic(test._list3) test._manager = PassageListManager() test._manager.add_subtopic(test._list)
class GuessVerseFrame(xrcGuessVerseFrame): def __init__(self, parent): super(GuessVerseFrame, self).__init__(parent) # This call makes sure that the reference display frame is loaded # with an empty reference. # This means that all future references displayed will be shown with # Javascript, and so there won't be any focus bugs. self.reference_frame.RefreshUI() self.reference_frame.template = VerseTemplate(body=u"$text", headings="") self.show_answer_button.Bind(wx.EVT_BUTTON, self.on_show_answer) self.guess_button.Bind(wx.EVT_BUTTON, self.on_guess) self.books.AppendItems([unicode(book) for book in UserVK.books]) self.books.Selection = 0 self.new_guess() self.Children[0].Fit() self.Fit() def new_guess(self): self.key = None while not self.key or not biblemgr.bible.mod.hasEntry(self.key): randomnum = random.randint(1, 31102) self.key = VK("Gen 1:%d" % randomnum) self.user_key = UserVK(self.key) self.reference_frame.SetReference(self.key.getText()) def on_show_answer(self, event): Tooltip.do_not_show_tooltip = True wx.MessageBox(_("The verse was %s") % UserVK(self.key).getText(), parent=self) Tooltip.do_not_show_tooltip = False self.new_guess() def on_guess(self, event): # XXX: We can't use the currently focused window trick to prevent # tooltips from grabbing focus when using a MessageBox, since it # gives the focused window as None. Instead, we use this hack. Tooltip.do_not_show_tooltip = True won = self.user_key.getBookName() == self.books.StringSelection if won: wx.MessageBox(_("Yes, you are right. The verse was %s") % UserVK(self.key).getText(), _("Correct"), parent=self) self.new_guess() else: wx.MessageBox( _("No, you are wrong. Try again."), _("Try again."), parent=self, style=wx.OK | wx.ICON_ERROR, ) Tooltip.do_not_show_tooltip = False
def __init__(self, parent, version=""): self.parent = parent self.mod = None self.observers = observerlist.ObserverList() self.cleanup_module = observerlist.ObserverList() self.template = VerseTemplate(body="$text") self.templatelist = [self.template] self.vk = VK() self.headings = False if self.ModuleExists(version): self.SetModule(version) else: mods = self.GetModuleList() if mods: self.SetModule(mods[0]) else: dprint(WARNING, "No modules of type", self.type) self.SetModule(None)
def yield_verses(mod): from swlib.pysw import VK, TOP vk = VK() vk.Headings(1) vk.setPosition(TOP) #vk.setText("Matthew 1:1") vk.Persist(1) vk.thisown = False mod.setKey(vk) books = ("Genesis", "Matthew") #"Exodus") while not vk.Error(): #while vk.Testament() in '\x00\x01': #while vk.Testament() == '\x00' or vk.Book() == '\x00' or \ # vk.getBookName() in books: yield vk.increment(1)
def testContainsVerseWorksWithRange(self): self.assert_(self._passage_entry2.contains_verse(VK("gen 3:5"))) self.assert_(self._passage_entry2.contains_verse(VK("gen 3:6"))) self.assert_(self._passage_entry2.contains_verse(VK("gen 3:9"))) self.assert_(self._passage_entry2.contains_verse(VK("gen 3:10"))) self.assert_(not self._passage_entry2.contains_verse(VK("gen 3:4"))) self.assert_(not self._passage_entry2.contains_verse(VK("gen 3:11")))
def cut_down_index(self, bottom, top): ### not fully implemented for non-bibles vk1 = VK((self.bookname, self.bookname)) vk = VK((bottom, top)) vk_dn = vk.LowerBound() vk_up = vk.UpperBound() # the item we are currently looking for start_ref = None ret = [] items = [] self.old_text = self.text self.old_index = self.index for match in re.finditer("(?m)^.*$", self.text): if vk_dn <= vk1 <= vk_up: items.append(match.group()) vk1.increment(1) self.text = '\n'.join(items) self.create_index_against_text(vk)
def insert_footnotes(match): #print "Inserting footnotes", match href = match.group(1) url = SW.URL(href.encode("utf8")) ftype = url.getParameterValue("type") #x or n value = url.getParameterValue("value") #number footnote in verse if ((not ftype) or (not value)): dprint(WARNING, "Not type or value in showNote", href) return "" module = biblemgr.get_module(url.getParameterValue("module")) passage = url.getParameterValue("passage") back_ref = VK(passage).getOSISRef() user_ref = book_fix(internal_to_user(passage)) if not passage or not module: print "No passage/module?" return "" id = "footnote_data_%s_%s" % (back_ref, value) #print passage, id if ftype in ("n", "x"): data = sword_book.GetFootnoteData(module, passage, value, "body") if footnotes[ftype] and footnotes[ftype][-1][0] == back_ref: footnotes_group = footnotes[ftype][-1] else: footnotes_group = [ back_ref, "<div class='verse_footnotes footnote_%s' id='verse_footnote_%s_%s'>%s for " "<a href='#%s_start'>%s</a>%%s</div>" % (ftype, back_ref, ftype, footnote_types[ftype], back_ref, user_ref) ] footnotes[ftype].append(footnotes_group) footnotes_group.append( "<div class='footnote_data' id='%s'><span class='footnote_marker'>%s</span>: %s</div>" % (id, match.group(3), data)) else: print "Footnote type was", ftype id = "verse_footnote_%s_%s" % (back_ref, ftype) return 'href="#%s"%s' % (id, match.group(2))
def __init__(self, parent, version = ""): self.parent = parent self.mod = None self.observers = observerlist.ObserverList() self.cleanup_module = observerlist.ObserverList() self.template = VerseTemplate(body = "$text") self.templatelist = [self.template] self.vk = VK() self.headings = False if self.ModuleExists(version): self.SetModule(version) else: mods = self.GetModuleList() if mods: self.SetModule(mods[0]) else: dprint(WARNING, "No modules of type", self.type) self.SetModule(None)
def get_verses_on_screen(self, verses): if not self.dom_loaded: return [] osis_refs = [VK(verse).getOSISRef() for verse in verses] osis_refs_on_screen = self.ExecuteScriptWithResult(""" (function(osis_refs) { var result = []; for (var index = 0; index < osis_refs.length; index++) { var osisRef = osis_refs[index]; var reference_found = $('[osisRef="' + osisRef + '"]').length > 0; if (reference_found) { result.push(osisRef); } } return JSON.stringify(result); })(%s); """ % json.dumps(osis_refs)) return json.loads(osis_refs_on_screen)
def yield_verses(mod): from swlib.pysw import VK, TOP vk = VK() vk.Headings(1) vk.setPosition(TOP) #vk.setText("Matthew 1:1") vk.Persist(1) vk.thisown = False mod.setKey(vk) books = ("Genesis", "Matthew")#"Exodus") while not vk.Error(): #while vk.Testament() in '\x00\x01': #while vk.Testament() == '\x00' or vk.Book() == '\x00' or \ # vk.getBookName() in books: yield vk.increment(1)
def testVersesInMainTopicShouldBeContainedDirectly(self): self.assert_(self._list.contains_verse(VK("gen 3:4")))
def random_verse(self): randomnum = random.randint(1, 31102) ref = VK("Gen 1:%d" % randomnum).text self.notify(ref, source=events.RANDOM_VERSE)
def testVersesInSubtopicsShouldNotBeContainedDirectly(self): self.assert_(not self._list.contains_verse(VK("ex 2:2"))) self.assert_(not self._list.contains_verse(VK("num 2:5")))
def get_key(self, module): vk = VK((self.bookname, self.bookname)) vk.Headings(0) vk.setPosition(TOP) return vk
def current_segment_changed(self, new_segment_ref): self.reference = VK(new_segment_ref).getText() self.latest_reference = self.reference self.ChangeCurrentReference(self.reference) self.update_title()
def get_ref_id(self, reference): osis_ref = VK(reference).getOSISRef() return super(LinkedFrame, self).get_ref_id(osis_ref)
def testValuesAreRight(self): self.assertEquals(self._list.passages[0].passage, VK("gen 2:3")) self.assertEquals(self._list.passages[2].passage, VK("gen 2:7"))
class Book(object): is_verse_keyed = False is_dictionary = False is_genbook = False chapter_view = False type = None category = None categories_to_exclude = () def __init__(self, parent, version=""): self.parent = parent self.mod = None self.observers = observerlist.ObserverList() self.cleanup_module = observerlist.ObserverList() self.template = VerseTemplate(body="$text") self.templatelist = [self.template] self.vk = VK() self.headings = False if self.ModuleExists(version): self.SetModule(version) else: mods = self.GetModuleList() if mods: self.SetModule(mods[0]) else: dprint(WARNING, "No modules of type", self.type) self.SetModule(None) def SetModule(self, modname, notify=True): """Sets the module to modname""" oldmod = self.mod # No book at all if modname is None: self.mod = None elif isinstance(modname, SW.Module): self.mod = modname else: # look up the book new_mod = self.parent.get_module(modname) if not new_mod: return False self.mod = new_mod self.features = None if self.mod != oldmod and notify: self.observers(self.mod) return True def ModuleExists(self, modname): return modname in self.GetModuleList() @property def version(self): if self.mod: return self.mod.Name() def GetModuleList(self): return sorted([ name for name, mod in self.parent.modules.iteritems() if (mod.Type() == self.type or self.type is None) and ( not self.category or (self.category and mod.getConfigEntry( "Category") == self.category)) and mod.getConfigEntry( "Category") not in self.categories_to_exclude ], key=lambda name: name.lower()) def GetModules(self): return sorted([ mod for name, mod in self.parent.modules.iteritems() if (mod.Type() == self.type or self.type is None) and ( not self.category or (self.category and mod.getConfigEntry( "Category") == self.category)) and mod.getConfigEntry( "Category") not in self.categories_to_exclude ], key=lambda mod: mod.Name().lower()) @staticmethod def get_template_options(): items = { "$": _("A $ sign"), "range": _("The range of verses"), "version": _("The version this is taken from"), "description": _("A description of the version"), } body_items = { "text": _("The text of a verse"), "versenumber": _("The verse number"), "reference": _("The reference for each verse"), "bookname": _("The name of the current book"), "bookabbrev": _("A shorter abbreviation of the book name"), "chapternumber": _("The number of the chapter in the book") } heading_items = {"heading": _("The text of the heading")} body_items.update(items) heading_items.update(body_items) return dict(body=body_items, headings=heading_items, header=items, footer=items) def GetReference(self, ref, specialref="", specialtemplate=None, context="", max_verses=177, raw=False, stripped=False, template=None, display_tags=None, exclude_topic_tag=None, end_ref=None, headings=False, verselist=None, remove_extra_whitespace=False): """GetReference gets a reference from a Book. specialref is a ref (string) which will be specially formatted according to specialtemplate. exclude_topic_tag: If this is not None, then it is a topic that should not have a tag generated, because it is obvious from the context (for example, the topic window for that topic). """ #only for bible keyed books if not self.mod: return None raw = raw or display_options.options["raw"] if template is None and self.templatelist: template = self.templatelist[-1] if context: lastverse = context else: lastverse = "" if display_tags is None: # if we don't have tags in, don't calculate them as it can be # expensive if "$tags" not in template.body.template: display_tags = False else: display_tags = passage_list.settings.display_tags assert not (verselist and end_ref), \ "No end ref with a listkey!!!" if end_ref: ref += " - " + end_ref old_headings = self.vk.Headings(headings) if not verselist: verselist = self.vk.ParseVerseList(to_str(ref), to_str(lastverse), True) # if they pass in a verselist, they can also pass in the ref they # would like to go along with it. This can be useful if it also # includes headings that shouldn't be seen rangetext = GetBestRange(ref, context=context, userInput=False, userOutput=True, headings=headings) internal_rangetext = GetBestRange(ref, context=context, headings=headings) if rangetext == "": self.vk.Headings(old_headings) #if invalid reference, return empty string return u"" if specialref: specialref = GetVerseStr(specialref) description = to_unicode(self.mod.Description(), self.mod) d = dict(range=rangetext, internal_range=internal_rangetext, version=self.mod.Name(), description=description) text = template.header.safe_substitute(d) verses = [] for body_dict, headings in self.GetReference_yield( verselist, max_verses, raw, stripped, exclude_topic_tag=exclude_topic_tag, display_tags=display_tags, ): # if we have exceeded the verse limit, body_dict will be None if body_dict is None: verses.append(config.MAX_VERSES_EXCEEDED() % max_verses) break body_dict.update(d) t = template if specialref == body_dict["internal_reference"]: t = specialtemplate verse = t.preverse.safe_substitute(body_dict) for heading_dict in headings: verse += t.headings.safe_substitute(heading_dict) verse += t.body.safe_substitute(body_dict) verses.append(verse) self.vk.Headings(old_headings) text += template.finalize(u''.join(verses)) text += self.end_of_render text += template.footer.safe_substitute(d) return text def GetReference_yield(self, verselist, max_verses=177, raw=False, stripped=False, module=None, exclude_topic_tag=None, display_tags=True, skip_linked_verses=True): """GetReference_yield: yield the body dictionary and headings dictinoary for each reference. Preconditions: one of module or self.mod is not None verselist is valid""" #only for bible keyed books verselist.setPosition(TOP) verselist.Persist(1) u_vk = pysw.UserVK() u_vk.Headings(1) versekey = SW.VerseKey() versekey.Headings(1) mod = module or self.mod old_mod_skiplinks = mod.getSkipConsecutiveLinks() mod.setSkipConsecutiveLinks(True) mod.SetKey(verselist) verses_left = max_verses render_text, render_start, render_end = self.get_rendertext(mod) if render_start: render_start() try: incrementer = mod if skip_linked_verses else verselist while not self.has_error(incrementer): if verses_left == 0: yield None, None break if not skip_linked_verses: mod.SetKey(verselist) key = mod.getKey() #versekey = VK.castTo(key) versekey.setText(key.getText()) #if(self.headings): # versekey.Headings(1) osisRef = versekey.getOSISRef() internal_reference = versekey.getText() rawentry = mod.getRawEntryBuf() if skip_linked_verses and not rawentry.length(): # don't include empty text; typically this may be at the # start of the chapter or something... incrementer.increment(1) continue start_verse = end_verse = versekey.Verse() # look forwards and backwards to see what the linked verse # number is (e.g. 3-5). Note: currently this won't cross # chapter boundaries vk = versekey.clone() vk = versekey.castTo(vk) vk.thisown = True vk.Headings(0) while (vk.Error() == '\x00' and vk.Chapter() == versekey.Chapter() and mod.isLinked(vk, versekey)): end_verse = vk.Verse() vk.increment(1) vk.copyFrom(versekey) vk.Headings(0) # hopefully we won't see anything backwards, but it is # possible (i.e. if we start in the middle of a linked # verse while (vk.Error() == '\x00' and vk.Chapter() == versekey.Chapter() and mod.isLinked(vk, versekey)): start_verse = vk.Verse() vk.decrement(1) if start_verse == end_verse: verse = "%d" % start_verse else: verse = "%d-%d" % (start_verse, end_verse) u_vk.setText(internal_reference) if internal_reference.endswith(":0"): if start_verse != end_verse: print "WARNING: unhandled linked verse with verse 0" if versekey.Chapter() == 0: reference = u_vk.getBookName() else: reference = u_vk.get_book_chapter() else: reference = u_vk.get_book_chapter() reference += ":" + verse body_dict = dict( # text comes later versenumber=process_digits(verse, userOutput=True), chapternumber=process_digits(str(versekey.Chapter()), userOutput=True), booknumber=ord(versekey.Book()), bookabbrev=versekey.getBookAbbrev(), bookname=versekey.getBookName(), reference=reference, internal_reference=internal_reference, osisRef=osisRef, ) # usually RenderText flushes this out, but we haven't called # that yet - but we definitely don't want extraneous headings mod.getEntryAttributesMap().clear() # we want to do our pre-verse content first, but we can't # without running it through the optionFilter first. # we'll then have to run it through again after, otherwise our # entryattributes may go walkabout if raw: rawentry_str = rawentry.c_str() mod.optionFilter(rawentry, versekey) if raw: option_filtered = rawentry.c_str() headings = self.get_headings(internal_reference, mod) #versekey = VK.castTo(key) heading_dicts = [] raw_headings = [] for heading, canonical in headings: # the new-style pre-verse content lives wrapped up in # <div>'s - it will contain the <title>, but the div will # be stripped out. # the old-style pre-verse content lives in <title>'s, # which will also be stripped out. Unfortunately, it isn't # that easy to tell whether it did have a title, so we # employ a heuristic - if it starts with an <, it is a new # one... nh = heading.startswith("<") if stripped: heading = mod.StripText(heading).decode( "utf8", "replace") else: heading = render_text(heading).decode( "utf8", "replace") if not nh: cls = " canonical" if (canonical and canonical == "true") else "" heading = '<h2 class="heading%s">%s</h2>\n' % (cls, heading) if raw: raw_headings.append(heading) heading_dict = dict(heading=heading, canonical=canonical) heading_dict.update(body_dict) heading_dicts.append(heading_dict) if stripped: text = mod.StripText(rawentry.c_str(), rawentry.length()).decode( "utf-8", "replace") else: # we can't use rawentry due to a static local buffer in # swmodule.c; breaks gospel harmonies text = ( render_text( #rawentry.c_str(), rawentry.length() ).decode("utf8", "replace")) # get our actual text if raw: text = self.process_raw(rawentry_str, text, versekey, mod, raw_headings, option_filtered) user_comments = self.get_user_comments(osisRef, versekey) # XXX: This needs to be done better than this. Move into # subclass somehow. if isinstance(self, Bible) and display_tags: tags = self.insert_tags(osisRef, versekey, exclude_topic_tag) else: tags = "" body_dict.update( dict(text=text, tags=tags, usercomments=user_comments)) yield body_dict, heading_dicts incrementer.increment(1) verses_left -= 1 finally: mod.setKey(SW.Key()) mod.setSkipConsecutiveLinks(old_mod_skiplinks) self.end_of_render = "" if render_end: self.end_of_render = render_end() def get_user_comments(self, osis_ref, verse_key): if not isinstance(self, Bible): return u"" manager = passage_list.get_primary_passage_list_manager() comments = u"".join( self.get_user_comment_div(passage_entry) for passage_entry in manager.get_all_passage_entries_for_verse(verse_key) if (self.get_tag_type_to_show(passage_entry) == "usercomment")) return u'<span class="usercomment_container" osisRef="%s">%s</span>' % ( osis_ref, comments) def get_user_comment_div(self, passage): passage_id = passage.get_id() return '<a class="usercomment" href="usercomment://%(passage_id)d" passageEntryId="%(passage_id)d"><sup>†</sup></a>' % locals( ) def insert_tags(self, osis_ref, verse_key, exclude_topic_tag): """Generates and returns all the passage tags for the given verse.""" manager = passage_list.get_primary_passage_list_manager() passage_tags = "".join( self.get_passage_topic_div(passage) for passage in manager.get_all_passage_entries_for_verse(verse_key) if (self.get_tag_type_to_show(passage, exclude_topic_tag) == "passage_tag")) return u'<span class="passage_tag_container" osisRef="%s">%s</span>' % ( osis_ref, passage_tags) def get_tag_type_to_show(self, passage, exclude_topic_tag=None): topic = passage.parent if (topic is not None and topic.parent is not None and topic is not exclude_topic_tag): if topic.can_display_tag: return "passage_tag" elif topic is passage_list.get_primary_passage_list_manager( ).comments_special_topic: return "usercomment" return None def get_passage_topic_div(self, passage): from gui import passage_tag topic_text = " > ".join(passage.parent.topic_trail) look, colour = passage.parent.resolve_tag_look() topic_id = passage.parent.get_id() passage_id = passage.get_id() return """ <a href="passagetag://passage/%(topic_id)d/%(passage_id)d" class="passage_tag passage_tag_%(colour)d_%(look)d" passageEntryId="%(passage_id)d"> <div> %(topic_text)s </div> </a> """ % locals() def get_headings(self, ref, mod=None): """Gets an array of the headings for the current verse. Must have just called RenderText on the verse you want headings for""" mod = mod or self.mod heading = SW.Buf("Heading") preverse = SW.Buf("Preverse") interverse = SW.Buf("Interverse") canonical = SW.Buf("canonical") headings = [] heading_types = [preverse, interverse] attrmap = mod.getEntryAttributesMap() #[SW.Buf("Heading") if heading in attrmap: h = attrmap[heading] if preverse in h: i = 0 p = h[preverse] while True: is_canonical = "false" i_buf = SW.Buf(str(i)) # try to see if this is a canonical heading # unfortunately, if there happens to be a interverse # heading after a canonical heading, it will overwrite it # so we may not get the correct answer. This oughtn't to # matter overly much if i_buf in h: attributes = h[i_buf] if (canonical in attributes and attributes[canonical].c_str() == "true"): is_canonical = "true" if i_buf in p: headings.append((p[i_buf].c_str(), is_canonical)) else: break i += 1 if not headings: dprint(WARNING, "no heading found for", ref) return headings def GetReferences(self, ref, context="", max_verses=-1): """Gets a list of references. In: ref - list of references context: context of first in list Out: A list of verses """ # TODO: If we have a list passed in like this: # ref= ['104:6', '8, 10, 105:1', '3'], context = 'PS 104:14' # for second item, GetVerseStr will return Psalms 104:8, instead # of Psalms 105:1, so the third retrieved will be 104:3, not 105:3 # Fixes: # Make GetVerseStr take last in list, not first as optional parameter results = [] lastref = context for j in ref: #get text results.append( self.GetReference(j, context=lastref, max_verses=max_verses)) # set context for next ref lastref = GetVerseStr(j, lastref) return results def GetFootnoteData(self, mod, passage, number, field): if mod != self.mod: if not isinstance(mod, SW.Module): mod = self.parent.get_module(mod) if mod is None: return None else: mod = self.mod vk = SW.Key(passage) mod.SetKey(vk) #set passage mod.RenderText() # force entry attributes to get set data = mod.getEntryAttributesMap()[SW.Buf("Footnote")] \ [SW.Buf(number)][SW.Buf(field)].c_str() # put it through the render filter before returning it return mod.RenderText(data).decode("utf8", "replace") def GetReferenceFromMod(self, mod, ref, max_verses=-1): oldmod = self.mod if not self.SetModule(mod, notify=False): return None try: verses = self.GetReference(ref, max_verses=max_verses) finally: self.SetModule(oldmod, notify=False) return verses def GetReferencesFromMod(self, mod, ref, context="", max_verses=-1): oldmod = self.mod if not self.SetModule(mod, notify=False): return None try: verses = self.GetReferences(ref, context, max_verses=max_verses) finally: self.SetModule(oldmod, notify=False) return verses def GetChapter(self, ref, specialref="", specialtemplate=None, context="", raw=False): self.vk.setText(to_str(ref, self.mod)) #get first ref text = self.vk.getText() match = re.match("([\w\s]+) (\d+):(\d+)", text) if match: book, chapter, verse = match.group(1, 2, 3) # include introductions - book introduction if necessary ref = "%s %s" % (book, chapter) text = "%s %s:0-%s %s" % (book, chapter, book, chapter) vk = SW.VerseKey() vk.Headings(1) list = vk.ParseVerseList(text, "", True) if chapter == "1": vk.setText("%s 0:0" % book) list.add(vk) #text = "%s 0:0-%s %s" % (book, book, chapter) if book == "Genesis": vk.Testament(0) list.add(vk) vk.Testament(1) list.add(vk) elif book == "Matthew": # set it to 0 first so that we come back to the testament # heading vk.Testament(0) vk.Testament(2) list.add(vk) list.sort() else: dprint(ERROR, "Couldn't parse verse text", text) return "" return self.GetReference(ref, specialref, specialtemplate, context, raw=raw, headings=True, verselist=list) def get_rendertext(self, mod=None): """Return the text render function. This makes sure that plaintext modules render whitespace properly""" module = mod or self.mod render_text = module.RenderText start = finish = None if module.getConfigEntry("SourceType") in (None, "Plaintext"): def render_text(*args): text = module.RenderText(*args) text = cgi.escape(text) return '<span class="plaintext">%s</span>' % text else: if ord(module.Markup()) == SW.FMT_OSIS: start = osisparser.p.block_start finish = osisparser.p.block_end return render_text, start, finish def has_feature(self, feature, module=None): if module is not None: oldmod = self.mod try: self.SetModule(module, notify=False) return self.has_feature(feature) finally: self.SetModule(oldmod, notify=False) if not self.mod: return False if self.features is None: self.features = [] mod = self.mod map = mod.getConfigMap() feature_buf = SW.Buf("Feature") featureBegin = map.lower_bound(feature_buf) featureEnd = map.upper_bound(feature_buf) while featureBegin != featureEnd: v = featureBegin.value() self.features.append(v[1].c_str()) featureBegin += 1 return feature in self.features def get_cipher_code(self, mod): """Return the cipher key for the module. This will be empty if locked, non-empty if unlocked and None if not enciphered""" return mod.getConfigEntry("CipherKey") def unlock(self, mod, key): assert self.get_cipher_code(mod) != None cm = mod.getConfigMap() cm[SW.Buf("CipherKey")] = SW.Buf(key) mgr = self.get_mgr(mod) mgr.setCipherKey(mod.Name(), key) conf = self.get_config(mod) conf.set(mod.Name(), "CipherKey", key) conf.Save() # send a refresh through for this book # TODO: do this better self.observers(self.mod) conf = self.get_config(mod) if conf.get(mod.Name(), "CipherKey") != key: raise FileSaveException( _("Couldn't save cipher key. You will have to set it again when you restart" )) def has_chapter(self, ref, mod=None): assert self.is_verse_keyed, "Calling has_chapter for non-verse keyed module." module = mod or self.mod if module is None: return False vk = VK(ref) if module.hasEntry(vk): return True vk.setVerse(1) if module.hasEntry(vk): return True module.setKey(vk) try: old_mod_skiplinks = module.getSkipConsecutiveLinks() module.setSkipConsecutiveLinks(True) module.increment() next_vk = VK.castTo(module.getKey()) return (next_vk.Book() == vk.Book() and next_vk.Chapter() == vk.Chapter() and next_vk.Testament() == vk.Testament()) and not self.has_error(module) finally: module.setSkipConsecutiveLinks(old_mod_skiplinks) def get_mgr(self, mod): for path, mgr, modules in self.parent.mgrs: if mod in [m for name, m in modules]: return mgr return None def get_config(self, mod): pp = mod.getConfigEntry("PrefixPath") pp += "mods.d/%s.conf" % mod.Name().lower() # make sure it exists os.stat(pp) return SW.Config(pp) def process_raw(self, text, rendered_text, key, module, headings=(), option_filtered=""): kt = key.getOSISRefRangeText() or key.getText() kt = to_unicode(kt, module) if headings: headings = "<ul class='raw-headings'>%s</ul>" % ('\n'.join( "<li>%s</li>" % cgi.escape(heading) for heading in headings)) else: headings = "" if option_filtered: option_filtered = "<pre class='raw-option-filtered'>%s</pre>" % cgi.escape( option_filtered.decode("utf-8", "replace")) return u""" %s <div class='debug-raw-details' key='%s'> <pre class='raw-rendered'>%s</pre> %s <pre class='raw'>%s</pre> %s </div>""" % (rendered_text, cgi.escape(kt), cgi.escape(rendered_text), headings, cgi.escape(text.decode("utf-8", "replace")), option_filtered) @staticmethod def has_error(module): ERR_OK = chr(0) return (module.Error() != ERR_OK)
def testVersesInSubtopicsShouldBeContainedRecursively(self): self.assert_(self._list.contains_verse(VK("ex 2:2"), recursive=True)) self.assert_(self._list.contains_verse(VK("num 3:5"), recursive=True))
def get_book(sword_book, bible_book, verse_per_line=False): print "fetching", bible_book, "from", sword_book bookname = str(bible_book) chapter_bookname = book_fix(bookname) osis_bookname = VK(bookname).getOSISBookName() filename = "book_%s.html" % osis_bookname preverse = '<span id="${osisRef}_start" />' # templates verse_number = u'''<span class="vnumber $numbertype%s" id="${osisRef}_number"> $versenumber<span class="post_versenumber_space"> </span></span>''' # TODO - reinstate $usercomments $tags after $text? body = (u'''%s<span class="zwnj">‌</span>$text''') % verse_number # <a id="${osisRef}_end" osisRef="$osisRef"></a>''') % verse_number bible_template = SmartVerseTemplate(body=body % (''), preverse=preverse) bible_template.body.verse_per_line = verse_per_line toc = [] chapters = [] footnotes = { 'n': [], 'x': [], } footnote_types = { 'n': "Footnotes", 'x': "Cross-references", } for chapter in bible_book.chapters: if chapter.chapter_number % 10 == 0: print osis_bookname, chapter if RESTRICTED: break chapter_id = "%s_%s_start" % (osis_bookname, chapter) chapter_link = '<a class="chapter_link" href="#intro">%s</a>' % chapter_bookname toc.append( '''<a class="toc_chapter_link" href="#chapter_%s">%s</a>''' % (chapter_id, chapter)) ref = "%s %s" % (osis_bookname, chapter) content = sword_book.GetReference(ref, end_ref=ref, template=bible_template, max_verses=-1) # content = re.sub(r'<(/?)h2([^>]*)>', r'<\1h4\2>', content) chapter_marker = '<span class="vnumber chapternumber' # always a chance new_content = content.replace(chapter_marker, chapter_link + chapter_marker) osisRef = "%s.%s.%s" % (osis_bookname, chapter, 1) if new_content == content: print "No chapter intro link found for %s %s" % (osis_bookname, chapter) new_content = (chapter_link + (verse_number % '').replace( "$numbertype", "chapternumber").replace( "${osisRef}", osisRef).replace("${versenumber}", "%s" % (chapter))) content = new_content expected_start = preverse.replace("${osisRef}", osisRef) + chapter_link if not content.startswith(expected_start): print "pre-content chapter intro link found for %s %s" % ( osis_bookname, chapter) #print "Sample starter content: " + content[:100] content = content.replace(chapter_link, "<br / >" + chapter_link) # now take it back out if write after a lg q = '<blockquote class="lg" width="0">' content = content.replace(q + '<br / >', q) # check - did we have a closing or opening <p> last? if 0: # note, it's only epubcheck which complains about this. kindlegen # complains as this support isn't perfect so it sees some unclosed # <p> tags add_p = True for a in re.findall("<(/?)p>", content): add_p = not (a) if add_p: content += '</p>' def insert_footnotes(match): #print "Inserting footnotes", match href = match.group(1) url = SW.URL(href.encode("utf8")) ftype = url.getParameterValue("type") #x or n value = url.getParameterValue("value") #number footnote in verse if ((not ftype) or (not value)): dprint(WARNING, "Not type or value in showNote", href) return "" module = biblemgr.get_module(url.getParameterValue("module")) passage = url.getParameterValue("passage") back_ref = VK(passage).getOSISRef() user_ref = book_fix(internal_to_user(passage)) if not passage or not module: print "No passage/module?" return "" id = "footnote_data_%s_%s" % (back_ref, value) #print passage, id if ftype in ("n", "x"): data = sword_book.GetFootnoteData(module, passage, value, "body") if footnotes[ftype] and footnotes[ftype][-1][0] == back_ref: footnotes_group = footnotes[ftype][-1] else: footnotes_group = [ back_ref, "<div class='verse_footnotes footnote_%s' id='verse_footnote_%s_%s'>%s for " "<a href='#%s_start'>%s</a>%%s</div>" % (ftype, back_ref, ftype, footnote_types[ftype], back_ref, user_ref) ] footnotes[ftype].append(footnotes_group) footnotes_group.append( "<div class='footnote_data' id='%s'><span class='footnote_marker'>%s</span>: %s</div>" % (id, match.group(3), data)) else: print "Footnote type was", ftype id = "verse_footnote_%s_%s" % (back_ref, ftype) return 'href="#%s"%s' % (id, match.group(2)) content = re.sub( r'href="newbible://content/(passagestudy\.jsp\?action=showNote&type=[nx]&value=\d+&module=\w+&passage=(?:[^"]+))"(>([^<]*)</a>)', insert_footnotes, content) chapters.append(''' <div class="chapter" id="chapter_%s"> <!-- <p> --> %s </div> <hr /> ''' % (chapter_id, content)) footnotes_html = '' for ftype in "nx": if footnotes[ftype]: footnotes_html += '<div class="book_footnotes"><h3>%s for %s</h3>%s</div>' % ( footnote_types[ftype], bookname, '<hr />\n'.join( [f[1] % ('\n\t'.join(f[2:])) for f in footnotes[ftype]])) html_content = '''<?xml version='1.0' encoding='utf-8'?> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>%s</title> <link type="text/css" rel="stylesheet" href="bpbible_epub.css" /> </head> <body> <div id="intro"> <h3>%s</h3> <div class="book_toc">%s</div> <hr style="clear:both" /> <div style="clear:both"> Return to <a href="toc.html">Table of Contents</a> </div> </div> <hr class="pagebreak" /> <div class="chapterview"> %s </div> %s </body> </html> ''' % (bookname, bookname, '\n'.join(toc), '\n'.join(chapters), footnotes_html) # TODO: sword:// links, any others? print "Resolving bible links for", bookname def replace_bible_links(match): ref = match.group(1) #print "Replacing bible link", ref vk = VK(ref) return "href='book_%s.html#%s_start'" % (vk.getOSISBookName(), vk.getOSISRef()) html_content = re.sub(r'href="bible:([^"]*)"', replace_bible_links, html_content) return ( osis_bookname, filename, bookname, html_content.encode("utf8"), )
def testVersesInVerseRangeShouldBeContained(self): self.assert_(self._list.contains_verse(VK("gen 2:5"))) self.assert_(self._list.contains_verse(VK("gen 2:4")))
def get_document(self, path): module_name, rest = path.split("/", 1) ref, direction = rest.rsplit("/", 1) assert direction in ("next", "previous") dir = {"next": 1, "previous": -1}[direction] book = biblemgr.get_module_book_wrapper(module_name) mod = book.mod no_more = False if book.is_verse_keyed: vk = VK(ref, headings=not book.chapter_view) if book.chapter_view: vk.chapter += dir if vk.Error(): print "No more in that direction", dir no_more = True else: # go back just a little, so that when we go forward on the module # we won't overshoot... (at least, that is our plan - we hope it # won't be baffled...) vk.Verse(vk.Verse() - dir) if vk.Error(): print "VK had an error taking away a verse", dir if not no_more: old_mod_skiplinks = mod.getSkipConsecutiveLinks() mod.setSkipConsecutiveLinks(True) try: vk.Persist(1) mod.setKey(vk) #print repr(mod.Error()) mod.increment(dir) if mod.Error() != '\x00': print "Mod had an error" no_more = True else: if book.chapter_view: new_ref = vk.get_chapter_osis_ref() else: new_ref = vk.getOSISRef() finally: mod.setKey(SW.Key()) mod.setSkipConsecutiveLinks(old_mod_skiplinks) elif book.is_dictionary: # XXX: Would using an index rather than a reference (as the XUL code did) be more efficient? book.snap_text(ref) book.mod.increment(dir) if mod.Error() == '\x00' and book.mod.getKey().getText(): new_ref = to_unicode(mod.getKey().getText(), mod) else: no_more = True elif book.is_genbook: ref = "/" + ref tk = book.GetKey() tk.Persist(1) assert tk.thisown newtk = book.GetKey() newtk.thisown = True mod.setKey(tk) print "Getting next for", ref tk.set_text(ref) print tk.getText() if mod.Error() != '\x00': print "Error on initial set?" mod.increment(dir) if mod.Error() == '\x00' and tk.getText(): new_ref = to_unicode(tk.getText(), mod)[1:] # trim off the leading / else: no_more = True mod.setKey(newtk) else: print "Book type not handled", module_name if no_more: message = (_("You are at the start of this book.") if dir == -1 else _("You are at the end of this book.")) class_name = "book-%s" % ("start" if dir == -1 else "end") return ''' <div class="page_segment" empty="true"> <div class='no_more_text %(class_name)s'> %(message)s </div> </div>''' % locals() return '<div class="page_segment">%(content)s%(timer)s</div>' % self._get_document_parts_for_ref(module_name, new_ref, do_current_ref=False)
def testVersesNotInVerseRangeShouldNotBeContained(self): self.assert_(not self._list.contains_verse(VK("deut 3:5"))) self.assert_( not self._list.contains_verse(VK("deut 3:5"), recursive=True))
def _get_document_parts_for_ref(self, module_name, ref, do_current_ref=True): t = default_timer() stylesheets = list(self.bible_stylesheets) scripts = self.standard_scripts + self.bible_scripts + [ "highlight.js", "bpbible_html.js", "contrib/hyphenate.js", "columns.js" ] book = biblemgr.get_module_book_wrapper(module_name) assert book, "Module wrapper not found for book " + module_name module = book.mod if book.chapter_view: scripts.append("bpbible_html_chapter_view.js") #stylesheets.append("bpbible_chapter_view.css") #stylesheets.append("bpbible://content/quotes_skin/") else: scripts.append("bpbible_html_page_view.js") stylesheets.append("bpbible_page_view.css") if is_debugging(): stylesheets.append("bpbible_html_debug.css") if book.is_verse_keyed: if book.chapter_view: if do_current_ref: c = book.GetChapter(ref, ref, config.current_verse_template) else: c = book.GetChapter(ref) ref_id = VK(ref).get_chapter_osis_ref() else: c = book.GetReference(ref, headings=True) ref_id = VK(ref).getOSISRef() elif book.is_dictionary: c = book.GetReference(ref) ref_id = ref elif book.is_genbook: c = book.GetReference(ref) ref_id = ref else: dprint(ERROR, "Book `%s' not found." % module_name) c = '' c = c.replace("<!P>", "</p><p>") clas = "" if not c: clas = " nocontent" lang = module.Lang() if module else "en", c = convert_language(c, lang) c = '<div class="segment%s" ref_id="%s">%s</div>' % ( clas, urllib.quote(ref_id.encode("utf8")), c) return dict( module=module, content=c, bodyattrs=self._get_body_attrs(module), stylesheets=stylesheets, scripts=scripts, timer="<div class='timer'>Time taken: %.3f (ref_id %s)</div>" % (default_timer() - t, ref_id))
def testContainsVerseWorksWithSingleVerse(self): self.assert_(self._passage_entry.contains_verse(VK("gen 2:2"))) self.assert_(not self._passage_entry.contains_verse(VK("gen 2:1")))
def get_document(self, path): module_name, rest = path.split("/", 1) ref, direction = rest.rsplit("/", 1) assert direction in ("next", "previous") dir = {"next": 1, "previous": -1}[direction] book = biblemgr.get_module_book_wrapper(module_name) mod = book.mod no_more = False if book.is_verse_keyed: vk = VK(ref, headings=not book.chapter_view) if book.chapter_view: vk.chapter += dir if vk.Error(): print "No more in that direction", dir no_more = True else: # go back just a little, so that when we go forward on the module # we won't overshoot... (at least, that is our plan - we hope it # won't be baffled...) vk.Verse(vk.Verse() - dir) if vk.Error(): print "VK had an error taking away a verse", dir if not no_more: old_mod_skiplinks = mod.getSkipConsecutiveLinks() mod.setSkipConsecutiveLinks(True) try: vk.Persist(1) mod.setKey(vk) #print repr(mod.Error()) mod.increment(dir) if mod.Error() != '\x00': print "Mod had an error" no_more = True else: if book.chapter_view: new_ref = vk.get_chapter_osis_ref() else: new_ref = vk.getOSISRef() finally: mod.setKey(SW.Key()) mod.setSkipConsecutiveLinks(old_mod_skiplinks) elif book.is_dictionary: # XXX: Would using an index rather than a reference (as the XUL code did) be more efficient? book.snap_text(ref) book.mod.increment(dir) if mod.Error() == '\x00' and book.mod.getKey().getText(): new_ref = to_unicode(mod.getKey().getText(), mod) else: no_more = True elif book.is_genbook: ref = "/" + ref tk = book.GetKey() tk.Persist(1) assert tk.thisown newtk = book.GetKey() newtk.thisown = True mod.setKey(tk) print "Getting next for", ref tk.set_text(ref) print tk.getText() if mod.Error() != '\x00': print "Error on initial set?" mod.increment(dir) if mod.Error() == '\x00' and tk.getText(): new_ref = to_unicode(tk.getText(), mod)[1:] # trim off the leading / else: no_more = True mod.setKey(newtk) else: print "Book type not handled", module_name if no_more: message = (_("You are at the start of this book.") if dir == -1 else _("You are at the end of this book.")) class_name = "book-%s" % ("start" if dir == -1 else "end") return ''' <div class="page_segment" empty="true"> <div class='no_more_text %(class_name)s'> %(message)s </div> </div>''' % locals() return '<div class="page_segment">%(content)s%(timer)s</div>' % self._get_document_parts_for_ref( module_name, new_ref, do_current_ref=False)
def get_tree_item(self): root = self.tree.GetRootItem() text = self.GetValue() was_book = False for book in UserVK.books: if ("%s" % book) == text: was_book = True self.currentverse = book.bookname break else: try: # try updating verse based on user text # if we fail, just use old text (assuming there is any) self.currentverse = GetVerseStr(text, self.currentverse, raiseError=True, userInput=True, userOutput=False) except VerseParsingError: if not self.currentverse: return self.tree.GetFirstChild(root)[0] verse_key = UserVK(VK(self.currentverse)) single_chapter_book = verse_key.getChapterMax() == 1 book, chapter = verse_key.getBookName(), verse_key.Chapter() verse = verse_key.Verse() chapter = process_digits(str(chapter), userOutput=True) verse = process_digits(str(verse), userOutput=True) if single_chapter_book: chapter = verse item, cookie = self.tree.GetFirstChild(root) while item: if self.tree.GetItemText(item) == book: break item, cookie = self.tree.GetNextChild(root, cookie) assert item, book + " not found!" if was_book or (single_chapter_book and not self.with_verses): return item self.tree.Expand(item) item2, cookie = self.tree.GetFirstChild(item) while item2: data = unicode(self.get_data(item2)) if data == chapter: # if : isn't in there, we take it as a chapter reference if not self.with_verses or ":" not in text \ or single_chapter_book: return item2 else: break item2, cookie = self.tree.GetNextChild(item, cookie) assert item2, "Chapter '%s' not found in %s" % (chapter, book) assert not single_chapter_book, "Single chapter books, but chapterMax == 1?!?" self.tree.Expand(item2) item3, cookie = self.tree.GetFirstChild(item2) while item3: data = unicode(self.get_data(item3)) if data == verse: return item3 item3, cookie = self.tree.GetNextChild(item2, cookie) assert item3, "Verse '%s' not found in %s %s" % (verse, book, chapter)
def chapter_move(self, number): vk = VK(self.reference) vk.chapter += number if not vk.Error(): self.notify(vk.text, source=events.CHAPTER_MOVE)
def verse_move(self, number): vk = VK(self.reference) vk += number self.notify(vk.text, source=events.VERSE_MOVE)
class GuessVerseFrame(xrcGuessVerseFrame): def __init__(self, parent): super(GuessVerseFrame, self).__init__(parent) # This call makes sure that the reference display frame is loaded # with an empty reference. # This means that all future references displayed will be shown with # Javascript, and so there won't be any focus bugs. self.reference_frame.RefreshUI() self.reference_frame.template = VerseTemplate( body=u"$text", headings="" ) self.show_answer_button.Bind(wx.EVT_BUTTON, self.on_show_answer) self.guess_button.Bind(wx.EVT_BUTTON, self.on_guess) self.books.AppendItems([unicode(book) for book in UserVK.books]) self.books.Selection = 0 self.new_guess() self.Children[0].Fit() self.Fit() def new_guess(self): self.key = None while not self.key or not biblemgr.bible.mod.hasEntry(self.key): randomnum = random.randint(1, 31102) self.key = VK("Gen 1:%d" % randomnum) self.user_key = UserVK(self.key) self.reference_frame.SetReference(self.key.getText()) def on_show_answer(self, event): Tooltip.do_not_show_tooltip = True wx.MessageBox( _("The verse was %s") % UserVK(self.key).getText(), parent=self ) Tooltip.do_not_show_tooltip = False self.new_guess() def on_guess(self, event): # XXX: We can't use the currently focused window trick to prevent # tooltips from grabbing focus when using a MessageBox, since it # gives the focused window as None. Instead, we use this hack. Tooltip.do_not_show_tooltip = True won = self.user_key.getBookName() == self.books.StringSelection if won: wx.MessageBox( _("Yes, you are right. The verse was %s") % UserVK(self.key).getText(), _("Correct"), parent=self ) self.new_guess() else: wx.MessageBox( _("No, you are wrong. Try again."), _("Try again."), parent=self, style=wx.OK | wx.ICON_ERROR, ) Tooltip.do_not_show_tooltip = False
class Book(object): is_verse_keyed = False is_dictionary = False is_genbook = False chapter_view = False type = None category = None categories_to_exclude = () def __init__(self, parent, version = ""): self.parent = parent self.mod = None self.observers = observerlist.ObserverList() self.cleanup_module = observerlist.ObserverList() self.template = VerseTemplate(body = "$text") self.templatelist = [self.template] self.vk = VK() self.headings = False if self.ModuleExists(version): self.SetModule(version) else: mods = self.GetModuleList() if mods: self.SetModule(mods[0]) else: dprint(WARNING, "No modules of type", self.type) self.SetModule(None) def SetModule(self, modname, notify=True): """Sets the module to modname""" oldmod = self.mod # No book at all if modname is None: self.mod = None elif isinstance(modname, SW.Module): self.mod = modname else: # look up the book new_mod = self.parent.get_module(modname) if not new_mod: return False self.mod = new_mod self.features = None if self.mod != oldmod and notify: self.observers(self.mod) return True def ModuleExists(self, modname): return modname in self.GetModuleList() @property def version(self): if self.mod: return self.mod.Name() def GetModuleList(self): return sorted([name for name, mod in self.parent.modules.iteritems() if (mod.Type() == self.type or self.type is None) and (not self.category or (self.category and mod.getConfigEntry("Category") == self.category)) and mod.getConfigEntry("Category") not in self.categories_to_exclude], key=lambda name:name.lower()) def GetModules(self): return sorted([mod for name, mod in self.parent.modules.iteritems() if (mod.Type() == self.type or self.type is None) and (not self.category or (self.category and mod.getConfigEntry("Category") == self.category)) and mod.getConfigEntry("Category") not in self.categories_to_exclude], key = lambda mod: mod.Name().lower()) @staticmethod def get_template_options(): items = { "$": _("A $ sign"), "range": _("The range of verses"), "version": _("The version this is taken from"), "description": _("A description of the version"), } body_items = { "text": _("The text of a verse"), "versenumber": _("The verse number"), "reference": _("The reference for each verse"), "bookname": _("The name of the current book"), "bookabbrev": _("A shorter abbreviation of the book name"), "chapternumber":_("The number of the chapter in the book") } heading_items = { "heading": _("The text of the heading") } body_items.update(items) heading_items.update(body_items) return dict(body=body_items, headings=heading_items, header=items, footer=items) def GetReference(self, ref, specialref="", specialtemplate=None, context="", max_verses=177, raw=False, stripped=False, template=None, display_tags=None, exclude_topic_tag=None, end_ref=None, headings=False, verselist=None, remove_extra_whitespace=False): """GetReference gets a reference from a Book. specialref is a ref (string) which will be specially formatted according to specialtemplate. exclude_topic_tag: If this is not None, then it is a topic that should not have a tag generated, because it is obvious from the context (for example, the topic window for that topic). """ #only for bible keyed books if not self.mod: return None raw = raw or display_options.options["raw"] if template is None and self.templatelist: template = self.templatelist[-1] if context: lastverse = context else: lastverse = "" if display_tags is None: # if we don't have tags in, don't calculate them as it can be # expensive if "$tags" not in template.body.template: display_tags = False else: display_tags = passage_list.settings.display_tags assert not (verselist and end_ref), \ "No end ref with a listkey!!!" if end_ref: ref += " - " + end_ref old_headings = self.vk.Headings(headings) if not verselist: verselist = self.vk.ParseVerseList(to_str(ref), to_str(lastverse), True) # if they pass in a verselist, they can also pass in the ref they # would like to go along with it. This can be useful if it also # includes headings that shouldn't be seen rangetext = GetBestRange(ref, context=context, userInput=False, userOutput=True, headings=headings) internal_rangetext = GetBestRange(ref, context=context, headings=headings) if rangetext == "": self.vk.Headings(old_headings) #if invalid reference, return empty string return u"" if specialref: specialref = GetVerseStr(specialref) description = to_unicode(self.mod.Description(), self.mod) d = dict(range=rangetext, internal_range=internal_rangetext, version=self.mod.Name(), description=description) text = template.header.safe_substitute(d) verses = [] for body_dict, headings in self.GetReference_yield( verselist, max_verses, raw, stripped, exclude_topic_tag=exclude_topic_tag, display_tags=display_tags, ): # if we have exceeded the verse limit, body_dict will be None if body_dict is None: verses.append(config.MAX_VERSES_EXCEEDED() % max_verses) break body_dict.update(d) t = template if specialref == body_dict["internal_reference"]: t = specialtemplate verse = t.preverse.safe_substitute(body_dict) for heading_dict in headings: verse += t.headings.safe_substitute(heading_dict) verse += t.body.safe_substitute(body_dict) verses.append(verse) self.vk.Headings(old_headings) text += template.finalize(u''.join(verses)) text += self.end_of_render text += template.footer.safe_substitute(d) return text def GetReference_yield(self, verselist, max_verses=177, raw=False, stripped=False, module=None, exclude_topic_tag=None, display_tags=True, skip_linked_verses=True): """GetReference_yield: yield the body dictionary and headings dictinoary for each reference. Preconditions: one of module or self.mod is not None verselist is valid""" #only for bible keyed books verselist.setPosition(TOP) verselist.Persist(1) u_vk = pysw.UserVK() u_vk.Headings(1) versekey = SW.VerseKey() versekey.Headings(1) mod = module or self.mod old_mod_skiplinks = mod.getSkipConsecutiveLinks() mod.setSkipConsecutiveLinks(True) mod.SetKey(verselist) verses_left = max_verses render_text, render_start, render_end = self.get_rendertext(mod) if render_start: render_start() try: incrementer = mod if skip_linked_verses else verselist while not self.has_error(incrementer): if verses_left == 0: yield None, None break if not skip_linked_verses: mod.SetKey(verselist) key = mod.getKey() #versekey = VK.castTo(key) versekey.setText(key.getText()) #if(self.headings): # versekey.Headings(1) osisRef = versekey.getOSISRef() internal_reference = versekey.getText() rawentry = mod.getRawEntryBuf() if skip_linked_verses and not rawentry.length(): # don't include empty text; typically this may be at the # start of the chapter or something... incrementer.increment(1) continue start_verse = end_verse = versekey.Verse() # look forwards and backwards to see what the linked verse # number is (e.g. 3-5). Note: currently this won't cross # chapter boundaries vk = versekey.clone() vk = versekey.castTo(vk) vk.thisown=True vk.Headings(0) while(vk.Error() == '\x00' and vk.Chapter() == versekey.Chapter() and mod.isLinked(vk, versekey)): end_verse = vk.Verse() vk.increment(1) vk.copyFrom(versekey) vk.Headings(0) # hopefully we won't see anything backwards, but it is # possible (i.e. if we start in the middle of a linked # verse while(vk.Error() == '\x00' and vk.Chapter() == versekey.Chapter() and mod.isLinked(vk, versekey)): start_verse = vk.Verse() vk.decrement(1) if start_verse == end_verse: verse = "%d" % start_verse else: verse = "%d-%d" % (start_verse, end_verse) u_vk.setText(internal_reference) if internal_reference.endswith(":0"): if start_verse != end_verse: print "WARNING: unhandled linked verse with verse 0" if versekey.Chapter() == 0: reference = u_vk.getBookName() else: reference = u_vk.get_book_chapter() else: reference = u_vk.get_book_chapter() reference += ":" + verse body_dict = dict( # text comes later versenumber = process_digits(verse, userOutput=True), chapternumber = process_digits( str(versekey.Chapter()), userOutput=True), booknumber = ord(versekey.Book()), bookabbrev = versekey.getBookAbbrev(), bookname = versekey.getBookName(), reference = reference, internal_reference = internal_reference, osisRef = osisRef, ) # usually RenderText flushes this out, but we haven't called # that yet - but we definitely don't want extraneous headings mod.getEntryAttributesMap().clear() # we want to do our pre-verse content first, but we can't # without running it through the optionFilter first. # we'll then have to run it through again after, otherwise our # entryattributes may go walkabout if raw: rawentry_str = rawentry.c_str() mod.optionFilter(rawentry, versekey) if raw: option_filtered = rawentry.c_str() headings = self.get_headings(internal_reference, mod) #versekey = VK.castTo(key) heading_dicts = [] raw_headings = [] for heading, canonical in headings: # the new-style pre-verse content lives wrapped up in # <div>'s - it will contain the <title>, but the div will # be stripped out. # the old-style pre-verse content lives in <title>'s, # which will also be stripped out. Unfortunately, it isn't # that easy to tell whether it did have a title, so we # employ a heuristic - if it starts with an <, it is a new # one... nh = heading.startswith("<") if stripped: heading = mod.StripText(heading).decode( "utf8", "replace" ) else: heading = render_text(heading).decode("utf8", "replace") if not nh: cls = " canonical" if (canonical and canonical == "true") else "" heading = '<h2 class="heading%s">%s</h2>\n' % (cls, heading) if raw: raw_headings.append(heading) heading_dict = dict(heading=heading, canonical=canonical) heading_dict.update(body_dict) heading_dicts.append(heading_dict) if stripped: text = mod.StripText(rawentry.c_str(), rawentry.length()).decode("utf-8", "replace") else: # we can't use rawentry due to a static local buffer in # swmodule.c; breaks gospel harmonies text = (render_text(#rawentry.c_str(), rawentry.length() ).decode("utf8", "replace")) # get our actual text if raw: text = self.process_raw(rawentry_str, text, versekey, mod, raw_headings, option_filtered) user_comments = self.get_user_comments(osisRef, versekey) # XXX: This needs to be done better than this. Move into # subclass somehow. if isinstance(self, Bible) and display_tags: tags = self.insert_tags(osisRef, versekey, exclude_topic_tag) else: tags = "" body_dict.update(dict(text=text, tags=tags, usercomments=user_comments)) yield body_dict, heading_dicts incrementer.increment(1) verses_left -= 1 finally: mod.setKey(SW.Key()) mod.setSkipConsecutiveLinks(old_mod_skiplinks) self.end_of_render = "" if render_end: self.end_of_render = render_end() def get_user_comments(self, osis_ref, verse_key): if not isinstance(self, Bible): return u"" manager = passage_list.get_primary_passage_list_manager() comments = u"".join( self.get_user_comment_div(passage_entry) for passage_entry in manager.get_all_passage_entries_for_verse(verse_key) if (self.get_tag_type_to_show(passage_entry) == "usercomment") ) return u'<span class="usercomment_container" osisRef="%s">%s</span>' % (osis_ref, comments) def get_user_comment_div(self, passage): passage_id = passage.get_id() return '<a class="usercomment" href="usercomment://%(passage_id)d" passageEntryId="%(passage_id)d"><sup>†</sup></a>' % locals() def insert_tags(self, osis_ref, verse_key, exclude_topic_tag): """Generates and returns all the passage tags for the given verse.""" manager = passage_list.get_primary_passage_list_manager() passage_tags = "".join( self.get_passage_topic_div(passage) for passage in manager.get_all_passage_entries_for_verse(verse_key) if (self.get_tag_type_to_show(passage, exclude_topic_tag) == "passage_tag") ) return u'<span class="passage_tag_container" osisRef="%s">%s</span>' % (osis_ref, passage_tags) def get_tag_type_to_show(self, passage, exclude_topic_tag=None): topic = passage.parent if (topic is not None and topic.parent is not None and topic is not exclude_topic_tag): if topic.can_display_tag: return "passage_tag" elif topic is passage_list.get_primary_passage_list_manager().comments_special_topic: return "usercomment" return None def get_passage_topic_div(self, passage): from gui import passage_tag topic_text = " > ".join(passage.parent.topic_trail) look, colour = passage.parent.resolve_tag_look() topic_id = passage.parent.get_id() passage_id = passage.get_id() return """ <a href="passagetag://passage/%(topic_id)d/%(passage_id)d" class="passage_tag passage_tag_%(colour)d_%(look)d" passageEntryId="%(passage_id)d"> <div> %(topic_text)s </div> </a> """ % locals() def get_headings(self, ref, mod=None): """Gets an array of the headings for the current verse. Must have just called RenderText on the verse you want headings for""" mod = mod or self.mod heading = SW.Buf("Heading") preverse = SW.Buf("Preverse") interverse = SW.Buf("Interverse") canonical = SW.Buf("canonical") headings = [] heading_types = [preverse, interverse] attrmap = mod.getEntryAttributesMap()#[SW.Buf("Heading") if heading in attrmap: h = attrmap[heading] if preverse in h: i = 0 p = h[preverse] while True: is_canonical = "false" i_buf = SW.Buf(str(i)) # try to see if this is a canonical heading # unfortunately, if there happens to be a interverse # heading after a canonical heading, it will overwrite it # so we may not get the correct answer. This oughtn't to # matter overly much if i_buf in h: attributes = h[i_buf] if(canonical in attributes and attributes[canonical].c_str() == "true"): is_canonical = "true" if i_buf in p: headings.append((p[i_buf].c_str(), is_canonical)) else: break i += 1 if not headings: dprint(WARNING, "no heading found for", ref) return headings def GetReferences(self, ref, context="", max_verses = -1): """Gets a list of references. In: ref - list of references context: context of first in list Out: A list of verses """ # TODO: If we have a list passed in like this: # ref= ['104:6', '8, 10, 105:1', '3'], context = 'PS 104:14' # for second item, GetVerseStr will return Psalms 104:8, instead # of Psalms 105:1, so the third retrieved will be 104:3, not 105:3 # Fixes: # Make GetVerseStr take last in list, not first as optional parameter results = [] lastref = context for j in ref: #get text results.append(self.GetReference(j, context=lastref, max_verses = max_verses)) # set context for next ref lastref = GetVerseStr(j, lastref) return results def GetFootnoteData(self, mod, passage, number, field): if mod != self.mod: if not isinstance(mod, SW.Module): mod = self.parent.get_module(mod) if mod is None: return None else: mod = self.mod vk = SW.Key(passage) mod.SetKey(vk) #set passage mod.RenderText() # force entry attributes to get set data = mod.getEntryAttributesMap()[SW.Buf("Footnote")] \ [SW.Buf(number)][SW.Buf(field)].c_str() # put it through the render filter before returning it return mod.RenderText(data).decode("utf8", "replace") def GetReferenceFromMod(self, mod, ref, max_verses = -1): oldmod = self.mod if not self.SetModule(mod, notify=False): return None try: verses = self.GetReference(ref, max_verses=max_verses) finally: self.SetModule(oldmod, notify=False) return verses def GetReferencesFromMod(self, mod, ref, context="", max_verses=-1): oldmod = self.mod if not self.SetModule(mod, notify=False): return None try: verses = self.GetReferences(ref, context, max_verses = max_verses) finally: self.SetModule(oldmod, notify=False) return verses def GetChapter(self, ref, specialref="", specialtemplate = None, context="", raw=False): self.vk.setText(to_str(ref, self.mod)) #get first ref text = self.vk.getText() match = re.match("([\w\s]+) (\d+):(\d+)", text) if match: book, chapter, verse = match.group(1, 2, 3) # include introductions - book introduction if necessary ref = "%s %s" % (book, chapter) text = "%s %s:0-%s %s" % (book, chapter, book, chapter) vk = SW.VerseKey() vk.Headings(1) list = vk.ParseVerseList(text, "", True) if chapter == "1": vk.setText("%s 0:0" % book) list.add(vk) #text = "%s 0:0-%s %s" % (book, book, chapter) if book == "Genesis": vk.Testament(0) list.add(vk) vk.Testament(1) list.add(vk) elif book == "Matthew": # set it to 0 first so that we come back to the testament # heading vk.Testament(0) vk.Testament(2) list.add(vk) list.sort() else: dprint(ERROR, "Couldn't parse verse text", text) return "" return self.GetReference(ref, specialref, specialtemplate, context, raw=raw, headings=True, verselist=list) def get_rendertext(self, mod=None): """Return the text render function. This makes sure that plaintext modules render whitespace properly""" module = mod or self.mod render_text = module.RenderText start = finish = None if module.getConfigEntry("SourceType") in (None, "Plaintext"): def render_text(*args): text = module.RenderText(*args) text = cgi.escape(text) return '<span class="plaintext">%s</span>' % text else: if ord(module.Markup()) == SW.FMT_OSIS: start = osisparser.p.block_start finish = osisparser.p.block_end return render_text, start, finish def has_feature(self, feature, module=None): if module is not None: oldmod = self.mod try: self.SetModule(module, notify=False) return self.has_feature(feature) finally: self.SetModule(oldmod, notify=False) if not self.mod: return False if self.features is None: self.features = [] mod = self.mod map = mod.getConfigMap() feature_buf = SW.Buf("Feature") featureBegin = map.lower_bound(feature_buf) featureEnd = map.upper_bound(feature_buf) while featureBegin != featureEnd: v = featureBegin.value() self.features.append(v[1].c_str()) featureBegin += 1 return feature in self.features def get_cipher_code(self, mod): """Return the cipher key for the module. This will be empty if locked, non-empty if unlocked and None if not enciphered""" return mod.getConfigEntry("CipherKey") def unlock(self, mod, key): assert self.get_cipher_code(mod) != None cm = mod.getConfigMap() cm[SW.Buf("CipherKey")] = SW.Buf(key) mgr = self.get_mgr(mod) mgr.setCipherKey(mod.Name(), key) conf = self.get_config(mod) conf.set(mod.Name(), "CipherKey", key) conf.Save() # send a refresh through for this book # TODO: do this better self.observers(self.mod) conf = self.get_config(mod) if conf.get(mod.Name(), "CipherKey") != key: raise FileSaveException( _("Couldn't save cipher key. You will have to set it again when you restart")) def has_chapter(self, ref, mod=None): assert self.is_verse_keyed, "Calling has_chapter for non-verse keyed module." module = mod or self.mod if module is None: return False vk = VK(ref) if module.hasEntry(vk): return True vk.setVerse(1) if module.hasEntry(vk): return True module.setKey(vk) try: old_mod_skiplinks = module.getSkipConsecutiveLinks() module.setSkipConsecutiveLinks(True) module.increment() next_vk = VK.castTo(module.getKey()) return (next_vk.Book() == vk.Book() and next_vk.Chapter() == vk.Chapter() and next_vk.Testament() == vk.Testament()) and not self.has_error(module) finally: module.setSkipConsecutiveLinks(old_mod_skiplinks) def get_mgr(self, mod): for path, mgr, modules in self.parent.mgrs: if mod in [m for name, m in modules]: return mgr return None def get_config(self, mod): pp = mod.getConfigEntry("PrefixPath") pp += "mods.d/%s.conf" % mod.Name().lower() # make sure it exists os.stat(pp) return SW.Config(pp) def process_raw(self, text, rendered_text, key, module, headings=(), option_filtered=""): kt = key.getOSISRefRangeText() or key.getText() kt = to_unicode(kt, module) if headings: headings = "<ul class='raw-headings'>%s</ul>" % ( '\n'.join("<li>%s</li>" % cgi.escape(heading) for heading in headings)) else: headings = "" if option_filtered: option_filtered = "<pre class='raw-option-filtered'>%s</pre>" % cgi.escape(option_filtered.decode("utf-8", "replace")) return u""" %s <div class='debug-raw-details' key='%s'> <pre class='raw-rendered'>%s</pre> %s <pre class='raw'>%s</pre> %s </div>""" % (rendered_text, cgi.escape(kt), cgi.escape(rendered_text), headings, cgi.escape(text.decode("utf-8", "replace")), option_filtered) @staticmethod def has_error(module): ERR_OK = chr(0) return (module.Error() != ERR_OK)