Merge branch 'master' of git://ichi2.net/ankiqt

This commit is contained in:
Susanna Björverud 2009-04-23 18:02:39 +02:00
commit 4852c42611
11 changed files with 116 additions and 67 deletions

View file

@ -75,6 +75,7 @@ class Config(dict):
'showStudyOptions': False,
'showStudyStats': True,
'showCardTimer': True,
'standaloneWindows': True,
'extraNewCards': 5,
'randomizeOnCram': True,
'created': time.time(),

View file

@ -22,7 +22,11 @@ class FocusButton(QPushButton):
class AddCards(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent, Qt.Window)
if parent.config['standaloneWindows']:
windParent = None
else:
windParent = parent
QDialog.__init__(self, windParent, Qt.Window)
self.parent = parent
self.config = parent.config
self.dialog = ankiqt.forms.addcards.Ui_AddCards()

View file

@ -278,7 +278,11 @@ class StatusDelegate(QItemDelegate):
class EditDeck(QMainWindow):
def __init__(self, parent):
QMainWindow.__init__(self, parent)
if parent.config['standaloneWindows']:
windParent = None
else:
windParent = parent
QMainWindow.__init__(self, windParent)
self.parent = parent
self.deck = self.parent.deck
self.config = parent.config
@ -412,8 +416,7 @@ class EditDeck(QMainWindow):
self.sortKey = ("field", self.sortFields[idx-9])
self.rebuildSortIndex(self.sortKey)
self.sortIndex = idx
if self.deck.getInt('sortIndex') != idx:
self.deck.setVar('sortIndex', idx)
self.deck.setVar('sortIndex', idx)
self.model.sortKey = self.sortKey
self.model.updateHeader()
if refresh:
@ -499,6 +502,8 @@ class EditDeck(QMainWindow):
self.updateSearch()
def updateSearch(self, force=True):
if self.parent.inDbHandler:
return
idx = self.dialog.tableView.currentIndex()
row = idx.row()
self.model.searchStr = unicode(self.dialog.filterEdit.text())

View file

@ -235,7 +235,7 @@ class DeckProperties(QDialog):
v = float(self.dialog.delay2.text())
self.updateField(self.d, 'delay2', v)
v = int(self.dialog.failedCardMax.text())
self.updateField(self.d, 'failedCardMax', max(v, 5))
self.updateField(self.d, 'failedCardMax', v)
except ValueError:
pass
# hour shift

View file

