diff --git a/app.py b/app.py
index 95f30ad..d97a37f 100644
--- a/app.py
+++ b/app.py
@@ -5,8 +5,9 @@ from gi.repository import Gtk, GObject, Gdk
from mods.db import store_patient_index, update_patient_index, search_patients, db, Patient, Reception, Catalog, List
from mods.settings import s_get_reception_list, s_set_reception_list
from mods.catalogs import add_catalog, search_catalogs
-from mods.lists import add_list_record, create_open_list_win
+from mods.lists import create_open_list_win
from mods.files import list_row_ui_str
+from mods.utils import show_msg, ConditionalFilter
from datetime import date, datetime, timedelta
import peewee
import re
@@ -55,18 +56,6 @@ def get_reception_timelist(rec_date):
shift_minutes_range = range(0, work_day_minutes_total, s.interval)
return [dstart + timedelta(minutes=x) for x in shift_minutes_range]
-class ConditionalFilter:
- def __init__(self, search_func):
- self.search_func = search_func
- self.reset()
- def filter(self, query):
- if query != self.fstr:
- self.fstr = query
- self.ids = list(map(lambda x: x.id, self.search_func(query)))
- return self.ids
- def reset(self):
- self.fstr = ''
- self.ids = []
patient_filter = ConditionalFilter(search_patients)
catalog_filter = ConditionalFilter(search_catalogs)
@@ -181,18 +170,6 @@ class MainWinHandler:
pl.unselect_all()
self.patient_list_unselected()
pl.invalidate_filter()
- '''pl = builder.get_object('patient_list')
- for r in pl.get_children():
- pl.remove(r)
- fstr = builder.get_object('patient_filter').get_text().strip()
- if not fstr:
- for p in Patient.select():
- pl.add(build_patient_row(p))
- else:
- patients = search_patients(fstr)
- for p in patients:
- pl.add(build_patient_row(p))
- pl.show_all()'''
def list_list_selected(self, *a):
open_button = builder.get_object('list_open_button')
open_button.set_sensitive(True)
@@ -341,15 +318,7 @@ with db.atomic():
for c in Catalog.select():
catalog_list.add(build_catalog_row(c))
-def show_msg(text, sec_text='', level='info'):
- msg_win_file = os.path.join(ui_dir, f'{level}_win.glade')
- b = Gtk.Builder()
- b.add_from_file(msg_win_file)
- w = b.get_object(level)
- w.set_property('text',text)
- w.set_property('secondary_text',sec_text)
- w.run()
- w.close()
+
def get_patient_win_values(b):
l_name = b.get_object('last_name').get_text().replace(' ', '')
diff --git a/mods/catalogs.py b/mods/catalogs.py
index f9024fc..082479f 100644
--- a/mods/catalogs.py
+++ b/mods/catalogs.py
@@ -1,6 +1,5 @@
from mods.db import db, Catalog, CatalogIndex
-
-
+import re
def add_catalog(name):
with db.atomic():
@@ -14,6 +13,8 @@ def add_catalog(name):
return catalog
def search_catalogs(q):
+ q = re.sub(r'\s+', ' ', q).strip()
+ q = ' '.join([ f'{x}*' for x in q.split(' ')])
with db.atomic():
return (Catalog.select()
.join(
diff --git a/mods/db.py b/mods/db.py
index b89d10b..1f84e10 100644
--- a/mods/db.py
+++ b/mods/db.py
@@ -1,6 +1,7 @@
import os
from peewee import Model, CharField, DateTimeField, TextField, ForeignKeyField, DateField, fn
from playhouse.sqlite_ext import CSqliteExtDatabase, FTS5Model, AutoIncrementField, SearchField, RowIDField, JSONField
+import re
var_dir = os.path.join(os.path.abspath(os.environ['HOME']), '.eldoc')
db_dir = os.path.join(var_dir, 'db')
@@ -87,7 +88,7 @@ Patient.add_index(
Patient.index(fn.lower(Patient.last_name), fn.lower(Patient.first_name), Patient.birth_date, unique=True, name='patient_first_last_name_birth_date_unique')
)
Catalog.add_index(Catalog.index(fn.lower(Catalog.name), unique=True, name='catalog_name_unique'))
-ListRecord.add_index(ListRecord.index(ListRecord.list, fn.lower(ListRecord.text), unique=True))
+ListRecord.add_index(ListRecord.index(ListRecord.list, fn.lower(ListRecord.text), unique=True, name='listrec_unique'))
db.create_tables([
Patient,
PatientIndex,
@@ -105,6 +106,8 @@ db.create_tables([
])
def search_patients(q):
+ q = re.sub(r'\s+', ' ', q).strip()
+ q = ' '.join([ f'{x}*' for x in q.split(' ')])
with db.atomic():
return (Patient.select()
.join(
diff --git a/mods/files.py b/mods/files.py
index 36ec732..a9733c2 100644
--- a/mods/files.py
+++ b/mods/files.py
@@ -9,3 +9,6 @@ open_list_win_file = os.path.join(ui_dir, 'open_list_win.glade')
listrecord_row_file = os.path.join(ui_dir, 'listrecord_row.glade')
with open(listrecord_row_file, 'r') as f:
listrecord_row_ui_str = f.read()
+editable_row_file = os.path.join(ui_dir, 'editable_row.glade')
+with open(editable_row_file, 'r') as f:
+ editable_row_ui_str = f.read()
diff --git a/mods/lists.py b/mods/lists.py
index 46e2c79..3173677 100644
--- a/mods/lists.py
+++ b/mods/lists.py
@@ -1,8 +1,11 @@
import gi
gi.require_version('Gtk', '3.0')
-from gi.repository import Gtk, GObject
+from gi.repository import Gtk, GObject, Gdk
from mods.db import db, List, ListRecord, ListRecordIndex
-from mods.files import open_list_win_file, listrecord_row_ui_str
+from mods.files import open_list_win_file, listrecord_row_ui_str, editable_row_ui_str
+from mods.utils import show_msg, disable_widget, enable_widget, ConditionalFilter
+import re
+import peewee
lists_map = {
'diagnoz': 'Диагноз',
@@ -17,6 +20,13 @@ for s_id in lists_map:
if not len(q):
List.create(name=lists_map[s_id], system_id=s_id)
+class ListRecFilter(ConditionalFilter):
+ def filter(self, list_id, query):
+ if query != self.fstr:
+ self.fstr = query
+ self.ids = list(map(lambda x: x.id, self.search_func(list_id, query)))
+ return self.ids
+
class ListRecordRow(Gtk.ListBoxRow):
@GObject.Property
def db_id(self):
@@ -31,22 +41,12 @@ class ListRecordRow(Gtk.ListBoxRow):
def text_setter(self, value):
self._text = value
-def build_listrecord_row(listrec_o):
- b = Gtk.Builder()
- b.add_from_string(listrecord_row_ui_str)
- win = b.get_object('win')
- box = b.get_object('listrecord_box')
- b.get_object('text').set_text(listrec_o.text)
- row = ListRecordRow()
- row.props.db_id = listrec_o.id
- row.text = listrec_o.text
- win.remove(win.get_children()[0])
- row.add(box)
- return row
-
def get_list(list_id):
with db.atomic():
return List.get_by_id(list_id)
+def get_listrecord(listrec_id):
+ with db.atomic():
+ return ListRecord.get_by_id(listrec_id)
def get_all_list_records(list_id):
with db.atomic():
@@ -68,14 +68,17 @@ def delete_list_record(listrec_id):
ListRecord.delete().where(ListRecord.id == listrec_id).execute()
ListRecordIndex.delete().where(ListRecordIndex.rowid == listrec_id).execute()
def change_list_record(listrec_id, new_text):
- listrec_o = ListRecord.get_by_id(listrec_id)
+ listrec_o = get_listrecord(listrec_id)
if listrec_o.text == new_text:
- return False
+ return listrec_o
with db.atomic():
- ListRecord.update(text=new_text).execute()
- ListRecordIndex.update(text=new_text).execute()
+ ListRecord.update(text=new_text).where(ListRecord.id == listrec_id).execute()
+ ListRecordIndex.update(text=new_text).where(ListRecordIndex.rowid == listrec_id).execute()
+ return ListRecord.get_by_id(listrec_id)
def search_list_record(list_id, q):
- list_o = List.get_by_id(list_id)
+ q = re.sub(r'\s+', ' ', q).strip()
+ q = ' '.join([ f'{x}*' for x in q.split(' ')])
+ list_o = get_list(list_id)
with db.atomic():
return (ListRecord.select()
.join(
@@ -83,19 +86,146 @@ def search_list_record(list_id, q):
on=(ListRecord.id == ListRecordIndex.rowid))
.where((ListRecord.list == list_o) & (ListRecordIndex.match(q)))
.order_by(ListRecordIndex.bm25()))
+#####################################################################################################################
+def build_listrecord_row(listrec_o):
+ b = Gtk.Builder()
+ b.add_from_string(listrecord_row_ui_str)
+ win = b.get_object('win')
+ box = b.get_object('listrecord_box')
+ b.get_object('text').set_text(listrec_o.text)
+ row = ListRecordRow()
+ row.props.db_id = listrec_o.id
+ row.text = listrec_o.text
+ win.remove(win.get_children()[0])
+ row.add(box)
+ return row
+
+def build_listrec_editable_row(listrec_o=None):
+ b = Gtk.Builder()
+ b.add_from_string(editable_row_ui_str)
+ #b.connect_signals({'editing_done': listrec_editing_done})
+ win = b.get_object('win')
+ box = b.get_object('editable_box')
+ text_input = b.get_object('text_input')
+ text_input.set_text(listrec_o.text if listrec_o else '')
+ row = ListRecordRow()
+ row.props.db_id = listrec_o.id if listrec_o else -1
+ row.text = listrec_o.text if listrec_o else ''
+ win.remove(win.get_children()[0])
+ row.add(box)
+ return (row, text_input)
def create_open_list_win(list_id):
list_o = get_list(list_id)
b = Gtk.Builder()
+ listrecord_filter = ListRecFilter(search_list_record)
class OpenListHandler:
- pass
+ def row_add_cancel(self, entry, ev, row):
+ if ev.keyval == Gdk.KEY_Escape:
+ lr_list.remove(row)
+ row.destroy()
+ def row_edit_cancel(self, entry, ev, edit_row):
+ if ev.keyval == Gdk.KEY_Escape:
+ rec = get_listrecord(edit_row.props.db_id)
+ row = build_listrecord_row(rec)
+ lr_list.remove(edit_row)
+ edit_row.destroy()
+ lr_list.add(row)
+ lr_list.show_all()
+ def enable_buttons_on_add_edit(self, *a):
+ enable_widget([add_button, edit_button, remove_button, lr_filter])
+ def remove_row(self, button):
+ row = lr_list.get_selected_row()
+ delete_list_record(row.props.db_id)
+ lr_list.remove(row)
+ row.destroy()
+ lr_list.show_all()
+ self.listrec_row_unselected()
+ def edit_row(self, button):
+ row = lr_list.get_selected_row()
+ rec = get_listrecord(row.props.db_id)
+ (edit_row, inp) = build_listrec_editable_row(rec)
+ lr_list.remove(row)
+ row.destroy()
+ lr_list.add(edit_row)
+ inp.grab_focus()
+ inp.connect('key-release-event', self.row_edit_cancel, edit_row)
+ inp.connect('activate', self.update_row, edit_row)
+ inp.connect('destroy', self.enable_buttons_on_add_edit)
+ disable_widget([add_button, edit_button, remove_button, lr_filter])
+ lr_list.show_all()
+ def add_new_row(self, button):
+ (row, text_input) = build_listrec_editable_row()
+ lr_list.add(row)
+ text_input.grab_focus()
+ text_input.connect('key-release-event', self.row_add_cancel, row)
+ text_input.connect('activate', self.save_new_row, row)
+ text_input.connect('destroy', self.enable_buttons_on_add_edit)
+ disable_widget([add_button, edit_button, remove_button, lr_filter])
+ lr_list.show_all()
+ def update_row(self, inp, edit_row):
+ new_text = re.sub(r'\s+', ' ', inp.get_text()).strip()
+ if new_text:
+ try:
+ rec = change_list_record(edit_row.props.db_id, new_text)
+ except peewee.IntegrityError:
+ return show_msg('Такая же запись уже существует', 'В данном списке уже существует\nдругая запись с данным текстом', level='warn')
+ row = build_listrecord_row(rec)
+ else:
+ row = build_listrecord_row(get_listrecord(edit_row.props.db_id))
+ lr_list.add(row)
+ lr_list.select_row(row)
+ lr_list.show_all()
+ lr_list.remove(edit_row)
+ edit_row.destroy()
+ def save_new_row(self, inp, row):
+ row_text = re.sub(r'\s+', ' ', inp.get_text()).strip()
+ if row_text:
+ try:
+ rec = add_list_record(list_id, row_text)
+ except peewee.IntegrityError:
+ return show_msg('Данная запись уже существует', 'В данном списке уже существует\nзапись с данным текстом', level='warn')
+ new_row = build_listrecord_row(rec)
+ lr_list.add(new_row)
+ lr_list.select_row(new_row)
+ lr_list.show_all()
+ lr_list.remove(row)
+ row.destroy()
+ def listrec_row_selected(self, *a):
+ enable_widget([edit_button, remove_button])
+ def listrec_row_unselected(self, *a):
+ disable_widget([edit_button, remove_button])
+ def listrec_filter_changed(self, filter_widget):
+ lr_list.unselect_all()
+ self.listrec_row_unselected()
+ lr_list.invalidate_filter()
b.add_from_file(open_list_win_file)
b.connect_signals(OpenListHandler())
+ # Gtk objects
w = b.get_object('open_list_window')
- listrec_list = b.get_object('listrecord_list')
+ lr_list = b.get_object('listrecord_list')
+ lr_filter = b.get_object('listrecord_filter')
+ add_button = b.get_object('add_button')
+ edit_button = b.get_object('edit_button')
+ remove_button = b.get_object('remove_button')
list_header = b.get_object('list_win_header')
+ #############
+ ######
+ def listrecord_sort_func(row1, row2, *a):
+ text1 = row1.props.text
+ text2 = row2.props.text
+ return (text1 > text2) - (text1 < text2)
+ def listrecord_filter_func(row):
+ fstr = lr_filter.get_text().strip()
+ if not fstr:
+ listrecord_filter.reset()
+ return True
+ return row.props.db_id in listrecord_filter.filter(list_id, fstr)
+ ######
+ lr_list.set_sort_func(listrecord_sort_func)
+ lr_list.set_filter_func(listrecord_filter_func)
list_header.props.title = list_o.name
for lr in get_all_list_records(list_id):
- listrec_list.add(build_listrecord_row(lr))
+ lr_list.add(build_listrecord_row(lr))
return w
\ No newline at end of file
diff --git a/mods/utils.py b/mods/utils.py
new file mode 100644
index 0000000..8a46cdb
--- /dev/null
+++ b/mods/utils.py
@@ -0,0 +1,34 @@
+import os
+from mods.files import ui_dir
+import gi
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk
+
+def show_msg(text, sec_text='', level='info'):
+ msg_win_file = os.path.join(ui_dir, f'{level}_win.glade')
+ b = Gtk.Builder()
+ b.add_from_file(msg_win_file)
+ w = b.get_object(level)
+ w.set_property('text',text)
+ w.set_property('secondary_text',sec_text)
+ w.run()
+ w.close()
+def enable_widget(w_list):
+ for widget in w_list:
+ widget.set_sensitive(True)
+def disable_widget(w_list):
+ for widget in w_list:
+ widget.set_sensitive(False)
+
+class ConditionalFilter:
+ def __init__(self, search_func):
+ self.search_func = search_func
+ self.reset()
+ def filter(self, query):
+ if query != self.fstr:
+ self.fstr = query
+ self.ids = list(map(lambda x: x.id, self.search_func(query)))
+ return self.ids
+ def reset(self):
+ self.fstr = ''
+ self.ids = []
diff --git a/res/ui/editable_row.glade b/res/ui/editable_row.glade
new file mode 100644
index 0000000..7f88ed9
--- /dev/null
+++ b/res/ui/editable_row.glade
@@ -0,0 +1,29 @@
+
+
+
+
+
+
diff --git a/res/ui/listrecord_list_row.glade b/res/ui/listrecord_list_row.glade
index f60f56a..2b06590 100644
--- a/res/ui/listrecord_list_row.glade
+++ b/res/ui/listrecord_list_row.glade
@@ -19,7 +19,7 @@
label
0
-
+
diff --git a/res/ui/listrecord_row.glade b/res/ui/listrecord_row.glade
index 6f49541..f60f56a 100644
--- a/res/ui/listrecord_row.glade
+++ b/res/ui/listrecord_row.glade
@@ -9,11 +9,11 @@
-
+
True
False
-
+
True
False
label
diff --git a/res/ui/open_list_win.glade b/res/ui/open_list_win.glade
index d904964..4c8f346 100644
--- a/res/ui/open_list_win.glade
+++ b/res/ui/open_list_win.glade
@@ -15,17 +15,18 @@
False
True
-
+
gtk-add
True
True
True
True
True
+
-
+
gtk-edit
True
False
@@ -33,13 +34,14 @@
True
True
True
+
1
-
+
gtk-remove
True
False
@@ -47,6 +49,7 @@
True
True
True
+
2
@@ -55,22 +58,85 @@
-
+
True
- True
- never
- in
+ False
+ vertical
-
+
True
- False
+ True
+ never
+ in
-
+
True
False
+
+
+ True
+ False
+
+
+
+
+ True
+ True
+ 0
+
+
+
+
+ True
+ False
+ 3
+ 3
+
+
+ True
+ False
+
+
+ True
+ True
+ 0
+
+
+
+
+ True
+ True
+ edit-find-symbolic
+ False
+ False
+
+
+
+ True
+ True
+ 1
+
+
+
+
+ True
+ False
+
+
+ True
+ True
+ 2
+
+
+
+
+ False
+ True
+ 1
+