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

Conflicts:
	ankiqt/locale/ankiqt_sv_SE.po
This commit is contained in:
Susanna Björverud 2009-03-25 11:02:00 +01:00
commit 5266233c01
48 changed files with 14973 additions and 6446 deletions

2
README
View file

@ -20,7 +20,7 @@ For audio playing support:
For audio recording support: For audio recording support:
- sox - sox 14.1+
- pyaudio - pyaudio
- lame - lame

View file

@ -6,7 +6,7 @@ from PyQt4.QtCore import *
from PyQt4.QtGui import * from PyQt4.QtGui import *
appName="Anki" appName="Anki"
appVersion="0.9.9.6" appVersion="0.9.9.7"
appWebsite="http://ichi2.net/anki/download/" appWebsite="http://ichi2.net/anki/download/"
appWiki="http://ichi2.net/anki/wiki/" appWiki="http://ichi2.net/anki/wiki/"
appHelpSite="http://ichi2.net/anki/wiki/AnkiWiki" appHelpSite="http://ichi2.net/anki/wiki/AnkiWiki"
@ -36,8 +36,23 @@ class SplashScreen(object):
self.splash = QSplashScreen(self.pixmap) self.splash = QSplashScreen(self.pixmap)
self.prog = QProgressBar(self.splash) self.prog = QProgressBar(self.splash)
self.prog.setMaximum(max) self.prog.setMaximum(max)
self.prog.setGeometry(self.splash.width()/10, 8*self.splash.height()/10, if QApplication.instance().style().objectName() != "plastique":
8*self.splash.width()/10, self.splash.height()/10) self.style = QStyleFactory.create("plastique")
self.prog.setStyle(self.style)
self.prog.setStyleSheet("""* {
color: #ffffff;
background-color: #061824;
margin:0px;
border:0px;
padding: 0px;
text-align: center;}
*::chunk {
color: #13486c;
}
""")
x = 8
self.prog.setGeometry(self.splash.width()/10, 8.85*self.splash.height()/10,
x*self.splash.width()/10, self.splash.height()/10)
self.splash.show() self.splash.show()
self.val = 1 self.val = 1
@ -93,7 +108,7 @@ def run():
if anki.version != appVersion: if anki.version != appVersion:
print "You have libanki %s, but this is ankiqt %s" % ( print "You have libanki %s, but this is ankiqt %s" % (
anki.version, appVersion) anki.version, appVersion)
print "\nPlease install the latest libanki." print "\nPlease ensure versions match."
return return
# parse args # parse args

View file

@ -57,6 +57,7 @@ class Config(dict):
'saveAfterAddingNum': 1, 'saveAfterAddingNum': 1,
'saveOnClose': True, 'saveOnClose': True,
'mainWindowGeom': None, 'mainWindowGeom': None,
'mainWindowState': None,
'suppressUpdate': False, 'suppressUpdate': False,
'suppressEstimates': False, 'suppressEstimates': False,
'showLastCardInterval': False, 'showLastCardInterval': False,
@ -84,6 +85,7 @@ class Config(dict):
'editLineSize': 20, 'editLineSize': 20,
'factEditorAdvanced': False, 'factEditorAdvanced': False,
'typeAnswerFontSize': 20, 'typeAnswerFontSize': 20,
'showProgress': True,
'recentColours': ["#000000", "#0000ff"], 'recentColours': ["#000000", "#0000ff"],
} }
for (k,v) in fields.items(): for (k,v) in fields.items():

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -13,7 +13,6 @@ def importAll():
import exporting import exporting
import facteditor import facteditor
import help import help
import importing
import lookup import lookup
import modelchooser import modelchooser
import modelproperties import modelproperties
@ -26,6 +25,7 @@ def importAll():
import update import update
import utils import utils
import view import view
import getshared
class DialogManager(object): class DialogManager(object):

View file

@ -1,4 +1,5 @@
# Copyright: Damien Elmes <anki@ichi2.net> # Copyright: Damien Elmes <anki@ichi2.net>
# -*- coding: utf-8 -*-
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html # License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
from PyQt4.QtGui import * from PyQt4.QtGui import *
@ -10,12 +11,31 @@ def show(parent):
abt = ankiqt.forms.about.Ui_About() abt = ankiqt.forms.about.Ui_About()
abt.setupUi(dialog) abt.setupUi(dialog)
abt.label.setText(_(""" abt.label.setText(_("""
<h1>Anki</h1> <center><img src=":/icons/anki-logo-thin.png"></center>
<img src=":/icons/anki.png">
<p> <p>
<span>Anki is a spaced repetition flashcard program designed to maximise your Anki is a friendly, intelligent spaced learning system. It's free and open
memory potential.<p/>It's free and licensed under the GPL.<p/> source.<p>
Version %s<br> Version %(ver)s<br>
<a href="http://ichi2.net/anki/">Visit website</a></span> <a href="http://ichi2.net/anki/">Visit website</a></span>
""") % appVersion) <p>
Written by Damien Elmes, with patches, translation, testing and design from:<p>%(cont)s
<p>
If you have contributed and are not on this list, please get in touch.
<p>
A big thanks to all the people who have provided suggestions, bug reports and
donations.""") % {
'cont': u"""
Alex Fraser, Andreas Klauer, Bananeweizen, Bernhard Ibertsberger, Christian
Rusche, David Smith, Dave Druelinger, Emmanuel Jarri, Frank Harper, Ian Lewis,
Iroiro, Jin Eun-Deok, Jo Nakashima, Krause Chr, LaC, Laurent Steffan, Marco
Giancotti, Mark Wilbur, Meelis Vasser, Michael Penkov, Michal Čadil, Nathanael
Law, Nick Cook, Niklas Laxström, Pcsl88, Piotr Kubowicz, Richard Colley,
Samson Melamed, Susanna Björverud, Timm Preetz, Timo Paulssen, Victor Suba,
and Xtru.
""",
'ver': appVersion})
dialog.show()
dialog.adjustSize()
dialog.exec_() dialog.exec_()

View file

@ -24,11 +24,19 @@ class ActiveTagsChooser(QDialog):
self.items = [] self.items = []
self.suspended = {} self.suspended = {}
for t in parseTags(self.parent.deck.suspended): for t in parseTags(self.parent.deck.suspended):
if t == "Suspended":
continue
self.suspended[t] = 1 self.suspended[t] = 1
if t not in self.tags: if t not in self.tags:
self.tags.append(t) self.tags.append(t)
self.tags.sort() self.tags.sort()
try:
self.tags.remove("Suspended")
except ValueError:
pass
for t in self.tags: for t in self.tags:
if t == "Suspended":
continue
item = QListWidgetItem(t, self.dialog.list) item = QListWidgetItem(t, self.dialog.list)
self.dialog.list.addItem(item) self.dialog.list.addItem(item)
self.items.append(item) self.items.append(item)

View file

