From bcfb8766646f28767df04342f40c9ad32d5be08a Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 5 Jan 2009 13:43:36 +0900 Subject: [PATCH] timeboxing, save fix, pref tweaks --- ankiqt/config.py | 4 +- ankiqt/ui/main.py | 141 +++++++++++++- ankiqt/ui/preferences.py | 6 +- designer/main.ui | 366 +++++++++++++++++++++++++++++++++--- designer/preferences.ui | 14 +- icons.qrc | 1 + icons/view-pim-calendar.png | Bin 0 -> 1486 bytes 7 files changed, 494 insertions(+), 38 deletions(-) create mode 100644 icons/view-pim-calendar.png diff --git a/ankiqt/config.py b/ankiqt/config.py index 88fb62e40..ee4fc841e 100644 --- a/ankiqt/config.py +++ b/ankiqt/config.py @@ -69,8 +69,10 @@ class Config(dict): 'qaDivider': True, 'splitQA': True, 'sortIndex': 0, - 'addZeroSpace': True, + 'addZeroSpace': False, 'alternativeTheme': False, + 'showStudyScreen': True, + 'showStudyOptions': False, } for (k,v) in fields.items(): if not self.has_key(k): diff --git a/ankiqt/ui/main.py b/ankiqt/ui/main.py index db985326f..c2fe000a9 100644 --- a/ankiqt/ui/main.py +++ b/ankiqt/ui/main.py @@ -19,6 +19,8 @@ from anki.media import rebuildMediaDir from anki.db import OperationalError from anki.stdmodels import BasicModel from anki.hooks import runHook, addHook, removeHook, _hooks +from anki.deck import newCardOrderLabels, newCardSchedulingLabels +from anki.deck import revCardOrderLabels import anki.latex import anki.lang import anki.deck @@ -50,6 +52,7 @@ class AnkiQt(QMainWindow): self.restoreGeometry(self.config['mainWindowGeom']) self.setupViews() self.setupEditor() + self.setupStudyScreen() self.setupButtons() self.setupAnchors() self.setupToolbar() @@ -195,9 +198,9 @@ Please do not file a bug report with Anki.\n\n""") self.state = state self.updateTitleBar() if 'state' != 'noDeck' and state != 'editCurrentFact': - self.showReviewScreen() + self.switchToReviewScreen() if state == "noDeck": - self.showWelcomeScreen() + self.switchToWelcomeScreen() self.help.hide() self.currentCard = None self.lastCard = None @@ -218,12 +221,17 @@ Please do not file a bug report with Anki.\n\n""") # if the same card is being shown and it's not # due yet, give up return self.moveToState("deckFinished") + if (self.config['showStudyScreen'] and + not self.deck.sessionStartTime): + return self.moveToState("studyScreen") + if self.deck.sessionLimitReached(): + return self.moveToState("studyScreen") self.enableCardMenuItems() return self.moveToState("showQuestion") else: return self.moveToState("deckFinished") elif state == "deckEmpty": - self.showWelcomeScreen() + self.switchToWelcomeScreen() self.disableCardMenuItems() elif state == "deckFinished": self.deck.s.flush() @@ -250,6 +258,10 @@ Please do not file a bug report with Anki.\n\n""") self.deck.s.flush() self.deck.refresh() return self.moveToState("auto") + elif state == "studyScreen": + self.currentCard = None + self.disableCardMenuItems() + self.showStudyScreen() self.updateViews(state) def keyPressEvent(self, evt): @@ -379,16 +391,19 @@ new: # Main stack ########################################################################## - def showWelcomeScreen(self): + def switchToWelcomeScreen(self): self.mainWin.mainStack.setCurrentIndex(1) self.hideButtons() - def showEditScreen(self): + def switchToEditScreen(self): self.mainWin.mainStack.setCurrentIndex(2) - def showReviewScreen(self): + def switchToStudyScreen(self): self.mainWin.mainStack.setCurrentIndex(3) + def switchToReviewScreen(self): + self.mainWin.mainStack.setCurrentIndex(4) + # Buttons ########################################################################## @@ -772,9 +787,10 @@ To upgrade an old deck, download Anki 0.9.8.7.""")) return self.onSaveAs() return if not self.deck.modifiedSinceSave(): - return + return True self.deck.save() self.updateTitleBar() + return True def onSaveAs(self): "Prompt for a file name, then save." @@ -892,7 +908,7 @@ To upgrade an old deck, download Anki 0.9.8.7.""")) def showEditor(self): self.showSaveEditorButton() - self.showEditScreen() + self.switchToEditScreen() self.editor.setFact(self.currentCard.fact) def onFactValid(self, fact): @@ -901,6 +917,108 @@ To upgrade an old deck, download Anki 0.9.8.7.""")) def onFactInvalid(self, fact): self.mainWin.saveEditorButton.setEnabled(False) + # Study screen + ########################################################################## + + def setupStudyScreen(self): + self.mainWin.newCardOrder.insertItems( + 0, QStringList(newCardOrderLabels().values())) + self.mainWin.newCardScheduling.insertItems( + 0, QStringList(newCardSchedulingLabels().values())) + self.mainWin.revCardOrder.insertItems( + 0, QStringList(revCardOrderLabels().values())) + self.connect(self.mainWin.optionsHelpButton, + SIGNAL("clicked()"), + lambda: QDesktopServices.openUrl(QUrl( + ankiqt.appWiki + "StudyOptions"))) + + def showStudyScreen(self): + self.switchToStudyScreen() + self.mainWin.optionsButton.setChecked(self.config['showStudyOptions']) + self.mainWin.optionsBox.setShown(self.config['showStudyOptions']) + initial = self.deck.sessionStartTime == 0 + if initial or not self.deck.sessionLimitReached(): + # deck just opened, or screen triggered manually + top = _("

