mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
more deck browser work
- add a separate toolbar for the deck browser - add a message when there are no decks - change the progress handler not to lock the UI immediately, which causes flicker - ensure the webview is focused after stdHtml()
This commit is contained in:
parent
87f5fe8769
commit
f96e03875a
5 changed files with 104 additions and 44 deletions
|
@ -27,14 +27,11 @@ a.opts { font-size: 80%; padding: 2; background-color: #ccc; border-radius: 2px;
|
||||||
_body = """
|
_body = """
|
||||||
<center>
|
<center>
|
||||||
<div id="outer">
|
<div id="outer">
|
||||||
<h1>%s</h1>
|
<h1>%(title)s</h1>
|
||||||
<table cellspacing=0 cellpadding=0 width=90%%>
|
<table cellspacing=0 cellpadding=0 width=90%%>
|
||||||
%s
|
%(rows)s
|
||||||
</table>
|
</table>
|
||||||
<br><br>
|
%(extra)s
|
||||||
%s
|
|
||||||
<p>
|
|
||||||
Click a deck to open it, or press the number/letter next to it.
|
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -45,11 +42,16 @@ class DeckBrowser(object):
|
||||||
self.web = mw.web
|
self.web = mw.web
|
||||||
self._browserLastRefreshed = 0
|
self._browserLastRefreshed = 0
|
||||||
self._decks = []
|
self._decks = []
|
||||||
|
mw.connect(mw.form.actionRefreshDeckBrowser, SIGNAL("activated()"),
|
||||||
|
self.refresh)
|
||||||
addHook("deckClosing", self.onClose)
|
addHook("deckClosing", self.onClose)
|
||||||
|
|
||||||
def show(self):
|
def show(self, _init=True):
|
||||||
self.web.setLinkHandler(self._linkHandler)
|
if _init:
|
||||||
self.mw.setKeyHandler(self._keyHandler)
|
self.web.setLinkHandler(self._linkHandler)
|
||||||
|
self.mw.setKeyHandler(self._keyHandler)
|
||||||
|
self._setupToolbar()
|
||||||
|
# refresh or reorder
|
||||||
if (time.time() - self._browserLastRefreshed >
|
if (time.time() - self._browserLastRefreshed >
|
||||||
self.mw.config['deckBrowserRefreshPeriod']):
|
self.mw.config['deckBrowserRefreshPeriod']):
|
||||||
t = time.time()
|
t = time.time()
|
||||||
|
@ -57,23 +59,8 @@ class DeckBrowser(object):
|
||||||
print "check decks", time.time() - t
|
print "check decks", time.time() - t
|
||||||
else:
|
else:
|
||||||
self._reorderDecks()
|
self._reorderDecks()
|
||||||
if self._decks:
|
# show
|
||||||
buf = ""
|
self._renderPage()
|
||||||
max=len(self._decks)-1
|
|
||||||
for c, deck in enumerate(self._decks):
|
|
||||||
buf += self._deckRow(c, max, deck)
|
|
||||||
self.web.stdHtml(_body%(_("Decks"), buf, self._summary()), _css)
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def onClose(self, deck):
|
def onClose(self, deck):
|
||||||
print "onClose"
|
print "onClose"
|
||||||
|
@ -90,6 +77,24 @@ later by using File>Close.
|
||||||
d['time'] = self.deck._dailyStats.reviewTime
|
d['time'] = self.deck._dailyStats.reviewTime
|
||||||
d['reps'] = self.deck._dailyStats.reps
|
d['reps'] = self.deck._dailyStats.reps
|
||||||
|
|
||||||
|
# Toolbar
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
def _setupToolbar(self):
|
||||||
|
frm = self.mw.form
|
||||||
|
tb = frm.toolBar
|
||||||
|
tb.clear()
|
||||||
|
tb.addAction(frm.actionDownloadSharedDeck)
|
||||||
|
tb.addAction(frm.actionNew)
|
||||||
|
tb.addAction(frm.actionOpen)
|
||||||
|
tb.addAction(frm.actionImport)
|
||||||
|
tb.addAction(frm.actionOpenOnline)
|
||||||
|
tb.addAction(frm.actionRefreshDeckBrowser)
|
||||||
|
tb.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
|
||||||
|
# reshow so osx recalculates sizes
|
||||||
|
tb.hide()
|
||||||
|
tb.show()
|
||||||
|
|
||||||
# Event handlers
|
# Event handlers
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
|
@ -117,6 +122,27 @@ later by using File>Close.
|
||||||
# HTML generation
|
# HTML generation
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
|
def _renderPage(self):
|
||||||
|
if self._decks:
|
||||||
|
buf = ""
|
||||||
|
max=len(self._decks)-1
|
||||||
|
for c, deck in enumerate(self._decks):
|
||||||
|
buf += self._deckRow(c, max, deck)
|
||||||
|
self.web.stdHtml(_body%dict(
|
||||||
|
title=_("Decks"),
|
||||||
|
rows=buf,
|
||||||
|
extra="<p>%s<p>%s" % (
|
||||||
|
self._summary(),
|
||||||
|
_("Click a deck to open, or type a number."))),
|
||||||
|
_css)
|
||||||
|
else:
|
||||||
|
self.web.stdHtml(_body%dict(
|
||||||
|
title=_("Welcome!"),
|
||||||
|
rows="<tr><td align=center>%s</td></tr>"%_(
|
||||||
|
"Click <b>Download</b> to get started."),
|
||||||
|
extra=""),
|
||||||
|
_css)
|
||||||
|
|
||||||
def _deckRow(self, c, max, deck):
|
def _deckRow(self, c, max, deck):
|
||||||
buf = "<tr>"
|
buf = "<tr>"
|
||||||
ok = deck['state'] == 'ok'
|
ok = deck['state'] == 'ok'
|
||||||
|
@ -207,10 +233,6 @@ later by using File>Close.
|
||||||
a.connect(a, SIGNAL("activated()"), lambda n=n: self._deleteRow(n))
|
a.connect(a, SIGNAL("activated()"), lambda n=n: self._deleteRow(n))
|
||||||
m.exec_(QCursor.pos())
|
m.exec_(QCursor.pos())
|
||||||
|
|
||||||
def _buttons(self):
|
|
||||||
# refresh = QPushButton(_("Refresh"))
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def _hideRow(self, c):
|
def _hideRow(self, c):
|
||||||
if aqt.utils.askUser(_("""\
|
if aqt.utils.askUser(_("""\
|
||||||
Hide %s from the list? You can File>Open it again later.""") %
|
Hide %s from the list? You can File>Open it again later.""") %
|
||||||
|
@ -303,4 +325,4 @@ not be touched.""") % self._decks[c]['name']):
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
self._browserLastRefreshed = 0
|
self._browserLastRefreshed = 0
|
||||||
self.show()
|
self.show(_init=False)
|
||||||
|
|
13
aqt/main.py
13
aqt/main.py
|
@ -95,8 +95,6 @@ class AnkiQt(QMainWindow):
|
||||||
self.deck = None
|
self.deck = None
|
||||||
self.currentCard = None
|
self.currentCard = None
|
||||||
self.lastCard = None
|
self.lastCard = None
|
||||||
# perhaps we want a separate toolbar instead?
|
|
||||||
self.form.toolBar.hide()
|
|
||||||
self.disableDeckMenuItems()
|
self.disableDeckMenuItems()
|
||||||
self.closeAllDeckWindows()
|
self.closeAllDeckWindows()
|
||||||
self.deckBrowser.show()
|
self.deckBrowser.show()
|
||||||
|
@ -1406,8 +1404,7 @@ learnt today")
|
||||||
# Toolbar
|
# Toolbar
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def setupToolbar(self):
|
def setupReviewToolbar(self):
|
||||||
mw = self.form
|
|
||||||
mw.toolBar.addAction(mw.actionAddcards)
|
mw.toolBar.addAction(mw.actionAddcards)
|
||||||
mw.toolBar.addAction(mw.actionEditCurrent)
|
mw.toolBar.addAction(mw.actionEditCurrent)
|
||||||
mw.toolBar.addAction(mw.actionEditLayout)
|
mw.toolBar.addAction(mw.actionEditLayout)
|
||||||
|
@ -1417,8 +1414,12 @@ learnt today")
|
||||||
mw.toolBar.addAction(mw.actionMarkCard)
|
mw.toolBar.addAction(mw.actionMarkCard)
|
||||||
mw.toolBar.addAction(mw.actionRepeatAudio)
|
mw.toolBar.addAction(mw.actionRepeatAudio)
|
||||||
mw.toolBar.addAction(mw.actionClose)
|
mw.toolBar.addAction(mw.actionClose)
|
||||||
mw.toolBar.setIconSize(QSize(self.config['iconSize'],
|
|
||||||
self.config['iconSize']))
|
def setupToolbar(self):
|
||||||
|
mw = self.form
|
||||||
|
mw.toolBar.setIconSize(QSize(24, 24))
|
||||||
|
#mw.toolBar.setIconSize(QSize(self.config['iconSize'],
|
||||||
|
# self.config['iconSize']))
|
||||||
toggle = mw.toolBar.toggleViewAction()
|
toggle = mw.toolBar.toggleViewAction()
|
||||||
toggle.setText(_("Toggle Toolbar"))
|
toggle.setText(_("Toggle Toolbar"))
|
||||||
self.connect(toggle, SIGNAL("triggered()"),
|
self.connect(toggle, SIGNAL("triggered()"),
|
||||||
|
|
|
@ -71,9 +71,6 @@ class ProgressManager(object):
|
||||||
self._levels += 1
|
self._levels += 1
|
||||||
if self._levels > 1:
|
if self._levels > 1:
|
||||||
return
|
return
|
||||||
# disable UI
|
|
||||||
self.mw.app.setOverrideCursor(QCursor(Qt.WaitCursor))
|
|
||||||
self.mw.setEnabled(False)
|
|
||||||
# setup window
|
# setup window
|
||||||
parent = parent or self.app.activeWindow() or self.mw
|
parent = parent or self.app.activeWindow() or self.mw
|
||||||
label = label or _("Processing...")
|
label = label or _("Processing...")
|
||||||
|
@ -96,6 +93,7 @@ class ProgressManager(object):
|
||||||
self._max = max
|
self._max = max
|
||||||
self._firstTime = time.time()
|
self._firstTime = time.time()
|
||||||
self._lastTime = time.time()
|
self._lastTime = time.time()
|
||||||
|
self._disabled = False
|
||||||
|
|
||||||
def update(self, label=None, value=None, process=True):
|
def update(self, label=None, value=None, process=True):
|
||||||
#print self._min, self._counter, self._max, label, time.time() - self._lastTime
|
#print self._min, self._counter, self._max, label, time.time() - self._lastTime
|
||||||
|
@ -113,8 +111,7 @@ class ProgressManager(object):
|
||||||
self._levels -= 1
|
self._levels -= 1
|
||||||
if self._levels == 0:
|
if self._levels == 0:
|
||||||
self._win.cancel()
|
self._win.cancel()
|
||||||
self.app.restoreOverrideCursor()
|
self._enableUI()
|
||||||
self.mw.setEnabled(True)
|
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
"Restore the interface after an error."
|
"Restore the interface after an error."
|
||||||
|
@ -123,7 +120,22 @@ class ProgressManager(object):
|
||||||
self.finishProgress()
|
self.finishProgress()
|
||||||
|
|
||||||
def _maybeShow(self):
|
def _maybeShow(self):
|
||||||
if not self._shown and (time.time() - self._firstTime) > 2:
|
delta = time.time() - self._firstTime
|
||||||
print "show2"
|
# if more than 500ms have passed, disable the UI so the user doesn't
|
||||||
|
# try to click again. We don't do it immediately to avoid flicker.
|
||||||
|
if not self._disabled and delta > 0.5:
|
||||||
|
self._disableUI()
|
||||||
|
# if more than 2 seconds have passed, show a progress dialog
|
||||||
|
if not self._shown and delta > 2:
|
||||||
self._shown = True
|
self._shown = True
|
||||||
self._win.show()
|
self._win.show()
|
||||||
|
|
||||||
|
def _disableUI(self):
|
||||||
|
self._disabled = True
|
||||||
|
self.mw.app.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||||
|
self.mw.setEnabled(False)
|
||||||
|
|
||||||
|
def _enableUI(self):
|
||||||
|
self._disabled = False
|
||||||
|
self.app.restoreOverrideCursor()
|
||||||
|
self.mw.setEnabled(True)
|
||||||
|
|
|
@ -68,6 +68,8 @@ class AnkiWebView(QWebView):
|
||||||
self.setHtml("""
|
self.setHtml("""
|
||||||
<html><head><style>%s</style><script src="qrc:/jquery.min.js"></script></head>
|
<html><head><style>%s</style><script src="qrc:/jquery.min.js"></script></head>
|
||||||
<body>%s</body></html>""" % (css, body), loadCB)
|
<body>%s</body></html>""" % (css, body), loadCB)
|
||||||
|
# ensure we're focused
|
||||||
|
self.setFocus()
|
||||||
def setBridge(self, bridge):
|
def setBridge(self, bridge):
|
||||||
self._bridge.setBridge(bridge)
|
self._bridge.setBridge(bridge)
|
||||||
def eval(self, js):
|
def eval(self, js):
|
||||||
|
|
|
@ -664,17 +664,31 @@
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionOpenOnline">
|
<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">
|
<property name="text">
|
||||||
<string>Personal Deck...</string>
|
<string>Personal Deck...</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="iconText">
|
||||||
|
<string>AnkiWeb</string>
|
||||||
|
</property>
|
||||||
<property name="statusTip">
|
<property name="statusTip">
|
||||||
<string>Download a deck that you synced from another computer</string>
|
<string>Download a deck that you synced from another computer</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionDownloadSharedDeck">
|
<action name="actionDownloadSharedDeck">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons.qrc">
|
||||||
|
<normaloff>:/icons/download.png</normaloff>:/icons/download.png</iconset>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Shared Deck...</string>
|
<string>Shared Deck...</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="iconText">
|
||||||
|
<string>Download</string>
|
||||||
|
</property>
|
||||||
<property name="statusTip">
|
<property name="statusTip">
|
||||||
<string>Download a deck that people have shared publicly</string>
|
<string>Download a deck that people have shared publicly</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -749,6 +763,15 @@
|
||||||
<string>Localize Media</string>
|
<string>Localize Media</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionRefreshDeckBrowser">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons.qrc">
|
||||||
|
<normaloff>:/icons/edit-redo.png</normaloff>:/icons/edit-redo.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Refresh</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="icons.qrc"/>
|
<include location="icons.qrc"/>
|
||||||
|
|
Loading…
Reference in a new issue