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.business import gmPerson
17 from Gnumed.business import gmStaff
18 from Gnumed.business import gmPathLab
19 from Gnumed.business import gmSurgery
20 from Gnumed.business import gmLOINC
21 from Gnumed.business import gmForms
22 from Gnumed.business import gmPersonSearch
23 from Gnumed.business import gmOrganization
24
25 from Gnumed.pycommon import gmTools
26 from Gnumed.pycommon import gmNetworkTools
27 from Gnumed.pycommon import gmI18N
28 from Gnumed.pycommon import gmShellAPI
29 from Gnumed.pycommon import gmCfg
30 from Gnumed.pycommon import gmDateTime
31 from Gnumed.pycommon import gmMatchProvider
32 from Gnumed.pycommon import gmDispatcher
33
34 from Gnumed.wxpython import gmRegetMixin
35 from Gnumed.wxpython import gmEditArea
36 from Gnumed.wxpython import gmPhraseWheel
37 from Gnumed.wxpython import gmListWidgets
38 from Gnumed.wxpython import gmGuiHelpers
39 from Gnumed.wxpython import gmAuthWidgets
40 from Gnumed.wxpython import gmOrganizationWidgets
41
42
43 _log = logging.getLogger('gm.ui')
44
45
46
47
49
50 wx.BeginBusyCursor()
51
52 gmDispatcher.send(signal = 'statustext', msg = _('Updating LOINC data can take quite a while...'), beep = True)
53
54
55 loinc_zip = gmNetworkTools.download_file(url = 'http://www.gnumed.de/downloads/data/loinc/loinctab.zip', suffix = '.zip')
56 if loinc_zip is None:
57 wx.EndBusyCursor()
58 gmGuiHelpers.gm_show_warning (
59 aTitle = _('Downloading LOINC'),
60 aMessage = _('Error downloading the latest LOINC data.\n')
61 )
62 return False
63
64 _log.debug('downloaded zipped LOINC data into [%s]', loinc_zip)
65
66 loinc_dir = gmNetworkTools.unzip_data_pack(filename = loinc_zip)
67
68
69 data_fname, license_fname = gmLOINC.split_LOINCDBTXT(input_fname = os.path.join(loinc_dir, 'LOINCDB.TXT'))
70
71 wx.EndBusyCursor()
72
73 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('importing LOINC reference data'))
74 if conn is None:
75 return False
76
77 wx.BeginBusyCursor()
78
79
80 if gmLOINC.loinc_import(data_fname = data_fname, license_fname = license_fname, conn = conn):
81 gmDispatcher.send(signal = 'statustext', msg = _('Successfully imported LOINC reference data.'))
82 else:
83 gmDispatcher.send(signal = 'statustext', msg = _('Importing LOINC reference data failed.'), beep = True)
84
85 wx.EndBusyCursor()
86 return True
87
88
89
91
92 dbcfg = gmCfg.cCfgSQL()
93
94 url = dbcfg.get (
95 option = u'external.urls.measurements_search',
96 workplace = gmSurgery.gmCurrentPractice().active_workplace,
97 bias = 'user',
98 default = u"http://www.google.de/search?as_oq=%(search_term)s&num=10&as_sitesearch=laborlexikon.de"
99 )
100
101 base_url = dbcfg.get2 (
102 option = u'external.urls.measurements_encyclopedia',
103 workplace = gmSurgery.gmCurrentPractice().active_workplace,
104 bias = 'user',
105 default = u'http://www.laborlexikon.de'
106 )
107
108 if measurement_type is None:
109 url = base_url
110
111 measurement_type = measurement_type.strip()
112
113 if measurement_type == u'':
114 url = base_url
115
116 url = url % {'search_term': measurement_type}
117
118 gmNetworkTools.open_url_in_browser(url = url)
119
120
132
133
135
136 if parent is None:
137 parent = wx.GetApp().GetTopWindow()
138
139 if emr is None:
140 emr = gmPerson.gmCurrentPatient().emr
141
142
143 def edit(measurement=None):
144 return edit_measurement(parent = parent, measurement = measurement, single_entry = True)
145
146 def delete(measurement):
147 gmPathLab.delete_test_result(result = measurement)
148 return True
149
150 def get_tooltip(measurement):
151 return measurement.format(with_review=True, with_evaluation=True, with_ranges=True)
152
153 def refresh(lctrl):
154 results = emr.get_test_results(order_by = 'clin_when DESC, unified_abbrev, unified_name')
155 items = [ [
156 gmDateTime.pydt_strftime (
157 r['clin_when'],
158 '%Y %b %d %H:%M',
159 accuracy = gmDateTime.acc_minutes
160 ),
161 r['unified_abbrev'],
162 u'%s%s%s' % (
163 r['unified_val'],
164 gmTools.coalesce(r['val_unit'], u'', u' %s'),
165 gmTools.coalesce(r['abnormality_indicator'], u'', u' %s')
166 ),
167 r['unified_name'],
168 gmTools.coalesce(r['comment'], u''),
169 r['pk_test_result']
170 ] for r in results ]
171 lctrl.set_string_items(items)
172 lctrl.set_data(results)
173
174 msg = _('Test results (ordered reverse-chronologicallly)')
175
176 return gmListWidgets.get_choices_from_list (
177 parent = parent,
178 msg = msg,
179 caption = _('Showing test results.'),
180 columns = [ _('When'), _('Abbrev'), _('Value'), _('Name'), _('Comment'), u'#' ],
181 single_selection = single_selection,
182 can_return_empty = False,
183 refresh_callback = refresh,
184 edit_callback = edit,
185 new_callback = edit,
186 delete_callback = delete,
187 list_tooltip_callback = get_tooltip
188 )
189
190
221
222
224
225 option = u'form_templates.default_gnuplot_template'
226
227 dbcfg = gmCfg.cCfgSQL()
228
229
230 default_template_name = dbcfg.get2 (
231 option = option,
232 workplace = gmSurgery.gmCurrentPractice().active_workplace,
233 bias = 'user'
234 )
235
236
237 if default_template_name is None:
238 gmDispatcher.send('statustext', msg = _('No default Gnuplot template configured.'), beep = False)
239 default_template = configure_default_gnuplot_template(parent = parent)
240
241 if default_template is None:
242 gmGuiHelpers.gm_show_error (
243 aMessage = _('There is no default Gnuplot one-type script template configured.'),
244 aTitle = _('Plotting test results')
245 )
246 return None
247 return default_template
248
249
250
251 try:
252 name, ver = default_template_name.split(u' - ')
253 except:
254
255 _log.exception('problem splitting Gnuplot script template name [%s]', default_template_name)
256 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading Gnuplot script template.'), beep = True)
257 return None
258
259 default_template = gmForms.get_form_template(name_long = name, external_version = ver)
260 if default_template is None:
261 default_template = configure_default_gnuplot_template(parent = parent)
262
263 if default_template is None:
264 gmGuiHelpers.gm_show_error (
265 aMessage = _('Cannot load default Gnuplot script template [%s - %s]') % (name, ver),
266 aTitle = _('Plotting test results')
267 )
268 return None
269
270 return default_template
271
272
273 -def plot_measurements(parent=None, tests=None, format=None, show_year = True, use_default_template=False):
299
300
301 -def plot_adjacent_measurements(parent=None, test=None, format=None, show_year=True, plot_singular_result=True, use_default_template=False):
302
303 earlier, later = test.get_adjacent_results(desired_earlier_results = 2, desired_later_results = 2)
304 results2plot = []
305 if earlier is not None:
306 results2plot.extend(earlier)
307 results2plot.append(test)
308 if later is not None:
309 results2plot.extend(later)
310 if len(results2plot) == 1:
311 if not plot_singular_result:
312 return
313 plot_measurements (
314 parent = parent,
315 tests = results2plot,
316 format = format,
317 show_year = show_year,
318 use_default_template = use_default_template
319 )
320
321
322
323
324
325
326
327
328
329
330
332 """A grid class for displaying measurment results.
333
334 - does NOT listen to the currently active patient
335 - thereby it can display any patient at any time
336 """
337
338
339
340
341
342
344
345 wx.grid.Grid.__init__(self, *args, **kwargs)
346
347 self.__patient = None
348 self.__panel_to_show = None
349 self.__show_by_panel = False
350 self.__cell_data = {}
351 self.__row_label_data = []
352
353 self.__prev_row = None
354 self.__prev_col = None
355 self.__prev_label_row = None
356 self.__date_format = str((_('lab_grid_date_format::%Y\n%b %d')).lstrip('lab_grid_date_format::'))
357
358 self.__init_ui()
359 self.__register_events()
360
361
362
364 if not self.IsSelection():
365 gmDispatcher.send(signal = u'statustext', msg = _('No results selected for deletion.'))
366 return True
367
368 selected_cells = self.get_selected_cells()
369 if len(selected_cells) > 20:
370 results = None
371 msg = _(
372 'There are %s results marked for deletion.\n'
373 '\n'
374 'Are you sure you want to delete these results ?'
375 ) % len(selected_cells)
376 else:
377 results = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
378 txt = u'\n'.join([ u'%s %s (%s): %s %s%s' % (
379 r['clin_when'].strftime('%x %H:%M').decode(gmI18N.get_encoding()),
380 r['unified_abbrev'],
381 r['unified_name'],
382 r['unified_val'],
383 r['val_unit'],
384 gmTools.coalesce(r['abnormality_indicator'], u'', u' (%s)')
385 ) for r in results
386 ])
387 msg = _(
388 'The following results are marked for deletion:\n'
389 '\n'
390 '%s\n'
391 '\n'
392 'Are you sure you want to delete these results ?'
393 ) % txt
394
395 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
396 self,
397 -1,
398 caption = _('Deleting test results'),
399 question = msg,
400 button_defs = [
401 {'label': _('Delete'), 'tooltip': _('Yes, delete all the results.'), 'default': False},
402 {'label': _('Cancel'), 'tooltip': _('No, do NOT delete any results.'), 'default': True}
403 ]
404 )
405 decision = dlg.ShowModal()
406
407 if decision == wx.ID_YES:
408 if results is None:
409 results = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
410 for result in results:
411 gmPathLab.delete_test_result(result)
412
414 if not self.IsSelection():
415 gmDispatcher.send(signal = u'statustext', msg = _('Cannot sign results. No results selected.'))
416 return True
417
418 selected_cells = self.get_selected_cells()
419 if len(selected_cells) > 10:
420 test_count = len(selected_cells)
421 tests = None
422 else:
423 test_count = None
424 tests = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
425 if len(tests) == 0:
426 return True
427
428 dlg = cMeasurementsReviewDlg (
429 self,
430 -1,
431 tests = tests,
432 test_count = test_count
433 )
434 decision = dlg.ShowModal()
435
436 if decision == wx.ID_APPLY:
437 wx.BeginBusyCursor()
438
439 if dlg._RBTN_confirm_abnormal.GetValue():
440 abnormal = None
441 elif dlg._RBTN_results_normal.GetValue():
442 abnormal = False
443 else:
444 abnormal = True
445
446 if dlg._RBTN_confirm_relevance.GetValue():
447 relevant = None
448 elif dlg._RBTN_results_not_relevant.GetValue():
449 relevant = False
450 else:
451 relevant = True
452
453 if tests is None:
454 tests = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
455
456 comment = None
457 if len(tests) == 1:
458 comment = dlg._TCTRL_comment.GetValue()
459
460 for test in tests:
461 test.set_review (
462 technically_abnormal = abnormal,
463 clinically_relevant = relevant,
464 comment = comment,
465 make_me_responsible = dlg._CHBOX_responsible.IsChecked()
466 )
467
468 wx.EndBusyCursor()
469
470 dlg.Destroy()
471
473
474 if not self.IsSelection():
475 gmDispatcher.send(signal = u'statustext', msg = _('Cannot plot results. No results selected.'))
476 return True
477
478 tests = self.__cells_to_data (
479 cells = self.get_selected_cells(),
480 exclude_multi_cells = False,
481 auto_include_multi_cells = True
482 )
483
484 plot_measurements(parent = self, tests = tests)
485
487
488 sel_block_top_left = self.GetSelectionBlockTopLeft()
489 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
490 sel_cols = self.GetSelectedCols()
491 sel_rows = self.GetSelectedRows()
492
493 selected_cells = []
494
495
496 selected_cells += self.GetSelectedCells()
497
498
499 selected_cells += list (
500 (row, col)
501 for row in sel_rows
502 for col in xrange(self.GetNumberCols())
503 )
504
505
506 selected_cells += list (
507 (row, col)
508 for row in xrange(self.GetNumberRows())
509 for col in sel_cols
510 )
511
512
513 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
514 selected_cells += [
515 (row, col)
516 for row in xrange(top_left[0], bottom_right[0] + 1)
517 for col in xrange(top_left[1], bottom_right[1] + 1)
518 ]
519
520 return set(selected_cells)
521
522 - def select_cells(self, unsigned_only=False, accountables_only=False, keep_preselections=False):
523 """Select a range of cells according to criteria.
524
525 unsigned_only: include only those which are not signed at all yet
526 accountable_only: include only those for which the current user is responsible
527 keep_preselections: broaden (rather than replace) the range of selected cells
528
529 Combinations are powerful !
530 """
531 wx.BeginBusyCursor()
532 self.BeginBatch()
533
534 if not keep_preselections:
535 self.ClearSelection()
536
537 for col_idx in self.__cell_data.keys():
538 for row_idx in self.__cell_data[col_idx].keys():
539
540
541 do_not_include = False
542 for result in self.__cell_data[col_idx][row_idx]:
543 if unsigned_only:
544 if result['reviewed']:
545 do_not_include = True
546 break
547 if accountables_only:
548 if not result['you_are_responsible']:
549 do_not_include = True
550 break
551 if do_not_include:
552 continue
553
554 self.SelectBlock(row_idx, col_idx, row_idx, col_idx, addToSelected = True)
555
556 self.EndBatch()
557 wx.EndBusyCursor()
558
560 self.empty_grid()
561 if self.__patient is None:
562 return
563
564 if self.__show_by_panel:
565 self.__repopulate_grid_by_panel()
566 return
567
568 self.__repopulate_grid_all_results()
569
571
572 if self.__panel_to_show is None:
573 return
574
575 emr = self.__patient.get_emr()
576
577
578 self.__row_label_data = self.__panel_to_show.test_types
579 row_labels = [ u'%s%s' % (
580 gmTools.bool2subst(test['is_fake_meta_type'], u'', gmTools.u_sum, u''),
581 test['unified_abbrev']
582 ) for test in self.__row_label_data
583 ]
584 if len(row_labels) == 0:
585 return
586
587
588 column_labels = [
589 date[0].strftime(self.__date_format) for date in emr.get_dates_for_results (
590 tests = self.__panel_to_show['pk_test_types'],
591
592 reverse_chronological = True
593 )
594 ]
595 results = emr.get_test_results_by_date (
596 tests = self.__panel_to_show['pk_test_types'],
597
598 reverse_chronological = True
599 )
600
601 self.BeginBatch()
602
603
604 self.AppendRows(numRows = len(row_labels))
605 for row_idx in range(len(row_labels)):
606 self.SetRowLabelValue(row_idx, row_labels[row_idx])
607
608
609 self.AppendCols(numCols = len(column_labels))
610 for date_idx in range(len(column_labels)):
611 self.SetColLabelValue(date_idx, column_labels[date_idx])
612
613
614 for result in results:
615 row = row_labels.index(u'%s%s' % (
616 gmTools.bool2subst(result['is_fake_meta_type'], u'', gmTools.u_sum, u''),
617 result['unified_abbrev']
618 ))
619 col = column_labels.index(result['clin_when'].strftime(self.__date_format))
620
621 try:
622 self.__cell_data[col]
623 except KeyError:
624 self.__cell_data[col] = {}
625
626
627 if self.__cell_data[col].has_key(row):
628 self.__cell_data[col][row].append(result)
629 self.__cell_data[col][row].sort(key = lambda x: x['clin_when'], reverse = True)
630 else:
631 self.__cell_data[col][row] = [result]
632
633
634 vals2display = []
635 for sub_result in self.__cell_data[col][row]:
636
637
638 ind = gmTools.coalesce(sub_result['abnormality_indicator'], u'').strip()
639 if ind != u'':
640 lab_abnormality_indicator = u' (%s)' % ind[:3]
641 else:
642 lab_abnormality_indicator = u''
643
644 if sub_result['is_technically_abnormal'] is None:
645 abnormality_indicator = lab_abnormality_indicator
646
647 elif sub_result['is_technically_abnormal'] is False:
648 abnormality_indicator = u''
649
650 else:
651
652 if lab_abnormality_indicator == u'':
653
654 abnormality_indicator = u' (%s)' % gmTools.u_plus_minus
655
656 else:
657 abnormality_indicator = lab_abnormality_indicator
658
659
660
661 sub_result_relevant = sub_result['is_clinically_relevant']
662 if sub_result_relevant is None:
663
664 sub_result_relevant = False
665
666 missing_review = False
667
668
669 if not sub_result['reviewed']:
670 missing_review = True
671
672 else:
673
674 if sub_result['you_are_responsible'] and not sub_result['review_by_you']:
675 missing_review = True
676
677
678 if len(sub_result['unified_val']) > 8:
679 tmp = u'%.7s%s' % (sub_result['unified_val'][:7], gmTools.u_ellipsis)
680 else:
681 tmp = u'%.8s' % sub_result['unified_val'][:8]
682
683
684 tmp = u'%s%.6s' % (tmp, abnormality_indicator)
685
686
687 has_sub_result_comment = gmTools.coalesce (
688 gmTools.coalesce(sub_result['note_test_org'], sub_result['comment']),
689 u''
690 ).strip() != u''
691 if has_sub_result_comment:
692 tmp = u'%s %s' % (tmp, gmTools.u_ellipsis)
693
694
695 if missing_review:
696 tmp = u'%s %s' % (tmp, gmTools.u_writing_hand)
697
698
699 if len(self.__cell_data[col][row]) > 1:
700 tmp = u'%s %s' % (sub_result['clin_when'].strftime('%H:%M'), tmp)
701
702 vals2display.append(tmp)
703
704 self.SetCellValue(row, col, u'\n'.join(vals2display))
705 self.SetCellAlignment(row, col, horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
706
707
708
709
710 if sub_result_relevant:
711 font = self.GetCellFont(row, col)
712 self.SetCellTextColour(row, col, 'firebrick')
713 font.SetWeight(wx.FONTWEIGHT_BOLD)
714 self.SetCellFont(row, col, font)
715
716
717 self.AutoSize()
718 self.EndBatch()
719 return
720
722 emr = self.__patient.get_emr()
723
724 self.__row_label_data = emr.get_test_types_for_results()
725 test_type_labels = [ u'%s%s' % (
726 gmTools.bool2subst(test['is_fake_meta_type'], u'', gmTools.u_sum, u''),
727 test['unified_abbrev']
728 ) for test in self.__row_label_data
729 ]
730 if len(test_type_labels) == 0:
731 return
732
733 test_date_labels = [ date[0].strftime(self.__date_format) for date in emr.get_dates_for_results() ]
734 results = emr.get_test_results_by_date()
735
736 self.BeginBatch()
737
738
739 self.AppendRows(numRows = len(test_type_labels))
740 for row_idx in range(len(test_type_labels)):
741 self.SetRowLabelValue(row_idx, test_type_labels[row_idx])
742
743
744 self.AppendCols(numCols = len(test_date_labels))
745 for date_idx in range(len(test_date_labels)):
746 self.SetColLabelValue(date_idx, test_date_labels[date_idx])
747
748
749 for result in results:
750 row = test_type_labels.index(u'%s%s' % (
751 gmTools.bool2subst(result['is_fake_meta_type'], u'', gmTools.u_sum, u''),
752 result['unified_abbrev']
753 ))
754 col = test_date_labels.index(result['clin_when'].strftime(self.__date_format))
755
756 try:
757 self.__cell_data[col]
758 except KeyError:
759 self.__cell_data[col] = {}
760
761
762 if self.__cell_data[col].has_key(row):
763 self.__cell_data[col][row].append(result)
764 self.__cell_data[col][row].sort(key = lambda x: x['clin_when'], reverse = True)
765 else:
766 self.__cell_data[col][row] = [result]
767
768
769 vals2display = []
770 for sub_result in self.__cell_data[col][row]:
771
772
773 ind = gmTools.coalesce(sub_result['abnormality_indicator'], u'').strip()
774 if ind != u'':
775 lab_abnormality_indicator = u' (%s)' % ind[:3]
776 else:
777 lab_abnormality_indicator = u''
778
779 if sub_result['is_technically_abnormal'] is None:
780 abnormality_indicator = lab_abnormality_indicator
781
782 elif sub_result['is_technically_abnormal'] is False:
783 abnormality_indicator = u''
784
785 else:
786
787 if lab_abnormality_indicator == u'':
788
789 abnormality_indicator = u' (%s)' % gmTools.u_plus_minus
790
791 else:
792 abnormality_indicator = lab_abnormality_indicator
793
794
795
796 sub_result_relevant = sub_result['is_clinically_relevant']
797 if sub_result_relevant is None:
798
799 sub_result_relevant = False
800
801 missing_review = False
802
803
804 if not sub_result['reviewed']:
805 missing_review = True
806
807 else:
808
809 if sub_result['you_are_responsible'] and not sub_result['review_by_you']:
810 missing_review = True
811
812
813 if len(sub_result['unified_val']) > 8:
814 tmp = u'%.7s%s' % (sub_result['unified_val'][:7], gmTools.u_ellipsis)
815 else:
816 tmp = u'%.8s' % sub_result['unified_val'][:8]
817
818
819 tmp = u'%s%.6s' % (tmp, abnormality_indicator)
820
821
822 has_sub_result_comment = gmTools.coalesce (
823 gmTools.coalesce(sub_result['note_test_org'], sub_result['comment']),
824 u''
825 ).strip() != u''
826 if has_sub_result_comment:
827 tmp = u'%s %s' % (tmp, gmTools.u_ellipsis)
828
829
830 if missing_review:
831 tmp = u'%s %s' % (tmp, gmTools.u_writing_hand)
832
833
834 if len(self.__cell_data[col][row]) > 1:
835 tmp = u'%s %s' % (sub_result['clin_when'].strftime('%H:%M'), tmp)
836
837 vals2display.append(tmp)
838
839 self.SetCellValue(row, col, u'\n'.join(vals2display))
840 self.SetCellAlignment(row, col, horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
841
842
843
844
845 if sub_result_relevant:
846 font = self.GetCellFont(row, col)
847 self.SetCellTextColour(row, col, 'firebrick')
848 font.SetWeight(wx.FONTWEIGHT_BOLD)
849 self.SetCellFont(row, col, font)
850
851
852 self.AutoSize()
853 self.EndBatch()
854 return
855
857 self.BeginBatch()
858 self.ClearGrid()
859
860
861 if self.GetNumberRows() > 0:
862 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
863 if self.GetNumberCols() > 0:
864 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
865 self.EndBatch()
866 self.__cell_data = {}
867 self.__row_label_data = []
868
881
903
904
905
907 self.CreateGrid(0, 1)
908 self.EnableEditing(0)
909 self.EnableDragGridSize(1)
910 self.SetMinSize(wx.DefaultSize)
911
912
913
914
915 self.SetRowLabelSize(wx.grid.GRID_AUTOSIZE)
916
917 self.SetRowLabelAlignment(horiz = wx.ALIGN_LEFT, vert = wx.ALIGN_CENTRE)
918
919
920 dbcfg = gmCfg.cCfgSQL()
921 url = dbcfg.get2 (
922 option = u'external.urls.measurements_encyclopedia',
923 workplace = gmSurgery.gmCurrentPractice().active_workplace,
924 bias = 'user',
925 default = u'http://www.laborlexikon.de'
926 )
927
928 self.__WIN_corner = self.GetGridCornerLabelWindow()
929
930 LNK_lab = wx.lib.hyperlink.HyperLinkCtrl (
931 self.__WIN_corner,
932 -1,
933 label = _('Tests'),
934 style = wx.HL_DEFAULT_STYLE
935 )
936 LNK_lab.SetURL(url)
937 LNK_lab.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BACKGROUND))
938 LNK_lab.SetToolTipString(_(
939 'Navigate to an encyclopedia of measurements\n'
940 'and test methods on the web.\n'
941 '\n'
942 ' <%s>'
943 ) % url)
944
945 SZR_inner = wx.BoxSizer(wx.HORIZONTAL)
946 SZR_inner.Add((20, 20), 1, wx.EXPAND, 0)
947 SZR_inner.Add(LNK_lab, 0, wx.ALIGN_CENTER_VERTICAL, 0)
948 SZR_inner.Add((20, 20), 1, wx.EXPAND, 0)
949
950 SZR_corner = wx.BoxSizer(wx.VERTICAL)
951 SZR_corner.Add((20, 20), 1, wx.EXPAND, 0)
952 SZR_corner.AddWindow(SZR_inner, 0, wx.EXPAND)
953 SZR_corner.Add((20, 20), 1, wx.EXPAND, 0)
954
955 self.__WIN_corner.SetSizer(SZR_corner)
956 SZR_corner.Fit(self.__WIN_corner)
957
959 self.__WIN_corner.Layout()
960
961 - def __cells_to_data(self, cells=None, exclude_multi_cells=False, auto_include_multi_cells=False):
962 """List of <cells> must be in row / col order."""
963 data = []
964 for row, col in cells:
965 try:
966
967 data_list = self.__cell_data[col][row]
968 except KeyError:
969 continue
970
971 if len(data_list) == 1:
972 data.append(data_list[0])
973 continue
974
975 if exclude_multi_cells:
976 gmDispatcher.send(signal = u'statustext', msg = _('Excluding multi-result field from further processing.'))
977 continue
978
979 if auto_include_multi_cells:
980 data.extend(data_list)
981 continue
982
983 data_to_include = self.__get_choices_from_multi_cell(cell_data = data_list)
984 if data_to_include is None:
985 continue
986 data.extend(data_to_include)
987
988 return data
989
991 data = gmListWidgets.get_choices_from_list (
992 parent = self,
993 msg = _(
994 'Your selection includes a field with multiple results.\n'
995 '\n'
996 'Please select the individual results you want to work on:'
997 ),
998 caption = _('Selecting test results'),
999 choices = [ [d['clin_when'], u'%s: %s' % (d['abbrev_tt'], d['name_tt']), d['unified_val']] for d in cell_data ],
1000 columns = [ _('Date / Time'), _('Test'), _('Result') ],
1001 data = cell_data,
1002 single_selection = single_selection
1003 )
1004 return data
1005
1006
1007
1009
1010 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
1011 self.GetGridRowLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_row_labels)
1012
1013
1014
1015 self.Bind(wx.EVT_SIZE, self.__resize_corner_window)
1016
1017
1018 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
1019
1021 col = evt.GetCol()
1022 row = evt.GetRow()
1023
1024
1025 try:
1026 self.__cell_data[col][row]
1027 except KeyError:
1028
1029
1030 return
1031
1032 if len(self.__cell_data[col][row]) > 1:
1033 data = self.__get_choices_from_multi_cell(cell_data = self.__cell_data[col][row], single_selection = True)
1034 else:
1035 data = self.__cell_data[col][row][0]
1036
1037 if data is None:
1038 return
1039
1040 edit_measurement(parent = self, measurement = data, single_entry = True)
1041
1042
1043
1044
1045
1046
1047
1049
1050
1051
1052 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
1053
1054 row = self.YToRow(y)
1055
1056 if self.__prev_label_row == row:
1057 return
1058
1059 self.__prev_label_row == row
1060
1061 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
1062
1063
1064
1065
1066
1067
1068
1069
1071 """Calculate where the mouse is and set the tooltip dynamically."""
1072
1073
1074
1075 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089 row, col = self.XYToCell(x, y)
1090
1091 if (row == self.__prev_row) and (col == self.__prev_col):
1092 return
1093
1094 self.__prev_row = row
1095 self.__prev_col = col
1096
1097 evt.GetEventObject().SetToolTipString(self.get_cell_tooltip(col=col, row=row))
1098
1099
1100
1104
1105 patient = property(lambda x:x, _set_patient)
1106
1110
1111 panel_to_show = property(lambda x:x, _set_panel_to_show)
1112
1116
1117 show_by_panel = property(lambda x:x, _set_show_by_panel)
1118
1119 from Gnumed.wxGladeWidgets import wxgMeasurementsPnl
1120
1121 -class cMeasurementsPnl(wxgMeasurementsPnl.wxgMeasurementsPnl, gmRegetMixin.cRegetOnPaintMixin):
1122 """Panel holding a grid with lab data. Used as notebook page."""
1123
1130
1131
1132
1134 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
1135 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
1136 gmDispatcher.connect(signal = u'test_result_mod_db', receiver = self._schedule_data_reget)
1137 gmDispatcher.connect(signal = u'reviewed_test_results_mod_db', receiver = self._schedule_data_reget)
1138
1140 wx.CallAfter(self.__on_post_patient_selection)
1141
1143 self._schedule_data_reget()
1144
1146 wx.CallAfter(self.__on_pre_patient_selection)
1147
1149 self.data_grid.patient = None
1150 self.panel_data_grid.patient = None
1151
1154
1157
1163
1166
1169
1172
1175
1177 wx.CallAfter(self.__on_panel_selected, panel=panel)
1178
1180 if panel is None:
1181 self._TCTRL_panel_comment.SetValue(u'')
1182 self.panel_data_grid.panel_to_show = None
1183 self.panel_data_grid.Hide()
1184 else:
1185 pnl = self._PRW_panel.GetData(as_instance = True)
1186 self._TCTRL_panel_comment.SetValue(gmTools.coalesce (
1187 pnl['comment'],
1188 u''
1189 ))
1190 self.panel_data_grid.panel_to_show = pnl
1191 self.panel_data_grid.Show()
1192 self.Layout()
1193
1194
1196 wx.CallAfter(self.__on_panel_selection_modified)
1197
1199 self._TCTRL_panel_comment.SetValue(u'')
1200 if self._PRW_panel.GetValue().strip() == u'':
1201 self.panel_data_grid.panel_to_show = None
1202 self.panel_data_grid.Hide()
1203 self.Layout()
1204
1205
1206
1208 self.__action_button_popup = wx.Menu(title = _('Perform on selected results:'))
1209
1210 menu_id = wx.NewId()
1211 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Review and &sign')))
1212 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_sign_current_selection)
1213
1214 menu_id = wx.NewId()
1215 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Plot')))
1216 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_plot_current_selection)
1217
1218 menu_id = wx.NewId()
1219 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Export to &file')))
1220
1221 self.__action_button_popup.Enable(id = menu_id, enable = False)
1222
1223 menu_id = wx.NewId()
1224 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Export to &clipboard')))
1225
1226 self.__action_button_popup.Enable(id = menu_id, enable = False)
1227
1228 menu_id = wx.NewId()
1229 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('&Delete')))
1230 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_delete_current_selection)
1231
1232
1233
1234
1235 self._PRW_panel.add_callback_on_selection(callback = self._on_panel_selected)
1236 self._PRW_panel.add_callback_on_modified(callback = self._on_panel_selection_modified)
1237
1238 self.panel_data_grid.show_by_panel = True
1239 self.panel_data_grid.panel_to_show = None
1240 self.panel_data_grid.Hide()
1241 self.Layout()
1242
1243 self._PRW_panel.SetFocus()
1244
1245
1246
1257
1258
1259
1260
1261 from Gnumed.wxGladeWidgets import wxgMeasurementsReviewDlg
1262
1264
1266
1267 try:
1268 tests = kwargs['tests']
1269 del kwargs['tests']
1270 test_count = len(tests)
1271 try: del kwargs['test_count']
1272 except KeyError: pass
1273 except KeyError:
1274 tests = None
1275 test_count = kwargs['test_count']
1276 del kwargs['test_count']
1277
1278 wxgMeasurementsReviewDlg.wxgMeasurementsReviewDlg.__init__(self, *args, **kwargs)
1279
1280 if tests is None:
1281 msg = _('%s results selected. Too many to list individually.') % test_count
1282 else:
1283 msg = ' // '.join (
1284 [ u'%s: %s %s (%s)' % (
1285 t['unified_abbrev'],
1286 t['unified_val'],
1287 t['val_unit'],
1288 t['clin_when'].strftime('%x').decode(gmI18N.get_encoding())
1289 ) for t in tests
1290 ]
1291 )
1292
1293 self._LBL_tests.SetLabel(msg)
1294
1295 if test_count == 1:
1296 self._TCTRL_comment.Enable(True)
1297 self._TCTRL_comment.SetValue(gmTools.coalesce(tests[0]['review_comment'], u''))
1298 if tests[0]['you_are_responsible']:
1299 self._CHBOX_responsible.Enable(False)
1300
1301 self.Fit()
1302
1303
1304
1310
1311 from Gnumed.wxGladeWidgets import wxgMeasurementEditAreaPnl
1312
1313 -class cMeasurementEditAreaPnl(wxgMeasurementEditAreaPnl.wxgMeasurementEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
1314 """This edit area saves *new* measurements into the active patient only."""
1315
1332
1333
1334
1336 self._PRW_test.SetText(u'', None, True)
1337 self.__refresh_loinc_info()
1338 self.__refresh_previous_value()
1339 self.__update_units_context()
1340 self._TCTRL_result.SetValue(u'')
1341 self._PRW_units.SetText(u'', None, True)
1342 self._PRW_abnormality_indicator.SetText(u'', None, True)
1343 if self.__default_date is None:
1344 self._DPRW_evaluated.SetData(data = pyDT.datetime.now(tz = gmDateTime.gmCurrentLocalTimezone))
1345 else:
1346 self._DPRW_evaluated.SetData(data = None)
1347 self._TCTRL_note_test_org.SetValue(u'')
1348 self._PRW_intended_reviewer.SetData(gmStaff.gmCurrentProvider()['pk_staff'])
1349 self._PRW_problem.SetData()
1350 self._TCTRL_narrative.SetValue(u'')
1351 self._CHBOX_review.SetValue(False)
1352 self._CHBOX_abnormal.SetValue(False)
1353 self._CHBOX_relevant.SetValue(False)
1354 self._CHBOX_abnormal.Enable(False)
1355 self._CHBOX_relevant.Enable(False)
1356 self._TCTRL_review_comment.SetValue(u'')
1357 self._TCTRL_normal_min.SetValue(u'')
1358 self._TCTRL_normal_max.SetValue(u'')
1359 self._TCTRL_normal_range.SetValue(u'')
1360 self._TCTRL_target_min.SetValue(u'')
1361 self._TCTRL_target_max.SetValue(u'')
1362 self._TCTRL_target_range.SetValue(u'')
1363 self._TCTRL_norm_ref_group.SetValue(u'')
1364
1365 self._PRW_test.SetFocus()
1366
1368 self._PRW_test.SetData(data = self.data['pk_test_type'])
1369 self.__refresh_loinc_info()
1370 self.__refresh_previous_value()
1371 self.__update_units_context()
1372 self._TCTRL_result.SetValue(self.data['unified_val'])
1373 self._PRW_units.SetText(self.data['val_unit'], self.data['val_unit'], True)
1374 self._PRW_abnormality_indicator.SetText (
1375 gmTools.coalesce(self.data['abnormality_indicator'], u''),
1376 gmTools.coalesce(self.data['abnormality_indicator'], u''),
1377 True
1378 )
1379 self._DPRW_evaluated.SetData(data = self.data['clin_when'])
1380 self._TCTRL_note_test_org.SetValue(gmTools.coalesce(self.data['note_test_org'], u''))
1381 self._PRW_intended_reviewer.SetData(self.data['pk_intended_reviewer'])
1382 self._PRW_problem.SetData(self.data['pk_episode'])
1383 self._TCTRL_narrative.SetValue(gmTools.coalesce(self.data['comment'], u''))
1384 self._CHBOX_review.SetValue(False)
1385 self._CHBOX_abnormal.SetValue(gmTools.coalesce(self.data['is_technically_abnormal'], False))
1386 self._CHBOX_relevant.SetValue(gmTools.coalesce(self.data['is_clinically_relevant'], False))
1387 self._CHBOX_abnormal.Enable(False)
1388 self._CHBOX_relevant.Enable(False)
1389 self._TCTRL_review_comment.SetValue(gmTools.coalesce(self.data['review_comment'], u''))
1390 self._TCTRL_normal_min.SetValue(unicode(gmTools.coalesce(self.data['val_normal_min'], u'')))
1391 self._TCTRL_normal_max.SetValue(unicode(gmTools.coalesce(self.data['val_normal_max'], u'')))
1392 self._TCTRL_normal_range.SetValue(gmTools.coalesce(self.data['val_normal_range'], u''))
1393 self._TCTRL_target_min.SetValue(unicode(gmTools.coalesce(self.data['val_target_min'], u'')))
1394 self._TCTRL_target_max.SetValue(unicode(gmTools.coalesce(self.data['val_target_max'], u'')))
1395 self._TCTRL_target_range.SetValue(gmTools.coalesce(self.data['val_target_range'], u''))
1396 self._TCTRL_norm_ref_group.SetValue(gmTools.coalesce(self.data['norm_ref_group'], u''))
1397
1398 self._TCTRL_result.SetFocus()
1399
1401 self._refresh_from_existing()
1402
1403 self._PRW_test.SetText(u'', None, True)
1404 self.__refresh_loinc_info()
1405 self.__refresh_previous_value()
1406 self.__update_units_context()
1407 self._TCTRL_result.SetValue(u'')
1408 self._PRW_units.SetText(u'', None, True)
1409 self._PRW_abnormality_indicator.SetText(u'', None, True)
1410
1411 self._TCTRL_note_test_org.SetValue(u'')
1412 self._TCTRL_narrative.SetValue(u'')
1413 self._CHBOX_review.SetValue(False)
1414 self._CHBOX_abnormal.SetValue(False)
1415 self._CHBOX_relevant.SetValue(False)
1416 self._CHBOX_abnormal.Enable(False)
1417 self._CHBOX_relevant.Enable(False)
1418 self._TCTRL_review_comment.SetValue(u'')
1419 self._TCTRL_normal_min.SetValue(u'')
1420 self._TCTRL_normal_max.SetValue(u'')
1421 self._TCTRL_normal_range.SetValue(u'')
1422 self._TCTRL_target_min.SetValue(u'')
1423 self._TCTRL_target_max.SetValue(u'')
1424 self._TCTRL_target_range.SetValue(u'')
1425 self._TCTRL_norm_ref_group.SetValue(u'')
1426
1427 self._PRW_test.SetFocus()
1428
1430
1431 validity = True
1432
1433 if not self._DPRW_evaluated.is_valid_timestamp():
1434 self._DPRW_evaluated.display_as_valid(False)
1435 validity = False
1436 else:
1437 self._DPRW_evaluated.display_as_valid(True)
1438
1439 if self._TCTRL_result.GetValue().strip() == u'':
1440 validity = False
1441 self.display_ctrl_as_valid(self._TCTRL_result, False)
1442 else:
1443 self.display_ctrl_as_valid(self._TCTRL_result, True)
1444
1445 if self._PRW_problem.GetValue().strip() == u'':
1446 self._PRW_problem.display_as_valid(False)
1447 validity = False
1448 else:
1449 self._PRW_problem.display_as_valid(True)
1450
1451 if self._PRW_test.GetValue().strip() == u'':
1452 self._PRW_test.display_as_valid(False)
1453 validity = False
1454 else:
1455 self._PRW_test.display_as_valid(True)
1456
1457 if self._PRW_intended_reviewer.GetData() is None:
1458 self._PRW_intended_reviewer.display_as_valid(False)
1459 validity = False
1460 else:
1461 self._PRW_intended_reviewer.display_as_valid(True)
1462
1463 if self._PRW_units.GetValue().strip() == u'':
1464 self._PRW_units.display_as_valid(False)
1465 validity = False
1466 else:
1467 self._PRW_units.display_as_valid(True)
1468
1469 ctrls = [self._TCTRL_normal_min, self._TCTRL_normal_max, self._TCTRL_target_min, self._TCTRL_target_max]
1470 for widget in ctrls:
1471 val = widget.GetValue().strip()
1472 if val == u'':
1473 continue
1474 try:
1475 decimal.Decimal(val.replace(',', u'.', 1))
1476 self.display_ctrl_as_valid(widget, True)
1477 except:
1478 validity = False
1479 self.display_ctrl_as_valid(widget, False)
1480
1481 if validity is False:
1482 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save result. Invalid or missing essential input.'))
1483
1484 return validity
1485
1487
1488 emr = gmPerson.gmCurrentPatient().get_emr()
1489
1490 success, result = gmTools.input2decimal(self._TCTRL_result.GetValue())
1491 if success:
1492 v_num = result
1493 v_al = None
1494 else:
1495 v_al = self._TCTRL_result.GetValue().strip()
1496 v_num = None
1497
1498 pk_type = self._PRW_test.GetData()
1499 if pk_type is None:
1500 tt = gmPathLab.create_measurement_type (
1501 lab = None,
1502 abbrev = self._PRW_test.GetValue().strip(),
1503 name = self._PRW_test.GetValue().strip(),
1504 unit = gmTools.coalesce(self._PRW_units.GetData(), self._PRW_units.GetValue()).strip()
1505 )
1506 pk_type = tt['pk_test_type']
1507
1508 tr = emr.add_test_result (
1509 episode = self._PRW_problem.GetData(can_create=True, is_open=False),
1510 type = pk_type,
1511 intended_reviewer = self._PRW_intended_reviewer.GetData(),
1512 val_num = v_num,
1513 val_alpha = v_al,
1514 unit = self._PRW_units.GetValue()
1515 )
1516
1517 tr['clin_when'] = self._DPRW_evaluated.GetData().get_pydt()
1518
1519 ctrls = [
1520 ('abnormality_indicator', self._PRW_abnormality_indicator),
1521 ('note_test_org', self._TCTRL_note_test_org),
1522 ('comment', self._TCTRL_narrative),
1523 ('val_normal_range', self._TCTRL_normal_range),
1524 ('val_target_range', self._TCTRL_target_range),
1525 ('norm_ref_group', self._TCTRL_norm_ref_group)
1526 ]
1527 for field, widget in ctrls:
1528 tr[field] = widget.GetValue().strip()
1529
1530 ctrls = [
1531 ('val_normal_min', self._TCTRL_normal_min),
1532 ('val_normal_max', self._TCTRL_normal_max),
1533 ('val_target_min', self._TCTRL_target_min),
1534 ('val_target_max', self._TCTRL_target_max)
1535 ]
1536 for field, widget in ctrls:
1537 val = widget.GetValue().strip()
1538 if val == u'':
1539 tr[field] = None
1540 else:
1541 tr[field] = decimal.Decimal(val.replace(',', u'.', 1))
1542
1543 tr.save_payload()
1544
1545 if self._CHBOX_review.GetValue() is True:
1546 tr.set_review (
1547 technically_abnormal = self._CHBOX_abnormal.GetValue(),
1548 clinically_relevant = self._CHBOX_relevant.GetValue(),
1549 comment = gmTools.none_if(self._TCTRL_review_comment.GetValue().strip(), u''),
1550 make_me_responsible = False
1551 )
1552
1553 self.data = tr
1554
1555 wx.CallAfter (
1556 plot_adjacent_measurements,
1557 test = self.data,
1558 plot_singular_result = False,
1559 use_default_template = True
1560 )
1561
1562 return True
1563
1565
1566 success, result = gmTools.input2decimal(self._TCTRL_result.GetValue())
1567 if success:
1568 v_num = result
1569 v_al = None
1570 else:
1571 v_num = None
1572 v_al = self._TCTRL_result.GetValue().strip()
1573
1574 pk_type = self._PRW_test.GetData()
1575 if pk_type is None:
1576 tt = gmPathLab.create_measurement_type (
1577 lab = None,
1578 abbrev = self._PRW_test.GetValue().strip(),
1579 name = self._PRW_test.GetValue().strip(),
1580 unit = gmTools.none_if(self._PRW_units.GetValue().strip(), u'')
1581 )
1582 pk_type = tt['pk_test_type']
1583
1584 tr = self.data
1585
1586 tr['pk_episode'] = self._PRW_problem.GetData(can_create=True, is_open=False)
1587 tr['pk_test_type'] = pk_type
1588 tr['pk_intended_reviewer'] = self._PRW_intended_reviewer.GetData()
1589 tr['val_num'] = v_num
1590 tr['val_alpha'] = v_al
1591 tr['val_unit'] = gmTools.coalesce(self._PRW_units.GetData(), self._PRW_units.GetValue()).strip()
1592 tr['clin_when'] = self._DPRW_evaluated.GetData().get_pydt()
1593
1594 ctrls = [
1595 ('abnormality_indicator', self._PRW_abnormality_indicator),
1596 ('note_test_org', self._TCTRL_note_test_org),
1597 ('comment', self._TCTRL_narrative),
1598 ('val_normal_range', self._TCTRL_normal_range),
1599 ('val_target_range', self._TCTRL_target_range),
1600 ('norm_ref_group', self._TCTRL_norm_ref_group)
1601 ]
1602 for field, widget in ctrls:
1603 tr[field] = widget.GetValue().strip()
1604
1605 ctrls = [
1606 ('val_normal_min', self._TCTRL_normal_min),
1607 ('val_normal_max', self._TCTRL_normal_max),
1608 ('val_target_min', self._TCTRL_target_min),
1609 ('val_target_max', self._TCTRL_target_max)
1610 ]
1611 for field, widget in ctrls:
1612 val = widget.GetValue().strip()
1613 if val == u'':
1614 tr[field] = None
1615 else:
1616 tr[field] = decimal.Decimal(val.replace(',', u'.', 1))
1617
1618 tr.save_payload()
1619
1620 if self._CHBOX_review.GetValue() is True:
1621 tr.set_review (
1622 technically_abnormal = self._CHBOX_abnormal.GetValue(),
1623 clinically_relevant = self._CHBOX_relevant.GetValue(),
1624 comment = gmTools.none_if(self._TCTRL_review_comment.GetValue().strip(), u''),
1625 make_me_responsible = False
1626 )
1627
1628 wx.CallAfter (
1629 plot_adjacent_measurements,
1630 test = self.data,
1631 plot_singular_result = False,
1632 use_default_template = True
1633 )
1634
1635 return True
1636
1637
1638
1642
1644 self.__refresh_loinc_info()
1645 self.__refresh_previous_value()
1646 self.__update_units_context()
1647
1649
1650 if not self._CHBOX_review.GetValue():
1651 self._CHBOX_abnormal.SetValue(self._PRW_abnormality_indicator.GetValue().strip() != u'')
1652
1654 self._CHBOX_abnormal.Enable(self._CHBOX_review.GetValue())
1655 self._CHBOX_relevant.Enable(self._CHBOX_review.GetValue())
1656 self._TCTRL_review_comment.Enable(self._CHBOX_review.GetValue())
1657
1674
1675
1676
1678
1679 self._PRW_units.unset_context(context = u'loinc')
1680
1681 tt = self._PRW_test.GetData(as_instance = True)
1682
1683 if tt is None:
1684 self._PRW_units.unset_context(context = u'pk_type')
1685 if self._PRW_test.GetValue().strip() == u'':
1686 self._PRW_units.unset_context(context = u'test_name')
1687 else:
1688 self._PRW_units.set_context(context = u'test_name', val = self._PRW_test.GetValue().strip())
1689 return
1690
1691 self._PRW_units.set_context(context = u'pk_type', val = tt['pk_test_type'])
1692 self._PRW_units.set_context(context = u'test_name', val = tt['name'])
1693
1694 if tt['loinc'] is None:
1695 return
1696
1697 self._PRW_units.set_context(context = u'loinc', val = tt['loinc'])
1698
1700
1701 self._TCTRL_loinc.SetValue(u'')
1702
1703 if self._PRW_test.GetData() is None:
1704 return
1705
1706 tt = self._PRW_test.GetData(as_instance = True)
1707
1708 if tt['loinc'] is None:
1709 return
1710
1711 info = gmLOINC.loinc2term(loinc = tt['loinc'])
1712 if len(info) == 0:
1713 self._TCTRL_loinc.SetValue(u'')
1714 return
1715
1716 self._TCTRL_loinc.SetValue(u'%s: %s' % (tt['loinc'], info[0]))
1717
1740
1741
1742
1743
1745
1746 if parent is None:
1747 parent = wx.GetApp().GetTopWindow()
1748
1749 if msg is None:
1750 msg = _('Pick the relevant measurement types.')
1751
1752 if right_column is None:
1753 right_columns = [_('Picked')]
1754 else:
1755 right_columns = [right_column]
1756
1757 picker = gmListWidgets.cItemPickerDlg(parent, -1, msg = msg)
1758 picker.set_columns(columns = [_('Known measurement types')], columns_right = right_columns)
1759 types = gmPathLab.get_measurement_types(order_by = 'unified_abbrev')
1760 picker.set_choices (
1761 choices = [
1762 u'%s: %s%s' % (
1763 t['unified_abbrev'],
1764 t['unified_name'],
1765 gmTools.coalesce(t['name_org'], u'', u' (%s)')
1766 )
1767 for t in types
1768 ],
1769 data = types
1770 )
1771 if picks is not None:
1772 picker.set_picks (
1773 picks = [
1774 u'%s: %s%s' % (
1775 p['unified_abbrev'],
1776 p['unified_name'],
1777 gmTools.coalesce(p['name_org'], u'', u' (%s)')
1778 )
1779 for p in picks
1780 ],
1781 data = picks
1782 )
1783 result = picker.ShowModal()
1784
1785 if result == wx.ID_CANCEL:
1786 picker.Destroy()
1787 return None
1788
1789 picks = picker.picks
1790 picker.Destroy()
1791 return picks
1792
1793
1816
1817 def delete(measurement_type):
1818 if measurement_type.in_use:
1819 gmDispatcher.send (
1820 signal = 'statustext',
1821 beep = True,
1822 msg = _('Cannot delete measurement type [%s (%s)] because it is in use.') % (measurement_type['name'], measurement_type['abbrev'])
1823 )
1824 return False
1825 gmPathLab.delete_measurement_type(measurement_type = measurement_type['pk_test_type'])
1826 return True
1827
1828 def get_tooltip(test_type):
1829 return test_type.format()
1830
1831 def refresh(lctrl):
1832 mtypes = gmPathLab.get_measurement_types(order_by = 'name, abbrev')
1833 items = [ [
1834 m['abbrev'],
1835 m['name'],
1836 gmTools.coalesce(m['conversion_unit'], u''),
1837 gmTools.coalesce(m['loinc'], u''),
1838 gmTools.coalesce(m['comment_type'], u''),
1839 gmTools.coalesce(m['name_org'], u'?'),
1840 gmTools.coalesce(m['comment_org'], u''),
1841 m['pk_test_type']
1842 ] for m in mtypes ]
1843 lctrl.set_string_items(items)
1844 lctrl.set_data(mtypes)
1845
1846 msg = _(
1847 '\n'
1848 'These are the measurement types currently defined in GNUmed.\n'
1849 '\n'
1850 )
1851
1852 gmListWidgets.get_choices_from_list (
1853 parent = parent,
1854 msg = msg,
1855 caption = _('Showing measurement types.'),
1856 columns = [ _('Abbrev'), _('Name'), _('Unit'), _('LOINC'), _('Comment'), _('Org'), _('Comment'), u'#' ],
1857 single_selection = True,
1858 refresh_callback = refresh,
1859 edit_callback = edit,
1860 new_callback = edit,
1861 delete_callback = delete,
1862 list_tooltip_callback = get_tooltip
1863 )
1864
1866
1868
1869 query = u"""
1870 SELECT DISTINCT ON (field_label)
1871 pk_test_type AS data,
1872 name
1873 || ' ('
1874 || coalesce (
1875 (SELECT unit || ' @ ' || organization FROM clin.v_test_orgs c_vto WHERE c_vto.pk_test_org = c_vtt.pk_test_org),
1876 '%(in_house)s'
1877 )
1878 || ')'
1879 AS field_label,
1880 name
1881 || ' ('
1882 || abbrev || ', '
1883 || coalesce(abbrev_meta || ': ' || name_meta || ', ', '')
1884 || coalesce (
1885 (SELECT unit || ' @ ' || organization FROM clin.v_test_orgs c_vto WHERE c_vto.pk_test_org = c_vtt.pk_test_org),
1886 '%(in_house)s'
1887 )
1888 || ')'
1889 AS list_label
1890 FROM
1891 clin.v_test_types c_vtt
1892 WHERE
1893 abbrev_meta %%(fragment_condition)s
1894 OR
1895 name_meta %%(fragment_condition)s
1896 OR
1897 abbrev %%(fragment_condition)s
1898 OR
1899 name %%(fragment_condition)s
1900 ORDER BY field_label
1901 LIMIT 50""" % {'in_house': _('generic / in house lab')}
1902
1903 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1904 mp.setThresholds(1, 2, 4)
1905 mp.word_separators = '[ \t:@]+'
1906 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1907 self.matcher = mp
1908 self.SetToolTipString(_('Select the type of measurement.'))
1909 self.selection_only = False
1910
1916
1917 from Gnumed.wxGladeWidgets import wxgMeasurementTypeEAPnl
1918
1919 -class cMeasurementTypeEAPnl(wxgMeasurementTypeEAPnl.wxgMeasurementTypeEAPnl, gmEditArea.cGenericEditAreaMixin):
1920
1937
1938
1940
1941
1942 query = u"""
1943 select distinct on (name)
1944 pk,
1945 name
1946 from clin.test_type
1947 where
1948 name %(fragment_condition)s
1949 order by name
1950 limit 50"""
1951 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1952 mp.setThresholds(1, 2, 4)
1953 self._PRW_name.matcher = mp
1954 self._PRW_name.selection_only = False
1955 self._PRW_name.add_callback_on_lose_focus(callback = self._on_name_lost_focus)
1956
1957
1958 query = u"""
1959 select distinct on (abbrev)
1960 pk,
1961 abbrev
1962 from clin.test_type
1963 where
1964 abbrev %(fragment_condition)s
1965 order by abbrev
1966 limit 50"""
1967 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1968 mp.setThresholds(1, 2, 3)
1969 self._PRW_abbrev.matcher = mp
1970 self._PRW_abbrev.selection_only = False
1971
1972
1973 self._PRW_conversion_unit.selection_only = False
1974
1975
1976 query = u"""
1977 SELECT DISTINCT ON (list_label)
1978 data,
1979 field_label,
1980 list_label
1981 FROM ((
1982
1983 SELECT
1984 loinc AS data,
1985 loinc AS field_label,
1986 (loinc || ': ' || abbrev || ' (' || name || ')') AS list_label
1987 FROM clin.test_type
1988 WHERE loinc %(fragment_condition)s
1989 LIMIT 50
1990
1991 ) UNION ALL (
1992
1993 SELECT
1994 code AS data,
1995 code AS field_label,
1996 (code || ': ' || term) AS list_label
1997 FROM ref.v_coded_terms
1998 WHERE
1999 coding_system = 'LOINC'
2000 AND
2001 lang = i18n.get_curr_lang()
2002 AND
2003 (code %(fragment_condition)s
2004 OR
2005 term %(fragment_condition)s)
2006 LIMIT 50
2007
2008 ) UNION ALL (
2009
2010 SELECT
2011 code AS data,
2012 code AS field_label,
2013 (code || ': ' || term) AS list_label
2014 FROM ref.v_coded_terms
2015 WHERE
2016 coding_system = 'LOINC'
2017 AND
2018 lang = 'en_EN'
2019 AND
2020 (code %(fragment_condition)s
2021 OR
2022 term %(fragment_condition)s)
2023 LIMIT 50
2024
2025 ) UNION ALL (
2026
2027 SELECT
2028 code AS data,
2029 code AS field_label,
2030 (code || ': ' || term) AS list_label
2031 FROM ref.v_coded_terms
2032 WHERE
2033 coding_system = 'LOINC'
2034 AND
2035 (code %(fragment_condition)s
2036 OR
2037 term %(fragment_condition)s)
2038 LIMIT 50
2039 )
2040 ) AS all_known_loinc
2041
2042 ORDER BY list_label
2043 LIMIT 50"""
2044 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
2045 mp.setThresholds(1, 2, 4)
2046 self._PRW_loinc.matcher = mp
2047 self._PRW_loinc.selection_only = False
2048 self._PRW_loinc.add_callback_on_lose_focus(callback = self._on_loinc_lost_focus)
2049
2051
2052 test = self._PRW_name.GetValue().strip()
2053
2054 if test == u'':
2055 self._PRW_conversion_unit.unset_context(context = u'test_name')
2056 return
2057
2058 self._PRW_conversion_unit.set_context(context = u'test_name', val = test)
2059
2061 loinc = self._PRW_loinc.GetData()
2062
2063 if loinc is None:
2064 self._TCTRL_loinc_info.SetValue(u'')
2065 self._PRW_conversion_unit.unset_context(context = u'loinc')
2066 return
2067
2068 self._PRW_conversion_unit.set_context(context = u'loinc', val = loinc)
2069
2070 info = gmLOINC.loinc2term(loinc = loinc)
2071 if len(info) == 0:
2072 self._TCTRL_loinc_info.SetValue(u'')
2073 return
2074
2075 self._TCTRL_loinc_info.SetValue(info[0])
2076
2077
2078
2080
2081 has_errors = False
2082 for field in [self._PRW_name, self._PRW_abbrev, self._PRW_conversion_unit]:
2083 if field.GetValue().strip() in [u'', None]:
2084 has_errors = True
2085 field.display_as_valid(valid = False)
2086 else:
2087 field.display_as_valid(valid = True)
2088 field.Refresh()
2089
2090 return (not has_errors)
2091
2093
2094 pk_org = self._PRW_test_org.GetData()
2095 if pk_org is None:
2096 pk_org = gmPathLab.create_test_org (
2097 name = gmTools.none_if(self._PRW_test_org.GetValue().strip(), u''),
2098 comment = gmTools.none_if(self._TCTRL_comment_org.GetValue().strip(), u'')
2099 )['pk_test_org']
2100
2101 tt = gmPathLab.create_measurement_type (
2102 lab = pk_org,
2103 abbrev = self._PRW_abbrev.GetValue().strip(),
2104 name = self._PRW_name.GetValue().strip(),
2105 unit = gmTools.coalesce (
2106 self._PRW_conversion_unit.GetData(),
2107 self._PRW_conversion_unit.GetValue()
2108 ).strip()
2109 )
2110 if self._PRW_loinc.GetData() is not None:
2111 tt['loinc'] = gmTools.none_if(self._PRW_loinc.GetData().strip(), u'')
2112 else:
2113 tt['loinc'] = gmTools.none_if(self._PRW_loinc.GetValue().strip(), u'')
2114 tt['comment_type'] = gmTools.none_if(self._TCTRL_comment_type.GetValue().strip(), u'')
2115 tt['pk_meta_test_type'] = self._PRW_meta_type.GetData()
2116
2117 tt.save()
2118
2119 self.data = tt
2120
2121 return True
2122
2150
2152 self._PRW_name.SetText(u'', None, True)
2153 self._on_name_lost_focus()
2154 self._PRW_abbrev.SetText(u'', None, True)
2155 self._PRW_conversion_unit.SetText(u'', None, True)
2156 self._PRW_loinc.SetText(u'', None, True)
2157 self._on_loinc_lost_focus()
2158 self._TCTRL_comment_type.SetValue(u'')
2159 self._PRW_test_org.SetText(u'', None, True)
2160 self._TCTRL_comment_org.SetValue(u'')
2161 self._PRW_meta_type.SetText(u'', None, True)
2162
2163 self._PRW_name.SetFocus()
2164
2166 self._PRW_name.SetText(self.data['name'], self.data['name'], True)
2167 self._on_name_lost_focus()
2168 self._PRW_abbrev.SetText(self.data['abbrev'], self.data['abbrev'], True)
2169 self._PRW_conversion_unit.SetText (
2170 gmTools.coalesce(self.data['conversion_unit'], u''),
2171 self.data['conversion_unit'],
2172 True
2173 )
2174 self._PRW_loinc.SetText (
2175 gmTools.coalesce(self.data['loinc'], u''),
2176 self.data['loinc'],
2177 True
2178 )
2179 self._on_loinc_lost_focus()
2180 self._TCTRL_comment_type.SetValue(gmTools.coalesce(self.data['comment_type'], u''))
2181 self._PRW_test_org.SetText (
2182 gmTools.coalesce(self.data['pk_test_org'], u'', self.data['name_org']),
2183 self.data['pk_test_org'],
2184 True
2185 )
2186 self._TCTRL_comment_org.SetValue(gmTools.coalesce(self.data['comment_org'], u''))
2187 if self.data['pk_meta_test_type'] is None:
2188 self._PRW_meta_type.SetText(u'', None, True)
2189 else:
2190 self._PRW_meta_type.SetText(u'%s: %s' % (self.data['abbrev_meta'], self.data['name_meta']), self.data['pk_meta_test_type'], True)
2191
2192 self._PRW_name.SetFocus()
2193
2204
2205
2206 _SQL_units_from_test_results = u"""
2207 -- via clin.v_test_results.pk_type (for types already used in results)
2208 SELECT
2209 val_unit AS data,
2210 val_unit AS field_label,
2211 val_unit || ' (' || name_tt || ')' AS list_label,
2212 1 AS rank
2213 FROM
2214 clin.v_test_results
2215 WHERE
2216 (
2217 val_unit %(fragment_condition)s
2218 OR
2219 conversion_unit %(fragment_condition)s
2220 )
2221 %(ctxt_type_pk)s
2222 %(ctxt_test_name)s
2223 """
2224
2225 _SQL_units_from_test_types = u"""
2226 -- via clin.test_type (for types not yet used in results)
2227 SELECT
2228 conversion_unit AS data,
2229 conversion_unit AS field_label,
2230 conversion_unit || ' (' || name || ')' AS list_label,
2231 2 AS rank
2232 FROM
2233 clin.test_type
2234 WHERE
2235 conversion_unit %(fragment_condition)s
2236 %(ctxt_ctt)s
2237 """
2238
2239 _SQL_units_from_loinc_ipcc = u"""
2240 -- via ref.loinc.ipcc_units
2241 SELECT
2242 ipcc_units AS data,
2243 ipcc_units AS field_label,
2244 ipcc_units || ' (LOINC.ipcc: ' || term || ')' AS list_label,
2245 3 AS rank
2246 FROM
2247 ref.loinc
2248 WHERE
2249 ipcc_units %(fragment_condition)s
2250 %(ctxt_loinc)s
2251 %(ctxt_loinc_term)s
2252 """
2253
2254 _SQL_units_from_loinc_submitted = u"""
2255 -- via ref.loinc.submitted_units
2256 SELECT
2257 submitted_units AS data,
2258 submitted_units AS field_label,
2259 submitted_units || ' (LOINC.submitted:' || term || ')' AS list_label,
2260 3 AS rank
2261 FROM
2262 ref.loinc
2263 WHERE
2264 submitted_units %(fragment_condition)s
2265 %(ctxt_loinc)s
2266 %(ctxt_loinc_term)s
2267 """
2268
2269 _SQL_units_from_loinc_example = u"""
2270 -- via ref.loinc.example_units
2271 SELECT
2272 example_units AS data,
2273 example_units AS field_label,
2274 example_units || ' (LOINC.example: ' || term || ')' AS list_label,
2275 3 AS rank
2276 FROM
2277 ref.loinc
2278 WHERE
2279 example_units %(fragment_condition)s
2280 %(ctxt_loinc)s
2281 %(ctxt_loinc_term)s
2282 """
2283
2284 _SQL_units_from_atc = u"""
2285 -- via ref.atc.unit
2286 SELECT
2287 unit AS data,
2288 unit AS field_label,
2289 unit || ' (ATC: ' || term || ')' AS list_label,
2290 2 AS rank
2291 FROM
2292 ref.atc
2293 WHERE
2294 unit IS NOT NULL
2295 AND
2296 unit %(fragment_condition)s
2297 """
2298
2299 _SQL_units_from_consumable_substance = u"""
2300 -- via ref.consumable_substance.unit
2301 SELECT
2302 unit AS data,
2303 unit AS field_label,
2304 unit || ' (' || description || ')' AS list_label,
2305 2 AS rank
2306 FROM
2307 ref.consumable_substance
2308 WHERE
2309 unit %(fragment_condition)s
2310 %(ctxt_substance)s
2311 """
2312
2313
2315
2317
2318 query = u"""
2319 SELECT DISTINCT ON (data)
2320 data,
2321 field_label,
2322 list_label
2323 FROM (
2324
2325 SELECT
2326 data,
2327 field_label,
2328 list_label,
2329 rank
2330 FROM (
2331 (%s) UNION ALL
2332 (%s) UNION ALL
2333 (%s) UNION ALL
2334 (%s) UNION ALL
2335 (%s) UNION ALL
2336 (%s) UNION ALL
2337 (%s)
2338 ) AS all_matching_units
2339 WHERE data IS NOT NULL
2340 ORDER BY rank
2341
2342 ) AS ranked_matching_units
2343 LIMIT 50""" % (
2344 _SQL_units_from_test_results,
2345 _SQL_units_from_test_types,
2346 _SQL_units_from_loinc_ipcc,
2347 _SQL_units_from_loinc_submitted,
2348 _SQL_units_from_loinc_example,
2349 _SQL_units_from_atc,
2350 _SQL_units_from_consumable_substance
2351 )
2352
2353 ctxt = {
2354 'ctxt_type_pk': {
2355 'where_part': u'AND pk_test_type = %(pk_type)s',
2356 'placeholder': u'pk_type'
2357 },
2358 'ctxt_test_name': {
2359 'where_part': u'AND %(test_name)s IN (name_tt, name_meta, abbrev_meta)',
2360 'placeholder': u'test_name'
2361 },
2362 'ctxt_ctt': {
2363 'where_part': u'AND %(test_name)s IN (name, abbrev)',
2364 'placeholder': u'test_name'
2365 },
2366 'ctxt_loinc': {
2367 'where_part': u'AND code = %(loinc)s',
2368 'placeholder': u'loinc'
2369 },
2370 'ctxt_loinc_term': {
2371 'where_part': u'AND term ~* %(test_name)s',
2372 'placeholder': u'test_name'
2373 },
2374 'ctxt_substance': {
2375 'where_part': u'AND description ~* %(substance)s',
2376 'placeholder': u'substance'
2377 }
2378 }
2379
2380 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query, context = ctxt)
2381 mp.setThresholds(1, 2, 4)
2382
2383 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
2384 self.matcher = mp
2385 self.SetToolTipString(_('Select the desired unit for the amount or measurement.'))
2386 self.selection_only = False
2387 self.phrase_separators = u'[;|]+'
2388
2389
2390
2392
2394
2395 query = u"""
2396 select distinct abnormality_indicator,
2397 abnormality_indicator, abnormality_indicator
2398 from clin.v_test_results
2399 where
2400 abnormality_indicator %(fragment_condition)s
2401 order by abnormality_indicator
2402 limit 25"""
2403
2404 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
2405 mp.setThresholds(1, 1, 2)
2406 mp.ignored_chars = "[.'\\\[\]#$%_]+" + '"'
2407 mp.word_separators = '[ \t&:]+'
2408 gmPhraseWheel.cPhraseWheel.__init__ (
2409 self,
2410 *args,
2411 **kwargs
2412 )
2413 self.matcher = mp
2414 self.SetToolTipString(_('Select an indicator for the level of abnormality.'))
2415 self.selection_only = False
2416
2417
2418
2419
2431
2433
2434 if parent is None:
2435 parent = wx.GetApp().GetTopWindow()
2436
2437
2438 def edit(org=None):
2439 return edit_measurement_org(parent = parent, org = org)
2440
2441 def refresh(lctrl):
2442 orgs = gmPathLab.get_test_orgs()
2443 lctrl.set_string_items ([
2444 (o['unit'], o['organization'], gmTools.coalesce(o['test_org_contact'], u''), gmTools.coalesce(o['comment'], u''), o['pk_test_org'])
2445 for o in orgs
2446 ])
2447 lctrl.set_data(orgs)
2448
2449 def delete(test_org):
2450 gmPathLab.delete_test_org(test_org = test_org['pk_test_org'])
2451 return True
2452
2453 gmListWidgets.get_choices_from_list (
2454 parent = parent,
2455 msg = _('\nThese are the diagnostic orgs (path labs etc) currently defined in GNUmed.\n\n'),
2456 caption = _('Showing diagnostic orgs.'),
2457 columns = [_('Name'), _('Organization'), _('Contact'), _('Comment'), u'#'],
2458 single_selection = True,
2459 refresh_callback = refresh,
2460 edit_callback = edit,
2461 new_callback = edit,
2462 delete_callback = delete
2463 )
2464
2465
2466 from Gnumed.wxGladeWidgets import wxgMeasurementOrgEAPnl
2467
2468 -class cMeasurementOrgEAPnl(wxgMeasurementOrgEAPnl.wxgMeasurementOrgEAPnl, gmEditArea.cGenericEditAreaMixin):
2469
2485
2486
2487
2488
2489
2490
2491
2492
2494 has_errors = False
2495 if self._PRW_org_unit.GetData() is None:
2496 if self._PRW_org_unit.GetValue().strip() == u'':
2497 has_errors = True
2498 self._PRW_org_unit.display_as_valid(valid = False)
2499 else:
2500 self._PRW_org_unit.display_as_valid(valid = True)
2501 else:
2502 self._PRW_org_unit.display_as_valid(valid = True)
2503
2504 return (not has_errors)
2505
2516
2536
2541
2546
2548 self._refresh_as_new()
2549
2552
2553
2555
2557
2558 query = u"""
2559 SELECT DISTINCT ON (list_label)
2560 pk AS data,
2561 unit || ' (' || organization || ')' AS field_label,
2562 unit || ' @ ' || organization AS list_label
2563 FROM clin.v_test_orgs
2564 WHERE
2565 unit %(fragment_condition)s
2566 OR
2567 organization %(fragment_condition)s
2568 ORDER BY list_label
2569 LIMIT 50"""
2570 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
2571 mp.setThresholds(1, 2, 4)
2572
2573 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
2574 self.matcher = mp
2575 self.SetToolTipString(_('The name of the path lab/diagnostic organisation.'))
2576 self.selection_only = False
2577
2590
2593
2594
2633
2678
2679
2680
2681
2683 ea = cTestPanelEAPnl(parent = parent, id = -1)
2684 ea.data = test_panel
2685 ea.mode = gmTools.coalesce(test_panel, 'new', 'edit')
2686 dlg = gmEditArea.cGenericEditAreaDlg2 (
2687 parent = parent,
2688 id = -1,
2689 edit_area = ea,
2690 single_entry = gmTools.bool2subst((test_panel is None), False, True)
2691 )
2692 dlg.SetTitle(gmTools.coalesce(test_panel, _('Adding new test panel'), _('Editing test panel')))
2693 if dlg.ShowModal() == wx.ID_OK:
2694 dlg.Destroy()
2695 return True
2696 dlg.Destroy()
2697 return False
2698
2699
2701
2702 if parent is None:
2703 parent = wx.GetApp().GetTopWindow()
2704
2705
2706 def edit(test_panel=None):
2707 return edit_test_panel(parent = parent, test_panel = test_panel)
2708
2709 def delete(test_panel):
2710 gmPathLab.delete_test_panel(pk = test_panel['pk_test_panel'])
2711 return True
2712
2713 def get_tooltip(test_panel):
2714 return test_panel.format()
2715
2716 def refresh(lctrl):
2717 panels = gmPathLab.get_test_panels(order_by = 'description')
2718 items = [ [
2719 p['description'],
2720 gmTools.coalesce(p['comment'], u''),
2721 p['pk_test_panel']
2722 ] for p in panels ]
2723 lctrl.set_string_items(items)
2724 lctrl.set_data(panels)
2725
2726 msg = _(
2727 '\n'
2728 'Test panels as defined in GNUmed.\n'
2729 )
2730
2731 gmListWidgets.get_choices_from_list (
2732 parent = parent,
2733 msg = msg,
2734 caption = _('Showing test panels.'),
2735 columns = [ _('Name'), _('Comment'), u'#' ],
2736 single_selection = True,
2737 refresh_callback = refresh,
2738 edit_callback = edit,
2739 new_callback = edit,
2740 delete_callback = delete,
2741 list_tooltip_callback = get_tooltip
2742 )
2743
2744
2746
2748 query = u"""
2749 SELECT
2750 pk_test_panel
2751 AS data,
2752 description
2753 AS field_label,
2754 description
2755 AS list_label
2756 FROM
2757 clin.v_test_panels
2758 WHERE
2759 description %(fragment_condition)s
2760 ORDER BY field_label
2761 LIMIT 30"""
2762 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
2763 mp.setThresholds(1, 2, 4)
2764
2765 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
2766 self.matcher = mp
2767 self.SetToolTipString(_('Select a test panel.'))
2768 self.selection_only = True
2769
2774
2779
2780
2781 from Gnumed.wxGladeWidgets import wxgTestPanelEAPnl
2782
2783 -class cTestPanelEAPnl(wxgTestPanelEAPnl.wxgTestPanelEAPnl, gmEditArea.cGenericEditAreaMixin):
2784
2802
2803
2804
2805
2806
2807
2808
2809
2811 validity = True
2812
2813 if self._test_types is None:
2814 validity = False
2815 gmDispatcher.send(signal = 'statustext', msg = _('No test types selected.'))
2816 self._BTN_select_tests.SetFocus()
2817
2818 if self._TCTRL_description.GetValue().strip() == u'':
2819 validity = False
2820 self.display_tctrl_as_valid(tctrl = self._TCTRL_description, valid = False)
2821 self._TCTRL_description.SetFocus()
2822 else:
2823 self.display_tctrl_as_valid(tctrl = self._TCTRL_description, valid = True)
2824
2825 return validity
2826
2835
2837 self.data['description'] = self._TCTRL_description.GetValue().strip()
2838 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
2839 self.data['pk_test_types'] = [ tt['pk_test_type'] for tt in self._test_types ]
2840 self.data.save()
2841 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ]
2842 return True
2843
2845 self._TCTRL_tests.SetValue(u'')
2846 self._test_types = test_types
2847 if self._test_types is None:
2848 return
2849 tmp = u';\n'.join ([
2850 u'%s: %s%s' % (
2851 t['unified_abbrev'],
2852 t['unified_name'],
2853 gmTools.coalesce(t['name_org'], u'', u' (%s)')
2854 )
2855 for t in self._test_types
2856 ])
2857 self._TCTRL_tests.SetValue(tmp)
2858
2860 self._TCTRL_description.SetValue(u'')
2861 self._TCTRL_comment.SetValue(u'')
2862 self.__refresh_test_types_field()
2863 self._PRW_codes.SetText()
2864
2865 self._TCTRL_description.SetFocus()
2866
2870
2879
2895
2896
2897
2898
2899 if __name__ == '__main__':
2900
2901 from Gnumed.pycommon import gmLog2
2902 from Gnumed.wxpython import gmPatSearchWidgets
2903
2904 gmI18N.activate_locale()
2905 gmI18N.install_domain()
2906 gmDateTime.init()
2907
2908
2916
2924
2925
2926
2927
2928
2929
2930
2931 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
2932
2933 test_test_ea_pnl()
2934
2935
2936
2937