@ -42,9 +42,10 @@ class AnkiFigureCanvas (FigureCanvas):
class AdjustableFigure(QWidget):
def __init__(self, config, name, figureFunc, choices=None):
def __init__(self, parent, name, figureFunc, choices=None):
QWidget.__init__(self)
self.config = config
self.parent = parent
self.config = parent.config
self.name = name
self.vbox = QVBoxLayout()
self.vbox.setSpacing(2)
@ -75,6 +76,8 @@ class AdjustableFigure(QWidget):
self.vbox.addLayout(self.hbox)
def updateFigure(self):
if self.parent.inDbHandler:
return
self.updateTimer = None
self.setUpdatesEnabled(False)
idx = self.vbox.indexOf(self.figureCanvas)
@ -184,43 +187,43 @@ class GraphWindow(object):
self.diag.show()
def setupGraphs(self):
nextDue = AdjustableFigure(self.parent.config, 'due', self.dg.nextDue, self.range)
nextDue = AdjustableFigure(self.parent, 'due', self.dg.nextDue, self.range)
nextDue.addWidget(QLabel(_("<h1>Due</h1>")))
self.vbox.addWidget(nextDue)
self.widgets.append(nextDue)
workload = AdjustableFigure(self.parent.config, 'reps', self.dg.workDone, self.range)
workload = AdjustableFigure(self.parent, 'reps', self.dg.workDone, self.range)
workload.addWidget(QLabel(_("<h1>Reps</h1>")))
self.vbox.addWidget(workload)
self.widgets.append(workload)
times = AdjustableFigure(self.parent.config, 'times', self.dg.timeSpent, self.range)
times = AdjustableFigure(self.parent, 'times', self.dg.timeSpent, self.range)
times.addWidget(QLabel(_("<h1>Review Time</h1>")))
self.vbox.addWidget(times)
self.widgets.append(times)
added = AdjustableFigure(self.parent.config, 'added', self.dg.addedRecently, self.range)
added = AdjustableFigure(self.parent, 'added', self.dg.addedRecently, self.range)
added.addWidget(QLabel(_("<h1>Added</h1>")))
self.vbox.addWidget(added)
self.widgets.append(added)
answered = AdjustableFigure(self.parent.config, 'answered', lambda *args: apply(
answered = AdjustableFigure(self.parent, 'answered', lambda *args: apply(
self.dg.addedRecently, args + ('firstAnswered',)), self.range)
answered.addWidget(QLabel(_("<h1>First Answered</h1>")))
self.vbox.addWidget(answered)
self.widgets.append(answered)
cumDue = AdjustableFigure(self.parent.config, 'cum', self.dg.cumulativeDue, self.range)
cumDue = AdjustableFigure(self.parent, 'cum', self.dg.cumulativeDue, self.range)
cumDue.addWidget(QLabel(_("<h1>Cumulative Due</h1>")))
self.vbox.addWidget(cumDue)
self.widgets.append(cumDue)
interval = AdjustableFigure(self.parent.config, 'interval', self.dg.intervalPeriod, self.range)
interval = AdjustableFigure(self.parent, 'interval', self.dg.intervalPeriod, self.range)
interval.addWidget(QLabel(_("<h1>Intervals</h1>")))
self.vbox.addWidget(interval)
self.widgets.append(interval)
eases = AdjustableFigure(self.parent.config, 'eases', self.dg.easeBars)
eases = AdjustableFigure(self.parent, 'eases', self.dg.easeBars)
eases.addWidget(QLabel(_("<h1>Eases</h1>")))
self.vbox.addWidget(eases)
self.widgets.append(eases)

View file

@ -134,6 +134,8 @@ class ImportDialog(QDialog):
txt = (
_("Importing complete. %(num)d facts imported from %(file)s.\n") %
{"num": self.importer.total, "file": os.path.basename(self.file)})
self.dialog.groupBox.setShown(False)
self.dialog.buttonBox.button(QDialogButtonBox.Close).setFocus()
if self.importer.log:
txt += _("Log of import:\n") + "\n".join(self.importer.log)
self.dialog.status.setText(txt)

View file

@ -14,7 +14,7 @@ from PyQt4.QtGui import *
from anki import DeckStorage
from anki.errors import *
from anki.sound import hasSound, playFromText, clearAudioQueue
from anki.utils import addTags, deleteTags, parseTags
from anki.utils import addTags, deleteTags, parseTags, canonifyTags
from anki.media import rebuildMediaDir
from anki.db import OperationalError
from anki.stdmodels import BasicModel
@ -685,8 +685,7 @@ To upgrade an old deck, download Anki 0.9.8.7."""))
def onClose(self):
if self.inMainWindow():
cramming = self.deck is not None and self.deck.name() == "cram"
self.saveAndClose(hideWelcome=cramming)
self.saveAndClose(hideWelcome=self.isCramming())
if cramming:
self.loadRecent(0)
else:
@ -830,14 +829,17 @@ To upgrade an old deck, download Anki 0.9.8.7."""))
self.updateRecentFiles(file)
return True
def onUnsavedTimer(self):
def showToolTip(self, msg):
t = QTimer(self)
t.setSingleShot(True)
t.start(200)
self.connect(t, SIGNAL("timeout()"),
lambda msg=msg: self._showToolTip(msg))
def _showToolTip(self, msg):
QToolTip.showText(
self.mainWin.statusbar.mapToGlobal(QPoint(0, -100)),
_("""\
<h1>Unsaved Deck</h1>
Careful. You're editing an unsaved Deck.<br>
Choose File -> Save to start autosaving<br>
your deck."""))
self.mainWin.statusbar.mapToGlobal(QPoint(0, -40)),
msg)
def save(self, required=False):
if not self.deck.path:
@ -845,10 +847,11 @@ your deck."""))
# backed in memory, make sure it's saved
return self.onSaveAs()
else:
t = QTimer(self)
t.setSingleShot(True)
t.start(200)
self.connect(t, SIGNAL("timeout()"), self.onUnsavedTimer)
self.showToolTip(_("""\
<h1>Unsaved Deck</h1>
Careful. You're editing an unsaved Deck.<br>
Choose File -> Save to start autosaving<br>
your deck."""))
return
if not self.deck.modifiedSinceSave():
return True
@ -1036,7 +1039,6 @@ your deck."""))
def updateStudyStats(self):
wasReached = self.deck.sessionLimitReached()
self.deck.sessionStartTime = 0
sessionColour = '<font color=#0000ff>%s</font>'
cardColour = '<font color=#0000ff>%s</font>'
if not wasReached:
@ -1155,8 +1157,21 @@ day = :d""", d=yesterday)
int(self.mainWin.questionLimit.text()))
except (ValueError, OverflowError):
pass
uf(self.deck, 'newCardOrder',
self.mainWin.newCardOrder.currentIndex())
ncOrd = self.mainWin.newCardOrder.currentIndex()
if self.deck.newCardOrder != ncOrd:
if self.deck.newCardOrder == 0 and ncOrd != 0:
# random to non-random
self.deck.startProgress()
self.deck.updateProgress(_("Ordering..."))
self.deck.orderNewCards()
self.deck.finishProgress()
elif self.deck.newCardOrder != 0 and ncOrd == 0:
# non-random to random
self.deck.startProgress()
self.deck.updateProgress(_("Randomizing..."))
self.deck.randomizeNewCards()
self.deck.finishProgress()
uf(self.deck, 'newCardOrder', ncOrd)
uf(self.deck, 'newCardSpacing',
self.mainWin.newCardScheduling.currentIndex())
uf(self.deck, 'revCardOrder',
@ -1315,11 +1330,11 @@ day = :d""", d=yesterday)
def onMark(self, toggled):
if self.currentCard.hasTag("Marked"):
self.currentCard.fact.tags = deleteTags(
"Marked", self.currentCard.fact.tags)
self.currentCard.fact.tags = canonifyTags(deleteTags(
"Marked", self.currentCard.fact.tags))
else:
self.currentCard.fact.tags = addTags(
"Marked", self.currentCard.fact.tags)
self.currentCard.fact.tags = canonifyTags(addTags(
"Marked", self.currentCard.fact.tags))
self.currentCard.fact.setModified(textChanged=True)
self.deck.updateFactTags([self.currentCard.fact.id])
self.deck.setModified()
@ -1327,7 +1342,8 @@ day = :d""", d=yesterday)
def onSuspend(self):
undo = _("Suspend")
self.deck.setUndoStart(undo)
self.currentCard.fact.tags = addTags("Suspended", self.currentCard.fact.tags)
self.currentCard.fact.tags = canonifyTags(
addTags("Suspended", self.currentCard.fact.tags))
self.currentCard.fact.setModified(textChanged=True)
self.deck.updateFactTags([self.currentCard.fact.id])
for card in self.currentCard.fact.cards:
@ -1358,10 +1374,19 @@ day = :d""", d=yesterday)
##########################################################################
def onAddCard(self):
if self.isCramming():
ui.utils.showInfo(_("""\
You are currently cramming. Please close this deck first."""))
return
ui.dialogs.get("AddCards", self)
def onEditDeck(self):
ui.dialogs.get("CardList", self)
if self.isCramming():
self.showToolTip(_("""\
<h1>Cramming</h1>
You are currently cramming. Any edits you make to this deck
will be lost when you close the deck."""))
def onEditCurrent(self):
self.moveToState("editCurrentFact")
@ -1397,7 +1422,10 @@ day = :d""", d=yesterday)
##########################################################################
def onImport(self):
import ui.importing
if self.isCramming():
ui.utils.showInfo(_("""\
You are currently cramming. Please close this deck first."""))
return
if self.deck is None:
self.onNew()
ui.importing.ImportDialog(self)
@ -1421,8 +1449,11 @@ day = :d""", d=yesterday)
e.exportInto(path)
return (e, path)
def isCramming(self):
return self.deck is not None and self.deck.name() == "cram"
def onCram(self, cardIds=[]):
if self.deck.name() == "cram":
if self.isCramming():
ui.utils.showInfo(
_("Already cramming. Please close this deck first."))
return
@ -1442,7 +1473,7 @@ day = :d""", d=yesterday)
ui.utils.showInfo(_("No cards matched the provided tags."))
return
if self.config['randomizeOnCram']:
n = 5
n = 3
else:
n = 2
p = ui.utils.ProgressWin(self, n, 0, _("Cram"))
@ -1462,22 +1493,11 @@ day = :d""", d=yesterday)
self.deck.easyIntervalMax = 0.25
self.deck.newCardOrder = 0
self.deck.syncName = None
p.update()
self.deck.updateDynamicIndices()
if self.config['randomizeOnCram']:
p.update(_("Randomizing..."))
self.deck.s.statement(
"create temporary table idmap (old, new, primary key (old))")
self.deck.s.statement(
"insert into idmap select id, random() from facts")
self.deck.s.statement(
"update facts set id = (select new from idmap where old = id)")
p.update()
self.deck.s.statement(
"update cards set factId = (select new from idmap where old = factId)")
p.update()
self.deck.s.statement(
"update fields set factId = (select new from idmap where old = factId)")
p.update()
self.deck.updateDynamicIndices()
self.deck.randomizeNewCards()
self.reset()
p.finish()
@ -1645,6 +1665,7 @@ it to your friends.
onlyMerge, self.sourcesToCheck)
self.connect(self.syncThread, SIGNAL("setStatus"), self.setSyncStatus)
self.connect(self.syncThread, SIGNAL("showWarning"), self.showSyncWarning)
self.connect(self.syncThread, SIGNAL("noSyncResponse"), self.noSyncResponse)
self.connect(self.syncThread, SIGNAL("moveToState"), self.moveToState)
self.connect(self.syncThread, SIGNAL("noMatchingDeck"), self.selectSyncDeck)
self.connect(self.syncThread, SIGNAL("syncClockOff"), self.syncClockOff)
@ -1719,6 +1740,11 @@ it to your friends.
ui.utils.showWarning(text, self)
self.setStatus("")
def noSyncResponse(self):
self.showToolTip(_("""\
<h1>Sync Failed</h1>
Couldn't contact Anki Online. Please check your internet connection."""))
def openSyncProgress(self):
self.syncProgressDialog = QProgressDialog(_("Syncing Media..."),
"", 0, 0, self)

