Skip to content

Commit

Permalink
Merge pull request #204 from mjuhanne/search_engine
Browse files Browse the repository at this point in the history
Search engine
  • Loading branch information
MinmoTech authored Dec 22, 2023
2 parents 88e01ba + a5e0605 commit d09c3fe
Show file tree
Hide file tree
Showing 9 changed files with 576 additions and 19 deletions.
1 change: 1 addition & 0 deletions addon/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def setup_menu():
submenu = QMenu("Kanji", aqt.mw)

lookup_action = QAction("Lookup", aqt.mw)
lookup_action.setShortcut(_("Ctrl+L"))
lookup_action.triggered.connect(on_loopup)
submenu.addAction(lookup_action)

Expand Down
4 changes: 3 additions & 1 deletion addon/kanji.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from . import config
from . import text_parser
from .kanji_confirm_dialog import KanjiConfirmDialog

from .search_engine import SearchEngine

kanji_db_path = addon_path("kanji.db")
user_db_path = user_path("user.db")
Expand Down Expand Up @@ -100,6 +100,8 @@ def initialize(self):
except sqlite3.OperationalError:
pass

self.search_engine = SearchEngine(self.crs)

# Close db
def shutdown(self):
self.crs.close()
Expand Down
7 changes: 6 additions & 1 deletion addon/kanji_confirm_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ def __init__(self):
super().__init__()
self.kanji = []
self.states = defaultdict(lambda: 0)
# These are used only by non-Unicode primitive .svg files
if aqt.theme.theme_manager.night_mode:
self.color = QColor( 0xff, 0xff, 0xff )
else:
self.color = QColor( 0x20, 0x20, 0x20 )

def add(self, kanji_list):
new_kanji = [kanji for kanji in kanji_list if kanji not in self.kanji]
Expand Down Expand Up @@ -59,7 +64,7 @@ def data(self, idx, role):
return str(kanji)
if role == Qt.ItemDataRole.DecorationRole:
if kanji[0] == '[':
return util.get_pixmap_from_tag(kanji, 35)
return util.get_pixmap_from_tag(kanji, 37, self.color)
if role == Qt.ItemDataRole.BackgroundRole:
state = self.states[kanji]
return QBrush(QColor(self.state_colors[state]))
Expand Down
16 changes: 5 additions & 11 deletions addon/lookup_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from . import fonts
from . import config

from .power_search_bar import PowerSearchBar

key_sequence = QKeySequence("Ctrl+Shift+K")
key_sequence_txt = key_sequence.toString(QKeySequence.SequenceFormat.NativeText)
Expand Down Expand Up @@ -40,15 +41,12 @@ def __init__(self, parent=None):
search_lyt = QHBoxLayout()
lyt.addLayout(search_lyt)

self.search_bar = QLineEdit()
self.search_bar.setPlaceholderText("字")
self.search_bar.returnPressed.connect(self.on_search_submit)
search_lyt.addWidget(self.search_bar)

search_btn = QPushButton("🔍")
search_btn.setFixedWidth(search_btn.sizeHint().height())
search_btn.setFixedWidth(search_btn.sizeHint().height()*2)
search_btn.setFocusPolicy(Qt.FocusPolicy.NoFocus)
search_btn.clicked.connect(self.on_search_submit)

self.power_search_bar = PowerSearchBar(search_lyt, lyt, 20, int(search_btn.sizeHint().height()*1.5), self.search)
search_btn.clicked.connect(self.power_search_bar.on_power_search_submit)
search_lyt.addWidget(search_btn)

self.keep_tab_on_search_box = QCheckBox("Keep tabs open")
Expand Down Expand Up @@ -168,10 +166,6 @@ def on_bridge_cmd(self, cmd):
if not handle_bridge_action(cmd, lookup_window=self):
print("Unhandled bridge command:", cmd)

def on_search_submit(self):
text = self.search_bar.text()
self.search(text)

def search(self, text, internal=False):
unique_characters = util.unique_characters(text)

Expand Down
130 changes: 130 additions & 0 deletions addon/power_search_bar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
from . import util
import aqt
from aqt.qt import *


class ResultsBar():

