refactor card layout, reviewing

This commit is contained in:
Damien Elmes 2011-11-28 14:37:07 +09:00
parent f2a39aad2a
commit cf87d19905
30 changed files with 1377 additions and 1195 deletions

0
anki.bat Normal file → Executable file
View file

View file

@ -29,13 +29,13 @@ Duggan, Matthew Holtz, Meelis Vasser, Michael Penkov, Michael Keppler, Michal
Petr Michalec, Piotr Kubowicz, Richard Colley, Samson Melamed, Stefaan Petr Michalec, Piotr Kubowicz, Richard Colley, Samson Melamed, Stefaan
De Pooter, Susanna Björverud, Tacutu, Timm Preetz, Timo Paulssen, Ursus, Victor De Pooter, Susanna Björverud, Tacutu, Timm Preetz, Timo Paulssen, Ursus, Victor
Suba, and Xtru. Suba, and Xtru.
<p>
Anki icon by Alex Fraser (CC GNU GPL) Anki icon by Alex Fraser (CC GNU GPL)<br>
Deck icon by Laurent Baumann (CC BY-NC-SA 3.0) Deck icon by Laurent Baumann (CC BY-NC-SA 3.0)<br>
Deck browser icons from: Deck browser icons from:<br>
http://led24.de/iconset http://led24.de/iconset<br>
http://p.yusukekamiyamane.com/ http://p.yusukekamiyamane.com/<br>
Other icons under LGPL or public domain. Other icons under LGPL or public domain.<br>
""" """
} }

View file

@ -9,7 +9,7 @@ import anki
from anki.errors import * from anki.errors import *
from anki.utils import stripHTML from anki.utils import stripHTML
from aqt.utils import saveGeom, restoreGeom, showWarning, askUser, shortcut, \ from aqt.utils import saveGeom, restoreGeom, showWarning, askUser, shortcut, \
tooltip tooltip, openHelp
from anki.sound import clearAudioQueue from anki.sound import clearAudioQueue
from anki.hooks import addHook, removeHook from anki.hooks import addHook, removeHook
from anki.utils import stripHTMLMedia, isMac from anki.utils import stripHTMLMedia, isMac
@ -46,7 +46,7 @@ class AddCards(QDialog):
self.mw, self.form.modelArea) self.mw, self.form.modelArea)
def helpRequested(self): def helpRequested(self):
aqt.openHelp("AddItems") openHelp("AddItems")
def setupButtons(self): def setupButtons(self):
bb = self.form.buttonBox bb = self.form.buttonBox

View file