View file

@ -64,13 +64,16 @@ class StatusView(object):
shown = True
self.progressBar.setShown(shown)
self.retentionBar.setShown(shown)
self.timer.setShown(shown)
self.etaText.setShown(shown)
self.remText.setShown(shown)
self.sep1.setShown(shown)
self.sep2.setShown(shown)
self.sep3.setShown(shown)
self.statusbar.hideOrShow()
# timer has a separate option
if not self.main.config['showTimer']:
shown = False
self.timer.setShown(shown)
self.sep3.setShown(shown)
# Setup and teardown
##########################################################################
@ -130,8 +133,6 @@ class StatusView(object):
self.timer.setText("00:00")
self.addWidget(self.timer)
self.redraw()
if not self.main.config['showTimer']:
self.timer.setShown(False)
def addWidget(self, w, stretch=0):
self.statusbar.addWidget(w, stretch)

View file

@ -36,8 +36,11 @@ class Sync(QThread):
self.syncDeck()
def error(self, error):
error = self.getErrorMessage(error)
self.emit(SIGNAL("showWarning"), error)
if error.data.get('type') == 'noResponse':
self.emit(SIGNAL("noSyncResponse"))
else:
error = self.getErrorMessage(error)
self.emit(SIGNAL("showWarning"), error)
if self.onlyMerge:
# new file needs cleaning up
self.emit(SIGNAL("cleanNewDeck"))
@ -50,11 +53,7 @@ class Sync(QThread):
elif error.data.get('status') == "oldVersion":
msg=_("The sync protocol has changed. Please upgrade.")
else:
msg=_("""\
Syncing failed. Please try again in a few minutes.
If the problem persists, please report it on the forum.
Error: %s""" % `getattr(error, 'data')`)
msg=_("Unknown error: %s" % `getattr(error, 'data')`)
return msg
def connect(self, *args):

