* Added search options to GUI, partially implemented.
authorUrban Wallasch <urban.wallasch@freenet.de>
Mon, 14 Jun 2021 11:20:57 +0000 (13:20 +0200)
committerUrban Wallasch <urban.wallasch@freenet.de>
Mon, 14 Jun 2021 11:20:57 +0000 (13:20 +0200)
* GUI improvements, refactoring.

jiten-pai.py

index 6fde4e9505d9afc18b9a13aa376bd4522b2b3355..1772c36c82e75c365e46d373a26b3e54fa06415d 100755 (executable)
@@ -26,6 +26,7 @@ import io
 import os
 import re
 import argparse
+import unicodedata
 from configparser import RawConfigParser as ConfigParser
 from PyQt5.QtCore import *
 from PyQt5.QtWidgets import *
@@ -38,6 +39,12 @@ from PyQt5.QtGui 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
@@ -59,6 +66,9 @@ cfg = {
 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)
@@ -74,10 +84,10 @@ class jpMainWindow(QMainWindow):
         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()
@@ -89,8 +99,54 @@ class jpMainWindow(QMainWindow):
         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);
@@ -102,13 +158,13 @@ class jpMainWindow(QMainWindow):
         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('')
@@ -120,16 +176,60 @@ class jpMainWindow(QMainWindow):
         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'])
@@ -149,6 +249,13 @@ class jpMainWindow(QMainWindow):
         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
@@ -170,7 +277,7 @@ def dict_lookup(dict_fname, term, max_res = 0):
                 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