From 8259347f34d25072e9b808cf159a41533297e3d4 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 16 Apr 2009 17:17:16 +0900 Subject: [PATCH 01/14] move errorOccurred up the top --- ankiqt/ui/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ankiqt/ui/main.py b/ankiqt/ui/main.py index 30b427a39..b3db0948b 100644 --- a/ankiqt/ui/main.py +++ b/ankiqt/ui/main.py @@ -31,6 +31,7 @@ config = ankiqt.config class AnkiQt(QMainWindow): def __init__(self, app, config, args): QMainWindow.__init__(self) + self.errorOccurred = False if sys.platform.startswith("darwin"): qt_mac_set_menubar_icons(False) ankiqt.mw = self @@ -69,7 +70,6 @@ class AnkiQt(QMainWindow): self.moveToState("auto") # check for updates ui.splash.update() - self.errorOccurred = False self.setupErrorHandler() self.setupMisc() self.loadPlugins() From f45fccb93f13b3f6d103b201a18b6e409961acd1 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 16 Apr 2009 17:43:54 +0900 Subject: [PATCH 02/14] fix concurrent mod error when deleting card while edit current open --- ankiqt/ui/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ankiqt/ui/main.py b/ankiqt/ui/main.py index b3db0948b..816f3491d 100644 --- a/ankiqt/ui/main.py +++ b/ankiqt/ui/main.py @@ -1336,6 +1336,8 @@ day = :d""", d=yesterday) def onDelete(self): undo = _("Delete") + if self.state == "editCurrent": + self.moveToState("saveEdit") self.deck.setUndoStart(undo) self.deck.deleteCard(self.currentCard.id) self.reset() From ba9279c1269e13d1d34b848e8cb1e3c24fd86104 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 17 Apr 2009 21:59:57 +0900 Subject: [PATCH 03/14] suppress timers in db progress handler, disable UI during progress --- ankiqt/ui/main.py | 7 +++++++ ankiqt/ui/status.py | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/ankiqt/ui/main.py b/ankiqt/ui/main.py index 816f3491d..8253502a2 100644 --- a/ankiqt/ui/main.py +++ b/ankiqt/ui/main.py @@ -32,6 +32,7 @@ class AnkiQt(QMainWindow): def __init__(self, app, config, args): QMainWindow.__init__(self) self.errorOccurred = False + self.inDbHandler = False if sys.platform.startswith("darwin"): qt_mac_set_menubar_icons(False) ankiqt.mw = self @@ -429,6 +430,8 @@ new: def refreshStatus(self): "If triggered when the deck is finished, reset state." + if self.inDbHandler: + return if self.state == "deckFinished": # don't try refresh if the deck is closed during a sync if self.deck: @@ -2154,7 +2157,9 @@ it to your friends. if self.mainThread != QThread.currentThread(): return self.setBusy() + self.inDbHandler = True self.app.processEvents() + self.inDbHandler = False def onDbFinished(self): if self.mainThread != QThread.currentThread(): @@ -2164,11 +2169,13 @@ it to your friends. def setBusy(self): if not self.busyCursor: + self.setEnabled(False) self.app.setOverrideCursor(QCursor(Qt.WaitCursor)) self.busyCursor = True def unsetBusy(self): if self.busyCursor: + self.setEnabled(True) self.app.restoreOverrideCursor() self.busyCursor = None diff --git a/ankiqt/ui/status.py b/ankiqt/ui/status.py index 044359029..d57e928d7 100644 --- a/ankiqt/ui/status.py +++ b/ankiqt/ui/status.py @@ -252,6 +252,8 @@ You should aim to answer each question within
palette.setColor(QPalette.Highlight, QColor("#00ee00")) def drawTimer(self): + if self.main.inDbHandler: + return if not self.main.config['showTimer']: return if not self.timer: @@ -280,6 +282,8 @@ You should aim to answer each question within
self.timerFlashStart = time.time() def updateCount(self): + if self.main.inDbHandler: + return if not self.main.deck: return if self.state in ("showQuestion", "showAnswer", "studyScreen"): From b15bc9ef61a4d55f46d177f6b72f6305341349ed Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 17 Apr 2009 23:19:05 +0900 Subject: [PATCH 04/14] delay update of scroll widget, if change timer fires while deleting, delay --- ankiqt/ui/facteditor.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ankiqt/ui/facteditor.py b/ankiqt/ui/facteditor.py index 5fb1cbee0..056e17bf4 100644 --- a/ankiqt/ui/facteditor.py +++ b/ankiqt/ui/facteditor.py @@ -396,6 +396,14 @@ class FactEditor(object): # update fields self.loadFields(check) self.parent.setUpdatesEnabled(True) + # update with timer so we don't delete old one in event handler + self.scrollUpdateTimer = QTimer(self.parent) + self.scrollUpdateTimer.setSingleShot(True) + self.parent.connect(self.scrollUpdateTimer, + SIGNAL("timeout()"), self.onScrollUpdate) + self.scrollUpdateTimer.start(0) + + def onScrollUpdate(self): self.fieldsScroll.setWidget(self.fieldsFrame) def needToRedraw(self): @@ -481,8 +489,13 @@ class FactEditor(object): self.onChangeTimer) def onChangeTimer(self): + from ankiqt import mw + interval = 250 if not self.fact: return + if mw.inDbHandler: + self.changeTimer.start(interval) + return self.saveFields() self.checkValid() if self.onChange: From 87a86cbdde0ffde55e17d1a2deb179a96ebe36b8 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 18 Apr 2009 00:42:55 +0900 Subject: [PATCH 05/14] update contributors --- ankiqt/ui/about.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ankiqt/ui/about.py b/ankiqt/ui/about.py index 6cb4d4b6c..124b7a273 100644 --- a/ankiqt/ui/about.py +++ b/ankiqt/ui/about.py @@ -26,13 +26,13 @@ A big thanks to all the people who have provided suggestions, bug reports and donations.""") % { 'cont': u""" -Alex Fraser, Andreas Klauer, Bananeweizen, Bernhard Ibertsberger, Christian -Rusche, David Smith, Dave Druelinger, Emmanuel Jarri, Frank Harper, Ian Lewis, -Iroiro, Jin Eun-Deok, Jo Nakashima, Krause Chr, LaC, Laurent Steffan, Marco -Giancotti, Mark Wilbur, Meelis Vasser, Michael Penkov, Michal Čadil, Nathanael -Law, Nick Cook, Niklas Laxström, Pcsl88, Piotr Kubowicz, Richard Colley, -Samson Melamed, Susanna Björverud, Timm Preetz, Timo Paulssen, Victor Suba, -and Xtru. +Alex Fraser, Andreas Klauer, Andrew Wright, Bananeweizen, Bernhard +Ibertsberger, Christian Rusche, David Smith, Dave Druelinger, Emmanuel Jarri, +Frank Harper, H. Mijail, Ian Lewis, Iroiro, Jin Eun-Deok, Jo Nakashima, Krause +Chr, LaC, Laurent Steffan, Marco Giancotti, Mark Wilbur, Meelis Vasser, +Michael Penkov, Michal Čadil, Nathanael Law, Nick Cook, Niklas Laxström, +Pcsl88, Piotr Kubowicz, Richard Colley, Samson Melamed, Susanna Björverud, +Timm Preetz, Timo Paulssen, Victor Suba, and Xtru. """, 'ver': appVersion}) From 513a23c251611ddf1b08e980839070f2c433fd05 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 18 Apr 2009 00:51:29 +0900 Subject: [PATCH 06/14] don't mark deck changed in editor on open --- ankiqt/ui/cardlist.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ankiqt/ui/cardlist.py b/ankiqt/ui/cardlist.py index 5368a8545..88af8cb33 100644 --- a/ankiqt/ui/cardlist.py +++ b/ankiqt/ui/cardlist.py @@ -402,7 +402,8 @@ class EditDeck(QMainWindow): self.sortKey = ("field", self.sortFields[idx-9]) self.rebuildSortIndex(self.sortKey) self.sortIndex = idx - self.deck.setVar('sortIndex', idx) + if self.deck.getInt('sortIndex') != idx: + self.deck.setVar('sortIndex', idx) self.model.sortKey = self.sortKey self.model.updateHeader() if refresh: From e1b7da08e5f22b7d54b58ee1e803eb09c421cf15 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 18 Apr 2009 00:59:01 +0900 Subject: [PATCH 07/14] show study screen regardless of deck due or not, tweak 'initial' --- ankiqt/ui/main.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/ankiqt/ui/main.py b/ankiqt/ui/main.py index 8253502a2..615029248 100644 --- a/ankiqt/ui/main.py +++ b/ankiqt/ui/main.py @@ -249,6 +249,12 @@ Please do not file a bug report with Anki.