View file

@ -12,6 +12,10 @@
<property name="windowTitle" >
<string>Add Items</string>
</property>
<property name="windowIcon" >
<iconset resource="../icons.qrc" >
<normaloff>:/icons/list-add.png</normaloff>:/icons/list-add.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout" >
<property name="spacing" >
<number>0</number>
@ -93,8 +97,8 @@
<string>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
p, li { white-space: pre-wrap; }
&lt;/style>&lt;/head>&lt;body style=" font-family:'Arial'; font-size:8pt; font-weight:400; font-style:normal;">
&lt;p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&lt;/p>&lt;/body>&lt;/html></string>
&lt;/style>&lt;/head>&lt;body style=" font-family:'Sans Serif'; font-size:8pt; font-weight:400; font-style:normal;">
&lt;p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Arial';">&lt;/p>&lt;/body>&lt;/html></string>
</property>
</widget>
</widget>

View file

@ -12,6 +12,10 @@
<property name="windowTitle" >
<string>Browse Items</string>
</property>
<property name="windowIcon" >
<iconset resource="../icons.qrc" >
<normaloff>:/icons/find.png</normaloff>:/icons/find.png</iconset>
</property>
<widget class="QWidget" name="centralwidget" >
<layout class="QVBoxLayout" name="verticalLayout" >
<property name="spacing" >