@ -56,7 +56,6 @@ class AddCards(QDialog):
self.addButton.setToolTip(_("Add (shortcut: command+return)")) self.addButton.setToolTip(_("Add (shortcut: command+return)"))
else: else:
self.addButton.setToolTip(_("Add (shortcut: ctrl+return)")) self.addButton.setToolTip(_("Add (shortcut: ctrl+return)"))
self.addButton.setAutoDefault(False)
s = QShortcut(QKeySequence(_("Ctrl+Enter")), self) s = QShortcut(QKeySequence(_("Ctrl+Enter")), self)
s.connect(s, SIGNAL("activated()"), self.addButton, SLOT("click()")) s.connect(s, SIGNAL("activated()"), self.addButton, SLOT("click()"))
self.connect(self.addButton, SIGNAL("clicked()"), self.addCards) self.connect(self.addButton, SIGNAL("clicked()"), self.addCards)
@ -95,6 +94,7 @@ class AddCards(QDialog):
fact.tags = self.parent.deck.lastTags fact.tags = self.parent.deck.lastTags
# set the new fact # set the new fact
self.editor.setFact(fact, check=True) self.editor.setFact(fact, check=True)
self.setTabOrder(self.editor.tags, self.addButton)
def addCards(self): def addCards(self):
# make sure updated # make sure updated
@ -131,6 +131,14 @@ question or answer on all cards."""), parent=self)
self.editor.tags.addTags(parseTags(self.parent.deck.lastTags)) self.editor.tags.addTags(parseTags(self.parent.deck.lastTags))
self.maybeSave() self.maybeSave()
def keyPressEvent(self, evt):
"Show answer on RET or register answer."
if (evt.key() in (Qt.Key_Enter, Qt.Key_Return)
and self.editor.tags.hasFocus()):
evt.accept()
return
return QDialog.keyPressEvent(self, evt)
def closeEvent(self, evt): def closeEvent(self, evt):
if self.onClose(): if self.onClose():
evt.accept() evt.accept()

View file

@ -106,11 +106,12 @@ class DeckModel(QAbstractTableModel):
d = {'str': [], d = {'str': [],
'tag': [], 'tag': [],
} }
for elem in search.split(): if search:
if len(elem) > 2 and elem.startswith("t:"): for elem in search.split():
d['tag'].append(elem[2:]) if len(elem) > 2 and elem.startswith("t:"):
else: d['tag'].append(elem[2:])
d['str'].append(elem) else:
d['str'].append(elem)
return d return d
def showMatching(self): def showMatching(self):
@ -189,8 +190,8 @@ class DeckModel(QAbstractTableModel):
self.cards[index.row()] = self.deck.s.first(""" self.cards[index.row()] = self.deck.s.first("""
select id, question, answer, due, reps, factId, created, modified, select id, question, answer, due, reps, factId, created, modified,
interval, factor from cards where id = :id""", id=self.cards[index.row()][0]) interval, factor from cards where id = :id""", id=self.cards[index.row()][0])
self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), #self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"),
index, self.index(index.row(), 1)) # index, self.index(index.row(), 1))
except IndexError: except IndexError:
# called after search changed # called after search changed
pass pass
@ -259,12 +260,12 @@ class DeckModel(QAbstractTableModel):
self.columns[-1][0] = k self.columns[-1][0] = k
def createdColumn(self, index): def createdColumn(self, index):
return fmtTimeSpan( return time.strftime("%Y-%m-%d", time.localtime(
time.time() - self.cards[index.row()][CARD_CREATED]) + " ago" self.cards[index.row()][CARD_CREATED]))
def modifiedColumn(self, index): def modifiedColumn(self, index):
return fmtTimeSpan( return time.strftime("%Y-%m-%d", time.localtime(
time.time() - self.cards[index.row()][CARD_MODIFIED]) + " ago" self.cards[index.row()][CARD_MODIFIED]))
def intervalColumn(self, index): def intervalColumn(self, index):
return fmtTimeSpan( return fmtTimeSpan(
@ -279,7 +280,7 @@ class DeckModel(QAbstractTableModel):
class EditDeck(QMainWindow): class EditDeck(QMainWindow):
def __init__(self, parent): def __init__(self, parent):
QDialog.__init__(self, parent, Qt.Window) QMainWindow.__init__(self, parent)
self.parent = parent self.parent = parent
self.deck = self.parent.deck self.deck = self.parent.deck
self.config = parent.config self.config = parent.config
@ -354,8 +355,8 @@ class EditDeck(QMainWindow):
self.dialog.tagList.setFixedWidth(130) self.dialog.tagList.setFixedWidth(130)
self.dialog.tagList.clear() self.dialog.tagList.clear()
self.dialog.tagList.addItems(QStringList( self.dialog.tagList.addItems(QStringList(
[_('All cards'), _('No tags')] + self.alltags)) [_('<Tag filter>'), _('No tags')] + self.alltags))
self.dialog.tagList.view().setFixedWidth(300) self.dialog.tagList.view().setFixedWidth(200)
def drawSort(self): def drawSort(self):
self.sortList = [ self.sortList = [
@ -515,12 +516,12 @@ class EditDeck(QMainWindow):
if not sys.platform.startswith("win32"): if not sys.platform.startswith("win32"):
self.dialog.tableView.verticalHeader().hide() self.dialog.tableView.verticalHeader().hide()
self.dialog.tableView.horizontalHeader().show() self.dialog.tableView.horizontalHeader().show()
for i in range(2):
self.dialog.tableView.horizontalHeader().setResizeMode(i, QHeaderView.Stretch)
self.dialog.tableView.horizontalHeader().setResizeMode(2, QHeaderView.Interactive)
restoreHeader(self.dialog.tableView.horizontalHeader(), "editor") restoreHeader(self.dialog.tableView.horizontalHeader(), "editor")
self.dialog.tableView.verticalHeader().setDefaultSectionSize( self.dialog.tableView.verticalHeader().setDefaultSectionSize(
self.parent.config['editLineSize']) self.parent.config['editLineSize'])
for i in range(2):
self.dialog.tableView.horizontalHeader().setResizeMode(i, QHeaderView.Stretch)
self.dialog.tableView.horizontalHeader().setResizeMode(2, QHeaderView.Interactive)
def setupMenus(self): def setupMenus(self):
# actions # actions
@ -723,18 +724,28 @@ where id in %s""" % ids2str(sf))
_("Can only operate on one model at a time."), _("Can only operate on one model at a time."),
parent=self) parent=self)
return return
# get cards to enable
cms = [x.id for x in self.deck.s.query(Fact).get(sf[0]).\ cms = [x.id for x in self.deck.s.query(Fact).get(sf[0]).\
model.cardModels] model.cardModels]
d = AddCardChooser(self, cms) d = AddCardChooser(self, cms)
if not d.exec_(): if not d.exec_():
return return
# for each fact id, generate
n = _("Generate Cards") n = _("Generate Cards")
self.parent.setProgressParent(self)
self.deck.startProgress()
self.deck.setUndoStart(n) self.deck.setUndoStart(n)
for id in sf: facts = self.deck.s.query(Fact).filter(
self.deck.addCards(self.deck.s.query(Fact).get(id), text("id in %s" % ids2str(sf))).order_by(Fact.created).all()
d.selectedCms) self.deck.updateProgress(_("Generating Cards..."))
for c, fact in enumerate(facts):
self.deck.addCards(fact, d.selectedCms)
if c % 50 == 0:
self.deck.updateProgress()
self.deck.flushMod() self.deck.flushMod()
self.deck.updateAllPriorities() self.deck.updateAllPriorities()
self.deck.finishProgress()
self.parent.setProgressParent(None)
self.deck.setUndoEnd(n) self.deck.setUndoEnd(n)
self.updateSearch() self.updateSearch()
self.updateAfterCardChange() self.updateAfterCardChange()
@ -811,14 +822,25 @@ where id in %s""" % ids2str(sf))
###################################################################### ######################################################################
def onFindReplace(self): def onFindReplace(self):
sf = self.selectedFacts()
if not sf:
return
mods = self.deck.s.column0("""
select distinct modelId from facts
where id in %s""" % ids2str(sf))
if not len(mods) == 1:
ui.utils.showInfo(
_("Can only operate on one model at a time."),
parent=self)
return
d = QDialog(self) d = QDialog(self)
frm = ankiqt.forms.findreplace.Ui_Dialog() frm = ankiqt.forms.findreplace.Ui_Dialog()
frm.setupUi(d) frm.setupUi(d)
fields = sorted(self.currentCard.fact.model.fieldModels, key=attrgetter("name"))
frm.field.addItems(QStringList(
[_("All Fields")] + [f.name for f in fields]))
self.connect(frm.buttonBox, SIGNAL("helpRequested()"), self.connect(frm.buttonBox, SIGNAL("helpRequested()"),
self.onFindReplaceHelp) self.onFindReplaceHelp)
frm.type.insertItems(0, [
_("Fields"),
_("Tags")])
if not d.exec_(): if not d.exec_():
return return
n = _("Find and Replace") n = _("Find and Replace")
@ -826,17 +848,20 @@ where id in %s""" % ids2str(sf))
self.deck.startProgress(2) self.deck.startProgress(2)
self.deck.updateProgress(_("Replacing...")) self.deck.updateProgress(_("Replacing..."))
self.deck.setUndoStart(n) self.deck.setUndoStart(n)
sf = self.selectedFacts()
self.deck.updateProgress() self.deck.updateProgress()
changed = None changed = None
try: try:
changed = self.deck.findReplace(self.selectedFacts(), if frm.field.currentIndex() == 0:
unicode(frm.find.text()), field = None
unicode(frm.replace.text()), else:
frm.type.currentIndex(), field = fields[frm.field.currentIndex()-1].id
frm.re.isChecked()) changed = self.deck.findReplace(sf,
unicode(frm.find.text()),
unicode(frm.replace.text()),
frm.re.isChecked(),
field)
except sre_constants.error: except sre_constants.error:
ui.utils.showInfo(_("Invalid regexp."), ui.utils.showInfo(_("Invalid regular expression."),
parent=self) parent=self)
self.deck.setUndoEnd(n) self.deck.setUndoEnd(n)
self.deck.finishProgress() self.deck.finishProgress()
@ -850,7 +875,6 @@ where id in %s""" % ids2str(sf))
'b': len(sf), 'b': len(sf),
}, parent=self) }, parent=self)
def onFindReplaceHelp(self): def onFindReplaceHelp(self):
QDesktopServices.openUrl(QUrl(ankiqt.appWiki + QDesktopServices.openUrl(QUrl(ankiqt.appWiki +
"Editor#FindReplace")) "Editor#FindReplace"))
@ -861,18 +885,21 @@ where id in %s""" % ids2str(sf))
def onFirstCard(self): def onFirstCard(self):
if not self.model.cards: if not self.model.cards:
return return
self.editor.saveFieldsNow()
self.dialog.tableView.selectionModel().clear() self.dialog.tableView.selectionModel().clear()
self.dialog.tableView.selectRow(0) self.dialog.tableView.selectRow(0)
def onLastCard(self): def onLastCard(self):
if not self.model.cards: if not self.model.cards:
return return
self.editor.saveFieldsNow()
self.dialog.tableView.selectionModel().clear() self.dialog.tableView.selectionModel().clear()
self.dialog.tableView.selectRow(len(self.model.cards) - 1) self.dialog.tableView.selectRow(len(self.model.cards) - 1)
def onPreviousCard(self): def onPreviousCard(self):
if not self.model.cards: if not self.model.cards:
return return
self.editor.saveFieldsNow()
row = self.dialog.tableView.currentIndex().row() row = self.dialog.tableView.currentIndex().row()
row = max(0, row - 1) row = max(0, row - 1)
self.dialog.tableView.selectionModel().clear() self.dialog.tableView.selectionModel().clear()
@ -881,6 +908,7 @@ where id in %s""" % ids2str(sf))
def onNextCard(self): def onNextCard(self):
if not self.model.cards: if not self.model.cards:
return return
self.editor.saveFieldsNow()
row = self.dialog.tableView.currentIndex().row() row = self.dialog.tableView.currentIndex().row()
row = min(len(self.model.cards) - 1, row + 1) row = min(len(self.model.cards) - 1, row + 1)
self.dialog.tableView.selectionModel().clear() self.dialog.tableView.selectionModel().clear()

View file

@ -243,6 +243,7 @@ class DeckProperties(QDialog):
*60*60 + time.timezone) *60*60 + time.timezone)
except: except:
pass pass
was = self.d.modified
self.updateField(self.d, 'collapseTime', self.updateField(self.d, 'collapseTime',
self.dialog.collapse.isChecked() and 1 or 0) self.dialog.collapse.isChecked() and 1 or 0)
self.updateField(self.d, self.updateField(self.d,
@ -257,6 +258,7 @@ class DeckProperties(QDialog):
self.updateField(self.d, self.updateField(self.d,
"suspended", "suspended",
unicode(self.dialog.postponing.text())) unicode(self.dialog.postponing.text()))
prioritiesChanged = was != self.d.modified
# sources # sources
d = {} d = {}
d.update(self.sources) d.update(self.sources)
@ -289,8 +291,8 @@ insert into sources values
self.d.setModified() self.d.setModified()
# mark deck dirty and close # mark deck dirty and close
if self.origMod != self.d.modified: if self.origMod != self.d.modified:
self.d.updateCardTags() if prioritiesChanged:
self.d.updateAllPriorities() self.d.updateAllPriorities()
ankiqt.mw.reset() ankiqt.mw.reset()
self.d.setUndoEnd(n) self.d.setUndoEnd(n)
self.d.finishProgress() self.d.finishProgress()

View file

@ -4,10 +4,20 @@
from PyQt4.QtGui import * from PyQt4.QtGui import *
from PyQt4.QtCore import * from PyQt4.QtCore import *
import anki, ankiqt import anki, ankiqt
from anki.exporting import exporters from anki.exporting import exporters as exporters_
from anki.utils import parseTags from anki.utils import parseTags
from ankiqt import ui from ankiqt import ui
class PackagedAnkiExporter(object):
def __init__(self, *args):
pass
def exporters():
l = list(exporters_())
l.insert(1, (_("Packaged Anki Deck (*.zip)"),
PackagedAnkiExporter))
return l
class ExportDialog(QDialog): class ExportDialog(QDialog):
def __init__(self, parent): def __init__(self, parent):
@ -35,7 +45,7 @@ class ExportDialog(QDialog):
self.setTabOrder(self.tags, self.setTabOrder(self.tags,
self.dialog.includeScheduling) self.dialog.includeScheduling)
# save button # save button
b = QPushButton(_("Export to...")) b = QPushButton(_("Export..."))
self.dialog.buttonBox.addButton(b, QDialogButtonBox.AcceptRole) self.dialog.buttonBox.addButton(b, QDialogButtonBox.AcceptRole)
def exporterChanged(self, idx): def exporterChanged(self, idx):
@ -50,6 +60,9 @@ class ExportDialog(QDialog):
self.dialog.includeTags.hide() self.dialog.includeTags.hide()
def accept(self): def accept(self):
if isinstance(self.exporter, PackagedAnkiExporter):
self.parent.onShare(parseTags(unicode(self.tags.text())))
return QDialog.accept(self)
file = ui.utils.getSaveFile(self, _("Choose file to export to"), "export", file = ui.utils.getSaveFile(self, _("Choose file to export to"), "export",
self.exporter.key, self.exporter.ext) self.exporter.key, self.exporter.ext)
self.hide() self.hide()

View file

@ -14,6 +14,7 @@ from ankiqt import ui
import ankiqt import ankiqt
from ankiqt.ui.utils import mungeQA, saveGeom, restoreGeom from ankiqt.ui.utils import mungeQA, saveGeom, restoreGeom
from anki.hooks import addHook from anki.hooks import addHook
from sqlalchemy.exceptions import InvalidRequestError
clozeColour = "#0000ff" clozeColour = "#0000ff"
@ -38,6 +39,7 @@ class FactEditor(object):
self.changeTimer = None self.changeTimer = None
self.lastCloze = None self.lastCloze = None
addHook("deckClosed", self.deckClosedHook) addHook("deckClosed", self.deckClosedHook)
addHook("guiReset", self.refresh)
def setFact(self, fact, noFocus=False, check=False): def setFact(self, fact, noFocus=False, check=False):
"Make FACT the current fact." "Make FACT the current fact."
@ -63,6 +65,15 @@ class FactEditor(object):
if self.deck.mediaDir(create=False): if self.deck.mediaDir(create=False):
self.initMedia() self.initMedia()
def refresh(self):
if self.fact:
try:
self.deck.s.refresh(self.fact)
except InvalidRequestError:
# not attached to session yet, add cards dialog will handle
return
self.setFact(self.fact, check=True)
def focusFirst(self): def focusFirst(self):
if self.focusTarget: if self.focusTarget:
self.focusTarget.setFocus() self.focusTarget.setFocus()
@ -253,12 +264,12 @@ class FactEditor(object):
self.preview.setStyle(self.plastiqueStyle) self.preview.setStyle(self.plastiqueStyle)
# cloze # cloze
self.cloze = QPushButton(self.widget) self.cloze = QPushButton(self.widget)
self.clozeSC = QShortcut(QKeySequence(_("F6")), self.widget) self.clozeSC = QShortcut(QKeySequence(_("F9")), self.widget)
self.cloze.connect(self.cloze, SIGNAL("clicked()"), self.cloze.connect(self.cloze, SIGNAL("clicked()"),
self.onCloze) self.onCloze)
self.cloze.connect(self.clozeSC, SIGNAL("activated()"), self.cloze.connect(self.clozeSC, SIGNAL("activated()"),
self.onCloze) self.onCloze)
self.cloze.setToolTip(_("Cloze (F6)")) self.cloze.setToolTip(_("Cloze (F9)"))
#self.cloze.setIcon(QIcon(":/icons/document-cloze.png")) #self.cloze.setIcon(QIcon(":/icons/document-cloze.png"))
self.cloze.setFixedWidth(30) self.cloze.setFixedWidth(30)
self.cloze.setFixedHeight(26) self.cloze.setFixedHeight(26)
@ -306,12 +317,12 @@ class FactEditor(object):
self.latexMathEnv.setStyle(self.plastiqueStyle) self.latexMathEnv.setStyle(self.plastiqueStyle)
# html # html
self.htmlEdit = QPushButton(self.widget) self.htmlEdit = QPushButton(self.widget)
self.htmlEdit.setToolTip(_("HTML Editor (F9)")) self.htmlEdit.setToolTip(_("HTML Editor"))
self.htmlEditSC = QShortcut(QKeySequence(_("F9")), self.widget) self.htmlEditSC = QShortcut(QKeySequence(_("Ctrl+F9")), self.widget)
self.htmlEdit.connect(self.htmlEdit, SIGNAL("clicked()"), self.htmlEdit.connect(self.htmlEdit, SIGNAL("clicked()"),
self.onHtmlEdit) self.onHtmlEdit)
self.htmlEdit.connect(self.htmlEditSC, SIGNAL("activated()"), self.htmlEdit.connect(self.htmlEditSC, SIGNAL("activated()"),
self.onHtmlEdit) self.onHtmlEdit)
self.htmlEdit.setIcon(QIcon(":/icons/text-xml.png")) self.htmlEdit.setIcon(QIcon(":/icons/text-xml.png"))
self.htmlEdit.setFocusPolicy(Qt.NoFocus) self.htmlEdit.setFocusPolicy(Qt.NoFocus)
self.htmlEdit.setEnabled(False) self.htmlEdit.setEnabled(False)
@ -679,17 +690,24 @@ class FactEditor(object):
src = self.focusedEdit() src = self.focusedEdit()
if not src: if not src:
return return
re1 = "\[.+?(:(.+?))?\]"
re2 = "\[(.+?)(:.+?)?\]"
# add brackets because selected? # add brackets because selected?
cursor = src.textCursor() cursor = src.textCursor()
oldSrc = None
if cursor.hasSelection(): if cursor.hasSelection():
oldSrc = src.toHtml()
s = cursor.selectionStart() s = cursor.selectionStart()
e = cursor.selectionEnd() e = cursor.selectionEnd()
cursor.setPosition(e) cursor.setPosition(e)
cursor.insertText("]") cursor.insertText("]]")
cursor.setPosition(s) cursor.setPosition(s)
cursor.insertText("[") cursor.insertText("[[")
re1 = "\[" + re1 + "\]"
re2 = "\[" + re2 + "\]"
dst = None dst = None
for (name, (field, w)) in self.fields.items(): for field in self.fact.fields:
w = self.fields[field.name][1]
if w.hasFocus(): if w.hasFocus():
dst = False dst = False
continue continue
@ -697,11 +715,12 @@ class FactEditor(object):
dst = w dst = w
break break
if not dst: if not dst:
dst = self.fields.values()[0][1] dst = self.fields[self.fact.fields[0].name][1]
if dst == w: if dst == w:
return return
# check if there's alredy something there # check if there's alredy something there
oldSrc = src.toHtml() if not oldSrc:
oldSrc = src.toHtml()
oldDst = dst.toHtml() oldDst = dst.toHtml()
if unicode(dst.toPlainText()): if unicode(dst.toPlainText()):
if (self.lastCloze and if (self.lastCloze and
@ -729,10 +748,9 @@ class FactEditor(object):
exp = match.group(2) exp = match.group(2)
return '<font color="%s"><b>[...%s]</b></font>' % ( return '<font color="%s"><b>[...%s]</b></font>' % (
clozeColour, exp) clozeColour, exp)
new = re.sub("\[.+?(:(.+?))?\]", repl, s) new = re.sub(re1, repl, s)
old = re.sub("\[(.+?)(:.+?)?\]", '<font color="%s"><b>\\1</b></font>' old = re.sub(re2, '<font color="%s"><b>\\1</b></font>'
% clozeColour, s) % clozeColour, s)
oldSrc = unicode(src.toHtml())
src.setHtml(new) src.setHtml(new)
dst.setHtml(old) dst.setHtml(old)
self.lastCloze = (oldSrc, unicode(src.toHtml()), self.lastCloze = (oldSrc, unicode(src.toHtml()),

227
ankiqt/ui/getshared.py Normal file
View file

@ -0,0 +1,227 @@
# -*- coding: utf-8 -*-
# Copyright: Damien Elmes <anki@ichi2.net>
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtNetwork import *
import ankiqt, simplejson, time, cStringIO, zipfile, tempfile, os, re
from ankiqt.ui.utils import saveGeom, restoreGeom, showInfo
from anki.utils import fmtTimeSpan
R_ID = 0
R_USERNAME = 1
R_TITLE = 2
R_DESCRIPTION = 3
R_TAGS = 4
R_VERSION = 5
R_FACTS = 6
R_SIZE = 7
R_COUNT = 8
R_MODIFIED = 9
R_FNAME = 10
class GetShared(QDialog):
def __init__(self, parent, type):
QDialog.__init__(self, parent, Qt.Window)
self.parent = parent
self.form = ankiqt.forms.getshared.Ui_Dialog()
self.form.setupUi(self)
restoreGeom(self, "getshared")
self.setupTable()
self.onChangeType(type)
self.ok = False
if type == 0:
self.setWindowTitle(_("Download Shared Deck"))
else:
self.setWindowTitle(_("Download Shared Plugin"))
self.exec_()
def setupTable(self):
self.connect(
self.form.table, SIGNAL("currentCellChanged(int,int,int,int)"),
self.onCellChanged)
self.form.table.verticalHeader().setDefaultSectionSize(
self.parent.config['editLineSize'])
self.connect(self.form.search, SIGNAL("textChanged(QString)"),
self.limit)
def fetchData(self):
h = QHttp(self)
h.connect(h, SIGNAL("requestFinished(int,bool)"), self.onReqFin)
h.setHost("anki.ichi2.net")
#h.setHost("localhost", 8001)
self.conId = h.get("/file/search?t=%d" % self.type)
self.http = h
self.parent.setProgressParent(self)
self.parent.startProgress()
def onReqFin(self, id, err):
"List fetched."
if id != self.conId:
return
self.parent.finishProgress()
self.parent.setProgressParent(None)
if err:
showInfo(_("Unable to connect to server."), parent=self)
self.close()
return
data = self.http.readAll()
self.allList = simplejson.loads(unicode(data))
self.typeChanged()
self.limit()
def limit(self, txt=""):
if not txt:
self.curList = self.allList
else:
txt = unicode(txt).lower()
self.curList = [
l for l in self.allList
if (txt in l[R_TITLE].lower() or
txt in l[R_DESCRIPTION].lower() or
txt in l[R_TAGS].lower())]
self.redraw()
def redraw(self):
self.form.table.setSortingEnabled(False)
self.form.table.setRowCount(len(self.curList))
self.items = {}
if self.type == 0:
cols = (R_TITLE, R_FACTS, R_COUNT)
else:
cols = (R_TITLE, R_COUNT)
for rc, r in enumerate(self.curList):
for cc, c in enumerate(cols):
if c == R_FACTS or c == R_COUNT:
txt = unicode("%15d" % r[c])
else:
txt = unicode(r[c])
item = QTableWidgetItem(txt)
item.setFlags(item.flags() & ~Qt.ItemIsEditable)
self.items[item] = r
self.form.table.setItem(rc, cc, item)
self.form.table.setSortingEnabled(True)
if self.type == 0:
self.form.table.sortItems(2, Qt.DescendingOrder)
else:
self.form.table.sortItems(1, Qt.DescendingOrder)
self.form.table.selectRow(0)
def onCellChanged(self, row, col, x, y):
ci = self.form.table.currentItem()
if not ci:
self.form.bottomLabel.setText(_("Nothing selected."))
return
r = self.items[ci]
self.curRow = r
self.form.bottomLabel.setText(_("""\
<b>Title</b>: %(title)s<br>
<b>Tags</b>: %(tags)s<br>
<b>Size</b>: %(size)0.2fKB<br>
<b>Uploader</b>: %(author)s<br>
<b>Downloads</b>: %(count)s<br>
<b>Description</b>:<br>%(description)s""") % {
'title': r[R_TITLE],
'tags': r[R_TAGS],
'size': r[R_SIZE] / 1024.0,
'author': r[R_USERNAME],
'count': r[R_COUNT],
'description': r[R_DESCRIPTION].replace("\n", "<br>"),
})
self.form.scrollAreaWidgetContents.adjustSize()
self.form.scrollArea.setWidget(self.form.scrollAreaWidgetContents)
def onChangeType(self, type):
self.type = type
self.fetchData()
def typeChanged(self):
self.form.table.clear()
if self.type == 0:
self.form.table.setColumnCount(3)
self.form.table.setHorizontalHeaderLabels([
_("Title"), _("Facts"), _("Downloads")])
else:
self.form.table.setColumnCount(2)
self.form.table.setHorizontalHeaderLabels([
_("Title"), _("Downloads")])
self.form.table.horizontalHeader().setResizeMode(
0, QHeaderView.Stretch)
self.form.table.verticalHeader().hide()
self.form.table.setSelectionBehavior(QAbstractItemView.SelectRows)
def accept(self):
h = QHttp(self)
h.connect(h, SIGNAL("requestFinished(int,bool)"), self.onReqFin2)
h.setHost("anki.ichi2.net")
#h.setHost("localhost", 8001)
self.conId = h.get("/file/get?id=%d" % self.curRow[R_ID])
self.http = h
self.parent.setProgressParent(self)
self.parent.startProgress()
def onReqFin2(self, id, err):
"File fetched."
if id != self.conId:
return
try:
self.parent.finishProgress()
self.parent.setProgressParent(None)
if err:
showInfo(_("Unable to connect to server."), parent=self)
self.close()
return
data = self.http.readAll()
ext = os.path.splitext(self.curRow[R_FNAME])[1]
if ext == ".zip":
f = cStringIO.StringIO()
f.write(data)
z = zipfile.ZipFile(f)
else:
z = None
tit = self.curRow[R_TITLE]
tit = re.sub("[^][A-Za-z0-9 ()\-]", "", tit)
tit = tit[0:40]
if self.type == 0:
# deck
dd = self.parent.documentDir
p = os.path.join(dd, tit + ".anki")
if os.path.exists(p):
tit += "%d" % time.time()
for l in z.namelist():
if l == "shared.anki":
dpath = os.path.join(dd, tit + ".anki")
open(dpath, "wb").write(z.read(l))
elif l.startswith("shared.media/"):
try:
os.mkdir(os.path.join(dd, tit + ".media"))
except OSError:
pass
open(os.path.join(dd, tit + ".media",
os.path.basename(l)),"wb").write(z.read(l))
self.parent.loadDeck(dpath)
self.ok = True
else:
pd = self.parent.pluginsFolder()
if z:
for l in z.infolist():
if not l.file_size:
continue
try:
os.makedirs(os.path.join(
pd, os.path.dirname(l.filename)))
except OSError:
pass
open(os.path.join(pd, l.filename), "wb").\
write(z.read(l.filename))
else:
open(os.path.join(pd, tit + ext), "wb").write(data)
self.ok = True
showInfo(_("Plugin downloaded. Please restart Anki."),
parent=self)
return
finally:
QDialog.accept(self)

View file

@ -41,7 +41,8 @@ class HelpArea(object):
def showText(self, text, py={}): def showText(self, text, py={}):
if "hide" in self.handlers: if "hide" in self.handlers:
self.handlers["hide"]() if self.handlers['hide'] != py.get('hide'):
self.handlers["hide"]()
self.show() self.show()
self.buffer = text self.buffer = text
self.addHider() self.addHider()

View file

@ -132,7 +132,7 @@ class ImportDialog(QDialog):
self.parent.deck.finishProgress() self.parent.deck.finishProgress()
self.parent.deck.setUndoEnd(n) self.parent.deck.setUndoEnd(n)
txt = ( txt = (
_("Importing complete. %(num)d cards imported from %(file)s.\n") % _("Importing complete. %(num)d facts imported from %(file)s.\n") %
{"num": self.importer.total, "file": os.path.basename(self.file)}) {"num": self.importer.total, "file": os.path.basename(self.file)})
txt += _("Click the close button or import another file.\n\n") txt += _("Click the close button or import another file.\n\n")
if self.importer.log: if self.importer.log:

View file

@ -6,8 +6,8 @@ from PyQt4.QtGui import *
from PyQt4.QtCore import * from PyQt4.QtCore import *
from PyQt4.QtWebKit import QWebPage from PyQt4.QtWebKit import QWebPage
import os, sys, re, types, gettext, stat, traceback import os, sys, re, types, gettext, stat, traceback, inspect
import shutil, time, glob, tempfile, datetime import shutil, time, glob, tempfile, datetime, zipfile, locale
from PyQt4.QtCore import * from PyQt4.QtCore import *
from PyQt4.QtGui import * from PyQt4.QtGui import *
@ -49,8 +49,6 @@ class AnkiQt(QMainWindow):
self.setupTray() self.setupTray()
self.connectMenuActions() self.connectMenuActions()
ui.splash.update() ui.splash.update()
if self.config['mainWindowGeom']:
self.restoreGeometry(self.config['mainWindowGeom'])
self.setupViews() self.setupViews()
self.setupEditor() self.setupEditor()
self.setupStudyScreen() self.setupStudyScreen()
@ -58,6 +56,9 @@ class AnkiQt(QMainWindow):
self.setupAnchors() self.setupAnchors()
self.setupToolbar() self.setupToolbar()
self.setupProgressInfo() self.setupProgressInfo()
if self.config['mainWindowState']:
self.restoreGeometry(self.config['mainWindowGeom'])
self.restoreState(self.config['mainWindowState'])
if sys.platform.startswith("darwin"): if sys.platform.startswith("darwin"):
self.setUnifiedTitleAndToolBarOnMac(True) self.setUnifiedTitleAndToolBarOnMac(True)
pass pass
@ -68,10 +69,11 @@ class AnkiQt(QMainWindow):
self.moveToState("auto") self.moveToState("auto")
# check for updates # check for updates
ui.splash.update() ui.splash.update()
self.setupAutoUpdate() self.errorOccurred = False
self.setupErrorHandler() self.setupErrorHandler()
self.setupMisc() self.setupMisc()
self.loadPlugins() self.loadPlugins()
self.setupAutoUpdate()
self.rebuildPluginsMenu() self.rebuildPluginsMenu()
# run after-init hook # run after-init hook
try: try:
@ -82,6 +84,9 @@ class AnkiQt(QMainWindow):
ui.splash.update() ui.splash.update()
ui.splash.finish(self) ui.splash.finish(self)
self.show() self.show()
if (self.deck and self.config['syncOnLoad'] and
self.deck.syncName):
self.syncDeck(interactive=False)
def setupMainWindow(self): def setupMainWindow(self):
# main window # main window
@ -142,9 +147,11 @@ class AnkiQt(QMainWindow):
# hack for matplotlib errors on osx # hack for matplotlib errors on osx
self.pool = "" self.pool = ""
stdText = _("""\ stdText = _("""\
An error occurred.<br> An error occurred. Please:<p>
Please run <b>Tools > Advanced > Check DB</b>.<br> <ol>
<br> <li><b>Restart Anki</b>.
<li><b>Tools > Advanced > Check DB</b>.
</ol>
If it does not fix the problem, please copy the following<br> If it does not fix the problem, please copy the following<br>
into a bug report:<br><br> into a bug report:<br><br>
""") """)
@ -156,6 +163,7 @@ Please do not file a bug report with Anki.<br><br>""")
else: else:
txt = stdText txt = stdText
if self.pool: if self.pool:
self.parent.errorOccurred = True
ui.utils.showText(txt + self.pool[0:10000].replace( ui.utils.showText(txt + self.pool[0:10000].replace(
"\n", "<br>")) "\n", "<br>"))
self.pool = "" self.pool = ""
@ -197,6 +205,7 @@ Please do not file a bug report with Anki.<br><br>""")
if count: if count:
self.deck.rebuildCounts() self.deck.rebuildCounts()
self.deck.rebuildQueue() self.deck.rebuildQueue()
runHook("guiReset")
self.moveToState("initial") self.moveToState("initial")
def moveToState(self, state): def moveToState(self, state):
@ -349,12 +358,12 @@ Please do not file a bug report with Anki.<br><br>""")
"Reschedule current card and move back to getQuestion state." "Reschedule current card and move back to getQuestion state."
if self.state != "showAnswer": if self.state != "showAnswer":
return return
# remove card from session before updating it # force refresh of card then remove from session as we update in pure sql
try: self.deck.s.refresh(self.currentCard)
self.deck.s.expunge(self.currentCard) self.deck.s.refresh(self.currentCard.fact)
except: self.deck.s.refresh(self.currentCard.cardModel)
# session has been reset self.deck.s.expunge(self.currentCard)
pass # answer
self.deck.answerCard(self.currentCard, quality) self.deck.answerCard(self.currentCard, quality)
self.lastScheduledTime = anki.utils.fmtTimeSpan( self.lastScheduledTime = anki.utils.fmtTimeSpan(
self.currentCard.due - time.time()) self.currentCard.due - time.time())
@ -611,10 +620,10 @@ To upgrade an old deck, download Anki 0.9.8.7."""))
# try a command line argument if available # try a command line argument if available
if args: if args:
f = unicode(args[0], sys.getfilesystemencoding()) f = unicode(args[0], sys.getfilesystemencoding())
return self.loadDeck(f) return self.loadDeck(f, sync=False)
# try recent deck paths # try recent deck paths
for path in self.config['recentDeckPaths']: for path in self.config['recentDeckPaths']:
r = self.loadDeck(path, interactive=False) r = self.loadDeck(path, interactive=False, sync=False)
if r: if r:
return r return r
self.onNew(initial=True) self.onNew(initial=True)
@ -626,50 +635,10 @@ To upgrade an old deck, download Anki 0.9.8.7."""))
latest = self.config['recentDeckPaths'][0] latest = self.config['recentDeckPaths'][0]
defaultDir = os.path.dirname(latest) defaultDir = os.path.dirname(latest)
else: else:
if save: defaultDir = unicode(os.path.expanduser("~/"),
defaultDir = unicode(os.path.expanduser("~/"), sys.getfilesystemencoding())
sys.getfilesystemencoding())
else:
samples = self.getSamplesDir()
if samples:
return samples
return defaultDir return defaultDir
def getSamplesDir(self):
path = os.path.join(ankiqt.runningDir, "libanki")
if not os.path.exists(path):
path = os.path.join(
os.path.join(ankiqt.runningDir, ".."), "libanki")
if not os.path.exists(path):
path = ankiqt.runningDir
if sys.platform.startswith("win32"):
path = os.path.split(
os.path.split(ankiqt.runningDir)[0])[0]
elif sys.platform.startswith("darwin"):
path = ankiqt.runningDir + "/../../.."
path = os.path.join(path, "samples")
path = os.path.normpath(path)
if os.path.exists(path):
if sys.platform.startswith("darwin"):
return self.openMacSamplesDir(path)
return path
return ""
def openMacSamplesDir(self, path):
# some versions of macosx don't allow the open dialog to point inside
# a .App file, it seems - so we copy the files onto the desktop.
newDir = os.path.expanduser("~/Documents/Anki 0.9 Sample Decks")
import shutil
if os.path.exists(newDir):
files = os.listdir(path)
for file in files:
loc = os.path.join(path, file)
if not os.path.exists(os.path.join(newDir, file)):
shutil.copy2(loc, newDir)
return newDir
shutil.copytree(path, newDir)
return newDir
def updateRecentFiles(self, path): def updateRecentFiles(self, path):
"Add the current deck to the list of recent files." "Add the current deck to the list of recent files."
path = os.path.normpath(path) path = os.path.normpath(path)
@ -761,6 +730,7 @@ To upgrade an old deck, download Anki 0.9.8.7."""))
return True return True
def inMainWindow(self): def inMainWindow(self):
return True
return self.app.activeWindow() == self return self.app.activeWindow() == self
def onNew(self, initial=False, path=None): def onNew(self, initial=False, path=None):
@ -826,23 +796,27 @@ To upgrade an old deck, download Anki 0.9.8.7."""))
self.deck = None self.deck = None
self.moveToState("initial") self.moveToState("initial")
def onOpen(self, samples=False): def onGetSharedDeck(self):
if not self.inMainWindow(): return
if not self.saveAndClose(hideWelcome=True): return
s = ui.getshared.GetShared(self, 0)
if not s.ok:
self.deck = None
self.moveToState("initial")
def onGetSharedPlugin(self):
if not self.inMainWindow(): return
ui.getshared.GetShared(self, 1)
def onOpen(self):
if not self.inMainWindow(): return if not self.inMainWindow(): return
key = _("Deck files (*.anki)") key = _("Deck files (*.anki)")
if samples: defaultDir = self.getSamplesDir() defaultDir = self.getDefaultDir()
else: defaultDir = self.getDefaultDir()
file = QFileDialog.getOpenFileName(self, _("Open deck"), file = QFileDialog.getOpenFileName(self, _("Open deck"),
defaultDir, key) defaultDir, key)
file = unicode(file) file = unicode(file)
if not file: if not file:
return False return False
if samples:
# we need to copy into a writeable location
d = unicode(
os.path.join(self.documentDir, os.path.basename(file)))
if not os.path.exists(d):
shutil.copy(file, d)
file = d
ret = self.loadDeck(file, interactive=True) ret = self.loadDeck(file, interactive=True)
if not ret: if not ret:
if ret is None: if ret is None:
@ -853,9 +827,6 @@ To upgrade an old deck, download Anki 0.9.8.7."""))
self.updateRecentFiles(file) self.updateRecentFiles(file)
return True return True
def onOpenSamples(self):
self.onOpen(samples=True)
def onUnsavedTimer(self): def onUnsavedTimer(self):
QToolTip.showText( QToolTip.showText(
self.mainWin.statusbar.mapToGlobal(QPoint(0, -100)), self.mainWin.statusbar.mapToGlobal(QPoint(0, -100)),
@ -925,6 +896,7 @@ your deck."""))
runHook("quit") runHook("quit")
self.help.hide() self.help.hide()
self.config['mainWindowGeom'] = self.saveGeometry() self.config['mainWindowGeom'] = self.saveGeometry()
self.config['mainWindowState'] = self.saveState()
# save config # save config
try: try:
self.config.save() self.config.save()
@ -950,14 +922,12 @@ your deck."""))
def onWelcomeAnchor(self, str): def onWelcomeAnchor(self, str):
if str == "new": if str == "new":
self.onNew() self.onNew()
elif str == "sample":
self.onOpenSamples()
elif str == "open": elif str == "open":
self.onOpen() self.onOpen()
elif str == "sample":
self.onGetSharedDeck()
elif str == "openrem": elif str == "openrem":
self.onOpenOnline() self.onOpenOnline()
elif str == "more":
self.onGetMoreDecks()
if str == "addfacts": if str == "addfacts":
if not self.deck: if not self.deck:
self.onNew() self.onNew()
@ -1175,7 +1145,6 @@ day = :d""", d=yesterday)
self.deck.newCardSpacing = self.mainWin.newCardScheduling.currentIndex() self.deck.newCardSpacing = self.mainWin.newCardScheduling.currentIndex()
self.deck.revCardOrder = self.mainWin.revCardOrder.currentIndex() self.deck.revCardOrder = self.mainWin.revCardOrder.currentIndex()
self.deck.setFailedCardPolicy(self.mainWin.failedCardsOption.currentIndex()) self.deck.setFailedCardPolicy(self.mainWin.failedCardsOption.currentIndex())
self.deck.updateDynamicIndices()
self.deck.startSession() self.deck.startSession()
self.deck.flushMod() self.deck.flushMod()
self.moveToState("getQuestion") self.moveToState("getQuestion")
@ -1401,13 +1370,11 @@ day = :d""", d=yesterday)
def onActiveTags(self): def onActiveTags(self):
ui.activetags.show(self) ui.activetags.show(self)
def onGetMoreDecks(self):
QDesktopServices.openUrl(QUrl(ankiqt.appMoreDecks))
# Importing & exporting # Importing & exporting
########################################################################## ##########################################################################
def onImport(self): def onImport(self):
import ui.importing
if self.deck is None: if self.deck is None:
self.onNew() self.onNew()
ui.importing.ImportDialog(self) ui.importing.ImportDialog(self)
@ -1415,9 +1382,20 @@ day = :d""", d=yesterday)
def onExport(self): def onExport(self):
ui.exporting.ExportDialog(self) ui.exporting.ExportDialog(self)
# Cramming # Cramming & Sharing
########################################################################## ##########################################################################
def _copyToTmpDeck(self, name="cram.anki", tags=""):
ndir = tempfile.mkdtemp(prefix="anki")
path = os.path.join(ndir, name)
from anki.exporting import AnkiExporter
e = AnkiExporter(self.deck)
if tags:
e.limitTags = parseTags(tags)
path = unicode(path, sys.getfilesystemencoding())
e.exportInto(path)
return (e, path)
def onCram(self): def onCram(self):
if self.deck.name() == "cram": if self.deck.name() == "cram":
ui.utils.showInfo( ui.utils.showInfo(
@ -1431,14 +1409,7 @@ day = :d""", d=yesterday)
return return
s = unicode(s) s = unicode(s)
# open tmp deck # open tmp deck
ndir = tempfile.mkdtemp(prefix="anki") (e, path) = self._copyToTmpDeck(tags=s)
path = os.path.join(ndir, "cram.anki")
from anki.exporting import AnkiExporter
e = AnkiExporter(self.deck)
if s:
e.limitTags = parseTags(s)
path = unicode(path, sys.getfilesystemencoding())
e.exportInto(path)
if not e.exportedCards: if not e.exportedCards:
ui.utils.showInfo(_("No cards matched the provided tags.")) ui.utils.showInfo(_("No cards matched the provided tags."))
return return
@ -1482,6 +1453,80 @@ day = :d""", d=yesterday)
self.reset() self.reset()
p.finish() p.finish()
def onShare(self, tags):
pwd = os.getcwd()
# open tmp deck
(e, path) = self._copyToTmpDeck(name="shared.anki", tags=tags)
if not e.exportedCards:
ui.utils.showInfo(_("No cards matched the provided tags."))
return
self.deck.startProgress()
self.deck.updateProgress()
d = DeckStorage.Deck(path)
# reset scheduling to defaults
d.newCardsPerDay = 20
d.delay0 = 600
d.delay1 = 600
d.delay2 = 0
d.hardIntervalMin = 0.333
d.hardIntervalMax = 0.5
d.midIntervalMin = 3.0
d.midIntervalMax = 5.0
d.easyIntervalMin = 7.0
d.easyIntervalMax = 9.0
d.syncName = None
d.suspended = u"Suspended"
self.deck.updateProgress()
d.updateAllPriorities()
d.utcOffset = -1
d.flushMod()
d.save()
self.deck.updateProgress()
# remove indices
indices = d.s.column0(
"select name from sqlite_master where type = 'index' "
"and sql != ''")
for i in indices:
d.s.statement("drop index %s" % i)
# and q/a cache
d.s.statement("update cards set question = '', answer = ''")
self.deck.updateProgress()
d.s.statement("vacuum")
self.deck.updateProgress()
nfacts = d.factCount
mdir = d.mediaDir()
d.close()
dir = os.path.dirname(path)
zippath = os.path.join(dir, "shared-%d.zip" % time.time())
# zip it up
zip = zipfile.ZipFile(zippath, "w", zipfile.ZIP_DEFLATED)
zip.writestr("facts", str(nfacts))
readmep = os.path.join(dir, "README.html")
readme = open(readmep, "w")
readme.write('''\
<html><body>
This is an exported packaged deck created by Anki.<p>
To share this deck with other people, upload it to
<a href="http://anki.ichi2.net/file/upload">
http://anki.ichi2.net/file/upload</a>, or email
it to your friends.
</body></html>''')
readme.close()
zip.write(readmep, "README.txt")
zip.write(path, "shared.anki")
if mdir:
for f in os.listdir(mdir):
zip.write(os.path.join(mdir, f),
str(os.path.join("shared.media/", f)))
shutil.rmtree(mdir)
self.deck.updateProgress()
zip.close()
os.chdir(pwd)
os.unlink(path)
self.deck.finishProgress()
self.onOpenPluginFolder(dir)
# Reviewing and learning ahead # Reviewing and learning ahead
########################################################################## ##########################################################################
@ -1498,6 +1543,7 @@ day = :d""", d=yesterday)
def setLang(self): def setLang(self):
"Set the user interface language." "Set the user interface language."
locale.setlocale(locale.LC_ALL, '')
languageDir=os.path.join(ankiqt.modDir, "locale") languageDir=os.path.join(ankiqt.modDir, "locale")
self.languageTrans = gettext.translation('ankiqt', languageDir, self.languageTrans = gettext.translation('ankiqt', languageDir,
languages=[self.config["interfaceLang"]], languages=[self.config["interfaceLang"]],
@ -1698,10 +1744,12 @@ day = :d""", d=yesterday)
s = SIGNAL("triggered()") s = SIGNAL("triggered()")
self.connect(m.actionNew, s, self.onNew) self.connect(m.actionNew, s, self.onNew)
self.connect(m.actionOpenOnline, s, self.onOpenOnline) self.connect(m.actionOpenOnline, s, self.onOpenOnline)
self.connect(m.actionDownloadSharedDeck, s, self.onGetSharedDeck)
self.connect(m.actionDownloadSharedPlugin, s, self.onGetSharedPlugin)
self.connect(m.actionOpen, s, self.onOpen) self.connect(m.actionOpen, s, self.onOpen)
self.connect(m.actionOpenSamples, s, self.onOpenSamples)
self.connect(m.actionSave, s, self.onSave) self.connect(m.actionSave, s, self.onSave)
self.connect(m.actionSaveAs, s, self.onSaveAs) self.connect(m.actionSaveAs, s, self.onSaveAs)
self.connect(m.actionShare, s, self.onShare)
self.connect(m.actionClose, s, self.onClose) self.connect(m.actionClose, s, self.onClose)
self.connect(m.actionExit, s, self, SLOT("close()")) self.connect(m.actionExit, s, self, SLOT("close()"))
self.connect(m.actionSyncdeck, s, self.syncDeck) self.connect(m.actionSyncdeck, s, self.syncDeck)
@ -1742,7 +1790,6 @@ day = :d""", d=yesterday)
self.connect(m.actionDisableAllPlugins, s, self.onDisableAllPlugins) self.connect(m.actionDisableAllPlugins, s, self.onDisableAllPlugins)
self.connect(m.actionActiveTags, s, self.onActiveTags) self.connect(m.actionActiveTags, s, self.onActiveTags)
self.connect(m.actionReleaseNotes, s, self.onReleaseNotes) self.connect(m.actionReleaseNotes, s, self.onReleaseNotes)
self.connect(m.actionGetMoreDecks, s, self.onGetMoreDecks)
self.connect(m.actionCacheLatex, s, self.onCacheLatex) self.connect(m.actionCacheLatex, s, self.onCacheLatex)
self.connect(m.actionUncacheLatex, s, self.onUncacheLatex) self.connect(m.actionUncacheLatex, s, self.onUncacheLatex)
self.connect(m.actionStudyOptions, s, self.onStudyOptions) self.connect(m.actionStudyOptions, s, self.onStudyOptions)
@ -1835,7 +1882,13 @@ day = :d""", d=yesterday)
self.mainWin.menu_Lookup.menuAction().setVisible(True) self.mainWin.menu_Lookup.menuAction().setVisible(True)
else: else:
self.mainWin.menu_Lookup.menuAction().setVisible(False) self.mainWin.menu_Lookup.menuAction().setVisible(False)
enable = False
self.mainWin.menu_Lookup.setEnabled(enable) self.mainWin.menu_Lookup.setEnabled(enable)
self.mainWin.actionLookup_es.setEnabled(enable)
self.mainWin.actionLookup_esk.setEnabled(enable)
self.mainWin.actionLookup_expr.setEnabled(enable)
self.mainWin.actionLookup_mean.setEnabled(enable)
self.mainWin.actionLookup_as.setEnabled(enable)
def maybeEnableUndo(self): def maybeEnableUndo(self):
if self.deck and self.deck.undoAvailable(): if self.deck and self.deck.undoAvailable():
@ -1904,6 +1957,7 @@ day = :d""", d=yesterday)
sys.path.insert(0, plugdir) sys.path.insert(0, plugdir)
plugins = self.enabledPlugins() plugins = self.enabledPlugins()
plugins.sort() plugins.sort()
self.registeredPlugins = {}
for plugin in plugins: for plugin in plugins:
try: try:
nopy = plugin.replace(".py", "") nopy = plugin.replace(".py", "")
@ -1911,6 +1965,7 @@ day = :d""", d=yesterday)
except: except:
print "Error in %s" % plugin print "Error in %s" % plugin
traceback.print_exc() traceback.print_exc()
self.checkForUpdatedPlugins()
def rebuildPluginsMenu(self): def rebuildPluginsMenu(self):
if getattr(self, "pluginActions", None) is None: if getattr(self, "pluginActions", None) is None:
@ -1922,6 +1977,8 @@ day = :d""", d=yesterday)
for fname in all: for fname in all:
enabled = fname.endswith(".py") enabled = fname.endswith(".py")
p = re.sub("\.py(\.off)?", "", fname) p = re.sub("\.py(\.off)?", "", fname)
if p+".py" in self.registeredPlugins:
p = self.registeredPlugins[p+".py"]['name']
a = QAction(p, self) a = QAction(p, self)
a.setCheckable(True) a.setCheckable(True)
a.setChecked(enabled) a.setChecked(enabled)
@ -1942,13 +1999,16 @@ day = :d""", d=yesterday)
return [p for p in os.listdir(self.pluginsFolder()) return [p for p in os.listdir(self.pluginsFolder())
if p.endswith(".py.off") or p.endswith(".py")] if p.endswith(".py.off") or p.endswith(".py")]
def onOpenPluginFolder(self): def onOpenPluginFolder(self, path=None):
if path is None:
path = self.pluginsFolder()
if sys.platform == "win32": if sys.platform == "win32":
# reuse our process handling code from latex # reuse our process handling code from latex
anki.latex.call(["explorer", self.pluginsFolder().encode( anki.latex.call(["explorer", path.encode(
sys.getfilesystemencoding())]) sys.getfilesystemencoding())],
wait=False)
else: else:
QDesktopServices.openUrl(QUrl("file://" + self.pluginsFolder())) QDesktopServices.openUrl(QUrl("file://" + path))
def onGetPlugins(self): def onGetPlugins(self):
QDesktopServices.openUrl(QUrl("http://ichi2.net/anki/wiki/Plugins")) QDesktopServices.openUrl(QUrl("http://ichi2.net/anki/wiki/Plugins"))
@ -1980,6 +2040,14 @@ day = :d""", d=yesterday)
self.enablePlugin(plugin) self.enablePlugin(plugin)
self.rebuildPluginsMenu() self.rebuildPluginsMenu()
def registerPlugin(self, name, updateId):
src = os.path.basename(inspect.getfile(inspect.currentframe(1)))
self.registeredPlugins[src] = {'name': name,
'id': updateId}
def checkForUpdatedPlugins(self):
pass
# Font localisation # Font localisation
########################################################################## ##########################################################################
@ -2011,9 +2079,9 @@ day = :d""", d=yesterday)
########################################################################## ##########################################################################
def setupProgressInfo(self): def setupProgressInfo(self):
addHook("startProgress", self.onStartProgress) addHook("startProgress", self.startProgress)
addHook("updateProgress", self.onUpdateProgress) addHook("updateProgress", self.updateProgress)
addHook("finishProgress", self.onFinishProgress) addHook("finishProgress", self.finishProgress)
addHook("dbProgress", self.onDbProgress) addHook("dbProgress", self.onDbProgress)
addHook("dbFinished", self.onDbFinished) addHook("dbFinished", self.onDbFinished)
self.progressParent = None self.progressParent = None
@ -2024,7 +2092,7 @@ day = :d""", d=yesterday)
def setProgressParent(self, parent): def setProgressParent(self, parent):
self.progressParent = parent self.progressParent = parent
def onStartProgress(self, max=100, min=0, title=None): def startProgress(self, max=0, min=0, title=None):
if self.mainThread != QThread.currentThread(): if self.mainThread != QThread.currentThread():
return return
self.setBusy() self.setBusy()
@ -2034,14 +2102,14 @@ day = :d""", d=yesterday)
p = ui.utils.ProgressWin(parent, max, min, title) p = ui.utils.ProgressWin(parent, max, min, title)
self.progressWins.append(p) self.progressWins.append(p)
def onUpdateProgress(self, label=None, value=None): def updateProgress(self, label=None, value=None):
if self.mainThread != QThread.currentThread(): if self.mainThread != QThread.currentThread():
return return
if self.progressWins: if self.progressWins:
self.progressWins[-1].update(label, value) self.progressWins[-1].update(label, value)
self.app.processEvents() self.app.processEvents()
def onFinishProgress(self): def finishProgress(self):
if self.mainThread != QThread.currentThread(): if self.mainThread != QThread.currentThread():
return return
if self.progressWins: if self.progressWins:
@ -2077,6 +2145,10 @@ day = :d""", d=yesterday)
def onCheckDB(self): def onCheckDB(self):
"True if no problems" "True if no problems"
if self.errorOccurred:
ui.utils.showWarning(_(
"Please restart Anki before checking the DB."))
return
if not ui.utils.askUser(_("""\ if not ui.utils.askUser(_("""\
This operation will find and fix some common problems.<br> This operation will find and fix some common problems.<br>
<br> <br>
@ -2098,7 +2170,7 @@ Proceed?""")):
def onOptimizeDB(self): def onOptimizeDB(self):
size = self.deck.optimize() size = self.deck.optimize()
ui.utils.showInfo("Database optimized.\nShrunk by %dKB" % (size/1024.0)) ui.utils.showInfo(_("Database optimized.\nShrunk by %dKB") % (size/1024.0))
def onCheckMediaDB(self): def onCheckMediaDB(self):
mb = QMessageBox(self) mb = QMessageBox(self)

