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}) 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/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/cardlist.py b/ankiqt/ui/cardlist.py index 5368a8545..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): @@ -402,7 +406,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: 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/ankiqt/ui/facteditor.py b/ankiqt/ui/facteditor.py index 5fb1cbee0..897d336e2 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) @@ -323,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) @@ -357,20 +369,25 @@ 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) 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 @@ -385,18 +402,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) 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: @@ -454,7 +467,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) @@ -481,8 +493,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: diff --git a/ankiqt/ui/main.py b/ankiqt/ui/main.py index 30b427a39..4c33536d8 100644 --- a/ankiqt/ui/main.py +++ b/ankiqt/ui/main.py @@ -31,6 +31,8 @@ config = ankiqt.config 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 @@ -69,7 +71,6 @@ class AnkiQt(QMainWindow): self.moveToState("auto") # check for updates ui.splash.update() - self.errorOccurred = False self.setupErrorHandler() self.setupMisc() self.loadPlugins() @@ -248,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: @@ -257,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: @@ -282,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() @@ -429,6 +431,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: @@ -553,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() @@ -729,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): @@ -1099,17 +1103,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()"), @@ -1336,6 +1339,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() @@ -2152,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(): @@ -2162,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"): 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 + + + + 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