# Copyright: Damien Elmes # License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html from PyQt4.QtGui import * from PyQt4.QtCore import * import anki import sys, time from ankiqt import ui from anki.hooks import addHook class QClickableLabel(QLabel): url = "http://ichi2.net/anki/wiki/TheTimerAndShortQuestions" def mouseReleaseEvent(self, evt): QDesktopServices.openUrl(QUrl(self.url)) class QClickableProgress(QProgressBar): url = "http://ichi2.net/anki/wiki/ProgressBars" def mouseReleaseEvent(self, evt): QDesktopServices.openUrl(QUrl(self.url)) # Status bar ########################################################################## class StatusView(object): "Manage the status bar as we transition through various states." warnTime = 10 def __init__(self, parent): self.main = parent self.statusbar = parent.mainWin.statusbar self.shown = [] self.hideBorders() self.setState("noDeck") self.timer = None self.timerFlashStart = 0 self.thinkingTimer = QTimer(parent) self.thinkingTimer.start(1000) parent.connect(self.thinkingTimer, SIGNAL("timeout()"), self.drawTimer) self.countTimer = QTimer(parent) self.countTimer.start(60000) parent.connect(self.countTimer, SIGNAL("timeout()"), self.updateCount) addHook("showQuestion", self.flashTimer) # State control ########################################################################## def setState(self, state): "Change to STATE, and update the display." self.state = state if self.state == "initial": self.showDeckStatus() elif self.state == "noDeck": self.hideDeckStatus() elif self.state in ("showQuestion", "deckFinished", "deckEmpty", "studyScreen"): self.redraw() self.showOrHideToolbar(self.state) def showOrHideToolbar(self, state): if (not self.main.config['showProgress'] and state in ("showQuestion", "showAnswer")): shown = False else: shown = True self.progressBar.setShown(shown) self.etaText.setShown(shown) self.remText.setShown(shown) self.sep1.setShown(shown) self.sep2.setShown(shown) # timer has a separate option if not self.main.config['showTimer']: shown = False self.timer.setShown(shown) self.sep3.setShown(shown) self.statusbar.hideOrShow() # Setup and teardown ########################################################################## def vertSep(self): spacer = QFrame() spacer.setFrameStyle(QFrame.VLine) spacer.setFrameShadow(QFrame.Plain) return spacer def showDeckStatus(self): if self.shown: return progressBarSize = (50, 14) # small spacer self.initialSpace = QWidget() self.addWidget(self.initialSpace, 1) # remaining & eta self.remText = QLabel() self.addWidget(self.remText, 0) self.sep1 = self.vertSep() self.addWidget(self.sep1, 0) self.etaText = QLabel() self.etaText.setToolTip(_( "

Estimated time

" "This is how long it will take to complete the current mode " "at your current pace.")) self.addWidget(self.etaText, 0) # progress&retention self.sep2 = self.vertSep() self.addWidget(self.sep2, 0) self.progressBar = QClickableProgress() self.progressBar.setFixedSize(*progressBarSize) self.progressBar.setMaximum(100) self.progressBar.setTextVisible(False) if QApplication.instance().style().objectName() != "plastique": self.plastiqueStyle = QStyleFactory.create("plastique") self.progressBar.setStyle(self.plastiqueStyle) self.addWidget(self.progressBar, 0) # timer self.sep3 = self.vertSep() self.addWidget(self.sep3, 0) self.timer = QClickableLabel() self.timer.setText("00:00") self.addWidget(self.timer) def addWidget(self, w, stretch=0): self.statusbar.addWidget(w, stretch) self.shown.append(w) def hideDeckStatus(self): for w in self.shown: self.statusbar.removeWidget(w) w.setParent(None) self.shown = [] def hideBorders(self): "Remove the ugly borders QT places on status bar widgets." self.statusbar.setStyleSheet("::item { border: 0; }") # Updating ########################################################################## def redraw(self): p = QPalette() stats = { 'failed': self.main.deck.failedSoonCount, 'new': self.main.deck.newCountToday, 'rev': self.main.deck.revCount, 'new2': self.main.deck.newCount } remStr = _("Remaining: ") if self.state == "deckFinished": remStr += "0" elif self.state == "deckEmpty": remStr += "0" else: # remaining string, bolded depending on current card if sys.platform.startswith("linux"): s = " " else: s = "  " if not self.main.currentCard: remStr += "%(failed1)s" + s + "%(rev1)s" + s + "%(new1)s" else: t = self.main.deck.cardQueue(self.main.currentCard) if t == 0: remStr += ("%(failed1)s" + s + "%(rev1)s" + s + "%(new1)s") elif t == 1: remStr += ("%(failed1)s" + s + "%(rev1)s" + s + "%(new1)s") else: remStr += ("%(failed1)s" + s + "%(rev1)s" + s + "%(new1)s") stats['failed1'] = '%s' % stats['failed'] stats['rev1'] = '%s' % stats['rev'] stats['new1'] = '%s' % stats['new'] self.remText.setText(remStr % stats) self.remText.setToolTip("