View file

@ -492,7 +492,7 @@ order by n""", id=card.id)
self.deck.setModified() self.deck.setModified()
# if changed, reset deck # if changed, reset deck
if self.origModTime != self.deck.modified: if self.origModTime != self.deck.modified:
self.deck.updateCardTags() self.deck.updateTagsForModel(self.m)
ankiqt.mw.reset() ankiqt.mw.reset()
if self.onFinish: if self.onFinish:
self.onFinish() self.onFinish()

View file

@ -28,8 +28,10 @@ class Preferences(QDialog):
self.supportedLanguages = [ self.supportedLanguages = [
(_("English"), "en_US"), (_("English"), "en_US"),
(_("Brazillian Portuguese"), "pt_BR"), (_("Brazillian Portuguese"), "pt_BR"),
(_("Chinese Traditional"), "zh_TW"), (_("Chinese - Simplified"), "zh_CN"),
(_("Chinese - Traditional"), "zh_TW"),
(_("Czech"), "cs_CZ"), (_("Czech"), "cs_CZ"),
(_("Estonian"), "ee_EE"),
(_("Finnish"), "fi_FI"), (_("Finnish"), "fi_FI"),
(_("French"), "fr_FR"), (_("French"), "fr_FR"),
(_("German"), "de_DE"), (_("German"), "de_DE"),
@ -111,6 +113,7 @@ class Preferences(QDialog):
self.dialog.splitQA.setChecked(self.config['splitQA']) self.dialog.splitQA.setChecked(self.config['splitQA'])
self.dialog.addZeroSpace.setChecked(self.config['addZeroSpace']) self.dialog.addZeroSpace.setChecked(self.config['addZeroSpace'])
self.dialog.alternativeTheme.setChecked(self.config['alternativeTheme']) self.dialog.alternativeTheme.setChecked(self.config['alternativeTheme'])
self.dialog.showProgress.setChecked(self.config['showProgress'])
def updateAdvanced(self): def updateAdvanced(self):
self.config['showTrayIcon'] = self.dialog.showTray.isChecked() self.config['showTrayIcon'] = self.dialog.showTray.isChecked()
@ -121,6 +124,7 @@ class Preferences(QDialog):
self.config['splitQA'] = self.dialog.splitQA.isChecked() self.config['splitQA'] = self.dialog.splitQA.isChecked()
self.config['addZeroSpace'] = self.dialog.addZeroSpace.isChecked() self.config['addZeroSpace'] = self.dialog.addZeroSpace.isChecked()
self.config['alternativeTheme'] = self.dialog.alternativeTheme.isChecked() self.config['alternativeTheme'] = self.dialog.alternativeTheme.isChecked()
self.config['showProgress'] = self.dialog.showProgress.isChecked()
def codeToIndex(self, code): def codeToIndex(self, code):
n = 0 n = 0

View file

@ -74,7 +74,8 @@ class StatusView(object):
# remaining & eta # remaining & eta
self.remText = QLabel() self.remText = QLabel()
self.addWidget(self.remText, 0) self.addWidget(self.remText, 0)
self.addWidget(self.vertSep(), 0) sep1 = self.vertSep()
self.addWidget(sep1, 0)
self.etaText = QLabel() self.etaText = QLabel()
self.etaText.setToolTip(_( self.etaText.setToolTip(_(
"<h1>Estimated time</h1>" "<h1>Estimated time</h1>"
@ -82,7 +83,8 @@ class StatusView(object):
"at your current pace.")) "at your current pace."))
self.addWidget(self.etaText, 0) self.addWidget(self.etaText, 0)
# progress&retention # progress&retention
self.addWidget(self.vertSep(), 0) sep2 = self.vertSep()
self.addWidget(sep2, 0)
vbox = QVBoxLayout() vbox = QVBoxLayout()
vbox.setSpacing(0) vbox.setSpacing(0)
vbox.setMargin(0) vbox.setMargin(0)
@ -105,13 +107,23 @@ class StatusView(object):
self.retentionBar.setStyle(self.plastiqueStyle) self.retentionBar.setStyle(self.plastiqueStyle)
self.addWidget(self.combinedBar, 0) self.addWidget(self.combinedBar, 0)
# timer # timer
self.addWidget(self.vertSep(), 0) sep3 = self.vertSep()
self.addWidget(sep3, 0)
self.timer = QClickableLabel() self.timer = QClickableLabel()
self.timer.setText("00:00") self.timer.setText("00:00")
self.addWidget(self.timer) self.addWidget(self.timer)
self.redraw() self.redraw()
if not self.main.config['showTimer']: if not self.main.config['showTimer']:
self.timer.setShown(False) self.timer.setShown(False)
if not self.main.config['showProgress']:
self.progressBar.hide()
self.retentionBar.hide()
self.timer.hide()
self.etaText.hide()
self.remText.hide()
sep1.hide()
sep2.hide()
sep3.hide()
def addWidget(self, w, stretch=0): def addWidget(self, w, stretch=0):
self.statusbar.addWidget(w, stretch) self.statusbar.addWidget(w, stretch)
@ -164,7 +176,7 @@ class StatusView(object):
"There are <b>%(rev)d</b> cards awaiting review.<br>" "There are <b>%(rev)d</b> cards awaiting review.<br>"
"There are <b>%(new)d</b> new cards due today.<br><br>" "There are <b>%(new)d</b> new cards due today.<br><br>"
"There are <b>%(new2)d</b> new cards in total.<br>" "There are <b>%(new2)d</b> new cards in total.<br>"
"There are <b>%(spaced)d</b> spaced cards.") % stats) "There are <b>%(spaced)d</b> delayed cards.") % stats)
# eta # eta
self.etaText.setText(_("ETA: <b>%(timeLeft)s</b>") % stats) self.etaText.setText(_("ETA: <b>%(timeLeft)s</b>") % stats)
# retention & progress bars # retention & progress bars
@ -177,31 +189,27 @@ class StatusView(object):
self.progressBar.setPalette(p) self.progressBar.setPalette(p)
self.progressBar.setValue(stats['dYesTotal%']) self.progressBar.setValue(stats['dYesTotal%'])
# tooltips # tooltips
stats['avgTime'] = anki.utils.fmtTimeSpan(stats['dAverageTime'], point=2) tip = "<h1>" + _("Performance") + "</h1>"
stats['revTime'] = anki.utils.fmtTimeSpan(stats['dReviewTime'], point=2) tip += _("""The top bar shows your performance today. The bottom bar shows your<br>
tip = _("""<h1>Performance</h1>
The top bar shows your performance today. The bottom bar shows your<br>
performance on cards scheduled for 21 days or more. The bottom bar should<br> performance on cards scheduled for 21 days or more. The bottom bar should<br>
generally be between 80-95%% - lower and you're forgetting mature cards<br> generally be between 80-95% - lower and you're forgetting mature cards<br>
too often, higher and you're spending too much time reviewing. too often, higher and you're spending too much time reviewing.""")
<h2>Reviews today</h2> tip += "<h2>" + _("Reviews today") + "</h2>"
<b>Correct today: %(dYesTotal%)0.1f%% tip += "<b>" + _("Correct today: ") + anki.utils.fmtPercentage(stats['dYesTotal%'], point=1)
(%(dYesTotal)d of %(dTotal)d)</b><br> tip += " (" + _("%(partOf)d of %(totalSum)d") % {'partOf' : stats['dYesTotal'], 'totalSum' : stats['dTotal'] } + ")</b><br>"
Average time per answer: %(avgTime)s<br> tip += _("Average time per answer: ") + anki.utils.fmtTimeSpan(stats['dAverageTime'], point=2) +"<br>"
Total review time: %(revTime)s""") % stats tip += _("Total review time: ") + anki.utils.fmtTimeSpan(stats['dReviewTime'], point=2)
stats['avgTime'] = anki.utils.fmtTimeSpan(stats['gAverageTime'], point=2) tip += "<h2>" + _("All Reviews") + "</h2>"
stats['revTime'] = anki.utils.fmtTimeSpan(stats['gReviewTime'], point=2) tip += "<b>" + _("Correct over a month: ") + anki.utils.fmtPercentage(stats['gMatureYes%'], point=1)
tip += _("""<h2>All Reviews</h2> tip += " (" + _("%(partOf)d of %(totalSum)d") % {'partOf' : stats['gMatureYes'], 'totalSum' : stats['gMatureTotal'] } + ")</b><br>"
<b>Correct over a month: %(gMatureYes%)0.1f%% tip += _("Average time per answer: ") + anki.utils.fmtTimeSpan(stats['gAverageTime'], point=2) +"<br>"
(%(gMatureYes)d of %(gMatureTotal)d)</b><br> tip += _("Total review time: ") + anki.utils.fmtTimeSpan(stats['gReviewTime'], point=2) +"<br>"
Average time per answer: %(avgTime)s<br> tip += _("Correct under a month: ") + anki.utils.fmtPercentage(stats['gYoungYes%'], point=1)
Total review time: %(revTime)s<br> tip += " (" + _("%(partOf)d of %(totalSum)d") % {'partOf' : stats['gYoungYes'], 'totalSum' : stats['gYoungTotal'] } + ")</b><br>"
Correct under a month: %(gYoungYes%)0.1f%% tip += _("Correct first time: ") + anki.utils.fmtPercentage(stats['gNewYes%'], point=1)
(%(gYoungYes)d of %(gYoungTotal)d)<br> tip += " (" + _("%(partOf)d of %(totalSum)d") % {'partOf' : stats['gNewYes'], 'totalSum' : stats['gNewTotal'] } + ")</b><br>"
Correct first time: %(gNewYes%)0.1f%% tip += _("Total correct: ") + anki.utils.fmtPercentage(stats['gYesTotal%'], point=1)
(%(gNewYes)d of %(gNewTotal)d)<br> tip += " (" + _("%(partOf)d of %(totalSum)d") % {'partOf' : stats['gYesTotal'], 'totalSum' : stats['gTotal'] } + ")</b><br>"
Total correct: %(gYesTotal%)0.1f%%
(%(gYesTotal)d of %(gTotal)d)""") % stats
self.combinedBar.setToolTip(tip) self.combinedBar.setToolTip(tip)
if self.main.config['showTimer']: if self.main.config['showTimer']:
self.drawTimer() self.drawTimer()

View file

@ -52,7 +52,9 @@ class Sync(QThread):
else: else:
msg=_("""\ msg=_("""\
Syncing failed. Please try again in a few minutes. Syncing failed. Please try again in a few minutes.
If the problem persists, please report it on the forum.""") If the problem persists, please report it on the forum.
Error: %s""" % `error`)
return msg return msg
def connect(self, *args): def connect(self, *args):

View file

@ -56,7 +56,7 @@ class View(object):
self.haveTop = (self.main.lastCard and ( self.haveTop = (self.main.lastCard and (
self.main.config['showLastCardContent'] or self.main.config['showLastCardContent'] or
self.main.config['showLastCardInterval'])) or ( self.main.config['showLastCardInterval'])) or (
self.main.currentCard and self.main.currentCard.due > time.time()) self.needFutureWarning())
self.drawRule = (self.main.config['qaDivider'] and self.drawRule = (self.main.config['qaDivider'] and
self.main.currentCard and self.main.currentCard and
not self.main.currentCard.cardModel.questionInAnswer) not self.main.currentCard.cardModel.questionInAnswer)
@ -204,13 +204,18 @@ class View(object):
self.drawLastCard() self.drawLastCard()
self.buffer += "</center>" self.buffer += "</center>"
def drawFutureWarning(self): def needFutureWarning(self):
if not self.main.currentCard: if not self.main.currentCard:
return return
if self.main.currentCard.due <= time.time(): if self.main.currentCard.due <= time.time():
return return
if self.main.currentCard.due - time.time() <= self.main.deck.delay0: if self.main.currentCard.due - time.time() <= self.main.deck.delay0:
return return
return True
def drawFutureWarning(self):
if not self.needFutureWarning():
return
self.write("<span style='color: %s'>" % futureWarningColour + self.write("<span style='color: %s'>" % futureWarningColour +
_("This card was due in %s.") % fmtTimeSpan( _("This card was due in %s.") % fmtTimeSpan(
self.main.currentCard.due - time.time()) + self.main.currentCard.due - time.time()) +
@ -247,8 +252,8 @@ class View(object):
########################################################################## ##########################################################################
def drawWelcomeMessage(self): def drawWelcomeMessage(self):
self.main.mainWin.welcomeText.setText(_("""\ self.main.mainWin.welcomeText.setText("""\
<h1>Welcome to Anki!</h1> <h1>%(welcome)s</h1>
<p> <p>
<table> <table>
@ -256,8 +261,8 @@ class View(object):
<td width=50> <td width=50>
<a href="welcome:addfacts"><img src=":/icons/list-add.png"></a> <a href="welcome:addfacts"><img src=":/icons/list-add.png"></a>
</td> </td>
<td valign=middle><h1><a href="welcome:addfacts">Add material</a></h1> <td valign=middle><h1><a href="welcome:addfacts">%(add)s</a></h1>
Start adding your own material.</td> %(start)s</td>
</tr> </tr>
</table> </table>
@ -269,31 +274,30 @@ Start adding your own material.</td>
<td> <td>
<a href="welcome:open"><img src=":/icons/document-open.png"></a> <a href="welcome:open"><img src=":/icons/document-open.png"></a>
</td> </td>
<td valign=middle><h2><a href="welcome:open">Open Local Deck</a></h2></td> <td valign=middle><h2><a href="welcome:open">%(local)s</a></h2></td>
</tr>
<tr>
<td>
<a href="welcome:openrem"><img src=":/icons/document-open-remote.png"></a>
</td>
<td valign=middle><h2><a href="welcome:openrem">Open Online Deck</a></h2></td>
</tr> </tr>
<tr> <tr>
<td width=50> <td width=50>
<a href="welcome:sample"><img src=":/icons/anki.png"></a> <a href="welcome:sample"><img src=":/icons/anki.png"></a>
</td> </td>
<td valign=middle><h2><a href="welcome:sample">Open Sample Deck</a></h2></td> <td valign=middle><h2><a href="welcome:sample">%(dl_shared)s</a></h2></td>
</tr> </tr>
<tr> <tr>
<td width=50> <td>
<a href="welcome:more"><img src=":/icons/khtml_kget.png"></a> <a href="welcome:openrem"><img src=":/icons/document-open-remote.png"></a>
</td> </td>
<td valign=middle><h2><a href="welcome:more">Get More Decks</a></h2></td> <td valign=middle><h2><a href="welcome:openrem">%(dl_personal)s</a></h2></td>
</tr> </tr>
</table>""")) </table>""" % \
{"welcome":_("Welcome to Anki!"),
"add":_("Add material"),
"start":_("Start adding your own material."),
"local":_("Open Local Deck"),
"dl_shared":_("Download Shared Deck"),
"dl_personal":_("Download Personal Deck")})
def drawDeckFinishedMessage(self): def drawDeckFinishedMessage(self):
"Tell the user the deck is finished." "Tell the user the deck is finished."

View file

@ -5,8 +5,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>224</width> <width>410</width>
<height>310</height> <height>447</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy" > <property name="sizePolicy" >

View file

@ -13,6 +13,14 @@
<string>Edit Items</string> <string>Edit Items</string>
</property> </property>
<widget class="QWidget" name="centralwidget" > <widget class="QWidget" name="centralwidget" >
<property name="geometry" >
<rect>
<x>0</x>
<y>23</y>
<width>599</width>
<height>439</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout" > <layout class="QVBoxLayout" name="verticalLayout" >
<property name="spacing" > <property name="spacing" >
<number>0</number> <number>0</number>
@ -162,7 +170,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>599</width> <width>599</width>
<height>25</height> <height>23</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuEdit" > <widget class="QMenu" name="menuEdit" >
@ -226,7 +234,7 @@
<string>Delete</string> <string>Delete</string>
</property> </property>
<property name="shortcut" > <property name="shortcut" >
<string>Del</string> <string>Ctrl+Del</string>
</property> </property>
</action> </action>
<action name="actionAddTag" > <action name="actionAddTag" >

View file

@ -300,8 +300,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>960</width> <width>348</width>
<height>480</height> <height>317</height>
</rect> </rect>
</property> </property>
<attribute name="title" > <attribute name="title" >
@ -556,6 +556,9 @@
<property name="text" > <property name="text" >
<string>Close</string> <string>Close</string>
</property> </property>
<property name="autoDefault" >
<bool>false</bool>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -613,6 +616,31 @@
</layout> </layout>
</widget> </widget>
<tabstops> <tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>cardList</tabstop>
<tabstop>questionFont</tabstop>
<tabstop>questionSize</tabstop>
<tabstop>questionColour</tabstop>
<tabstop>questionAlign</tabstop>
<tabstop>answerFont</tabstop>
<tabstop>answerSize</tabstop>
<tabstop>answerColour</tabstop>
<tabstop>answerAlign</tabstop>
<tabstop>backgroundColour</tabstop>
<tabstop>fieldList</tabstop>
<tabstop>useFamily</tabstop>
<tabstop>fontFamily</tabstop>
<tabstop>useSize</tabstop>
<tabstop>fontSize</tabstop>
<tabstop>useColour</tabstop>
<tabstop>fontColour</tabstop>
<tabstop>useFamilyEdit</tabstop>
<tabstop>fontFamilyEdit</tabstop>
<tabstop>useSizeEdit</tabstop>
<tabstop>fontSizeEdit</tabstop>
<tabstop>helpButton</tabstop>
<tabstop>preview</tabstop>
<tabstop>closeButton</tabstop>
<tabstop>question</tabstop> <tabstop>question</tabstop>
<tabstop>answer</tabstop> <tabstop>answer</tabstop>
</tabstops> </tabstops>

View file

@ -58,6 +58,19 @@
</item> </item>
</layout> </layout>
</item> </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>
<item> <item>
<widget class="QDialogButtonBox" name="buttonBox" > <widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" > <property name="orientation" >

View file

@ -18,32 +18,22 @@
<item row="0" column="0" > <item row="0" column="0" >
<widget class="QLabel" name="label" > <widget class="QLabel" name="label" >
<property name="text" > <property name="text" >
<string>Find</string> <string>&lt;b>Find&lt;/b>:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" > <item row="0" column="1" >
<widget class="QLineEdit" name="find" /> <widget class="QLineEdit" name="find" />
</item> </item>
<item row="1" column="0" > <item row="2" column="0" >
<widget class="QLabel" name="label_2" > <widget class="QLabel" name="label_2" >
<property name="text" > <property name="text" >
<string>Replace</string> <string>&lt;b>Replace With&lt;/b>:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1" >
<widget class="QLineEdit" name="replace" />
</item>
<item row="2" column="1" > <item row="2" column="1" >
<widget class="QComboBox" name="type" /> <widget class="QLineEdit" name="replace" />
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Search</string>
</property>
</widget>
</item> </item>
<item row="3" column="1" > <item row="3" column="1" >
<widget class="QCheckBox" name="re" > <widget class="QCheckBox" name="re" >
@ -52,6 +42,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>&lt;b>In&lt;/b>:</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QComboBox" name="field" />
</item>
</layout> </layout>
</item> </item>
<item> <item>
@ -81,8 +81,8 @@
</widget> </widget>
<tabstops> <tabstops>
<tabstop>find</tabstop> <tabstop>find</tabstop>
<tabstop>field</tabstop>
<tabstop>replace</tabstop> <tabstop>replace</tabstop>
<tabstop>type</tabstop>
<tabstop>re</tabstop> <tabstop>re</tabstop>
<tabstop>buttonBox</tabstop> <tabstop>buttonBox</tabstop>
</tabstops> </tabstops>
@ -95,8 +95,8 @@
<slot>accept()</slot> <slot>accept()</slot>
<hints> <hints>
<hint type="sourcelabel" > <hint type="sourcelabel" >
<x>252</x> <x>256</x>
<y>127</y> <y>154</y>
</hint> </hint>
<hint type="destinationlabel" > <hint type="destinationlabel" >
<x>157</x> <x>157</x>
@ -111,8 +111,8 @@
<slot>reject()</slot> <slot>reject()</slot>
<hints> <hints>
<hint type="sourcelabel" > <hint type="sourcelabel" >
<x>286</x> <x>290</x>
<y>127</y> <y>154</y>
</hint> </hint>
<hint type="destinationlabel" > <hint type="destinationlabel" >
<x>286</x> <x>286</x>

133
designer/getshared.ui Normal file
View file

@ -0,0 +1,133 @@
<ui version="4.0" >
<class>Dialog</class>
<widget class="QDialog" name="Dialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>517</width>
<height>411</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout" >
<item>
<layout class="QHBoxLayout" name="horizontalLayout" >
<item>
<widget class="QLabel" name="searchLabel" >
<property name="text" >
<string>Search:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="search" />
</item>
</layout>
</item>
<item>
<widget class="QSplitter" name="splitter" >
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<widget class="QTableWidget" name="table" />
<widget class="QScrollArea" name="scrollArea" >
<property name="frameShape" >
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Plain</enum>
</property>
<property name="verticalScrollBarPolicy" >
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="horizontalScrollBarPolicy" >
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>494</width>
<height>54</height>
</rect>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" >
<item>
<widget class="QLabel" name="bottomLabel" >
<property name="maximumSize" >
<size>
<width>430</width>
<height>16777215</height>
</size>
</property>
<property name="text" >
<string>Loading...</string>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
<property name="textInteractionFlags" >
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<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

@ -6,7 +6,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>723</width> <width>723</width>
<height>504</height> <height>513</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy" > <property name="sizePolicy" >
@ -28,7 +28,7 @@
<x>0</x> <x>0</x>
<y>69</y> <y>69</y>
<width>723</width> <width>723</width>
<height>415</height> <height>424</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy" > <property name="sizePolicy" >
@ -145,8 +145,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>422</width> <width>100</width>
<height>57</height> <height>30</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout" > <layout class="QVBoxLayout" name="verticalLayout" >
@ -224,8 +224,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>422</width> <width>100</width>
<height>57</height> <height>30</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_3" > <layout class="QVBoxLayout" name="verticalLayout_3" >
@ -371,8 +371,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>422</width> <width>100</width>
<height>57</height> <height>30</height>
</rect> </rect>
</property> </property>
</widget> </widget>
@ -397,7 +397,7 @@
</sizepolicy> </sizepolicy>
</property> </property>
<property name="currentIndex" > <property name="currentIndex" >
<number>0</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="blankPage" > <widget class="QWidget" name="blankPage" >
<property name="geometry" > <property name="geometry" >
@ -405,7 +405,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>446</width> <width>446</width>
<height>358</height> <height>367</height>
</rect> </rect>
</property> </property>
</widget> </widget>
@ -415,7 +415,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>446</width> <width>446</width>
<height>358</height> <height>367</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_5" > <layout class="QVBoxLayout" name="verticalLayout_5" >
@ -440,7 +440,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>446</width> <width>446</width>
<height>358</height> <height>367</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2" > <layout class="QVBoxLayout" name="verticalLayout_2" >
@ -478,7 +478,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>446</width> <width>446</width>
<height>358</height> <height>367</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_4" > <layout class="QVBoxLayout" name="verticalLayout_4" >
@ -530,7 +530,7 @@
<item> <item>
<widget class="QLabel" name="optionsLabel" > <widget class="QLabel" name="optionsLabel" >
<property name="text" > <property name="text" >
<string>xxx</string> <string/>
</property> </property>
<property name="textInteractionFlags" > <property name="textInteractionFlags" >
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set> <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
@ -736,6 +736,12 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="minimumSize" >
<size>
<width>0</width>
<height>26</height>
</size>
</property>
<property name="text" > <property name="text" >
<string>Review</string> <string>Review</string>
</property> </property>
@ -743,10 +749,22 @@
<iconset resource="../icons.qrc" > <iconset resource="../icons.qrc" >
<normaloff>:/icons/player-time.png</normaloff>:/icons/player-time.png</iconset> <normaloff>:/icons/player-time.png</normaloff>:/icons/player-time.png</iconset>
</property> </property>
<property name="autoDefault" >
<bool>true</bool>
</property>
<property name="default" >
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
<item row="0" column="1" > <item row="0" column="1" >
<widget class="QPushButton" name="optionsButton" > <widget class="QPushButton" name="optionsButton" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>26</height>
</size>
</property>
<property name="text" > <property name="text" >
<string>More>></string> <string>More>></string>
</property> </property>
@ -763,6 +781,12 @@
</item> </item>
<item row="0" column="2" > <item row="0" column="2" >
<widget class="QPushButton" name="optionsHelpButton" > <widget class="QPushButton" name="optionsHelpButton" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>26</height>
</size>
</property>
<property name="text" > <property name="text" >
<string>Help</string> <string>Help</string>
</property> </property>
@ -813,7 +837,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>446</width> <width>446</width>
<height>358</height> <height>367</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_8" > <layout class="QVBoxLayout" name="verticalLayout_8" >
@ -878,7 +902,7 @@
<item> <item>
<widget class="QLabel" name="congratsLabel" > <widget class="QLabel" name="congratsLabel" >
<property name="text" > <property name="text" >
<string>xxx</string> <string/>
</property> </property>
<property name="margin" > <property name="margin" >
<number>0</number> <number>0</number>
@ -1174,7 +1198,6 @@
<addaction name="actionReportbug" /> <addaction name="actionReportbug" />
<addaction name="actionForum" /> <addaction name="actionForum" />
<addaction name="actionReleaseNotes" /> <addaction name="actionReleaseNotes" />
<addaction name="actionGetMoreDecks" />
<addaction name="separator" /> <addaction name="separator" />
<addaction name="actionDonate" /> <addaction name="actionDonate" />
<addaction name="actionAbout" /> <addaction name="actionAbout" />
@ -1208,10 +1231,23 @@
<normaloff>:/icons/document-open-recent.png</normaloff>:/icons/document-open-recent.png</iconset> <normaloff>:/icons/document-open-recent.png</normaloff>:/icons/document-open-recent.png</iconset>
</property> </property>
</widget> </widget>
<widget class="QMenu" name="menuDownload" >
<property name="title" >
<string>&amp;Download...</string>
</property>
<property name="icon" >
<iconset resource="../icons.qrc" >
<normaloff>:/icons/document-open-remote.png</normaloff>:/icons/document-open-remote.png</iconset>
</property>
<addaction name="actionOpenOnline" />
<addaction name="separator" />
<addaction name="actionDownloadSharedDeck" />
<addaction name="actionDownloadSharedPlugin" />
</widget>
<addaction name="actionNew" /> <addaction name="actionNew" />
<addaction name="actionOpen" /> <addaction name="actionOpen" />
<addaction name="menuOpenRecent" /> <addaction name="menuOpenRecent" />
<addaction name="actionOpenOnline" /> <addaction name="menuDownload" />
<addaction name="actionImport" /> <addaction name="actionImport" />
<addaction name="separator" /> <addaction name="separator" />
<addaction name="actionSave" /> <addaction name="actionSave" />
@ -1288,7 +1324,6 @@
<addaction name="actionDisableAllPlugins" /> <addaction name="actionDisableAllPlugins" />
<addaction name="separator" /> <addaction name="separator" />
</widget> </widget>
<addaction name="actionGetPlugins" />
<addaction name="actionOpenPluginFolder" /> <addaction name="actionOpenPluginFolder" />
<addaction name="separator" /> <addaction name="separator" />
<addaction name="menuStartup" /> <addaction name="menuStartup" />
@ -1313,7 +1348,7 @@
<property name="geometry" > <property name="geometry" >
<rect> <rect>
<x>0</x> <x>0</x>
<y>484</y> <y>493</y>
<width>723</width> <width>723</width>
<height>20</height> <height>20</height>
</rect> </rect>
@ -1427,6 +1462,9 @@
<property name="shortcut" > <property name="shortcut" >
<string>Ctrl+S</string> <string>Ctrl+S</string>
</property> </property>
<property name="shortcutContext" >
<enum>Qt::ApplicationShortcut</enum>
</property>
</action> </action>
<action name="actionSyncdeck" > <action name="actionSyncdeck" >
<property name="icon" > <property name="icon" >
@ -1762,15 +1800,6 @@
<string>Check Media Database...</string> <string>Check Media Database...</string>
</property> </property>
</action> </action>
<action name="actionOpenOnline" >
<property name="icon" >
<iconset resource="../icons.qrc" >
<normaloff>:/icons/document-open-remote.png</normaloff>:/icons/document-open-remote.png</iconset>
</property>
<property name="text" >
<string>Open On&amp;line...</string>
</property>
</action>
<action name="actionCram" > <action name="actionCram" >
<property name="icon" > <property name="icon" >
<iconset resource="../icons.qrc" > <iconset resource="../icons.qrc" >
@ -1823,15 +1852,6 @@
<string>Active &amp;Tags...</string> <string>Active &amp;Tags...</string>
</property> </property>
</action> </action>
<action name="actionGetMoreDecks" >
<property name="icon" >
<iconset resource="../icons.qrc" >
<normaloff>:/icons/download.png</normaloff>:/icons/download.png</iconset>
</property>
<property name="text" >
<string>&amp;Get More Decks...</string>
</property>
</action>
<action name="actionEditCurrent" > <action name="actionEditCurrent" >
<property name="icon" > <property name="icon" >
<iconset resource="../icons.qrc" > <iconset resource="../icons.qrc" >
@ -1861,6 +1881,9 @@
<property name="text" > <property name="text" >
<string>&amp;Delete Card</string> <string>&amp;Delete Card</string>
</property> </property>
<property name="shortcut" >
<string>Ctrl+Del</string>
</property>
</action> </action>
<action name="action_Delete_Fact" > <action name="action_Delete_Fact" >
<property name="text" > <property name="text" >
@ -1904,6 +1927,34 @@
<string>&amp;Record Noise Profile...</string> <string>&amp;Record Noise Profile...</string>
</property> </property>
</action> </action>
<action name="actionGetShared" >
<property name="text" >
<string>Get Shared...</string>
</property>
<property name="statusTip" >
<string>Open a pre-made deck or plugin</string>
</property>
</action>
<action name="actionShare" >
<property name="text" >
<string>Share...</string>
</property>
</action>
<action name="actionOpenOnline" >
<property name="text" >
<string>Personal Deck</string>
</property>
</action>
<action name="actionDownloadSharedDeck" >
<property name="text" >
<string>Shared Deck</string>
</property>
</action>
<action name="actionDownloadSharedPlugin" >
<property name="text" >
<string>Shared Plugin</string>
</property>
</action>
</widget> </widget>
<tabstops> <tabstops>
<tabstop>newPerDay</tabstop> <tabstop>newPerDay</tabstop>
@ -1921,11 +1972,11 @@
<tabstop>help</tabstop> <tabstop>help</tabstop>
<tabstop>welcomeText</tabstop> <tabstop>welcomeText</tabstop>
<tabstop>showAnswerButton</tabstop> <tabstop>showAnswerButton</tabstop>
<tabstop>saveEditorButton</tabstop>
<tabstop>easeButton2</tabstop>
<tabstop>easeButton1</tabstop> <tabstop>easeButton1</tabstop>
<tabstop>easeButton2</tabstop>
<tabstop>easeButton3</tabstop> <tabstop>easeButton3</tabstop>
<tabstop>easeButton4</tabstop> <tabstop>easeButton4</tabstop>
<tabstop>saveEditorButton</tabstop>
</tabstops> </tabstops>
<resources> <resources>
<include location="../icons.qrc" /> <include location="../icons.qrc" />

View file

@ -97,6 +97,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="showProgress" >
<property name="text" >
<string>Show information in status bar</string>
</property>
</widget>
</item>
<item> <item>
<spacer name="verticalSpacer" > <spacer name="verticalSpacer" >
<property name="orientation" > <property name="orientation" >
@ -110,6 +117,16 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Some settings will take effect after you restart Anki.</string>
</property>
<property name="alignment" >
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_2" > <widget class="QWidget" name="tab_2" >
@ -318,7 +335,7 @@
<item row="2" column="0" > <item row="2" column="0" >
<widget class="QLabel" name="label_6" > <widget class="QLabel" name="label_6" >
<property name="text" > <property name="text" >
<string>&lt;h1>Advanced settings&lt;/h1>Some settings require a restart.</string> <string>&lt;h1>Advanced settings&lt;/h1></string>
</property> </property>
</widget> </widget>
</item> </item>
@ -388,6 +405,16 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<widget class="QLabel" name="label_8" >
<property name="text" >
<string>Some settings will take effect after you restart Anki.</string>
</property>
<property name="alignment" >
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
@ -411,6 +438,7 @@
<tabstop>showDivider</tabstop> <tabstop>showDivider</tabstop>
<tabstop>splitQA</tabstop> <tabstop>splitQA</tabstop>
<tabstop>showEstimates</tabstop> <tabstop>showEstimates</tabstop>
<tabstop>showProgress</tabstop>
<tabstop>saveWhenClosing</tabstop> <tabstop>saveWhenClosing</tabstop>
<tabstop>saveAfterEvery</tabstop> <tabstop>saveAfterEvery</tabstop>
<tabstop>saveAfterEveryNum</tabstop> <tabstop>saveAfterEveryNum</tabstop>
@ -422,7 +450,9 @@
<tabstop>syncOnClose</tabstop> <tabstop>syncOnClose</tabstop>
<tabstop>alternativeTheme</tabstop> <tabstop>alternativeTheme</tabstop>
<tabstop>showTimer</tabstop> <tabstop>showTimer</tabstop>
<tabstop>showTray</tabstop>
<tabstop>showStudyOptions</tabstop> <tabstop>showStudyOptions</tabstop>
<tabstop>addZeroSpace</tabstop>
<tabstop>buttonBox</tabstop> <tabstop>buttonBox</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>

134
designer/share.ui Normal file
View file

@ -0,0 +1,134 @@
<ui version="4.0" >
<class>Dialog</class>
<widget class="QDialog" name="Dialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>517</width>
<height>411</height>
</rect>
</property>
<property name="windowTitle" >
<string>Get Shared Decks/Plugins</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" >
<item>
<layout class="QHBoxLayout" name="horizontalLayout" >
<item>
<widget class="QLabel" name="searchLabel" >
<property name="text" >
<string>Search:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="search" />
</item>
<item>
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Type:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="type" />
</item>
</layout>
</item>
<item>
<widget class="QSplitter" name="splitter" >
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<widget class="QTableWidget" name="table" />
<widget class="QScrollArea" name="scrollArea" >
<property name="frameShape" >
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Plain</enum>
</property>
<property name="verticalScrollBarPolicy" >
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="horizontalScrollBarPolicy" >
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>494</width>
<height>54</height>
</rect>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" >
<item>
<widget class="QLabel" name="bottomLabel" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<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,5 +1,6 @@
<RCC> <RCC>
<qresource prefix="/" > <qresource prefix="/" >
<file>icons/anki-logo-thin.png</file>
<file>icons/anki-logo.png</file> <file>icons/anki-logo.png</file>
<file>icons/download.png</file> <file>icons/download.png</file>
<file>icons/preferences-plugin.png</file> <file>icons/preferences-plugin.png</file>

BIN
icons/anki-logo-thin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View file

@ -45,7 +45,6 @@ DATA_FILES = [
'ankiqt/ankiqt/locale', 'ankiqt/ankiqt/locale',
'kakasi', 'kakasi',
#'audio', #'audio',
'libanki/samples',
'ankiqt/imageformats', 'ankiqt/imageformats',
'libanki/anki/features/chinese/unihan.db', 'libanki/anki/features/chinese/unihan.db',
] ]