def _renderQA(self, model, gname, data): "Returns hash of id, question, answer." # data is [cid, fid, mid, gid, ord, tags, flds] # unpack fields and create dict flist = splitFields(data[6]) fields = {} for (name, (idx, conf)) in model.fieldMap().items(): fields[name] = flist[idx] if fields[name]: fields[name] = '<span class="fm%s-%s">%s</span>' % ( hexifyID(data[2]), hexifyID(idx), fields[name]) else: fields[name] = "" fields['Tags'] = data[5] fields['Model'] = model.name fields['Group'] = gname template = model.templates[data[4]] fields['Template'] = template['name'] # render q & a d = dict(id=data[0]) for (type, format) in (("q", template['qfmt']), ("a", template['afmt'])): if type == "q": format = format.replace("cloze:", "cq:") else: if model.conf['clozectx']: name = "cactx:" else: name = "ca:" format = format.replace("cloze:", name) fields = runFilter("mungeFields", fields, model, gname, data, self) html = anki.template.render(format, fields) d[type] = runFilter( "mungeQA", html, type, fields, model, gname, data, self) return d
def rubify(txt): expr = '<span class="fm%s">' % hexifyID( [x.id for x in mw.currentCard.fact.model.fieldModels if x.name == "Expression"][0]) read = '<span class="fm%s">' % hexifyID( [x.id for x in mw.currentCard.fact.model.fieldModels if x.name == "Reading"][0]) txt = re.sub("([^ >]+?)\[(.+?)\]", """\ <span class="ezRuby" title="\\2">\\1</span>""", txt) txt = re.sub("> +", ">", txt) txt = re.sub(" +<", "<", txt) return txt
def genCSS(self): if not self.id: return "" # fields css = "".join(self._fieldCSS( ".fm%s-%s" % (hexifyID(self.id), hexifyID(f['ord'])), (f['font'], f['qsize'], f['qcol'], f['rtl'], f['pre'])) for f in self.fields) # templates css += "".join(".cm%s-%s {text-align:%s;background:%s}\n" % ( hexifyID(self.id), hexifyID(t['ord']), ("center", "left", "right")[t['align']], t['bg']) for t in self.templates) return css
def genCSS(self): if not self.id: return "" # fields css = "".join( self._fieldCSS( ".fm%s-%s" % (hexifyID(self.id), hexifyID(f['ord'])), ( f['font'], f['qsize'], f['qcol'], f['rtl'], f['pre'])) for f in self.fields) # templates css += "".join(".cm%s-%s {text-align:%s;background:%s}\n" % (hexifyID(self.id), hexifyID(t['ord']), ("center", "left", "right")[t['align']], t['bg']) for t in self.templates) return css
def formatQA(cid, mid, fact, tags, cm, deck): "Return a dict of {id, question, answer}" d = {'id': cid} fields = {} for (k, v) in fact.items(): fields["text:" + k] = stripHTML(v[1]) if v[1]: fields[k] = '<span class="fm%s">%s</span>' % (hexifyID(v[0]), v[1]) else: fields[k] = u"" fields['tags'] = tags[0] fields['Tags'] = tags[0] fields['modelTags'] = tags[1] fields['cardModel'] = tags[2] # render q & a ret = [] for (type, format) in (("question", cm.qformat), ("answer", cm.aformat)): # convert old style format = re.sub("%\((.+?)\)s", "{{\\1}}", format) # allow custom rendering functions & info fields = runFilter("prepareFields", fields, cid, mid, fact, tags, cm, deck) html = render(format, fields) d[type] = runFilter("formatQA", html, type, cid, mid, fact, tags, cm, deck) return d
def onDelete(self): model = self.selectedModel() row = self.dialog.modelsList.currentRow() if not model: return if len(self.d.models) < 2: ui.utils.showWarning(_("Please add another model first."), parent=self) return if self.d.s.scalar("select 1 from sources where id=:id", id=model.source): ui.utils.showWarning(_("This model is used by deck source:\n" "%s\nYou will need to remove the source " "first.") % hexifyID(model.source)) return count = self.d.modelUseCount(model) if count: if not ui.utils.askUser( _("This model is used by %d facts.\n" "Are you sure you want to delete it?\n" "If you delete it, these cards will be lost.") % count, parent=self): return self.d.deleteModel(model) self.updateModelsList() self.dialog.modelsList.setCurrentRow(row) self.parent.reset()
def onDelete(self): model = self.selectedModel() row = self.dialog.modelsList.currentRow() if not model: return if len(self.d.models) < 2: ui.utils.showWarning(_("Please add another model first."), parent=self) return if self.d.s.scalar("select 1 from sources where id=:id", id=model.source): ui.utils.showWarning(_("This model is used by deck source:\n" "%s\nYou will need to remove the source " "first.") % hexifyID(model.source)) return count = self.d.modelUseCount(model) if count: if not ui.utils.askUser( _("This model is used by %d facts.\n" "Are you sure you want to delete it?\n" "If you delete it, these cards will be lost.") % count, parent=self): return self.d.deleteModel(model) self.updateModelsList() self.dialog.modelsList.setCurrentRow(row)
def formatQA(cid, mid, fact, tags, cm, deck, build=False): "Return a dict of {id, question, answer}" d = {'id': cid} fields = {} for (k, v) in fact.items(): fields["text:"+k] = stripHTML(v[1]) if v[1]: fields[k] = '<span class="fm%s">%s</span>' % ( hexifyID(v[0]), v[1]) else: fields[k] = u"" fields['tags'] = tags[0] fields['Tags'] = tags[0] fields['modelTags'] = tags[1] fields['cardModel'] = tags[2] # render q & a ret = [] for (type, format) in (("question", cm.qformat), ("answer", cm.aformat)): # convert old style format = re.sub("%\((.+?)\)s", "{{\\1}}", format) # allow custom rendering functions & info fields = runFilter("prepareFields", fields, cid, mid, fact, tags, cm, deck) html = render(format, fields) d[type] = runFilter("formatQA", html, type, cid, mid, fact, tags, cm, deck, build) return d
def formatQA(cid, mid, fact, tags, cm): "Return a dict of {id, question, answer}" d = {'id': cid} fields = {} for (k, v) in fact.items(): fields["text:"+k] = v[1] if v[1]: fields[k] = '<span class="fm%s">%s</span>' % ( hexifyID(v[0]), v[1]) else: fields[k] = u"" fields['tags'] = tags[0] fields['Tags'] = tags[0] fields['modelTags'] = tags[1] fields['cardModel'] = tags[2] # render q & a ret = [] for (type, format) in (("question", cm.qformat), ("answer", cm.aformat)): try: html = format % fields except (KeyError, TypeError, ValueError): html = _("[invalid question/answer format]") d[type] = html return d
def getReading(card): if not "[" in card.fact.get(READING, ""): return # get the reading field read = [x.id for x in card.fact.model.fieldModels if x.name == READING] if not read: return return '<span class="fm%s">' % hexifyID(read[0])
def filterHint(a, currentCard): """If we are showing the hint, filter out the ANSWER_FIELDS""" if mw.state == "showHint": fieldIDs = ["fm" + hexifyID(field.id) for field in currentCard.fact.model.fieldModels if field.name in ANSWER_FIELDS] for fid in fieldIDs: p = re.compile('<span class="%s">' % fid) a = p.sub('<span class="%s" style="visibility:hidden">' % fid, a, re.IGNORECASE) return a
def htmlQuestion(self, type="question", align=True): div = '''<div class="card%s" id="cm%s%s">%s</div>''' % ( type[0], type[0], hexifyID(self.cardModelId), getattr(self, type)) # add outer div & alignment (with tables due to qt's html handling) if not align: return div attr = type + 'Align' if getattr(self.cardModel, attr) == 0: align = "center" elif getattr(self.cardModel, attr) == 1: align = "left" else: align = "right" return (("<center><table width=95%%><tr><td align=%s>" % align) + div + "</td></tr></table></center>")
def filterAnswer(txt): if (not "Japanese" in mw.currentCard.fact.model.tags and not "Mandarin" in mw.currentCard.fact.model.tags and not "Cantonese" in mw.currentCard.fact.model.tags): return txt if not "[" in mw.currentCard.fact.get('Reading', ""): return txt # get the reading field read = [x.id for x in mw.currentCard.fact.model.fieldModels if x.name == "Reading"] if not read: return txt read = '<span class="fm%s">' % hexifyID(read[0]) # replace def repl(match): return read + rubify(match.group(1)) + "</span>" txt = re.sub("%s(.*?)</span>" % read, repl, txt) return txt
def formatQAAsImage(html, type, cid, mid, fact, tags, cm, deck): # build up the html div = '''<div class="card%s" id="cm%s%s">%s</div>''' % ( type[0], type[0], hexifyID(cm.id), html) attr = type + 'Align' if getattr(cm, attr) == 0: align = "center" elif getattr(cm, attr) == 1: align = "left" else: align = "right" html = (("<center><table width=95%%><tr><td align=%s>" % align) + div + "</td></tr></table></center>") t = "<body><br><center>%s</center></body>" % (html) bg = "body { background-color: #fff; }\n" html = "<style>\n" + bg + deck.rebuildCSS() + "</style>\n" + t # create the web page object page = QWebPage() page.mainFrame().setHtml(html) # size everything all nice page = fitContentsInPage(page) image= QImage(page.viewportSize(), QImage.Format_ARGB32_Premultiplied) painter = QPainter(image) page.mainFrame().render(painter) painter.end() path = saveImage(image, deck) link = u"<img src=\"%s\">" % ( path ) #print link #print html return link
def formatQA(cid, mid, fact, tags, cm): "Return a dict of {id, question, answer}" d = {'id': cid} fields = {} for (k, v) in fact.items(): fields["text:" + k] = stripHTML(v[1]) if v[1]: fields[k] = '<span class="fm%s">%s</span>' % (hexifyID(v[0]), v[1]) else: fields[k] = u"" fields['tags'] = tags[0] fields['Tags'] = tags[0] fields['modelTags'] = tags[1] fields['cardModel'] = tags[2] # render q & a ret = [] for (type, format) in (("question", cm.qformat), ("answer", cm.aformat)): try: html = format % fields except (KeyError, TypeError, ValueError): html = _("[invalid question/answer format]") d[type] = runFilter("formatQA", html, type, cid, mid, fact, tags, cm) return d
def drawSourcesTable(self): self.dialog.sourcesTable.clear() self.dialog.sourcesTable.setRowCount(len(self.sources)) self.dialog.sourcesTable.setColumnCount(2) self.dialog.sourcesTable.setHorizontalHeaderLabels( QStringList([_("ID"), _("Name")])) self.dialog.sourcesTable.horizontalHeader().setResizeMode( QHeaderView.Stretch) self.dialog.sourcesTable.verticalHeader().hide() self.dialog.sourcesTable.setSelectionBehavior( QAbstractItemView.SelectRows) self.dialog.sourcesTable.setSelectionMode( QAbstractItemView.SingleSelection) self.sourceItems = [] n = 0 for (id, name) in self.sources: a = QTableWidgetItem(hexifyID(id)) b = QTableWidgetItem(name) self.sourceItems.append([a, b]) self.dialog.sourcesTable.setItem(n, 0, a) self.dialog.sourcesTable.setItem(n, 1, b) n += 1
def syncOneWayDeckName(self): return (self.deck.s.scalar("select name from sources where id = :id", id=self.server.deckName) or hexifyID(int(self.server.deckName)))
def cssClass(self): return "cm%s-%s" % (hexifyID( self.model().id), hexifyID(self.template()['ord']))
def append_JxPlugin(Answer,Card): """Append additional information about kanji and words in answer.""" # Guess the type(s) and the relevant content(s) of the Fact JxGuessedList = JxMagicalGuess(Card) # that's it. Chose the right name for the right job. This should always work now, lol... # Get and translate the new CardModel Template JxPrefix = u'' for (Type,Field,Content) in JxGuessedList: JxPrefix += JxAbbrev[Type] try: JxAnswer = JxLink[JxPrefix + u'-' + Card.cardModel.aformat] except KeyError: try: JxAnswer = JxLink["D-"+Card.cardModel.aformat] # in case the right template hasn't been set, we try with the default template "D:" except KeyError: return Answer # Then create a dictionnary for all data replacement strings... JxAnswerDict = { 'F':'','F-Stroke':'', 'K':'','W':'','S':'','G':'', 'K-Stroke':'','W-Stroke':'','S-Stroke':'','G-Stroke':'', "W-JLPT":'','W-Freq':'', 'K-JLPT':'','K-Jouyou':'','K-Freq':'', 'K-Words':'', 'W-Sentences':'' } # ${F-Types} JxAnswerDict['F-Types'] = str(JxGuessedList) # ${K}, ${W}, ${S}, ${G} and ${K-Stroke}, ${W-Stroke}, ${S-Stroke}, ${G-Stroke} for (Type,Field,Content) in JxGuessedList: ShortType = JxAbbrev[Type] Stripped = Content.strip() JxAnswerDict[ShortType] = Stripped KanjiList= [c for c in Stripped if JxIsKanji(c)] if ShortType != 'K': JxAnswerDict[ShortType + '-Stroke'] = JxStrokeDisplay(KanjiList,ShortType + '-Stroke') else: JxAnswerDict[ShortType + '-Stroke'] = ''.join(KanjiList) # need those for performance : every tenth second counts if you review 300+ Card a day # (the first brutal implementation had sometimes between 0.5s and 2s of lag to display the answer (i.e. make the user wait). JxK = JxAnswerDict['K'] JxW = JxAnswerDict['W'] JxS = JxAnswerDict['S'] JxG = JxAnswerDict['G'] # ${F} and ${F-Stroke} if JxGuessedList: JxAnswerDict['F'] = JxGuessedList[0][0].strip() JxAnswerDict['F-Stroke'] = u"""%s""" % ''.join([c for c in JxGuessedList[0][0].strip() if JxIsKanji(c)]) if JxW: try: # ${W-JLPT} JxAnswerDict['W-JLPT'] = '%s' % MapJLPTTango.String(JxW) except KeyError:pass try: # ${W-Freq} JxAnswerDict['W-Freq'] = '%s' % MapFreqTango.Value(JxW, lambda x:int(100*(log(x+1,2)-log(Jx_Word_MinOccurences+1,2))/(log(Jx_Word_MaxOccurences+1,2)-log(Jx_Word_MinOccurences+1,2)))) except KeyError:pass Query = """select expression.factId, expression.value, meaning.value, reading.value from fields as expression, fields as reading, fields as meaning, fieldModels as fmexpression, fieldModels as fmreading, fieldModels as fmmeaning where expression.fieldModelId= fmexpression.id and fmexpression.name in ("%s") and reading.fieldModelId= fmreading.id and fmreading.name="Reading" and reading.factId=expression.factId and meaning.fieldModelId= fmmeaning.id and fmmeaning.name="Meaning" and meaning.factId=expression.factId and expression.factId != "%s" and expression.value like "%%%s%%" """ % ('","'.join(JxTypeHash[u'Sentence'])+'","'.join(JxTypeHash[u'Word'])+'","'+'","'+JxExpression,Card.factId,JxW) result=mw.deck.s.all(Query) JxAnswerDict['W-Sentences'] = JxTableDisplay(result,'W-Sentences',u'Sentence') JxAnswerDict['W-Words'] = JxTableDisplay(result,'W-Words',u'Word') #for idioms and compound words if JxK: try: # ${K:JLPT} JxAnswerDict['K-JLPT'] = '%s' % MapJLPTKanji.String(JxK) except KeyError:pass try: # ${K:Jouyou} JxAnswerDict['K-Jouyou'] = '%s' % MapJouyouKanji.String(JxK) except KeyError:pass try: # ${K:Freq} JxAnswerDict['K-Freq'] = '%s' % MapFreqKanji.Value(JxK, lambda x:int((log(x+1,2)-log(Jx_Kanji_MaxOccurences+1,2))*10+100)) except KeyError:pass Query = """select expression.factId, expression.value, meaning.value, reading.value from fields as expression, fields as reading, fields as meaning, fieldModels as fmexpression, fieldModels as fmreading, fieldModels as fmmeaning where expression.fieldModelId= fmexpression.id and fmexpression.name in ("%s") and reading.fieldModelId= fmreading.id and fmreading.name="Reading" and reading.factId=expression.factId and meaning.fieldModelId= fmmeaning.id and fmmeaning.name="Meaning" and meaning.factId=expression.factId and expression.factId != "%s" and expression.value like "%%%s%%" """ % ('","'.join(JxTypeHash[u'Sentence'])+'","'+'","'.join(JxTypeHash[u'Word'])+'","'+JxExpression,Card.factId,JxK) result=mw.deck.s.all(Query) JxAnswerDict['K-Words'] = JxTableDisplay(result,'K-Words',u'Word') JxAnswerDict['K-Sentences'] = JxTableDisplay(result,'K-Sentences',u'Sentence') from controls import JxSettings JxAnswerDict['Css'] = '<style>%s</style>' % JxSettings.Get(u'Css') # ${<Field>} for FieldModel in Card.fact.model.fieldModels: JxAnswerDict[FieldModel.name] = '<span class="fm%s">%s</span>' % ( hexifyID(FieldModel.id), Card.fact[FieldModel.name]) # ${F-Tags}, ${M-Tags}, ${Tags} JxAnswerDict['F-Tags'] = Card.fact.tags JxAnswerDict['M-Tags'] = Card.fact.model.tags JxAnswerDict['Tags'] = " ".join(set(Card.fact.model.tags.split(" ") + Card.fact.tags.split(" ") + [Card.cardModel.name])) JxProfile("Fill JxCodes") JxAnswer = re.sub("\$\{(.*?)\}",lambda x:JxReplace(x,JxAnswerDict),JxAnswer) JxProfile("Substitutions") from controls import JxSettings Mode=JxSettings.Get(u'Mode') if Mode == "Append": JxAnswer = Answer + JxAnswer elif Mode == "Prepend": JxAnswer += Answer JxProfile("Concatenation") removeHook("drawAnswer",append_JxPlugin) JxAnswer = runFilter("drawAnswer",JxAnswer, Card) addHook("drawAnswer",append_JxPlugin) JxProfile("Filter") #JxShowProfile() return JxAnswer
def cssClass(self): return "cm%s-%s" % (hexifyID(self.model().id), hexifyID(self.template()['ord']))