type in answer patch from bernhard

This commit is contained in:
Damien Elmes 2011-01-27 07:09:25 +09:00
parent 57b816d573
commit 50e547d685

View file

@ -10,6 +10,7 @@ from anki.utils import stripHTML
from anki.hooks import runHook, runFilter from anki.hooks import runHook, runFilter
from anki.media import stripMedia from anki.media import stripMedia
import types, time, re, os, urllib, sys, difflib import types, time, re, os, urllib, sys, difflib
import unicodedata as ucd
from ankiqt import ui from ankiqt import ui
from ankiqt.ui.utils import mungeQA, getBase from ankiqt.ui.utils import mungeQA, getBase
from anki.utils import fmtTimeSpan from anki.utils import fmtTimeSpan
@ -141,13 +142,8 @@ class View(object):
and self.main.config['autoplaySounds']): and self.main.config['autoplaySounds']):
playFromText(q) playFromText(q)
def correct(self, a, b): def calculateOkBadStyle(self):
if b == "": "Precalculates styles for correct and incorrect part of answer"
return "";
ret = "";
s = difflib.SequenceMatcher(None, b, a)
sz = 20 sz = 20
fn = u"Arial" fn = u"Arial"
for fm in self.main.currentCard.fact.model.fieldModels: for fm in self.main.currentCard.fact.model.fieldModels:
@ -156,24 +152,61 @@ class View(object):
fn = fm.quizFontFamily or fn fn = fm.quizFontFamily or fn
break break
st = "background: %s; color: #000; font-size: %dpx; font-family: %s;" st = "background: %s; color: #000; font-size: %dpx; font-family: %s;"
ok = st % (passedCharColour, sz, fn) self.styleOk = st % (passedCharColour, sz, fn)
bad = st % (failedCharColour, sz, fn) self.styleBad = st % (failedCharColour, sz, fn)
def ok(self, a):
"returns given sring in style correct (green)"
if len(a) == 0:
return ""
return "<span style='%s'>%s</span>" % (self.styleOk, a)
def bad(self, a):
"returns given sring in style incorrect (red)"
if len(a) == 0:
return ""
return "<span style='%s'>%s</span>" % (self.styleBad, a)
def head(self, a):
return a[:len(a) - 1]
def tail(self, a):
return a[len(a) - 1:]
def applyStyle(self, testChar, correct, wrong):
"Calculates answer fragment depending on testChar's unicode category"
ZERO_SIZE = 'Mn'
if ucd.category(testChar) == ZERO_SIZE:
return self.ok(self.head(correct)) + self.bad(self.tail(correct) + wrong)
return self.ok(correct) + self.bad(wrong)
def correct(self, a, b):
"Diff-corrects the typed-in answer."
if b == "":
return "";
self.calculateOkBadStyle()
ret = ""
lastEqual = ""
s = difflib.SequenceMatcher(None, b, a)
for tag, i1, i2, j1, j2 in s.get_opcodes(): for tag, i1, i2, j1, j2 in s.get_opcodes():
if tag == "equal": if tag == "equal":
ret += ("<span style='%s'>%s</span>" % (ok, b[i1:i2])) lastEqual = b[i1:i2]
elif tag == "replace": elif tag == "replace":
ret += ("<span style='%s'>%s</span>" ret += self.applyStyle(b[i1], lastEqual,
% (bad, b[i1:i2] + (" " * ((j2 - j1) - (i2 - i1))))) b[i1:i2] + ("-" * ((j2 - j1) - (i2 - i1))))
lastEqual = ""
elif tag == "delete": elif tag == "delete":
p = re.compile(r"^\s*$") ret += self.applyStyle(b[i1], lastEqual, b[i1:i2])
if p.match(b[i1:i2]): lastEqual = ""
ret += ("<span style='%s'>%s</span>" % (ok, b[i1:i2]))
else:
ret += ("<span style='%s'>%s</span>" % (bad, b[i1:i2]))
elif tag == "insert": elif tag == "insert":
ret += ("<span style='%s'>%s</span>" % (bad, " " * (j2 - j1))) dashNum = (j2 - j1) if ucd.category(a[i1]) != 'Mn' else ((j2 - j1) - 1)
return ret ret += self.applyStyle(a[i1], lastEqual, "-" * dashNum)
lastEqual = ""
return ret + self.ok(lastEqual)
def drawAnswer(self): def drawAnswer(self):
"Show the answer." "Show the answer."
@ -188,7 +221,8 @@ class View(object):
cor = "" cor = ""
if cor: if cor:
given = unicode(self.main.typeAnswerField.text()) given = unicode(self.main.typeAnswerField.text())
res = self.correct(given, cor) res = self.correct(ucd.normalize('NFC', cor),
ucd.normalize('NFC', given))
a = res + "<br>" + a a = res + "<br>" + a
self.write(self.center('<span id=answer />' self.write(self.center('<span id=answer />'
+ self.mungeQA(self.main.deck, a))) + self.mungeQA(self.main.deck, a)))