""") if self.deck.isEmpty(): return self.moveToState("deckEmpty") else: + if not self.deck.reviewEarly: + if (self.config['showStudyScreen'] and + not self.deck.sessionStartTime): + return self.moveToState("studyScreen") + if self.deck.sessionLimitReached(): + return self.moveToState("studyScreen") if not self.currentCard: self.currentCard = self.deck.getCard() if self.currentCard: @@ -258,12 +264,6 @@ Please do not file a bug report with Anki.

""") # if the same card is being shown and it's not # due yet, give up return self.moveToState("deckFinished") - if not self.deck.reviewEarly: - if (self.config['showStudyScreen'] and - not self.deck.sessionStartTime): - return self.moveToState("studyScreen") - if self.deck.sessionLimitReached(): - return self.moveToState("studyScreen") self.enableCardMenuItems() return self.moveToState("showQuestion") else: @@ -283,6 +283,7 @@ Please do not file a bug report with Anki.

""") # make sure the buttons aren't focused self.mainWin.congratsLabel.setFocus() elif state == "showQuestion": + self.reviewingStarted = True if self.deck.mediaDir(): os.chdir(self.deck.mediaDir()) self.showAnswerButton() @@ -556,6 +557,7 @@ new: def loadDeck(self, deckPath, sync=True, interactive=True, uprecent=True): "Load a deck and update the user interface. Maybe sync." + self.reviewingStarted = False # return True on success try: self.pauseViews() @@ -1102,17 +1104,16 @@ day = :d""", d=yesterday) %s""" % (stats1, stats2)) def showStudyScreen(self): - initial = self.deck.sessionStartTime == 0 self.mainWin.optionsButton.setChecked(self.config['showStudyOptions']) self.mainWin.optionsBox.setShown(self.config['showStudyOptions']) self.switchToStudyScreen() self.updateStudyStats() # start reviewing button self.mainWin.buttonStack.hide() - if initial: - self.mainWin.startReviewingButton.setText(_("Start &Reviewing")) - else: + if self.reviewingStarted: self.mainWin.startReviewingButton.setText(_("Continue &Reviewing")) + else: + self.mainWin.startReviewingButton.setText(_("Start &Reviewing")) self.mainWin.startReviewingButton.setFocus() self.connect(self.mainWin.startReviewingButton, SIGNAL("clicked()"), From 4d95b3487daaa3daba04fad89e4f3af52bb896d1 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 18 Apr 2009 02:41:16 +0900 Subject: [PATCH 08/14] scroll to top when adding, keep tags always shown, not tag up on field edit --- ankiqt/ui/addcards.py | 2 +- ankiqt/ui/facteditor.py | 35 +++++++++++++++++++---------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/ankiqt/ui/addcards.py b/ankiqt/ui/addcards.py index 1e43e41cd..31f98e13c 100644 --- a/ankiqt/ui/addcards.py +++ b/ankiqt/ui/addcards.py @@ -135,7 +135,7 @@ question or answer on all cards."""), parent=self) # start a new fact f = self.parent.deck.newFact() f.tags = self.parent.deck.lastTags - self.editor.setFact(f, check=True) + self.editor.setFact(f, check=True, scroll=True) # let completer know our extra tags self.editor.tags.addTags(parseTags(self.parent.deck.lastTags)) self.maybeSave() diff --git a/ankiqt/ui/facteditor.py b/ankiqt/ui/facteditor.py index 056e17bf4..450e95d85 100644 --- a/ankiqt/ui/facteditor.py +++ b/ankiqt/ui/facteditor.py @@ -47,7 +47,7 @@ class FactEditor(object): addHook("colourChanged", self.colourChanged) removeHook("colourChanged", self.colourChanged) - def setFact(self, fact, noFocus=False, check=False): + def setFact(self, fact, noFocus=False, check=False, scroll=False): "Make FACT the current fact." self.fact = fact self.factState = None @@ -63,6 +63,8 @@ class FactEditor(object): else: self.loadFields(check) self.widget.show() + if scroll: + self.fieldsScroll.ensureVisible(0, 0) if not noFocus: # update focus to first field self.fields[self.fact.fields[0].name][1].setFocus() @@ -109,6 +111,16 @@ class FactEditor(object): self.fieldsScroll.setFrameStyle(0) self.fieldsScroll.setFocusPolicy(Qt.NoFocus) self.fieldsBox.addWidget(self.fieldsScroll) + # tags + self.tagsBox = QHBoxLayout() + self.tagsLabel = QLabel(_("Tags")) + self.tagsBox.addWidget(self.tagsLabel) + self.tags = ui.tagedit.TagEdit(self.parent) + self.tags.connect(self.tags, SIGNAL("lostFocus"), + self.onTagChange) + self.tagsBox.addWidget(self.tags) + self.fieldsBox.addLayout(self.tagsBox) + # icons self.iconsBox.setMargin(0) self.iconsBox.addItem(QSpacerItem(20,1, QSizePolicy.Expanding)) self.iconsBox2.setMargin(0) @@ -357,14 +369,18 @@ class FactEditor(object): fields = self.fact.fields self.fields = {} self.widgets = {} + self.labels = [] n = 0 first = True + last = None for field in fields: # label l = QLabel(field.name) + self.labels.append(l) self.fieldsGrid.addWidget(l, n, 0) # edit widget w = FactEdit(self) + last = w w.setTabChangesFocus(True) w.setAcceptRichText(True) w.setMinimumSize(20, 60) @@ -385,26 +401,14 @@ class FactEditor(object): self.focusTarget = w first = False n += 1 - # tags - self.fieldsGrid.addWidget(QLabel(_("Tags")), n, 0) - self.tags = ui.tagedit.TagEdit(self.parent) - self.tags.connect(self.tags, SIGNAL("lostFocus"), - self.onTagChange) # update available tags self.tags.setDeck(self.deck) - self.fieldsGrid.addWidget(self.tags, n, 1) # update fields self.loadFields(check) self.parent.setUpdatesEnabled(True) - # update with timer so we don't delete old one in event handler - self.scrollUpdateTimer = QTimer(self.parent) - self.scrollUpdateTimer.setSingleShot(True) - self.parent.connect(self.scrollUpdateTimer, - SIGNAL("timeout()"), self.onScrollUpdate) - self.scrollUpdateTimer.start(0) - - def onScrollUpdate(self): self.fieldsScroll.setWidget(self.fieldsFrame) + self.tagsLabel.setFixedWidth(max(*[l.width() for l in self.labels])) + self.parent.setTabOrder(last, self.tags) def needToRedraw(self): if self.fact is None: @@ -462,7 +466,6 @@ class FactEditor(object): modified = True if modified: self.fact.setModified(textChanged=True) - self.deck.updateFactTags([self.fact.id]) self.deck.setModified() self.deck.setUndoEnd(n) From ef17e3b4c65ee61202281153d76e2632c3fae642 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 18 Apr 2009 03:20:54 +0900 Subject: [PATCH 09/14] call a hook after creating a field --- ankiqt/ui/facteditor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ankiqt/ui/facteditor.py b/ankiqt/ui/facteditor.py index 450e95d85..7084e4ae2 100644 --- a/ankiqt/ui/facteditor.py +++ b/ankiqt/ui/facteditor.py @@ -387,6 +387,7 @@ class FactEditor(object): w.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) w.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) w.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + runHook("makeField", w, field) self.fieldsGrid.addWidget(w, n, 1) self.fields[field.name] = (field, w) self.widgets[w] = field From a962a9fb51e69f675fef9066d3f10949b7ffd222 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 18 Apr 2009 03:27:51 +0900 Subject: [PATCH 10/14] document html editor shortcut --- ankiqt/ui/facteditor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ankiqt/ui/facteditor.py b/ankiqt/ui/facteditor.py index 7084e4ae2..897d336e2 100644 --- a/ankiqt/ui/facteditor.py +++ b/ankiqt/ui/facteditor.py @@ -335,7 +335,7 @@ class FactEditor(object): self.latexMathEnv.setStyle(self.plastiqueStyle) # html self.htmlEdit = QPushButton(self.widget) - self.htmlEdit.setToolTip(_("HTML Editor")) + self.htmlEdit.setToolTip(_("HTML Editor (Ctrl+F9)")) self.htmlEditSC = QShortcut(QKeySequence(_("Ctrl+F9")), self.widget) self.htmlEdit.connect(self.htmlEdit, SIGNAL("clicked()"), self.onHtmlEdit) From bb876ce3ed51b3c4c0492cfe51a44de73c583634 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 18 Apr 2009 03:44:05 +0900 Subject: [PATCH 11/14] ignore enter in deck properties --- ankiqt/ui/deckproperties.py | 2 ++ designer/deckproperties.ui | 33 +++++++++------------------------ 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/ankiqt/ui/deckproperties.py b/ankiqt/ui/deckproperties.py index 53d49b2b9..d5cd6ae88 100644 --- a/ankiqt/ui/deckproperties.py +++ b/ankiqt/ui/deckproperties.py @@ -28,6 +28,8 @@ class DeckProperties(QDialog): self.origMod = self.d.modified self.dialog = ankiqt.forms.deckproperties.Ui_DeckProperties() self.dialog.setupUi(self) + self.dialog.buttonBox.button(QDialogButtonBox.Help).setAutoDefault(False) + self.dialog.buttonBox.button(QDialogButtonBox.Close).setAutoDefault(False) self.readData() self.connect(self.dialog.modelsAdd, SIGNAL("clicked()"), self.onAdd) self.connect(self.dialog.modelsEdit, SIGNAL("clicked()"), self.onEdit) diff --git a/designer/deckproperties.ui b/designer/deckproperties.ui index c27cbd9d4..b54b2a947 100644 --- a/designer/deckproperties.ui +++ b/designer/deckproperties.ui @@ -25,14 +25,6 @@ 0 - - - 0 - 0 - 410 - 334 - - Models && Priorities @@ -139,6 +131,9 @@ &Add + + false + @@ -146,6 +141,9 @@ &Edit + + false + @@ -153,6 +151,9 @@ &Delete + + false + @@ -160,14 +161,6 @@ - - - 0 - 0 - 375 - 334 - - Synchronisation @@ -300,14 +293,6 @@ p, li { white-space: pre-wrap; } - - - 0 - 0 - 346 - 356 - - Advanced From 39dbbe4489e6a5b77bc06dbbbf022e3f84f28c1f Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 18 Apr 2009 04:46:22 +0900 Subject: [PATCH 12/14] add select all/none/invert buttons to active tags dialog --- ankiqt/ui/activetags.py | 24 ++++++++++++++++++++++++ designer/activetags.ui | 40 ++++++++++++++++++++++------------------ 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/ankiqt/ui/activetags.py b/ankiqt/ui/activetags.py index a2ec6854b..ca2588dd8 100644 --- a/ankiqt/ui/activetags.py +++ b/ankiqt/ui/activetags.py @@ -14,11 +14,35 @@ class ActiveTagsChooser(QDialog): self.parent = parent self.dialog = ankiqt.forms.activetags.Ui_Dialog() self.dialog.setupUi(self) + self.selectAll = QPushButton(_("Select All")) + self.connect(self.selectAll, SIGNAL("clicked()"), self.onSelectAll) + self.dialog.buttonBox.addButton(self.selectAll, + QDialogButtonBox.ActionRole) + self.selectNone = QPushButton(_("Select None")) + self.connect(self.selectNone, SIGNAL("clicked()"), self.onSelectNone) + self.dialog.buttonBox.addButton(self.selectNone, + QDialogButtonBox.ActionRole) + self.invert = QPushButton(_("Invert")) + self.connect(self.invert, SIGNAL("clicked()"), self.onInvert) + self.dialog.buttonBox.addButton(self.invert, + QDialogButtonBox.ActionRole) self.connect(self.dialog.buttonBox, SIGNAL("helpRequested()"), self.onHelp) self.rebuildTagList() restoreGeom(self, "activeTags") + def onSelectAll(self): + self.dialog.list.selectAll() + + def onSelectNone(self): + self.dialog.list.clearSelection() + + def onInvert(self): + sm = self.dialog.list.selectionModel() + sel = sm.selection() + self.dialog.list.selectAll() + sm.select(sel, QItemSelectionModel.Deselect) + def rebuildTagList(self): self.tags = self.parent.deck.allTags() self.items = [] diff --git a/designer/activetags.ui b/designer/activetags.ui index 6915ec8d1..a9501a348 100644 --- a/designer/activetags.ui +++ b/designer/activetags.ui @@ -5,8 +5,8 @@ 0 0 - 248 - 268 + 369 + 393 @@ -16,26 +16,30 @@ - <h1>Select tags to suspend</h1> + Select tags to suspend. Deselect to unsuspend. - - - QAbstractItemView::MultiSelection - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok - - + + + + + QAbstractItemView::MultiSelection + + + + + + + Qt::Vertical + + + QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok + + + + From c19c45ef4ae85c503a9d68e9b11e70cdd5db3e9c Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 18 Apr 2009 04:56:14 +0900 Subject: [PATCH 13/14] fix inMainWindow() --- ankiqt/ui/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ankiqt/ui/main.py b/ankiqt/ui/main.py index 615029248..4c33536d8 100644 --- a/ankiqt/ui/main.py +++ b/ankiqt/ui/main.py @@ -734,7 +734,6 @@ To upgrade an old deck, download Anki 0.9.8.7.""")) return True def inMainWindow(self): - return True return self.app.activeWindow() == self def onNew(self, initial=False, path=None): From fcba72e40ddb3a49d87a09c53e07fc3b929f9e8b Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 18 Apr 2009 05:01:57 +0900 Subject: [PATCH 14/14] add shortcut key to close window on osx --- ankiqt/ui/cardlist.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ankiqt/ui/cardlist.py b/ankiqt/ui/cardlist.py index 88af8cb33..6d3d74cce 100644 --- a/ankiqt/ui/cardlist.py +++ b/ankiqt/ui/cardlist.py @@ -320,6 +320,10 @@ class EditDeck(QMainWindow): if self.parent.currentCard: self.currentCard = self.parent.currentCard self.focusCurrentCard() + if sys.platform.startswith("darwin"): + self.macCloseShortcut = QShortcut(QKeySequence("Ctrl+w"), self) + self.connect(self.macCloseShortcut, SIGNAL("activated()"), + self.close) def findCardInDeckModel(self, model, card): for i, thisCard in enumerate(model.cards):