@ -10,7 +10,7 @@ import anki, anki.utils, aqt.forms
from anki.utils import fmtTimeSpan, ids2str, stripHTMLMedia, isWin, intTime from anki.utils import fmtTimeSpan, ids2str, stripHTMLMedia, isWin, intTime
from aqt.utils import saveGeom, restoreGeom, saveSplitter, restoreSplitter, \ from aqt.utils import saveGeom, restoreGeom, saveSplitter, restoreSplitter, \
saveHeader, restoreHeader, saveState, restoreState, applyStyles, getTag, \ saveHeader, restoreHeader, saveState, restoreState, applyStyles, getTag, \
showInfo, askUser, tooltip showInfo, askUser, tooltip, openHelp
from anki.errors import * from anki.errors import *
from anki.db import * from anki.db import *
from anki.hooks import runHook, addHook, removeHook from anki.hooks import runHook, addHook, removeHook
@ -69,7 +69,7 @@ class DataModel(QAbstractTableModel):
return return
if role == Qt.FontRole: if role == Qt.FontRole:
f = QFont() f = QFont()
f.setPixelSize(self.browser.mw.config['editFontSize']) f.setPixelSize(self.browser.mw.pm.profile['editFontSize'])
return f return f
if role == Qt.TextAlignmentRole: if role == Qt.TextAlignmentRole:
align = Qt.AlignVCenter align = Qt.AlignVCenter
@ -112,7 +112,7 @@ class DataModel(QAbstractTableModel):
# the db progress handler may cause a refresh, so we need to zero out # the db progress handler may cause a refresh, so we need to zero out
# old data first # old data first
self.cards = [] self.cards = []
self.cards = self.col.findCards(txt, self.browser.mw.config['fullSearch']) self.cards = self.col.findCards(txt, self.browser.mw.pm.profile['fullSearch'])
print "fetch cards in %dms" % ((time.time() - t)*1000) print "fetch cards in %dms" % ((time.time() - t)*1000)
if reset: if reset:
self.endReset() self.endReset()
@ -332,8 +332,8 @@ class Browser(QMainWindow):
self.onSearch() self.onSearch()
def setupToolbar(self): def setupToolbar(self):
self.form.toolBar.setIconSize(QSize(self.mw.config['iconSize'], self.form.toolBar.setIconSize(QSize(self.mw.pm.profile['iconSize'],
self.mw.config['iconSize'])) self.mw.pm.profile['iconSize']))
self.form.toolBar.toggleViewAction().setText(_("Toggle Toolbar")) self.form.toolBar.toggleViewAction().setText(_("Toggle Toolbar"))
def setupMenus(self): def setupMenus(self):
@ -372,10 +372,10 @@ class Browser(QMainWindow):
def updateFont(self): def updateFont(self):
self.form.tableView.setFont(QFont( self.form.tableView.setFont(QFont(
self.mw.config['editFontFamily'], self.mw.pm.profile['editFontFamily'],
self.mw.config['editFontSize'])) self.mw.pm.profile['editFontSize']))
self.form.tableView.verticalHeader().setDefaultSectionSize( self.form.tableView.verticalHeader().setDefaultSectionSize(
self.mw.config['editLineSize']) self.mw.pm.profile['editLineSize'])
def closeEvent(self, evt): def closeEvent(self, evt):
saveSplitter(self.form.splitter_2, "editor2") saveSplitter(self.form.splitter_2, "editor2")
@ -432,7 +432,7 @@ class Browser(QMainWindow):
self.onSearch) self.onSearch)
self.setTabOrder(self.form.searchEdit, self.form.tableView) self.setTabOrder(self.form.searchEdit, self.form.tableView)
self.compModel = QStringListModel() self.compModel = QStringListModel()
self.compModel.setStringList(self.mw.config['searchHistory']) self.compModel.setStringList(self.mw.pm.profile['searchHistory'])
self.searchComp = QCompleter(self.compModel, self.form.searchEdit) self.searchComp = QCompleter(self.compModel, self.form.searchEdit)
self.searchComp.setCompletionMode(QCompleter.UnfilteredPopupCompletion) self.searchComp.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
self.searchComp.setCaseSensitivity(Qt.CaseInsensitive) self.searchComp.setCaseSensitivity(Qt.CaseInsensitive)
@ -441,18 +441,18 @@ class Browser(QMainWindow):
def onSearch(self, reset=True): def onSearch(self, reset=True):
"Careful: if reset is true, the current note is saved." "Careful: if reset is true, the current note is saved."
txt = unicode(self.form.searchEdit.text()).strip() txt = unicode(self.form.searchEdit.text()).strip()
sh = self.mw.config['searchHistory'] sh = self.mw.pm.profile['searchHistory']
if txt not in sh: if txt not in sh:
sh.insert(0, txt) sh.insert(0, txt)
sh = sh[:30] sh = sh[:30]
self.compModel.setStringList(sh) self.compModel.setStringList(sh)
self.mw.config['searchHistory'] = sh self.mw.pm.profile['searchHistory'] = sh
self.model.search(txt, reset) self.model.search(txt, reset)
if not self.model.cards: if not self.model.cards:
# no row change will fire # no row change will fire
self.onRowChanged(None, None) self.onRowChanged(None, None)
txt = _("No matches found.") txt = _("No matches found.")
if not self.mw.config['fullSearch']: if not self.mw.pm.profile['fullSearch']:
txt += "<p>" + _( txt += "<p>" + _(
_("If your cards have formatting, you may want <br>" _("If your cards have formatting, you may want <br>"
"to enable 'search within formatting' in the<br>" "to enable 'search within formatting' in the<br>"
@ -834,7 +834,7 @@ where id in %s""" % ids2str(sf))
return sf return sf
def onHelp(self): def onHelp(self):
aqt.openHelp("Browser") openHelp("Browser")
# Misc menu options # Misc menu options
###################################################################### ######################################################################
@ -1066,18 +1066,18 @@ where id in %s""" % ids2str(self.selectedCards()), mod)
frm = aqt.forms.browseropts.Ui_Dialog() frm = aqt.forms.browseropts.Ui_Dialog()
frm.setupUi(d) frm.setupUi(d)
frm.fontCombo.setCurrentFont(QFont( frm.fontCombo.setCurrentFont(QFont(
self.mw.config['editFontFamily'])) self.mw.pm.profile['editFontFamily']))
frm.fontSize.setValue(self.mw.config['editFontSize']) frm.fontSize.setValue(self.mw.pm.profile['editFontSize'])
frm.lineSize.setValue(self.mw.config['editLineSize']) frm.lineSize.setValue(self.mw.pm.profile['editLineSize'])
frm.fullSearch.setChecked(self.mw.config['fullSearch']) frm.fullSearch.setChecked(self.mw.pm.profile['fullSearch'])
if d.exec_(): if d.exec_():
self.mw.config['editFontFamily'] = ( self.mw.pm.profile['editFontFamily'] = (
unicode(frm.fontCombo.currentFont().family())) unicode(frm.fontCombo.currentFont().family()))
self.mw.config['editFontSize'] = ( self.mw.pm.profile['editFontSize'] = (
int(frm.fontSize.value())) int(frm.fontSize.value()))
self.mw.config['editLineSize'] = ( self.mw.pm.profile['editLineSize'] = (
int(frm.lineSize.value())) int(frm.lineSize.value()))
self.mw.config['fullSearch'] = frm.fullSearch.isChecked() self.mw.pm.profile['fullSearch'] = frm.fullSearch.isChecked()
self.updateFont() self.updateFont()
# Edit: replacing # Edit: replacing
@ -1130,7 +1130,7 @@ where id in %s""" % ids2str(self.selectedCards()), mod)
}) })
def onFindReplaceHelp(self): def onFindReplaceHelp(self):
aqt.openHelp("Browser#FindReplace") openHelp("Browser#FindReplace")
# Edit: finding dupes # Edit: finding dupes
###################################################################### ######################################################################
@ -1311,7 +1311,7 @@ select id from cards where nid in %s and ord in %s""" % (
self.browser.onSearch() self.browser.onSearch()
def onHelp(self): def onHelp(self):
aqt.openHelp("Browser#GenerateCards") openHelp("Browser#GenerateCards")
# Change model dialog # Change model dialog
###################################################################### ######################################################################
@ -1477,4 +1477,4 @@ Are you sure you want to continue?""")):
return QDialog.accept(self) return QDialog.accept(self)
def onHelp(self): def onHelp(self):
aqt.openHelp("Browser#ChangeModel") openHelp("Browser#ChangeModel")

View file

@ -7,439 +7,217 @@ from anki.consts import *
import aqt import aqt
from anki.sound import playFromText, clearAudioQueue from anki.sound import playFromText, clearAudioQueue
from aqt.utils import saveGeom, restoreGeom, getBase, mungeQA, \ from aqt.utils import saveGeom, restoreGeom, getBase, mungeQA, \
saveSplitter, restoreSplitter, showInfo, askUser, getText saveSplitter, restoreSplitter, showInfo, askUser, getOnlyText, \
showWarning, openHelp
from anki.utils import isMac, isWin from anki.utils import isMac, isWin
import aqt.templates import aqt.templates
# fixme: replace font substitutions with native comma list # raise Exception("Remember to disallow media&latex refs in edit.")
class ResizingTextEdit(QTextEdit):
def sizeHint(self):
return QSize(200, 800)
class CardLayout(QDialog): class CardLayout(QDialog):
# type is previewCards() type def __init__(self, mw, note, ord=0, parent=None):
def __init__(self, mw, note, type=0, ord=0, parent=None):
QDialog.__init__(self, parent or mw, Qt.Window) QDialog.__init__(self, parent or mw, Qt.Window)
raise Exception("Remember to disallow media&latex refs in edit.")
self.mw = aqt.mw self.mw = aqt.mw
self.parent = parent or mw self.parent = parent or mw
self.note = note self.note = note
self.type = type
self.ord = ord self.ord = ord
self.col = self.mw.col self.col = self.mw.col
self.mm = self.mw.col.models self.mm = self.mw.col.models
self.model = note.model() self.model = note.model()
self.form = aqt.forms.clayout.Ui_Dialog() self.setupTabs()
self.form.setupUi(self)
self.setWindowTitle(_("%s Layout") % self.model['name']) self.setWindowTitle(_("%s Layout") % self.model['name'])
self.plastiqueStyle = None v1 = QVBoxLayout()
if isMac or isWin: v1.addWidget(self.tabs)
self.plastiqueStyle = QStyleFactory.create("plastique") self.bbox = QDialogButtonBox(
self.connect(self.form.buttonBox, SIGNAL("helpRequested()"), QDialogButtonBox.Close|QDialogButtonBox.Help)
v1.addWidget(self.bbox)
self.setLayout(v1)
self.connect(self.bbox, SIGNAL("helpRequested()"),
self.onHelp) self.onHelp)
self.setupCards() self.bbox.button(QDialogButtonBox.Help).setAutoDefault(False)
self.setupFields() self.bbox.button(QDialogButtonBox.Close).setAutoDefault(False)
self.form.buttonBox.button(QDialogButtonBox.Help).setAutoDefault(False) self.mw.checkpoint(_("Card Layout"))
self.form.buttonBox.button(QDialogButtonBox.Close).setAutoDefault(False) self.redraw()
restoreSplitter(self.form.splitter, "clayout")
restoreGeom(self, "CardLayout") restoreGeom(self, "CardLayout")
if not self.reload(first=True):
return
self.exec_() self.exec_()
def reload(self, first=False): def redraw(self):
self.cards = self.col.previewCards(self.note, self.type) self.cards = self.col.previewCards(self.note, 2)
if not self.cards: self.redrawing = True
self.accept() self.updateTabs()
if first: self.redrawing = False
showInfo(_("Please enter some text first.")) self.selectCard(self.ord)
else:
showInfo(_("The current note was deleted.")) def setupTabs(self):
return c = self.connect
self.fillCardList() self.tabs = QTabWidget()
self.fillFieldList() self.tabs.setTabsClosable(True)
self.fieldChanged() self.tabs.setUsesScrollButtons(True)
self.readField() add = QPushButton("+")
return True add.setFixedWidth(30)
c(add, SIGNAL("clicked()"), self.onAddCard)
self.tabs.setCornerWidget(add)
c(self.tabs, SIGNAL("currentChanged(int)"), self.selectCard)
c(self.tabs, SIGNAL("tabCloseRequested(int)"), self.onRemoveTab)
def updateTabs(self):
self.forms = []
self.tabs.clear()
for t in self.model['tmpls']:
self.addTab(t)
def addTab(self, t):
c = self.connect
w = QWidget()
h = QHBoxLayout()
h.addStretch()
rename = QPushButton("Rename")
c(rename, SIGNAL("clicked()"), self.onRename)
h.addWidget(rename)
order = QPushButton(_("Reposition"))
h.addWidget(order)
c(order, SIGNAL("clicked()"), self.onReorder)
h.addStretch()
v = QVBoxLayout()
v.setMargin(3)
v.setSpacing(3)
v.addLayout(h)
l = QHBoxLayout()
l.setMargin(0)
l.setSpacing(3)
left = QWidget()
# template area
tform = aqt.forms.template.Ui_Form()
tform.setupUi(left)
c(tform.front, SIGNAL("textChanged()"), self.onTemplateEdit)
c(tform.back, SIGNAL("textChanged()"), self.onTemplateEdit)
l.addWidget(left, 5)
# preview area
right = QWidget()
pform = aqt.forms.preview.Ui_Form()
pform.setupUi(right)
def linkClicked(url):
QDesktopServices.openUrl(QUrl(url))
for wig in pform.front, pform.back:
wig.page().setLinkDelegationPolicy(
QWebPage.DelegateExternalLinks)
c(wig, SIGNAL("linkClicked(QUrl)"), linkClicked)
l.addWidget(right, 5)
v.addLayout(l)
w.setLayout(v)
self.forms.append({'tform': tform, 'pform': pform})
self.tabs.addTab(w, t['name'])
def onRemoveTab(self, idx):
if not self.mm.remTemplate(self.model, self.cards[idx].template()):
return showWarning(_("""\
Removing this card would cause one or more notes to be deleted. \
Please create a new card first."""))
self.redraw()
# Cards & Preview # Cards & Preview
########################################################################## ##########################################################################
def setupCards(self): def selectCard(self, idx):
self.updatingCards = False if self.redrawing:
self.playedAudio = {}
f = self.form
if self.type == 0:
f.templateType.setText(
_("Templates that will be created:"))
elif self.type == 1:
f.templateType.setText(
_("Templates used by note:"))
else:
f.templateType.setText(
_("All templates:"))
# replace with more appropriate size hints
for e in ("cardQuestion", "cardAnswer"):
w = getattr(f, e)
idx = f.templateLayout.indexOf(w)
r = f.templateLayout.getItemPosition(idx)
f.templateLayout.removeWidget(w)
w.hide()
w.deleteLater()
w = ResizingTextEdit(self)
setattr(f, e, w)
f.templateLayout.addWidget(w, r[0], r[1])
c = self.connect
c(f.cardList, SIGNAL("activated(int)"), self.cardChanged)
c(f.editTemplates, SIGNAL("clicked()"), self.onEdit)
c(f.cardQuestion, SIGNAL("textChanged()"), self.formatChanged)
c(f.cardAnswer, SIGNAL("textChanged()"), self.formatChanged)
c(f.alignment, SIGNAL("activated(int)"), self.saveCard)
c(f.background, SIGNAL("clicked()"),
lambda w=f.background:\
self.chooseColour(w, "card"))
c(f.questionInAnswer, SIGNAL("clicked()"), self.saveCard)
c(f.allowEmptyAnswer, SIGNAL("clicked()"), self.saveCard)
c(f.typeAnswer, SIGNAL("activated(int)"), self.saveCard)
c(f.flipButton, SIGNAL("clicked()"), self.onFlip)
c(f.clozectx, SIGNAL("clicked()"), self.saveCard)
def linkClicked(url):
QDesktopServices.openUrl(QUrl(url))
f.preview.page().setLinkDelegationPolicy(
QWebPage.DelegateExternalLinks)
self.connect(f.preview,
SIGNAL("linkClicked(QUrl)"),
linkClicked)
if self.plastiqueStyle:
f.background.setStyle(self.plastiqueStyle)
f.alignment.addItems(alignmentLabels().values())
self.typeFieldNames = self.mm.fieldMap(self.model)
s = [_("Don't ask me to type in the answer")]
s += [_("Compare with field '%s'") % fi
for fi in self.typeFieldNames.keys()]
f.typeAnswer.insertItems(0, s)
def formatToScreen(self, fmt):
fmt = fmt.replace("}}<br>", "}}\n")
return fmt
def screenToFormat(self, fmt):
fmt = fmt.replace("}}\n", "}}<br>")
return fmt
def onEdit(self):
aqt.templates.Templates(self.mw, self.model, self)
self.reload()
def formatChanged(self):
if self.updatingCards:
return return
text = unicode(self.form.cardQuestion.toPlainText()) self.ord = idx
self.card.template()['qfmt'] = self.screenToFormat(text)
text = unicode(self.form.cardAnswer.toPlainText())
self.card.template()['afmt'] = self.screenToFormat(text)
self.renderPreview()
def onFlip(self):
q = unicode(self.form.cardQuestion.toPlainText())
a = unicode(self.form.cardAnswer.toPlainText())
self.form.cardAnswer.setPlainText(q)
self.form.cardQuestion.setPlainText(a)
def readCard(self):
self.updatingCards = True
t = self.card.template()
f = self.form
f.background.setPalette(QPalette(QColor(t['bg'])))
f.cardQuestion.setPlainText(self.formatToScreen(t['qfmt']))
f.cardAnswer.setPlainText(self.formatToScreen(t['afmt']))
f.questionInAnswer.setChecked(t['hideQ'])
f.allowEmptyAnswer.setChecked(t['emptyAns'])
f.alignment.setCurrentIndex(t['align'])
if t['typeAns'] is None:
f.typeAnswer.setCurrentIndex(0)
else:
f.typeAnswer.setCurrentIndex(t['typeAns'] + 1)
# model-level, but there's nowhere else to put this
f.clozectx.setChecked(self.model['clozectx'])
self.updatingCards = False
def fillCardList(self):
self.form.cardList.clear()
cards = []
idx = 0
for n, c in enumerate(self.cards):
if c.ord == self.ord:
cards.append(_("%s (current)") % c.template()['name'])
idx = n
else:
cards.append(c.template()['name'])
self.form.cardList.addItems(cards)
self.form.cardList.setCurrentIndex(idx)
self.cardChanged(idx)
self.form.cardList.setFocus()
def cardChanged(self, idx):
self.card = self.cards[idx] self.card = self.cards[idx]
self.tab = self.forms[idx]
self.tabs.setCurrentIndex(idx)
self.readCard() self.readCard()
self.renderPreview() self.renderPreview()
def saveCard(self): def readCard(self):
if self.updatingCards:
return
t = self.card.template() t = self.card.template()
t['align'] = self.form.alignment.currentIndex() self.redrawing = True
t['bg'] = unicode( self.tab['tform'].front.setPlainText(t['qfmt'])
self.form.background.palette().window().color().name()) self.tab['tform'].back.setPlainText(t['afmt'])
t['hideQ'] = self.form.questionInAnswer.isChecked() self.redrawing = False
t['emptyAns'] = self.form.allowEmptyAnswer.isChecked()
idx = self.form.typeAnswer.currentIndex() def onTemplateEdit(self):
if not idx: if self.redrawing:
t['typeAns'] = None return
else: text = self.tab['tform'].front.toPlainText()
t['typeAns'] = idx-1 self.card.template()['qfmt'] = text
self.model['clozectx'] = self.form.clozectx.isChecked() text = self.tab['tform'].back.toPlainText()
self.card.template()['afmt'] = text
self.renderPreview() self.renderPreview()
def chooseColour(self, button, type="field"): def saveCard(self):
new = QColorDialog.getColor(button.palette().window().color(), self, t = self.card.template()
_("Choose Color"), self.renderPreview()
QColorDialog.DontUseNativeDialog)
if new.isValid():
button.setPalette(QPalette(new))
if type == "field":
self.saveField()
else:
self.saveCard()
def renderPreview(self): def renderPreview(self):
print "preview"
c = self.card c = self.card
styles = self.model['css'] styles = "\n.cloze { font-weight: bold; color: blue; }"
styles += "\n.cloze { font-weight: bold; color: blue; }" html = '<html><body id=card><style>%s</style>%s</body></html>'
self.form.preview.setHtml( self.tab['pform'].front.setHtml(
('<html><head>%s</head><body class="%s">' % html % (styles, mungeQA(c.q(reload=True))))
(getBase(self.col), c.cssClass())) + self.tab['pform'].back.setHtml(
"<style>" + styles + "</style>" + html % (styles, mungeQA(c.a())))
mungeQA(c.q(reload=True)) +
self.maybeTextInput() +
"<hr>" +
mungeQA(c.a())
+ "</body></html>")
clearAudioQueue()
if c.id not in self.playedAudio:
playFromText(c.q())
playFromText(c.a())
self.playedAudio[c.id] = True
def maybeTextInput(self): def maybeTextInput(self):
return "text input"
if self.card.template()['typeAns'] is not None: if self.card.template()['typeAns'] is not None:
return "<center><input type=text></center>" return "<center><input type=text></center>"
return "" return ""
def onRename(self):
name = getOnlyText(_("New name:"))
if not name:
return
if name in [c.template()['name'] for c in self.cards
if c.template()['ord'] != self.ord]:
return showWarning(_("That name is already used."))
self.card.template()['name'] = name
self.tabs.setTabText(self.tabs.currentIndex(), name)
def onReorder(self):
n = len(self.cards)
cur = self.card.template()['ord']+1
pos = getOnlyText(
_("Enter new card position (1..%s):") % n,
default=str(cur))
if not pos:
return
try:
pos = int(pos)
except ValueError:
return
if pos < 1 or pos > n:
return
if pos == cur:
return
pos -= 1
self.mm.moveTemplate(self.model, self.card.template(), pos)
self.ord = pos
self.redraw()
def onAddCard(self):
name = getOnlyText(_("Name:"))
if not name:
return
if name in [c.template()['name'] for c in self.cards]:
return showWarning(_("That name is already used."))
t = self.mm.newTemplate(name)
self.mm.addTemplate(self.model, t)
self.redraw()
# Closing & Help
######################################################################
def accept(self): def accept(self):
self.reject() self.reject()
def reject(self): def reject(self):
self.mm.save(self.model) self.mm.save(self.model)
saveGeom(self, "CardLayout")
saveSplitter(self.form.splitter, "clayout")
self.mw.reset() self.mw.reset()
saveGeom(self, "CardLayout")
return QDialog.reject(self) return QDialog.reject(self)
modified = False
self.mw.startProgress()
self.col.updateProgress(_("Applying changes..."))
reset=True
if len(self.fieldOrdinalUpdatedIds) > 0:
self.col.rebuildFieldOrdinals(self.model.id, self.fieldOrdinalUpdatedIds)
modified = True
if self.needFieldRebuild:
modified = True
if modified:
self.note.model.setModified()
self.col.flushMod()
if self.noteedit and self.noteedit.onChange:
self.noteedit.onChange("all")
reset=False
if reset:
self.mw.reset()
self.col.finishProgress()
QDialog.reject(self)
def onHelp(self): def onHelp(self):
aqt.openHelp("CardLayout") openHelp("CardLayout")
# Fields
##########################################################################
def setupFields(self):
self.fieldOrdinalUpdatedIds = []
self.updatingFields = False
self.needFieldRebuild = False
c = self.connect; f = self.form
sc = SIGNAL("stateChanged(int)")
cl = SIGNAL("clicked()")
c(f.fieldAdd, cl, self.addField)
c(f.fieldDelete, cl, self.deleteField)
c(f.fieldUp, cl, self.moveFieldUp)
c(f.fieldDown, cl, self.moveFieldDown)
c(f.preserveWhitespace, sc, self.saveField)
c(f.fieldUnique, sc, self.saveField)
c(f.fieldRequired, sc, self.saveField)
c(f.sticky, sc, self.saveField)
c(f.fieldList, SIGNAL("currentRowChanged(int)"),
self.fieldChanged)
c(f.fieldName, SIGNAL("lostFocus()"),
self.saveField)
c(f.fontFamily, SIGNAL("currentFontChanged(QFont)"),
self.saveField)
c(f.fontSize, SIGNAL("valueChanged(int)"),
self.saveField)
c(f.fontSizeEdit, SIGNAL("valueChanged(int)"),
self.saveField)
w = self.form.fontColour
if self.plastiqueStyle:
w.setStyle(self.plastiqueStyle)
c(w, SIGNAL("clicked()"),
lambda w=w: self.chooseColour(w))
c(self.form.rtl,
SIGNAL("stateChanged(int)"),
self.saveField)
def fieldChanged(self):
row = self.form.fieldList.currentRow()
if row == -1:
row = 0
self.field = self.model['flds'][row]
self.readField()
self.enableFieldMoveButtons()
def readField(self):
fld = self.field
f = self.form
self.updatingFields = True
f.fieldName.setText(fld['name'])
f.fieldUnique.setChecked(fld['uniq'])
f.fieldRequired.setChecked(fld['req'])
f.fontFamily.setCurrentFont(QFont(fld['font']))
f.fontSize.setValue(fld['qsize'])
f.fontSizeEdit.setValue(fld['esize'])
f.fontColour.setPalette(QPalette(QColor(fld['qcol'])))
f.rtl.setChecked(fld['rtl'])
f.preserveWhitespace.setChecked(fld['pre'])
f.sticky.setChecked(fld['sticky'])
self.updatingFields = False
def saveField(self, *args):
self.needFieldRebuild = True
if self.updatingFields:
return
self.updatingFields = True
fld = self.field
# get name; we'll handle it last
name = unicode(self.form.fieldName.text())
if not name:
return
fld['uniq'] = self.form.fieldUnique.isChecked()
fld['req'] = self.form.fieldRequired.isChecked()
fld['font'] = unicode(
self.form.fontFamily.currentFont().family())
fld['qsize'] = self.form.fontSize.value()
fld['esize'] = self.form.fontSizeEdit.value()
fld['qcol'] = str(
self.form.fontColour.palette().window().color().name())
fld['rtl'] = self.form.rtl.isChecked()
fld['pre'] = self.form.preserveWhitespace.isChecked()
fld['sticky'] = self.form.sticky.isChecked()
self.updatingFields = False
if fld['name'] != name:
self.mm.renameField(self.model, fld, name)
# as the field name has changed, we have to regenerate cards
self.cards = self.col.previewCards(self.note, self.type)
self.cardChanged(0)
self.renderPreview()
self.fillFieldList()
def fillFieldList(self, row = None):
oldRow = self.form.fieldList.currentRow()
if oldRow == -1:
oldRow = 0
self.form.fieldList.clear()
n = 1
for field in self.model['flds']:
label = field['name']
item = QListWidgetItem(label)
self.form.fieldList.addItem(item)
n += 1
count = self.form.fieldList.count()
if row != None:
self.form.fieldList.setCurrentRow(row)
else:
while (count > 0 and oldRow > (count - 1)):
oldRow -= 1
self.form.fieldList.setCurrentRow(oldRow)
self.enableFieldMoveButtons()
def enableFieldMoveButtons(self):
row = self.form.fieldList.currentRow()
if row < 1:
self.form.fieldUp.setEnabled(False)
else:
self.form.fieldUp.setEnabled(True)
if row == -1 or row >= (self.form.fieldList.count() - 1):
self.form.fieldDown.setEnabled(False)
else:
self.form.fieldDown.setEnabled(True)
def addField(self):
f = self.mm.newField(self.model)
l = len(self.model['flds'])
f['name'] = _("Field %d") % l
self.mw.progress.start()
self.mm.addField(self.model, f)
self.mw.progress.finish()
self.reload()
self.form.fieldList.setCurrentRow(l)
self.form.fieldName.setFocus()
self.form.fieldName.selectAll()
def deleteField(self):
row = self.form.fieldList.currentRow()
if row == -1:
return
if len(self.model.fields) < 2:
showInfo(_("Please add a new field first."))
return
if askUser(_("Delete this field and its data from all notes?")):
self.mw.progress.start()
self.model.delField(self.field)
self.mw.progress.finish()
# need to update q/a format
self.reload()
def moveFieldUp(self):
row = self.form.fieldList.currentRow()
if row == -1:
return
if row == 0:
return
self.mw.progress.start()
self.model.moveField(self.field, row-1)
self.mw.progress.finish()
self.form.fieldList.setCurrentRow(row-1)
self.reload()
def moveFieldDown(self):
row = self.form.fieldList.currentRow()
if row == -1:
return
if row == len(self.model.fields) - 1:
return
self.mw.progress.start()
self.model.moveField(self.field, row+1)
self.mw.progress.finish()
self.form.fieldList.setCurrentRow(row+1)
self.reload()

View file

@ -3,7 +3,7 @@
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from aqt.qt import * from aqt.qt import *
from aqt.utils import askUser from aqt.utils import askUser, getOnlyText
class DeckBrowser(object): class DeckBrowser(object):
@ -27,7 +27,7 @@ class DeckBrowser(object):
if cmd == "open": if cmd == "open":
self._selDeck(arg) self._selDeck(arg)
elif cmd == "opts": elif cmd == "opts":
self._optsForRow(int(arg)) self._showOptions(arg)
elif cmd == "download": elif cmd == "download":
self.mw.onGetSharedDeck() self.mw.onGetSharedDeck()
elif cmd == "new": elif cmd == "new":
@ -43,7 +43,7 @@ class DeckBrowser(object):
def _selDeck(self, did): def _selDeck(self, did):
self.mw.col.decks.select(did) self.mw.col.decks.select(did)
self.mw.moveToState("overview") self.mw.onOverview()
# HTML generation # HTML generation
########################################################################## ##########################################################################
@ -85,13 +85,15 @@ body { margin: 1em; }
def _deckRow(self, node, depth): def _deckRow(self, node, depth):
name, did, due, new, children = node name, did, due, new, children = node
def indent():
return "&nbsp;"*3*depth
# due image # due image
buf = "<tr><td colspan=5>" + self._dueImg(due, new) buf = "<tr><td colspan=5>" + indent() + self._dueImg(due, new)
# deck link # deck link
buf += " <a class=deck href='open:%d'>%s</a></td>"% (did, name) buf += " <a class=deck href='open:%d'>%s</a></td>"% (did, name)
# options # options
buf += "<td align=right class=opts>%s</td></tr>" % self.mw.button( buf += "<td align=right class=opts>%s</td></tr>" % self.mw.button(
link="opts:%d"%did, name=_("Options")+'&#9662') link="opts:%d"%did, name="<img valign=bottom src='qrc:/icons/gears.png'>&#9662")
# children # children
buf += self._renderDeckTree(children, depth+1) buf += self._renderDeckTree(children, depth+1)
return buf return buf
@ -108,25 +110,29 @@ body { margin: 1em; }
# Options # Options
########################################################################## ##########################################################################
def _optsForRow(self, n): def _showOptions(self, did):
m = QMenu(self.mw) m = QMenu(self.mw)
# delete a = m.addAction(_("Rename"))
a = m.addAction(QIcon(":/icons/editdelete.png"), _("Delete")) a.connect(a, SIGNAL("triggered()"), lambda did=did: self._rename(did))
a.connect(a, SIGNAL("triggered()"), lambda n=n: self._deleteRow(n)) a = m.addAction(_("Delete"))
a.connect(a, SIGNAL("triggered()"), lambda did=did: self._delete(did))
m.exec_(QCursor.pos()) m.exec_(QCursor.pos())
def _deleteRow(self, c): def _rename(self, did):
d = self._decks[c] deck = self.mw.col.decks.get(did)
if d['state'] == 'missing': newName = getOnlyText(_("New deck name:"))
return self._hideRow(c) if not newName:
return
if deck in self.mw.col.decks.allNames():
return showWarning(_("That deck already exists."))
self.mw.col.decks.rename(deck, newName)
self.show()
def _delete(self, did):
if did == 1:
return showWarning(_("The default deck can't be deleted."))
deck = self.mw.col.decks.get(did)
if askUser(_("""\ if askUser(_("""\
Delete %s? If this deck is synchronized the online version will \ Are you sure you wish to delete all of the cards in %s?""")%deck['name']):
not be touched.""") % d['name']): self.mw.col.decks.rem(did, True)
deck = d['path'] self.show()
os.unlink(deck)
try:
shutil.rmtree(re.sub(".anki$", ".media", deck))
except OSError:
pass
self.mw.config.delRecentDeck(deck)
self.refresh()

View file

@ -4,7 +4,7 @@
from aqt.qt import * from aqt.qt import *
import sys, re import sys, re
import aqt import aqt
from aqt.utils import maybeHideClose from aqt.utils import maybeHideClose, openHelp
class ColOptions(QDialog): class ColOptions(QDialog):
@ -28,7 +28,7 @@ class ColOptions(QDialog):
self.form.mediaURL.setText(self.d.conf['mediaURL']) self.form.mediaURL.setText(self.d.conf['mediaURL'])
def helpRequested(self): def helpRequested(self):
aqt.openHelp("ColOptions") openHelp("ColOptions")
def reject(self): def reject(self):
needSync = False needSync = False

View file

@ -9,7 +9,8 @@ from anki.sound import play
from anki.hooks import runHook from anki.hooks import runHook
from aqt.sound import getAudio from aqt.sound import getAudio
from aqt.webview import AnkiWebView from aqt.webview import AnkiWebView
from aqt.utils import shortcut, showInfo, showWarning, getBase, getFile from aqt.utils import shortcut, showInfo, showWarning, getBase, getFile, \
openHelp
import aqt import aqt
import anki.js import anki.js
@ -449,7 +450,7 @@ class Editor(object):
form = aqt.forms.edithtml.Ui_Dialog() form = aqt.forms.edithtml.Ui_Dialog()
form.setupUi(d) form.setupUi(d)
d.connect(form.buttonBox, SIGNAL("helpRequested()"), d.connect(form.buttonBox, SIGNAL("helpRequested()"),
lambda: aqt.openHelp("HtmlEditor")) lambda: openHelp("HtmlEditor"))
form.textEdit.setPlainText(self.note.fields[self.currentField]) form.textEdit.setPlainText(self.note.fields[self.currentField])
form.textEdit.moveCursor(QTextCursor.End) form.textEdit.moveCursor(QTextCursor.End)
d.exec_() d.exec_()
@ -582,7 +583,7 @@ class Editor(object):
txtcol) txtcol)
def colourChanged(self): def colourChanged(self):
recent = self.mw.config['recentColours'] recent = self.mw.pm.profile['recentColours']
self._updateForegroundButton(recent[-1]) self._updateForegroundButton(recent[-1])
def onForeground(self): def onForeground(self):
@ -606,7 +607,7 @@ class Editor(object):
self.colourChoose = QShortcut(QKeySequence("F6"), p) self.colourChoose = QShortcut(QKeySequence("F6"), p)
p.connect(self.colourChoose, SIGNAL("activated()"), p.connect(self.colourChoose, SIGNAL("activated()"),
self.onChooseColourKey) self.onChooseColourKey)
for n, c in enumerate(reversed(self.mw.config['recentColours'])): for n, c in enumerate(reversed(self.mw.pm.profile['recentColours'])):
col = QToolButton() col = QToolButton()
col.setAutoRaise(True) col.setAutoRaise(True)
col.setFixedWidth(64) col.setFixedWidth(64)
@ -640,7 +641,7 @@ class Editor(object):
p.show() p.show()
def onRemoveColour(self, colour): def onRemoveColour(self, colour):
recent = self.mw.config['recentColours'] recent = self.mw.pm.profile['recentColours']
recent.remove(colour) recent.remove(colour)
if not recent: if not recent:
recent.append("#000000") recent.append("#000000")
@ -659,7 +660,7 @@ class Editor(object):
pass pass
def onChooseColour(self, colour): def onChooseColour(self, colour):
recent = self.mw.config['recentColours'] recent = self.mw.pm.profile['recentColours']
recent.remove(colour) recent.remove(colour)
recent.append(colour) recent.append(colour)
self.web.eval("setFormat('forecolor', '%s')" % colour) self.web.eval("setFormat('forecolor', '%s')" % colour)
@ -669,7 +670,7 @@ class Editor(object):
def onNewColour(self): def onNewColour(self):
new = QColorDialog.getColor(Qt.white, self.widget) new = QColorDialog.getColor(Qt.white, self.widget)
self.widget.raise_() self.widget.raise_()
recent = self.mw.config['recentColours'] recent = self.mw.pm.profile['recentColours']
if new.isValid(): if new.isValid():
txtcol = unicode(new.name()) txtcol = unicode(new.name())
if txtcol not in recent: if txtcol not in recent:
@ -698,7 +699,7 @@ class Editor(object):
# copy to media folder # copy to media folder
name = self.mw.col.media.addFile(path) name = self.mw.col.media.addFile(path)
# remove original? # remove original?
if canDelete and self.mw.config['deleteMedia']: if canDelete and self.mw.pm.profile['deleteMedia']:
if os.path.abspath(name) != os.path.abspath(path): if os.path.abspath(name) != os.path.abspath(path):
try: try:
os.unlink(old) os.unlink(old)
@ -738,7 +739,7 @@ class Editor(object):
###################################################################### ######################################################################
def setupKeyboard(self): def setupKeyboard(self):
if isWin and self.mw.config['preserveKeyboard']: if isWin and self.mw.pm.profile['preserveKeyboard']:
a = ctypes.windll.user32.ActivateKeyboardLayout a = ctypes.windll.user32.ActivateKeyboardLayout
a.restype = ctypes.c_void_p a.restype = ctypes.c_void_p
a.argtypes = [ctypes.c_void_p, ctypes.c_uint] a.argtypes = [ctypes.c_void_p, ctypes.c_uint]
@ -773,7 +774,7 @@ class EditorWebView(AnkiWebView):
AnkiWebView.__init__(self, parent) AnkiWebView.__init__(self, parent)
self.editor = editor self.editor = editor
self.errtxt = _("An error occured while opening %s") self.errtxt = _("An error occured while opening %s")
self.strip = self.editor.mw.config['stripHTML'] self.strip = self.editor.mw.pm.profile['stripHTML']
def keyPressEvent(self, evt): def keyPressEvent(self, evt):
self._curKey = True self._curKey = True

495
aqt/fields.py Normal file
View file

@ -0,0 +1,495 @@
# Copyright: Damien Elmes <anki@ichi2.net>
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from aqt.qt import *
import re
from anki.consts import *
import aqt
from anki.sound import playFromText, clearAudioQueue
from aqt.utils import saveGeom, restoreGeom, getBase, mungeQA, \
saveSplitter, restoreSplitter, showInfo, askUser, getText, \
openHelp
from anki.utils import isMac, isWin
import aqt.templates
# raise Exception("Remember to disallow media&latex refs in edit.")
# need to strip the field management code out of this
class CardLayout(QDialog):
def __init__(self, mw, note, ord=0, parent=None):
QDialog.__init__(self, parent or mw, Qt.Window)
self.mw = aqt.mw
self.parent = parent or mw
self.note = note
self.ord = ord
self.col = self.mw.col
self.mm = self.mw.col.models
self.model = note.model()
self.setupTabs()
v1 = QVBoxLayout()
v1.addWidget(self.tabs)
self.bbox = QDialogButtonBox(QDialogButtonBox.Close)
v1.addWidget(self.bbox)
self.setLayout(v1)
self.updateTabs()
self.exec_()
return
def setupTabs(self):
self.tabs = QTabWidget()
self.tabs.setTabsClosable(True)
self.tabs.setUsesScrollButtons(True)
self.tabs.setMovable(True)
add = QPushButton("+")
add.setFixedWidth(30)
self.tabs.setCornerWidget(add)
def updateTabs(self):
self.forms = []
self.tabs.clear()
for t in self.model['tmpls']:
self.addTab(t)
def addTab(self, t):
w = QWidget()
h = QHBoxLayout()
h.addStretch()
label = QLabel(_("Name:"))
h.addWidget(label)
edit = QLineEdit()
edit.setFixedWidth(200)
h.addWidget(edit)
h.addStretch()
v = QVBoxLayout()
v.addLayout(h)
l = QHBoxLayout()
l.setMargin(0)
l.setSpacing(3)
left = QWidget()
# template area
tform = aqt.forms.template.Ui_Form()
tform.setupUi(left)
l.addWidget(left, 5)
# preview area
right = QWidget()
pform = aqt.forms.preview.Ui_Form()
pform.setupUi(right)
l.addWidget(right, 5)
v.addLayout(l)
w.setLayout(v)
self.tabs.addTab(w, t['name'])
self.forms.append([tform, pform, edit])
def old():
self.form = aqt.forms.clayout.Ui_Dialog()
self.form.setupUi(self)
self.setWindowTitle(_("%s Layout") % self.model['name'])
self.plastiqueStyle = None
if isMac or isWin:
self.plastiqueStyle = QStyleFactory.create("plastique")
self.connect(self.form.buttonBox, SIGNAL("helpRequested()"),
self.onHelp)
self.setupCards()
self.setupFields()
self.form.buttonBox.button(QDialogButtonBox.Help).setAutoDefault(False)
self.form.buttonBox.button(QDialogButtonBox.Close).setAutoDefault(False)
restoreSplitter(self.form.splitter, "clayout")
restoreGeom(self, "CardLayout")
if not self.reload(first=True):
return
self.exec_()
def reload(self, first=False):
self.cards = self.col.previewCards(self.note, self.type)
if not self.cards:
self.accept()
if first:
showInfo(_("Please enter some text first."))
else:
showInfo(_("The current note was deleted."))
return
self.fillCardList()
self.fillFieldList()
self.fieldChanged()
self.readField()
return True
# Cards & Preview
##########################################################################
def setupCards(self):
self.updatingCards = False
self.playedAudio = {}
f = self.form
if self.type == 0:
f.templateType.setText(
_("Templates that will be created:"))
elif self.type == 1:
f.templateType.setText(
_("Templates used by note:"))
else:
f.templateType.setText(
_("All templates:"))
# replace with more appropriate size hints
for e in ("cardQuestion", "cardAnswer"):
w = getattr(f, e)
idx = f.templateLayout.indexOf(w)
r = f.templateLayout.getItemPosition(idx)
f.templateLayout.removeWidget(w)
w.hide()
w.deleteLater()
w = ResizingTextEdit(self)
setattr(f, e, w)
f.templateLayout.addWidget(w, r[0], r[1])
c = self.connect
c(f.cardList, SIGNAL("activated(int)"), self.cardChanged)
c(f.editTemplates, SIGNAL("clicked()"), self.onEdit)
c(f.cardQuestion, SIGNAL("textChanged()"), self.formatChanged)
c(f.cardAnswer, SIGNAL("textChanged()"), self.formatChanged)
c(f.alignment, SIGNAL("activated(int)"), self.saveCard)
c(f.background, SIGNAL("clicked()"),
lambda w=f.background:\
self.chooseColour(w, "card"))
c(f.questionInAnswer, SIGNAL("clicked()"), self.saveCard)
c(f.allowEmptyAnswer, SIGNAL("clicked()"), self.saveCard)
c(f.typeAnswer, SIGNAL("activated(int)"), self.saveCard)
c(f.flipButton, SIGNAL("clicked()"), self.onFlip)
c(f.clozectx, SIGNAL("clicked()"), self.saveCard)
def linkClicked(url):
QDesktopServices.openUrl(QUrl(url))
f.preview.page().setLinkDelegationPolicy(
QWebPage.DelegateExternalLinks)
self.connect(f.preview,
SIGNAL("linkClicked(QUrl)"),
linkClicked)
f.alignment.addItems(alignmentLabels().values())
self.typeFieldNames = self.mm.fieldMap(self.model)
s = [_("Don't ask me to type in the answer")]
s += [_("Compare with field '%s'") % fi
for fi in self.typeFieldNames.keys()]
f.typeAnswer.insertItems(0, s)
def formatToScreen(self, fmt):
fmt = fmt.replace("}}<br>", "}}\n")
return fmt
def screenToFormat(self, fmt):
fmt = fmt.replace("}}\n", "}}<br>")
return fmt
def onEdit(self):
aqt.templates.Templates(self.mw, self.model, self)
self.reload()
def formatChanged(self):
if self.updatingCards:
return
text = unicode(self.form.cardQuestion.toPlainText())
self.card.template()['qfmt'] = self.screenToFormat(text)
text = unicode(self.form.cardAnswer.toPlainText())
self.card.template()['afmt'] = self.screenToFormat(text)
self.renderPreview()
def onFlip(self):
q = unicode(self.form.cardQuestion.toPlainText())
a = unicode(self.form.cardAnswer.toPlainText())
self.form.cardAnswer.setPlainText(q)
self.form.cardQuestion.setPlainText(a)
def readCard(self):
self.updatingCards = True
t = self.card.template()
f = self.form
f.background.setPalette(QPalette(QColor(t['bg'])))
f.cardQuestion.setPlainText(self.formatToScreen(t['qfmt']))
f.cardAnswer.setPlainText(self.formatToScreen(t['afmt']))
f.questionInAnswer.setChecked(t['hideQ'])
f.allowEmptyAnswer.setChecked(t['emptyAns'])
f.alignment.setCurrentIndex(t['align'])
if t['typeAns'] is None:
f.typeAnswer.setCurrentIndex(0)
else:
f.typeAnswer.setCurrentIndex(t['typeAns'] + 1)
# model-level, but there's nowhere else to put this
f.clozectx.setChecked(self.model['clozectx'])
self.updatingCards = False
def fillCardList(self):
self.form.cardList.clear()
cards = []
idx = 0
for n, c in enumerate(self.cards):
if c.ord == self.ord:
cards.append(_("%s (current)") % c.template()['name'])
idx = n
else:
cards.append(c.template()['name'])
self.form.cardList.addItems(cards)
self.form.cardList.setCurrentIndex(idx)
self.cardChanged(idx)
self.form.cardList.setFocus()
def cardChanged(self, idx):
self.card = self.cards[idx]
self.readCard()
self.renderPreview()
def saveCard(self):
if self.updatingCards:
return
t = self.card.template()
t['align'] = self.form.alignment.currentIndex()
t['bg'] = unicode(
self.form.background.palette().window().color().name())
t['hideQ'] = self.form.questionInAnswer.isChecked()
t['emptyAns'] = self.form.allowEmptyAnswer.isChecked()
idx = self.form.typeAnswer.currentIndex()
if not idx:
t['typeAns'] = None
else:
t['typeAns'] = idx-1
self.model['clozectx'] = self.form.clozectx.isChecked()
self.renderPreview()
def chooseColour(self, button, type="field"):
new = QColorDialog.getColor(button.palette().window().color(), self,
_("Choose Color"),
QColorDialog.DontUseNativeDialog)
if new.isValid():
button.setPalette(QPalette(new))
if type == "field":
self.saveField()
else:
self.saveCard()
def renderPreview(self):
c = self.card
styles = self.model['css']
styles += "\n.cloze { font-weight: bold; color: blue; }"
self.form.preview.setHtml(
('<html><head>%s</head><body class="%s">' %
(getBase(self.col), c.cssClass())) +
"<style>" + styles + "</style>" +
mungeQA(c.q(reload=True)) +
self.maybeTextInput() +
"<hr>" +
mungeQA(c.a())
+ "</body></html>")
clearAudioQueue()
if c.id not in self.playedAudio:
playFromText(c.q())
playFromText(c.a())
self.playedAudio[c.id] = True
def maybeTextInput(self):
if self.card.template()['typeAns'] is not None:
return "<center><input type=text></center>"
return ""
def accept(self):
self.reject()
def reject(self):
return QDialog.reject(self)
self.mm.save(self.model)
saveGeom(self, "CardLayout")
saveSplitter(self.form.splitter, "clayout")
self.mw.reset()
return QDialog.reject(self)
modified = False
self.mw.startProgress()
self.col.updateProgress(_("Applying changes..."))
reset=True
if len(self.fieldOrdinalUpdatedIds) > 0:
self.col.rebuildFieldOrdinals(self.model.id, self.fieldOrdinalUpdatedIds)
modified = True
if self.needFieldRebuild:
modified = True
if modified:
self.note.model.setModified()
self.col.flushMod()
if self.noteedit and self.noteedit.onChange:
self.noteedit.onChange("all")
reset=False
if reset:
self.mw.reset()
self.col.finishProgress()
QDialog.reject(self)
def onHelp(self):
openHelp("CardLayout")
# Fields
##########################################################################
def setupFields(self):
self.fieldOrdinalUpdatedIds = []
self.updatingFields = False
self.needFieldRebuild = False
c = self.connect; f = self.form
sc = SIGNAL("stateChanged(int)")
cl = SIGNAL("clicked()")
c(f.fieldAdd, cl, self.addField)
c(f.fieldDelete, cl, self.deleteField)
c(f.fieldUp, cl, self.moveFieldUp)
c(f.fieldDown, cl, self.moveFieldDown)
c(f.preserveWhitespace, sc, self.saveField)
c(f.fieldUnique, sc, self.saveField)
c(f.fieldRequired, sc, self.saveField)
c(f.sticky, sc, self.saveField)
c(f.fieldList, SIGNAL("currentRowChanged(int)"),
self.fieldChanged)
c(f.fieldName, SIGNAL("lostFocus()"),
self.saveField)
c(f.fontFamily, SIGNAL("currentFontChanged(QFont)"),
self.saveField)
c(f.fontSize, SIGNAL("valueChanged(int)"),
self.saveField)
c(f.fontSizeEdit, SIGNAL("valueChanged(int)"),
self.saveField)
w = self.form.fontColour
c(w, SIGNAL("clicked()"),
lambda w=w: self.chooseColour(w))
c(self.form.rtl,
SIGNAL("stateChanged(int)"),
self.saveField)
def fieldChanged(self):
row = self.form.fieldList.currentRow()
if row == -1:
row = 0
self.field = self.model['flds'][row]
self.readField()
self.enableFieldMoveButtons()
def readField(self):
fld = self.field
f = self.form
self.updatingFields = True
f.fieldName.setText(fld['name'])
f.fieldUnique.setChecked(fld['uniq'])
f.fieldRequired.setChecked(fld['req'])
f.fontFamily.setCurrentFont(QFont(fld['font']))
f.fontSize.setValue(fld['qsize'])
f.fontSizeEdit.setValue(fld['esize'])
f.fontColour.setPalette(QPalette(QColor(fld['qcol'])))
f.rtl.setChecked(fld['rtl'])
f.preserveWhitespace.setChecked(fld['pre'])
f.sticky.setChecked(fld['sticky'])
self.updatingFields = False
def saveField(self, *args):
self.needFieldRebuild = True
if self.updatingFields:
return
self.updatingFields = True
fld = self.field
# get name; we'll handle it last
name = unicode(self.form.fieldName.text())
if not name:
return
fld['uniq'] = self.form.fieldUnique.isChecked()
fld['req'] = self.form.fieldRequired.isChecked()
fld['font'] = unicode(
self.form.fontFamily.currentFont().family())
fld['qsize'] = self.form.fontSize.value()
fld['esize'] = self.form.fontSizeEdit.value()
fld['qcol'] = str(
self.form.fontColour.palette().window().color().name())
fld['rtl'] = self.form.rtl.isChecked()
fld['pre'] = self.form.preserveWhitespace.isChecked()
fld['sticky'] = self.form.sticky.isChecked()
self.updatingFields = False
if fld['name'] != name:
self.mm.renameField(self.model, fld, name)
# as the field name has changed, we have to regenerate cards
self.cards = self.col.previewCards(self.note, self.type)
self.cardChanged(0)
self.renderPreview()
self.fillFieldList()
def fillFieldList(self, row = None):
oldRow = self.form.fieldList.currentRow()
if oldRow == -1:
oldRow = 0
self.form.fieldList.clear()
n = 1
for field in self.model['flds']:
label = field['name']
item = QListWidgetItem(label)
self.form.fieldList.addItem(item)
n += 1
count = self.form.fieldList.count()
if row != None:
self.form.fieldList.setCurrentRow(row)
else:
while (count > 0 and oldRow > (count - 1)):
oldRow -= 1
self.form.fieldList.setCurrentRow(oldRow)
self.enableFieldMoveButtons()
def enableFieldMoveButtons(self):
row = self.form.fieldList.currentRow()
if row < 1:
self.form.fieldUp.setEnabled(False)
else:
self.form.fieldUp.setEnabled(True)
if row == -1 or row >= (self.form.fieldList.count() - 1):
self.form.fieldDown.setEnabled(False)
else:
self.form.fieldDown.setEnabled(True)
def addField(self):
f = self.mm.newField(self.model)
l = len(self.model['flds'])
f['name'] = _("Field %d") % l
self.mw.progress.start()
self.mm.addField(self.model, f)
self.mw.progress.finish()
self.reload()
self.form.fieldList.setCurrentRow(l)
self.form.fieldName.setFocus()
self.form.fieldName.selectAll()
def deleteField(self):
row = self.form.fieldList.currentRow()
if row == -1:
return
if len(self.model.fields) < 2:
showInfo(_("Please add a new field first."))
return
if askUser(_("Delete this field and its data from all notes?")):
self.mw.progress.start()
self.model.delField(self.field)
self.mw.progress.finish()
# need to update q/a format
self.reload()
def moveFieldUp(self):
row = self.form.fieldList.currentRow()
if row == -1:
return
if row == 0:
return
self.mw.progress.start()
self.model.moveField(self.field, row-1)
self.mw.progress.finish()
self.form.fieldList.setCurrentRow(row-1)
self.reload()
def moveFieldDown(self):
row = self.form.fieldList.currentRow()
if row == -1:
return
if row == len(self.model.fields) - 1:
return
self.mw.progress.start()
self.model.moveField(self.field, row+1)
self.mw.progress.finish()
self.form.fieldList.setCurrentRow(row+1)
self.reload()

View file

@ -51,7 +51,7 @@ Error was:<pre>%s</pre>""")
self.form.table, SIGNAL("currentCellChanged(int,int,int,int)"), self.form.table, SIGNAL("currentCellChanged(int,int,int,int)"),
self.onCellChanged) self.onCellChanged)
self.form.table.verticalHeader().setDefaultSectionSize( self.form.table.verticalHeader().setDefaultSectionSize(
self.parent.config['editLineSize']) self.parent.pm.profile['editLineSize'])
self.connect(self.form.search, SIGNAL("textChanged(QString)"), self.connect(self.form.search, SIGNAL("textChanged(QString)"),
self.limit) self.limit)
@ -222,7 +222,7 @@ Error was:<pre>%s</pre>""")
tit = tit[0:40] tit = tit[0:40]
if self.type == 0: if self.type == 0:
# col # col
dd = self.parent.config['documentDir'] dd = self.parent.pm.profile['documentDir']
p = os.path.join(dd, tit + ".anki") p = os.path.join(dd, tit + ".anki")
if os.path.exists(p): if os.path.exists(p):
tit += "%d" % time.time() tit += "%d" % time.time()

View file

@ -5,7 +5,7 @@
from aqt.qt import * from aqt.qt import *
import aqt, simplejson import aqt, simplejson
from anki.utils import ids2str from anki.utils import ids2str
from aqt.utils import showInfo, showWarning from aqt.utils import showInfo, showWarning, openHelp
# Configuration editing # Configuration editing
########################################################################## ##########################################################################
@ -24,7 +24,7 @@ class GroupConf(QDialog):
self.setup() self.setup()
self.connect(self.form.buttonBox, self.connect(self.form.buttonBox,
SIGNAL("helpRequested()"), SIGNAL("helpRequested()"),
lambda: aqt.openHelp("GroupOptions")) lambda: openHelp("GroupOptions"))
self.connect(self.form.buttonBox.button(QDialogButtonBox.RestoreDefaults), self.connect(self.form.buttonBox.button(QDialogButtonBox.RestoreDefaults),
SIGNAL("clicked()"), SIGNAL("clicked()"),
self.onRestore) self.onRestore)

View file

@ -4,7 +4,7 @@
from aqt.qt import * from aqt.qt import *
import aqt import aqt
from aqt.utils import showInfo, getOnlyText from aqt.utils import showInfo, getOnlyText, openHelp
COLNAME = 0 COLNAME = 0
COLOPTS = 1 COLOPTS = 1
@ -79,7 +79,7 @@ class Groups(QDialog):
button(f.delete_2, self.onDelete) button(f.delete_2, self.onDelete)
self.connect(self.form.buttonBox, self.connect(self.form.buttonBox,
SIGNAL("helpRequested()"), SIGNAL("helpRequested()"),
lambda: aqt.openHelp("Groups")) lambda: openHelp("Groups"))
def onSelectAll(self): def onSelectAll(self):
for i in self.items: for i in self.items:

View file

@ -65,7 +65,7 @@ class UpdateMap(QDialog):
self.exec_() self.exec_()
def helpRequested(self): def helpRequested(self):
aqt.openHelp("FileImport") openHelp("FileImport")
def accept(self): def accept(self):
self.updateKey = ( self.updateKey = (
@ -311,4 +311,4 @@ you can enter it here. Use \\t to represent tab."""),
QDialog.reject(self) QDialog.reject(self)
def helpRequested(self): def helpRequested(self):
aqt.openHelp("FileImport") openHelp("FileImport")

