import os
import re
import argparse
+import unicodedata
from configparser import RawConfigParser as ConfigParser
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
def die(rc=0):
sys.exit(rc)
+def contains_cjk(s):
+ for c in s:
+ if "Lo" == unicodedata.category(c):
+ return True
+ return False
+
############################################################
# configuration
class jpMainWindow(QMainWindow):
def __init__(self, *args, title='', **kwargs):
super().__init__(*args, **kwargs)
+ self.init_ui(title)
+
+ def init_ui(self, title=''):
#jpIcon()
self.setWindowTitle(title)
#self.setWindowIcon(jpIcon.jitenpai)
edit_menu = menubar.addMenu('&Edit')
copy_action = QAction('&Copy', self)
copy_action.setShortcut('Ctrl+C')
- copy_action.triggered.connect(lambda: self.clipboard.setText(self.result_pane.textCursor().selectedText()))
+ copy_action.triggered.connect(self.kbd_copy)
paste_action = QAction('&Paste', self)
paste_action.setShortcut('Ctrl+V')
- paste_action.triggered.connect(lambda: self.search_box.lineEdit().setText(self.clipboard.text()))
+ paste_action.triggered.connect(self.kbd_paste)
pref_action = QAction('Prefere&nces', self)
# TODO: preferences dialog
#pref_action.triggered.connect()
help_menu = menubar.addMenu('&Help')
about_action = QAction('&About', self)
help_menu.addAction(about_action)
+ # options
+ japopt_group = QGroupBox('Japanese Search Options')
+ self.japopt_exact = QRadioButton('Exact Matches')
+ self.japopt_exact.setChecked(True)
+ self.japopt_start = QRadioButton('Start With Expression')
+ self.japopt_end = QRadioButton('End With Expression')
+ self.japopt_any = QRadioButton('Any Matches')
+ japopt_layout = QVBoxLayout()
+ japopt_layout.addWidget(self.japopt_exact)
+ japopt_layout.addWidget(self.japopt_start)
+ japopt_layout.addWidget(self.japopt_end)
+ japopt_layout.addWidget(self.japopt_any)
+ japopt_layout.addStretch()
+ japopt_group.setLayout(japopt_layout)
+ engopt_group = QGroupBox('English Search Options')
+ self.engopt_expr = QRadioButton('Whole Expressions')
+ self.engopt_word = QRadioButton('Whole Words')
+ self.engopt_any = QRadioButton('Any Matches')
+ self.engopt_any.setChecked(True)
+ engopt_layout = QVBoxLayout()
+ engopt_layout.addWidget(self.engopt_expr)
+ engopt_layout.addWidget(self.engopt_word)
+ engopt_layout.addWidget(self.engopt_any)
+ engopt_layout.addStretch()
+ engopt_group.setLayout(engopt_layout)
+ genopt_group = QGroupBox('General Options')
+ # TODO: add remaining general options
+ self.genopt_dolimit = QCheckBox('Limit Results:')
+ self.genopt_dolimit.setTristate(False)
+ self.genopt_dolimit.setChecked(True)
+ self.genopt_limit = QSpinBox()
+ self.genopt_limit.setMinimum(1)
+ self.genopt_limit.setMaximum(1000)
+ self.genopt_limit.setValue(cfg['max_res'])
+ self.genopt_dolimit.toggled.connect(self.genopt_limit.setEnabled)
+ genopt_limit_layout = QHBoxLayout()
+ genopt_limit_layout.addWidget(self.genopt_dolimit)
+ genopt_limit_layout.addWidget(self.genopt_limit)
+ genopt_layout = QVBoxLayout()
+ genopt_layout.addLayout(genopt_limit_layout)
+ genopt_layout.addStretch()
+ genopt_group.setLayout(genopt_layout)
+ opt_layout = QHBoxLayout()
+ opt_layout.addWidget(japopt_group)
+ opt_layout.addWidget(engopt_group)
+ opt_layout.addWidget(genopt_group)
# search area
- search_group = QGroupBox('Enter expression:')
+ search_group = QGroupBox('Enter expression')
self.search_box = QComboBox()
self.search_box.setEditable(True)
self.search_box.setMinimumWidth(400);
clear_button = QPushButton('Clear')
clear_button.clicked.connect(lambda: self.search_box.lineEdit().setText(""))
search_layout = QHBoxLayout()
- search_layout.addWidget(self.search_box)
- search_layout.addWidget(search_button)
- search_layout.addWidget(clear_button)
+ search_layout.addWidget(self.search_box, 100)
+ search_layout.addWidget(search_button, 5)
+ search_layout.addWidget(clear_button, 1)
search_group.setLayout(search_layout)
# result area
- result_group = QGroupBox('Search results:')
- self.matches_label = QLabel('Matches found:')
+ result_group = QGroupBox('Search results')
+ self.matches_label = QLabel(' ')
self.result_pane = QTextEdit()
self.result_pane.setReadOnly(True)
self.result_pane.setText('')
main_frame = QWidget()
main_layout = QVBoxLayout(main_frame)
main_layout.addWidget(menubar)
- main_layout.addWidget(search_group)
- main_layout.addWidget(result_group)
+ main_layout.addLayout(opt_layout, 1)
+ main_layout.addWidget(search_group, 20)
+ main_layout.addWidget(result_group, 100)
self.setCentralWidget(main_frame)
+ self.search_box.setFocus()
def search(self):
term = self.search_box.lineEdit().text().strip()
+ self.search_box.lineEdit().setText(term)
if len(term) < 1:
return
- result = dict_lookup(cfg['dict'], term, cfg['max_res'])
- # result formatting
+ # apply search options
+ if contains_cjk(term):
+ print('apply japopt')
+ if self.japopt_exact.isChecked():
+ if term[0] != '^':
+ term = '^' + term
+ if term[-1] != '$':
+ term = term + '$'
+ elif self.japopt_start.isChecked():
+ if term[0] != '^':
+ term = '^' + term
+ if term[-1] == '$':
+ term = term[:-1]
+ elif self.japopt_end.isChecked():
+ if term[0] == '^':
+ term = term[1:]
+ if term[-1] != '$':
+ term = term + '$'
+ elif self.japopt_any.isChecked():
+ if term[0] == '^':
+ term = term[1:]
+ if term[-1] == '$':
+ term = term[:-1]
+ else:
+ print('apply engopt')
+ if self.engopt_expr.isChecked():
+ term = '[^a-zA-Z] ' + term
+ if term[-1] != ';':
+ term = term + ';'
+ if self.engopt_word.isChecked():
+ term = '[^a-zA-Z]' + term + '[^a-zA-Z]'
+ if self.engopt_any.isChecked():
+ if term[-1] == ';':
+ term = term[:-1]
+ # result limiting
+ max_res = self.genopt_limit.value() if self.genopt_limit.isEnabled() else 0
+ # perform lookup
+ result = dict_lookup(cfg['dict'], term, max_res)
+ if len(result) < 1:
+ self.matches_label.setText("No match found!")
+ self.result_pane.setHtml('')
+ return
+ # format result
re_term = re.compile(term)
nfmt = '<div style="font-family: %s; font-size: %dpt">' % (cfg['font'], cfg['font_sz'])
lfmt = '<span style="font-family: %s; font-size: %dpt;">' % (cfg['lfont'], cfg['lfont_sz'])
self.result_pane.setHtml(''.join(html))
self.matches_label.setText("Matches found: %d" % len(result))
+ def kbd_copy(self):
+ self.clipboard.setText(self.result_pane.textCursor().selectedText())
+
+ def kbd_paste(self):
+ self.search_box.lineEdit().setText(self.clipboard.text())
+ self.search_box.setFocus()
+
############################################################
# dictionary lookup
p2 = p1[1].split(']', 1)
kanji = p1[0].strip()
kana = p2[0].strip()
- trans = p2[1].strip('/ \t\r\n')
+ trans = ' ' + p2[1].lstrip('/ ').rstrip(' \t\r\n').replace('/', '; ')
except:
continue
# for now promiscuously try to match anything anywhere