Merge pull request #967 from RumovZ/dyn-deckconf

Dyn deckconf
This commit is contained in:
Damien Elmes 2021-02-02 09:41:23 +10:00 committed by GitHub
commit 68ea2fce49
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 347 additions and 135 deletions

View file

@ -24,6 +24,8 @@ browsing-change-to = Change { $val } to:
browsing-clear-unused = Clear Unused browsing-clear-unused = Clear Unused
browsing-clear-unused-tags = Clear Unused Tags browsing-clear-unused-tags = Clear Unused Tags
browsing-created = Created browsing-created = Created
browsing-create-filtered-deck = Create Filtered Deck...
browsing-create-filtered-deck_2 = Create Filtered Deck (2nd Filter)...
browsing-ctrlandshiftande = Ctrl+Shift+E browsing-ctrlandshiftande = Ctrl+Shift+E
browsing-current-deck = Current Deck browsing-current-deck = Current Deck
browsing-current-note-type = Current note type: browsing-current-note-type = Current note type:

View file

@ -35,3 +35,5 @@ search-card-modified = Card Modified
## ##
# Tooltip for search lines outside browser
search-view-in-browser = View in browser

View file

@ -69,7 +69,7 @@ except ImportError as e:
# - make preferences modal? cmd+q does wrong thing # - make preferences modal? cmd+q does wrong thing
from aqt import addcards, addons, browser, editcurrent # isort:skip from aqt import addcards, addons, browser, editcurrent, dyndeckconf # isort:skip
from aqt import stats, about, preferences, mediasync # isort:skip from aqt import stats, about, preferences, mediasync # isort:skip
@ -80,6 +80,7 @@ class DialogManager:
"AddonsDialog": [addons.AddonsDialog, None], "AddonsDialog": [addons.AddonsDialog, None],
"Browser": [browser.Browser, None], "Browser": [browser.Browser, None],
"EditCurrent": [editcurrent.EditCurrent, None], "EditCurrent": [editcurrent.EditCurrent, None],
"DynDeckConfDialog": [dyndeckconf.DeckConf, None],
"DeckStats": [stats.DeckStats, None], "DeckStats": [stats.DeckStats, None],
"NewDeckStats": [stats.NewDeckStats, None], "NewDeckStats": [stats.NewDeckStats, None],
"About": [about.show, None], "About": [about.show, None],
@ -87,7 +88,7 @@ class DialogManager:
"sync_log": [mediasync.MediaSyncDialog, None], "sync_log": [mediasync.MediaSyncDialog, None],
} }
def open(self, name: str, *args: Any) -> Any: def open(self, name: str, *args: Any, **kwargs: Any) -> Any:
(creator, instance) = self._dialogs[name] (creator, instance) = self._dialogs[name]
if instance: if instance:
if instance.windowState() & Qt.WindowMinimized: if instance.windowState() & Qt.WindowMinimized:
@ -95,10 +96,9 @@ class DialogManager:
instance.activateWindow() instance.activateWindow()
instance.raise_() instance.raise_()
if hasattr(instance, "reopen"): if hasattr(instance, "reopen"):
instance.reopen(*args) instance.reopen(*args, **kwargs)
return instance
else: else:
instance = creator(*args) instance = creator(*args, **kwargs)
self._dialogs[name][1] = instance self._dialogs[name][1] = instance
return instance return instance

View file

@ -162,7 +162,7 @@ class AddCards(QDialog):
m.exec_(self.historyButton.mapToGlobal(QPoint(0, 0))) m.exec_(self.historyButton.mapToGlobal(QPoint(0, 0)))
def editHistory(self, nid) -> None: def editHistory(self, nid) -> None:
self.mw.browser_search(SearchTerm(nid=nid)) aqt.dialogs.open("Browser", self.mw, search=(SearchTerm(nid=nid),))
def addNote(self, note) -> Optional[Note]: def addNote(self, note) -> Optional[Note]:
note.model()["did"] = self.deckChooser.selectedId() note.model()["did"] = self.deckChooser.selectedId()