def __init__(self, layout, max_results, result_button_size, on_select_result_function, hide_empty_buttons=True):
self.hide_empty_buttons = hide_empty_buttons
self.on_select_result_function = on_select_result_function
self.max_results = max_results
self.button_size = result_button_size

# search result buttons
self.buttons_lyt = QHBoxLayout()

layout.addLayout(self.buttons_lyt)
self.buttons_lyt.setSpacing(3)
self.buttons_lyt.setAlignment(Qt.AlignmentFlag.AlignLeft)
self.buttons = []

if aqt.theme.theme_manager.night_mode:
self.color = QColor( 0xe9, 0xe9, 0xe9 )
self.background_color = QColor( 0x45, 0x45, 0x45 )
else:
self.color = QColor( 0x20, 0x20, 0x20 )
self.background_color = QColor( 0xe9, 0xe9, 0xe9 )

btn_style_sheet = \
f"color: {self.color.name()};" \
f"background-color: {self.background_color.name()};"

btn_style_sheet += \
"font-size: 20px;" \
"border-style: ridge;" \
"border-width: 2px;" \
"border-radius: 6px;" \
"padding: 2px;"

for i in range(max_results):
result_btn = QPushButton(' ', objectName='result_btn_' + str(i+1))
result_btn.setStyleSheet(btn_style_sheet)
result_btn.setFixedWidth(result_button_size)
result_btn.setFixedHeight(result_button_size)
result_btn.setFocusPolicy(Qt.FocusPolicy.NoFocus)
result_btn.clicked.connect(lambda state, x=result_btn: self.on_button_click(x))
result_btn.character = None
if self.hide_empty_buttons:
result_btn.setVisible(False)
else:
result_btn.setText('')
self.buttons_lyt.addWidget(result_btn)
self.buttons.append(result_btn)


def set_contents(self, contents):
idx = 0
for r in contents:
if idx < self.max_results:
btn = self.buttons[idx]
btn.setVisible(True)
if r[0] == '[':
btn.setText('')
icon_size = int(self.button_size*0.8)
pixmap = util.get_pixmap_from_tag(r, icon_size*2, self.color) # to avoid smoothing we double the size and then resize below
icon = QIcon(pixmap)
btn.setIcon(icon)
btn.setIconSize(QSize(icon_size,icon_size))
else:
# normal unicode kanji character
btn.setText(r)
btn.setIcon(QIcon())
btn.character = r
idx += 1
for i in range(idx,self.max_results):
# clear/hide rest of the buttons
btn = self.buttons[i]
btn.character = None
if self.hide_empty_buttons:
btn.setVisible(False)
else:
btn.setText('')
btn.setIcon(QIcon())


def on_button_click(self, button):
text = button.text()
if button.character is not None:
self.on_select_result_function(button.character)



class PowerSearchBar():

def __init__(self, search_bar_layout, search_results_layout, max_results, result_button_width, on_select_result_function, hide_empty_result_buttons=True):

self.on_select_result_function = on_select_result_function
self.max_results = max_results

# search bar
self.input_bar = QLineEdit()
self.input_bar.setPlaceholderText("")
self.input_bar.returnPressed.connect(self.on_power_search_submit)
self.input_bar.textChanged.connect(self.on_power_search_changed)
search_bar_layout.addWidget(self.input_bar)

self.results_bar = ResultsBar(search_results_layout, max_results, result_button_width, on_select_result_function, hide_empty_result_buttons)


def on_power_search_changed(self):
text = self.input_bar.text()
result = aqt.mw.migaku_kanji_db.search_engine.search(text, self.max_results)
self.results_bar.set_contents(result)

def on_power_search_submit(self):
btn = self.results_bar.buttons[0]
if btn.character is not None:
# There is a match from search engine --> Do not do any additional searches
# but just select the first match
self.on_select_result_function(btn.character)
else:
text = self.input_bar.text()
if len(text) > 0:
# retain the old functionality of the search bar: Open many tabs (one for each character)
self.on_select_result_function(text)


def clear(self):
self.input_bar.setText("")
self.results_bar.set_contents([])
Loading

0 comments on commit d09c3fe

Please sign in to comment.