mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 22:42:25 -04:00

Earlier today I pushed a change that split this code up into multiple repos, but that has proved to complicate things too much. So we're back to a single repo, except the individual submodules are better separated than they were before. The README files need updating again; I will push them out soon. Aside from splitting out the different modules, the sound code has moved from from anki to aqt.
234 lines
7.7 KiB
Python
234 lines
7.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright: Ankitects Pty Ltd and contributors
|
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
import datetime
|
|
import time
|
|
|
|
import anki.lang
|
|
import aqt
|
|
from anki.lang import _
|
|
from aqt import AnkiQt
|
|
from aqt.qt import *
|
|
from aqt.utils import askUser, openHelp, showInfo
|
|
|
|
|
|
class Preferences(QDialog):
|
|
def __init__(self, mw: AnkiQt):
|
|
QDialog.__init__(self, mw, Qt.Window)
|
|
self.mw = mw
|
|
self.prof = self.mw.pm.profile
|
|
self.form = aqt.forms.preferences.Ui_Preferences()
|
|
self.form.setupUi(self)
|
|
self.form.buttonBox.button(QDialogButtonBox.Help).setAutoDefault(False)
|
|
self.form.buttonBox.button(QDialogButtonBox.Close).setAutoDefault(False)
|
|
self.form.buttonBox.helpRequested.connect(lambda: openHelp("profileprefs"))
|
|
self.silentlyClose = True
|
|
self.setupLang()
|
|
self.setupCollection()
|
|
self.setupNetwork()
|
|
self.setupBackup()
|
|
self.setupOptions()
|
|
self.show()
|
|
|
|
def accept(self):
|
|
# avoid exception if main window is already closed
|
|
if not self.mw.col:
|
|
return
|
|
self.updateCollection()
|
|
self.updateNetwork()
|
|
self.updateBackup()
|
|
self.updateOptions()
|
|
self.mw.pm.save()
|
|
self.mw.reset()
|
|
self.done(0)
|
|
aqt.dialogs.markClosed("Preferences")
|
|
|
|
def reject(self):
|
|
self.accept()
|
|
|
|
# Language
|
|
######################################################################
|
|
|
|
def setupLang(self):
|
|
f = self.form
|
|
f.lang.addItems([x[0] for x in anki.lang.langs])
|
|
f.lang.setCurrentIndex(self.langIdx())
|
|
f.lang.currentIndexChanged.connect(self.onLangIdxChanged)
|
|
|
|
def langIdx(self):
|
|
codes = [x[1] for x in anki.lang.langs]
|
|
try:
|
|
return codes.index(anki.lang.getLang())
|
|
except:
|
|
return codes.index("en_US")
|
|
|
|
def onLangIdxChanged(self, idx):
|
|
code = anki.lang.langs[idx][1]
|
|
self.mw.pm.setLang(code)
|
|
showInfo(_("Please restart Anki to complete language change."), parent=self)
|
|
|
|
# Collection options
|
|
######################################################################
|
|
|
|
def setupCollection(self):
|
|
import anki.consts as c
|
|
|
|
f = self.form
|
|
qc = self.mw.col.conf
|
|
self._setupDayCutoff()
|
|
if isMac:
|
|
f.hwAccel.setVisible(False)
|
|
else:
|
|
f.hwAccel.setChecked(self.mw.pm.glMode() != "software")
|
|
f.lrnCutoff.setValue(qc["collapseTime"] / 60.0)
|
|
f.timeLimit.setValue(qc["timeLim"] / 60.0)
|
|
f.showEstimates.setChecked(qc["estTimes"])
|
|
f.showProgress.setChecked(qc["dueCounts"])
|
|
f.nightMode.setChecked(qc.get("nightMode", False))
|
|
f.newSpread.addItems(list(c.newCardSchedulingLabels().values()))
|
|
f.newSpread.setCurrentIndex(qc["newSpread"])
|
|
f.useCurrent.setCurrentIndex(int(not qc.get("addToCur", True)))
|
|
f.dayLearnFirst.setChecked(qc.get("dayLearnFirst", False))
|
|
if self.mw.col.schedVer() != 2:
|
|
f.dayLearnFirst.setVisible(False)
|
|
else:
|
|
f.newSched.setChecked(True)
|
|
|
|
def updateCollection(self):
|
|
f = self.form
|
|
d = self.mw.col
|
|
|
|
if not isMac:
|
|
wasAccel = self.mw.pm.glMode() != "software"
|
|
wantAccel = f.hwAccel.isChecked()
|
|
if wasAccel != wantAccel:
|
|
if wantAccel:
|
|
self.mw.pm.setGlMode("auto")
|
|
else:
|
|
self.mw.pm.setGlMode("software")
|
|
showInfo(_("Changes will take effect when you restart Anki."))
|
|
|
|
qc = d.conf
|
|
qc["dueCounts"] = f.showProgress.isChecked()
|
|
qc["estTimes"] = f.showEstimates.isChecked()
|
|
qc["newSpread"] = f.newSpread.currentIndex()
|
|
qc["nightMode"] = f.nightMode.isChecked()
|
|
qc["timeLim"] = f.timeLimit.value() * 60
|
|
qc["collapseTime"] = f.lrnCutoff.value() * 60
|
|
qc["addToCur"] = not f.useCurrent.currentIndex()
|
|
qc["dayLearnFirst"] = f.dayLearnFirst.isChecked()
|
|
self._updateDayCutoff()
|
|
self._updateSchedVer(f.newSched.isChecked())
|
|
d.setMod()
|
|
|
|
# Scheduler version
|
|
######################################################################
|
|
|
|
def _updateSchedVer(self, wantNew):
|
|
haveNew = self.mw.col.schedVer() == 2
|
|
|
|
# nothing to do?
|
|
if haveNew == wantNew:
|
|
return
|
|
|
|
if not askUser(
|
|
_(
|
|
"This will reset any cards in learning, clear filtered decks, and change the scheduler version. Proceed?"
|
|
)
|
|
):
|
|
return
|
|
|
|
if wantNew:
|
|
self.mw.col.changeSchedulerVer(2)
|
|
else:
|
|
self.mw.col.changeSchedulerVer(1)
|
|
|
|
# Day cutoff
|
|
######################################################################
|
|
|
|
def _setupDayCutoff(self):
|
|
if self.mw.col.schedVer() == 2:
|
|
self._setupDayCutoffV2()
|
|
else:
|
|
self._setupDayCutoffV1()
|
|
|
|
def _setupDayCutoffV1(self):
|
|
self.startDate = datetime.datetime.fromtimestamp(self.mw.col.crt)
|
|
self.form.dayOffset.setValue(self.startDate.hour)
|
|
|
|
def _setupDayCutoffV2(self):
|
|
self.form.dayOffset.setValue(self.mw.col.conf.get("rollover", 4))
|
|
|
|
def _updateDayCutoff(self):
|
|
if self.mw.col.schedVer() == 2:
|
|
self._updateDayCutoffV2()
|
|
else:
|
|
self._updateDayCutoffV1()
|
|
|
|
def _updateDayCutoffV1(self):
|
|
hrs = self.form.dayOffset.value()
|
|
old = self.startDate
|
|
date = datetime.datetime(old.year, old.month, old.day, hrs)
|
|
self.mw.col.crt = int(time.mktime(date.timetuple()))
|
|
|
|
def _updateDayCutoffV2(self):
|
|
self.mw.col.conf["rollover"] = self.form.dayOffset.value()
|
|
|
|
# Network
|
|
######################################################################
|
|
|
|
def setupNetwork(self):
|
|
self.form.syncOnProgramOpen.setChecked(self.prof["autoSync"])
|
|
self.form.syncMedia.setChecked(self.prof["syncMedia"])
|
|
if not self.prof["syncKey"]:
|
|
self._hideAuth()
|
|
else:
|
|
self.form.syncUser.setText(self.prof.get("syncUser", ""))
|
|
self.form.syncDeauth.clicked.connect(self.onSyncDeauth)
|
|
|
|
def _hideAuth(self):
|
|
self.form.syncDeauth.setVisible(False)
|
|
self.form.syncUser.setText("")
|
|
self.form.syncLabel.setText(
|
|
_(
|
|
"""\
|
|
<b>Synchronization</b><br>
|
|
Not currently enabled; click the sync button in the main window to enable."""
|
|
)
|
|
)
|
|
|
|
def onSyncDeauth(self):
|
|
self.prof["syncKey"] = None
|
|
self.mw.col.media.forceResync()
|
|
self._hideAuth()
|
|
|
|
def updateNetwork(self):
|
|
self.prof["autoSync"] = self.form.syncOnProgramOpen.isChecked()
|
|
self.prof["syncMedia"] = self.form.syncMedia.isChecked()
|
|
if self.form.fullSync.isChecked():
|
|
self.mw.col.modSchema(check=False)
|
|
self.mw.col.setMod()
|
|
|
|
# Backup
|
|
######################################################################
|
|
|
|
def setupBackup(self):
|
|
self.form.numBackups.setValue(self.prof["numBackups"])
|
|
|
|
def updateBackup(self):
|
|
self.prof["numBackups"] = self.form.numBackups.value()
|
|
|
|
# Basic & Advanced Options
|
|
######################################################################
|
|
|
|
def setupOptions(self):
|
|
self.form.pastePNG.setChecked(self.prof.get("pastePNG", False))
|
|
self.form.uiScale.setValue(self.mw.pm.uiScale() * 100)
|
|
|
|
def updateOptions(self):
|
|
self.prof["pastePNG"] = self.form.pastePNG.isChecked()
|
|
newScale = self.form.uiScale.value() / 100
|
|
if newScale != self.mw.pm.uiScale():
|
|
self.mw.pm.setUiScale(newScale)
|
|
showInfo(_("Changes will take effect when you restart Anki."))
|