View file

@ -444,7 +444,12 @@ class Browser(QMainWindow):
col: Collection col: Collection
editor: Optional[Editor] editor: Optional[Editor]
def __init__(self, mw: AnkiQt) -> None: def __init__(
self,
mw: AnkiQt,
card: Optional[Card] = None,
search: Optional[Tuple[Union[str, SearchTerm]]] = None,
) -> None:
QMainWindow.__init__(self, None, Qt.Window) QMainWindow.__init__(self, None, Qt.Window)
self.mw = mw self.mw = mw
self.col = self.mw.col self.col = self.mw.col
@ -468,7 +473,7 @@ class Browser(QMainWindow):
self.setupEditor() self.setupEditor()
self.updateFont() self.updateFont()
self.onUndoState(self.mw.form.actionUndo.isEnabled()) self.onUndoState(self.mw.form.actionUndo.isEnabled())
self.setupSearch() self.setupSearch(card, search)
gui_hooks.browser_will_show(self) gui_hooks.browser_will_show(self)
self.show() self.show()
@ -483,6 +488,10 @@ class Browser(QMainWindow):
qconnect(f.actionSelectNotes.triggered, self.selectNotes) qconnect(f.actionSelectNotes.triggered, self.selectNotes)
if not isMac: if not isMac:
f.actionClose.setVisible(False) f.actionClose.setVisible(False)
qconnect(f.actionCreateFilteredDeck.triggered, self.createFilteredDeck)
qconnect(f.actionCreateFilteredDeck2.triggered, self.createFilteredDeck2)
if self.mw.col.schedVer() == 1:
f.menuEdit.removeAction(f.actionCreateFilteredDeck2)
# notes # notes
qconnect(f.actionAdd.triggered, self.mw.onAddCard) qconnect(f.actionAdd.triggered, self.mw.onAddCard)
qconnect(f.actionAdd_Tags.triggered, lambda: self.addTags()) qconnect(f.actionAdd_Tags.triggered, lambda: self.addTags())
@ -606,17 +615,41 @@ class Browser(QMainWindow):
] ]
self.columns.sort(key=itemgetter(1)) self.columns.sort(key=itemgetter(1))
def reopen(
self,
_mw: AnkiQt,
card: Optional[Card] = None,
search: Optional[Tuple[Union[str, SearchTerm]]] = None,
) -> None:
if search is not None:
self.search_for_terms(*search)
self.form.searchEdit.setFocus()
elif card:
self.show_single_card(card)
self.form.searchEdit.setFocus()
# Searching # Searching
###################################################################### ######################################################################
def setupSearch(self) -> None: def setupSearch(
self,
card: Optional[Card] = None,
search: Optional[Tuple[Union[str, SearchTerm]]] = None,
) -> None:
qconnect(self.form.searchEdit.lineEdit().returnPressed, self.onSearchActivated) qconnect(self.form.searchEdit.lineEdit().returnPressed, self.onSearchActivated)
self.form.searchEdit.setCompleter(None) self.form.searchEdit.setCompleter(None)
self.form.searchEdit.lineEdit().setPlaceholderText( self.form.searchEdit.lineEdit().setPlaceholderText(
tr(TR.BROWSING_SEARCH_BAR_HINT) tr(TR.BROWSING_SEARCH_BAR_HINT)
) )
self.form.searchEdit.addItems(self.mw.pm.profile["searchHistory"]) self.form.searchEdit.addItems(self.mw.pm.profile["searchHistory"])
self.search_for(self.col.build_search_string(SearchTerm(deck="current")), "") if search is not None:
self.search_for_terms(*search)
elif card:
self.show_single_card(card)
else:
self.search_for(
self.col.build_search_string(SearchTerm(deck="current")), ""
)
self.form.searchEdit.setFocus() self.form.searchEdit.setFocus()
# search triggered by user # search triggered by user
@ -675,15 +708,17 @@ class Browser(QMainWindow):
) )
return selected return selected
def show_single_card(self, card: Optional[Card]) -> None: def search_for_terms(self, *search_terms: Union[str, SearchTerm]) -> None:
"""Try to search for the according note and select the given card.""" search = self.col.build_search_string(*search_terms)
self.form.searchEdit.setEditText(search)
self.onSearchActivated()
nid: Optional[int] = card and card.nid or 0 def show_single_card(self, card: Card) -> None:
if nid: if card.nid:
def on_show_single_card() -> None: def on_show_single_card() -> None:
self.card = card self.card = card
search = self.col.build_search_string(SearchTerm(nid=nid)) search = self.col.build_search_string(SearchTerm(nid=card.nid))
search = gui_hooks.default_search(search, card) search = gui_hooks.default_search(search, card)
self.search_for(search, "") self.search_for(search, "")
self.focusCid(card.id) self.focusCid(card.id)
@ -1162,6 +1197,14 @@ where id in %s"""
if nids: if nids:
ChangeModel(self, nids) ChangeModel(self, nids)
def createFilteredDeck(self) -> None:
search = self.form.searchEdit.lineEdit().text()
aqt.dialogs.open("DynDeckConfDialog", self.mw, search=search)
def createFilteredDeck2(self) -> None:
search = self.form.searchEdit.lineEdit().text()
aqt.dialogs.open("DynDeckConfDialog", self.mw, search_2=search)
# Preview # Preview
###################################################################### ######################################################################

View file

@ -1,14 +1,16 @@
# Copyright: Ankitects Pty Ltd and contributors # Copyright: Ankitects Pty Ltd and contributors
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from typing import Dict, List, Optional from typing import Callable, List, Optional
import aqt import aqt
from anki.collection import SearchTerm from anki.collection import SearchTerm
from anki.decks import Deck, DeckRenameError
from anki.errors import InvalidInput from anki.errors import InvalidInput
from anki.lang import without_unicode_isolation from anki.lang import without_unicode_isolation
from aqt.main import AnkiQt from aqt import AnkiQt, gui_hooks
from aqt.qt import * from aqt.qt import *
from aqt.theme import theme_manager
from aqt.utils import ( from aqt.utils import (
TR, TR,
HelpPage, HelpPage,
@ -24,25 +26,55 @@ from aqt.utils import (
class DeckConf(QDialog): class DeckConf(QDialog):
"""Dialogue to modify and build a filtered deck."""
def __init__( def __init__(
self, self,
mw: AnkiQt, mw: AnkiQt,
first: bool = False, search: Optional[str] = None,
search: str = "", search_2: Optional[str] = None,
deck: Optional[Dict] = None, deck: Optional[Deck] = None,
) -> None: ) -> None:
"""If 'deck' is an existing filtered deck, load and modify its settings.
Otherwise, build a new one and derive settings from the current deck.
"""
QDialog.__init__(self, mw) QDialog.__init__(self, mw)
self.mw = mw self.mw = mw
self.deck = deck or self.mw.col.decks.current() self.did: Optional[int] = None
self.search = search
self.form = aqt.forms.dyndconf.Ui_Dialog() self.form = aqt.forms.dyndconf.Ui_Dialog()
self.form.setupUi(self) self.form.setupUi(self)
if first:
label = tr(TR.DECKS_BUILD)
else:
label = tr(TR.ACTIONS_REBUILD)
self.ok = self.form.buttonBox.addButton(label, QDialogButtonBox.AcceptRole)
self.mw.checkpoint(tr(TR.ACTIONS_OPTIONS)) self.mw.checkpoint(tr(TR.ACTIONS_OPTIONS))
self.initialSetup()
self.old_deck = self.mw.col.decks.current()
if deck and deck["dyn"]:
# modify existing dyn deck
label = tr(TR.ACTIONS_REBUILD)
self.deck = deck
self.loadConf()
elif self.old_deck["dyn"]:
# create new dyn deck from other dyn deck
label = tr(TR.DECKS_BUILD)
self.loadConf(deck=self.old_deck)
self.new_dyn_deck()
else:
# create new dyn deck from regular deck
label = tr(TR.DECKS_BUILD)
self.new_dyn_deck()
self.loadConf()
self.set_default_searches(self.old_deck["name"])
self.form.name.setText(self.deck["name"])
self.form.name.setPlaceholderText(self.deck["name"])
self.set_custom_searches(search, search_2)
qconnect(self.form.search_button.clicked, self.on_search_button)
qconnect(self.form.search_button_2.clicked, self.on_search_button_2)
color = theme_manager.str_color("link")
self.setStyleSheet(
f"""QPushButton[flat=true] {{ text-align: left; color: {color}; padding: 0; border: 0 }}
QPushButton[flat=true]:hover {{ text-decoration: underline }}"""
)
disable_help_button(self) disable_help_button(self)
self.setWindowModality(Qt.WindowModal) self.setWindowModality(Qt.WindowModal)
qconnect( qconnect(
@ -51,26 +83,63 @@ class DeckConf(QDialog):
self.setWindowTitle( self.setWindowTitle(
without_unicode_isolation(tr(TR.ACTIONS_OPTIONS_FOR, val=self.deck["name"])) without_unicode_isolation(tr(TR.ACTIONS_OPTIONS_FOR, val=self.deck["name"]))
) )
restoreGeom(self, "dyndeckconf") self.form.buttonBox.button(QDialogButtonBox.Ok).setText(label)
self.initialSetup() self.form.buttonBox.button(QDialogButtonBox.Cancel).setText(
self.loadConf() tr(TR.ACTIONS_CANCEL)
if search:
search = self.mw.col.build_search_string(
search, SearchTerm(card_state=SearchTerm.CARD_STATE_DUE)
) )
self.form.search.setText(search) self.form.buttonBox.button(QDialogButtonBox.Help).setText(tr(TR.ACTIONS_HELP))
search_2 = self.mw.col.build_search_string(
search, SearchTerm(card_state=SearchTerm.CARD_STATE_NEW)
)
self.form.search_2.setText(search_2)
self.form.search.selectAll()
if self.mw.col.schedVer() == 1: if self.mw.col.schedVer() == 1:
self.form.secondFilter.setVisible(False) self.form.secondFilter.setVisible(False)
restoreGeom(self, "dyndeckconf")
self.show() self.show()
self.exec_()
saveGeom(self, "dyndeckconf") def reopen(
self,
_mw: AnkiQt,
search: Optional[str] = None,
search_2: Optional[str] = None,
_deck: Optional[Deck] = None,
) -> None:
self.set_custom_searches(search, search_2)
def new_dyn_deck(self) -> None:
suffix: int = 1
while self.mw.col.decks.id_for_name(
without_unicode_isolation(tr(TR.QT_MISC_FILTERED_DECK, val=suffix))
):
suffix += 1
name: str = without_unicode_isolation(tr(TR.QT_MISC_FILTERED_DECK, val=suffix))
self.did = self.mw.col.decks.new_filtered(name)
self.deck = self.mw.col.decks.current()
def set_default_searches(self, deck_name: str) -> None:
self.form.search.setText(
self.mw.col.build_search_string(
SearchTerm(deck=deck_name),
SearchTerm(card_state=SearchTerm.CARD_STATE_DUE),
)
)
self.form.search_2.setText(
self.mw.col.build_search_string(
SearchTerm(deck=deck_name),
SearchTerm(card_state=SearchTerm.CARD_STATE_NEW),
)
)
def set_custom_searches(
self, search: Optional[str], search_2: Optional[str]
) -> None:
if search is not None:
self.form.search.setText(search)
self.form.search.setFocus()
self.form.search.selectAll()
if search_2 is not None:
self.form.secondFilter.setChecked(True)
self.form.filter2group.setVisible(True)
self.form.search_2.setText(search_2)
self.form.search_2.setFocus()
self.form.search_2.selectAll()
def initialSetup(self) -> None: def initialSetup(self) -> None:
import anki.consts as cs import anki.consts as cs
@ -80,14 +149,30 @@ class DeckConf(QDialog):
qconnect(self.form.resched.stateChanged, self._onReschedToggled) qconnect(self.form.resched.stateChanged, self._onReschedToggled)
def on_search_button(self) -> None:
self._on_search_button(self.form.search)
def on_search_button_2(self) -> None:
self._on_search_button(self.form.search_2)
def _on_search_button(self, line: QLineEdit) -> None:
try:
search = self.mw.col.build_search_string(line.text())
except InvalidInput as err:
line.setFocus()
line.selectAll()
show_invalid_search_error(err)
else:
aqt.dialogs.open("Browser", self.mw, search=(search,))
def _onReschedToggled(self, _state: int) -> None: def _onReschedToggled(self, _state: int) -> None:
self.form.previewDelayWidget.setVisible( self.form.previewDelayWidget.setVisible(
not self.form.resched.isChecked() and self.mw.col.schedVer() > 1 not self.form.resched.isChecked() and self.mw.col.schedVer() > 1
) )
def loadConf(self) -> None: def loadConf(self, deck: Optional[Deck] = None) -> None:
f = self.form f = self.form
d = self.deck d = deck or self.deck
f.resched.setChecked(d["resched"]) f.resched.setChecked(d["resched"])
self._onReschedToggled(0) self._onReschedToggled(0)
@ -123,6 +208,11 @@ class DeckConf(QDialog):
def saveConf(self) -> None: def saveConf(self) -> None:
f = self.form f = self.form
d = self.deck d = self.deck
if f.name.text() and d["name"] != f.name.text():
self.mw.col.decks.rename(d, f.name.text())
gui_hooks.sidebar_should_refresh_decks()
d["resched"] = f.resched.isChecked() d["resched"] = f.resched.isChecked()
d["delays"] = None d["delays"] = None
@ -146,29 +236,45 @@ class DeckConf(QDialog):
self.mw.col.decks.save(d) self.mw.col.decks.save(d)
def reject(self) -> None: def reject(self) -> None:
self.ok = False if self.did:
self.mw.col.decks.rem(self.did)
self.mw.col.decks.select(self.old_deck["id"])
saveGeom(self, "dyndeckconf")
QDialog.reject(self) QDialog.reject(self)
aqt.dialogs.markClosed("DynDeckConfDialog")
def accept(self) -> None: def accept(self) -> None:
try: try:
self.saveConf() self.saveConf()
except InvalidInput as err: except InvalidInput as err:
show_invalid_search_error(err) show_invalid_search_error(err)
return except DeckRenameError as err:
showWarning(err.description)
else:
if not self.mw.col.sched.rebuild_filtered_deck(self.deck["id"]): if not self.mw.col.sched.rebuild_filtered_deck(self.deck["id"]):
if askUser(tr(TR.DECKS_THE_PROVIDED_SEARCH_DID_NOT_MATCH)): if askUser(tr(TR.DECKS_THE_PROVIDED_SEARCH_DID_NOT_MATCH)):
return return
saveGeom(self, "dyndeckconf")
self.mw.reset() self.mw.reset()
QDialog.accept(self) QDialog.accept(self)
aqt.dialogs.markClosed("DynDeckConfDialog")
def closeWithCallback(self, callback: Callable) -> None:
self.reject()
callback()
# Step load/save - fixme: share with std options screen # Step load/save - fixme: share with std options screen
######################################################## ########################################################
def listToUser(self, l) -> str: def listToUser(self, values: List[Union[float, int]]) -> str:
return " ".join([str(x) for x in l]) return " ".join(
[str(int(val)) if int(val) == val else str(val) for val in values]
)
def userToList(self, w, minSize=1) -> Optional[List[Union[float, int]]]: def userToList(
items = str(w.text()).split(" ") self, line: QLineEdit, minSize: int = 1
) -> Optional[List[Union[float, int]]]:
items = str(line.text()).split(" ")
ret = [] ret = []
for item in items: for item in items:
if not item: if not item:

View file

@ -542,12 +542,17 @@ class Editor:
self.web.eval("setBackgrounds(%s);" % json.dumps(cols)) self.web.eval("setBackgrounds(%s);" % json.dumps(cols))
def showDupes(self) -> None: def showDupes(self) -> None:
self.mw.browser_search( aqt.dialogs.open(
"Browser",
self.mw,
search=(
SearchTerm( SearchTerm(
dupe=SearchTerm.Dupe( dupe=SearchTerm.Dupe(
notetype_id=self.note.model()["id"], first_field=self.note.fields[0] notetype_id=self.note.model()["id"],
) first_field=self.note.fields[0],
) )
),
),
) )
def fieldsAreBlank(self, previousNote: Optional[Note] = None) -> bool: def fieldsAreBlank(self, previousNote: Optional[Note] = None) -> bool:

View file

@ -66,7 +66,7 @@ class EmptyCardsDialog(QDialog):
self._delete_button.clicked.connect(self._on_delete) self._delete_button.clicked.connect(self._on_delete)
def _on_note_link_clicked(self, link) -> None: def _on_note_link_clicked(self, link) -> None:
self.mw.browser_search(link) aqt.dialogs.open("Browser", self.mw, search=(link,))
def _on_delete(self) -> None: def _on_delete(self) -> None:
self.mw.progress.start() self.mw.progress.start()

View file

@ -230,6 +230,9 @@
<addaction name="actionInvertSelection"/> <addaction name="actionInvertSelection"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionClose"/> <addaction name="actionClose"/>
<addaction name="separator"/>
<addaction name="actionCreateFilteredDeck"/>
<addaction name="actionCreateFilteredDeck2"/>
</widget> </widget>
<widget class="QMenu" name="menuJump"> <widget class="QMenu" name="menuJump">
<property name="title"> <property name="title">
@ -583,6 +586,22 @@
<string notr="true">Ctrl+Shift+E</string> <string notr="true">Ctrl+Shift+E</string>
</property> </property>
</action> </action>
<action name="actionCreateFilteredDeck">
<property name="text">
<string>BROWSING_CREATE_FILTERED_DECK</string>
</property>
<property name="shortcut">
<string notr="true">Ctrl+G</string>
</property>
</action>
<action name="actionCreateFilteredDeck2">
<property name="text">
<string>BROWSING_CREATE_FILTERED_DECK_2</string>
</property>
<property name="shortcut">
<string notr="true">Ctrl+Shift+G</string>
</property>
</action>
</widget> </widget>
<resources> <resources>
<include location="icons.qrc"/> <include location="icons.qrc"/>

View file

@ -6,14 +6,56 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>392</width> <width>757</width>
<height>472</height> <height>589</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string notr="true">Dialog</string> <string notr="true">Dialog</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>DECKS_DECK</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>ACTIONS_NAME</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLineEdit" name="name">
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string notr="true"/>
</property>
</widget>
</item>
<item row="0" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="groupBox">
<property name="title"> <property name="title">
@ -21,20 +63,28 @@
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_5"> <widget class="QPushButton" name="search_button">
<property name="text"> <property name="focusPolicy">
<string>DECKS_LIMIT_TO</string> <enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>SEARCH_VIEW_IN_BROWSER</string>
</property> </property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>ACTIONS_SEARCH</string> <string>ACTIONS_SEARCH</string>
</property> </property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="2" colspan="4">
<widget class="QLineEdit" name="search"/>
</item>
<item row="2" column="2">
<widget class="QSpinBox" name="limit"> <widget class="QSpinBox" name="limit">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
@ -50,18 +100,22 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="2"> <item row="2" column="4" colspan="2">
<widget class="QComboBox" name="order"/>
</item>
<item row="2" column="3">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
<string>DECKS_CARDS_SELECTED_BY</string> <string>DECKS_CARDS_SELECTED_BY</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" colspan="4"> <item row="2" column="0">
<widget class="QLineEdit" name="search"/> <widget class="QLabel" name="label_5">
</item> <property name="text">
<item row="1" column="3" colspan="2"> <string>DECKS_LIMIT_TO</string>
<widget class="QComboBox" name="order"/> </property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -72,23 +126,32 @@
<string>DECKS_FILTER_2</string> <string>DECKS_FILTER_2</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3"> <layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_6"> <widget class="QPushButton" name="search_button_2">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>SEARCH_VIEW_IN_BROWSER</string>
</property>
<property name="text"> <property name="text">
<string>DECKS_LIMIT_TO</string> <string>ACTIONS_SEARCH</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="3" colspan="2">
<widget class="QComboBox" name="order_2"/>
</item>
<item row="0" column="1" colspan="4"> <item row="0" column="1" colspan="4">
<widget class="QLineEdit" name="search_2"/> <widget class="QLineEdit" name="search_2"/>
</item> </item>
<item row="0" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_6">
<property name="text"> <property name="text">
<string>ACTIONS_SEARCH</string> <string>DECKS_LIMIT_TO</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -108,6 +171,9 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="3" colspan="2">
<widget class="QComboBox" name="order_2"/>
</item>
<item row="1" column="2"> <item row="1" column="2">
<widget class="QLabel" name="label_4"> <widget class="QLabel" name="label_4">
<property name="text"> <property name="text">
@ -203,16 +269,19 @@
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="standardButtons"> <property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Help</set> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
</property> </property>
</widget> </widget>
</item> </item>
</layout> </layout>
</widget> </widget>
<tabstops> <tabstops>
<tabstop>name</tabstop>
<tabstop>search_button</tabstop>
<tabstop>search</tabstop> <tabstop>search</tabstop>
<tabstop>limit</tabstop> <tabstop>limit</tabstop>
<tabstop>order</tabstop> <tabstop>order</tabstop>
<tabstop>search_button_2</tabstop>
<tabstop>search_2</tabstop> <tabstop>search_2</tabstop>
<tabstop>limit_2</tabstop> <tabstop>limit_2</tabstop>
<tabstop>order_2</tabstop> <tabstop>order_2</tabstop>

View file

@ -14,7 +14,7 @@ import weakref
import zipfile import zipfile
from argparse import Namespace from argparse import Namespace
from threading import Thread from threading import Thread
from typing import Any, Callable, List, Optional, Sequence, TextIO, Tuple, Union, cast from typing import Any, Callable, List, Optional, Sequence, TextIO, Tuple, cast
import anki import anki
import aqt import aqt
@ -27,10 +27,9 @@ import aqt.toolbar
import aqt.webview import aqt.webview
from anki import hooks from anki import hooks
from anki._backend import RustBackend as _RustBackend from anki._backend import RustBackend as _RustBackend
from anki.collection import Collection, SearchTerm from anki.collection import Collection
from anki.decks import Deck from anki.decks import Deck
from anki.hooks import runHook from anki.hooks import runHook
from anki.lang import without_unicode_isolation
from anki.sound import AVTag, SoundOrVideoTag from anki.sound import AVTag, SoundOrVideoTag
from anki.utils import devMode, ids2str, intTime, isMac, isWin, splitFields from anki.utils import devMode, ids2str, intTime, isMac, isWin, splitFields
from aqt import gui_hooks from aqt import gui_hooks
@ -1055,22 +1054,19 @@ title="%s" %s>%s</button>""" % (
aqt.dialogs.open("AddCards", self) aqt.dialogs.open("AddCards", self)
def onBrowse(self) -> None: def onBrowse(self) -> None:
browser = aqt.dialogs.open("Browser", self) aqt.dialogs.open("Browser", self, card=self.reviewer.card)
browser.show_single_card(self.reviewer.card)
def onEditCurrent(self) -> None: def onEditCurrent(self) -> None:
aqt.dialogs.open("EditCurrent", self) aqt.dialogs.open("EditCurrent", self)
def onDeckConf(self, deck=None) -> None: def onDeckConf(self, deck: Optional[Deck] = None) -> None:
import aqt.deckconf
if not deck: if not deck:
deck = self.col.decks.current() deck = self.col.decks.current()
if deck["dyn"]: if deck["dyn"]:
import aqt.dyndeckconf aqt.dialogs.open("DynDeckConfDialog", self, deck=deck)
aqt.dyndeckconf.DeckConf(self, deck=deck)
else: else:
import aqt.deckconf
aqt.deckconf.DeckConf(self, deck) aqt.deckconf.DeckConf(self, deck)
def onOverview(self) -> None: def onOverview(self) -> None:
@ -1145,25 +1141,8 @@ title="%s" %s>%s</button>""" % (
# Cramming # Cramming
########################################################################## ##########################################################################
def onCram(self, search: str = "") -> None: def onCram(self) -> None:
import aqt.dyndeckconf aqt.dialogs.open("DynDeckConfDialog", self)
n = 1
deck = self.col.decks.current()
if not search:
if not deck["dyn"]:
search = self.col.build_search_string(SearchTerm(deck=deck["name"]))
while self.col.decks.id_for_name(
without_unicode_isolation(tr(TR.QT_MISC_FILTERED_DECK, val=n))
):
n += 1
name = without_unicode_isolation(tr(TR.QT_MISC_FILTERED_DECK, val=n))
did = self.col.decks.new_filtered(name)
diag = aqt.dyndeckconf.DeckConf(self, first=True, search=search)
if not diag.ok:
# user cancelled first config
self.col.decks.rem(did)
self.col.decks.select(deck["id"])
# Menu, title bar & status # Menu, title bar & status
########################################################################## ##########################################################################
@ -1630,14 +1609,3 @@ title="%s" %s>%s</button>""" % (
def serverURL(self) -> str: def serverURL(self) -> str:
return "http://127.0.0.1:%d/" % self.mediaServer.getPort() return "http://127.0.0.1:%d/" % self.mediaServer.getPort()
# Helpers for all windows
##########################################################################
def browser_search(self, *terms: Union[str, SearchTerm]) -> None:
"""Wrapper for col.build_search_string() to look up the result in the browser."""
search = self.col.build_search_string(*terms)
browser = aqt.dialogs.open("Browser", self)
browser.form.searchEdit.lineEdit().setText(search)
browser.onSearchActivated()

View file

@ -148,7 +148,7 @@ class MediaChecker:
if out is not None: if out is not None:
nid, err = out nid, err = out
self.mw.browser_search(SearchTerm(nid=nid)) aqt.dialogs.open("Browser", self.mw, search=(SearchTerm(nid=nid),))
showText(err, type="html") showText(err, type="html")
else: else:
tooltip(tr(TR.MEDIA_CHECK_ALL_LATEX_RENDERED)) tooltip(tr(TR.MEDIA_CHECK_ALL_LATEX_RENDERED))

View file

@ -7,7 +7,6 @@ from dataclasses import dataclass
from typing import Any, Callable, Dict, List, Optional, Tuple from typing import Any, Callable, Dict, List, Optional, Tuple
import aqt import aqt
from anki.collection import SearchTerm
from aqt import gui_hooks from aqt import gui_hooks
from aqt.sound import av_player from aqt.sound import av_player
from aqt.toolbar import BottomBar from aqt.toolbar import BottomBar
@ -72,8 +71,7 @@ class Overview:
elif url == "opts": elif url == "opts":
self.mw.onDeckConf() self.mw.onDeckConf()
elif url == "cram": elif url == "cram":
deck = self.mw.col.decks.current()["name"] aqt.dialogs.open("DynDeckConfDialog", self.mw)
self.mw.onCram(self.mw.col.build_search_string(SearchTerm(deck=deck)))
elif url == "refresh": elif url == "refresh":
self.mw.col.sched.rebuild_filtered_deck(self.mw.col.decks.selected()) self.mw.col.sched.rebuild_filtered_deck(self.mw.col.decks.selected())
self.mw.reset() self.mw.reset()