Welcome back!

") + else: + top = _("

Well done!

") + # top label + h = {} + s = self.deck.getStats() + h['lapsed'] = '%s' % s['failed'] + h['ret'] = s['rev'] + h['new'] = '%s' % s['new'] + h['repsToday'] = '%s' % s['dTotal'] + h['repsIn5'] = '%s' % self.deck.s.scalar( + "select count(*) from reviewHistory where time > :t", + t = time.time() - 300) + h['timeToday'] = '%s' % ( + anki.utils.fmtTimeSpan(s['dReviewTime'], short=True)) + self.mainWin.optionsLabel.setText(top + _("""\ +

+ + +
+ + + + +
Reps done today:%(repsToday)s
Reps in last 5 mins:%(repsIn5)s
Total time today:%(timeToday)s
+ + + +
Lapsed due:%(lapsed)s
Retained due:%(ret)s
New due:%(new)s
""") % h) + # start reviewing button + self.mainWin.buttonStack.setCurrentIndex(3) + self.mainWin.buttonStack.show() + if initial: + self.mainWin.startReviewingButton.setText(_("Start &Reviewing")) + else: + self.mainWin.startReviewingButton.setText(_("Continue &Reviewing")) + self.mainWin.startReviewingButton.setFocus() + self.connect(self.mainWin.startReviewingButton, + SIGNAL("clicked()"), + self.onStartReview) + self.setupStudyOptions() + + def setupStudyOptions(self): + self.mainWin.newPerDay.setText(str(self.deck.newCardsPerDay)) + self.mainWin.minuteLimit.setText(str(self.deck.sessionTimeLimit/60.0)) + self.mainWin.questionLimit.setText(str(self.deck.sessionRepLimit)) + self.mainWin.newCardOrder.setCurrentIndex(self.deck.newCardOrder) + self.mainWin.newCardScheduling.setCurrentIndex(self.deck.newCardSpacing) + self.mainWin.revCardOrder.setCurrentIndex(self.deck.revCardOrder) + self.mainWin.delayLapsedCards.setChecked(not self.deck.delay0) + + def onStartReview(self): + self.config['showStudyOptions'] = self.mainWin.optionsButton.isChecked() + try: + self.deck.newCardsPerDay = int(self.mainWin.newPerDay.text()) + self.deck.sessionTimeLimit = float( + self.mainWin.minuteLimit.text()) * 60 + self.deck.sessionRepLimit = int(self.mainWin.questionLimit.text()) + except (ValueError, OverflowError): + pass + self.deck.newCardOrder = self.mainWin.newCardOrder.currentIndex() + self.deck.newCardSpacing = self.mainWin.newCardScheduling.currentIndex() + self.deck.revCardOrder = self.mainWin.revCardOrder.currentIndex() + # avoid clobbering the user's settings if they haven't changed + if self.deck.delay0 and self.mainWin.delayLapsedCards.isChecked(): + self.deck.delay0 = 0 + elif (not self.deck.delay0 and + not self.mainWin.delayLapsedCards.isChecked()): + self.deck.delay0 = 600 + if not self.deck.sessionStartTime or self.deck.sessionLimitReached(): + self.deck.startSession() + self.deck.flushMod() + self.moveToState("getQuestion") + + def onStudyOptions(self): + if self.state == "studyScreen": + self.onStartReview() + else: + self.moveToState("studyScreen") + # Toolbar ########################################################################## @@ -917,8 +1035,9 @@ To upgrade an old deck, download Anki 0.9.8.7.""")) mw.toolBar.addAction(mw.actionAddcards) mw.toolBar.addAction(mw.actionEditCurrent) mw.toolBar.addAction(mw.actionEditdeck) - mw.toolBar.addAction(mw.actionMarkCard) mw.toolBar.addAction(mw.actionGraphs) + mw.toolBar.addAction(mw.actionStudyOptions) + mw.toolBar.addAction(mw.actionMarkCard) mw.toolBar.addAction(mw.actionRepeatAudio) self.addToolBar(Qt.TopToolBarArea, mw.toolBar) mw.toolBar.setIconSize(QSize(self.config['iconSize'], @@ -1248,7 +1367,7 @@ To upgrade an old deck, download Anki 0.9.8.7.""")) self.connect(self.syncThread, SIGNAL("updateSyncProgress"), self.updateSyncProgress) self.connect(self.syncThread, SIGNAL("bulkSyncFailed"), self.bulkSyncFailed) self.syncThread.start() - self.showWelcomeScreen() + self.switchToWelcomeScreen() self.setEnabled(False) while not self.syncThread.isFinished(): self.app.processEvents() @@ -1353,6 +1472,7 @@ To upgrade an old deck, download Anki 0.9.8.7.""")) "Kstats", "Cstats", "ActiveTags", + "StudyOptions", ) deckRelatedMenus = ( @@ -1413,6 +1533,7 @@ To upgrade an old deck, download Anki 0.9.8.7.""")) self.connect(m.actionGetMoreDecks, s, self.onGetMoreDecks) self.connect(m.actionCacheLatex, s, self.onCacheLatex) self.connect(m.actionUncacheLatex, s, self.onUncacheLatex) + self.connect(m.actionStudyOptions, s, self.onStudyOptions) def enableDeckMenuItems(self, enabled=True): "setEnabled deck-related items." diff --git a/ankiqt/ui/preferences.py b/ankiqt/ui/preferences.py index 18c6b64f5..56a115733 100644 --- a/ankiqt/ui/preferences.py +++ b/ankiqt/ui/preferences.py @@ -165,7 +165,8 @@ class Preferences(QDialog): self.dialog.showToolbar.setChecked(self.config['showToolbar']) self.dialog.tallButtons.setChecked( self.config['easeButtonHeight'] != 'standard') - self.dialog.suppressEstimates.setChecked(self.config['suppressEstimates']) + self.dialog.showEstimates.setChecked(not self.config['suppressEstimates']) + self.dialog.showStudyOptions.setChecked(self.config['showStudyScreen']) self.dialog.showLastCardInterval.setChecked(self.config['showLastCardInterval']) self.dialog.showLastCardContent.setChecked(self.config['showLastCardContent']) self.dialog.showTray.setChecked(self.config['showTrayIcon']) @@ -188,7 +189,8 @@ class Preferences(QDialog): self.config['showLastCardContent'] = self.dialog.showLastCardContent.isChecked() self.config['showTrayIcon'] = self.dialog.showTray.isChecked() self.config['showTimer'] = self.dialog.showTimer.isChecked() - self.config['suppressEstimates'] = self.dialog.suppressEstimates.isChecked() + self.config['suppressEstimates'] = not self.dialog.showEstimates.isChecked() + self.config['showStudyScreen'] = self.dialog.showStudyOptions.isChecked() self.config['simpleToolbar'] = self.dialog.simpleToolbar.isChecked() self.config['scrollToAnswer'] = self.dialog.scrollToAnswer.isChecked() self.config['qaDivider'] = self.dialog.showDivider.isChecked() diff --git a/designer/main.ui b/designer/main.ui index b28f097f3..bf8b1af18 100644 --- a/designer/main.ui +++ b/designer/main.ui @@ -5,8 +5,8 @@ 0 0 - 655 - 487 + 827 + 648 @@ -27,8 +27,8 @@ 0 69 - 655 - 398 + 827 + 559 @@ -154,8 +154,8 @@ 0 0 - 370 - 343 + 542 + 504 @@ -164,8 +164,8 @@ 0 0 - 100 - 30 + 550 + 413 @@ -186,8 +186,8 @@ 0 0 - 100 - 30 + 550 + 413 @@ -202,19 +202,261 @@ + + + + 0 + 0 + 542 + 504 + + + + + + + + + + + <h1>Welcome!</h1> + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 10 + + + + + + + + + + + + Review &Options>> + + + true + + + false + + + false + + + + + + + Help + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + 2 + + + 0 + + + + + + 90 + 0 + + + + Time limit (mins): + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + + + + + Question limit: + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 90 + 0 + + + + New per day + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + + + + + + + + + + + + + + + + Delay lapsed cards until after reviews + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + - 3 + 4 0 0 - 370 + 542 49 @@ -249,7 +491,7 @@ 0 0 - 370 + 542 49 @@ -399,8 +641,8 @@ 0 0 - 100 - 30 + 542 + 49 @@ -434,7 +676,39 @@ 0 0 - 370 + 542 + 49 + + + + + + + Qt::Vertical + + + + 20 + 13 + + + + + + + + PushButton + + + + + + + + + 0 + 0 + 542 49 @@ -632,7 +906,7 @@ 0 0 - 655 + 827 23 @@ -761,6 +1035,7 @@ + @@ -778,8 +1053,8 @@ 0 - 467 - 655 + 628 + 827 20 @@ -792,7 +1067,7 @@ 0 23 - 655 + 827 46 @@ -827,6 +1102,7 @@ + @@ -1243,7 +1519,7 @@ - :/icons/chronometer.png:/icons/chronometer.png + :/icons/view-pim-calendar.png:/icons/view-pim-calendar.png C&ram... @@ -1351,9 +1627,55 @@ Uncache LaTeX + + + + :/icons/chronometer.png:/icons/chronometer.png + + + &Study Options + + + + optionsButton + optionsHelpButton + newPerDay + minuteLimit + questionLimit + newCardOrder + newCardScheduling + revCardOrder + delayLapsedCards + easeButton2 + easeButton3 + easeButton1 + easeButton4 + saveEditorButton + help + welcomeText + startReviewingButton + showAnswerButton + - + + + optionsButton + toggled(bool) + optionsBox + setShown(bool) + + + 98 + 134 + + + 219 + 190 + + + + diff --git a/designer/preferences.ui b/designer/preferences.ui index 970a13395..59fa87715 100644 --- a/designer/preferences.ui +++ b/designer/preferences.ui @@ -177,9 +177,16 @@ - + - Don't show next time before answer + Show next time before answer + + + + + + + Show study options on startup @@ -546,7 +553,8 @@ backgroundColour showDivider splitQA - suppressEstimates + showEstimates + showStudyOptions saveWhenClosing saveAfterEvery saveAfterEveryNum diff --git a/icons.qrc b/icons.qrc index d6c0dae44..f2915a5f2 100644 --- a/icons.qrc +++ b/icons.qrc @@ -1,5 +1,6 @@ + icons/view-pim-calendar.png icons/anki-tag.png icons/edit-redo.png icons/text-xml.png diff --git a/icons/view-pim-calendar.png b/icons/view-pim-calendar.png new file mode 100644 index 0000000000000000000000000000000000000000..2e02fc9b1bbd26e4e32234be05493288b8f8da06 GIT binary patch literal 1486 zcmV;<1u^=GP)^SJXL=$3T)wOPn4k&EXg;A#e6i=ZJ+*vI(>2Srs;fx!{iaVh`Ey2c zj`Pnue%`Ul5@k~F!B-CU#283Z9Tf*UK7WtqiX@?W)fp^xKMmqgN5#IQSC8z&99Wg{ z91gEN1;!X=W@hkN!`{GfcoM|c{B1V@L<8d=^#QQgUDO% z#$52+cA>hn8l0lcCAj111K~@}%#GQC($Z3I>F!qx$Ur#Ephg(lR{sDF)zzzcV0UN` zMI^;^W-r==DsTiz?eY;BNX<12+zv8qDR>`k_nI*knZn|< zT=b0J#mkG=p{DB~vONrsirc9$(gg5^X+YCdzrYw2S%yEuk8VTog+(tRqD4@7?I?!B z4^W)B9DoW%R`94uqG)PbTcGQ@%olHrU54Af0N-9e3005aMc*2n>pY8={w6360gsNU zXK7kZs6^aYJ07wc{|DYMov!nUG2o1N@Y2Yb?4r~nMlrn zO_otxa~gsmpuN2vvMfO|BCfG?9S6St%3R<6?lv?A0!9^Vu-RmuITz=Vd=HSgIZ7gl z^Q>a1J6ng&&fCVGFGK12^$0W@1`KiAL$iF}Ntm`KwgSoDUIJuEj59FwU>*g00~pf&d!>D6{n}CX`H(OQ4}F3s6bV96=r9`NOz^7{>O7>-0kWz%?=F> zqTxO*V}mZRW?=yoLW;o)JkL7h$~ z#oP_-`D8D>IMKZxcg}ZySWa0}(~&S`PU6&vR@iJdW*MM=5Ez92It3JQqWpR#VSdhe zw~vpHo8pS1SecVJjhSArWErqK>;OYdhKw;QOAen$mzs-HXY+GTWhZf(lOQ+1gWjE$ zoh@1hQk*IDQgTg;{PyE;K^kLjH5y5jUouluQ*_K|&uNX`Lng=!&zwqc%$?9wRkIAZ z(p>28>q9UY{O7`vY2+1&&Ni;uqSv^n$K#mH}N= ok3&_j2!I!l83vP(4z$taZ(le3Ps)hU9{>OV07*qoM6N<$f`jz2761SM literal 0 HcmV?d00001