diff --git a/ankiqt/ui/addcards.py b/ankiqt/ui/addcards.py
index e4186ade1..a121708ba 100644
--- a/ankiqt/ui/addcards.py
+++ b/ankiqt/ui/addcards.py
@@ -92,6 +92,8 @@ class AddCards(QDialog):
# make sure updated
self.editor.saveFieldsNow()
fact = self.editor.fact
+ n = _("Add")
+ self.parent.deck.setUndoStart(n)
try:
cards = self.parent.deck.addFact(fact)
except FactInvalidError:
@@ -109,6 +111,7 @@ question or answer on all cards. Can't proceed."""), parent=self)
# we're guaranteed that all fields will exist now
"str": stripHTML(fact[fact.fields[0].name]),
})
+ self.parent.deck.setUndoEnd(n)
self.parent.updateTitleBar()
# start a new fact
f = self.parent.deck.newFact()
diff --git a/ankiqt/ui/cardlist.py b/ankiqt/ui/cardlist.py
index 6f8557f81..ab3016c52 100644
--- a/ankiqt/ui/cardlist.py
+++ b/ankiqt/ui/cardlist.py
@@ -223,7 +223,7 @@ class EditDeck(QMainWindow):
self.updateFilterLabel()
restoreGeom(self, "editor")
self.show()
- self.selectLastCard()
+ self.updateSearch()
def findCardInDeckModel(self, model, card):
for i, thisCard in enumerate(model.cards):
@@ -231,18 +231,6 @@ class EditDeck(QMainWindow):
return i
return -1
- def selectLastCard(self):
- "Show the row corresponding to the current card."
- self.updateSearch()
- if self.parent.currentCard:
- currentCardIndex = self.findCardInDeckModel(
- self.model, self.parent.currentCard)
- if currentCardIndex >= 0:
- self.dialog.tableView.selectRow(currentCardIndex)
- self.dialog.tableView.scrollTo(
- self.model.index(currentCardIndex,0),
- self.dialog.tableView.PositionAtTop)
-
def setupFilter(self):
self.filterTimer = None
self.currentTag = None
@@ -318,6 +306,8 @@ class EditDeck(QMainWindow):
if refresh:
self.model.showMatching()
self.updateFilterLabel()
+ self.onEvent()
+ self.focusCurrentCard()
def tagChanged(self, idx):
if idx == 0:
@@ -339,6 +329,20 @@ class EditDeck(QMainWindow):
{"cur": len(self.model.cards),
"tot": self.deck.cardCount})
+ def onEvent(self):
+ if self.deck.undoAvailable():
+ self.dialog.actionUndo.setText(_("Undo %s") %
+ self.deck.undoName())
+ self.dialog.actionUndo.setEnabled(True)
+ else:
+ self.dialog.actionUndo.setEnabled(False)
+ if self.deck.redoAvailable():
+ self.dialog.actionRedo.setText(_("Redo %s") %
+ self.deck.redoName())
+ self.dialog.actionRedo.setEnabled(True)
+ else:
+ self.dialog.actionRedo.setEnabled(False)
+
def filterTextChanged(self):
interval = 500
if self.filterTimer:
@@ -359,6 +363,7 @@ class EditDeck(QMainWindow):
self.model.tag = self.currentTag
self.model.showMatching()
self.updateFilterLabel()
+ self.onEvent()
self.filterTimer = None
if self.model.cards:
self.dialog.cardInfoGroup.show()
@@ -369,6 +374,17 @@ class EditDeck(QMainWindow):
else:
self.dialog.cardInfoGroup.hide()
self.dialog.fieldsArea.hide()
+ self.focusCurrentCard()
+
+ def focusCurrentCard(self):
+ if self.parent.currentCard:
+ currentCardIndex = self.findCardInDeckModel(
+ self.model, self.parent.currentCard)
+ if currentCardIndex >= 0:
+ self.dialog.tableView.selectRow(currentCardIndex)
+ self.dialog.tableView.scrollTo(
+ self.model.index(currentCardIndex,0),
+ self.dialog.tableView.PositionAtTop)
def setupHeaders(self):
if not sys.platform.startswith("win32"):
@@ -385,6 +401,8 @@ class EditDeck(QMainWindow):
self.connect(self.dialog.actionAddCards, SIGNAL("triggered()"), self.addCards)
self.connect(self.dialog.actionResetProgress, SIGNAL("triggered()"), self.resetProgress)
self.connect(self.dialog.actionSelectFacts, SIGNAL("triggered()"), self.selectFacts)
+ self.connect(self.dialog.actionUndo, SIGNAL("triggered()"), self.onUndo)
+ self.connect(self.dialog.actionRedo, SIGNAL("triggered()"), self.onRedo)
self.parent.runHook('editor.setupMenus', self)
def onClose(self):
@@ -422,6 +440,7 @@ class EditDeck(QMainWindow):
self.factValid = True
self.editor.onFactValid = self.onFactValid
self.editor.onFactInvalid = self.onFactInvalid
+ self.editor.onChange = self.onEvent
self.connect(self.dialog.tableView.selectionModel(),
SIGNAL("currentRowChanged(QModelIndex, QModelIndex)"),
self.rowChanged)
@@ -453,6 +472,7 @@ class EditDeck(QMainWindow):
fact = self.currentCard.fact
self.editor.setFact(fact, True)
self.showCardInfo(self.currentCard)
+ self.onEvent()
def setupCardInfo(self):
self.currentCard = None
@@ -501,16 +521,27 @@ where id in (%s)""" % ",".join([
def addTags(self):
tags = ui.utils.getOnlyText(_("Enter tag(s) to add:"), self)
- if tags: self.deck.addTags(self.selectedFacts(), tags)
+ if tags:
+ n = _("Add Tags")
+ self.deck.setUndoStart(n)
+ self.deck.addTags(self.selectedFacts(), tags)
+ self.deck.setUndoEnd(n)
self.updateAfterCardChange()
def deleteTags(self):
tags = ui.utils.getOnlyText(_("Enter tag(s) to delete:"), self)
- if tags: self.deck.deleteTags(self.selectedFacts(), tags)
+ if tags:
+ n = _("Delete Tags")
+ self.deck.setUndoStart(n)
+ self.deck.deleteTags(self.selectedFacts(), tags)
+ self.deck.setUndoEnd(n)
self.updateAfterCardChange()
def resetProgress(self):
+ n = _("Reset Progress")
+ self.deck.setUndoStart(n)
self.deck.resetCards(self.selectedCards())
+ self.deck.setUndoEnd(n)
self.updateAfterCardChange(reset=True)
def addCards(self):
@@ -522,10 +553,13 @@ where id in (%s)""" % ",".join([
d = AddCardChooser(self, cms)
if not d.exec_():
return
+ n = _("Add Cards")
+ self.deck.setUndoStart(n)
for id in sf:
self.deck.addCards(self.deck.s.query(Fact).get(id),
d.selectedCms)
self.deck.flushMod()
+ self.deck.setUndoEnd(n)
self.updateSearch()
def selectFacts(self):
@@ -536,6 +570,17 @@ where id in (%s)""" % ",".join([
sm.select(self.model.index(i, 0),
QItemSelectionModel.Select | QItemSelectionModel.Rows)
+ # Undo/Redo
+ ######################################################################
+
+ def onUndo(self):
+ self.deck.undo()
+ self.updateSearch()
+
+ def onRedo(self):
+ self.deck.redo()
+ self.updateSearch()
+
class AddCardChooser(QDialog):
def __init__(self, parent, cms):
diff --git a/ankiqt/ui/facteditor.py b/ankiqt/ui/facteditor.py
index 710c93b2c..11f78c59b 100644
--- a/ankiqt/ui/facteditor.py
+++ b/ankiqt/ui/facteditor.py
@@ -47,6 +47,7 @@ class FactEditor(object):
# update focus to first field
self.fields[self.fact.fields[0].name][1].setFocus()
self.fontChanged = False
+ self.deck.setUndoBarrier()
def initMedia(self):
os.chdir(self.deck.mediaDir(create=True))
@@ -297,6 +298,8 @@ class FactEditor(object):
def saveFields(self):
"Save field text into fact."
modified = False
+ n = _("Edit")
+ self.deck.setUndoStart(n, merge=True)
for (w, f) in self.widgets.items():
v = tidyHTML(unicode(w.toHtml())).strip()
if self.fact[f.name] != v:
@@ -305,6 +308,7 @@ class FactEditor(object):
if modified:
self.fact.setModified(textChanged=True)
self.deck.setModified()
+ self.deck.setUndoEnd(n)
def onFocusLost(self, widget):
self.saveFields()
diff --git a/ankiqt/ui/main.py b/ankiqt/ui/main.py
index f1d8a8b63..bf9fac033 100644
--- a/ankiqt/ui/main.py
+++ b/ankiqt/ui/main.py
@@ -230,6 +230,7 @@ An error occurred. Please copy the following message into a bug report.\n\n""" +
elif state == "editCurrentFact":
if self.lastState == "editCurrentFact":
return self.moveToState("saveEdit")
+ self.deck.s.flush()
self.showEditor()
elif state == "saveEdit":
self.editor.saveFieldsNow()
@@ -1382,15 +1383,15 @@ To upgrade an old deck, download Anki 0.9.8.7."""))
self.mainWin.actionEditCurrent.setEnabled(True)
def maybeEnableUndo(self):
- if self.deck and self.deck.undoStack:
+ if self.deck and self.deck.undoAvailable():
self.mainWin.actionUndo.setText(_("Undo %s") %
- self.deck.undoStack[-1][0])
+ self.deck.undoName())
self.mainWin.actionUndo.setEnabled(True)
else:
self.mainWin.actionUndo.setEnabled(False)
- if self.deck and self.deck.redoStack:
+ if self.deck and self.deck.redoAvailable():
self.mainWin.actionRedo.setText(_("Redo %s") %
- self.deck.redoStack[-1][0])
+ self.deck.redoName())
self.mainWin.actionRedo.setEnabled(True)
else:
self.mainWin.actionRedo.setEnabled(False)
diff --git a/designer/cardlist.ui b/designer/cardlist.ui
index 612f8d3f8..74de66a4b 100644
--- a/designer/cardlist.ui
+++ b/designer/cardlist.ui
@@ -187,6 +187,9 @@
&Edit
+
+
+
@@ -214,7 +217,7 @@
Delete
- Ctrl+Del
+ Del
@@ -266,6 +269,24 @@
Select &Facts
+
+
+
+ :/icons/edit-undo.png:/icons/edit-undo.png
+
+
+ &Undo
+
+
+
+
+
+ :/icons/edit-redo.png:/icons/edit-redo.png
+
+
+ &Redo
+
+