Skip to content

Commit d09c3fe

Browse files
authored
Merge pull request #204 from mjuhanne/search_engine
Search engine
2 parents 88e01ba + a5e0605 commit d09c3fe

File tree

9 files changed

+576
-19
lines changed

9 files changed

+576
-19
lines changed

addon/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def setup_menu():
2929
submenu = QMenu("Kanji", aqt.mw)
3030

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

addon/kanji.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from . import config
1515
from . import text_parser
1616
from .kanji_confirm_dialog import KanjiConfirmDialog
17-
17+
from .search_engine import SearchEngine
1818

1919
kanji_db_path = addon_path("kanji.db")
2020
user_db_path = user_path("user.db")
@@ -100,6 +100,8 @@ def initialize(self):
100100
except sqlite3.OperationalError:
101101
pass
102102

103+
self.search_engine = SearchEngine(self.crs)
104+
103105
# Close db
104106
def shutdown(self):
105107
self.crs.close()

addon/kanji_confirm_dialog.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ def __init__(self):
3232
super().__init__()
3333
self.kanji = []
3434
self.states = defaultdict(lambda: 0)
35+
# These are used only by non-Unicode primitive .svg files
36+
if aqt.theme.theme_manager.night_mode:
37+
self.color = QColor( 0xff, 0xff, 0xff )
38+
else:
39+
self.color = QColor( 0x20, 0x20, 0x20 )
3540

3641
def add(self, kanji_list):
3742
new_kanji = [kanji for kanji in kanji_list if kanji not in self.kanji]
@@ -59,7 +64,7 @@ def data(self, idx, role):
5964
return str(kanji)
6065
if role == Qt.ItemDataRole.DecorationRole:
6166
if kanji[0] == '[':
62-
return util.get_pixmap_from_tag(kanji, 35)
67+
return util.get_pixmap_from_tag(kanji, 37, self.color)
6368
if role == Qt.ItemDataRole.BackgroundRole:
6469
state = self.states[kanji]
6570
return QBrush(QColor(self.state_colors[state]))

addon/lookup_window.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from . import fonts
1111
from . import config
1212

13+
from .power_search_bar import PowerSearchBar
1314

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

43-
self.search_bar = QLineEdit()
44-
self.search_bar.setPlaceholderText("字")
45-
self.search_bar.returnPressed.connect(self.on_search_submit)
46-
search_lyt.addWidget(self.search_bar)
47-
4844
search_btn = QPushButton("🔍")
49-
search_btn.setFixedWidth(search_btn.sizeHint().height())
45+
search_btn.setFixedWidth(search_btn.sizeHint().height()*2)
5046
search_btn.setFocusPolicy(Qt.FocusPolicy.NoFocus)
51-
search_btn.clicked.connect(self.on_search_submit)
47+
48+
self.power_search_bar = PowerSearchBar(search_lyt, lyt, 20, int(search_btn.sizeHint().height()*1.5), self.search)
49+
search_btn.clicked.connect(self.power_search_bar.on_power_search_submit)
5250
search_lyt.addWidget(search_btn)
5351

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

171-
def on_search_submit(self):
172-
text = self.search_bar.text()
173-
self.search(text)
174-
175169
def search(self, text, internal=False):
176170
unique_characters = util.unique_characters(text)
177171

