From 830c3aed101c205343dac8febd281e5f6dd1a84b Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 01:10:27 +0900 Subject: [PATCH 01/18] import importing on startup --- ankiqt/ui/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ankiqt/ui/__init__.py b/ankiqt/ui/__init__.py index 61c0cc82d..0c74141a9 100644 --- a/ankiqt/ui/__init__.py +++ b/ankiqt/ui/__init__.py @@ -9,6 +9,7 @@ def importAll(): import addcards import cardlist import deckproperties + import importing import displayproperties import exporting import facteditor From 0534ce5d40dcd7790a8f49978e7f9b83d0c0e61a Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 01:16:06 +0900 Subject: [PATCH 02/18] don't convert \n to
and vice versa in card templates --- ankiqt/ui/modelproperties.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ankiqt/ui/modelproperties.py b/ankiqt/ui/modelproperties.py index 4f37353a2..b1043bb10 100644 --- a/ankiqt/ui/modelproperties.py +++ b/ankiqt/ui/modelproperties.py @@ -289,8 +289,8 @@ class ModelProperties(QDialog): self.currentCard = self.m.cardModels[self.dialog.cardList.currentRow()] card = self.currentCard self.dialog.cardName.setText(card.name) - self.dialog.cardQuestion.setPlainText(card.qformat.replace("
", "\n")) - self.dialog.cardAnswer.setPlainText(card.aformat.replace("
", "\n")) + self.dialog.cardQuestion.setPlainText(card.qformat.replace("
", "
\n")) + self.dialog.cardAnswer.setPlainText(card.aformat.replace("
", "
\n")) self.dialog.questionInAnswer.setChecked(card.questionInAnswer) self.dialog.allowEmptyAnswer.setChecked(card.allowEmptyAnswer) self.dialog.typeAnswer.clear() @@ -335,10 +335,10 @@ order by n""", id=card.id) newname = _("Card %d") % (self.m.cardModels.index(card) + 1) self.updateField(card, 'name', newname) s = unicode(self.dialog.cardQuestion.toPlainText()) - s = s.replace("\n", "
") + s = s.replace("
\n", "
") changed = self.updateField(card, 'qformat', s) s = unicode(self.dialog.cardAnswer.toPlainText()) - s = s.replace("\n", "
") + s = s.replace("
\n", "
") changed2 = self.updateField(card, 'aformat', s) changed = changed or changed2 self.updateField(card, 'questionInAnswer', self.dialog.questionInAnswer.isChecked()) From 612eafc64a85b55cf870340db1a4c6aaba6de251 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 01:18:44 +0900 Subject: [PATCH 03/18] prevent double click except in chinese/japanese models --- ankiqt/ui/facteditor.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ankiqt/ui/facteditor.py b/ankiqt/ui/facteditor.py index 32fef4bb4..223b97bfe 100644 --- a/ankiqt/ui/facteditor.py +++ b/ankiqt/ui/facteditor.py @@ -995,6 +995,11 @@ class FactEdit(QTextEdit): # this shouldn't be necessary if/when we move away from kakasi def mouseDoubleClickEvent(self, evt): + t = self.parent.fact.model.tags.lower() + if (not "japanese" in t and + not "mandarin" in t and + not "cantonese" in t): + return r = QRegExp("\\{(.*[|,].*)\\}") r.setMinimal(True) From 840c3549b44d37c63627a1375324f7d049062698 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 01:29:07 +0900 Subject: [PATCH 04/18] call sys.exit() after exit from main loop so audio thread dies --- ankiqt/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ankiqt/__init__.py b/ankiqt/__init__.py index 5b08d732a..75b34fa89 100644 --- a/ankiqt/__init__.py +++ b/ankiqt/__init__.py @@ -175,5 +175,8 @@ def run(): app.exec_() + # ensure we kill any other threads + sys.exit(0) + if __name__ == "__main__": run() From 29bbbe0416926ea224323c22ee654e639d1e219e Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 02:17:00 +0900 Subject: [PATCH 05/18] use instead of munging image urls --- ankiqt/ui/utils.py | 16 ---------------- ankiqt/ui/view.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/ankiqt/ui/utils.py b/ankiqt/ui/utils.py index dd258fa6b..91e80837f 100644 --- a/ankiqt/ui/utils.py +++ b/ankiqt/ui/utils.py @@ -185,24 +185,8 @@ def restoreHeader(widget, key): widget.restoreState(ankiqt.mw.config[key]) def mungeQA(deck, txt): - def quote(match): - match = unicode(match.group(1)) - if match.lower().startswith("http"): - src = match - else: - if sys.platform.startswith("win32"): - prefix = u"file:///" - else: - prefix = u"file://" - src = prefix + unicode( - urllib.quote(os.path.join(deck.mediaDir( - create=True), match).encode("utf-8")), "utf-8") - return src - def quoteImg(match): - return 'img src="%s"' % quote(match) txt = renderLatex(deck, txt) txt = stripSounds(txt) - txt = re.sub('img src="(.*?)"', quoteImg, txt) return txt class ProgressWin(object): diff --git a/ankiqt/ui/view.py b/ankiqt/ui/view.py index 497e102d4..ae58ebf53 100644 --- a/ankiqt/ui/view.py +++ b/ankiqt/ui/view.py @@ -106,6 +106,19 @@ class View(object): self.buffer = self.addStyles() + self.buffer # hook for user css runHook("preFlushHook") + if self.main.deck.mediaDir(): + if sys.platform.startswith("win32"): + prefix = u"file:///" + else: + prefix = u"file://" + base = prefix + unicode( + urllib.quote(self.main.deck.mediaDir().encode("utf-8")), + "utf-8") + base = '' % base + else: + base = "" + self.buffer = '''%s%s''' % ( + base, self.buffer) #print self.buffer.encode("utf-8") self.body.setHtml(self.buffer) From 4fd65c37c5c019ca1995143e9ef15e5225cd4cac Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 02:38:16 +0900 Subject: [PATCH 06/18] refactor error handler to handle error messages in other threads, mention mplayer --- ankiqt/ui/main.py | 66 ++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/ankiqt/ui/main.py b/ankiqt/ui/main.py index d58ad0f0b..f011c63cc 100644 --- a/ankiqt/ui/main.py +++ b/ankiqt/ui/main.py @@ -126,29 +126,42 @@ class AnkiQt(QMainWindow): self.parent = parent self.timer = None self.pool = "" + self.poolUpdated = 0 def write(self, data): print data.encode("utf-8"), self.pool += data - self.updateTimer() + self.poolUpdated = time.time() - def updateTimer(self): - interval = 200 - if not self.timer: - self.timer = QTimer(self.parent) - self.timer.setSingleShot(True) - self.timer.start(interval) - self.parent.connect(self.timer, - SIGNAL("timeout()"), - self.onTimeout) - else: - self.timer.setInterval(interval) + def haveError(self): + if self.pool: + if (time.time() - self.poolUpdated) > 1: + return True - def onTimeout(self): - if "font_manager.py" in self.pool: - # hack for matplotlib errors on osx - self.pool = "" - stdText = _("""\ + def getError(self): + p = self.pool + self.pool = "" + return p + + self.errorPipe = ErrorPipe(self) + sys.stderr = self.errorPipe + self.errorTimer = QTimer(self) + self.errorTimer.start(1000) + self.connect(self.errorTimer, + SIGNAL("timeout()"), + self.onErrorTimer) + + def onErrorTimer(self): + if self.errorPipe.haveError(): + error = self.errorPipe.getError() + if "font_manager.py" in error: + # hack for matplotlib errors on osx + return + if "Audio player not found" in error: + ui.utils.showInfo( + _("Couldn't play sound. Please install mplayer.")) + return + stdText = _("""\ An error occurred. Please:

  1. Restart Anki. @@ -157,21 +170,16 @@ An error occurred. Please:

    If it does not fix the problem, please copy the following
    into a bug report:

    """) - pluginText = _("""\ + pluginText = _("""\ An error occurred in a plugin. Please contact the plugin author.
    Please do not file a bug report with Anki.

    """) - if "plugin" in self.pool: - txt = pluginText - else: - txt = stdText - if self.pool: - self.parent.errorOccurred = True - ui.utils.showText(txt + self.pool[0:10000].replace( + if "plugin" in error: + txt = pluginText + else: + txt = stdText + self.errorOccurred = True + ui.utils.showText(txt + error[0:10000].replace( "\n", "
    ")) - self.pool = "" - self.timer = None - pipe = ErrorPipe(self) - sys.stderr = pipe def closeAllDeckWindows(self): ui.dialogs.closeAll() From b1b6d322dff5e5fa56039361fb0f7401f2b6e722 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 02:45:11 +0900 Subject: [PATCH 07/18] fix startup when no deck available --- ankiqt/ui/view.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ankiqt/ui/view.py b/ankiqt/ui/view.py index ae58ebf53..b4836e395 100644 --- a/ankiqt/ui/view.py +++ b/ankiqt/ui/view.py @@ -106,7 +106,7 @@ class View(object): self.buffer = self.addStyles() + self.buffer # hook for user css runHook("preFlushHook") - if self.main.deck.mediaDir(): + if self.main.deck and self.main.deck.mediaDir(): if sys.platform.startswith("win32"): prefix = u"file:///" else: From c32a230766d2dea85f19488a8144be0d19a19917 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 03:04:06 +0900 Subject: [PATCH 08/18] don't lower tags, it causes problems for foreign characters --- ankiqt/ui/cardlist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ankiqt/ui/cardlist.py b/ankiqt/ui/cardlist.py index 48296956d..0a75224f1 100644 --- a/ankiqt/ui/cardlist.py +++ b/ankiqt/ui/cardlist.py @@ -453,7 +453,7 @@ class EditDeck(QMainWindow): elif idx == 1: self.dialog.filterEdit.setText("tag:none") else: - self.dialog.filterEdit.setText("tag:" + self.alltags[idx-2].lower()) + self.dialog.filterEdit.setText("tag:" + self.alltags[idx-2]) self.showFilterNow() self.dialog.tagList.setCurrentIndex(0) From 96cac67ea623b152a5d58c1c200ee579dd36291c Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 03:16:36 +0900 Subject: [PATCH 09/18] set focus on search after downloaded data --- ankiqt/ui/getshared.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ankiqt/ui/getshared.py b/ankiqt/ui/getshared.py index c6179b415..3b63620a9 100644 --- a/ankiqt/ui/getshared.py +++ b/ankiqt/ui/getshared.py @@ -63,6 +63,7 @@ class GetShared(QDialog): return self.parent.finishProgress() self.parent.setProgressParent(None) + self.form.search.setFocus() if err: showInfo(_("Unable to connect to server."), parent=self) self.close() From a41cfb88ec2c5e9e75322a4974100bf940870735 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 03:18:49 +0900 Subject: [PATCH 10/18] update bottom area of downloads when searching --- ankiqt/ui/getshared.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ankiqt/ui/getshared.py b/ankiqt/ui/getshared.py index 3b63620a9..1850790c0 100644 --- a/ankiqt/ui/getshared.py +++ b/ankiqt/ui/getshared.py @@ -109,6 +109,7 @@ class GetShared(QDialog): else: self.form.table.sortItems(1, Qt.DescendingOrder) self.form.table.selectRow(0) + self.onCellChanged(None, None, None, None) def onCellChanged(self, row, col, x, y): ci = self.form.table.currentItem() From 78f0e25c405f674d45cd5115087af795d4c1d6a7 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 03:23:42 +0900 Subject: [PATCH 11/18] increase default size of download box, increase lower area size --- designer/getshared.ui | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/designer/getshared.ui b/designer/getshared.ui index 15b21bb75..884084485 100644 --- a/designer/getshared.ui +++ b/designer/getshared.ui @@ -5,8 +5,8 @@ 0 0 - 517 - 411 + 715 + 598 @@ -29,8 +29,21 @@ Qt::Vertical - + + + + 0 + 1 + + + + + + 0 + 3 + + QFrame::StyledPanel @@ -61,9 +74,15 @@ + + + 0 + 0 + + - 430 + 500 16777215 From 0946a3e0c4bd66a8a377be440d4fc9bcadaad01b Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 03:28:35 +0900 Subject: [PATCH 12/18] bump version --- ankiqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ankiqt/__init__.py b/ankiqt/__init__.py index 75b34fa89..8c2f85898 100644 --- a/ankiqt/__init__.py +++ b/ankiqt/__init__.py @@ -6,7 +6,7 @@ from PyQt4.QtCore import * from PyQt4.QtGui import * appName="Anki" -appVersion="0.9.9.7.5" +appVersion="0.9.9.7.6" appWebsite="http://ichi2.net/anki/download/" appWiki="http://ichi2.net/anki/wiki/" appHelpSite="http://ichi2.net/anki/wiki/AnkiWiki" From 0b7c8bceccbed94991f8b9d2ee3c082da8c168e1 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 19:18:07 +0900 Subject: [PATCH 13/18] fix double-click to select --- ankiqt/ui/facteditor.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ankiqt/ui/facteditor.py b/ankiqt/ui/facteditor.py index 223b97bfe..b1dcc32a8 100644 --- a/ankiqt/ui/facteditor.py +++ b/ankiqt/ui/facteditor.py @@ -999,7 +999,7 @@ class FactEdit(QTextEdit): if (not "japanese" in t and not "mandarin" in t and not "cantonese" in t): - return + return QTextEdit.mouseDoubleClickEvent(self,evt) r = QRegExp("\\{(.*[|,].*)\\}") r.setMinimal(True) @@ -1030,8 +1030,7 @@ class FactEdit(QTextEdit): result = r.indexIn(self.toPlainText(), blockoffset) if found == "": - QTextEdit.mouseDoubleClickEvent(self,evt) - return + return QTextEdit.mouseDoubleClickEvent(self,evt) self.setPlainText(self.toPlainText().replace(result, r.matchedLength(), found)) def focusInEvent(self, evt): From 62f154b1b6b0d2f07bfed877b0c33fc5c3e7c983 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 19:55:34 +0900 Subject: [PATCH 14/18] improve wording in study options page --- designer/main.ui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/designer/main.ui b/designer/main.ui index 5790226e1..35d68d272 100644 --- a/designer/main.ui +++ b/designer/main.ui @@ -514,7 +514,7 @@ - <b>Session limit (mins):</b> + <b>Limit minutes per session to:</b> 4 @@ -546,7 +546,7 @@ - <b>New cards per day:</b> + <b>Limit new cards per day to:</b> 4 @@ -601,7 +601,7 @@ - <b>Session limit (reps): + <b>Limit repetitions per session to:</b> 4 From d0f918cdb0334c06e226b0371e22587f0dce1096 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 20:06:31 +0900 Subject: [PATCH 15/18] add tooltip to study stats --- ankiqt/ui/main.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/ankiqt/ui/main.py b/ankiqt/ui/main.py index f011c63cc..7c430280a 100644 --- a/ankiqt/ui/main.py +++ b/ankiqt/ui/main.py @@ -1112,6 +1112,33 @@ day = :d""", d=yesterday)

    %s
    %s
    """ % (stats1, stats2)) + self.mainWin.optionsLabel.setToolTip(_("""\ +

    Session Statistics

    +
    +
    Cards/session
    +
    The number of cards you studied in the current session (blue) and previous +session (black)
    +
    +
    +
    Cards/day
    +
    The number of cards you studied today (blue) and yesterday (black)
    +
    +
    +
    Time/day
    +
    The number of minutes you studied today (blue) and yesterday (black)
    +
    +
    +
    Reviews due
    +
    The number of cards that are waiting to be reviewed today
    +
    +
    +
    New today
    +
    The number of new cards that are waiting to be learnt today
    +
    +
    +
    New total
    +
    The total number of new cards in the deck
    +
    """)) def showStudyScreen(self): self.mainWin.optionsButton.setChecked(self.config['showStudyOptions']) From cafe0706249bb122db7605a57b9d186cacad7003 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 21:38:18 +0900 Subject: [PATCH 16/18] fix reference to isCramming --- 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 7c430280a..5e4bf2504 100644 --- a/ankiqt/ui/main.py +++ b/ankiqt/ui/main.py @@ -695,7 +695,7 @@ To upgrade an old deck, download Anki 0.9.8.7.""")) def onClose(self): if self.inMainWindow(): self.saveAndClose(hideWelcome=self.isCramming()) - if cramming: + if self.isCramming(): self.loadRecent(0) else: self.app.activeWindow().close() From b4b4805a0b56e5e4fd1d2a7861ce36a0855b3ddd Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 21:43:34 +0900 Subject: [PATCH 17/18] bump version --- ankiqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ankiqt/__init__.py b/ankiqt/__init__.py index 8c2f85898..14ee2f5c5 100644 --- a/ankiqt/__init__.py +++ b/ankiqt/__init__.py @@ -6,7 +6,7 @@ from PyQt4.QtCore import * from PyQt4.QtGui import * appName="Anki" -appVersion="0.9.9.7.6" +appVersion="0.9.9.7.6b" appWebsite="http://ichi2.net/anki/download/" appWiki="http://ichi2.net/anki/wiki/" appHelpSite="http://ichi2.net/anki/wiki/AnkiWiki" From 067f94aae22bebbb632b4c828a273f2f4ea888c5 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 25 Apr 2009 22:27:16 +0900 Subject: [PATCH 18/18] add icon to plist --- mac/setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mac/setup.py b/mac/setup.py index 1f1cad20c..91a747c1d 100644 --- a/mac/setup.py +++ b/mac/setup.py @@ -53,7 +53,8 @@ PLIST = dict( CFBundleName = 'Anki', CFBundleDocumentTypes=[dict(CFBundleTypeExtensions=["anki"], CFBundleTypeName="Anki Deck", - CFBundleTypeRole="Editor")], + CFBundleTypeRole="Editor", + CFBundleTypeIconFile="anki.icns")], CFBundleLocalizations = ['en'], ) OPTIONS = {