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:
- sox
- sox 14.1+
- pyaudio
- lame

View file

@ -6,7 +6,7 @@ from PyQt4.QtCore import *
from PyQt4.QtGui import *
appName="Anki"
appVersion="0.9.9.6"
appVersion="0.9.9.7"
appWebsite="http://ichi2.net/anki/download/"
appWiki="http://ichi2.net/anki/wiki/"
appHelpSite="http://ichi2.net/anki/wiki/AnkiWiki"
@ -36,8 +36,23 @@ class SplashScreen(object):
self.splash = QSplashScreen(self.pixmap)
self.prog = QProgressBar(self.splash)
self.prog.setMaximum(max)
self.prog.setGeometry(self.splash.width()/10, 8*self.splash.height()/10,
8*self.splash.width()/10, self.splash.height()/10)
if QApplication.instance().style().objectName() != "plastique":
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.val = 1
@ -93,7 +108,7 @@ def run():
if anki.version != appVersion:
print "You have libanki %s, but this is ankiqt %s" % (
anki.version, appVersion)
print "\nPlease install the latest libanki."
print "\nPlease ensure versions match."
return
# parse args

View file

@ -57,6 +57,7 @@ class Config(dict):
'saveAfterAddingNum': 1,
'saveOnClose': True,
'mainWindowGeom': None,
'mainWindowState': None,
'suppressUpdate': False,
'suppressEstimates': False,
'showLastCardInterval': False,
@ -84,6 +85,7 @@ class Config(dict):
'editLineSize': 20,
'factEditorAdvanced': False,
'typeAnswerFontSize': 20,
'showProgress': True,
'recentColours': ["#000000", "#0000ff"],
}
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 facteditor
import help
import importing
import lookup
import modelchooser
import modelproperties
@ -26,6 +25,7 @@ def importAll():
import update
import utils
import view
import getshared
class DialogManager(object):

View file

