mirror of
https://github.com/ankitects/anki.git
synced 2025-11-07 21:27:14 -05:00
new 'new' and 'save' behaviour, document dir per platform
- 'new' now creates or opens mydeck on new install - if not on a new install, open an in-memory database instead - saveas refactored to require saving of an in-memory db - autosave disabled until deck has an associated file - openonline uses a tmp file as it depends on a file at the moment. this can go away if the sync code is refactored in the future
This commit is contained in:
parent
a698f95b97
commit
75af04b383
2 changed files with 78 additions and 67 deletions
|
|
@ -154,4 +154,4 @@ question or answer on all cards."""), parent=self)
|
||||||
if not self.parent.config['saveAfterAdding']:
|
if not self.parent.config['saveAfterAdding']:
|
||||||
return
|
return
|
||||||
if (self.addedItems % self.parent.config['saveAfterAddingNum']) == 0:
|
if (self.addedItems % self.parent.config['saveAfterAddingNum']) == 0:
|
||||||
self.parent.saveDeck()
|
self.parent.onSave()
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ from PyQt4.QtCore import *
|
||||||
from PyQt4.QtWebKit import QWebPage
|
from PyQt4.QtWebKit import QWebPage
|
||||||
|
|
||||||
import os, sys, re, types, gettext, stat, traceback
|
import os, sys, re, types, gettext, stat, traceback
|
||||||
import shutil, time, glob
|
import shutil, time, glob, tempfile
|
||||||
|
|
||||||
from PyQt4.QtCore import *
|
from PyQt4.QtCore import *
|
||||||
from PyQt4.QtGui import *
|
from PyQt4.QtGui import *
|
||||||
|
|
@ -39,6 +39,7 @@ class AnkiQt(QMainWindow):
|
||||||
self.hideWelcome = False
|
self.hideWelcome = False
|
||||||
self.views = []
|
self.views = []
|
||||||
self.setLang()
|
self.setLang()
|
||||||
|
self.setupDocumentDir()
|
||||||
self.setupFonts()
|
self.setupFonts()
|
||||||
self.setupBackupDir()
|
self.setupBackupDir()
|
||||||
self.setupMainWindow()
|
self.setupMainWindow()
|
||||||
|
|
@ -90,7 +91,7 @@ class AnkiQt(QMainWindow):
|
||||||
self.addView(self.bodyView)
|
self.addView(self.bodyView)
|
||||||
self.statusView = ui.status.StatusView(self)
|
self.statusView = ui.status.StatusView(self)
|
||||||
self.addView(self.statusView)
|
self.addView(self.statusView)
|
||||||
|
|
||||||
def setupTray(self):
|
def setupTray(self):
|
||||||
self.trayIcon = ui.tray.AnkiTrayIcon(self)
|
self.trayIcon = ui.tray.AnkiTrayIcon(self)
|
||||||
|
|
||||||
|
|
@ -268,11 +269,11 @@ Please do not file a bug report with Anki.\n\n""")
|
||||||
elif evt.key() == Qt.Key_Right:
|
elif evt.key() == Qt.Key_Right:
|
||||||
mf.evaluateJavaScript("window.scrollBy(20,0)")
|
mf.evaluateJavaScript("window.scrollBy(20,0)")
|
||||||
elif evt.key() == Qt.Key_PageUp:
|
elif evt.key() == Qt.Key_PageUp:
|
||||||
mf.evaluateJavaScript("window.scrollBy(0,-%d)" %
|
mf.evaluateJavaScript("window.scrollBy(0,-%d)" %
|
||||||
int(0.9*self.bodyView.body.size().
|
int(0.9*self.bodyView.body.size().
|
||||||
height()))
|
height()))
|
||||||
elif evt.key() == Qt.Key_PageDown:
|
elif evt.key() == Qt.Key_PageDown:
|
||||||
mf.evaluateJavaScript("window.scrollBy(0,%d)" %
|
mf.evaluateJavaScript("window.scrollBy(0,%d)" %
|
||||||
int(0.9*self.bodyView.body.size().
|
int(0.9*self.bodyView.body.size().
|
||||||
height()))
|
height()))
|
||||||
|
|
||||||
|
|
@ -313,7 +314,7 @@ Please do not file a bug report with Anki.\n\n""")
|
||||||
num = self.config['saveAfterAnswerNum']
|
num = self.config['saveAfterAnswerNum']
|
||||||
stats = self.deck.getStats()
|
stats = self.deck.getStats()
|
||||||
if stats['gTotal'] % num == 0:
|
if stats['gTotal'] % num == 0:
|
||||||
self.saveDeck()
|
self.onSave()
|
||||||
self.moveToState("getQuestion")
|
self.moveToState("getQuestion")
|
||||||
|
|
||||||
def startRefreshTimer(self):
|
def startRefreshTimer(self):
|
||||||
|
|
@ -464,7 +465,7 @@ new:
|
||||||
anki.deck.backupDir = os.path.join(
|
anki.deck.backupDir = os.path.join(
|
||||||
self.config.configPath, "backups")
|
self.config.configPath, "backups")
|
||||||
|
|
||||||
def loadDeck(self, deckPath, sync=True, interactive=True):
|
def loadDeck(self, deckPath, sync=True, interactive=True, uprecent=True):
|
||||||
"Load a deck and update the user interface. Maybe sync."
|
"Load a deck and update the user interface. Maybe sync."
|
||||||
# return True on success
|
# return True on success
|
||||||
try:
|
try:
|
||||||
|
|
@ -500,7 +501,8 @@ To upgrade an old deck, download Anki 0.9.8.7.
|
||||||
Error was:\n%(f1)s\n...\n%(f2)s""") % {'f1': fmt1, 'f2': fmt2})
|
Error was:\n%(f1)s\n...\n%(f2)s""") % {'f1': fmt1, 'f2': fmt2})
|
||||||
self.moveToState("noDeck")
|
self.moveToState("noDeck")
|
||||||
return
|
return
|
||||||
self.updateRecentFiles(self.deck.path)
|
if uprecent:
|
||||||
|
self.updateRecentFiles(self.deck.path)
|
||||||
if sync and self.config['syncOnLoad']:
|
if sync and self.config['syncOnLoad']:
|
||||||
if self.syncDeck(interactive=False):
|
if self.syncDeck(interactive=False):
|
||||||
return True
|
return True
|
||||||
|
|
@ -538,7 +540,7 @@ Error was:\n%(f1)s\n...\n%(f2)s""") % {'f1': fmt1, 'f2': fmt2})
|
||||||
r = self.loadDeck(path, interactive=False)
|
r = self.loadDeck(path, interactive=False)
|
||||||
if r:
|
if r:
|
||||||
return r
|
return r
|
||||||
self.onNew(True)
|
self.onNew(initial=True)
|
||||||
|
|
||||||
def getDefaultDir(self, save=False):
|
def getDefaultDir(self, save=False):
|
||||||
"Try and get default dir from most recently opened file."
|
"Try and get default dir from most recently opened file."
|
||||||
|
|
@ -642,28 +644,30 @@ Error was:\n%(f1)s\n...\n%(f2)s""") % {'f1': fmt1, 'f2': fmt2})
|
||||||
"(Auto)save and close. Prompt if necessary. True if okay to proceed."
|
"(Auto)save and close. Prompt if necessary. True if okay to proceed."
|
||||||
self.hideWelcome = hideWelcome
|
self.hideWelcome = hideWelcome
|
||||||
if self.deck is not None:
|
if self.deck is not None:
|
||||||
count = self.deck.cardCount
|
if self.deck.modifiedSinceSave():
|
||||||
path = self.deck.path
|
if (self.deck.path is None or
|
||||||
name = self.deck.name()
|
(not self.config['saveOnClose'] and
|
||||||
# sync (saving automatically)
|
not self.config['syncOnClose'])):
|
||||||
|
# backed in memory or autosave/sync off, must confirm
|
||||||
|
while 1:
|
||||||
|
res = ui.unsaved.ask(self)
|
||||||
|
if res == ui.unsaved.save:
|
||||||
|
if self.onSave(required=True):
|
||||||
|
break
|
||||||
|
elif res == ui.unsaved.cancel:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
# auto sync (saving automatically)
|
||||||
if self.config['syncOnClose'] and self.deck.syncName:
|
if self.config['syncOnClose'] and self.deck.syncName:
|
||||||
self.syncDeck(False, reload=False)
|
self.syncDeck(False, reload=False)
|
||||||
while self.deckPath:
|
while self.deckPath:
|
||||||
self.app.processEvents()
|
self.app.processEvents()
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
return True
|
return True
|
||||||
# save
|
# auto save
|
||||||
if self.deck.modifiedSinceSave():
|
if self.config['saveOnClose'] or self.config['syncOnClose']:
|
||||||
if self.config['saveOnClose'] or self.config['syncOnClose']:
|
self.onSave()
|
||||||
self.saveDeck()
|
|
||||||
else:
|
|
||||||
res = ui.unsaved.ask(self)
|
|
||||||
if res == ui.unsaved.save:
|
|
||||||
self.saveDeck()
|
|
||||||
elif res == ui.unsaved.cancel:
|
|
||||||
return False
|
|
||||||
elif res == ui.unsaved.discard:
|
|
||||||
pass
|
|
||||||
# close
|
# close
|
||||||
self.deck.rollback()
|
self.deck.rollback()
|
||||||
self.deck.close()
|
self.deck.close()
|
||||||
|
|
@ -674,21 +678,17 @@ Error was:\n%(f1)s\n...\n%(f2)s""") % {'f1': fmt1, 'f2': fmt2})
|
||||||
ui.dialogs.closeAll()
|
ui.dialogs.closeAll()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def onNew(self, auto=False):
|
def onNew(self, initial=False, path=None):
|
||||||
if not self.saveAndClose(hideWelcome=True): return
|
if not self.saveAndClose(hideWelcome=True): return
|
||||||
if auto:
|
if initial:
|
||||||
self.deck = DeckStorage.Deck()
|
path = os.path.join(self.documentDir, "mydeck.anki")
|
||||||
else:
|
if os.path.exists(path):
|
||||||
file = self.onSaveAsOrNew(new=True)
|
# load mydeck instead
|
||||||
if not file:
|
return self.loadDeck(path)
|
||||||
return
|
self.deck = DeckStorage.Deck(path)
|
||||||
if os.path.exists(file):
|
|
||||||
os.unlink(file)
|
|
||||||
self.deck = DeckStorage.Deck(file)
|
|
||||||
self.deck.initUndo()
|
self.deck.initUndo()
|
||||||
self.deck.addModel(BasicModel())
|
self.deck.addModel(BasicModel())
|
||||||
self.saveDeck()
|
self.deck.save()
|
||||||
self.updateRecentFiles(self.deck.path)
|
|
||||||
self.moveToState("initial")
|
self.moveToState("initial")
|
||||||
|
|
||||||
def ensureSyncParams(self):
|
def ensureSyncParams(self):
|
||||||
|
|
@ -723,16 +723,17 @@ Error was:\n%(f1)s\n...\n%(f2)s""") % {'f1': fmt1, 'f2': fmt2})
|
||||||
def onOpenOnline(self):
|
def onOpenOnline(self):
|
||||||
self.ensureSyncParams()
|
self.ensureSyncParams()
|
||||||
if not self.saveAndClose(hideWelcome=True): return
|
if not self.saveAndClose(hideWelcome=True): return
|
||||||
self.onNew()
|
# we need a disk-backed file for syncing
|
||||||
if self.deck is None:
|
dir = tempfile.mkdtemp()
|
||||||
return
|
path = os.path.join(dir, u"untitled.anki")
|
||||||
|
self.onNew(path=path)
|
||||||
# ensure all changes come to us
|
# ensure all changes come to us
|
||||||
self.deck.modified = 0
|
self.deck.modified = 0
|
||||||
self.deck.s.commit()
|
self.deck.s.commit()
|
||||||
self.deck.syncName = "something"
|
self.deck.syncName = "something"
|
||||||
self.deck.lastLoaded = self.deck.modified
|
self.deck.lastLoaded = self.deck.modified
|
||||||
if self.config['syncUsername'] and self.config['syncPassword']:
|
if self.config['syncUsername'] and self.config['syncPassword']:
|
||||||
if self.syncDeck(onlyMerge=True):
|
if self.syncDeck(onlyMerge=True, reload=2):
|
||||||
return
|
return
|
||||||
self.deck = None
|
self.deck = None
|
||||||
self.moveToState("initial")
|
self.moveToState("initial")
|
||||||
|
|
@ -764,22 +765,24 @@ Error was:\n%(f1)s\n...\n%(f2)s""") % {'f1': fmt1, 'f2': fmt2})
|
||||||
def onOpenSamples(self):
|
def onOpenSamples(self):
|
||||||
self.onOpen(samples=True)
|
self.onOpen(samples=True)
|
||||||
|
|
||||||
def onSave(self):
|
def onSave(self, required=False):
|
||||||
if self.deck.modifiedSinceSave():
|
if not self.deck.path:
|
||||||
self.saveDeck()
|
if required:
|
||||||
else:
|
# backed in memory, make sure it's saved
|
||||||
self.setStatus(_("Deck is not modified."))
|
return self.onSaveAs()
|
||||||
|
return
|
||||||
|
if not self.deck.modifiedSinceSave():
|
||||||
|
return
|
||||||
|
self.deck.save()
|
||||||
|
self.updateTitleBar()
|
||||||
|
|
||||||
self.updateTitleBar()
|
def onSaveAs(self):
|
||||||
|
|
||||||
def onSaveAsOrNew(self, new=False):
|
|
||||||
"Prompt for a file name, then save."
|
"Prompt for a file name, then save."
|
||||||
if new:
|
title = _("Save Deck As")
|
||||||
title = "Name Deck"
|
if self.deck.path:
|
||||||
dir = anki.deck.ankiDir
|
|
||||||
else:
|
|
||||||
title = _("Save Deck As")
|
|
||||||
dir = os.path.dirname(self.deck.path)
|
dir = os.path.dirname(self.deck.path)
|
||||||
|
else:
|
||||||
|
dir = self.documentDir
|
||||||
file = QFileDialog.getSaveFileName(self, title,
|
file = QFileDialog.getSaveFileName(self, title,
|
||||||
dir,
|
dir,
|
||||||
_("Deck files (*.anki)"),
|
_("Deck files (*.anki)"),
|
||||||
|
|
@ -795,19 +798,12 @@ Error was:\n%(f1)s\n...\n%(f2)s""") % {'f1': fmt1, 'f2': fmt2})
|
||||||
if not ui.utils.askUser(
|
if not ui.utils.askUser(
|
||||||
"This file exists. Are you sure you want to overwrite it?"):
|
"This file exists. Are you sure you want to overwrite it?"):
|
||||||
return
|
return
|
||||||
if new:
|
|
||||||
return file
|
|
||||||
self.deck = self.deck.saveAs(file)
|
self.deck = self.deck.saveAs(file)
|
||||||
self.deck.initUndo()
|
self.deck.initUndo()
|
||||||
self.updateTitleBar()
|
self.updateTitleBar()
|
||||||
self.updateRecentFiles(self.deck.path)
|
self.updateRecentFiles(self.deck.path)
|
||||||
self.moveToState("initial")
|
self.moveToState("initial")
|
||||||
|
return file
|
||||||
def saveDeck(self):
|
|
||||||
self.setStatus(_("Saving..."))
|
|
||||||
self.deck.save()
|
|
||||||
self.updateTitleBar()
|
|
||||||
self.setStatus(_("Saving...done"))
|
|
||||||
|
|
||||||
# Opening and closing the app
|
# Opening and closing the app
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
@ -1124,8 +1120,7 @@ Error was:\n%(f1)s\n...\n%(f2)s""") % {'f1': fmt1, 'f2': fmt2})
|
||||||
def onImport(self):
|
def onImport(self):
|
||||||
if self.deck is None:
|
if self.deck is None:
|
||||||
self.onNew()
|
self.onNew()
|
||||||
if self.deck is not None:
|
ui.importing.ImportDialog(self)
|
||||||
ui.importing.ImportDialog(self)
|
|
||||||
|
|
||||||
def onExport(self):
|
def onExport(self):
|
||||||
ui.exporting.ExportDialog(self)
|
ui.exporting.ExportDialog(self)
|
||||||
|
|
@ -1219,7 +1214,6 @@ Error was:\n%(f1)s\n...\n%(f2)s""") % {'f1': fmt1, 'f2': fmt2})
|
||||||
if self.deck:
|
if self.deck:
|
||||||
# save first, so we can rollback on failure
|
# save first, so we can rollback on failure
|
||||||
self.deck.save()
|
self.deck.save()
|
||||||
self.deck.close()
|
|
||||||
# store data we need before closing the deck
|
# store data we need before closing the deck
|
||||||
self.deckPath = self.deck.path
|
self.deckPath = self.deck.path
|
||||||
self.syncName = self.deck.syncName or self.deck.name()
|
self.syncName = self.deck.syncName or self.deck.name()
|
||||||
|
|
@ -1231,6 +1225,7 @@ Error was:\n%(f1)s\n...\n%(f2)s""") % {'f1': fmt1, 'f2': fmt2})
|
||||||
t=time.time())
|
t=time.time())
|
||||||
else:
|
else:
|
||||||
self.sourcesToCheck = []
|
self.sourcesToCheck = []
|
||||||
|
self.deck.close()
|
||||||
self.deck = None
|
self.deck = None
|
||||||
self.loadAfterSync = reload
|
self.loadAfterSync = reload
|
||||||
# hide all deck-associated dialogs
|
# hide all deck-associated dialogs
|
||||||
|
|
@ -1265,10 +1260,15 @@ Error was:\n%(f1)s\n...\n%(f2)s""") % {'f1': fmt1, 'f2': fmt2})
|
||||||
"Reopen after sync finished."
|
"Reopen after sync finished."
|
||||||
self.mainWin.buttonStack.show()
|
self.mainWin.buttonStack.show()
|
||||||
if self.loadAfterSync:
|
if self.loadAfterSync:
|
||||||
self.loadDeck(self.deckPath, sync=False)
|
uprecent = self.loadAfterSync != 2
|
||||||
|
self.loadDeck(self.deckPath, sync=False, uprecent=uprecent)
|
||||||
self.deck.syncName = self.syncName
|
self.deck.syncName = self.syncName
|
||||||
self.deck.s.flush()
|
self.deck.s.flush()
|
||||||
self.deck.s.commit()
|
self.deck.s.commit()
|
||||||
|
if self.loadAfterSync == 2:
|
||||||
|
# special case for open online: mark temp deck as in-memory
|
||||||
|
self.deck.path = None
|
||||||
|
self.deck.flushMod()
|
||||||
elif not self.hideWelcome:
|
elif not self.hideWelcome:
|
||||||
self.moveToState("noDeck")
|
self.moveToState("noDeck")
|
||||||
self.deckPath = None
|
self.deckPath = None
|
||||||
|
|
@ -1367,7 +1367,7 @@ Error was:\n%(f1)s\n...\n%(f2)s""") % {'f1': fmt1, 'f2': fmt2})
|
||||||
self.connect(m.actionOpen, s, self.onOpen)
|
self.connect(m.actionOpen, s, self.onOpen)
|
||||||
self.connect(m.actionOpenSamples, s, self.onOpenSamples)
|
self.connect(m.actionOpenSamples, s, self.onOpenSamples)
|
||||||
self.connect(m.actionSave, s, self.onSave)
|
self.connect(m.actionSave, s, self.onSave)
|
||||||
self.connect(m.actionSaveAs, s, self.onSaveAsOrNew)
|
self.connect(m.actionSaveAs, s, self.onSaveAs)
|
||||||
self.connect(m.actionClose, s, self.onClose)
|
self.connect(m.actionClose, s, self.onClose)
|
||||||
self.connect(m.actionExit, s, self, SLOT("close()"))
|
self.connect(m.actionExit, s, self, SLOT("close()"))
|
||||||
self.connect(m.actionSyncdeck, s, self.syncDeck)
|
self.connect(m.actionSyncdeck, s, self.syncDeck)
|
||||||
|
|
@ -1743,3 +1743,14 @@ tag or delete references to missing files?"""))
|
||||||
|
|
||||||
def onUncacheLatex(self):
|
def onUncacheLatex(self):
|
||||||
anki.latex.deleteAllLatexImages(self.deck)
|
anki.latex.deleteAllLatexImages(self.deck)
|
||||||
|
|
||||||
|
# System specific misc
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
def setupDocumentDir(self):
|
||||||
|
if sys.platform.startswith("win32"):
|
||||||
|
raise "nyi"
|
||||||
|
elif sys.platform.startswith("darwin"):
|
||||||
|
self.documentDir = os.path.expanduser("~/Documents")
|
||||||
|
else:
|
||||||
|
self.documentDir = os.path.expanduser("~/.anki")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue