new toolbar for the browser

This commit is contained in:
Damien Elmes 2011-11-29 13:35:13 +09:00
parent 0411d9f11e
commit 1c58306d7a
15 changed files with 211 additions and 149 deletions

View file

@ -15,6 +15,7 @@ from anki.errors import *
from anki.db import *
from anki.hooks import runHook, addHook, removeHook
from aqt.webview import AnkiWebView
from aqt.toolbar import Toolbar
COLOUR_SUSPENDED1 = "#ffffcc"
COLOUR_SUSPENDED2 = "#ffffaa"
@ -304,15 +305,14 @@ class Browser(QMainWindow):
self.lastFilter = ""
self.form = aqt.forms.browser.Ui_Dialog()
self.form.setupUi(self)
self.setUnifiedTitleAndToolBarOnMac(True)
restoreGeom(self, "editor", 38)
#self.setUnifiedTitleAndToolBarOnMac(True)
restoreGeom(self, "editor", 0)
restoreState(self, "editor")
restoreSplitter(self.form.splitter_2, "editor2")
restoreSplitter(self.form.splitter, "editor3")
self.form.splitter_2.setChildrenCollapsible(False)
self.form.splitter.setChildrenCollapsible(False)
self.setupColumns()
self.setupToolbar()
self.setupTable()
self.setupMenus()
self.setupSearch()
@ -320,7 +320,8 @@ class Browser(QMainWindow):
self.setupHeaders()
self.setupHooks()
self.setupEditor()
self.setupCardInfo()
self.setupToolbar()
#self.setupCardInfo()
self.updateFont()
self.onUndoState(self.mw.form.actionUndo.isEnabled())
self.form.searchEdit.setFocus()
@ -330,8 +331,10 @@ class Browser(QMainWindow):
self.onSearch()
def setupToolbar(self):
self.form.toolBar.setIconSize(QSize(24, 24))
self.form.toolBar.toggleViewAction().setText(_("Toggle Toolbar"))
self.toolbarWeb = AnkiWebView()
self.toolbarWeb.setFixedHeight(34)
self.toolbar = BrowserToolbar(self.mw, self.toolbarWeb, self)
self.form.verticalLayout_3.insertWidget(0, self.toolbarWeb)
def setupMenus(self):
# actions
@ -491,7 +494,7 @@ class Browser(QMainWindow):
def onRowChanged(self, current, previous):
"Update current note and hide/show editor."
show = self.model.cards and self.updateTitle() == 1
self.form.splitter_2.widget(1).setShown(not not show)
self.form.splitter.widget(1).setShown(not not show)
if not show:
self.editor.setNote(None)
else:
@ -500,7 +503,7 @@ class Browser(QMainWindow):
self.editor.setNote(self.card.note())
self.editor.card = self.card
self.showCardInfo(self.card)
self.updateToggles()
self.toolbar.draw()
def refreshCurrentCard(self, note):
self.model.refreshNote(note)
@ -690,6 +693,7 @@ class Browser(QMainWindow):
self.onCardLink)
def showCardInfo(self, card):
return
self.cardStats.card = self.card
rep = self.cardStats.report()
rep = "<style>table * { font-size: 12px; }</style>" + rep
@ -858,10 +862,10 @@ where id in %s""" % ids2str(sf))
self.model.endReset()
self.mw.requireReset()
# Group change
# Deck change
######################################################################
def setGroup(self, initial=False):
def setDeck(self, initial=False):
d = QDialog(self)
d.setWindowModality(Qt.WindowModal)
frm = aqt.forms.setgroup.Ui_Dialog()
@ -870,7 +874,7 @@ where id in %s""" % ids2str(sf))
te = TagEdit(d, type=1)
frm.groupBox.layout().insertWidget(0, te)
te.setCol(self.col)
d.connect(d, SIGNAL("accepted()"), lambda: self.onSetGroup(frm, te))
d.connect(d, SIGNAL("accepted()"), lambda: self._onSetDeck(frm, te))
self.setTabOrder(frm.setCur, te)
self.setTabOrder(te, frm.setInitial)
if initial:
@ -878,22 +882,22 @@ where id in %s""" % ids2str(sf))
d.show()
te.setFocus()
def onSetGroup(self, frm, te):
def _onSetDeck(self, frm, te):
self.model.beginReset()
self.mw.checkpoint(_("Set Group"))
self.mw.checkpoint(_("Set Deck"))
mod = intTime()
if frm.setCur.isChecked():
gid = self.col.groups.id(unicode(te.text()))
did = self.col.decks.id(unicode(te.text()))
self.col.db.execute(
"update cards set mod=?, gid=? where id in " + ids2str(
self.selectedCards()), mod, gid)
"update cards set mod=?, did=? where id in " + ids2str(
self.selectedCards()), mod, did)
if frm.setInitial.isChecked():
self.col.db.execute(
"update notes set mod=?, gid=? where id in " + ids2str(
self.selectedNotes()), mod, gid)
"update notes set mod=?, did=? where id in " + ids2str(
self.selectedNotes()), mod, did)
else:
self.col.db.execute("""
update cards set mod=?, gid=(select gid from notes where id = cards.nid)
update cards set mod=?, did=(select did from notes where id = cards.nid)
where id in %s""" % ids2str(self.selectedCards()), mod)
self.onSearch(reset=False)
self.mw.requireReset()
@ -932,14 +936,12 @@ where id in %s""" % ids2str(self.selectedCards()), mod)
# Suspending and marking
######################################################################
def updateToggles(self):
self.form.actionToggleSuspend.setChecked(self.isSuspended())
self.form.actionToggleMark.setChecked(self.isMarked())
def isSuspended(self):
return not not (self.card and self.card.queue == -1)
def onSuspend(self, sus):
def onSuspend(self, sus=None):
if sus is None:
sus = not self.isSuspended()
# focus lost hook may not have chance to fire
self.editor.saveNow()
c = self.selectedCards()
@ -953,7 +955,9 @@ where id in %s""" % ids2str(self.selectedCards()), mod)
def isMarked(self):
return not not (self.card and self.card.note().hasTag("Marked"))
def onMark(self, mark):
def onMark(self, mark=None):
if mark is None:
mark = not self.isMarked()
if mark:
self.addTags(tags="marked", label=False)
else:
@ -1397,3 +1401,69 @@ Are you sure you want to continue?""")):
def onHelp(self):
openHelp("Browser#ChangeModel")
# Toolbar
######################################################################
class BrowserToolbar(Toolbar):
always = [
["setDeck", "Move to Deck"],
["addTags", "Add Tags"],
["remTags", "Remove Tags"],
]
singleOnly = [
["info", "Info"],
]
rightIcons = [
["mark", "qrc:/icons/star16.png"],
["pause", "qrc:/icons/star_off16.png"],
]
def __init__(self, mw, web, browser):
self.browser = browser
Toolbar.__init__(self, mw, web)
def draw(self):
single = self.browser.editor.note
mark = self.browser.isMarked()
pause = self.browser.isSuspended()
links = self.always[:]
if single:
links += self.singleOnly
self.centerLinks = links
def borderImg(link, icon, on):
if on:
fmt = '''\
<a class=hitem href="%s">
<img style='background: #000;' src="qrc:/icons/%s.png"></a>'''
else:
fmt = '''\
<a class=hitem href="%s"><img src="qrc:/icons/%s.png"></a>'''
return fmt % (link, icon)
right = ""
right += borderImg("mark", "star16", mark)
right += borderImg("pause", "pause16", pause)
self.web.stdHtml(self._body % (
'<a class="hitem" href="anki">Browser &#9662</a>',
self._centerLinks(),
right), self._css, focus=False)
# Link handling
######################################################################
def _linkHandler(self, l):
if l == "anki":
self.showMenu()
elif l == "setDeck":
self.browser.setDeck()
elif l == "addTags":
self.browser.addTags()
elif l == "remTags":
self.browser.deleteTags()
# icons
elif l == "mark":
self.browser.onMark()
elif l == "pause":
self.browser.onSuspend()

