update columns code and add support for multiple columns

This commit is contained in:
Damien Elmes 2011-04-11 23:27:12 +09:00
parent 1d9f0176a5
commit 07c2591be0
2 changed files with 108 additions and 187 deletions

View file

@ -31,22 +31,21 @@ COLOUR_MARKED2 = "#aaaaff"
class DeckModel(QAbstractTableModel): class DeckModel(QAbstractTableModel):
def __init__(self, parent): def __init__(self, browser):
QAbstractTableModel.__init__(self) QAbstractTableModel.__init__(self)
self.parent = parent self.browser = browser
self.deck = parent.deck self.deck = browser.deck
self.filterTag = None
self.sortKey = None self.sortKey = None
# column title, display accessor, sort attr self.columns = ["question", "answer", "sortField", "cardDue", "cardEase"]
self.columns = [(_("Question"), self.currentQuestion),
(_("Answer"), self.currentAnswer),
[_("Due"), self.thirdColumn],
]
self.searchStr = ""
self.lastSearch = ""
self.cards = [] self.cards = []
self.cardObjs = {} self.cardObjs = {}
def getCard(self, index):
id = self.cards[index.row()]
if not id in self.cardObjs:
self.cardObjs[id] = self.deck.getCard(id)
return self.cardObjs[id]
# Model interface # Model interface
###################################################################### ######################################################################
@ -54,43 +53,40 @@ class DeckModel(QAbstractTableModel):
return len(self.cards) return len(self.cards)
def columnCount(self, index): def columnCount(self, index):
return 3 return len(self.columns)
def data(self, index, role): def data(self, index, role):
if not index.isValid(): if not index.isValid():
return QVariant() return QVariant()
if role == Qt.FontRole: if role == Qt.FontRole:
f = QFont() f = QFont()
f.setPixelSize(self.parent.mw.config['editFontSize']) f.setPixelSize(self.browser.mw.config['editFontSize'])
return QVariant(f) return QVariant(f)
if role == Qt.TextAlignmentRole and index.column() == 2: if role == Qt.TextAlignmentRole:
return QVariant(Qt.AlignHCenter) align = Qt.AlignVCenter
if index.column() > 1:
align |= Qt.AlignHCenter
return QVariant(align)
elif role == Qt.DisplayRole or role == Qt.EditRole: elif role == Qt.DisplayRole or role == Qt.EditRole:
c = self.getCard(index) return QVariant(self.columnData(index))
s = self.columns[index.column()][1](index)
s = self.limitContent(s)
s = s.replace("<br>", u" ")
s = s.replace("<br />", u" ")
s = s.replace("\n", u" ")
s = re.sub("\[sound:[^]]+\]", "", s)
s = stripHTMLMedia(s)
s = s.strip()
return QVariant(s)
else: else:
return QVariant() return QVariant()
def limitContent(self, txt):
if "<c>" in txt:
matches = re.findall("(?s)<c>(.*?)</c>", txt)
return " ".join(matches)
else:
return txt
def headerData(self, section, orientation, role): def headerData(self, section, orientation, role):
if orientation == Qt.Vertical: if orientation == Qt.Vertical:
return QVariant() return QVariant()
elif role == Qt.DisplayRole: elif role == Qt.DisplayRole:
return QVariant(self.columns[section][0]) type = self.columnType(section)
if type == "question":
txt = _("Question")
elif type == "answer":
txt = _("Answer")
else:
for stype, name in self.browser.sortTypes:
if type == stype:
txt = name
break
return QVariant(txt)
elif role == Qt.FontRole: elif role == Qt.FontRole:
f = QFont() f = QFont()
f.setPixelSize(10) f.setPixelSize(10)
@ -106,128 +102,91 @@ class DeckModel(QAbstractTableModel):
###################################################################### ######################################################################
def showMatching(self, force=True): def showMatching(self, force=True):
self.parent.mw.progress.start() self.browser.mw.progress.start()
t = time.time() t = time.time()
self.cards = self.deck.findCards(self.searchStr.strip()) self.cards = self.deck.findCards(self.searchStr.strip())
print "fetch cards in %dms" % ((time.time() - t)*1000) print "fetch cards in %dms" % ((time.time() - t)*1000)
self.parent.mw.progress.finish() self.browser.mw.progress.finish()
# if self.deck.getInt('reverseOrder'):
# self.cards.reverse()
self.reset() self.reset()
def refresh(self): def refresh(self):
self.cardObjs = {} self.cardObjs = {}
self.emit(SIGNAL("layoutChanged()")) self.emit(SIGNAL("layoutChanged()"))
# Tools # Column data
###################################################################### ######################################################################
def getCard(self, index): def columnType(self, column):
id = self.cards[index.row()] type = self.columns[column]
if not id in self.cardObjs: if type == "sortField":
self.cardObjs[id] = self.deck.getCard(id) type = self.deck.conf['sortType']
return self.cardObjs[id] if type == "factFld":
type = "cardDue"
return type
def currentQuestion(self, index): def columnData(self, index):
return self.getCard(index).q() row = index.row()
col = index.column()
def currentAnswer(self, index): type = self.columnType(col)
return self.getCard(index).a()
def nextDue(self, index):
c = self.getCard(index) c = self.getCard(index)
if type == "question":
return self.formatQA(c.q())
elif type == "answer":
return self.formatQA(c.a())
elif type == "factFld" or type == "cardDue":
return self.nextDue(c, index)
elif type == "factCrt":
return time.strftime("%Y-%m-%d", time.localtime(c.fact().crt))
elif type == "factMod":
return time.strftime("%Y-%m-%d", time.localtime(c.fact().mod))
elif type == "cardMod":
return time.strftime("%Y-%m-%d", time.localtime(c.mod))
elif type == "cardReps":
return str(c.reps)
elif type == "cardLapses":
return str(c.lapses)
elif type == "cardIvl":
return fmtTimeSpan(c.ivl*86400)
elif type == "cardEase":
return "%d%%" % (c.factor/10)
# def intervalColumn(self, index):
# return fmtTimeSpan(
# self.cards[index.row()][CARD_INTERVAL]*86400)
# def limitContent(self, txt):
# if "<c>" in txt:
# matches = re.findall("(?s)<c>(.*?)</c>", txt)
# return " ".join(matches)
# else:
# return txt
def formatQA(self, txt):
#s = self.limitContent(s)
s = txt.replace("<br>", u" ")
s = s.replace("<br />", u" ")
s = s.replace("\n", u" ")
s = re.sub("\[sound:[^]]+\]", "", s)
s = stripHTMLMedia(s)
s = s.strip()
return s
def nextDue(self, c, index):
if c.type == 0: if c.type == 0:
return _("(new card)") return _("(new card)")
elif c.type == 1: elif c.type == 1:
diff = c.due - time.time() date = c.due
elif c.type == 2: elif c.type == 2:
diff = (c.due - self.deck.sched.today)*86400 date = time.time() + ((c.due - self.deck.sched.today)*86400)
if diff <= 0: return time.strftime("%Y-%m-%d", time.localtime(date))
return _("%s ago") % fmtTimeSpan(abs(diff), pad=0)
else:
return _("in %s") % fmtTimeSpan(diff, pad=0)
def thirdColumn(self, index):
self.sortKey = "aoeu"
if self.sortKey == "created":
return self.createdColumn(index)
elif self.sortKey == "modified":
return self.modifiedColumn(index)
elif self.sortKey == "interval":
return self.intervalColumn(index)
elif self.sortKey == "reps":
return self.repsColumn(index)
elif self.sortKey == "factor":
return self.easeColumn(index)
elif self.sortKey == "noCount":
return self.noColumn(index)
elif self.sortKey == "fact":
return self.factCreatedColumn(index)
elif self.sortKey == "firstAnswered":
return self.firstAnsweredColumn(index)
else:
return self.nextDue(index)
def onSortChanged(self):
if self.sortKey == "created":
k = _("Created")
elif self.sortKey == "modified":
k = _("Modified")
elif self.sortKey == "interval":
k = _("Interval")
elif self.sortKey == "reps":
k = _("Reps")
elif self.sortKey == "factor":
k = _("Ease")
elif self.sortKey == "noCount":
k = _("Lapses")
elif self.sortKey == "firstAnswered":
k = _("First Answered")
elif self.sortKey == "fact":
k = _("Fact Created")
else:
k = _("Due")
self.columns[-1][0] = k
def createdColumn(self, index):
return time.strftime("%Y-%m-%d", time.localtime(
self.cards[index.row()][CARD_CREATED]))
def factCreatedColumn(self, index):
return time.strftime("%Y-%m-%d", time.localtime(
self.cards[index.row()][CARD_FACTCREATED]))
def modifiedColumn(self, index):
return time.strftime("%Y-%m-%d", time.localtime(
self.cards[index.row()][CARD_MODIFIED]))
def intervalColumn(self, index):
return fmtTimeSpan(
self.cards[index.row()][CARD_INTERVAL]*86400)
def repsColumn(self, index):
return str(self.cards[index.row()][CARD_REPS])
def easeColumn(self, index):
return "%0.2f" % self.cards[index.row()][CARD_EASE]
def noColumn(self, index):
return "%d" % self.cards[index.row()][CARD_NO]
def firstAnsweredColumn(self, index):
firstAnswered = self.cards[index.row()][CARD_FIRSTANSWERED]
if firstAnswered == 0:
return _("(new card)")
else:
return time.strftime("%Y-%m-%d", time.localtime(firstAnswered))
# Line painter # Line painter
###################################################################### ######################################################################
class StatusDelegate(QItemDelegate): class StatusDelegate(QItemDelegate):
def __init__(self, parent, model): def __init__(self, browser, model):
QItemDelegate.__init__(self, parent) QItemDelegate.__init__(self, browser)
self.model = model self.model = model
def paint(self, painter, option, index): def paint(self, painter, option, index):
@ -276,11 +235,11 @@ class Browser(QMainWindow):
self.form.splitter.setChildrenCollapsible(False) self.form.splitter.setChildrenCollapsible(False)
self.form.splitter_2.setChildrenCollapsible(False) self.form.splitter_2.setChildrenCollapsible(False)
self.form.splitter_3.setChildrenCollapsible(False) self.form.splitter_3.setChildrenCollapsible(False)
self.setupSort()
self.setupToolbar() self.setupToolbar()
self.setupTable() self.setupTable()
self.setupMenus() self.setupMenus()
self.setupSearch() self.setupSearch()
self.setupSort()
self.setupTree() self.setupTree()
self.setupHeaders() self.setupHeaders()
self.setupHooks() self.setupHooks()
@ -474,16 +433,20 @@ class Browser(QMainWindow):
def setupSort(self): def setupSort(self):
self.sortTypes = [ self.sortTypes = [
"factFld", ('factFld', _("Fields")),
"factCrt", ('factCrt', _("Creation date")),
"factMod", ('factMod', _("Edit date")),
"cardMod", ('cardMod', _("Review date")),
"cardDue", ('cardDue', _("Due date")),
"cardEase", ('cardIvl', _("Card interval")),
"cardReps", ('cardEase', _("Ease factor")),
"cardLapses", ('cardReps', _("Review count")),
('cardLapses', _("Lapse count")),
] ]
idx = self.sortTypes.index(self.deck.conf['sortType']) for c, (type, name) in enumerate(self.sortTypes):
self.form.sortBox.addItem(name)
if type == self.deck.conf['sortType']:
idx = c
self.form.sortBox.setCurrentIndex(idx) self.form.sortBox.setCurrentIndex(idx)
self.connect(self.form.sortBox, SIGNAL("activated(int)"), self.connect(self.form.sortBox, SIGNAL("activated(int)"),
self.sortChanged) self.sortChanged)
@ -505,11 +468,10 @@ class Browser(QMainWindow):
self.form.sortOrder.setIcon(QIcon(":/icons/view-sort-ascending.png")) self.form.sortOrder.setIcon(QIcon(":/icons/view-sort-ascending.png"))
def sortChanged(self, idx, refresh=True): def sortChanged(self, idx, refresh=True):
self.sortIndex = idx self.deck.conf['sortType'] = self.sortTypes[idx][0]
self.deck.conf['sortType'] = self.sortTypes[idx]
self.model.onSortChanged()
if refresh: if refresh:
self.model.showMatching() self.model.showMatching()
# fixme: we do this in various locations
self.updateFilterLabel() self.updateFilterLabel()
self.focusCard() self.focusCard()

View file

@ -119,48 +119,7 @@
</widget> </widget>
</item> </item>
<item row="0" column="4"> <item row="0" column="4">
<widget class="QComboBox" name="sortBox"> <widget class="QComboBox" name="sortBox"/>
<item>
<property name="text">
<string>Fields</string>
</property>
</item>
<item>
<property name="text">
<string>Creation date</string>
</property>
</item>
<item>
<property name="text">
<string>Edit date</string>
</property>
</item>
<item>
<property name="text">
<string>Review date</string>
</property>
</item>
<item>
<property name="text">
<string>Due date</string>
</property>
</item>
<item>
<property name="text">
<string>Ease factor</string>
</property>
</item>
<item>
<property name="text">
<string>Review count</string>
</property>
</item>
<item>
<property name="text">
<string>Lapse count</string>
</property>
</item>
</widget>
</item> </item>
</layout> </layout>
</item> </item>