1 """GNUmed measurement widgets."""
2
3 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
4 __license__ = "GPL"
5
6
7 import sys, logging, datetime as pyDT, decimal, os, subprocess, codecs
8 import os.path
9
10
11 import wx, wx.grid, wx.lib.hyperlink
12
13
14 if __name__ == '__main__':
15 sys.path.insert(0, '../../')
16 from Gnumed.pycommon import gmTools
17 from Gnumed.pycommon import gmNetworkTools
18 from Gnumed.pycommon import gmI18N
19 from Gnumed.pycommon import gmShellAPI
20 from Gnumed.pycommon import gmCfg
21 from Gnumed.pycommon import gmDateTime
22 from Gnumed.pycommon import gmMatchProvider
23 from Gnumed.pycommon import gmDispatcher
24 from Gnumed.pycommon import gmMimeLib
25
26 from Gnumed.business import gmPerson
27 from Gnumed.business import gmStaff
28 from Gnumed.business import gmPathLab
29 from Gnumed.business import gmPraxis
30 from Gnumed.business import gmLOINC
31 from Gnumed.business import gmForms
32 from Gnumed.business import gmPersonSearch
33 from Gnumed.business import gmOrganization
34
35 from Gnumed.wxpython import gmRegetMixin
36 from Gnumed.wxpython import gmEditArea
37 from Gnumed.wxpython import gmPhraseWheel
38 from Gnumed.wxpython import gmListWidgets
39 from Gnumed.wxpython import gmGuiHelpers
40 from Gnumed.wxpython import gmAuthWidgets
41 from Gnumed.wxpython import gmOrganizationWidgets
42
43
44 _log = logging.getLogger('gm.ui')
45
46
47
48
50
51 if parent is None:
52 parent = wx.GetApp().GetTopWindow()
53
54
55 dlg = wx.FileDialog (
56 parent = parent,
57 message = 'Import Excelleris HL7 from XML file:',
58
59
60 wildcard = "xml files|*.xml|XML files|*.XML|all files|*",
61 style = wx.OPEN | wx.FILE_MUST_EXIST
62 )
63 choice = dlg.ShowModal()
64 xml_name = dlg.GetPath()
65 dlg.Destroy()
66 if choice != wx.ID_OK:
67 return False
68
69
70 from Gnumed.business import gmHL7
71
72 hl7 = gmHL7.extract_HL7_from_CDATA(xml_name, u'.//Message')
73 if hl7 is None:
74 gmGuiHelpers.gm_show_info (
75 u'File [%s]\ndoes not seem to contain HL7 wrapped in XML.' % xml_name,
76 u'Extracting HL7 from XML'
77 )
78 return False
79 fixed_hl7 = gmHL7.fix_HL7_stupidities(hl7)
80 PID_names = gmHL7.split_HL7_by_PID(fixed_hl7)
81 for name in PID_names:
82 gmHL7.stage_MSH_as_incoming_data(name, source = u'Excelleris')
83
84
86
87 if parent is None:
88 parent = wx.GetApp().GetTopWindow()
89
90
91 dlg = wx.FileDialog (
92 parent = parent,
93 message = 'Import HL7 from file:',
94
95
96 wildcard = "*.hl7|*.hl7|*.HL7|*.HL7|all files|*",
97 style = wx.OPEN | wx.FILE_MUST_EXIST
98 )
99 choice = dlg.ShowModal()
100 hl7_name = dlg.GetPath()
101 dlg.Destroy()
102 if choice != wx.ID_OK:
103 return False
104
105
106 from Gnumed.business import gmHL7
107
108 fixed_hl7 = gmHL7.fix_HL7_stupidities(hl7_name)
109 PID_names = gmHL7.split_HL7_by_PID(fixed_hl7)
110 for name in PID_names:
111 gmHL7.stage_MSH_as_incoming_data(name, source = u'generic')
112
113
132
133 def refresh(lctrl):
134 incoming = gmHL7.get_incoming_data()
135 items = [ [
136 i['data_type'],
137 u'%s, %s (%s) %s' % (
138 i['lastnames'],
139 i['firstnames'],
140 i['dob'],
141 i['gender']
142 ),
143 i['external_data_id'],
144 i['pk_incoming_data_unmatched']
145 ] for i in incoming ]
146 lctrl.set_string_items(items)
147 lctrl.set_data(incoming)
148
149 gmListWidgets.get_choices_from_list (
150 parent = parent,
151 msg = None,
152 caption = _('Showing unmatched incoming data'),
153 columns = [ _('Type'), _('Patient'), _('Data ID'), '#' ],
154 single_selection = True,
155 can_return_empty = False,
156 ignore_OK_button = True,
157 refresh_callback = refresh,
158
159
160
161 left_extra_button = [_('Show'), _('Show formatted HL7'), show_hl7]
162
163
164 )
165
166
167
168
170
171 wx.BeginBusyCursor()
172
173 gmDispatcher.send(signal = 'statustext', msg = _('Updating LOINC data can take quite a while...'), beep = True)
174
175
176 loinc_zip = gmNetworkTools.download_file(url = 'http://www.gnumed.de/downloads/data/loinc/loinctab.zip', suffix = '.zip')
177 if loinc_zip is None:
178 wx.EndBusyCursor()
179 gmGuiHelpers.gm_show_warning (
180 aTitle = _('Downloading LOINC'),
181 aMessage = _('Error downloading the latest LOINC data.\n')
182 )
183 return False
184
185 _log.debug('downloaded zipped LOINC data into [%s]', loinc_zip)
186
187 loinc_dir = gmNetworkTools.unzip_data_pack(filename = loinc_zip)
188
189
190 data_fname, license_fname = gmLOINC.split_LOINCDBTXT(input_fname = os.path.join(loinc_dir, 'LOINCDB.TXT'))
191
192 wx.EndBusyCursor()
193
194 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('importing LOINC reference data'))
195 if conn is None:
196 return False
197
198 wx.BeginBusyCursor()
199
200
201 if gmLOINC.loinc_import(data_fname = data_fname, license_fname = license_fname, conn = conn):
202 gmDispatcher.send(signal = 'statustext', msg = _('Successfully imported LOINC reference data.'))
203 else:
204 gmDispatcher.send(signal = 'statustext', msg = _('Importing LOINC reference data failed.'), beep = True)
205
206 wx.EndBusyCursor()
207 return True
208
209
210
212
213 dbcfg = gmCfg.cCfgSQL()
214
215 url = dbcfg.get (
216 option = u'external.urls.measurements_search',
217 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
218 bias = 'user',
219 default = u"http://www.google.de/search?as_oq=%(search_term)s&num=10&as_sitesearch=laborlexikon.de"
220 )
221
222 base_url = dbcfg.get2 (
223 option = u'external.urls.measurements_encyclopedia',
224 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
225 bias = 'user',
226 default = u'http://www.laborlexikon.de'
227 )
228
229 if measurement_type is None:
230 url = base_url
231
232 measurement_type = measurement_type.strip()
233
234 if measurement_type == u'':
235 url = base_url
236
237 url = url % {'search_term': measurement_type}
238
239 gmNetworkTools.open_url_in_browser(url = url)
240
241
253
254
256
257 if parent is None:
258 parent = wx.GetApp().GetTopWindow()
259
260 if emr is None:
261 emr = gmPerson.gmCurrentPatient().emr
262
263
264 def edit(measurement=None):
265 return edit_measurement(parent = parent, measurement = measurement, single_entry = True)
266
267 def delete(measurement):
268 gmPathLab.delete_test_result(result = measurement)
269 return True
270
271 def get_tooltip(measurement):
272 return measurement.format(with_review=True, with_evaluation=True, with_ranges=True)
273
274 def refresh(lctrl):
275 results = emr.get_test_results(order_by = 'clin_when DESC, unified_abbrev, unified_name')
276 items = [ [
277 gmDateTime.pydt_strftime (
278 r['clin_when'],
279 '%Y %b %d %H:%M',
280 accuracy = gmDateTime.acc_minutes
281 ),
282 r['unified_abbrev'],
283 u'%s%s%s' % (
284 r['unified_val'],
285 gmTools.coalesce(r['val_unit'], u'', u' %s'),
286 gmTools.coalesce(r['abnormality_indicator'], u'', u' %s')
287 ),
288 r['unified_name'],
289 gmTools.coalesce(r['comment'], u''),
290 r['pk_test_result']
291 ] for r in results ]
292 lctrl.set_string_items(items)
293 lctrl.set_data(results)
294
295 msg = _('Test results (ordered reverse-chronologically)')
296
297 return gmListWidgets.get_choices_from_list (
298 parent = parent,
299 msg = msg,
300 caption = _('Showing test results.'),
301 columns = [ _('When'), _('Abbrev'), _('Value'), _('Name'), _('Comment'), u'#' ],
302 single_selection = single_selection,
303 can_return_empty = False,
304 refresh_callback = refresh,
305 edit_callback = edit,
306 new_callback = edit,
307 delete_callback = delete,
308 list_tooltip_callback = get_tooltip
309 )
310
311
342
343
345
346 option = u'form_templates.default_gnuplot_template'
347
348 dbcfg = gmCfg.cCfgSQL()
349
350
351 default_template_name = dbcfg.get2 (
352 option = option,
353 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
354 bias = 'user'
355 )
356
357
358 if default_template_name is None:
359 gmDispatcher.send('statustext', msg = _('No default Gnuplot template configured.'), beep = False)
360 default_template = configure_default_gnuplot_template(parent = parent)
361
362 if default_template is None:
363 gmGuiHelpers.gm_show_error (
364 aMessage = _('There is no default Gnuplot one-type script template configured.'),
365 aTitle = _('Plotting test results')
366 )
367 return None
368 return default_template
369
370
371
372 try:
373 name, ver = default_template_name.split(u' - ')
374 except:
375
376 _log.exception('problem splitting Gnuplot script template name [%s]', default_template_name)
377 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading Gnuplot script template.'), beep = True)
378 return None
379
380 default_template = gmForms.get_form_template(name_long = name, external_version = ver)
381 if default_template is None:
382 default_template = configure_default_gnuplot_template(parent = parent)
383
384 if default_template is None:
385 gmGuiHelpers.gm_show_error (
386 aMessage = _('Cannot load default Gnuplot script template [%s - %s]') % (name, ver),
387 aTitle = _('Plotting test results')
388 )
389 return None
390
391 return default_template
392
393
394 -def plot_measurements(parent=None, tests=None, format=None, show_year = True, use_default_template=False):
420
421
422 -def plot_adjacent_measurements(parent=None, test=None, format=None, show_year=True, plot_singular_result=True, use_default_template=False):
423
424 earlier, later = test.get_adjacent_results(desired_earlier_results = 2, desired_later_results = 2)
425 results2plot = []
426 if earlier is not None:
427 results2plot.extend(earlier)
428 results2plot.append(test)
429 if later is not None:
430 results2plot.extend(later)
431 if len(results2plot) == 1:
432 if not plot_singular_result:
433 return
434 plot_measurements (
435 parent = parent,
436 tests = results2plot,
437 format = format,
438 show_year = show_year,
439 use_default_template = use_default_template
440 )
441
442
443
444
445
446
447
448
449
450
451
453 """A grid class for displaying measurment results.
454
455 - does NOT listen to the currently active patient
456 - thereby it can display any patient at any time
457 """
458
459
460
461
462
463
465
466 wx.grid.Grid.__init__(self, *args, **kwargs)
467
468 self.__patient = None
469 self.__panel_to_show = None
470 self.__show_by_panel = False
471 self.__cell_data = {}
472 self.__row_label_data = []
473
474 self.__prev_row = None
475 self.__prev_col = None
476 self.__prev_label_row = None
477 self.__date_format = str((_('lab_grid_date_format::%Y\n%b %d')).lstrip('lab_grid_date_format::'))
478
479 self.__init_ui()
480 self.__register_events()
481
482
483
485 if not self.IsSelection():
486 gmDispatcher.send(signal = u'statustext', msg = _('No results selected for deletion.'))
487 return True
488
489 selected_cells = self.get_selected_cells()
490 if len(selected_cells) > 20:
491 results = None
492 msg = _(
493 'There are %s results marked for deletion.\n'
494 '\n'
495 'Are you sure you want to delete these results ?'
496 ) % len(selected_cells)
497 else:
498 results = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
499 txt = u'\n'.join([ u'%s %s (%s): %s %s%s' % (
500 r['clin_when'].strftime('%x %H:%M').decode(gmI18N.get_encoding()),
501 r['unified_abbrev'],
502 r['unified_name'],
503 r['unified_val'],
504 r['val_unit'],
505 gmTools.coalesce(r['abnormality_indicator'], u'', u' (%s)')
506 ) for r in results
507 ])
508 msg = _(
509 'The following results are marked for deletion:\n'
510 '\n'
511 '%s\n'
512 '\n'
513 'Are you sure you want to delete these results ?'
514 ) % txt
515
516 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
517 self,
518 -1,
519 caption = _('Deleting test results'),
520 question = msg,
521 button_defs = [
522 {'label': _('Delete'), 'tooltip': _('Yes, delete all the results.'), 'default': False},
523 {'label': _('Cancel'), 'tooltip': _('No, do NOT delete any results.'), 'default': True}
524 ]
525 )
526 decision = dlg.ShowModal()
527
528 if decision == wx.ID_YES:
529 if results is None:
530 results = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
531 for result in results:
532 gmPathLab.delete_test_result(result)
533
535 if not self.IsSelection():
536 gmDispatcher.send(signal = u'statustext', msg = _('Cannot sign results. No results selected.'))
537 return True
538
539 selected_cells = self.get_selected_cells()
540 if len(selected_cells) > 10:
541 test_count = len(selected_cells)
542 tests = None
543 else:
544 test_count = None
545 tests = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
546 if len(tests) == 0:
547 return True
548
549 dlg = cMeasurementsReviewDlg (
550 self,
551 -1,
552 tests = tests,
553 test_count = test_count
554 )
555 decision = dlg.ShowModal()
556
557 if decision == wx.ID_APPLY:
558 wx.BeginBusyCursor()
559
560 if dlg._RBTN_confirm_abnormal.GetValue():
561 abnormal = None
562 elif dlg._RBTN_results_normal.GetValue():
563 abnormal = False
564 else:
565 abnormal = True
566
567 if dlg._RBTN_confirm_relevance.GetValue():
568 relevant = None
569 elif dlg._RBTN_results_not_relevant.GetValue():
570 relevant = False
571 else:
572 relevant = True
573
574 if tests is None:
575 tests = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
576
577 comment = None
578 if len(tests) == 1:
579 comment = dlg._TCTRL_comment.GetValue()
580
581 for test in tests:
582 test.set_review (
583 technically_abnormal = abnormal,
584 clinically_relevant = relevant,
585 comment = comment,
586 make_me_responsible = dlg._CHBOX_responsible.IsChecked()
587 )
588
589 wx.EndBusyCursor()
590
591 dlg.Destroy()
592
594
595 if not self.IsSelection():
596 gmDispatcher.send(signal = u'statustext', msg = _('Cannot plot results. No results selected.'))
597 return True
598
599 tests = self.__cells_to_data (
600 cells = self.get_selected_cells(),
601 exclude_multi_cells = False,
602 auto_include_multi_cells = True
603 )
604
605 plot_measurements(parent = self, tests = tests)
606
608
609 sel_block_top_left = self.GetSelectionBlockTopLeft()
610 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
611 sel_cols = self.GetSelectedCols()
612 sel_rows = self.GetSelectedRows()
613
614 selected_cells = []
615
616
617 selected_cells += self.GetSelectedCells()
618
619
620 selected_cells += list (
621 (row, col)
622 for row in sel_rows
623 for col in xrange(self.GetNumberCols())
624 )
625
626
627 selected_cells += list (
628 (row, col)
629 for row in xrange(self.GetNumberRows())
630 for col in sel_cols
631 )
632
633
634 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
635 selected_cells += [
636 (row, col)
637 for row in xrange(top_left[0], bottom_right[0] + 1)
638 for col in xrange(top_left[1], bottom_right[1] + 1)
639 ]
640
641 return set(selected_cells)
642
643 - def select_cells(self, unsigned_only=False, accountables_only=False, keep_preselections=False):
644 """Select a range of cells according to criteria.
645
646 unsigned_only: include only those which are not signed at all yet
647 accountable_only: include only those for which the current user is responsible
648 keep_preselections: broaden (rather than replace) the range of selected cells
649
650 Combinations are powerful !
651 """
652 wx.BeginBusyCursor()
653 self.BeginBatch()
654
655 if not keep_preselections:
656 self.ClearSelection()
657
658 for col_idx in self.__cell_data.keys():
659 for row_idx in self.__cell_data[col_idx].keys():
660
661
662 do_not_include = False
663 for result in self.__cell_data[col_idx][row_idx]:
664 if unsigned_only:
665 if result['reviewed']:
666 do_not_include = True
667 break
668 if accountables_only:
669 if not result['you_are_responsible']:
670 do_not_include = True
671 break
672 if do_not_include:
673 continue
674
675 self.SelectBlock(row_idx, col_idx, row_idx, col_idx, addToSelected = True)
676
677 self.EndBatch()
678 wx.EndBusyCursor()
679
681 self.empty_grid()
682 if self.__patient is None:
683 return
684
685 if self.__show_by_panel:
686 self.__repopulate_grid_by_panel()
687 return
688
689 self.__repopulate_grid_all_results()
690
692
693 if self.__panel_to_show is None:
694 return
695
696 emr = self.__patient.get_emr()
697
698
699 self.__row_label_data = self.__panel_to_show.test_types
700 row_labels = [ u'%s%s' % (
701 gmTools.bool2subst(test['is_fake_meta_type'], u'', gmTools.u_sum, u''),
702 test['unified_abbrev']
703 ) for test in self.__row_label_data
704 ]
705 if len(row_labels) == 0:
706 return
707
708
709 column_labels = [
710 date[0].strftime(self.__date_format) for date in emr.get_dates_for_results (
711 tests = self.__panel_to_show['pk_test_types'],
712
713 reverse_chronological = True
714 )
715 ]
716 results = emr.get_test_results_by_date (
717 tests = self.__panel_to_show['pk_test_types'],
718
719 reverse_chronological = True
720 )
721
722 self.BeginBatch()
723
724
725 self.AppendRows(numRows = len(row_labels))
726 for row_idx in range(len(row_labels)):
727 self.SetRowLabelValue(row_idx, row_labels[row_idx])
728
729
730 self.AppendCols(numCols = len(column_labels))
731 for date_idx in range(len(column_labels)):
732 self.SetColLabelValue(date_idx, column_labels[date_idx])
733
734
735 for result in results:
736 row = row_labels.index(u'%s%s' % (
737 gmTools.bool2subst(result['is_fake_meta_type'], u'', gmTools.u_sum, u''),
738 result['unified_abbrev']
739 ))
740 col = column_labels.index(result['clin_when'].strftime(self.__date_format))
741
742 try:
743 self.__cell_data[col]
744 except KeyError:
745 self.__cell_data[col] = {}
746
747
748 if self.__cell_data[col].has_key(row):
749 self.__cell_data[col][row].append(result)
750 self.__cell_data[col][row].sort(key = lambda x: x['clin_when'], reverse = True)
751 else:
752 self.__cell_data[col][row] = [result]
753
754
755 vals2display = []
756 for sub_result in self.__cell_data[col][row]:
757
758
759 ind = gmTools.coalesce(sub_result['abnormality_indicator'], u'').strip()
760 if ind != u'':
761 lab_abnormality_indicator = u' (%s)' % ind[:3]
762 else:
763 lab_abnormality_indicator = u''
764
765 if sub_result['is_technically_abnormal'] is None:
766 abnormality_indicator = lab_abnormality_indicator
767
768 elif sub_result['is_technically_abnormal'] is False:
769 abnormality_indicator = u''
770
771 else:
772
773 if lab_abnormality_indicator == u'':
774
775 abnormality_indicator = u' (%s)' % gmTools.u_plus_minus
776
777 else:
778 abnormality_indicator = lab_abnormality_indicator
779
780
781
782 sub_result_relevant = sub_result['is_clinically_relevant']
783 if sub_result_relevant is None:
784
785 sub_result_relevant = False
786
787 missing_review = False
788
789
790 if not sub_result['reviewed']:
791 missing_review = True
792
793 else:
794
795 if sub_result['you_are_responsible'] and not sub_result['review_by_you']:
796 missing_review = True
797
798
799 if len(sub_result['unified_val']) > 8:
800 tmp = u'%.7s%s' % (sub_result['unified_val'][:7], gmTools.u_ellipsis)
801 else:
802 tmp = u'%.8s' % sub_result['unified_val'][:8]
803
804
805 tmp = u'%s%.6s' % (tmp, abnormality_indicator)
806
807
808 has_sub_result_comment = gmTools.coalesce (
809 gmTools.coalesce(sub_result['note_test_org'], sub_result['comment']),
810 u''
811 ).strip() != u''
812 if has_sub_result_comment:
813 tmp = u'%s %s' % (tmp, gmTools.u_ellipsis)
814
815
816 if missing_review:
817 tmp = u'%s %s' % (tmp, gmTools.u_writing_hand)
818
819
820 if len(self.__cell_data[col][row]) > 1:
821 tmp = u'%s %s' % (sub_result['clin_when'].strftime('%H:%M'), tmp)
822
823 vals2display.append(tmp)
824
825 self.SetCellValue(row, col, u'\n'.join(vals2display))
826 self.SetCellAlignment(row, col, horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
827
828
829
830
831 if sub_result_relevant:
832 font = self.GetCellFont(row, col)
833 self.SetCellTextColour(row, col, 'firebrick')
834 font.SetWeight(wx.FONTWEIGHT_BOLD)
835 self.SetCellFont(row, col, font)
836
837
838 self.AutoSize()
839 self.EndBatch()
840 return
841
843 emr = self.__patient.get_emr()
844
845 self.__row_label_data = emr.get_test_types_for_results()
846 test_type_labels = [ u'%s%s' % (
847 gmTools.bool2subst(test['is_fake_meta_type'], u'', gmTools.u_sum, u''),
848 test['unified_abbrev']
849 ) for test in self.__row_label_data
850 ]
851 if len(test_type_labels) == 0:
852 return
853
854 test_date_labels = [ date[0].strftime(self.__date_format) for date in emr.get_dates_for_results() ]
855 results = emr.get_test_results_by_date()
856
857 self.BeginBatch()
858
859
860 self.AppendRows(numRows = len(test_type_labels))
861 for row_idx in range(len(test_type_labels)):
862 self.SetRowLabelValue(row_idx, test_type_labels[row_idx])
863
864
865 self.AppendCols(numCols = len(test_date_labels))
866 for date_idx in range(len(test_date_labels)):
867 self.SetColLabelValue(date_idx, test_date_labels[date_idx])
868
869
870 for result in results:
871 row = test_type_labels.index(u'%s%s' % (
872 gmTools.bool2subst(result['is_fake_meta_type'], u'', gmTools.u_sum, u''),
873 result['unified_abbrev']
874 ))
875 col = test_date_labels.index(result['clin_when'].strftime(self.__date_format))
876
877 try:
878 self.__cell_data[col]
879 except KeyError:
880 self.__cell_data[col] = {}
881
882
883 if self.__cell_data[col].has_key(row):
884 self.__cell_data[col][row].append(result)
885 self.__cell_data[col][row].sort(key = lambda x: x['clin_when'], reverse = True)
886 else:
887 self.__cell_data[col][row] = [result]
888
889
890 vals2display = []
891 for sub_result in self.__cell_data[col][row]:
892
893
894 ind = gmTools.coalesce(sub_result['abnormality_indicator'], u'').strip()
895 if ind != u'':
896 lab_abnormality_indicator = u' (%s)' % ind[:3]
897 else:
898 lab_abnormality_indicator = u''
899
900 if sub_result['is_technically_abnormal'] is None:
901 abnormality_indicator = lab_abnormality_indicator
902
903 elif sub_result['is_technically_abnormal'] is False:
904 abnormality_indicator = u''
905
906 else:
907
908 if lab_abnormality_indicator == u'':
909
910 abnormality_indicator = u' (%s)' % gmTools.u_plus_minus
911
912 else:
913 abnormality_indicator = lab_abnormality_indicator
914
915
916
917 sub_result_relevant = sub_result['is_clinically_relevant']
918 if sub_result_relevant is None:
919
920 sub_result_relevant = False
921
922 missing_review = False
923
924
925 if not sub_result['reviewed']:
926 missing_review = True
927
928 else:
929
930 if sub_result['you_are_responsible'] and not sub_result['review_by_you']:
931 missing_review = True
932
933
934 if len(sub_result['unified_val']) > 8:
935 tmp = u'%.7s%s' % (sub_result['unified_val'][:7], gmTools.u_ellipsis)
936 else:
937 tmp = u'%.8s' % sub_result['unified_val'][:8]
938
939
940 tmp = u'%s%.6s' % (tmp, abnormality_indicator)
941
942
943 has_sub_result_comment = gmTools.coalesce (
944 gmTools.coalesce(sub_result['note_test_org'], sub_result['comment']),
945 u''
946 ).strip() != u''
947 if has_sub_result_comment:
948 tmp = u'%s %s' % (tmp, gmTools.u_ellipsis)
949
950
951 if missing_review:
952 tmp = u'%s %s' % (tmp, gmTools.u_writing_hand)
953
954
955 if len(self.__cell_data[col][row]) > 1:
956 tmp = u'%s %s' % (sub_result['clin_when'].strftime('%H:%M'), tmp)
957
958 vals2display.append(tmp)
959
960 self.SetCellValue(row, col, u'\n'.join(vals2display))
961 self.SetCellAlignment(row, col, horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
962
963
964
965
966 if sub_result_relevant:
967 font = self.GetCellFont(row, col)
968 self.SetCellTextColour(row, col, 'firebrick')
969 font.SetWeight(wx.FONTWEIGHT_BOLD)
970 self.SetCellFont(row, col, font)
971
972
973 self.AutoSize()
974 self.EndBatch()
975 return
976
978 self.BeginBatch()
979 self.ClearGrid()
980
981
982 if self.GetNumberRows() > 0:
983 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
984 if self.GetNumberCols() > 0:
985 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
986 self.EndBatch()
987 self.__cell_data = {}
988 self.__row_label_data = []
989
1002
1024
1025
1026
1028 self.CreateGrid(0, 1)
1029 self.EnableEditing(0)
1030 self.EnableDragGridSize(1)
1031 self.SetMinSize(wx.DefaultSize)
1032
1033
1034
1035
1036 self.SetRowLabelSize(wx.grid.GRID_AUTOSIZE)
1037
1038 self.SetRowLabelAlignment(horiz = wx.ALIGN_LEFT, vert = wx.ALIGN_CENTRE)
1039
1040
1041 dbcfg = gmCfg.cCfgSQL()
1042 url = dbcfg.get2 (
1043 option = u'external.urls.measurements_encyclopedia',
1044 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
1045 bias = 'user',
1046 default = u'http://www.laborlexikon.de'
1047 )
1048
1049 self.__WIN_corner = self.GetGridCornerLabelWindow()
1050
1051 LNK_lab = wx.lib.hyperlink.HyperLinkCtrl (
1052 self.__WIN_corner,
1053 -1,
1054 label = _('Tests'),
1055 style = wx.HL_DEFAULT_STYLE
1056 )
1057 LNK_lab.SetURL(url)
1058 LNK_lab.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BACKGROUND))
1059 LNK_lab.SetToolTipString(_(
1060 'Navigate to an encyclopedia of measurements\n'
1061 'and test methods on the web.\n'
1062 '\n'
1063 ' <%s>'
1064 ) % url)
1065
1066 SZR_inner = wx.BoxSizer(wx.HORIZONTAL)
1067 SZR_inner.Add((20, 20), 1, wx.EXPAND, 0)
1068 SZR_inner.Add(LNK_lab, 0, wx.ALIGN_CENTER_VERTICAL, 0)
1069 SZR_inner.Add((20, 20), 1, wx.EXPAND, 0)
1070
1071 SZR_corner = wx.BoxSizer(wx.VERTICAL)
1072 SZR_corner.Add((20, 20), 1, wx.EXPAND, 0)
1073 SZR_corner.AddWindow(SZR_inner, 0, wx.EXPAND)
1074 SZR_corner.Add((20, 20), 1, wx.EXPAND, 0)
1075
1076 self.__WIN_corner.SetSizer(SZR_corner)
1077 SZR_corner.Fit(self.__WIN_corner)
1078
1080 self.__WIN_corner.Layout()
1081
1082 - def __cells_to_data(self, cells=None, exclude_multi_cells=False, auto_include_multi_cells=False):
1083 """List of <cells> must be in row / col order."""
1084 data = []
1085 for row, col in cells:
1086 try:
1087
1088 data_list = self.__cell_data[col][row]
1089 except KeyError:
1090 continue
1091
1092 if len(data_list) == 1:
1093 data.append(data_list[0])
1094 continue
1095
1096 if exclude_multi_cells:
1097 gmDispatcher.send(signal = u'statustext', msg = _('Excluding multi-result field from further processing.'))
1098 continue
1099
1100 if auto_include_multi_cells:
1101 data.extend(data_list)
1102 continue
1103
1104 data_to_include = self.__get_choices_from_multi_cell(cell_data = data_list)
1105 if data_to_include is None:
1106 continue
1107 data.extend(data_to_include)
1108
1109 return data
1110
1112 data = gmListWidgets.get_choices_from_list (
1113 parent = self,
1114 msg = _(
1115 'Your selection includes a field with multiple results.\n'
1116 '\n'
1117 'Please select the individual results you want to work on:'
1118 ),
1119 caption = _('Selecting test results'),
1120 choices = [ [d['clin_when'], u'%s: %s' % (d['abbrev_tt'], d['name_tt']), d['unified_val']] for d in cell_data ],
1121 columns = [ _('Date / Time'), _('Test'), _('Result') ],
1122 data = cell_data,
1123 single_selection = single_selection
1124 )
1125 return data
1126
1127
1128
1130
1131 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
1132 self.GetGridRowLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_row_labels)
1133
1134
1135
1136 self.Bind(wx.EVT_SIZE, self.__resize_corner_window)
1137
1138
1139 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
1140
1142 col = evt.GetCol()
1143 row = evt.GetRow()
1144
1145
1146 try:
1147 self.__cell_data[col][row]
1148 except KeyError:
1149
1150
1151 return
1152
1153 if len(self.__cell_data[col][row]) > 1:
1154 data = self.__get_choices_from_multi_cell(cell_data = self.__cell_data[col][row], single_selection = True)
1155 else:
1156 data = self.__cell_data[col][row][0]
1157
1158 if data is None:
1159 return
1160
1161 edit_measurement(parent = self, measurement = data, single_entry = True)
1162
1163
1164
1165
1166
1167
1168
1170
1171
1172
1173 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
1174
1175 row = self.YToRow(y)
1176
1177 if self.__prev_label_row == row:
1178 return
1179
1180 self.__prev_label_row == row
1181
1182 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
1183
1184
1185
1186
1187
1188
1189
1190
1192 """Calculate where the mouse is and set the tooltip dynamically."""
1193
1194
1195
1196 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210 row, col = self.XYToCell(x, y)
1211
1212 if (row == self.__prev_row) and (col == self.__prev_col):
1213 return
1214
1215 self.__prev_row = row
1216 self.__prev_col = col
1217
1218 evt.GetEventObject().SetToolTipString(self.get_cell_tooltip(col=col, row=row))
1219
1220
1221
1225
1226 patient = property(lambda x:x, _set_patient)
1227
1231
1232 panel_to_show = property(lambda x:x, _set_panel_to_show)
1233
1237
1238 show_by_panel = property(lambda x:x, _set_show_by_panel)
1239
1240 from Gnumed.wxGladeWidgets import wxgMeasurementsPnl
1241
1242 -class cMeasurementsPnl(wxgMeasurementsPnl.wxgMeasurementsPnl, gmRegetMixin.cRegetOnPaintMixin):
1243 """Panel holding a grid with lab data. Used as notebook page."""
1244
1251
1252
1253
1255 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
1256 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
1257 gmDispatcher.connect(signal = u'test_result_mod_db', receiver = self._schedule_data_reget)
1258 gmDispatcher.connect(signal = u'reviewed_test_results_mod_db', receiver = self._schedule_data_reget)
1259
1261 wx.CallAfter(self.__on_post_patient_selection)
1262
1264 self._schedule_data_reget()
1265
1267 wx.CallAfter(self.__on_pre_patient_selection)
1268
1270 self.data_grid.patient = None
1271 self.panel_data_grid.patient = None
1272
1275
1278
1284
1287
1290
1293
1296
1298 wx.CallAfter(self.__on_panel_selected, panel=panel)
1299
1301 if panel is None:
1302 self._TCTRL_panel_comment.SetValue(u'')
1303 self.panel_data_grid.panel_to_show = None
1304 self.panel_data_grid.Hide()
1305 else:
1306 pnl = self._PRW_panel.GetData(as_instance = True)
1307 self._TCTRL_panel_comment.SetValue(gmTools.coalesce (
1308 pnl['comment'],
1309 u''
1310 ))
1311 self.panel_data_grid.panel_to_show = pnl
1312 self.panel_data_grid.Show()
1313 self.Layout()
1314
1315
1317 wx.CallAfter(self.__on_panel_selection_modified)
1318
1320 self._TCTRL_panel_comment.SetValue(u'')
1321 if self._PRW_panel.GetValue().strip() == u'':
1322 self.panel_data_grid.panel_to_show = None
1323 self.panel_data_grid.Hide()
1324 self.Layout()
1325
1326
1327
1329 self.__action_button_popup = wx.Menu(title = _('Perform on selected results:'))
1330
1331 menu_id = wx.NewId()
1332 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Review and &sign')))
1333 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_sign_current_selection)
1334
1335 menu_id = wx.NewId()
1336 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Plot')))
1337 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_plot_current_selection)
1338
1339 menu_id = wx.NewId()
1340 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Export to &file')))
1341
1342 self.__action_button_popup.Enable(id = menu_id, enable = False)
1343
1344 menu_id = wx.NewId()
1345 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Export to &clipboard')))
1346
1347 self.__action_button_popup.Enable(id = menu_id, enable = False)
1348
1349 menu_id = wx.NewId()
1350 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('&Delete')))
1351 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_delete_current_selection)
1352
1353
1354
1355
1356 self._PRW_panel.add_callback_on_selection(callback = self._on_panel_selected)
1357 self._PRW_panel.add_callback_on_modified(callback = self._on_panel_selection_modified)
1358
1359 self.panel_data_grid.show_by_panel = True
1360 self.panel_data_grid.panel_to_show = None
1361 self.panel_data_grid.Hide()
1362 self.Layout()
1363
1364 self._PRW_panel.SetFocus()
1365
1366
1367
1378
1379
1380
1381
1382 from Gnumed.wxGladeWidgets import wxgMeasurementsReviewDlg
1383
1385
1387
1388 try:
1389 tests = kwargs['tests']
1390 del kwargs['tests']
1391 test_count = len(tests)
1392 try: del kwargs['test_count']
1393 except KeyError: pass
1394 except KeyError:
1395 tests = None
1396 test_count = kwargs['test_count']
1397 del kwargs['test_count']
1398
1399 wxgMeasurementsReviewDlg.wxgMeasurementsReviewDlg.__init__(self, *args, **kwargs)
1400
1401 if tests is None:
1402 msg = _('%s results selected. Too many to list individually.') % test_count
1403 else:
1404 msg = ' // '.join (
1405 [ u'%s: %s %s (%s)' % (
1406 t['unified_abbrev'],
1407 t['unified_val'],
1408 t['val_unit'],
1409 gmDateTime.pydt_strftime(t['clin_when'], '%Y %b %d')
1410 ) for t in tests
1411 ]
1412 )
1413
1414 self._LBL_tests.SetLabel(msg)
1415
1416 if test_count == 1:
1417 self._TCTRL_comment.Enable(True)
1418 self._TCTRL_comment.SetValue(gmTools.coalesce(tests[0]['review_comment'], u''))
1419 if tests[0]['you_are_responsible']:
1420 self._CHBOX_responsible.Enable(False)
1421
1422 self.Fit()
1423
1424
1425
1431
1432 from Gnumed.wxGladeWidgets import wxgMeasurementEditAreaPnl
1433
1434 -class cMeasurementEditAreaPnl(wxgMeasurementEditAreaPnl.wxgMeasurementEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
1435 """This edit area saves *new* measurements into the active patient only."""
1436
1453
1454
1455
1457 self._PRW_test.SetText(u'', None, True)
1458 self.__refresh_loinc_info()
1459 self.__refresh_previous_value()
1460 self.__update_units_context()
1461 self._TCTRL_result.SetValue(u'')
1462 self._PRW_units.SetText(u'', None, True)
1463 self._PRW_abnormality_indicator.SetText(u'', None, True)
1464 if self.__default_date is None:
1465 self._DPRW_evaluated.SetData(data = pyDT.datetime.now(tz = gmDateTime.gmCurrentLocalTimezone))
1466 else:
1467 self._DPRW_evaluated.SetData(data = None)
1468 self._TCTRL_note_test_org.SetValue(u'')
1469 self._PRW_intended_reviewer.SetData(gmStaff.gmCurrentProvider()['pk_staff'])
1470 self._PRW_problem.SetData()
1471 self._TCTRL_narrative.SetValue(u'')
1472 self._CHBOX_review.SetValue(False)
1473 self._CHBOX_abnormal.SetValue(False)
1474 self._CHBOX_relevant.SetValue(False)
1475 self._CHBOX_abnormal.Enable(False)
1476 self._CHBOX_relevant.Enable(False)
1477 self._TCTRL_review_comment.SetValue(u'')
1478 self._TCTRL_normal_min.SetValue(u'')
1479 self._TCTRL_normal_max.SetValue(u'')
1480 self._TCTRL_normal_range.SetValue(u'')
1481 self._TCTRL_target_min.SetValue(u'')
1482 self._TCTRL_target_max.SetValue(u'')
1483 self._TCTRL_target_range.SetValue(u'')
1484 self._TCTRL_norm_ref_group.SetValue(u'')
1485
1486 self._PRW_test.SetFocus()
1487
1489 self._PRW_test.SetData(data = self.data['pk_test_type'])
1490 self.__refresh_loinc_info()
1491 self.__refresh_previous_value()
1492 self.__update_units_context()
1493 self._TCTRL_result.SetValue(self.data['unified_val'])
1494 self._PRW_units.SetText(self.data['val_unit'], self.data['val_unit'], True)
1495 self._PRW_abnormality_indicator.SetText (
1496 gmTools.coalesce(self.data['abnormality_indicator'], u''),
1497 gmTools.coalesce(self.data['abnormality_indicator'], u''),
1498 True
1499 )
1500 self._DPRW_evaluated.SetData(data = self.data['clin_when'])
1501 self._TCTRL_note_test_org.SetValue(gmTools.coalesce(self.data['note_test_org'], u''))
1502 self._PRW_intended_reviewer.SetData(self.data['pk_intended_reviewer'])
1503 self._PRW_problem.SetData(self.data['pk_episode'])
1504 self._TCTRL_narrative.SetValue(gmTools.coalesce(self.data['comment'], u''))
1505 self._CHBOX_review.SetValue(False)
1506 self._CHBOX_abnormal.SetValue(gmTools.coalesce(self.data['is_technically_abnormal'], False))
1507 self._CHBOX_relevant.SetValue(gmTools.coalesce(self.data['is_clinically_relevant'], False))
1508 self._CHBOX_abnormal.Enable(False)
1509 self._CHBOX_relevant.Enable(False)
1510 self._TCTRL_review_comment.SetValue(gmTools.coalesce(self.data['review_comment'], u''))
1511 self._TCTRL_normal_min.SetValue(unicode(gmTools.coalesce(self.data['val_normal_min'], u'')))
1512 self._TCTRL_normal_max.SetValue(unicode(gmTools.coalesce(self.data['val_normal_max'], u'')))
1513 self._TCTRL_normal_range.SetValue(gmTools.coalesce(self.data['val_normal_range'], u''))
1514 self._TCTRL_target_min.SetValue(unicode(gmTools.coalesce(self.data['val_target_min'], u'')))
1515 self._TCTRL_target_max.SetValue(unicode(gmTools.coalesce(self.data['val_target_max'], u'')))
1516 self._TCTRL_target_range.SetValue(gmTools.coalesce(self.data['val_target_range'], u''))
1517 self._TCTRL_norm_ref_group.SetValue(gmTools.coalesce(self.data['norm_ref_group'], u''))
1518
1519 self._TCTRL_result.SetFocus()
1520
1522 self._refresh_from_existing()
1523
1524 self._PRW_test.SetText(u'', None, True)
1525 self.__refresh_loinc_info()
1526 self.__refresh_previous_value()
1527 self.__update_units_context()
1528 self._TCTRL_result.SetValue(u'')
1529 self._PRW_units.SetText(u'', None, True)
1530 self._PRW_abnormality_indicator.SetText(u'', None, True)
1531
1532 self._TCTRL_note_test_org.SetValue(u'')
1533 self._TCTRL_narrative.SetValue(u'')
1534 self._CHBOX_review.SetValue(False)
1535 self._CHBOX_abnormal.SetValue(False)
1536 self._CHBOX_relevant.SetValue(False)
1537 self._CHBOX_abnormal.Enable(False)
1538 self._CHBOX_relevant.Enable(False)
1539 self._TCTRL_review_comment.SetValue(u'')
1540 self._TCTRL_normal_min.SetValue(u'')
1541 self._TCTRL_normal_max.SetValue(u'')
1542 self._TCTRL_normal_range.SetValue(u'')
1543 self._TCTRL_target_min.SetValue(u'')
1544 self._TCTRL_target_max.SetValue(u'')
1545 self._TCTRL_target_range.SetValue(u'')
1546 self._TCTRL_norm_ref_group.SetValue(u'')
1547
1548 self._PRW_test.SetFocus()
1549
1551
1552 validity = True
1553
1554 if not self._DPRW_evaluated.is_valid_timestamp():
1555 self._DPRW_evaluated.display_as_valid(False)
1556 validity = False
1557 else:
1558 self._DPRW_evaluated.display_as_valid(True)
1559
1560 if self._TCTRL_result.GetValue().strip() == u'':
1561 validity = False
1562 self.display_ctrl_as_valid(self._TCTRL_result, False)
1563 else:
1564 self.display_ctrl_as_valid(self._TCTRL_result, True)
1565
1566 if self._PRW_problem.GetValue().strip() == u'':
1567 self._PRW_problem.display_as_valid(False)
1568 validity = False
1569 else:
1570 self._PRW_problem.display_as_valid(True)
1571
1572 if self._PRW_test.GetValue().strip() == u'':
1573 self._PRW_test.display_as_valid(False)
1574 validity = False
1575 else:
1576 self._PRW_test.display_as_valid(True)
1577
1578 if self._PRW_intended_reviewer.GetData() is None:
1579 self._PRW_intended_reviewer.display_as_valid(False)
1580 validity = False
1581 else:
1582 self._PRW_intended_reviewer.display_as_valid(True)
1583
1584 if self._PRW_units.GetValue().strip() == u'':
1585 self._PRW_units.display_as_valid(False)
1586 validity = False
1587 else:
1588 self._PRW_units.display_as_valid(True)
1589
1590 ctrls = [self._TCTRL_normal_min, self._TCTRL_normal_max, self._TCTRL_target_min, self._TCTRL_target_max]
1591 for widget in ctrls:
1592 val = widget.GetValue().strip()
1593 if val == u'':
1594 continue
1595 try:
1596 decimal.Decimal(val.replace(',', u'.', 1))
1597 self.display_ctrl_as_valid(widget, True)
1598 except:
1599 validity = False
1600 self.display_ctrl_as_valid(widget, False)
1601
1602 if validity is False:
1603 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save result. Invalid or missing essential input.'))
1604
1605 return validity
1606
1608
1609 emr = gmPerson.gmCurrentPatient().get_emr()
1610
1611 success, result = gmTools.input2decimal(self._TCTRL_result.GetValue())
1612 if success:
1613 v_num = result
1614 v_al = None
1615 else:
1616 v_al = self._TCTRL_result.GetValue().strip()
1617 v_num = None
1618
1619 pk_type = self._PRW_test.GetData()
1620 if pk_type is None:
1621 tt = gmPathLab.create_measurement_type (
1622 lab = None,
1623 abbrev = self._PRW_test.GetValue().strip(),
1624 name = self._PRW_test.GetValue().strip(),
1625 unit = gmTools.coalesce(self._PRW_units.GetData(), self._PRW_units.GetValue()).strip()
1626 )
1627 pk_type = tt['pk_test_type']
1628
1629 tr = emr.add_test_result (
1630 episode = self._PRW_problem.GetData(can_create=True, is_open=False),
1631 type = pk_type,
1632 intended_reviewer = self._PRW_intended_reviewer.GetData(),
1633 val_num = v_num,
1634 val_alpha = v_al,
1635 unit = self._PRW_units.GetValue()
1636 )
1637
1638 tr['clin_when'] = self._DPRW_evaluated.GetData().get_pydt()
1639
1640 ctrls = [
1641 ('abnormality_indicator', self._PRW_abnormality_indicator),
1642 ('note_test_org', self._TCTRL_note_test_org),
1643 ('comment', self._TCTRL_narrative),
1644 ('val_normal_range', self._TCTRL_normal_range),
1645 ('val_target_range', self._TCTRL_target_range),
1646 ('norm_ref_group', self._TCTRL_norm_ref_group)
1647 ]
1648 for field, widget in ctrls:
1649 tr[field] = widget.GetValue().strip()
1650
1651 ctrls = [
1652 ('val_normal_min', self._TCTRL_normal_min),
1653 ('val_normal_max', self._TCTRL_normal_max),
1654 ('val_target_min', self._TCTRL_target_min),
1655 ('val_target_max', self._TCTRL_target_max)
1656 ]
1657 for field, widget in ctrls:
1658 val = widget.GetValue().strip()
1659 if val == u'':
1660 tr[field] = None
1661 else:
1662 tr[field] = decimal.Decimal(val.replace(',', u'.', 1))
1663
1664 tr.save_payload()
1665
1666 if self._CHBOX_review.GetValue() is True:
1667 tr.set_review (
1668 technically_abnormal = self._CHBOX_abnormal.GetValue(),
1669 clinically_relevant = self._CHBOX_relevant.GetValue(),
1670 comment = gmTools.none_if(self._TCTRL_review_comment.GetValue().strip(), u''),
1671 make_me_responsible = False
1672 )
1673
1674 self.data = tr
1675
1676 wx.CallAfter (
1677 plot_adjacent_measurements,
1678 test = self.data,
1679 plot_singular_result = False,
1680 use_default_template = True
1681 )
1682
1683 return True
1684
1686
1687 success, result = gmTools.input2decimal(self._TCTRL_result.GetValue())
1688 if success:
1689 v_num = result
1690 v_al = None
1691 else:
1692 v_num = None
1693 v_al = self._TCTRL_result.GetValue().strip()
1694
1695 pk_type = self._PRW_test.GetData()
1696 if pk_type is None:
1697 tt = gmPathLab.create_measurement_type (
1698 lab = None,
1699 abbrev = self._PRW_test.GetValue().strip(),
1700 name = self._PRW_test.GetValue().strip(),
1701 unit = gmTools.none_if(self._PRW_units.GetValue().strip(), u'')
1702 )
1703 pk_type = tt['pk_test_type']
1704
1705 tr = self.data
1706
1707 tr['pk_episode'] = self._PRW_problem.GetData(can_create=True, is_open=False)
1708 tr['pk_test_type'] = pk_type
1709 tr['pk_intended_reviewer'] = self._PRW_intended_reviewer.GetData()
1710 tr['val_num'] = v_num
1711 tr['val_alpha'] = v_al
1712 tr['val_unit'] = gmTools.coalesce(self._PRW_units.GetData(), self._PRW_units.GetValue()).strip()
1713 tr['clin_when'] = self._DPRW_evaluated.GetData().get_pydt()
1714
1715 ctrls = [
1716 ('abnormality_indicator', self._PRW_abnormality_indicator),
1717 ('note_test_org', self._TCTRL_note_test_org),
1718 ('comment', self._TCTRL_narrative),
1719 ('val_normal_range', self._TCTRL_normal_range),
1720 ('val_target_range', self._TCTRL_target_range),
1721 ('norm_ref_group', self._TCTRL_norm_ref_group)
1722 ]
1723 for field, widget in ctrls:
1724 tr[field] = widget.GetValue().strip()
1725
1726 ctrls = [
1727 ('val_normal_min', self._TCTRL_normal_min),
1728 ('val_normal_max', self._TCTRL_normal_max),
1729 ('val_target_min', self._TCTRL_target_min),
1730 ('val_target_max', self._TCTRL_target_max)
1731 ]
1732 for field, widget in ctrls:
1733 val = widget.GetValue().strip()
1734 if val == u'':
1735 tr[field] = None
1736 else:
1737 tr[field] = decimal.Decimal(val.replace(',', u'.', 1))
1738
1739 tr.save_payload()
1740
1741 if self._CHBOX_review.GetValue() is True:
1742 tr.set_review (
1743 technically_abnormal = self._CHBOX_abnormal.GetValue(),
1744 clinically_relevant = self._CHBOX_relevant.GetValue(),
1745 comment = gmTools.none_if(self._TCTRL_review_comment.GetValue().strip(), u''),
1746 make_me_responsible = False
1747 )
1748
1749 wx.CallAfter (
1750 plot_adjacent_measurements,
1751 test = self.data,
1752 plot_singular_result = False,
1753 use_default_template = True
1754 )
1755
1756 return True
1757
1758
1759
1763
1765 self.__refresh_loinc_info()
1766 self.__refresh_previous_value()
1767 self.__update_units_context()
1768
1770
1771 if not self._CHBOX_review.GetValue():
1772 self._CHBOX_abnormal.SetValue(self._PRW_abnormality_indicator.GetValue().strip() != u'')
1773
1775 self._CHBOX_abnormal.Enable(self._CHBOX_review.GetValue())
1776 self._CHBOX_relevant.Enable(self._CHBOX_review.GetValue())
1777 self._TCTRL_review_comment.Enable(self._CHBOX_review.GetValue())
1778
1795
1796
1797
1799
1800 self._PRW_units.unset_context(context = u'loinc')
1801
1802 tt = self._PRW_test.GetData(as_instance = True)
1803
1804 if tt is None:
1805 self._PRW_units.unset_context(context = u'pk_type')
1806 if self._PRW_test.GetValue().strip() == u'':
1807 self._PRW_units.unset_context(context = u'test_name')
1808 else:
1809 self._PRW_units.set_context(context = u'test_name', val = self._PRW_test.GetValue().strip())
1810 return
1811
1812 self._PRW_units.set_context(context = u'pk_type', val = tt['pk_test_type'])
1813 self._PRW_units.set_context(context = u'test_name', val = tt['name'])
1814
1815 if tt['loinc'] is None:
1816 return
1817
1818 self._PRW_units.set_context(context = u'loinc', val = tt['loinc'])
1819
1821
1822 self._TCTRL_loinc.SetValue(u'')
1823
1824 if self._PRW_test.GetData() is None:
1825 return
1826
1827 tt = self._PRW_test.GetData(as_instance = True)
1828
1829 if tt['loinc'] is None:
1830 return
1831
1832 info = gmLOINC.loinc2term(loinc = tt['loinc'])
1833 if len(info) == 0:
1834 self._TCTRL_loinc.SetValue(u'')
1835 return
1836
1837 self._TCTRL_loinc.SetValue(u'%s: %s' % (tt['loinc'], info[0]))
1838
1861
1862
1863
1864
1866
1867 if parent is None:
1868 parent = wx.GetApp().GetTopWindow()
1869
1870 if msg is None:
1871 msg = _('Pick the relevant measurement types.')
1872
1873 if right_column is None:
1874 right_columns = [_('Picked')]
1875 else:
1876 right_columns = [right_column]
1877
1878 picker = gmListWidgets.cItemPickerDlg(parent, -1, msg = msg)
1879 picker.set_columns(columns = [_('Known measurement types')], columns_right = right_columns)
1880 types = gmPathLab.get_measurement_types(order_by = 'unified_abbrev')
1881 picker.set_choices (
1882 choices = [
1883 u'%s: %s%s' % (
1884 t['unified_abbrev'],
1885 t['unified_name'],
1886 gmTools.coalesce(t['name_org'], u'', u' (%s)')
1887 )
1888 for t in types
1889 ],
1890 data = types
1891 )
1892 if picks is not None:
1893 picker.set_picks (
1894 picks = [
1895 u'%s: %s%s' % (
1896 p['unified_abbrev'],
1897 p['unified_name'],
1898 gmTools.coalesce(p['name_org'], u'', u' (%s)')
1899 )
1900 for p in picks
1901 ],
1902 data = picks
1903 )
1904 result = picker.ShowModal()
1905
1906 if result == wx.ID_CANCEL:
1907 picker.Destroy()
1908 return None
1909
1910 picks = picker.picks
1911 picker.Destroy()
1912 return picks
1913
1914
1937
1938 def delete(measurement_type):
1939 if measurement_type.in_use:
1940 gmDispatcher.send (
1941 signal = 'statustext',
1942 beep = True,
1943 msg = _('Cannot delete measurement type [%s (%s)] because it is in use.') % (measurement_type['name'], measurement_type['abbrev'])
1944 )
1945 return False
1946 gmPathLab.delete_measurement_type(measurement_type = measurement_type['pk_test_type'])
1947 return True
1948
1949 def get_tooltip(test_type):
1950 return test_type.format()
1951
1952 def refresh(lctrl):
1953 mtypes = gmPathLab.get_measurement_types(order_by = 'name, abbrev')
1954 items = [ [
1955 m['abbrev'],
1956 m['name'],
1957 gmTools.coalesce(m['conversion_unit'], u''),
1958 gmTools.coalesce(m['loinc'], u''),
1959 gmTools.coalesce(m['comment_type'], u''),
1960 gmTools.coalesce(m['name_org'], u'?'),
1961 gmTools.coalesce(m['comment_org'], u''),
1962 m['pk_test_type']
1963 ] for m in mtypes ]
1964 lctrl.set_string_items(items)
1965 lctrl.set_data(mtypes)
1966
1967 msg = _(
1968 '\n'
1969 'These are the measurement types currently defined in GNUmed.\n'
1970 '\n'
1971 )
1972
1973 gmListWidgets.get_choices_from_list (
1974 parent = parent,
1975 msg = msg,
1976 caption = _('Showing measurement types.'),
1977 columns = [ _('Abbrev'), _('Name'), _('Unit'), _('LOINC'), _('Comment'), _('Org'), _('Comment'), u'#' ],
1978 single_selection = True,
1979 refresh_callback = refresh,
1980 edit_callback = edit,
1981 new_callback = edit,
1982 delete_callback = delete,
1983 list_tooltip_callback = get_tooltip
1984 )
1985
1987
1989
1990 query = u"""
1991 SELECT DISTINCT ON (field_label)
1992 pk_test_type AS data,
1993 name
1994 || ' ('
1995 || coalesce (
1996 (SELECT unit || ' @ ' || organization FROM clin.v_test_orgs c_vto WHERE c_vto.pk_test_org = c_vtt.pk_test_org),
1997 '%(in_house)s'
1998 )
1999 || ')'
2000 AS field_label,
2001 name
2002 || ' ('
2003 || abbrev || ', '
2004 || coalesce(abbrev_meta || ': ' || name_meta || ', ', '')
2005 || coalesce (
2006 (SELECT unit || ' @ ' || organization FROM clin.v_test_orgs c_vto WHERE c_vto.pk_test_org = c_vtt.pk_test_org),
2007 '%(in_house)s'
2008 )
2009 || ')'
2010 AS list_label
2011 FROM
2012 clin.v_test_types c_vtt
2013 WHERE
2014 abbrev_meta %%(fragment_condition)s
2015 OR
2016 name_meta %%(fragment_condition)s
2017 OR
2018 abbrev %%(fragment_condition)s
2019 OR
2020 name %%(fragment_condition)s
2021 ORDER BY field_label
2022 LIMIT 50""" % {'in_house': _('generic / in house lab')}
2023
2024 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
2025 mp.setThresholds(1, 2, 4)
2026 mp.word_separators = '[ \t:@]+'
2027 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
2028 self.matcher = mp
2029 self.SetToolTipString(_('Select the type of measurement.'))
2030 self.selection_only = False
2031
2037
2038 from Gnumed.wxGladeWidgets import wxgMeasurementTypeEAPnl
2039
2040 -class cMeasurementTypeEAPnl(wxgMeasurementTypeEAPnl.wxgMeasurementTypeEAPnl, gmEditArea.cGenericEditAreaMixin):
2041
2058
2059
2061
2062
2063 query = u"""
2064 select distinct on (name)
2065 pk,
2066 name
2067 from clin.test_type
2068 where
2069 name %(fragment_condition)s
2070 order by name
2071 limit 50"""
2072 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
2073 mp.setThresholds(1, 2, 4)
2074 self._PRW_name.matcher = mp
2075 self._PRW_name.selection_only = False
2076 self._PRW_name.add_callback_on_lose_focus(callback = self._on_name_lost_focus)
2077
2078
2079 query = u"""
2080 select distinct on (abbrev)
2081 pk,
2082 abbrev
2083 from clin.test_type
2084 where
2085 abbrev %(fragment_condition)s
2086 order by abbrev
2087 limit 50"""
2088 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
2089 mp.setThresholds(1, 2, 3)
2090 self._PRW_abbrev.matcher = mp
2091 self._PRW_abbrev.selection_only = False
2092
2093
2094 self._PRW_conversion_unit.selection_only = False
2095
2096
2097 query = u"""
2098 SELECT DISTINCT ON (list_label)
2099 data,
2100 field_label,
2101 list_label
2102 FROM ((
2103
2104 SELECT
2105 loinc AS data,
2106 loinc AS field_label,
2107 (loinc || ': ' || abbrev || ' (' || name || ')') AS list_label
2108 FROM clin.test_type
2109 WHERE loinc %(fragment_condition)s
2110 LIMIT 50
2111
2112 ) UNION ALL (
2113
2114 SELECT
2115 code AS data,
2116 code AS field_label,
2117 (code || ': ' || term) AS list_label
2118 FROM ref.v_coded_terms
2119 WHERE
2120 coding_system = 'LOINC'
2121 AND
2122 lang = i18n.get_curr_lang()
2123 AND
2124 (code %(fragment_condition)s
2125 OR
2126 term %(fragment_condition)s)
2127 LIMIT 50
2128
2129 ) UNION ALL (
2130
2131 SELECT
2132 code AS data,
2133 code AS field_label,
2134 (code || ': ' || term) AS list_label
2135 FROM ref.v_coded_terms
2136 WHERE
2137 coding_system = 'LOINC'
2138 AND
2139 lang = 'en_EN'
2140 AND
2141 (code %(fragment_condition)s
2142 OR
2143 term %(fragment_condition)s)
2144 LIMIT 50
2145
2146 ) UNION ALL (
2147
2148 SELECT
2149 code AS data,
2150 code AS field_label,
2151 (code || ': ' || term) AS list_label
2152 FROM ref.v_coded_terms
2153 WHERE
2154 coding_system = 'LOINC'
2155 AND
2156 (code %(fragment_condition)s
2157 OR
2158 term %(fragment_condition)s)
2159 LIMIT 50
2160 )
2161 ) AS all_known_loinc
2162
2163 ORDER BY list_label
2164 LIMIT 50"""
2165 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
2166 mp.setThresholds(1, 2, 4)
2167 self._PRW_loinc.matcher = mp
2168 self._PRW_loinc.selection_only = False
2169 self._PRW_loinc.add_callback_on_lose_focus(callback = self._on_loinc_lost_focus)
2170
2172
2173 test = self._PRW_name.GetValue().strip()
2174
2175 if test == u'':
2176 self._PRW_conversion_unit.unset_context(context = u'test_name')
2177 return
2178
2179 self._PRW_conversion_unit.set_context(context = u'test_name', val = test)
2180
2182 loinc = self._PRW_loinc.GetData()
2183
2184 if loinc is None:
2185 self._TCTRL_loinc_info.SetValue(u'')
2186 self._PRW_conversion_unit.unset_context(context = u'loinc')
2187 return
2188
2189 self._PRW_conversion_unit.set_context(context = u'loinc', val = loinc)
2190
2191 info = gmLOINC.loinc2term(loinc = loinc)
2192 if len(info) == 0:
2193 self._TCTRL_loinc_info.SetValue(u'')
2194 return
2195
2196 self._TCTRL_loinc_info.SetValue(info[0])
2197
2198
2199
2201
2202 has_errors = False
2203 for field in [self._PRW_name, self._PRW_abbrev, self._PRW_conversion_unit]:
2204 if field.GetValue().strip() in [u'', None]:
2205 has_errors = True
2206 field.display_as_valid(valid = False)
2207 else:
2208 field.display_as_valid(valid = True)
2209 field.Refresh()
2210
2211 return (not has_errors)
2212
2214
2215 pk_org = self._PRW_test_org.GetData()
2216 if pk_org is None:
2217 pk_org = gmPathLab.create_test_org (
2218 name = gmTools.none_if(self._PRW_test_org.GetValue().strip(), u''),
2219 comment = gmTools.none_if(self._TCTRL_comment_org.GetValue().strip(), u'')
2220 )['pk_test_org']
2221
2222 tt = gmPathLab.create_measurement_type (
2223 lab = pk_org,
2224 abbrev = self._PRW_abbrev.GetValue().strip(),
2225 name = self._PRW_name.GetValue().strip(),
2226 unit = gmTools.coalesce (
2227 self._PRW_conversion_unit.GetData(),
2228 self._PRW_conversion_unit.GetValue()
2229 ).strip()
2230 )
2231 if self._PRW_loinc.GetData() is not None:
2232 tt['loinc'] = gmTools.none_if(self._PRW_loinc.GetData().strip(), u'')
2233 else:
2234 tt['loinc'] = gmTools.none_if(self._PRW_loinc.GetValue().strip(), u'')
2235 tt['comment_type'] = gmTools.none_if(self._TCTRL_comment_type.GetValue().strip(), u'')
2236 tt['pk_meta_test_type'] = self._PRW_meta_type.GetData()
2237
2238 tt.save()
2239
2240 self.data = tt
2241
2242 return True
2243
2271
2273 self._PRW_name.SetText(u'', None, True)
2274 self._on_name_lost_focus()
2275 self._PRW_abbrev.SetText(u'', None, True)
2276 self._PRW_conversion_unit.SetText(u'', None, True)
2277 self._PRW_loinc.SetText(u'', None, True)
2278 self._on_loinc_lost_focus()
2279 self._TCTRL_comment_type.SetValue(u'')
2280 self._PRW_test_org.SetText(u'', None, True)
2281 self._TCTRL_comment_org.SetValue(u'')
2282 self._PRW_meta_type.SetText(u'', None, True)
2283
2284 self._PRW_name.SetFocus()
2285
2287 self._PRW_name.SetText(self.data['name'], self.data['name'], True)
2288 self._on_name_lost_focus()
2289 self._PRW_abbrev.SetText(self.data['abbrev'], self.data['abbrev'], True)
2290 self._PRW_conversion_unit.SetText (
2291 gmTools.coalesce(self.data['conversion_unit'], u''),
2292 self.data['conversion_unit'],
2293 True
2294 )
2295 self._PRW_loinc.SetText (
2296 gmTools.coalesce(self.data['loinc'], u''),
2297 self.data['loinc'],
2298 True
2299 )
2300 self._on_loinc_lost_focus()
2301 self._TCTRL_comment_type.SetValue(gmTools.coalesce(self.data['comment_type'], u''))
2302 self._PRW_test_org.SetText (
2303 gmTools.coalesce(self.data['pk_test_org'], u'', self.data['name_org']),
2304 self.data['pk_test_org'],
2305 True
2306 )
2307 self._TCTRL_comment_org.SetValue(gmTools.coalesce(self.data['comment_org'], u''))
2308 if self.data['pk_meta_test_type'] is None:
2309 self._PRW_meta_type.SetText(u'', None, True)
2310 else:
2311 self._PRW_meta_type.SetText(u'%s: %s' % (self.data['abbrev_meta'], self.data['name_meta']), self.data['pk_meta_test_type'], True)
2312
2313 self._PRW_name.SetFocus()
2314
2325
2326
2327 _SQL_units_from_test_results = u"""
2328 -- via clin.v_test_results.pk_type (for types already used in results)
2329 SELECT
2330 val_unit AS data,
2331 val_unit AS field_label,
2332 val_unit || ' (' || name_tt || ')' AS list_label,
2333 1 AS rank
2334 FROM
2335 clin.v_test_results
2336 WHERE
2337 (
2338 val_unit %(fragment_condition)s
2339 OR
2340 conversion_unit %(fragment_condition)s
2341 )
2342 %(ctxt_type_pk)s
2343 %(ctxt_test_name)s
2344 """
2345
2346 _SQL_units_from_test_types = u"""
2347 -- via clin.test_type (for types not yet used in results)
2348 SELECT
2349 conversion_unit AS data,
2350 conversion_unit AS field_label,
2351 conversion_unit || ' (' || name || ')' AS list_label,
2352 2 AS rank
2353 FROM
2354 clin.test_type
2355 WHERE
2356 conversion_unit %(fragment_condition)s
2357 %(ctxt_ctt)s
2358 """
2359
2360 _SQL_units_from_loinc_ipcc = u"""
2361 -- via ref.loinc.ipcc_units
2362 SELECT
2363 ipcc_units AS data,
2364 ipcc_units AS field_label,
2365 ipcc_units || ' (LOINC.ipcc: ' || term || ')' AS list_label,
2366 3 AS rank
2367 FROM
2368 ref.loinc
2369 WHERE
2370 ipcc_units %(fragment_condition)s
2371 %(ctxt_loinc)s
2372 %(ctxt_loinc_term)s
2373 """
2374
2375 _SQL_units_from_loinc_submitted = u"""
2376 -- via ref.loinc.submitted_units
2377 SELECT
2378 submitted_units AS data,
2379 submitted_units AS field_label,
2380 submitted_units || ' (LOINC.submitted:' || term || ')' AS list_label,
2381 3 AS rank
2382 FROM
2383 ref.loinc
2384 WHERE
2385 submitted_units %(fragment_condition)s
2386 %(ctxt_loinc)s
2387 %(ctxt_loinc_term)s
2388 """
2389
2390 _SQL_units_from_loinc_example = u"""
2391 -- via ref.loinc.example_units
2392 SELECT
2393 example_units AS data,
2394 example_units AS field_label,
2395 example_units || ' (LOINC.example: ' || term || ')' AS list_label,
2396 3 AS rank
2397 FROM
2398 ref.loinc
2399 WHERE
2400 example_units %(fragment_condition)s
2401 %(ctxt_loinc)s
2402 %(ctxt_loinc_term)s
2403 """
2404
2405 _SQL_units_from_atc = u"""
2406 -- via ref.atc.unit
2407 SELECT
2408 unit AS data,
2409 unit AS field_label,
2410 unit || ' (ATC: ' || term || ')' AS list_label,
2411 2 AS rank
2412 FROM
2413 ref.atc
2414 WHERE
2415 unit IS NOT NULL
2416 AND
2417 unit %(fragment_condition)s
2418 """
2419
2420 _SQL_units_from_consumable_substance = u"""
2421 -- via ref.consumable_substance.unit
2422 SELECT
2423 unit AS data,
2424 unit AS field_label,
2425 unit || ' (' || description || ')' AS list_label,
2426 2 AS rank
2427 FROM
2428 ref.consumable_substance
2429 WHERE
2430 unit %(fragment_condition)s
2431 %(ctxt_substance)s
2432 """
2433
2434
2436
2438
2439 query = u"""
2440 SELECT DISTINCT ON (data)
2441 data,
2442 field_label,
2443 list_label
2444 FROM (
2445
2446 SELECT
2447 data,
2448 field_label,
2449 list_label,
2450 rank
2451 FROM (
2452 (%s) UNION ALL
2453 (%s) UNION ALL
2454 (%s) UNION ALL
2455 (%s) UNION ALL
2456 (%s) UNION ALL
2457 (%s) UNION ALL
2458 (%s)
2459 ) AS all_matching_units
2460 WHERE data IS NOT NULL
2461 ORDER BY rank
2462
2463 ) AS ranked_matching_units
2464 LIMIT 50""" % (
2465 _SQL_units_from_test_results,
2466 _SQL_units_from_test_types,
2467 _SQL_units_from_loinc_ipcc,
2468 _SQL_units_from_loinc_submitted,
2469 _SQL_units_from_loinc_example,
2470 _SQL_units_from_atc,
2471 _SQL_units_from_consumable_substance
2472 )
2473
2474 ctxt = {
2475 'ctxt_type_pk': {
2476 'where_part': u'AND pk_test_type = %(pk_type)s',
2477 'placeholder': u'pk_type'
2478 },
2479 'ctxt_test_name': {
2480 'where_part': u'AND %(test_name)s IN (name_tt, name_meta, abbrev_meta)',
2481 'placeholder': u'test_name'
2482 },
2483 'ctxt_ctt': {
2484 'where_part': u'AND %(test_name)s IN (name, abbrev)',
2485 'placeholder': u'test_name'
2486 },
2487 'ctxt_loinc': {
2488 'where_part': u'AND code = %(loinc)s',
2489 'placeholder': u'loinc'
2490 },
2491 'ctxt_loinc_term': {
2492 'where_part': u'AND term ~* %(test_name)s',
2493 'placeholder': u'test_name'
2494 },
2495 'ctxt_substance': {
2496 'where_part': u'AND description ~* %(substance)s',
2497 'placeholder': u'substance'
2498 }
2499 }
2500
2501 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query, context = ctxt)
2502 mp.setThresholds(1, 2, 4)
2503
2504 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
2505 self.matcher = mp
2506 self.SetToolTipString(_('Select the desired unit for the amount or measurement.'))
2507 self.selection_only = False
2508 self.phrase_separators = u'[;|]+'
2509
2510
2511
2513
2515
2516 query = u"""
2517 select distinct abnormality_indicator,
2518 abnormality_indicator, abnormality_indicator
2519 from clin.v_test_results
2520 where
2521 abnormality_indicator %(fragment_condition)s
2522 order by abnormality_indicator
2523 limit 25"""
2524
2525 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
2526 mp.setThresholds(1, 1, 2)
2527 mp.ignored_chars = "[.'\\\[\]#$%_]+" + '"'
2528 mp.word_separators = '[ \t&:]+'
2529 gmPhraseWheel.cPhraseWheel.__init__ (
2530 self,
2531 *args,
2532 **kwargs
2533 )
2534 self.matcher = mp
2535 self.SetToolTipString(_('Select an indicator for the level of abnormality.'))
2536 self.selection_only = False
2537
2538
2539
2540
2552
2554
2555 if parent is None:
2556 parent = wx.GetApp().GetTopWindow()
2557
2558
2559 def edit(org=None):
2560 return edit_measurement_org(parent = parent, org = org)
2561
2562 def refresh(lctrl):
2563 orgs = gmPathLab.get_test_orgs()
2564 lctrl.set_string_items ([
2565 (o['unit'], o['organization'], gmTools.coalesce(o['test_org_contact'], u''), gmTools.coalesce(o['comment'], u''), o['pk_test_org'])
2566 for o in orgs
2567 ])
2568 lctrl.set_data(orgs)
2569
2570 def delete(test_org):
2571 gmPathLab.delete_test_org(test_org = test_org['pk_test_org'])
2572 return True
2573
2574 gmListWidgets.get_choices_from_list (
2575 parent = parent,
2576 msg = _('\nThese are the diagnostic orgs (path labs etc) currently defined in GNUmed.\n\n'),
2577 caption = _('Showing diagnostic orgs.'),
2578 columns = [_('Name'), _('Organization'), _('Contact'), _('Comment'), u'#'],
2579 single_selection = True,
2580 refresh_callback = refresh,
2581 edit_callback = edit,
2582 new_callback = edit,
2583 delete_callback = delete
2584 )
2585
2586
2587 from Gnumed.wxGladeWidgets import wxgMeasurementOrgEAPnl
2588
2589 -class cMeasurementOrgEAPnl(wxgMeasurementOrgEAPnl.wxgMeasurementOrgEAPnl, gmEditArea.cGenericEditAreaMixin):
2590
2606
2607
2608
2609
2610
2611
2612
2613
2615 has_errors = False
2616 if self._PRW_org_unit.GetData() is None:
2617 if self._PRW_org_unit.GetValue().strip() == u'':
2618 has_errors = True
2619 self._PRW_org_unit.display_as_valid(valid = False)
2620 else:
2621 self._PRW_org_unit.display_as_valid(valid = True)
2622 else:
2623 self._PRW_org_unit.display_as_valid(valid = True)
2624
2625 return (not has_errors)
2626
2637
2657
2662
2667
2669 self._refresh_as_new()
2670
2673
2674
2676
2678
2679 query = u"""
2680 SELECT DISTINCT ON (list_label)
2681 pk AS data,
2682 unit || ' (' || organization || ')' AS field_label,
2683 unit || ' @ ' || organization AS list_label
2684 FROM clin.v_test_orgs
2685 WHERE
2686 unit %(fragment_condition)s
2687 OR
2688 organization %(fragment_condition)s
2689 ORDER BY list_label
2690 LIMIT 50"""
2691 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
2692 mp.setThresholds(1, 2, 4)
2693
2694 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
2695 self.matcher = mp
2696 self.SetToolTipString(_('The name of the path lab/diagnostic organisation.'))
2697 self.selection_only = False
2698
2711
2714
2715
2754
2799
2800
2801
2802
2804 ea = cTestPanelEAPnl(parent = parent, id = -1)
2805 ea.data = test_panel
2806 ea.mode = gmTools.coalesce(test_panel, 'new', 'edit')
2807 dlg = gmEditArea.cGenericEditAreaDlg2 (
2808 parent = parent,
2809 id = -1,
2810 edit_area = ea,
2811 single_entry = gmTools.bool2subst((test_panel is None), False, True)
2812 )
2813 dlg.SetTitle(gmTools.coalesce(test_panel, _('Adding new test panel'), _('Editing test panel')))
2814 if dlg.ShowModal() == wx.ID_OK:
2815 dlg.Destroy()
2816 return True
2817 dlg.Destroy()
2818 return False
2819
2820
2822
2823 if parent is None:
2824 parent = wx.GetApp().GetTopWindow()
2825
2826
2827 def edit(test_panel=None):
2828 return edit_test_panel(parent = parent, test_panel = test_panel)
2829
2830 def delete(test_panel):
2831 gmPathLab.delete_test_panel(pk = test_panel['pk_test_panel'])
2832 return True
2833
2834 def get_tooltip(test_panel):
2835 return test_panel.format()
2836
2837 def refresh(lctrl):
2838 panels = gmPathLab.get_test_panels(order_by = 'description')
2839 items = [ [
2840 p['description'],
2841 gmTools.coalesce(p['comment'], u''),
2842 p['pk_test_panel']
2843 ] for p in panels ]
2844 lctrl.set_string_items(items)
2845 lctrl.set_data(panels)
2846
2847 msg = _(
2848 '\n'
2849 'Test panels as defined in GNUmed.\n'
2850 )
2851
2852 gmListWidgets.get_choices_from_list (
2853 parent = parent,
2854 msg = msg,
2855 caption = _('Showing test panels.'),
2856 columns = [ _('Name'), _('Comment'), u'#' ],
2857 single_selection = True,
2858 refresh_callback = refresh,
2859 edit_callback = edit,
2860 new_callback = edit,
2861 delete_callback = delete,
2862 list_tooltip_callback = get_tooltip
2863 )
2864
2865
2867
2869 query = u"""
2870 SELECT
2871 pk_test_panel
2872 AS data,
2873 description
2874 AS field_label,
2875 description
2876 AS list_label
2877 FROM
2878 clin.v_test_panels
2879 WHERE
2880 description %(fragment_condition)s
2881 ORDER BY field_label
2882 LIMIT 30"""
2883 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
2884 mp.setThresholds(1, 2, 4)
2885
2886 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
2887 self.matcher = mp
2888 self.SetToolTipString(_('Select a test panel.'))
2889 self.selection_only = True
2890
2895
2900
2901
2902 from Gnumed.wxGladeWidgets import wxgTestPanelEAPnl
2903
2904 -class cTestPanelEAPnl(wxgTestPanelEAPnl.wxgTestPanelEAPnl, gmEditArea.cGenericEditAreaMixin):
2905
2923
2924
2925
2926
2927
2928
2929
2930
2932 validity = True
2933
2934 if self._test_types is None:
2935 validity = False
2936 gmDispatcher.send(signal = 'statustext', msg = _('No test types selected.'))
2937 self._BTN_select_tests.SetFocus()
2938
2939 if self._TCTRL_description.GetValue().strip() == u'':
2940 validity = False
2941 self.display_tctrl_as_valid(tctrl = self._TCTRL_description, valid = False)
2942 self._TCTRL_description.SetFocus()
2943 else:
2944 self.display_tctrl_as_valid(tctrl = self._TCTRL_description, valid = True)
2945
2946 return validity
2947
2956
2958 self.data['description'] = self._TCTRL_description.GetValue().strip()
2959 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
2960 self.data['pk_test_types'] = [ tt['pk_test_type'] for tt in self._test_types ]
2961 self.data.save()
2962 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ]
2963 return True
2964
2966 self._TCTRL_tests.SetValue(u'')
2967 self._test_types = test_types
2968 if self._test_types is None:
2969 return
2970 tmp = u';\n'.join ([
2971 u'%s: %s%s' % (
2972 t['unified_abbrev'],
2973 t['unified_name'],
2974 gmTools.coalesce(t['name_org'], u'', u' (%s)')
2975 )
2976 for t in self._test_types
2977 ])
2978 self._TCTRL_tests.SetValue(tmp)
2979
2981 self._TCTRL_description.SetValue(u'')
2982 self._TCTRL_comment.SetValue(u'')
2983 self.__refresh_test_types_field()
2984 self._PRW_codes.SetText()
2985
2986 self._TCTRL_description.SetFocus()
2987
2991
3000
3016
3017
3018
3019
3020 if __name__ == '__main__':
3021
3022 from Gnumed.pycommon import gmLog2
3023 from Gnumed.wxpython import gmPatSearchWidgets
3024
3025 gmI18N.activate_locale()
3026 gmI18N.install_domain()
3027 gmDateTime.init()
3028
3029
3037
3045
3046
3047
3048
3049
3050
3051
3052 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
3053
3054 test_test_ea_pnl()
3055
3056
3057
3058