2019-02-05 04:59:03 +01:00
|
|
|
# Copyright: Ankitects Pty Ltd and contributors
|
2012-12-21 08:51:59 +01:00
|
|
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
|
2020-05-08 10:17:57 +02:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2012-12-22 01:17:10 +01:00
|
|
|
import re
|
2021-10-03 10:59:42 +02:00
|
|
|
from typing import Iterable
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2021-02-01 13:08:56 +01:00
|
|
|
from anki.collection import Collection
|
2020-03-31 15:00:26 +02:00
|
|
|
from aqt import gui_hooks
|
2019-12-20 10:19:03 +01:00
|
|
|
from aqt.qt import *
|
|
|
|
|
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
class TagEdit(QLineEdit):
|
2021-10-03 10:59:42 +02:00
|
|
|
_completer: QCompleter | TagCompleter
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2016-05-31 10:51:40 +02:00
|
|
|
lostFocus = pyqtSignal()
|
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
# 0 = tags, 1 = decks
|
2021-03-17 05:51:59 +01:00
|
|
|
def __init__(self, parent: QWidget, type: int = 0) -> None:
|
2012-12-21 08:51:59 +01:00
|
|
|
QLineEdit.__init__(self, parent)
|
2021-10-03 10:59:42 +02:00
|
|
|
self.col: Collection | None = None
|
2012-12-21 08:51:59 +01:00
|
|
|
self.model = QStringListModel()
|
|
|
|
self.type = type
|
|
|
|
if type == 0:
|
2021-03-17 05:51:59 +01:00
|
|
|
self._completer = TagCompleter(self.model, parent, self)
|
2012-12-21 08:51:59 +01:00
|
|
|
else:
|
2021-03-17 05:51:59 +01:00
|
|
|
self._completer = QCompleter(self.model, parent)
|
|
|
|
self._completer.setCompletionMode(QCompleter.PopupCompletion)
|
|
|
|
self._completer.setCaseSensitivity(Qt.CaseInsensitive)
|
|
|
|
self._completer.setFilterMode(Qt.MatchContains)
|
|
|
|
self.setCompleter(self._completer)
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2021-02-01 13:08:56 +01:00
|
|
|
def setCol(self, col: Collection) -> None:
|
2012-12-21 08:51:59 +01:00
|
|
|
"Set the current col, updating list of available tags."
|
|
|
|
self.col = col
|
2021-02-01 13:08:56 +01:00
|
|
|
l: Iterable[str]
|
2012-12-21 08:51:59 +01:00
|
|
|
if self.type == 0:
|
2020-05-15 13:21:10 +02:00
|
|
|
l = self.col.tags.all()
|
2012-12-21 08:51:59 +01:00
|
|
|
else:
|
2020-05-15 13:21:10 +02:00
|
|
|
l = (d.name for d in self.col.decks.all_names_and_ids())
|
2012-12-21 08:51:59 +01:00
|
|
|
self.model.setStringList(l)
|
|
|
|
|
2021-02-01 13:08:56 +01:00
|
|
|
def focusInEvent(self, evt: QFocusEvent) -> None:
|
2012-12-21 08:51:59 +01:00
|
|
|
QLineEdit.focusInEvent(self, evt)
|
|
|
|
|
2021-02-01 13:08:56 +01:00
|
|
|
def keyPressEvent(self, evt: QKeyEvent) -> None:
|
2017-08-30 13:13:10 +02:00
|
|
|
if evt.key() in (Qt.Key_Up, Qt.Key_Down):
|
|
|
|
# show completer on arrow key up/down
|
2021-03-17 05:51:59 +01:00
|
|
|
if not self._completer.popup().isVisible():
|
2017-08-30 13:13:10 +02:00
|
|
|
self.showCompleter()
|
|
|
|
return
|
2021-03-17 05:51:59 +01:00
|
|
|
if evt.key() == Qt.Key_Tab and int(evt.modifiers()) & Qt.ControlModifier:
|
2017-08-30 13:11:03 +02:00
|
|
|
# select next completion
|
2021-03-17 05:51:59 +01:00
|
|
|
if not self._completer.popup().isVisible():
|
2017-08-30 12:49:04 +02:00
|
|
|
self.showCompleter()
|
2021-03-17 05:51:59 +01:00
|
|
|
index = self._completer.currentIndex()
|
|
|
|
self._completer.popup().setCurrentIndex(index)
|
2017-08-30 12:49:04 +02:00
|
|
|
cur_row = index.row()
|
2021-03-17 05:51:59 +01:00
|
|
|
if not self._completer.setCurrentRow(cur_row + 1):
|
|
|
|
self._completer.setCurrentRow(0)
|
2017-08-30 12:49:04 +02:00
|
|
|
return
|
2020-10-14 04:00:24 +02:00
|
|
|
if (
|
|
|
|
evt.key() in (Qt.Key_Enter, Qt.Key_Return)
|
2021-03-17 05:51:59 +01:00
|
|
|
and self._completer.popup().isVisible()
|
2020-10-14 04:00:24 +02:00
|
|
|
):
|
2017-08-30 13:11:03 +02:00
|
|
|
# apply first completion if no suggestion selected
|
2021-03-17 05:51:59 +01:00
|
|
|
selected_row = self._completer.popup().currentIndex().row()
|
2017-08-30 13:11:03 +02:00
|
|
|
if selected_row == -1:
|
2021-03-17 05:51:59 +01:00
|
|
|
self._completer.setCurrentRow(0)
|
|
|
|
index = self._completer.currentIndex()
|
|
|
|
self._completer.popup().setCurrentIndex(index)
|
2013-05-22 05:03:30 +02:00
|
|
|
self.hideCompleter()
|
2013-05-27 04:37:35 +02:00
|
|
|
QWidget.keyPressEvent(self, evt)
|
2013-05-22 05:03:30 +02:00
|
|
|
return
|
2012-12-21 08:51:59 +01:00
|
|
|
QLineEdit.keyPressEvent(self, evt)
|
|
|
|
if not evt.text():
|
|
|
|
# if it's a modifier, don't show
|
|
|
|
return
|
|
|
|
if evt.key() not in (
|
2019-12-23 01:34:10 +01:00
|
|
|
Qt.Key_Enter,
|
|
|
|
Qt.Key_Return,
|
|
|
|
Qt.Key_Escape,
|
|
|
|
Qt.Key_Space,
|
|
|
|
Qt.Key_Tab,
|
|
|
|
Qt.Key_Backspace,
|
|
|
|
Qt.Key_Delete,
|
|
|
|
):
|
2012-12-21 08:51:59 +01:00
|
|
|
self.showCompleter()
|
2020-04-01 09:13:08 +02:00
|
|
|
gui_hooks.tag_editor_did_process_key(self, evt)
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2021-02-01 13:08:56 +01:00
|
|
|
def showCompleter(self) -> None:
|
2021-03-17 05:51:59 +01:00
|
|
|
self._completer.setCompletionPrefix(self.text())
|
|
|
|
self._completer.complete()
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2021-02-02 14:30:53 +01:00
|
|
|
def focusOutEvent(self, evt: QFocusEvent) -> None:
|
2012-12-21 08:51:59 +01:00
|
|
|
QLineEdit.focusOutEvent(self, evt)
|
2020-05-04 05:23:08 +02:00
|
|
|
self.lostFocus.emit() # type: ignore
|
2021-03-17 05:51:59 +01:00
|
|
|
self._completer.popup().hide()
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2021-02-01 13:08:56 +01:00
|
|
|
def hideCompleter(self) -> None:
|
2021-03-17 05:51:59 +01:00
|
|
|
if sip.isdeleted(self._completer):
|
2018-04-18 05:21:10 +02:00
|
|
|
return
|
2021-03-17 05:51:59 +01:00
|
|
|
self._completer.popup().hide()
|
2012-12-21 08:51:59 +01:00
|
|
|
|
|
|
|
|
2019-12-23 01:34:10 +01:00
|
|
|
class TagCompleter(QCompleter):
|
2021-02-01 13:08:56 +01:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
model: QStringListModel,
|
|
|
|
parent: QWidget,
|
|
|
|
edit: TagEdit,
|
|
|
|
) -> None:
|
2012-12-21 08:51:59 +01:00
|
|
|
QCompleter.__init__(self, model, parent)
|
2021-10-03 10:59:42 +02:00
|
|
|
self.tags: list[str] = []
|
2012-12-21 08:51:59 +01:00
|
|
|
self.edit = edit
|
2021-10-03 10:59:42 +02:00
|
|
|
self.cursor: int | None = None
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2021-10-03 10:59:42 +02:00
|
|
|
def splitPath(self, tags: str) -> list[str]:
|
2017-08-30 14:19:15 +02:00
|
|
|
stripped_tags = tags.strip()
|
|
|
|
stripped_tags = re.sub(" +", " ", stripped_tags)
|
|
|
|
self.tags = self.edit.col.tags.split(stripped_tags)
|
2016-05-12 06:45:35 +02:00
|
|
|
self.tags.append("")
|
2012-12-21 08:51:59 +01:00
|
|
|
p = self.edit.cursorPosition()
|
2017-08-30 14:52:58 +02:00
|
|
|
if tags.endswith(" "):
|
|
|
|
self.cursor = len(self.tags) - 1
|
|
|
|
else:
|
|
|
|
self.cursor = stripped_tags.count(" ", 0, p)
|
2012-12-21 08:51:59 +01:00
|
|
|
return [self.tags[self.cursor]]
|
|
|
|
|
2021-02-01 13:08:56 +01:00
|
|
|
def pathFromIndex(self, idx: QModelIndex) -> str:
|
2012-12-21 08:51:59 +01:00
|
|
|
if self.cursor is None:
|
|
|
|
return self.edit.text()
|
|
|
|
ret = QCompleter.pathFromIndex(self, idx)
|
2016-05-31 10:51:40 +02:00
|
|
|
self.tags[self.cursor] = ret
|
2012-12-21 08:51:59 +01:00
|
|
|
try:
|
2016-05-12 06:45:35 +02:00
|
|
|
self.tags.remove("")
|
2012-12-21 08:51:59 +01:00
|
|
|
except ValueError:
|
|
|
|
pass
|
2021-02-11 01:09:06 +01:00
|
|
|
return f"{' '.join(self.tags)} "
|