@ -1,4 +1,5 @@
# Copyright: Damien Elmes <anki@ichi2.net>
# -*- coding: utf-8 -*-
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
from PyQt4.QtGui import *
@ -10,12 +11,31 @@ def show(parent):
abt = ankiqt.forms.about.Ui_About()
abt.setupUi(dialog)
abt.label.setText(_("""
<h1>Anki</h1>
<img src=":/icons/anki.png">
<center><img src=":/icons/anki-logo-thin.png"></center>
<p>
<span>Anki is a spaced repetition flashcard program designed to maximise your
memory potential.<p/>It's free and licensed under the GPL.<p/>
Version %s<br>
Anki is a friendly, intelligent spaced learning system. It's free and open
source.<p>
Version %(ver)s<br>
<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_()

View file

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

View file

@ -56,7 +56,6 @@ class AddCards(QDialog):
self.addButton.setToolTip(_("Add (shortcut: command+return)"))
else:
self.addButton.setToolTip(_("Add (shortcut: ctrl+return)"))
self.addButton.setAutoDefault(False)
s = QShortcut(QKeySequence(_("Ctrl+Enter")), self)
s.connect(s, SIGNAL("activated()"), self.addButton, SLOT("click()"))
self.connect(self.addButton, SIGNAL("clicked()"), self.addCards)
@ -95,6 +94,7 @@ class AddCards(QDialog):
fact.tags = self.parent.deck.lastTags
# set the new fact
self.editor.setFact(fact, check=True)
self.setTabOrder(self.editor.tags, self.addButton)
def addCards(self):
# 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.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):
if self.onClose():
evt.accept()

View file

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

View file

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

View file

@ -4,10 +4,20 @@
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import anki, ankiqt
from anki.exporting import exporters
from anki.exporting import exporters as exporters_
from anki.utils import parseTags
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):
def __init__(self, parent):
@ -35,7 +45,7 @@ class ExportDialog(QDialog):
self.setTabOrder(self.tags,
self.dialog.includeScheduling)
# save button
b = QPushButton(_("Export to..."))
b = QPushButton(_("Export..."))
self.dialog.buttonBox.addButton(b, QDialogButtonBox.AcceptRole)
def exporterChanged(self, idx):
@ -50,6 +60,9 @@ class ExportDialog(QDialog):
self.dialog.includeTags.hide()
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",
self.exporter.key, self.exporter.ext)
self.hide()

View file

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

View file

@ -132,7 +132,7 @@ class ImportDialog(QDialog):
self.parent.deck.finishProgress()
self.parent.deck.setUndoEnd(n)
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)})
txt += _("Click the close button or import another file.\n\n")
if self.importer.log:

View file

@ -6,8 +6,8 @@ from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtWebKit import QWebPage
import os, sys, re, types, gettext, stat, traceback
import shutil, time, glob, tempfile, datetime
import os, sys, re, types, gettext, stat, traceback, inspect
import shutil, time, glob, tempfile, datetime, zipfile, locale
from PyQt4.QtCore import *
from PyQt4.QtGui import *
@ -49,8 +49,6 @@ class AnkiQt(QMainWindow):
self.setupTray()
self.connectMenuActions()
ui.splash.update()
if self.config['mainWindowGeom']:
self.restoreGeometry(self.config['mainWindowGeom'])
self.setupViews()
self.setupEditor()
self.setupStudyScreen()
@ -58,6 +56,9 @@ class AnkiQt(QMainWindow):
self.setupAnchors()
self.setupToolbar()
self.setupProgressInfo()
if self.config['mainWindowState']:
self.restoreGeometry(self.config['mainWindowGeom'])
self.restoreState(self.config['mainWindowState'])
if sys.platform.startswith("darwin"):
self.setUnifiedTitleAndToolBarOnMac(True)
pass
@ -68,10 +69,11 @@ class AnkiQt(QMainWindow):
self.moveToState("auto")
# check for updates
ui.splash.update()
self.setupAutoUpdate()
self.errorOccurred = False
self.setupErrorHandler()
self.setupMisc()
self.loadPlugins()
self.setupAutoUpdate()
self.rebuildPluginsMenu()
# run after-init hook
try:
@ -82,6 +84,9 @@ class AnkiQt(QMainWindow):
ui.splash.update()
ui.splash.finish(self)
self.show()
if (self.deck and self.config['syncOnLoad'] and
self.deck.syncName):
self.syncDeck(interactive=False)
def setupMainWindow(self):
# main window
@ -142,9 +147,11 @@ class AnkiQt(QMainWindow):
# hack for matplotlib errors on osx
self.pool = ""
stdText = _("""\
An error occurred.<br>
Please run <b>Tools > Advanced > Check DB</b>.<br>
<br>
An error occurred. Please:<p>
<ol>
<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>
into a bug report:<br><br>
""")
@ -156,6 +163,7 @@ Please do not file a bug report with Anki.<br><br>""")
else:
txt = stdText
if self.pool:
self.parent.errorOccurred = True
ui.utils.showText(txt + self.pool[0:10000].replace(
"\n", "<br>"))
self.pool = ""
@ -197,6 +205,7 @@ Please do not file a bug report with Anki.<br><br>""")
if count:
self.deck.rebuildCounts()
self.deck.rebuildQueue()
runHook("guiReset")
self.moveToState("initial")
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."
if self.state != "showAnswer":
return
# remove card from session before updating it
try:
self.deck.s.expunge(self.currentCard)
except:
# session has been reset
pass
# force refresh of card then remove from session as we update in pure sql
self.deck.s.refresh(self.currentCard)
self.deck.s.refresh(self.currentCard.fact)
self.deck.s.refresh(self.currentCard.cardModel)
self.deck.s.expunge(self.currentCard)
# answer
self.deck.answerCard(self.currentCard, quality)
self.lastScheduledTime = anki.utils.fmtTimeSpan(
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
if args:
f = unicode(args[0], sys.getfilesystemencoding())
return self.loadDeck(f)
return self.loadDeck(f, sync=False)
# try recent deck paths
for path in self.config['recentDeckPaths']:
r = self.loadDeck(path, interactive=False)
r = self.loadDeck(path, interactive=False, sync=False)
if r:
return r
self.onNew(initial=True)
@ -626,50 +635,10 @@ To upgrade an old deck, download Anki 0.9.8.7."""))
latest = self.config['recentDeckPaths'][0]
defaultDir = os.path.dirname(latest)
else:
if save:
defaultDir = unicode(os.path.expanduser("~/"),
sys.getfilesystemencoding())
else:
samples = self.getSamplesDir()
if samples:
return samples
defaultDir = unicode(os.path.expanduser("~/"),
sys.getfilesystemencoding())
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):
"Add the current deck to the list of recent files."
path = os.path.normpath(path)
@ -761,6 +730,7 @@ To upgrade an old deck, download Anki 0.9.8.7."""))
return True
def inMainWindow(self):
return True
return self.app.activeWindow() == self
def onNew(self, initial=False, path=None):
@ -826,23 +796,27 @@ To upgrade an old deck, download Anki 0.9.8.7."""))
self.deck = None
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
key = _("Deck files (*.anki)")
if samples: defaultDir = self.getSamplesDir()
else: defaultDir = self.getDefaultDir()
defaultDir = self.getDefaultDir()
file = QFileDialog.getOpenFileName(self, _("Open deck"),
defaultDir, key)
file = unicode(file)
if not file:
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)
if not ret:
if ret is None:
@ -853,9 +827,6 @@ To upgrade an old deck, download Anki 0.9.8.7."""))
self.updateRecentFiles(file)
return True
def onOpenSamples(self):
self.onOpen(samples=True)
def onUnsavedTimer(self):
QToolTip.showText(
self.mainWin.statusbar.mapToGlobal(QPoint(0, -100)),
@ -925,6 +896,7 @@ your deck."""))
runHook("quit")
self.help.hide()
self.config['mainWindowGeom'] = self.saveGeometry()
self.config['mainWindowState'] = self.saveState()
# save config
try:
self.config.save()
@ -950,14 +922,12 @@ your deck."""))
def onWelcomeAnchor(self, str):
if str == "new":
self.onNew()
elif str == "sample":
self.onOpenSamples()
elif str == "open":
self.onOpen()
elif str == "sample":
self.onGetSharedDeck()
elif str == "openrem":
self.onOpenOnline()
elif str == "more":
self.onGetMoreDecks()
if str == "addfacts":
if not self.deck:
self.onNew()
@ -1175,7 +1145,6 @@ day = :d""", d=yesterday)
self.deck.newCardSpacing = self.mainWin.newCardScheduling.currentIndex()
self.deck.revCardOrder = self.mainWin.revCardOrder.currentIndex()
self.deck.setFailedCardPolicy(self.mainWin.failedCardsOption.currentIndex())
self.deck.updateDynamicIndices()
self.deck.startSession()
self.deck.flushMod()
self.moveToState("getQuestion")
@ -1401,13 +1370,11 @@ day = :d""", d=yesterday)
def onActiveTags(self):
ui.activetags.show(self)
def onGetMoreDecks(self):
QDesktopServices.openUrl(QUrl(ankiqt.appMoreDecks))
# Importing & exporting
##########################################################################
def onImport(self):
import ui.importing
if self.deck is None:
self.onNew()
ui.importing.ImportDialog(self)
@ -1415,9 +1382,20 @@ day = :d""", d=yesterday)
def onExport(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):
if self.deck.name() == "cram":
ui.utils.showInfo(
@ -1431,14 +1409,7 @@ day = :d""", d=yesterday)
return
s = unicode(s)
# open tmp deck
ndir = tempfile.mkdtemp(prefix="anki")
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)
(e, path) = self._copyToTmpDeck(tags=s)
if not e.exportedCards:
ui.utils.showInfo(_("No cards matched the provided tags."))
return
@ -1482,6 +1453,80 @@ day = :d""", d=yesterday)
self.reset()
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
##########################################################################
@ -1498,6 +1543,7 @@ day = :d""", d=yesterday)
def setLang(self):
"Set the user interface language."
locale.setlocale(locale.LC_ALL, '')
languageDir=os.path.join(ankiqt.modDir, "locale")
self.languageTrans = gettext.translation('ankiqt', languageDir,
languages=[self.config["interfaceLang"]],
@ -1698,10 +1744,12 @@ day = :d""", d=yesterday)
s = SIGNAL("triggered()")
self.connect(m.actionNew, s, self.onNew)
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.actionOpenSamples, s, self.onOpenSamples)
self.connect(m.actionSave, s, self.onSave)
self.connect(m.actionSaveAs, s, self.onSaveAs)
self.connect(m.actionShare, s, self.onShare)
self.connect(m.actionClose, s, self.onClose)
self.connect(m.actionExit, s, self, SLOT("close()"))
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.actionActiveTags, s, self.onActiveTags)
self.connect(m.actionReleaseNotes, s, self.onReleaseNotes)
self.connect(m.actionGetMoreDecks, s, self.onGetMoreDecks)
self.connect(m.actionCacheLatex, s, self.onCacheLatex)
self.connect(m.actionUncacheLatex, s, self.onUncacheLatex)
self.connect(m.actionStudyOptions, s, self.onStudyOptions)
@ -1835,7 +1882,13 @@ day = :d""", d=yesterday)
self.mainWin.menu_Lookup.menuAction().setVisible(True)
else:
self.mainWin.menu_Lookup.menuAction().setVisible(False)
enable = False
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):
if self.deck and self.deck.undoAvailable():
@ -1904,6 +1957,7 @@ day = :d""", d=yesterday)
sys.path.insert(0, plugdir)
plugins = self.enabledPlugins()
plugins.sort()
self.registeredPlugins = {}
for plugin in plugins:
try:
nopy = plugin.replace(".py", "")
@ -1911,6 +1965,7 @@ day = :d""", d=yesterday)
except:
print "Error in %s" % plugin
traceback.print_exc()
self.checkForUpdatedPlugins()
def rebuildPluginsMenu(self):
if getattr(self, "pluginActions", None) is None:
@ -1922,6 +1977,8 @@ day = :d""", d=yesterday)
for fname in all:
enabled = fname.endswith(".py")
p = re.sub("\.py(\.off)?", "", fname)
if p+".py" in self.registeredPlugins:
p = self.registeredPlugins[p+".py"]['name']
a = QAction(p, self)
a.setCheckable(True)
a.setChecked(enabled)
@ -1942,13 +1999,16 @@ day = :d""", d=yesterday)
return [p for p in os.listdir(self.pluginsFolder())
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":
# reuse our process handling code from latex
anki.latex.call(["explorer", self.pluginsFolder().encode(
sys.getfilesystemencoding())])
anki.latex.call(["explorer", path.encode(
sys.getfilesystemencoding())],
wait=False)
else:
QDesktopServices.openUrl(QUrl("file://" + self.pluginsFolder()))
QDesktopServices.openUrl(QUrl("file://" + path))
def onGetPlugins(self):
QDesktopServices.openUrl(QUrl("http://ichi2.net/anki/wiki/Plugins"))
@ -1980,6 +2040,14 @@ day = :d""", d=yesterday)
self.enablePlugin(plugin)
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
##########################################################################
@ -2011,9 +2079,9 @@ day = :d""", d=yesterday)
##########################################################################
def setupProgressInfo(self):
addHook("startProgress", self.onStartProgress)
addHook("updateProgress", self.onUpdateProgress)
addHook("finishProgress", self.onFinishProgress)
addHook("startProgress", self.startProgress)
addHook("updateProgress", self.updateProgress)
addHook("finishProgress", self.finishProgress)
addHook("dbProgress", self.onDbProgress)
addHook("dbFinished", self.onDbFinished)
self.progressParent = None
@ -2024,7 +2092,7 @@ day = :d""", d=yesterday)
def setProgressParent(self, 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():
return
self.setBusy()
@ -2034,14 +2102,14 @@ day = :d""", d=yesterday)
p = ui.utils.ProgressWin(parent, max, min, title)
self.progressWins.append(p)
def onUpdateProgress(self, label=None, value=None):
def updateProgress(self, label=None, value=None):
if self.mainThread != QThread.currentThread():
return
if self.progressWins:
self.progressWins[-1].update(label, value)
self.app.processEvents()
def onFinishProgress(self):
def finishProgress(self):
if self.mainThread != QThread.currentThread():
return
if self.progressWins:
@ -2077,6 +2145,10 @@ day = :d""", d=yesterday)
def onCheckDB(self):
"True if no problems"
if self.errorOccurred:
ui.utils.showWarning(_(
"Please restart Anki before checking the DB."))
return
if not ui.utils.askUser(_("""\
This operation will find and fix some common problems.<br>
<br>
@ -2098,7 +2170,7 @@ Proceed?""")):
def onOptimizeDB(self):
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):
mb = QMessageBox(self)