" +_( "Remaining cards") + "

" + ngettext("There is %d failed card due soon.", \ "There are %d failed cards due soon.", \ stats['failed']) % stats['failed'] + "
" + ngettext("There is %d card awaiting review.", "There are %d cards awaiting review.", \ stats['rev']) % stats['rev'] + "
" + ngettext("There is %d new card due today.", \ "There are %d new cards due today.",\ stats['new']) % stats['new'] + "

" + ngettext("There is %d new card in total.", \ "There are %d new cards in total.",\ stats['new2']) % stats['new2']) # eta print "need eta" self.etaText.setText(_("ETA: %(timeLeft)s")) # % stats) # retention & progress bars p.setColor(QPalette.Base, QColor("black")) p.setColor(QPalette.Button, QColor("black")) print "need yes total%" self.setProgressColour(p, 50) #stats['dYesTotal%']) self.progressBar.setPalette(p) self.progressBar.setValue(50) # tooltips self.progressBar.setToolTip( _("The percentage of correct answers this session.")) if self.main.config['showTimer']: self.drawTimer() self.timer.setToolTip(_("""

Time

Anki tracks how long you spend looking at a card.
This time is used to calculate the ETA, but not used
for scheduling.

You should aim to answer each question within
10 seconds. Click the timer to learn more.""")) def setProgressColour(self, palette, perc): if perc == 0: palette.setColor(QPalette.Highlight, QColor("black")) elif perc < 50: palette.setColor(QPalette.Highlight, QColor("#ee0000")) elif perc < 65: palette.setColor(QPalette.Highlight, QColor("#ee7700")) elif perc < 75: palette.setColor(QPalette.Highlight, QColor("#eeee00")) else: palette.setColor(QPalette.Highlight, QColor("#00ee00")) def drawTimer(self): if self.main.inDbHandler: return if not self.main.config['showTimer']: return if not self.timer: return if self.main.deck and self.main.state in ("showQuestion", "showAnswer"): if self.main.currentCard: if time.time() - self.timerFlashStart < 1: return if not self.main.config['showCardTimer']: return t = self.main.currentCard.thinkingTime() self.setTimer('%02d:%02d' % (t/60, t%60)) return self.setTimer("00:00") def flashTimer(self): if not (self.main.deck.sessionStartTime and self.main.deck.sessionTimeLimit): # or self.main.deck.reviewEarly: return t = time.time() - self.main.deck.sessionStartTime t = self.main.deck.sessionTimeLimit - t if t < 0: t = 0 self.setTimer('%02d:%02d' % (t/60, t%60)) self.timerFlashStart = time.time() def updateCount(self): if self.main.inDbHandler: return if not self.main.deck: return if self.state in ("deckFinished", "studyScreen"): self.main.deck.updateCutoff() self.main.deck.reset() self.redraw() self.main.updateTitleBar() if self.state == "studyScreen": self.main.updateStudyStats() def setTimer(self, txt): self.timer.setText("" + txt + " ")