addon/power_search_bar.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
from . import util
2+
import aqt
3+
from aqt.qt import *
4+
5+
6+
class ResultsBar():
7+
8+
def __init__(self, layout, max_results, result_button_size, on_select_result_function, hide_empty_buttons=True):
9+
self.hide_empty_buttons = hide_empty_buttons
10+
self.on_select_result_function = on_select_result_function
11+
self.max_results = max_results
12+
self.button_size = result_button_size
13+
14+
# search result buttons
15+
self.buttons_lyt = QHBoxLayout()
16+
17+
layout.addLayout(self.buttons_lyt)
18+
self.buttons_lyt.setSpacing(3)
19+
self.buttons_lyt.setAlignment(Qt.AlignmentFlag.AlignLeft)
20+
self.buttons = []
21+
22+
if aqt.theme.theme_manager.night_mode:
23+
self.color = QColor( 0xe9, 0xe9, 0xe9 )
24+
self.background_color = QColor( 0x45, 0x45, 0x45 )
25+
else:
26+
self.color = QColor( 0x20, 0x20, 0x20 )
27+
self.background_color = QColor( 0xe9, 0xe9, 0xe9 )
28+
29+
btn_style_sheet = \
30+
f"color: {self.color.name()};" \
31+
f"background-color: {self.background_color.name()};"
32+
33+
btn_style_sheet += \
34+
"font-size: 20px;" \
35+
"border-style: ridge;" \
36+
"border-width: 2px;" \
37+
"border-radius: 6px;" \
38+
"padding: 2px;"
39+
40+
for i in range(max_results):
41+
result_btn = QPushButton(' ', objectName='result_btn_' + str(i+1))
42+
result_btn.setStyleSheet(btn_style_sheet)
43+
result_btn.setFixedWidth(result_button_size)
44+
result_btn.setFixedHeight(result_button_size)
45+
result_btn.setFocusPolicy(Qt.FocusPolicy.NoFocus)
46+
result_btn.clicked.connect(lambda state, x=result_btn: self.on_button_click(x))
47+
result_btn.character = None
48+
if self.hide_empty_buttons:
49+
result_btn.setVisible(False)
50+
else:
51+
result_btn.setText('')
52+
self.buttons_lyt.addWidget(result_btn)
53+
self.buttons.append(result_btn)
54+
55+
56+
def set_contents(self, contents):
57+
idx = 0
58+
for r in contents:
59+
if idx < self.max_results:
60+
btn = self.buttons[idx]
61+
btn.setVisible(True)
62+
if r[0] == '[':
63+
btn.setText('')
64+
icon_size = int(self.button_size*0.8)
65+
pixmap = util.get_pixmap_from_tag(r, icon_size*2, self.color) # to avoid smoothing we double the size and then resize below
66+
icon = QIcon(pixmap)
67+
btn.setIcon(icon)
68+
btn.setIconSize(QSize(icon_size,icon_size))
69+
else:
70+
# normal unicode kanji character
71+
btn.setText(r)
72+
btn.setIcon(QIcon())
73+
btn.character = r
74+
idx += 1
75+
for i in range(idx,self.max_results):
76+
# clear/hide rest of the buttons
77+
btn = self.buttons[i]
78+
btn.character = None
79+
if self.hide_empty_buttons:
80+
btn.setVisible(False)
81+
else:
82+
btn.setText('')
83+
btn.setIcon(QIcon())
84+
85+
86+
def on_button_click(self, button):
87+
text = button.text()
88+
if button.character is not None:
89+
self.on_select_result_function(button.character)
90+
91+
92+
93+
class PowerSearchBar():
94+
95+
def __init__(self, search_bar_layout, search_results_layout, max_results, result_button_width, on_select_result_function, hide_empty_result_buttons=True):
96+
97+
self.on_select_result_function = on_select_result_function
98+
self.max_results = max_results
99+
100+
# search bar
101+
self.input_bar = QLineEdit()
102+
self.input_bar.setPlaceholderText("")
103+
self.input_bar.returnPressed.connect(self.on_power_search_submit)
104+
self.input_bar.textChanged.connect(self.on_power_search_changed)
105+
search_bar_layout.addWidget(self.input_bar)
106+
107+
self.results_bar = ResultsBar(search_results_layout, max_results, result_button_width, on_select_result_function, hide_empty_result_buttons)
108+
109+
110+
def on_power_search_changed(self):
111+
text = self.input_bar.text()
112+
result = aqt.mw.migaku_kanji_db.search_engine.search(text, self.max_results)
113+
self.results_bar.set_contents(result)
114+
115+
def on_power_search_submit(self):
116+
btn = self.results_bar.buttons[0]
117+
if btn.character is not None:
118+
# There is a match from search engine --> Do not do any additional searches
119+
# but just select the first match
120+
self.on_select_result_function(btn.character)
121+
else:
122+
text = self.input_bar.text()
123+
if len(text) > 0:
124+
# retain the old functionality of the search bar: Open many tabs (one for each character)
125+
self.on_select_result_function(text)
126+
127+
128+
def clear(self):
129+
self.input_bar.setText("")
130+
self.results_bar.set_contents([])

0 commit comments

Comments
 (0)