use callback when closing windows
remove the old forceClose hack in favour of a callback when closing, so all windows have a chance to save properly before the collection is unloaded also: - fix a warning shown when opening about screen - require a call to editor.cleanup() when closing a window, to make sure any pending js callbacks don't try to fire on a deleted object - make sure we gc webview when closing editcurrent - main.py still needs refactoring to make use of the change
This commit is contained in:
parent
ca9d80c014
commit
8ab5a3a176
@ -38,8 +38,8 @@ except ImportError as e:
|
||||
|
||||
from anki.utils import checksum
|
||||
|
||||
# Dialog manager - manages modeless windows
|
||||
##########################################################################emacs
|
||||
# Dialog manager - manages non-modal windows
|
||||
##########################################################################
|
||||
|
||||
class DialogManager:
|
||||
|
||||
@ -65,18 +65,32 @@ class DialogManager:
|
||||
self._dialogs[name][1] = instance
|
||||
return instance
|
||||
|
||||
def close(self, name):
|
||||
def markClosed(self, name):
|
||||
self._dialogs[name] = [self._dialogs[name][0], None]
|
||||
|
||||
def closeAll(self):
|
||||
"True if all closed successfully."
|
||||
for (n, (creator, instance)) in list(self._dialogs.items()):
|
||||
if instance:
|
||||
if not instance.canClose():
|
||||
return False
|
||||
instance.forceClose = True
|
||||
instance.close()
|
||||
self.close(n)
|
||||
def allClosed(self):
|
||||
return not any(x[1] for x in self._dialogs.values())
|
||||
|
||||
def closeAll(self, onsuccess):
|
||||
# can we close immediately?
|
||||
if self.allClosed():
|
||||
onsuccess()
|
||||
return
|
||||
|
||||
# ask all windows to close and await a reply
|
||||
for (name, (creator, instance)) in self._dialogs.items():
|
||||
if not instance:
|
||||
continue
|
||||
|
||||
def callback():
|
||||
if self.allClosed():
|
||||
onsuccess()
|
||||
else:
|
||||
# still waiting for others to close
|
||||
pass
|
||||
|
||||
instance.closeWithCallback(callback)
|
||||
|
||||
return True
|
||||
|
||||
dialogs = DialogManager()
|
||||
|
17
aqt/about.py
17
aqt/about.py
@ -7,17 +7,18 @@ import aqt.forms
|
||||
from aqt import appVersion
|
||||
|
||||
class ClosableQDialog(QDialog):
|
||||
def canClose(self):
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
aqt.dialogs.close("About")
|
||||
aqt.dialogs.markClosed("About")
|
||||
QDialog.reject(self)
|
||||
|
||||
def accept(self):
|
||||
aqt.dialogs.close("About")
|
||||
aqt.dialogs.markClosed("About")
|
||||
QDialog.accept(self)
|
||||
|
||||
def closeWithCallback(self, callback):
|
||||
self.reject()
|
||||
callback()
|
||||
|
||||
def show(mw):
|
||||
dialog = ClosableQDialog(mw)
|
||||
mw.setupDialogGC(dialog)
|
||||
@ -124,6 +125,8 @@ please get in touch.")
|
||||
abouttext += '<p>' + _("A big thanks to all the people who have provided \
|
||||
suggestions, bug reports and donations.")
|
||||
abt.label.stdHtml(abouttext, js=" ")
|
||||
dialog.adjustSize()
|
||||
dialog.show()
|
||||
def resizeAndShow(arg):
|
||||
dialog.adjustSize()
|
||||
dialog.show()
|
||||
abt.label.evalWithCallback("1", resizeAndShow)
|
||||
return dialog
|
||||
|
@ -28,7 +28,6 @@ class AddCards(QDialog):
|
||||
self.setupButtons()
|
||||
self.onReset()
|
||||
self.history = []
|
||||
self.forceClose = False
|
||||
restoreGeom(self, "add")
|
||||
addHook('reset', self.onReset)
|
||||
addHook('currentModelChanged', self.onModelChange)
|
||||
@ -205,22 +204,32 @@ question on all cards."""), help="AddItems")
|
||||
return QDialog.keyPressEvent(self, evt)
|
||||
|
||||
def reject(self):
|
||||
if not self.canClose():
|
||||
return
|
||||
self.ifCanClose(self._reject)
|
||||
|
||||
def _reject(self):
|
||||
remHook('reset', self.onReset)
|
||||
remHook('currentModelChanged', self.onModelChange)
|
||||
clearAudioQueue()
|
||||
self.removeTempNote(self.editor.note)
|
||||
self.editor.setNote(None)
|
||||
self.editor.cleanup()
|
||||
self.modelChooser.cleanup()
|
||||
self.deckChooser.cleanup()
|
||||
self.mw.maybeReset()
|
||||
saveGeom(self, "add")
|
||||
aqt.dialogs.close("AddCards")
|
||||
aqt.dialogs.markClosed("AddCards")
|
||||
QDialog.reject(self)
|
||||
|
||||
def canClose(self):
|
||||
if (self.forceClose or self.editor.fieldsAreBlank() or
|
||||
askUser(_("Close and lose current input?"))):
|
||||
return True
|
||||
return False
|
||||
def ifCanClose(self, onOk):
|
||||
def afterSave():
|
||||
ok = (self.editor.fieldsAreBlank() or
|
||||
askUser(_("Close and lose current input?")))
|
||||
if ok:
|
||||
onOk()
|
||||
|
||||
self.editor.saveNow(afterSave)
|
||||
|
||||
def closeWithCallback(self, cb):
|
||||
def doClose():
|
||||
self._reject()
|
||||
cb()
|
||||
self.ifCanClose(doClose)
|
||||
|
@ -366,7 +366,6 @@ class Browser(QMainWindow):
|
||||
applyStyles(self)
|
||||
self.mw = mw
|
||||
self.col = self.mw.col
|
||||
self.forceClose = False
|
||||
self.lastFilter = ""
|
||||
self.focusTo = None
|
||||
self._previewWindow = None
|
||||
@ -459,26 +458,15 @@ class Browser(QMainWindow):
|
||||
curmax + 6)
|
||||
|
||||
def closeEvent(self, evt):
|
||||
if not self._closeEventHasCleanedUp:
|
||||
if self.editor.note and not self.forceClose:
|
||||
# ignore event for now to allow us to save
|
||||
self.editor.saveNow(self._closeEventAfterSave)
|
||||
evt.ignore()
|
||||
else:
|
||||
self._closeEventCleanup()
|
||||
evt.accept()
|
||||
self.mw.gcWindow(self)
|
||||
else:
|
||||
if self._closeEventHasCleanedUp:
|
||||
evt.accept()
|
||||
self.mw.gcWindow(self)
|
||||
return
|
||||
self.editor.saveNow(self._closeWindow)
|
||||
evt.ignore()
|
||||
|
||||
def _closeEventAfterSave(self):
|
||||
self._closeEventCleanup()
|
||||
self.close()
|
||||
|
||||
def _closeEventCleanup(self):
|
||||
def _closeWindow(self):
|
||||
self._cancelPreviewTimer()
|
||||
self.editor.setNote(None)
|
||||
self.editor.cleanup()
|
||||
saveSplitter(self.form.splitter, "editor3")
|
||||
saveGeom(self, "editor")
|
||||
saveState(self, "editor")
|
||||
@ -487,14 +475,18 @@ class Browser(QMainWindow):
|
||||
self.col.setMod()
|
||||
self.teardownHooks()
|
||||
self.mw.maybeReset()
|
||||
aqt.dialogs.close("Browser")
|
||||
aqt.dialogs.markClosed("Browser")
|
||||
self._closeEventHasCleanedUp = True
|
||||
self.mw.gcWindow(self)
|
||||
self.close()
|
||||
|
||||
def canClose(self):
|
||||
return True
|
||||
def closeWithCallback(self, onsuccess):
|
||||
def callback():
|
||||
self._closeWindow()
|
||||
onsuccess()
|
||||
self.editor.saveNow(callback)
|
||||
|
||||
def keyPressEvent(self, evt):
|
||||
"Show answer on RET or register answer."
|
||||
if evt.key() == Qt.Key_Escape:
|
||||
self.close()
|
||||
else:
|
||||
|
@ -12,13 +12,13 @@ class EditCurrent(QDialog):
|
||||
|
||||
def __init__(self, mw):
|
||||
QDialog.__init__(self, None, Qt.Window)
|
||||
mw.setupDialogGC(self)
|
||||
self.mw = mw
|
||||
self.form = aqt.forms.editcurrent.Ui_Dialog()
|
||||
self.form.setupUi(self)
|
||||
self.setWindowTitle(_("Edit Current"))
|
||||
self.setMinimumHeight(400)
|
||||
self.setMinimumWidth(500)
|
||||
self.rejected.connect(self.onSave)
|
||||
self.form.buttonBox.button(QDialogButtonBox.Close).setShortcut(
|
||||
QKeySequence("Ctrl+Return"))
|
||||
self.editor = aqt.editor.Editor(self.mw, self.form.fieldsArea, self)
|
||||
@ -40,15 +40,18 @@ class EditCurrent(QDialog):
|
||||
remHook("reset", self.onReset)
|
||||
self.editor.setNote(None)
|
||||
self.mw.reset()
|
||||
aqt.dialogs.close("EditCurrent")
|
||||
aqt.dialogs.markClosed("EditCurrent")
|
||||
self.close()
|
||||
return
|
||||
self.editor.setNote(n)
|
||||
|
||||
def onSave(self):
|
||||
self.editor.saveNow(self._onSave)
|
||||
def reject(self):
|
||||
self.saveAndClose()
|
||||
|
||||
def _onSave(self):
|
||||
def saveAndClose(self):
|
||||
self.editor.saveNow(self._saveAndClose)
|
||||
|
||||
def _saveAndClose(self):
|
||||
remHook("reset", self.onReset)
|
||||
r = self.mw.reviewer
|
||||
try:
|
||||
@ -58,9 +61,14 @@ class EditCurrent(QDialog):
|
||||
pass
|
||||
else:
|
||||
self.mw.reviewer.cardQueue.append(self.mw.reviewer.card)
|
||||
self.editor.cleanup()
|
||||
self.mw.moveToState("review")
|
||||
saveGeom(self, "editcurrent")
|
||||
aqt.dialogs.close("EditCurrent")
|
||||
aqt.dialogs.markClosed("EditCurrent")
|
||||
QDialog.reject(self)
|
||||
|
||||
def canClose(self):
|
||||
return True
|
||||
def closeWithCallback(self, onsuccess):
|
||||
def callback():
|
||||
self._saveAndClose()
|
||||
onsuccess()
|
||||
self.editor.saveNow(callback)
|
||||
|
@ -319,6 +319,11 @@ class Editor:
|
||||
return False
|
||||
return True
|
||||
|
||||
def cleanup(self):
|
||||
self.setNote(None)
|
||||
# prevent any remaining evalWithCallback() events from firing after C++ object deleted
|
||||
self.web = None
|
||||
|
||||
# HTML editing
|
||||
######################################################################
|
||||
|
||||
|
@ -530,7 +530,8 @@ title="%s" %s>%s</button>''' % (
|
||||
self.form.centralwidget.setLayout(self.mainLayout)
|
||||
|
||||
def closeAllCollectionWindows(self):
|
||||
return aqt.dialogs.closeAll()
|
||||
aqt.dialogs.closeAll(lambda: 1)
|
||||
return True
|
||||
|
||||
# Components
|
||||
##########################################################################
|
||||
|
@ -42,14 +42,15 @@ class DeckStats(QDialog):
|
||||
self.show()
|
||||
self.activateWindow()
|
||||
|
||||
def canClose(self):
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
saveGeom(self, self.name)
|
||||
aqt.dialogs.close("DeckStats")
|
||||
aqt.dialogs.markClosed("DeckStats")
|
||||
QDialog.reject(self)
|
||||
|
||||
def closeWithCallback(self, callback):
|
||||
self.reject()
|
||||
callback()
|
||||
|
||||
def _imagePath(self):
|
||||
name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf",
|
||||
time.localtime(time.time()))
|
||||
|
Loading…
Reference in New Issue
Block a user