mirror of
https://github.com/ankitects/anki.git
synced 2025-09-21 15:32:23 -04:00
update config.py
- move into an sqlite file so we don't have to worry about db corruption anymore, and can share the deck list among multiple instances - remove some old options
This commit is contained in:
parent
fbb7fe8a3e
commit
c01c6cb79a
9 changed files with 128 additions and 195 deletions
|
@ -123,7 +123,7 @@ def run():
|
|||
if 'APPDATA' in os.environ:
|
||||
os.environ['HOME'] = os.environ['APPDATA']
|
||||
else:
|
||||
os.environ['HOME'] = "c:\\anki"
|
||||
mustQuit = True
|
||||
# make and check accessible
|
||||
try:
|
||||
os.makedirs(os.path.expanduser("~/.anki"))
|
||||
|
|
|
@ -22,10 +22,7 @@ class FocusButton(QPushButton):
|
|||
class AddCards(QDialog):
|
||||
|
||||
def __init__(self, parent):
|
||||
if parent.config['standaloneWindows']:
|
||||
windParent = None
|
||||
else:
|
||||
windParent = parent
|
||||
windParent = None
|
||||
QDialog.__init__(self, windParent, Qt.Window)
|
||||
self.parent = parent
|
||||
ui.utils.applyStyles(self)
|
||||
|
|
|
@ -342,10 +342,7 @@ class StatusDelegate(QItemDelegate):
|
|||
class EditDeck(QMainWindow):
|
||||
|
||||
def __init__(self, parent):
|
||||
if parent.config['standaloneWindows']:
|
||||
windParent = None
|
||||
else:
|
||||
windParent = parent
|
||||
windParent = None
|
||||
QMainWindow.__init__(self, windParent)
|
||||
applyStyles(self)
|
||||
self.parent = parent
|
||||
|
|
266
aqt/config.py
266
aqt/config.py
|
@ -3,132 +3,126 @@
|
|||
|
||||
# User configuration handling
|
||||
##########################################################################
|
||||
# The majority of the config is serialized into a string, both for easy access
|
||||
# and backwards compatibility. A separate table keeps track of seen decks, so
|
||||
# that multiple instances can update the recent decks list.
|
||||
|
||||
from PyQt4.QtGui import *
|
||||
from PyQt4.QtCore import *
|
||||
import os, sys, cPickle, locale, types, shutil, time, re, random
|
||||
import os, sys, time, random, cPickle
|
||||
from anki.db import DB
|
||||
|
||||
# compatability
|
||||
def unpickleWxFont(*args):
|
||||
pass
|
||||
def pickleWxFont(*args):
|
||||
pass
|
||||
defaultConf = {
|
||||
'confVer': 3,
|
||||
# remove?
|
||||
'colourTimes': True,
|
||||
'deckBrowserNameLength': 30,
|
||||
'deckBrowserOrder': 0,
|
||||
'deckBrowserRefreshPeriod': 3600,
|
||||
'factEditorAdvanced': False,
|
||||
'showStudyScreen': True,
|
||||
|
||||
class Config(dict):
|
||||
'recentDeckPaths': [],
|
||||
'interfaceLang': "en",
|
||||
|
||||
configDbName = "config.db"
|
||||
'autoplaySounds': True,
|
||||
'checkForUpdates': True,
|
||||
'created': time.time(),
|
||||
'deleteMedia': False,
|
||||
'documentDir': u"",
|
||||
'dropboxPublicFolder': u"",
|
||||
'editFontFamily': 'Arial',
|
||||
'editFontSize': 12,
|
||||
'editLineSize': 20,
|
||||
'editorReverseOrder': False,
|
||||
'iconSize': 32,
|
||||
'id': random.randrange(0, 2**63),
|
||||
'lastMsg': -1,
|
||||
'loadLastDeck': False,
|
||||
'mainWindowGeom': None,
|
||||
'mainWindowState': None,
|
||||
'mediaLocation': "",
|
||||
'numBackups': 30,
|
||||
'optimizeSmall': False,
|
||||
'preserveKeyboard': True,
|
||||
'proxyHost': '',
|
||||
'proxyPass': '',
|
||||
'proxyPort': 8080,
|
||||
'proxyUser': '',
|
||||
'qaDivider': True,
|
||||
'recentColours': ["#000000", "#0000ff"],
|
||||
'repeatQuestionAudio': True,
|
||||
'scrollToAnswer': True,
|
||||
'showCardTimer': True,
|
||||
'showProgress': True,
|
||||
'showTimer': True,
|
||||
'showToolbar': True,
|
||||
'showTrayIcon': False,
|
||||
'splitQA': True,
|
||||
'stripHTML': True,
|
||||
'studyOptionsTab': 0,
|
||||
'suppressEstimates': False,
|
||||
'suppressUpdate': False,
|
||||
'syncDisableWhenMoved': True,
|
||||
'syncOnLoad': False,
|
||||
'syncOnProgramOpen': True,
|
||||
'syncPassword': "",
|
||||
'syncUsername': "",
|
||||
}
|
||||
|
||||
def __init__(self, configPath):
|
||||
self.configPath = configPath
|
||||
if sys.platform == "win32":
|
||||
if self.configPath.startswith("~"):
|
||||
# windows sucks
|
||||
self.configPath = "c:\\anki"
|
||||
elif sys.platform.startswith("darwin"):
|
||||
if self.configPath == os.path.expanduser("~/.anki"):
|
||||
oldDb = self.getDbPath()
|
||||
self.configPath = os.path.expanduser(
|
||||
class Config(object):
|
||||
configDbName = "ankiprefs.db"
|
||||
|
||||
def __init__(self, confDir):
|
||||
self.confDir = confDir
|
||||
self._conf = {}
|
||||
if sys.platform.startswith("darwin") and (
|
||||
self.confDir == os.path.expanduser("~/.anki")):
|
||||
self.confDir = os.path.expanduser(
|
||||
"~/Library/Application Support/Anki")
|
||||
# upgrade?
|
||||
if (not os.path.exists(self.configPath) and
|
||||
os.path.exists(oldDb)):
|
||||
self.makeAnkiDir()
|
||||
newDb = self.getDbPath()
|
||||
shutil.copy2(oldDb, newDb)
|
||||
self.makeAnkiDir()
|
||||
self._addAnkiDirs()
|
||||
self.load()
|
||||
|
||||
def defaults(self):
|
||||
fields = {
|
||||
'addZeroSpace': False,
|
||||
'alternativeTheme': False,
|
||||
'autoplaySounds': True,
|
||||
'checkForUpdates': True,
|
||||
'colourTimes': True,
|
||||
'created': time.time(),
|
||||
'deckBrowserNameLength': 30,
|
||||
'deckBrowserOrder': 0,
|
||||
'deckBrowserRefreshPeriod': 3600,
|
||||
'deleteMedia': False,
|
||||
'documentDir': u"",
|
||||
'dropboxPublicFolder': u"",
|
||||
'editFontFamily': 'Arial',
|
||||
'editFontSize': 12,
|
||||
'editLineSize': 20,
|
||||
'editorReverseOrder': False,
|
||||
'extraNewCards': 5,
|
||||
'factEditorAdvanced': False,
|
||||
'forceLTR': False,
|
||||
'iconSize': 32,
|
||||
'id': random.randrange(0, 2**63),
|
||||
'interfaceLang': "",
|
||||
'lastMsg': -1,
|
||||
'loadLastDeck': False,
|
||||
'mainWindowGeom': None,
|
||||
'mainWindowState': None,
|
||||
# one of empty, 'dropbox', or path used as prefix
|
||||
'mediaLocation': "",
|
||||
'mainWindowState': None,
|
||||
'numBackups': 30,
|
||||
'optimizeSmall': False,
|
||||
'preserveKeyboard': True,
|
||||
'preventEditUntilAnswer': False,
|
||||
'proxyHost': '',
|
||||
'proxyPass': '',
|
||||
'proxyPort': 8080,
|
||||
'proxyUser': '',
|
||||
'qaDivider': True,
|
||||
'randomizeOnCram': True,
|
||||
'recentColours': ["#000000", "#0000ff"],
|
||||
'recentDeckPaths': [],
|
||||
'repeatQuestionAudio': True,
|
||||
'saveAfterAdding': True,
|
||||
'saveAfterAddingNum': 1,
|
||||
'saveAfterAnswer': True,
|
||||
'saveAfterAnswerNum': 10,
|
||||
'saveOnClose': True,
|
||||
'scrollToAnswer': True,
|
||||
'showCardTimer': True,
|
||||
'showFontPreview': False,
|
||||
'showLastCardContent': False,
|
||||
'showLastCardInterval': False,
|
||||
'showProgress': True,
|
||||
'showStudyScreen': True,
|
||||
'showStudyStats': True,
|
||||
'showTimer': True,
|
||||
'showToolbar': True,
|
||||
'showTrayIcon': False,
|
||||
'sortIndex': 0,
|
||||
'splitQA': True,
|
||||
'standaloneWindows': True,
|
||||
'stripHTML': True,
|
||||
'studyOptionsScreen': 0,
|
||||
'suppressEstimates': False,
|
||||
'suppressUpdate': False,
|
||||
'syncDisableWhenMoved': True,
|
||||
'syncInMsgBox': False,
|
||||
'syncOnLoad': False,
|
||||
'syncOnProgramOpen': True,
|
||||
'syncPassword': "",
|
||||
'syncUsername': "",
|
||||
}
|
||||
# disable sync on deck load when upgrading
|
||||
if not self.has_key("syncOnProgramOpen"):
|
||||
self['syncOnLoad'] = False
|
||||
self['syncOnClose'] = False
|
||||
for (k,v) in fields.items():
|
||||
if not self.has_key(k):
|
||||
# dict interface
|
||||
def get(self, *args):
|
||||
return self._conf.get(*args)
|
||||
def __getitem__(self, key):
|
||||
return self._conf[key]
|
||||
def __setitem__(self, key, val):
|
||||
self._conf[key] = val
|
||||
def __contains__(self, key):
|
||||
return self._conf.__contains__(key)
|
||||
|
||||
# load/save
|
||||
def load(self):
|
||||
path = self._dbPath()
|
||||
self.db = DB(path, level=None, text=str)
|
||||
self.db.executescript("""
|
||||
create table if not exists recentDecks (path not null);
|
||||
create table if not exists config (conf text not null);
|
||||
insert or ignore into config values ('');""")
|
||||
conf = self.db.scalar("select conf from config")
|
||||
if conf:
|
||||
self._conf.update(cPickle.loads(conf))
|
||||
else:
|
||||
self._conf.update(defaultConf)
|
||||
self._addDefaults()
|
||||
|
||||
def save(self):
|
||||
self.db.execute("update config set conf = ?",
|
||||
cPickle.dumps(self._conf))
|
||||
self.db.commit()
|
||||
|
||||
def _addDefaults(self):
|
||||
if self.get('confVer') >= defaultConf['confVer']:
|
||||
return
|
||||
for (k,v) in defaultConf.items():
|
||||
if k not in self:
|
||||
self[k] = v
|
||||
if not self['interfaceLang']:
|
||||
# guess interface and target languages
|
||||
(lang, enc) = locale.getdefaultlocale()
|
||||
self['interfaceLang'] = lang
|
||||
|
||||
def getDbPath(self):
|
||||
return os.path.join(self.configPath, self.configDbName)
|
||||
def _dbPath(self):
|
||||
return os.path.join(self.confDir, self.configDbName)
|
||||
|
||||
def makeAnkiDir(self):
|
||||
base = self.configPath
|
||||
def _addAnkiDirs(self):
|
||||
base = self.confDir
|
||||
for x in (base,
|
||||
os.path.join(base, "plugins"),
|
||||
os.path.join(base, "backups")):
|
||||
|
@ -137,41 +131,9 @@ class Config(dict):
|
|||
except:
|
||||
pass
|
||||
|
||||
def save(self):
|
||||
path = self.getDbPath()
|
||||
# write to a temp file
|
||||
from tempfile import mkstemp
|
||||
(fd, tmpname) = mkstemp(dir=os.path.dirname(path))
|
||||
tmpfile = os.fdopen(fd, 'w')
|
||||
cPickle.dump(dict(self), tmpfile)
|
||||
tmpfile.close()
|
||||
# the write was successful, delete config file (if exists) and rename
|
||||
if os.path.exists(path):
|
||||
os.unlink(path)
|
||||
os.rename(tmpname, path)
|
||||
|
||||
def fixLang(self, lang):
|
||||
if lang and lang not in ("pt_BR", "zh_CN", "zh_TW"):
|
||||
lang = re.sub("(.*)_.*", "\\1", lang)
|
||||
if not lang:
|
||||
lang = "en"
|
||||
return lang
|
||||
|
||||
def load(self):
|
||||
base = self.configPath
|
||||
db = self.getDbPath()
|
||||
# load config
|
||||
try:
|
||||
f = open(db)
|
||||
self.update(cPickle.load(f))
|
||||
except:
|
||||
# config file was corrupted previously
|
||||
def _importOldData(self):
|
||||
# compatability
|
||||
def unpickleWxFont(*args):
|
||||
pass
|
||||
def pickleWxFont(*args):
|
||||
pass
|
||||
self.defaults()
|
||||
# fix old recent deck path list
|
||||
for n in range(len(self['recentDeckPaths'])):
|
||||
s = self['recentDeckPaths'][n]
|
||||
if not isinstance(s, types.UnicodeType):
|
||||
self['recentDeckPaths'][n] = unicode(s, sys.getfilesystemencoding())
|
||||
# fix locale settings
|
||||
self["interfaceLang"] = self.fixLang(self["interfaceLang"])
|
||||
|
|
32
aqt/main.py
32
aqt/main.py
|
@ -594,10 +594,7 @@ counts are %d %d %d
|
|||
self.connect(self.mainWin.showAnswerButton, SIGNAL("clicked()"),
|
||||
lambda: self.moveToState("showAnswer"))
|
||||
if sys.platform.startswith("win32"):
|
||||
if self.config['alternativeTheme']:
|
||||
self.mainWin.showAnswerButton.setFixedWidth(370)
|
||||
else:
|
||||
self.mainWin.showAnswerButton.setFixedWidth(358)
|
||||
self.mainWin.showAnswerButton.setFixedWidth(358)
|
||||
else:
|
||||
self.mainWin.showAnswerButton.setFixedWidth(351)
|
||||
self.mainWin.showAnswerButton.setFixedHeight(41)
|
||||
|
@ -1309,9 +1306,6 @@ your deck."""))
|
|||
focusButton = openButton
|
||||
# more
|
||||
moreButton = QPushButton(_("More"))
|
||||
if sys.platform.startswith("win32") and \
|
||||
self.config['alternativeTheme']:
|
||||
moreButton.setFixedHeight(24)
|
||||
moreMenu = QMenu()
|
||||
a = moreMenu.addAction(QIcon(":/icons/edit-undo.png"),
|
||||
_("Hide From List"))
|
||||
|
@ -1549,7 +1543,7 @@ not be touched.""") %
|
|||
SIGNAL("clicked()"), self.onNewCategoriesClicked)
|
||||
self.connect(self.mainWin.revCategories,
|
||||
SIGNAL("clicked()"), self.onRevCategoriesClicked)
|
||||
self.mainWin.tabWidget.setCurrentIndex(self.config['studyOptionsScreen'])
|
||||
self.mainWin.tabWidget.setCurrentIndex(self.config['studyOptionsTab'])
|
||||
|
||||
def onNewCategoriesClicked(self):
|
||||
aqt.activetags.show(self, "new")
|
||||
|
@ -1706,13 +1700,6 @@ not be touched.""") %
|
|||
<tr><td>%(ntod_header)s</td><td align=right><b>%(new)s</b></td></tr>
|
||||
<tr><td>%(ntot_header)s</td><td align=right>%(newof)s</td></tr>
|
||||
</table>""") % h
|
||||
# if (not dyest and not dtoday) or not self.config['showStudyStats']:
|
||||
# self.haveYesterday = False
|
||||
# stats1 = ""
|
||||
# else:
|
||||
# self.haveYesterday = True
|
||||
# stats1 = (
|
||||
# "<td>%s</td><td> </td>" % stats1)
|
||||
self.mainWin.optionsLabel.setText("""\
|
||||
<p><table><tr>
|
||||
%s
|
||||
|
@ -1790,7 +1777,7 @@ learnt today")
|
|||
self.deck.reset()
|
||||
if not self.deck.finishScheduler:
|
||||
self.deck.startTimebox()
|
||||
self.config['studyOptionsScreen'] = self.mainWin.tabWidget.currentIndex()
|
||||
self.config['studyOptionsTab'] = self.mainWin.tabWidget.currentIndex()
|
||||
self.moveToState("getQuestion")
|
||||
|
||||
def onStudyOptions(self):
|
||||
|
@ -2137,8 +2124,7 @@ it to your friends.
|
|||
self.mainWin.retranslateUi(self)
|
||||
anki.lang.setLang(self.config["interfaceLang"], local=False)
|
||||
self.updateTitleBar()
|
||||
if self.config['interfaceLang'] in ("he","ar","fa") and \
|
||||
not self.config['forceLTR']:
|
||||
if self.config['interfaceLang'] in ("he","ar","fa"):
|
||||
self.app.setLayoutDirection(Qt.RightToLeft)
|
||||
else:
|
||||
self.app.setLayoutDirection(Qt.LeftToRight)
|
||||
|
@ -2565,10 +2551,8 @@ This deck already exists on your computer. Overwrite the local copy?"""),
|
|||
self.mainWin.actionSuspendCard.setEnabled(True)
|
||||
self.mainWin.actionDelete.setEnabled(True)
|
||||
self.mainWin.actionBuryFact.setEnabled(True)
|
||||
enableEdits = (not self.config['preventEditUntilAnswer'] or
|
||||
self.state != "getQuestion")
|
||||
self.mainWin.actionEditCurrent.setEnabled(enableEdits)
|
||||
self.mainWin.actionEditdeck.setEnabled(enableEdits)
|
||||
self.mainWin.actionEditCurrent.setEnabled(True)
|
||||
self.mainWin.actionEditdeck.setEnabled(True)
|
||||
runHook("enableCardMenuItems")
|
||||
|
||||
def maybeEnableUndo(self):
|
||||
|
@ -2635,7 +2619,7 @@ This deck already exists on your computer. Overwrite the local copy?"""),
|
|||
##########################################################################
|
||||
|
||||
def pluginsFolder(self):
|
||||
dir = self.config.configPath
|
||||
dir = self.config.confDir
|
||||
if sys.platform.startswith("win32"):
|
||||
dir = dir.encode(sys.getfilesystemencoding())
|
||||
return os.path.join(dir, "plugins")
|
||||
|
@ -2809,7 +2793,7 @@ to work with this version of Anki."""))
|
|||
|
||||
def setupSound(self):
|
||||
anki.sound.noiseProfile = os.path.join(
|
||||
self.config.configPath, "noise.profile").\
|
||||
self.config.confDir, "noise.profile").\
|
||||
encode(sys.getfilesystemencoding())
|
||||
anki.sound.checkForNoiseProfile()
|
||||
if sys.platform.startswith("darwin"):
|
||||
|
|
|
@ -173,7 +173,7 @@ class Preferences(QDialog):
|
|||
self.onOpenBackup)
|
||||
|
||||
def onOpenBackup(self):
|
||||
path = os.path.join(self.config.configPath, "backups")
|
||||
path = os.path.join(self.config.confDir, "backups")
|
||||
if sys.platform == "win32":
|
||||
anki.utils.call(["explorer", path.encode(
|
||||
sys.getfilesystemencoding())],
|
||||
|
@ -213,8 +213,6 @@ class Preferences(QDialog):
|
|||
self.dialog.showTimer.setChecked(self.config['showTimer'])
|
||||
self.dialog.showDivider.setChecked(self.config['qaDivider'])
|
||||
self.dialog.splitQA.setChecked(self.config['splitQA'])
|
||||
self.dialog.addZeroSpace.setChecked(self.config['addZeroSpace'])
|
||||
self.dialog.alternativeTheme.setChecked(self.config['alternativeTheme'])
|
||||
self.dialog.showProgress.setChecked(self.config['showProgress'])
|
||||
self.dialog.openLastDeck.setChecked(self.config['loadLastDeck'])
|
||||
self.dialog.deckBrowserOrder.setChecked(self.config['deckBrowserOrder'])
|
||||
|
@ -232,10 +230,7 @@ class Preferences(QDialog):
|
|||
self.config['showStudyScreen'] = self.dialog.showStudyOptions.isChecked()
|
||||
self.config['qaDivider'] = self.dialog.showDivider.isChecked()
|
||||
self.config['splitQA'] = self.dialog.splitQA.isChecked()
|
||||
self.config['addZeroSpace'] = self.dialog.addZeroSpace.isChecked()
|
||||
self.config['alternativeTheme'] = self.dialog.alternativeTheme.isChecked()
|
||||
self.config['showProgress'] = self.dialog.showProgress.isChecked()
|
||||
self.config['preventEditUntilAnswer'] = self.dialog.preventEdits.isChecked()
|
||||
self.config['stripHTML'] = self.dialog.stripHTML.isChecked()
|
||||
self.config['autoplaySounds'] = self.dialog.autoplaySounds.isChecked()
|
||||
self.config['loadLastDeck'] = self.dialog.openLastDeck.isChecked()
|
||||
|
|
|
@ -34,6 +34,7 @@ class StatusView(object):
|
|||
self.timer = None
|
||||
self.timerFlashStart = 0
|
||||
self.thinkingTimer = QTimer(parent)
|
||||
print "show timer"
|
||||
self.thinkingTimer.start(1000)
|
||||
parent.connect(self.thinkingTimer, SIGNAL("timeout()"),
|
||||
self.drawTimer)
|
||||
|
|
|
@ -262,7 +262,7 @@ def mungeQA(deck, txt):
|
|||
|
||||
def applyStyles(widget):
|
||||
try:
|
||||
styleFile = open(os.path.join(aqt.mw.config.configPath,
|
||||
styleFile = open(os.path.join(aqt.mw.config.confDir,
|
||||
"style.css"))
|
||||
widget.setStyleSheet(styleFile.read())
|
||||
except (IOError, OSError):
|
||||
|
|
|
@ -254,9 +254,6 @@ class View(object):
|
|||
|
||||
def mungeQA(self, deck, txt):
|
||||
txt = mungeQA(deck, txt)
|
||||
# hack to fix thai presentation issues
|
||||
if self.main.config['addZeroSpace']:
|
||||
txt = txt.replace("</span>", "​</span>")
|
||||
return txt
|
||||
|
||||
def onLoadFinished(self, bool):
|
||||
|
|
Loading…
Reference in a new issue