View file

@ -426,7 +426,6 @@ class Editor(object):
def showDupes(self):
contents = self.note.fields[0]
print "conts", `self.note.fields`
browser = aqt.dialogs.open("Browser", self.mw)
browser.form.searchEdit.setText(
"'model:%s' '%s'" % (self.note.model()['name'], contents))

View file

@ -322,10 +322,12 @@ title="%s">%s</button>''' % (
tweb.setFocusPolicy(Qt.WheelFocus)
tweb.setFixedHeight(32)
self.toolbar = aqt.toolbar.Toolbar(self, tweb)
self.toolbar.draw()
# main area
self.web = aqt.webview.AnkiWebView()
self.web.setObjectName("mainText")
self.web.setFocusPolicy(Qt.WheelFocus)
self.web.setMinimumWidth(400)
# add in a layout
self.mainLayout = QVBoxLayout()
self.mainLayout.setContentsMargins(0,0,0,0)
@ -527,17 +529,21 @@ Debug info:\n%s""") % traceback.format_exc(), help="DeckErrors")
# Dockable widgets
##########################################################################
def addDockable(self, title, w):
dock = QDockWidget(title, self)
def addDockable(self, title, w, target=None):
target = target or self
dock = QDockWidget(title, target)
dock.setObjectName(title)
dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
dock.setFeatures(QDockWidget.DockWidgetClosable)
dock.setWidget(w)
self.addDockWidget(Qt.RightDockWidgetArea, dock)
if target.width() < 600:
target.resize(QSize(600, target.height()))
target.addDockWidget(Qt.RightDockWidgetArea, dock)
return dock
def rmDockable(self, dock):
self.removeDockWidget(dock)
def rmDockable(self, dock, target=None):
target = target or self
target.removeDockWidget(dock)
# Marking, suspending and deleting
##########################################################################

View file

@ -23,8 +23,10 @@ class CardStats(object):
def show(self):
if not self.shown:
self.web = AnkiWebView()
self.web.setMaximumWidth(400)
class ThinAnkiWebView(AnkiWebView):
def sizeHint(self):
return QSize(200, 100)
self.web = ThinAnkiWebView()
self.shown = self.mw.addDockable(_("Card Info"), self.web)
self.shown.connect(self.shown, SIGNAL("visibilityChanged(bool)"),
self._visChange)

View file

@ -6,7 +6,7 @@ import re, sys
class TagEdit(QLineEdit):
# 0 = tags, 1 = groups
# 0 = tags, 1 = decks
def __init__(self, parent, type=0):
QLineEdit.__init__(self, parent)
self.col = None
@ -26,7 +26,7 @@ class TagEdit(QLineEdit):
if self.type == 0:
l = sorted(self.col.tags.all())
else:
l = self.col.groups.all()
l = sorted(self.col.decks.allNames())
self.model.setStringList(l)
def addTags(self, tags):
@ -50,7 +50,7 @@ class TagCompleter(QCompleter):
def splitPath(self, str):
str = unicode(str).strip()
str = re.sub(" +", " ", str)
self.tags = self.parent.col.tags.split(str)
self.tags = self.edit.col.tags.split(str)
self.tags.append(u"")
p = self.edit.cursorPosition()
self.cursor = str.count(" ", 0, p)

View file

@ -13,11 +13,13 @@ class Toolbar(object):
self.web.page().mainFrame().setScrollBarPolicy(
Qt.Vertical, Qt.ScrollBarAlwaysOff)
self.web.setLinkHandler(self._linkHandler)
self.draw()
def draw(self):
body = self._body % (self._centerLinks(), self._rightIcons())
self.web.stdHtml(body, self._css)
self.web.stdHtml(self._body % (
'<a class="hitem" href="anki">Anki &#9662</a>',
self._centerLinks(),
self._rightIcons()),
self._css, focus=False)
# Available links
######################################################################
@ -38,6 +40,7 @@ class Toolbar(object):
buf = ""
for ln, name in self.centerLinks:
buf += '<a class=hitem href="%s">%s</a>' % (ln, _(name))
buf += "&nbsp;"*3
return buf
def _rightIcons(self):
@ -72,9 +75,9 @@ class Toolbar(object):
_body = """
<table id=header width=100%%>
<tr>
<td width=20%%><a class="hitem" href="anki">Anki &#9662</a></td>
<td align=left>%s</td>
<td align=center>%s</td>
<td width=20%% align=right>%s</td>
<td align=right>%s</td>
</tr></table>
"""

View file

@ -208,7 +208,7 @@ def chooseList(prompt, choices, startrow=0, parent=None):
def getTag(parent, deck, question, tags="user", **kwargs):
from aqt.tagedit import TagEdit
te = TagEdit(parent)
te.setDeck(deck)
te.setCol(deck)
return getText(question, parent, edit=te, **kwargs)
# File handling

View file

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

View file

@ -6,10 +6,16 @@
<rect>
<x>0</x>
<y>0</y>
<width>524</width>
<height>382</height>
<width>610</width>
<height>430</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Browser</string>
</property>
@ -19,34 +25,40 @@
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QSplitter" name="splitter_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTreeWidget" name="tree">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Vertical</enum>
</property>
<widget class="QTreeWidget" name="tree">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
@ -98,7 +110,7 @@
<widget class="QTableView" name="tableView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>4</horstretch>
<horstretch>0</horstretch>
<verstretch>4</verstretch>
</sizepolicy>
</property>
@ -142,58 +154,48 @@
</item>
</layout>
</widget>
</widget>
<widget class="QWidget" name="verticalLayoutWidget">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout2">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="fieldsArea" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>7</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>50</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="cardLabel">
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="margin">
<number>6</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
<widget class="QWidget" name="verticalLayoutWidget">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout2">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="fieldsArea" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>50</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
@ -204,7 +206,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>524</width>
<width>610</width>
<height>22</height>
</rect>
</property>
@ -274,37 +276,6 @@
<addaction name="menuJump"/>
<addaction name="menu_Help"/>
</widget>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonIconOnly</enum>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionAddItems"/>
<addaction name="separator"/>
<addaction name="actionSetDeck"/>
<addaction name="separator"/>
<addaction name="actionAddTag"/>
<addaction name="actionDeleteTag"/>
<addaction name="separator"/>
<addaction name="actionToggleMark"/>
<addaction name="actionToggleSuspend"/>
<addaction name="separator"/>
<addaction name="actionDelete"/>
</widget>
<action name="actionDelete">
<property name="icon">
<iconset resource="icons.qrc">

View file

@ -117,5 +117,9 @@
<file>icons/stock_new_template_green.png</file>
<file>icons/stock_new_template_red.png</file>
<file>icons/stock_group.png</file>
<file>icons/star16.png</file>
<file>icons/star_off16.png</file>
<file>icons/pause16.png</file>
<file>icons/pause_off16.png</file>
</qresource>
</RCC>

BIN
designer/icons/pause16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

BIN
designer/icons/star16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -16,6 +16,12 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Anki</string>
</property>