mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
start refactoring main window
- moved progress handling into separate progress.py - moved deck browser code into separate deckbrowser.py - started reworking the state code; views will be rolled into this in the future - the main window has been stripped of the study options, inline editor, congrats screen and so on, and now consists of a single main widget which has a webview placed inside it. The stripped features will be implemented either in separate windows, or as part of the web view
This commit is contained in:
parent
798b0af128
commit
d948b00c54
16 changed files with 986 additions and 4099 deletions
7
anki
7
anki
|
@ -13,15 +13,14 @@ if __name__ == "__main__":
|
|||
runningDir=os.path.dirname(sys.argv[0])
|
||||
modDir=runningDir
|
||||
|
||||
# set up paths for local development
|
||||
sys.path.insert(0, os.path.join(modDir, "libanki"))
|
||||
sys.path.insert(0, os.path.join(os.path.join(modDir, ".."), "libanki"))
|
||||
|
||||
import ankiqt
|
||||
import aqt
|
||||
|
||||
try:
|
||||
import ankiqt.forms
|
||||
import aqt.forms
|
||||
except ImportError:
|
||||
raise Exception("You need to run tools/build_ui.sh in order for anki to work.")
|
||||
|
||||
ankiqt.run()
|
||||
aqt.run()
|
||||
|
|
|
@ -94,7 +94,7 @@ class AddCards(QDialog):
|
|||
self.onLink)
|
||||
|
||||
def onLink(self, url):
|
||||
browser = ui.dialogs.get("CardList", self.parent)
|
||||
browser = ui.dialogs.open("CardList", self.parent)
|
||||
browser.dialog.filterEdit.setText("fid:" + url.toString())
|
||||
browser.updateSearch()
|
||||
browser.onFact()
|
||||
|
|
|
@ -1038,10 +1038,13 @@ where id in %s""" % ids2str(sf))
|
|||
######################################################################
|
||||
|
||||
def setupHooks(self):
|
||||
print "setupHooks()"
|
||||
return
|
||||
addHook("postUndoRedo", self.postUndoRedo)
|
||||
addHook("currentCardDeleted", self.updateSearch)
|
||||
|
||||
def teardownHooks(self):
|
||||
return
|
||||
removeHook("postUndoRedo", self.postUndoRedo)
|
||||
removeHook("currentCardDeleted", self.updateSearch)
|
||||
|
||||
|
|
|
@ -298,7 +298,7 @@ order by n""", id=card.id)
|
|||
|
||||
def reject(self):
|
||||
modified = False
|
||||
self.deck.startProgress()
|
||||
self.mw.startProgress()
|
||||
self.deck.updateProgress(_("Applying changes..."))
|
||||
reset=True
|
||||
if self.needFormatRebuild:
|
||||
|
|
|
@ -14,8 +14,8 @@ defaultConf = {
|
|||
'confVer': 3,
|
||||
# remove?
|
||||
'colourTimes': True,
|
||||
'deckBrowserNameLength': 30,
|
||||
'deckBrowserOrder': 0,
|
||||
# too long?
|
||||
'deckBrowserRefreshPeriod': 3600,
|
||||
'factEditorAdvanced': False,
|
||||
'showStudyScreen': True,
|
||||
|
@ -96,7 +96,7 @@ class Config(object):
|
|||
path = self._dbPath()
|
||||
self.db = DB(path, level=None, text=str)
|
||||
self.db.executescript("""
|
||||
create table if not exists recentDecks (path not null);
|
||||
create table if not exists decks (path text primary key);
|
||||
create table if not exists config (conf text not null);
|
||||
insert or ignore into config values ('');""")
|
||||
conf = self.db.scalar("select conf from config")
|
||||
|
@ -111,6 +111,24 @@ insert or ignore into config values ('');""")
|
|||
cPickle.dumps(self._conf))
|
||||
self.db.commit()
|
||||
|
||||
# recent deck support
|
||||
def recentDecks(self):
|
||||
"Return a list of paths to remembered decks."
|
||||
# have to convert to unicode manually because of the text factory
|
||||
return [unicode(d[0]) for d in
|
||||
self.db.execute("select path from decks")]
|
||||
|
||||
def addRecentDeck(self, path):
|
||||
"Add PATH to the list of recent decks if not already. Must be unicode."
|
||||
self.db.execute("insert or ignore into decks values (?)",
|
||||
path.encode("utf-8"))
|
||||
|
||||
def delRecentDeck(self, path):
|
||||
"Remove PATH from the list if it exists. Must be unicode."
|
||||
self.db.execute("delete from decks where path = ?",
|
||||
path.encode("utf-8"))
|
||||
|
||||
# helpers
|
||||
def _addDefaults(self):
|
||||
if self.get('confVer') >= defaultConf['confVer']:
|
||||
return
|
||||
|
|
289
aqt/deckbrowser.py
Normal file
289
aqt/deckbrowser.py
Normal file
|
@ -0,0 +1,289 @@
|
|||
# Copyright: Damien Elmes <anki@ichi2.net>
|
||||
# -*- coding: utf-8 -*-
|
||||
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
import time, os, stat
|
||||
from PyQt4.QtCore import *
|
||||
from PyQt4.QtGui import *
|
||||
from anki import Deck
|
||||
from anki.utils import fmtTimeSpan
|
||||
from anki.hooks import addHook
|
||||
|
||||
class DeckBrowser(object):
|
||||
|
||||
def __init__(self, mw):
|
||||
self.mw = mw
|
||||
self._browserLastRefreshed = 0
|
||||
self._decks = []
|
||||
addHook("deckClosing", self.onClose)
|
||||
|
||||
def show(self):
|
||||
if (time.time() - self._browserLastRefreshed >
|
||||
self.mw.config['deckBrowserRefreshPeriod']):
|
||||
t = time.time()
|
||||
self._checkDecks()
|
||||
print "check decks", time.time() - t
|
||||
else:
|
||||
self._reorderDecks()
|
||||
if self._decks:
|
||||
buf = self._header()
|
||||
buf += "<center><h1>Decks</h1><table cellspacing=0 width=90%>"
|
||||
t = time.time
|
||||
for c, deck in enumerate(self._decks):
|
||||
buf += self._deckRow(c, deck)
|
||||
buf += "</table>"
|
||||
buf += self._buttons()
|
||||
buf += self._summary()
|
||||
else:
|
||||
buf = ("""\
|
||||
<br>
|
||||
<font size=+1>
|
||||
Welcome to Anki! Click <b>'Download'</b> to get started. You can return here
|
||||
later by using File>Close.
|
||||
</font>
|
||||
<br>
|
||||
""")
|
||||
# FIXME: ensure deck open button is focused
|
||||
self.mw.web.setHtml(buf)
|
||||
|
||||
def onClose(self, deck):
|
||||
print "onClose"
|
||||
return
|
||||
if deck.finishScheduler:
|
||||
self.deck.finishScheduler()
|
||||
self.deck.reset()
|
||||
# update counts
|
||||
for d in self.browserDecks:
|
||||
if d['path'] == self.deck.path:
|
||||
d['due'] = self.deck.failedSoonCount + self.deck.revCount
|
||||
d['new'] = self.deck.newCount
|
||||
d['mod'] = self.deck.modified
|
||||
d['time'] = self.deck._dailyStats.reviewTime
|
||||
d['reps'] = self.deck._dailyStats.reps
|
||||
|
||||
def _header(self):
|
||||
return "<html><head><style>td { border-bottom: 1px solid #000; margin:0px; padding:0px;} </style></head><body>"
|
||||
|
||||
def _footer(self):
|
||||
return "</body></html>"
|
||||
|
||||
def _deckRow(self, c, deck):
|
||||
buf = "<tr>"
|
||||
# name and status
|
||||
ok = deck['state'] == 'ok'
|
||||
if ok:
|
||||
sub = _("%s ago") % fmtTimeSpan(
|
||||
time.time() - deck['mod'])
|
||||
elif deck['state'] == 'missing':
|
||||
sub = _("(moved or removed)")
|
||||
elif deck['state'] == 'corrupt':
|
||||
sub = _("(corrupt)")
|
||||
elif deck['state'] == 'in use':
|
||||
sub = _("(already open)")
|
||||
sub = "<font size=-1>%s</font>" % sub
|
||||
buf += "<td>%s<br>%s</td>" % (deck['name'], sub)
|
||||
if ok:
|
||||
# due
|
||||
col = '<td><b><font color=#0000ff>%s</font></b></td>'
|
||||
if deck['due'] > 0:
|
||||
s = col % str(deck['due'])
|
||||
else:
|
||||
s = col % ""
|
||||
buf += s
|
||||
# new
|
||||
if deck['new']:
|
||||
s = str(deck['new'])
|
||||
else:
|
||||
s = ""
|
||||
buf += "<td>%s</td>" % s
|
||||
else:
|
||||
buf += "<td></td><td></td>"
|
||||
# open
|
||||
# openButton = QPushButton(_("Open"))
|
||||
# if c < 9:
|
||||
# if sys.platform.startswith("darwin"):
|
||||
# extra = ""
|
||||
# # appears to be broken on osx
|
||||
# #extra = _(" (Command+Option+%d)") % (c+1)
|
||||
# #openButton.setShortcut(_("Ctrl+Alt+%d" % (c+1)))
|
||||
# else:
|
||||
# extra = _(" (Alt+%d)") % (c+1)
|
||||
# openButton.setShortcut(_("Alt+%d" % (c+1)))
|
||||
# else:
|
||||
# extra = ""
|
||||
# openButton.setToolTip(_("Open this deck%s") % extra)
|
||||
# self.connect(openButton, SIGNAL("clicked()"),
|
||||
# lambda d=deck['path']: self.loadDeck(d))
|
||||
# layout.addWidget(openButton, c+1, 5)
|
||||
# if c == 0:
|
||||
# focusButton = openButton
|
||||
# more
|
||||
# moreButton = QPushButton(_("More"))
|
||||
# moreMenu = QMenu()
|
||||
# a = moreMenu.addAction(QIcon(":/icons/edit-undo.png"),
|
||||
# _("Hide From List"))
|
||||
# a.connect(a, SIGNAL("triggered()"),
|
||||
# lambda c=c: self.onDeckBrowserForget(c))
|
||||
# a = moreMenu.addAction(QIcon(":/icons/editdelete.png"),
|
||||
# _("Delete"))
|
||||
# a.connect(a, SIGNAL("triggered()"),
|
||||
# lambda c=c: self.onDeckBrowserDelete(c))
|
||||
# moreButton.setMenu(moreMenu)
|
||||
# self.moreMenus.append(moreMenu)
|
||||
# layout.addWidget(moreButton, c+1, 6)
|
||||
buf += "</tr>"
|
||||
return buf
|
||||
|
||||
def _buttons(self):
|
||||
# refresh = QPushButton(_("Refresh"))
|
||||
# refresh.setToolTip(_("Check due counts again (F5)"))
|
||||
# refresh.setShortcut(_("F5"))
|
||||
# self.connect(refresh, SIGNAL("clicked()"),
|
||||
# self.refresh)
|
||||
# layout.addItem(QSpacerItem(1,20, QSizePolicy.Preferred,
|
||||
# QSizePolicy.Preferred), c+2, 5)
|
||||
# layout.addWidget(refresh, c+3, 5)
|
||||
# more = QPushButton(_("More"))
|
||||
# moreMenu = QMenu()
|
||||
# a = moreMenu.addAction(QIcon(":/icons/edit-undo.png"),
|
||||
# _("Forget Inaccessible Decks"))
|
||||
# a.connect(a, SIGNAL("triggered()"),
|
||||
# self.onDeckBrowserForgetInaccessible)
|
||||
# more.setMenu(moreMenu)
|
||||
# layout.addWidget(more, c+3, 6)
|
||||
# self.moreMenus.append(moreMenu)
|
||||
return ""
|
||||
|
||||
def _summary(self):
|
||||
return ""
|
||||
# summarize
|
||||
reps = 0
|
||||
mins = 0
|
||||
revC = 0
|
||||
newC = 0
|
||||
for d in self._decks:
|
||||
reps += d['reps']
|
||||
mins += d['time']
|
||||
revC += d['due']
|
||||
newC += d['new']
|
||||
line1 = ngettext(
|
||||
"Studied <b>%(reps)d card</b> in <b>%(time)s</b> today.",
|
||||
"Studied <b>%(reps)d cards</b> in <b>%(time)s</b> today.",
|
||||
reps) % {
|
||||
'reps': reps,
|
||||
'time': anki.utils.fmtTimeSpan(mins, point=2),
|
||||
}
|
||||
rev = ngettext(
|
||||
"<b><font color=#0000ff>%d</font></b> review",
|
||||
"<b><font color=#0000ff>%d</font></b> reviews",
|
||||
revC) % revC
|
||||
new = ngettext("<b>%d</b> new card", "<b>%d</b> new cards", newC) % newC
|
||||
line2 = _("Due: %(rev)s, %(new)s") % {
|
||||
'rev': rev, 'new': new}
|
||||
return ""
|
||||
|
||||
def _checkDecks(self, forget=False):
|
||||
self._decks = []
|
||||
decks = self.mw.config.recentDecks()
|
||||
if not decks:
|
||||
return
|
||||
missingDecks = []
|
||||
tx = time.time()
|
||||
self.mw.progress.start(max=len(decks))
|
||||
for c, d in enumerate(decks):
|
||||
self.mw.progress.update(_("Checking deck %(x)d of %(y)d...") % {
|
||||
'x': c+1, 'y': len(decks)})
|
||||
base = os.path.basename(d)
|
||||
if not os.path.exists(d):
|
||||
missingDecks.append(d)
|
||||
self._decks.append({'name': base, 'state': 'missing'})
|
||||
continue
|
||||
try:
|
||||
mod = os.stat(d)[stat.ST_MTIME]
|
||||
t = time.time()
|
||||
deck = Deck(d)
|
||||
counts = deck.sched.counts()
|
||||
self._decks.append({
|
||||
'path': d,
|
||||
'state': 'ok',
|
||||
'name': deck.name(),
|
||||
'due': counts[0],
|
||||
'new': counts[1],
|
||||
'mod': deck.mod,
|
||||
# these multiple deck check time by a factor of 6
|
||||
'time': 0, #deck.sched.timeToday(),
|
||||
'reps': 0, #deck.sched.repsToday()
|
||||
})
|
||||
deck.close()
|
||||
# reset modification time for the sake of backup systems
|
||||
try:
|
||||
os.utime(d, (mod, mod))
|
||||
except:
|
||||
# some misbehaving filesystems may fail here
|
||||
pass
|
||||
except Exception, e:
|
||||
if "File is in use" in unicode(e):
|
||||
state = "in use"
|
||||
else:
|
||||
raise
|
||||
state = "corrupt"
|
||||
self._decks.append({'name': base, 'state':state})
|
||||
if forget:
|
||||
for d in missingDecks:
|
||||
self.mw.config.delRecentDeck(d)
|
||||
self.mw.progress.finish()
|
||||
self._browserLastRefreshed = time.time()
|
||||
self._reorderDecks()
|
||||
|
||||
def _reorderDecks(self):
|
||||
print "reorder decks"
|
||||
return
|
||||
if self.mw.config['deckBrowserOrder'] == 0:
|
||||
self._decks.sort(key=itemgetter('mod'),
|
||||
reverse=True)
|
||||
else:
|
||||
def custcmp(a, b):
|
||||
x = cmp(not not b['due'], not not a['due'])
|
||||
if x:
|
||||
return x
|
||||
x = cmp(not not b['new'], not not a['new'])
|
||||
if x:
|
||||
return x
|
||||
return cmp(a['mod'], b['mod'])
|
||||
self._decks.sort(cmp=custcmp)
|
||||
|
||||
def refresh(self):
|
||||
self._browserLastRefreshed = 0
|
||||
self.show()
|
||||
|
||||
def onDeckBrowserForget(self, c):
|
||||
if aqt.utils.askUser(_("""\
|
||||
Hide %s from the list? You can File>Open it again later.""") %
|
||||
self._decks[c]['name']):
|
||||
self.mw.config['recentDeckPaths'].remove(self._decks[c]['path'])
|
||||
del self._decks[c]
|
||||
self.doLater(100, self.showDeckBrowser)
|
||||
|
||||
def onDeckBrowserDelete(self, c):
|
||||
deck = self._decks[c]['path']
|
||||
if aqt.utils.askUser(_("""\
|
||||
Delete %s? If this deck is synchronized the online version will \
|
||||
not be touched.""") %
|
||||
self._decks[c]['name']):
|
||||
del self._decks[c]
|
||||
os.unlink(deck)
|
||||
try:
|
||||
shutil.rmtree(re.sub(".anki$", ".media", deck))
|
||||
except OSError:
|
||||
pass
|
||||
#self.config['recentDeckPaths'].remove(deck)
|
||||
self.doLater(100, self.showDeckBrowser)
|
||||
|
||||
def onDeckBrowserForgetInaccessible(self):
|
||||
self._checkDecks(forget=True)
|
||||
|
||||
def doLater(self, msecs, func):
|
||||
timer = QTimer(self)
|
||||
timer.setSingleShot(True)
|
||||
timer.start(msecs)
|
||||
self.connect(timer, SIGNAL("timeout()"), func)
|
|
@ -152,7 +152,7 @@ class DeckProperties(QDialog):
|
|||
|
||||
def reject(self):
|
||||
n = _("Deck Properties")
|
||||
self.d.startProgress()
|
||||
self.mw.startProgress()
|
||||
self.d.setUndoStart(n)
|
||||
needSync = False
|
||||
# syncing
|
||||
|
|
|
@ -250,7 +250,7 @@ class GraphWindow(object):
|
|||
self.hbox.addWidget(buttonBox)
|
||||
|
||||
def showHideAll(self):
|
||||
self.deck.startProgress(len(self.widgets))
|
||||
self.mw.startProgress(len(self.widgets))
|
||||
for w in self.widgets:
|
||||
self.deck.updateProgress(_("Processing..."))
|
||||
w.showHide()
|
||||
|
@ -280,7 +280,7 @@ class GraphWindow(object):
|
|||
QDesktopServices.openUrl(QUrl(aqt.appWiki + "Graphs"))
|
||||
|
||||
def onRefresh(self):
|
||||
self.deck.startProgress(len(self.widgets))
|
||||
self.mw.startProgress(len(self.widgets))
|
||||
self.dg.stats = None
|
||||
for w in self.widgets:
|
||||
self.deck.updateProgress(_("Processing..."))
|
||||
|
|
1448
aqt/main.py
1448
aqt/main.py
File diff suppressed because it is too large
Load diff
|
@ -261,7 +261,7 @@ class ModelProperties(QDialog):
|
|||
def reject(self):
|
||||
"Save user settings on close."
|
||||
# update properties
|
||||
self.deck.startProgress()
|
||||
self.mw.startProgress()
|
||||
mname = unicode(self.dialog.name.text())
|
||||
if not mname:
|
||||
mname = _("Model")
|
||||
|
|
129
aqt/progress.py
Normal file
129
aqt/progress.py
Normal file
|
@ -0,0 +1,129 @@
|
|||
# Copyright: Damien Elmes <anki@ichi2.net>
|
||||
# -*- coding: utf-8 -*-
|
||||
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
import time
|
||||
from PyQt4.QtGui import *
|
||||
from PyQt4.QtCore import *
|
||||
|
||||
# Progress info
|
||||
##########################################################################
|
||||
|
||||
class ProgressManager(object):
|
||||
|
||||
def __init__(self, mw):
|
||||
self.mw = mw
|
||||
self.app = QApplication.instance()
|
||||
self._win = None
|
||||
self._levels = 0
|
||||
self._mainThread = QThread.currentThread()
|
||||
|
||||
# SQLite progress handler
|
||||
##########################################################################
|
||||
|
||||
def setupDB(self):
|
||||
"Install a handler in the current deck."
|
||||
self.lastDbProgress = 0
|
||||
self.inDB = False
|
||||
self.mw.deck.db.set_progress_handler(self._dbProgress, 100000)
|
||||
|
||||
def _dbProgress(self):
|
||||
"Called from SQLite."
|
||||
# do nothing if we don't have a progress window
|
||||
if not self._progressWin:
|
||||
return
|
||||
# make sure we're not executing too frequently
|
||||
if (time.time() - self.lastDbProgress) < 0.2:
|
||||
return
|
||||
self.lastDbProgress = time.time()
|
||||
# and we're in the main thread
|
||||
if self._mainThread != QThread.currentThread():
|
||||
return
|
||||
# ensure timers don't fire
|
||||
self.inDB = True
|
||||
# handle GUI events
|
||||
self._maybeShow()
|
||||
self.app.processEvents(QEventLoop.ExcludeUserInputEvents)
|
||||
self.inDB = False
|
||||
|
||||
# DB-safe timers
|
||||
##########################################################################
|
||||
# QTimer may fire in processEvents(). We provide a custom timer which
|
||||
# automatically defers until the DB is not busy.
|
||||
|
||||
def timer(self, ms, func, repeat):
|
||||
def handler():
|
||||
if self.inDB:
|
||||
# retry in 100ms
|
||||
self.timer(100, func, repeat)
|
||||
else:
|
||||
func()
|
||||
t = QTimer(self.mw)
|
||||
if not repeat:
|
||||
t.setSingleShot(True)
|
||||
t.connect(t, SIGNAL("timeout()"), handler)
|
||||
t.start(ms)
|
||||
|
||||
# Creating progress dialogs
|
||||
##########################################################################
|
||||
|
||||
def start(self, max=0, min=0, label=None, parent=None, immediate=False):
|
||||
self._levels += 1
|
||||
if self._levels > 1:
|
||||
return
|
||||
# disable UI
|
||||
self.mw.app.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||
self.mw.setEnabled(False)
|
||||
# setup window
|
||||
parent = parent or self.app.activeWindow() or self.mw
|
||||
label = label or _("Processing...")
|
||||
self._win = QProgressDialog(label, "", min, max, parent)
|
||||
self._win.setWindowTitle("Anki")
|
||||
self._win.setCancelButton(None)
|
||||
self._win.setAutoClose(False)
|
||||
self._win.setAutoReset(False)
|
||||
# we need to manually manage minimum time to show, as qt gets confused
|
||||
# by the db handler
|
||||
self._win.setMinimumDuration(100000)
|
||||
if immediate:
|
||||
self._shown = True
|
||||
print "show"
|
||||
self._win.show()
|
||||
else:
|
||||
self._shown = False
|
||||
self._counter = min
|
||||
self._min = min
|
||||
self._max = max
|
||||
self._firstTime = time.time()
|
||||
self._lastTime = time.time()
|
||||
|
||||
def update(self, label=None, value=None, process=True):
|
||||
#print self._min, self._counter, self._max, label, time.time() - self._lastTime
|
||||
self._maybeShow()
|
||||
self._lastTime = time.time()
|
||||
if label:
|
||||
self._win.setLabelText(label)
|
||||
if self._max and self._shown:
|
||||
self._counter = value or (self._counter+1)
|
||||
self._win.setValue(self._counter)
|
||||
if process:
|
||||
self.app.processEvents()
|
||||
|
||||
def finish(self):
|
||||
self._levels -= 1
|
||||
if self._levels == 0:
|
||||
self._win.cancel()
|
||||
self.app.restoreOverrideCursor()
|
||||
self.mw.setEnabled(True)
|
||||
|
||||
def clear(self):
|
||||
"Restore the interface after an error."
|
||||
if self._levels:
|
||||
self._levels = 1
|
||||
self.finishProgress()
|
||||
|
||||
def _maybeShow(self):
|
||||
if not self._shown and (time.time() - self._firstTime) > 2:
|
||||
print "show2"
|
||||
self._shown = True
|
||||
self._win.show()
|
|
@ -26,6 +26,7 @@ class StatusView(object):
|
|||
warnTime = 10
|
||||
|
||||
def __init__(self, parent):
|
||||
return
|
||||
self.main = parent
|
||||
self.statusbar = parent.mainWin.statusbar
|
||||
self.shown = []
|
||||
|
|
50
aqt/utils.py
50
aqt/utils.py
|
@ -285,53 +285,3 @@ def getBase(deck, card):
|
|||
return '<base href="%s">' % base
|
||||
else:
|
||||
return ""
|
||||
|
||||
class ProgressWin(object):
|
||||
|
||||
def __init__(self, parent, max=0, min=0, title=None, immediate=False):
|
||||
if not title:
|
||||
title = "Anki"
|
||||
self.diag = QProgressDialog("", "", min, max, parent)
|
||||
self.diag.setWindowTitle(title)
|
||||
self.diag.setCancelButton(None)
|
||||
self.diag.setAutoClose(False)
|
||||
self.diag.setAutoReset(False)
|
||||
# qt doesn't seem to honour this consistently, and it's not triggered
|
||||
# by the db progress handler, so we set it high and use maybeShow() below
|
||||
if immediate:
|
||||
self.diag.show()
|
||||
else:
|
||||
self.diag.setMinimumDuration(100000)
|
||||
self.counter = min
|
||||
self.min = min
|
||||
self.max = max
|
||||
self.firstTime = time.time()
|
||||
self.lastTime = time.time()
|
||||
self.app = QApplication.instance()
|
||||
self.shown = False
|
||||
if max == 0:
|
||||
self.diag.setLabelText(_("Processing..."))
|
||||
|
||||
def maybeShow(self):
|
||||
if time.time() - self.firstTime > 2 and not self.shown:
|
||||
self.shown = True
|
||||
self.diag.show()
|
||||
|
||||
def update(self, label=None, value=None, process=True):
|
||||
#print self.min, self.counter, self.max, label, time.time() - self.lastTime
|
||||
self.maybeShow()
|
||||
self.lastTime = time.time()
|
||||
if label:
|
||||
self.diag.setLabelText(label)
|
||||
if value is None:
|
||||
value = self.counter
|
||||
self.counter += 1
|
||||
else:
|
||||
self.counter = value + 1
|
||||
if self.max:
|
||||
self.diag.setValue(value)
|
||||
if process:
|
||||
self.app.processEvents()
|
||||
|
||||
def finish(self):
|
||||
self.diag.cancel()
|
||||
|
|
19
aqt/view.py
19
aqt/view.py
|
@ -12,7 +12,6 @@ import types, time, re, os, urllib, sys, difflib
|
|||
import unicodedata as ucd
|
||||
from aqt.utils import mungeQA, getBase
|
||||
from anki.utils import fmtTimeSpan
|
||||
from PyQt4.QtWebKit import QWebPage, QWebView
|
||||
|
||||
failedCharColour = "#FF0000"
|
||||
passedCharColour = "#00FF00"
|
||||
|
@ -330,21 +329,3 @@ class View(object):
|
|||
"Tell the user the deck is finished."
|
||||
self.main.mainWin.congratsLabel.setText(
|
||||
self.main.deck.deckFinishedMsg())
|
||||
|
||||
class AnkiWebView(QWebView):
|
||||
|
||||
def __init__(self, *args):
|
||||
QWebView.__init__(self, *args)
|
||||
self.setObjectName("mainText")
|
||||
|
||||
def keyPressEvent(self, evt):
|
||||
if evt.matches(QKeySequence.Copy):
|
||||
self.triggerPageAction(QWebPage.Copy)
|
||||
evt.accept()
|
||||
QWebView.keyPressEvent(self, evt)
|
||||
|
||||
def contextMenuEvent(self, evt):
|
||||
QWebView.contextMenuEvent(self, evt)
|
||||
|
||||
def dropEvent(self, evt):
|
||||
pass
|
||||
|
|
3104
designer/main.ui
3104
designer/main.ui
File diff suppressed because it is too large
Load diff
1
icons/.gitignore
vendored
1
icons/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
/.directory
|
Loading…
Reference in a new issue