View file

@ -191,8 +191,10 @@ Are you sure?"""):
# maybe sync # maybe sync
self.onSync() self.onSync()
# then load collection and launch into the deck browser # then load collection and launch into the deck browser
print "fixme: safeguard against multiple instances"
self.col = Collection(self.pm.collectionPath()) self.col = Collection(self.pm.collectionPath())
self.moveToState("overview") # skip the reset step; open overview directly
self.moveToState("review")
def unloadProfile(self): def unloadProfile(self):
self.col = None self.col = None
@ -633,8 +635,7 @@ Debug info:\n%s""") % traceback.format_exc(), help="DeckErrors")
def onCardLayout(self): def onCardLayout(self):
from aqt.clayout import CardLayout from aqt.clayout import CardLayout
CardLayout(self, self.reviewer.card.note(), type=1, CardLayout(self, self.reviewer.card.note(), ord=self.reviewer.card.ord)
ord=self.reviewer.card.ord)
def onDeckOpts(self): def onDeckOpts(self):
import aqt.deckopts import aqt.deckopts
@ -797,7 +798,7 @@ Please choose a new deck name:"""))
self.form.actionDelete.setEnabled(True) self.form.actionDelete.setEnabled(True)
self.form.actionBuryNote.setEnabled(True) self.form.actionBuryNote.setEnabled(True)
self.form.actionEditCurrent.setEnabled(True) self.form.actionEditCurrent.setEnabled(True)
self.form.actionEditdeck.setEnabled(True) self.form.actionBrowse.setEnabled(True)
self.updateMarkAction() self.updateMarkAction()
runHook("enableCardMenuItems") runHook("enableCardMenuItems")

View file

@ -196,4 +196,4 @@ class AddModel(QDialog):
QDialog.accept(self) QDialog.accept(self)
def onHelp(self): def onHelp(self):
aqt.openHelp("AddModel") openHelp("AddModel")

View file

@ -15,7 +15,7 @@ class Models(QDialog):
self.form = aqt.forms.models.Ui_Dialog() self.form = aqt.forms.models.Ui_Dialog()
self.form.setupUi(self) self.form.setupUi(self)
self.connect(self.form.buttonBox, SIGNAL("helpRequested()"), self.connect(self.form.buttonBox, SIGNAL("helpRequested()"),
lambda: aqt.openHelp("Models")) lambda: openHelp("Models"))
self.setupModels() self.setupModels()
self.exec_() self.exec_()

View file

@ -6,7 +6,7 @@ import simplejson
from aqt.qt import * from aqt.qt import *
from anki.consts import NEW_CARDS_RANDOM from anki.consts import NEW_CARDS_RANDOM
from anki.hooks import addHook from anki.hooks import addHook
from aqt.utils import limitedCount, showInfo from aqt.utils import showInfo
class Overview(object): class Overview(object):
"Deck overview." "Deck overview."
@ -57,9 +57,6 @@ class Overview(object):
############################################################ ############################################################
def _renderPage(self): def _renderPage(self):
css = self.mw.sharedCSS + self._overviewCSS
fc = self._ovForecast()
tbl = self._overviewTable()
but = self.mw.button but = self.mw.button
deck = self.mw.col.decks.current() deck = self.mw.col.decks.current()
sid = deck.get("sharedFrom") sid = deck.get("sharedFrom")
@ -67,85 +64,67 @@ class Overview(object):
shareLink = '<a class=smallLink href="review">Reviews and Updates</a>' shareLink = '<a class=smallLink href="review">Reviews and Updates</a>'
else: else:
shareLink = "" shareLink = ""
header = "" print self._body % dict(
self.web.stdHtml(self._overviewBody % dict(
title=_("Overview"),
table=tbl,
fcsub=_("Reviews over next two weeks"),
deck=deck['name'], deck=deck['name'],
shareLink=shareLink, shareLink=shareLink,
desc="", desc=self._desc(deck),
header=header, table=self._table())
fcdata=fc, self.web.stdHtml(self._body % dict(
), css) deck=deck['name'],
shareLink=shareLink,
desc=self._desc(deck),
table=self._table()
), self.mw.sharedCSS + self._css)
_overviewBody = """ def _desc(self, deck):
%(header)s desc = deck.get("desc", "")
if not desc:
return ""
if len(desc) < 160:
return '<div class="descfont description">%s</div>' % desc
else:
return '''
<div class="descfont description descmid" id=shortdesc>%s\
<a href=# onclick="$('shortdesc').hide();$('fulldesc').show();">...More</a></div>
<div class="descfont description descmid" id=fulldesc>%s</div>''' % (
desc[:160], desc)
def _table(self):
counts = self.mw.col.sched.repCounts()
finished = not sum(counts)
but = self.mw.button
if finished:
return '<div class=fin style="white-space: pre-wrap;">%s</div>' % (
self.mw.col.sched.finishedMsg())
else:
return '''
<table width=300 cellpadding=5>
<tr><td align=center valign=top>
<table cellspacing=5>
<tr><td>%s:</td><td><b><font color=#00a>%s</font></b></td></tr>
<tr><td>%s:</td><td><b><font color=#a00>%s</font></b></td></tr>
<tr><td>%s:</td><td><b><font color=#0a0>%s</font></b></td></tr>
</table>
</td><td>%s</td></tr></table>''' % (_("New"), counts[0],
_("In Learning"), counts[1],
_("To Review"), counts[2],
but("study", _("Study")))
_body = """
<center> <center>
<h3>%(deck)s</h3> <h3>%(deck)s</h3>
%(shareLink)s %(shareLink)s
%(desc)s %(desc)s
<p> <p>
<div id="placeholder" style="width:350px; height:100px;"></div> %(table)s
<span class=sub>%(fcsub)s</span>
<p>
</center> </center>
<script>
$("#study").focus();
$(function () {
var d = %(fcdata)s;
if (typeof(d) !== "string") {
$.plot($("#placeholder"), [
{ data: d, bars: { show: true, barWidth: 0.8 }, color: "#0c0" }
], {
xaxis: { ticks: [[0.4, "Today"]] },
yaxis: { tickDecimals: 0 }
});
} else {
$("#placeholder").text(d);
$(".sub").hide();
}
});
</script>
""" """
_overviewCSS = """ _css = """
.due { text-align: right; } .smallLink { font-size: 10px; }
.new { text-align: right; }
.sub { font-size: 80%; color: #555; }
.smallLink { font-size: 12px; }
h3 { margin-bottom: 0; } h3 { margin-bottom: 0; }
.fin { font-size: 12px; font-weight: normal; }
td { font-size: 14px; }
""" """
def _overviewTable(self):
return ""
but = self.mw.button
buf = "<table cellspacing=0 cellpadding=3 width=400>"
buf += "<tr><th></th><th align=right>%s</th>" % _("Due")
buf += "<th align=right>%s</th><th></th></tr>" % _("New")
line = "<tr><td><b>%s</b></td><td class=due>%s</td>"
line += "<td class=new>%s</td><td>%s</td></tr>"
buf += line % (
"<a href=chgrp>%s</a>" % _("Selected Groups"),
counts[0], counts[1],
but("study", _("Study"), _("s"), "gbut", id="study") +
but("cram", _("Cram"), "c"))
buf += line % (
_("Whole Deck"),
counts[2], counts[3],
but("opts", _("Study Options")))
buf += "</table>"
return buf
def _ovOpts(self):
return ""
# Data
##########################################################################
def _ovForecast(self):
fc = self.mw.col.sched.dueForecast(14)
if not sum(fc):
return "'%s'" % _('No cards due in next two weeks')
return simplejson.dumps(tuple(enumerate(fc)))

View file

@ -13,12 +13,12 @@ class Preferences(QDialog):
def __init__(self, mw): def __init__(self, mw):
QDialog.__init__(self, mw, Qt.Window) QDialog.__init__(self, mw, Qt.Window)
self.mw = mw self.mw = mw
self.config = mw.config self.config = mw.pm.config
self.form = aqt.forms.preferences.Ui_Preferences() self.form = aqt.forms.preferences.Ui_Preferences()
self.form.setupUi(self) self.form.setupUi(self)
self.needDeckClose = False self.needDeckClose = False
self.connect(self.form.buttonBox, SIGNAL("helpRequested()"), self.connect(self.form.buttonBox, SIGNAL("helpRequested()"),
lambda: aqt.openHelp("Preferences")) lambda: openHelp("Preferences"))
self.setupLang() self.setupLang()
self.setupNetwork() self.setupNetwork()
self.setupBackup() self.setupBackup()

View file

@ -89,36 +89,18 @@ class Reviewer(object):
########################################################################## ##########################################################################
_revHtml = """ _revHtml = """
<table width=100%% height=100%%><tr valign=%(align)s><td> <div id=qa></div>
<div id=q></div>
<hr class=inv id=midhr>
<div id=a></div>
<div id=filler></div>
</td></tr></table>
<a id=ansbut class="ansbut ansbutbig" href=ans onclick="_showans();">
<div class=ansbuttxt>%(showans)s</div>
</a>
<div id=easebuts>
</div>
<script> <script>
var ankiPlatform = "desktop"; var ankiPlatform = "desktop";
var hideq; var hideq;
var ans; var ans;
var typeans; var typeans;
function _updateQA (qa) { function _updateQA (q) {
hideq = qa[4];
location.hash = ""; location.hash = "";
$("#q").html(qa[0]); $("#qa").html(q[0]);
if (hideq) { $("#qa:first").css("height", "100%%");
ans = qa[1]; //$("#easebuts").html(q[1]).addClass("inv");
$("#a").html(""); //$("#ansbut").show();
} else {
$("#a").html(qa[1]).addClass("inv");
}
$("#midhr").addClass("inv");
$("#easebuts").html(qa[2]).addClass("inv");
$("#ansbut").show();
$("body").removeClass().addClass(qa[3]);
typeans = document.getElementById("typeans"); typeans = document.getElementById("typeans");
if (typeans) { if (typeans) {
typeans.focus(); typeans.focus();
@ -128,7 +110,8 @@ function _updateQA (qa) {
onQuestion(); onQuestion();
} }
}; };
function _showans () { function _showans (a) {
$("#qa").html(a);
if (typeans) { if (typeans) {
py.link("typeans:"+typeans.value); py.link("typeans:"+typeans.value);
} }
@ -139,7 +122,7 @@ function _showans () {
} else { } else {
location.hash = "a"; location.hash = "a";
} }
$("#ansbut").hide(); //$("#ansbut").hide();
$("#defease").focus(); $("#defease").focus();
// user hook // user hook
if (typeof(onAnswer) === "function") { if (typeof(onAnswer) === "function") {
@ -167,8 +150,8 @@ $(".ansbut").focus();
def _initWeb(self): def _initWeb(self):
self.web.stdHtml(self._revHtml % dict( self.web.stdHtml(self._revHtml % dict(
align="middle" if self.mw.config['centerQA'] else "top",
showans=_("Show Answer")), self._styles(), showans=_("Show Answer")), self._styles(),
bodyID="card",
loadCB=lambda x: self._showQuestion()) loadCB=lambda x: self._showQuestion())
# Showing the question (and preparing answer) # Showing the question (and preparing answer)
@ -181,15 +164,14 @@ $(".ansbut").focus();
c = self.card c = self.card
q = c.q() q = c.q()
a = c.a() a = c.a()
if self.mw.config['autoplaySounds']: if self.mw.pm.profile['autoplay']:
playFromText(q) playFromText(q)
# render # render
esc = self.mw.col.media.escapeImages esc = self.mw.col.media.escapeImages
q=esc(mungeQA(q)) + self.typeAnsInput() q=esc(mungeQA(q)) + self.typeAnsInput()
a=esc(mungeQA(a)) a=esc(mungeQA(a))
self.web.eval("_updateQA(%s);" % simplejson.dumps( self.web.eval("_updateQA(%s);" % simplejson.dumps(
[q, a, self._answerButtons(), c.cssClass(), (q, self._answerButtons())))
c.template()['hideQ']]))
runHook('showQuestion') runHook('showQuestion')
# Showing the answer # Showing the answer
@ -199,7 +181,7 @@ $(".ansbut").focus();
self.state = "answer" self.state = "answer"
c = self.card c = self.card
a = c.a() a = c.a()
if self.mw.config['autoplaySounds']: if self.mw.pm.profile['autoplay']:
playFromText(a) playFromText(a)
# render # render
runHook('showAnswer') runHook('showAnswer')
@ -238,7 +220,7 @@ $(".ansbut").focus();
return buf return buf
def _buttonTime(self, i, green): def _buttonTime(self, i, green):
if self.mw.config['suppressEstimates']: if self.mw.pm.profile['showDueTimes']:
return "" return ""
txt = self.mw.col.sched.nextIvlStr(self.card, i+1, True) txt = self.mw.col.sched.nextIvlStr(self.card, i+1, True)
if i == 0: if i == 0:
@ -335,9 +317,7 @@ div.ansbuttxt {
position: relative; top: 25%; position: relative; top: 25%;
} }
div#q, div#a { body { margin:1em; }
margin: 0px;
}
#easebuts { #easebuts {
bottom: 1em; bottom: 1em;
@ -373,7 +353,6 @@ div#filler {
def _styles(self): def _styles(self):
css = self.mw.sharedCSS css = self.mw.sharedCSS
css += self.mw.col.models.css()
css += self._css css += self._css
return css return css
@ -385,10 +364,10 @@ div#filler {
def typeAns(self): def typeAns(self):
"None if answer typing disabled." "None if answer typing disabled."
return self.card.template()['typeAns'] self.card.template()['typeAns']
def typeAnsInput(self): def typeAnsInput(self):
if self.typeAns() is None: if not self.typeAns():
return "" return ""
return """ return """
<center> <center>
@ -412,6 +391,8 @@ div#filler {
self.web.eval("_processTyped(%s);" % simplejson.dumps(res)) self.web.eval("_processTyped(%s);" % simplejson.dumps(res))
def getFont(self): def getFont(self):
print "fix getFont()"
return ("arial", 20)
f = self.card.model().fields[self.typeAns()] f = self.card.model().fields[self.typeAns()]
return (f['font'], f['qsize']) return (f['font'], f['qsize'])
@ -549,7 +530,7 @@ div#filler {
addWgt(vertSep()) addWgt(vertSep())
class QClickableProgress(QProgressBar): class QClickableProgress(QProgressBar):
def mouseReleaseEvent(self, evt): def mouseReleaseEvent(self, evt):
aqt.openHelp("ProgressBars") openHelp("ProgressBars")
progressBarSize = (50, 14) progressBarSize = (50, 14)
self.progressBar = QClickableProgress() self.progressBar = QClickableProgress()
self.progressBar.setFixedSize(*progressBarSize) self.progressBar.setFixedSize(*progressBarSize)
@ -561,6 +542,7 @@ div#filler {
addWgt(self.progressBar, 0) addWgt(self.progressBar, 0)
def _showStatus(self): def _showStatus(self):
return
self._showStatusWidgets(True) self._showStatusWidgets(True)
self._updateRemaining() self._updateRemaining()
self._updateProgress() self._updateProgress()
@ -569,6 +551,7 @@ div#filler {
self._showStatusWidgets(False) self._showStatusWidgets(False)
def _showStatusWidgets(self, shown=True): def _showStatusWidgets(self, shown=True):
return
for w in self._statusWidgets: for w in self._statusWidgets:
w.setShown(shown) w.setShown(shown)
self.mw.form.statusbar.hideOrShow() self.mw.form.statusbar.hideOrShow()

View file

@ -26,7 +26,7 @@ class StudyOptions(QDialog):
0, c.revCardOrderLabels().values()) 0, c.revCardOrderLabels().values())
self.connect(self.form.buttonBox, self.connect(self.form.buttonBox,
SIGNAL("helpRequested()"), SIGNAL("helpRequested()"),
lambda: aqt.openHelp("StudyOptions")) lambda: openHelp("StudyOptions"))
def load(self): def load(self):
f = self.form f = self.form

View file

@ -25,8 +25,8 @@ class SyncManager(object):
# vet input # vet input
if interactive: if interactive:
self.ensureSyncParams() self.ensureSyncParams()
u=self.config['syncUsername'] u=self.pm.profile['syncUsername']
p=self.config['syncPassword'] p=self.pm.profile['syncPassword']
if not u or not p: if not u or not p:
return return
if self.deck: if self.deck:
@ -35,7 +35,7 @@ class SyncManager(object):
return return
if self.deck and not self.deck.syncName: if self.deck and not self.deck.syncName:
if interactive: if interactive:
if (not self.config['mediaLocation'] if (not self.pm.profile['mediaLocation']
and self.deck.db.scalar("select 1 from media limit 1")): and self.deck.db.scalar("select 1 from media limit 1")):
showInfo(_("""\ showInfo(_("""\
Syncing sounds and images requires a free file synchronization service like \ Syncing sounds and images requires a free file synchronization service like \
@ -105,7 +105,7 @@ will sync automatically from then on."""))
def decksToSync(self): def decksToSync(self):
ok = [] ok = []
for d in self.config['recentDeckPaths']: for d in self.pm.profile['recentDeckPaths']:
if os.path.exists(d): if os.path.exists(d):
ok.append(d) ok.append(d)
return ok return ok
@ -159,7 +159,7 @@ Are you sure?""" % deckName),
elif self.loadAfterSync and self.deckPath: elif self.loadAfterSync and self.deckPath:
if self.loadAfterSync == 2: if self.loadAfterSync == 2:
name = re.sub("[<>]", "", self.syncName) name = re.sub("[<>]", "", self.syncName)
p = os.path.join(self.config['documentDir'], name + ".anki") p = os.path.join(self.pm.profile['documentDir'], name + ".anki")
shutil.copy2(self.deckPath, p) shutil.copy2(self.deckPath, p)
self.deckPath = p self.deckPath = p
# since we've moved the deck, we have to set sync path # since we've moved the deck, we have to set sync path
@ -195,7 +195,7 @@ Are you sure?""" % deckName),
self.syncName = name self.syncName = name
if name: if name:
# name chosen # name chosen
p = os.path.join(self.config['documentDir'], name + ".anki") p = os.path.join(self.pm.profile['documentDir'], name + ".anki")
if os.path.exists(p): if os.path.exists(p):
d = askUserDialog(_("""\ d = askUserDialog(_("""\
This deck already exists on your computer. Overwrite the local copy?"""), This deck already exists on your computer. Overwrite the local copy?"""),
@ -237,7 +237,7 @@ This deck already exists on your computer. Overwrite the local copy?"""),
self.setStatus("") self.setStatus("")
def badUserPass(self): def badUserPass(self):
aqt.preferences.Preferences(self, self.config).dialog.tabWidget.\ aqt.preferences.Preferences(self, self.pm.profile).dialog.tabWidget.\
setCurrentIndex(1) setCurrentIndex(1)
def openSyncProgress(self): def openSyncProgress(self):
@ -282,7 +282,7 @@ This deck already exists on your computer. Overwrite the local copy?"""),
self.updateProgress(label=s % (val / 1024)) self.updateProgress(label=s % (val / 1024))
def ensureSyncParams(self): def ensureSyncParams(self):
if not self.config['syncUsername'] or not self.config['syncPassword']: if not self.pm.profile['syncUsername'] or not self.pm.profile['syncPassword']:
d = QDialog(self) d = QDialog(self)
vbox = QVBoxLayout() vbox = QVBoxLayout()
l = QLabel(_( l = QLabel(_(
@ -310,8 +310,8 @@ This deck already exists on your computer. Overwrite the local copy?"""),
vbox.addWidget(bb) vbox.addWidget(bb)
d.setLayout(vbox) d.setLayout(vbox)
d.exec_() d.exec_()
self.config['syncUsername'] = unicode(user.text()) self.pm.profile['syncUsername'] = unicode(user.text())
self.config['syncPassword'] = unicode(passwd.text()) self.pm.profile['syncPassword'] = unicode(passwd.text())
# Synchronising a deck with a public server # Synchronising a deck with a public server

View file

@ -17,7 +17,7 @@ class LatestVersionFinder(QThread):
print "autoupdate" print "autoupdate"
return return
self.main = main self.main = main
self.config = main.config self.config = main.pm.profile
plat=sys.platform plat=sys.platform
pver=platform.platform() pver=platform.platform()
d = {"ver": aqt.appVersion, d = {"ver": aqt.appVersion,

View file

@ -13,7 +13,7 @@ def openHelp(name):
name = name[0] + ".html#" + name[1] name = name[0] + ".html#" + name[1]
else: else:
name = name + ".html" name = name + ".html"
QDesktopServices.openUrl(QUrl(appHelpSite + name)) QDesktopServices.openUrl(QUrl(aqt.appHelpSite + name))
def openLink(link): def openLink(link):
QDesktopServices.openUrl(QUrl(link)) QDesktopServices.openUrl(QUrl(link))
@ -44,7 +44,7 @@ def showInfo(text, parent=None, help="", type="info"):
b.setDefault(True) b.setDefault(True)
if help: if help:
b = mb.addButton(QMessageBox.Help) b = mb.addButton(QMessageBox.Help)
b.connect(b, SIGNAL("clicked()"), lambda: aqt.openHelp(help)) b.connect(b, SIGNAL("clicked()"), lambda: openHelp(help))
b.setAutoDefault(False) b.setAutoDefault(False)
return mb.exec_() return mb.exec_()
@ -84,7 +84,8 @@ def askUser(text, parent=None, help="", defaultno=False):
r = QMessageBox.question(parent, "Anki", text, sb, r = QMessageBox.question(parent, "Anki", text, sb,
default) default)
if r == QMessageBox.Help: if r == QMessageBox.Help:
aqt.openHelp(help)
openHelp(help)
else: else:
break break
return r == QMessageBox.Yes return r == QMessageBox.Yes
@ -115,7 +116,7 @@ class ButtonedDialog(QMessageBox):
but = self.clickedButton().text() but = self.clickedButton().text()
if but == "Help": if but == "Help":
# FIXME stop dialog closing? # FIXME stop dialog closing?
aqt.openHelp(self.help) openHelp(self.help)
return self.clickedButton().text() return self.clickedButton().text()
def setDefault(self, idx): def setDefault(self, idx):
@ -166,7 +167,7 @@ class GetTextDialog(QDialog):
return QDialog.reject(self) return QDialog.reject(self)
def helpRequested(self): def helpRequested(self):
aqt.openHelp(self.help) openHelp(self.help)
def getText(prompt, parent=None, help=None, edit=None, default=u"", title="Anki"): def getText(prompt, parent=None, help=None, edit=None, default=u"", title="Anki"):
if not parent: if not parent:
@ -347,11 +348,6 @@ def maybeHideClose(bbox):
if b: if b:
bbox.removeButton(b) bbox.removeButton(b)
def limitedCount(count):
if count >= 1000:
return "1000+"
return str(count)
# Tooltips # Tooltips
###################################################################### ######################################################################

View file

@ -83,13 +83,13 @@ class AnkiWebView(QWebView):
if loadCB: if loadCB:
self._loadFinishedCB = loadCB self._loadFinishedCB = loadCB
QWebView.setHtml(self, html) QWebView.setHtml(self, html)
def stdHtml(self, body, css="", bodyClass="", loadCB=None): def stdHtml(self, body, css="", bodyID="", loadCB=None):
self.setHtml(""" self.setHtml("""
<html><head><style>%s</style> <html><head><style>%s</style>
<script>%s</script> <script>%s</script>
</head> </head>
<body class="%s">%s</body></html>""" % ( <body id="%s">%s</body></html>""" % (
css, anki.js.all, bodyClass, body), loadCB) css, anki.js.all, bodyID, body), loadCB)
# ensure we're focused # ensure we're focused
self.setFocus() self.setFocus()
def setBridge(self, bridge): def setBridge(self, bridge):

View file

@ -6,546 +6,152 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>759</width> <width>1311</width>
<height>560</height> <height>658</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string/> <string/>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_5"> <widget class="QWidget" name="">
<item> <property name="geometry">
<widget class="QSplitter" name="splitter"> <rect>
<property name="orientation"> <x>20</x>
<enum>Qt::Horizontal</enum> <y>120</y>
</property> <width>360</width>
<property name="childrenCollapsible"> <height>366</height>
<bool>false</bool> </rect>
</property> </property>
<widget class="QWidget" name="layoutWidget"> <layout class="QGridLayout" name="templateLayout">
<layout class="QVBoxLayout" name="verticalLayout_4"> <property name="verticalSpacing">
<item> <number>6</number>
<widget class="QTabWidget" name="tabWidget"> </property>
<property name="sizePolicy"> <item row="1" column="1">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <widget class="QTextEdit" name="cardQuestion">
<horstretch>2</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Appearance</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="templateLayout">
<property name="verticalSpacing">
<number>6</number>
</property>
<item row="3" column="1">
<widget class="QTextEdit" name="cardQuestion">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>2</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="tabChangesFocus">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QTextEdit" name="cardAnswer">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="tabChangesFocus">
<bool>true</bool>
</property>
<property name="acceptRichText">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0" rowspan="2">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QLabel" name="label_14">
<property name="text">
<string>Question</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="flipButton">
<property name="text">
<string>Flip</string>
</property>
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/icons/multisynk.png</normaloff>:/icons/multisynk.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_15">
<property name="text">
<string>Answer</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Alignment</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="alignment"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Background</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QPushButton" name="background">
<property name="text">
<string/>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="templateType">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QComboBox" name="cardList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="editTemplates">
<property name="text">
<string>&amp;Manage...</string>
</property>
<property name="shortcut">
<string>Ctrl+M</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QComboBox" name="typeAnswer"/>
</item>
<item>
<widget class="QCheckBox" name="questionInAnswer">
<property name="text">
<string>Hide the question when showing answer</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="allowEmptyAnswer">
<property name="text">
<string>Add cards even if answer is blank</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="clozectx">
<property name="text">
<string>Include context in cloze answers</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Fields</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QListWidget" name="fieldList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>60</height>
</size>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QPushButton" name="fieldAdd">
<property name="text">
<string>&amp;Add</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="fieldUp">
<property name="toolTip">
<string>Move selected field up</string>
</property>
<property name="text">
<string>&amp;Up</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="fieldDown">
<property name="toolTip">
<string>Move selected field down</string>
</property>
<property name="text">
<string>Dow&amp;n</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="fieldDelete">
<property name="text">
<string>&amp;Delete</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="_2">
<item row="0" column="1">
<widget class="QLineEdit" name="fieldName"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Name</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Font</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Size</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Color</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QFontComboBox" name="fontFamily">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="fontColour">
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="text">
<string/>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Reviewing</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="fontSize">
<property name="minimum">
<number>5</number>
</property>
<property name="maximum">
<number>300</number>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Editing</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QSpinBox" name="fontSizeEdit">
<property name="minimum">
<number>5</number>
</property>
<property name="maximum">
<number>300</number>
</property>
</widget>
</item>
<item row="0" column="5">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>1</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Options</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QCheckBox" name="rtl">
<property name="text">
<string>Reverse text direction (RTL)</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="fieldRequired">
<property name="text">
<string>Require text in field</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="fieldUnique">
<property name="text">
<string>Prevent duplicates</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QCheckBox" name="preserveWhitespace">
<property name="text">
<string>Preserve whitespace</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="sticky">
<property name="text">
<string>Keep previous input when adding cards</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close|QDialogButtonBox::Help</set>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="previewGroup">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>1</horstretch> <horstretch>2</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="title"> <property name="minimumSize">
<string>Preview</string> <size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="tabChangesFocus">
<bool>true</bool>
</property> </property>
<layout class="QVBoxLayout" name="_3">
<property name="margin">
<number>6</number>
</property>
<item>
<widget class="QWebView" name="preview">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="url">
<url>
<string>about:blank</string>
</url>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</widget> </item>
</item> <item row="2" column="1">
</layout> <widget class="QTextEdit" name="cardAnswer">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="tabChangesFocus">
<bool>true</bool>
</property>
<property name="acceptRichText">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0" rowspan="2">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QLabel" name="label_14">
<property name="text">
<string>Question</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_15">
<property name="text">
<string>Answer</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QComboBox" name="typeAnswer">
<property name="geometry">
<rect>
<x>20</x>
<y>500</y>
<width>366</width>
<height>26</height>
</rect>
</property>
</widget>
<widget class="QCheckBox" name="clozectx">
<property name="geometry">
<rect>
<x>20</x>
<y>540</y>
<width>371</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>Include context in cloze answers</string>
</property>
</widget>
<widget class="QWebView" name="preview">
<property name="geometry">
<rect>
<x>450</x>
<y>90</y>
<width>308</width>
<height>499</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="url">
<url>
<string>about:blank</string>
</url>
</property>
</widget>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>
@ -555,70 +161,11 @@
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<tabstops> <tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>cardList</tabstop>
<tabstop>editTemplates</tabstop>
<tabstop>cardQuestion</tabstop> <tabstop>cardQuestion</tabstop>
<tabstop>flipButton</tabstop>
<tabstop>cardAnswer</tabstop> <tabstop>cardAnswer</tabstop>
<tabstop>alignment</tabstop>
<tabstop>background</tabstop>
<tabstop>typeAnswer</tabstop>
<tabstop>questionInAnswer</tabstop>
<tabstop>allowEmptyAnswer</tabstop>
<tabstop>clozectx</tabstop>
<tabstop>buttonBox</tabstop>
<tabstop>fieldList</tabstop>
<tabstop>fieldAdd</tabstop>
<tabstop>fieldUp</tabstop>
<tabstop>fieldDown</tabstop>
<tabstop>fieldDelete</tabstop>
<tabstop>fieldName</tabstop>
<tabstop>fontFamily</tabstop>
<tabstop>fontSize</tabstop>
<tabstop>fontSizeEdit</tabstop>
<tabstop>fontColour</tabstop>
<tabstop>fieldUnique</tabstop>
<tabstop>fieldRequired</tabstop>
<tabstop>sticky</tabstop>
<tabstop>preserveWhitespace</tabstop>
<tabstop>rtl</tabstop>
</tabstops> </tabstops>
<resources> <resources>
<include location="icons.qrc"/> <include location="icons.qrc"/>
</resources> </resources>
<connections> <connections/>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui> </ui>

243
designer/fields.ui Normal file
View file

@ -0,0 +1,243 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>372</width>
<height>340</height>
</rect>
</property>
<property name="windowTitle">
<string>Fields</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QListWidget" name="fieldList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>60</height>
</size>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QPushButton" name="fieldAdd">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/icons/list-add.png</normaloff>:/icons/list-add.png</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="fieldDelete">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/icons/editdelete.png</normaloff>:/icons/editdelete.png</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="fieldUp">
<property name="toolTip">
<string>Move selected field up</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/icons/arrow-up.png</normaloff>:/icons/arrow-up.png</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="fieldDown">
<property name="toolTip">
<string>Move selected field down</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/icons/arrow-down.png</normaloff>:/icons/arrow-down.png</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="_2">
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="fieldName"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Name</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Font</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QFontComboBox" name="fontFamily">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Options</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="rtl">
<property name="text">
<string>Reverse text direction (RTL)</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QSpinBox" name="fontSize">
<property name="minimum">
<number>5</number>
</property>
<property name="maximum">
<number>300</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="sticky">
<property name="text">
<string>Remember last input</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close|QDialogButtonBox::Help</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>fieldList</tabstop>
<tabstop>fieldAdd</tabstop>
<tabstop>fieldDelete</tabstop>
<tabstop>fieldUp</tabstop>
<tabstop>fieldDown</tabstop>
<tabstop>fieldName</tabstop>
<tabstop>fontFamily</tabstop>
<tabstop>fontSize</tabstop>
<tabstop>sticky</tabstop>
<tabstop>rtl</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources>
<include location="icons.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -1,6 +1,9 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>icons/arrow-up.png</file>
<file>icons/arrow-down.png</file>
<file>icons/blue.png</file> <file>icons/blue.png</file>
<file>icons/gears.png</file>
<file>icons/both.png</file> <file>icons/both.png</file>
<file>icons/green.png</file> <file>icons/green.png</file>
<file>icons/clock-icon.png</file> <file>icons/clock-icon.png</file>

BIN
designer/icons/gears.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 701 B

82
designer/preview.ui Normal file
View file

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>335</width>
<height>282</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Front Preview</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QWebView" name="front">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="url">
<url>
<string>about:blank</string>
</url>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Back Preview</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QWebView" name="back">
<property name="url">
<url>
<string>about:blank</string>
</url>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QWebView</class>
<extends>QWidget</extends>
<header>QtWebKit/QWebView</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

68
designer/template.ui Normal file
View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>279</width>
<height>251</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Front Template</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QTextEdit" name="front"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>10</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Back Template</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QTextEdit" name="back"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="icons.qrc"/>
</resources>
<connections/>
</ui>