View file

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

View file

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

View file

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

View file

@ -52,7 +52,9 @@ class Sync(QThread):
else:
msg=_("""\
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
def connect(self, *args):

View file

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

View file

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

View file

@ -13,6 +13,14 @@
<string>Edit Items</string>
</property>
<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" >
<property name="spacing" >
<number>0</number>
@ -162,7 +170,7 @@
<x>0</x>
<y>0</y>
<width>599</width>
<height>25</height>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="menuEdit" >
@ -226,7 +234,7 @@
<string>Delete</string>
</property>
<property name="shortcut" >
<string>Del</string>
<string>Ctrl+Del</string>
</property>
</action>
<action name="actionAddTag" >

View file

@ -300,8 +300,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>960</width>
<height>480</height>
<width>348</width>
<height>317</height>
</rect>
</property>
<attribute name="title" >
@ -556,6 +556,9 @@
<property name="text" >
<string>Close</string>
</property>
<property name="autoDefault" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
@ -613,6 +616,31 @@
</layout>
</widget>
<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>answer</tabstop>
</tabstops>

View file

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

View file

@ -18,32 +18,22 @@
<item row="0" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Find</string>
<string>&lt;b>Find&lt;/b>:</string>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLineEdit" name="find" />
</item>
<item row="1" column="0" >
<item row="2" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Replace</string>
<string>&lt;b>Replace With&lt;/b>:</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLineEdit" name="replace" />
</item>
<item row="2" column="1" >
<widget class="QComboBox" name="type" />
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Search</string>
</property>
</widget>
<widget class="QLineEdit" name="replace" />
</item>
<item row="3" column="1" >
<widget class="QCheckBox" name="re" >
@ -52,6 +42,16 @@
</property>
</widget>
</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>
</item>
<item>
@ -81,8 +81,8 @@
</widget>
<tabstops>
<tabstop>find</tabstop>
<tabstop>field</tabstop>
<tabstop>replace</tabstop>
<tabstop>type</tabstop>
<tabstop>re</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
@ -95,8 +95,8 @@
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>252</x>
<y>127</y>
<x>256</x>
<y>154</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
@ -111,8 +111,8 @@
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>286</x>
<y>127</y>
<x>290</x>
<y>154</y>
</hint>
<hint type="destinationlabel" >
<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>
<y>0</y>
<width>723</width>
<height>504</height>
<height>513</height>
</rect>
</property>
<property name="sizePolicy" >
@ -28,7 +28,7 @@
<x>0</x>
<y>69</y>
<width>723</width>
<height>415</height>
<height>424</height>
</rect>
</property>
<property name="sizePolicy" >
@ -145,8 +145,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>422</width>
<height>57</height>
<width>100</width>
<height>30</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout" >
@ -224,8 +224,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>422</width>
<height>57</height>
<width>100</width>
<height>30</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3" >
@ -371,8 +371,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>422</width>
<height>57</height>
<width>100</width>
<height>30</height>
</rect>
</property>
</widget>
@ -397,7 +397,7 @@
</sizepolicy>
</property>
<property name="currentIndex" >
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="blankPage" >
<property name="geometry" >
@ -405,7 +405,7 @@
<x>0</x>
<y>0</y>
<width>446</width>
<height>358</height>
<height>367</height>
</rect>
</property>
</widget>
@ -415,7 +415,7 @@
<x>0</x>
<y>0</y>
<width>446</width>
<height>358</height>
<height>367</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5" >
@ -440,7 +440,7 @@
<x>0</x>
<y>0</y>
<width>446</width>
<height>358</height>
<height>367</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" >
@ -478,7 +478,7 @@
<x>0</x>
<y>0</y>
<width>446</width>
<height>358</height>
<height>367</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4" >
@ -530,7 +530,7 @@
<item>
<widget class="QLabel" name="optionsLabel" >
<property name="text" >
<string>xxx</string>
<string/>
</property>
<property name="textInteractionFlags" >
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
@ -736,6 +736,12 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>0</width>
<height>26</height>
</size>
</property>
<property name="text" >
<string>Review</string>
</property>
@ -743,10 +749,22 @@
<iconset resource="../icons.qrc" >
<normaloff>:/icons/player-time.png</normaloff>:/icons/player-time.png</iconset>
</property>
<property name="autoDefault" >
<bool>true</bool>
</property>
<property name="default" >
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QPushButton" name="optionsButton" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>26</height>
</size>
</property>
<property name="text" >
<string>More>></string>
</property>
@ -763,6 +781,12 @@
</item>
<item row="0" column="2" >
<widget class="QPushButton" name="optionsHelpButton" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>26</height>
</size>
</property>
<property name="text" >
<string>Help</string>
</property>
@ -813,7 +837,7 @@
<x>0</x>
<y>0</y>
<width>446</width>
<height>358</height>
<height>367</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_8" >
@ -878,7 +902,7 @@
<item>
<widget class="QLabel" name="congratsLabel" >
<property name="text" >
<string>xxx</string>
<string/>
</property>
<property name="margin" >
<number>0</number>
@ -1174,7 +1198,6 @@
<addaction name="actionReportbug" />
<addaction name="actionForum" />
<addaction name="actionReleaseNotes" />
<addaction name="actionGetMoreDecks" />
<addaction name="separator" />
<addaction name="actionDonate" />
<addaction name="actionAbout" />
@ -1208,10 +1231,23 @@
<normaloff>:/icons/document-open-recent.png</normaloff>:/icons/document-open-recent.png</iconset>
</property>
</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="actionOpen" />
<addaction name="menuOpenRecent" />
<addaction name="actionOpenOnline" />
<addaction name="menuDownload" />
<addaction name="actionImport" />
<addaction name="separator" />
<addaction name="actionSave" />
@ -1288,7 +1324,6 @@
<addaction name="actionDisableAllPlugins" />
<addaction name="separator" />
</widget>
<addaction name="actionGetPlugins" />
<addaction name="actionOpenPluginFolder" />
<addaction name="separator" />
<addaction name="menuStartup" />
@ -1313,7 +1348,7 @@
<property name="geometry" >
<rect>
<x>0</x>
<y>484</y>
<y>493</y>
<width>723</width>
<height>20</height>
</rect>
@ -1427,6 +1462,9 @@
<property name="shortcut" >
<string>Ctrl+S</string>
</property>
<property name="shortcutContext" >
<enum>Qt::ApplicationShortcut</enum>
</property>
</action>
<action name="actionSyncdeck" >
<property name="icon" >
@ -1762,15 +1800,6 @@
<string>Check Media Database...</string>
</property>
</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" >
<property name="icon" >
<iconset resource="../icons.qrc" >
@ -1823,15 +1852,6 @@
<string>Active &amp;Tags...</string>
</property>
</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" >
<property name="icon" >
<iconset resource="../icons.qrc" >
@ -1861,6 +1881,9 @@
<property name="text" >
<string>&amp;Delete Card</string>
</property>
<property name="shortcut" >
<string>Ctrl+Del</string>
</property>
</action>
<action name="action_Delete_Fact" >
<property name="text" >
@ -1904,6 +1927,34 @@
<string>&amp;Record Noise Profile...</string>
</property>
</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>
<tabstops>
<tabstop>newPerDay</tabstop>
@ -1921,11 +1972,11 @@
<tabstop>help</tabstop>
<tabstop>welcomeText</tabstop>
<tabstop>showAnswerButton</tabstop>
<tabstop>saveEditorButton</tabstop>
<tabstop>easeButton2</tabstop>
<tabstop>easeButton1</tabstop>
<tabstop>easeButton2</tabstop>
<tabstop>easeButton3</tabstop>
<tabstop>easeButton4</tabstop>
<tabstop>saveEditorButton</tabstop>
</tabstops>
<resources>
<include location="../icons.qrc" />

View file

@ -97,6 +97,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showProgress" >
<property name="text" >
<string>Show information in status bar</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer" >
<property name="orientation" >
@ -110,6 +117,16 @@
</property>
</spacer>
</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>
</widget>
<widget class="QWidget" name="tab_2" >
@ -318,7 +335,7 @@
<item row="2" column="0" >
<widget class="QLabel" name="label_6" >
<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>
</widget>
</item>
@ -388,6 +405,16 @@
</property>
</spacer>
</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>
</widget>
</widget>
@ -411,6 +438,7 @@
<tabstop>showDivider</tabstop>
<tabstop>splitQA</tabstop>
<tabstop>showEstimates</tabstop>
<tabstop>showProgress</tabstop>
<tabstop>saveWhenClosing</tabstop>
<tabstop>saveAfterEvery</tabstop>
<tabstop>saveAfterEveryNum</tabstop>
@ -422,7 +450,9 @@
<tabstop>syncOnClose</tabstop>
<tabstop>alternativeTheme</tabstop>
<tabstop>showTimer</tabstop>
<tabstop>showTray</tabstop>
<tabstop>showStudyOptions</tabstop>
<tabstop>addZeroSpace</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<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>
<qresource prefix="/" >
<file>icons/anki-logo-thin.png</file>
<file>icons/anki-logo.png</file>
<file>icons/download.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',
'kakasi',
#'audio',
'libanki/samples',
'ankiqt/imageformats',
'libanki/anki/features/chinese/unihan.db',
]