1 """GNUmed measurement widgets."""
2
3 __version__ = "$Revision: 1.66 $"
4 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
5 __license__ = "GPL"
6
7
8 import sys, logging, datetime as pyDT, decimal, os, webbrowser, subprocess, codecs
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, gmPathLab, gmSurgery, gmLOINC, gmForms, gmPersonSearch
17 from Gnumed.pycommon import gmTools, gmDispatcher, gmMatchProvider, gmDateTime, gmI18N, gmCfg, gmShellAPI
18 from Gnumed.wxpython import gmRegetMixin, gmPhraseWheel, gmEditArea, gmGuiHelpers, gmListWidgets
19 from Gnumed.wxpython import gmAuthWidgets, gmPatSearchWidgets, gmFormWidgets
20 from Gnumed.wxGladeWidgets import wxgMeasurementsPnl, wxgMeasurementsReviewDlg
21 from Gnumed.wxGladeWidgets import wxgMeasurementEditAreaPnl
22
23
24 _log = logging.getLogger('gm.ui')
25 _log.info(__version__)
26
27
28
29
31
32 wx.BeginBusyCursor()
33
34 gmDispatcher.send(signal = 'statustext', msg = _('Updating LOINC data can take quite a while...'), beep = True)
35
36
37 downloaded = gmShellAPI.run_command_in_shell(command = 'gm-download_loinc', blocking = True)
38 if not downloaded:
39 wx.EndBusyCursor()
40 gmGuiHelpers.gm_show_warning (
41 aTitle = _('Downloading LOINC'),
42 aMessage = _(
43 'Running <gm-download_loinc> to retrieve\n'
44 'the latest LOINC data failed.\n'
45 )
46 )
47 return False
48
49
50 data_fname, license_fname = gmLOINC.split_LOINCDBTXT(input_fname = '/tmp/LOINCDB.TXT')
51
52 wx.EndBusyCursor()
53
54 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('importing LOINC reference data'))
55 if conn is None:
56 return False
57
58 wx.BeginBusyCursor()
59
60 if gmLOINC.loinc_import(data_fname = data_fname, license_fname = license_fname, conn = conn):
61 gmDispatcher.send(signal = 'statustext', msg = _('Successfully imported LOINC reference data.'))
62 try:
63 os.remove(data_fname)
64 os.remove(license_fname)
65 except OSError:
66 _log.error('unable to remove [%s] or [%s]', data_fname, license_fname)
67 else:
68 gmDispatcher.send(signal = 'statustext', msg = _('Importing LOINC reference data failed.'), beep = True)
69
70 wx.EndBusyCursor()
71 return True
72
73
74
76
77 dbcfg = gmCfg.cCfgSQL()
78
79 url = dbcfg.get (
80 option = u'external.urls.measurements_search',
81 workplace = gmSurgery.gmCurrentPractice().active_workplace,
82 bias = 'user',
83 default = u"http://www.google.de/search?as_oq=%(search_term)s&num=10&as_sitesearch=laborlexikon.de"
84 )
85
86 base_url = dbcfg.get2 (
87 option = u'external.urls.measurements_encyclopedia',
88 workplace = gmSurgery.gmCurrentPractice().active_workplace,
89 bias = 'user',
90 default = u'http://www.laborlexikon.de'
91 )
92
93 if measurement_type is None:
94 url = base_url
95
96 measurement_type = measurement_type.strip()
97
98 if measurement_type == u'':
99 url = base_url
100
101 url = url % {'search_term': measurement_type}
102
103 webbrowser.open (
104 url = url,
105 new = False,
106 autoraise = True
107 )
108
120
141
142
143
144
145
146
147
148
149
150
151
152
153
154
156 """A grid class for displaying measurment results.
157
158 - does NOT listen to the currently active patient
159 - thereby it can display any patient at any time
160 """
161
162
163
164
165
166
168
169 wx.grid.Grid.__init__(self, *args, **kwargs)
170
171 self.__patient = None
172 self.__cell_data = {}
173 self.__row_label_data = []
174
175 self.__prev_row = None
176 self.__prev_col = None
177 self.__prev_label_row = None
178 self.__date_format = str((_('lab_grid_date_format::%Y\n%b %d')).lstrip('lab_grid_date_format::'))
179
180 self.__init_ui()
181 self.__register_events()
182
183
184
186 if not self.IsSelection():
187 gmDispatcher.send(signal = u'statustext', msg = _('No results selected for deletion.'))
188 return True
189
190 selected_cells = self.get_selected_cells()
191 if len(selected_cells) > 20:
192 results = None
193 msg = _(
194 'There are %s results marked for deletion.\n'
195 '\n'
196 'Are you sure you want to delete these results ?'
197 ) % len(selected_cells)
198 else:
199 results = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
200 txt = u'\n'.join([ u'%s %s (%s): %s %s%s' % (
201 r['clin_when'].strftime('%x %H:%M').decode(gmI18N.get_encoding()),
202 r['unified_abbrev'],
203 r['unified_name'],
204 r['unified_val'],
205 r['val_unit'],
206 gmTools.coalesce(r['abnormality_indicator'], u'', u' (%s)')
207 ) for r in results
208 ])
209 msg = _(
210 'The following results are marked for deletion:\n'
211 '\n'
212 '%s\n'
213 '\n'
214 'Are you sure you want to delete these results ?'
215 ) % txt
216
217 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
218 self,
219 -1,
220 caption = _('Deleting test results'),
221 question = msg,
222 button_defs = [
223 {'label': _('Delete'), 'tooltip': _('Yes, delete all the results.'), 'default': False},
224 {'label': _('Cancel'), 'tooltip': _('No, do NOT delete any results.'), 'default': True}
225 ]
226 )
227 decision = dlg.ShowModal()
228
229 if decision == wx.ID_YES:
230 if results is None:
231 results = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
232 for result in results:
233 gmPathLab.delete_test_result(result)
234
236 if not self.IsSelection():
237 gmDispatcher.send(signal = u'statustext', msg = _('Cannot sign results. No results selected.'))
238 return True
239
240 selected_cells = self.get_selected_cells()
241 if len(selected_cells) > 10:
242 test_count = len(selected_cells)
243 tests = None
244 else:
245 test_count = None
246 tests = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
247
248 dlg = cMeasurementsReviewDlg (
249 self,
250 -1,
251 tests = tests,
252 test_count = test_count
253 )
254 decision = dlg.ShowModal()
255
256 if decision == wx.ID_APPLY:
257 wx.BeginBusyCursor()
258
259 if dlg._RBTN_confirm_abnormal.GetValue():
260 abnormal = None
261 elif dlg._RBTN_results_normal.GetValue():
262 abnormal = False
263 else:
264 abnormal = True
265
266 if dlg._RBTN_confirm_relevance.GetValue():
267 relevant = None
268 elif dlg._RBTN_results_not_relevant.GetValue():
269 relevant = False
270 else:
271 relevant = True
272
273 if tests is None:
274 tests = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
275
276 comment = None
277 if len(tests) == 1:
278 comment = dlg._TCTRL_comment.GetValue()
279
280 for test in tests:
281 test.set_review (
282 technically_abnormal = abnormal,
283 clinically_relevant = relevant,
284 comment = comment,
285 make_me_responsible = dlg._CHBOX_responsible.IsChecked()
286 )
287
288 wx.EndBusyCursor()
289
290 dlg.Destroy()
291
293
294 if not self.IsSelection():
295 gmDispatcher.send(signal = u'statustext', msg = _('Cannot plot results. No results selected.'))
296 return True
297
298 tests = self.__cells_to_data (
299 cells = self.get_selected_cells(),
300 exclude_multi_cells = False,
301 auto_include_multi_cells = True
302 )
303
304 plot_measurements(parent = self, tests = tests)
305
307
308 sel_block_top_left = self.GetSelectionBlockTopLeft()
309 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
310 sel_cols = self.GetSelectedCols()
311 sel_rows = self.GetSelectedRows()
312
313 selected_cells = []
314
315
316 selected_cells += self.GetSelectedCells()
317
318
319 selected_cells += list (
320 (row, col)
321 for row in sel_rows
322 for col in xrange(self.GetNumberCols())
323 )
324
325
326 selected_cells += list (
327 (row, col)
328 for row in xrange(self.GetNumberRows())
329 for col in sel_cols
330 )
331
332
333 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
334 selected_cells += [
335 (row, col)
336 for row in xrange(top_left[0], bottom_right[0] + 1)
337 for col in xrange(top_left[1], bottom_right[1] + 1)
338 ]
339
340 return set(selected_cells)
341
342 - def select_cells(self, unsigned_only=False, accountables_only=False, keep_preselections=False):
343 """Select a range of cells according to criteria.
344
345 unsigned_only: include only those which are not signed at all yet
346 accountable_only: include only those for which the current user is responsible
347 keep_preselections: broaden (rather than replace) the range of selected cells
348
349 Combinations are powerful !
350 """
351 wx.BeginBusyCursor()
352 self.BeginBatch()
353
354 if not keep_preselections:
355 self.ClearSelection()
356
357 for col_idx in self.__cell_data.keys():
358 for row_idx in self.__cell_data[col_idx].keys():
359
360
361 do_not_include = False
362 for result in self.__cell_data[col_idx][row_idx]:
363 if unsigned_only:
364 if result['reviewed']:
365 do_not_include = True
366 break
367 if accountables_only:
368 if not result['you_are_responsible']:
369 do_not_include = True
370 break
371 if do_not_include:
372 continue
373
374 self.SelectBlock(row_idx, col_idx, row_idx, col_idx, addToSelected = True)
375
376 self.EndBatch()
377 wx.EndBusyCursor()
378
380
381 self.empty_grid()
382 if self.__patient is None:
383 return
384
385 emr = self.__patient.get_emr()
386
387 self.__row_label_data = emr.get_test_types_for_results()
388 test_type_labels = [ u'%s (%s)' % (test['unified_abbrev'], test['unified_name']) for test in self.__row_label_data ]
389 if len(test_type_labels) == 0:
390 return
391
392 test_date_labels = [ date[0].strftime(self.__date_format) for date in emr.get_dates_for_results() ]
393 results = emr.get_test_results_by_date()
394
395 self.BeginBatch()
396
397
398 self.AppendRows(numRows = len(test_type_labels))
399 for row_idx in range(len(test_type_labels)):
400 self.SetRowLabelValue(row_idx, test_type_labels[row_idx])
401
402
403 self.AppendCols(numCols = len(test_date_labels))
404 for date_idx in range(len(test_date_labels)):
405 self.SetColLabelValue(date_idx, test_date_labels[date_idx])
406
407
408 for result in results:
409 row = test_type_labels.index(u'%s (%s)' % (result['unified_abbrev'], result['unified_name']))
410 col = test_date_labels.index(result['clin_when'].strftime(self.__date_format))
411
412 try:
413 self.__cell_data[col]
414 except KeyError:
415 self.__cell_data[col] = {}
416
417
418 if self.__cell_data[col].has_key(row):
419 self.__cell_data[col][row].append(result)
420 self.__cell_data[col][row].sort(key = lambda x: x['clin_when'], reverse = True)
421 else:
422 self.__cell_data[col][row] = [result]
423
424
425 vals2display = []
426 for sub_result in self.__cell_data[col][row]:
427
428
429 ind = gmTools.coalesce(sub_result['abnormality_indicator'], u'').strip()
430 if ind != u'':
431 lab_abnormality_indicator = u' (%s)' % ind[:3]
432 else:
433 lab_abnormality_indicator = u''
434
435 if sub_result['is_technically_abnormal'] is None:
436 abnormality_indicator = lab_abnormality_indicator
437
438 elif sub_result['is_technically_abnormal'] is False:
439 abnormality_indicator = u''
440
441 else:
442
443 if lab_abnormality_indicator == u'':
444
445 abnormality_indicator = u' (%s)' % gmTools.u_plus_minus
446
447 else:
448 abnormality_indicator = lab_abnormality_indicator
449
450
451
452 sub_result_relevant = sub_result['is_clinically_relevant']
453 if sub_result_relevant is None:
454
455 sub_result_relevant = False
456
457 missing_review = False
458
459
460 if not sub_result['reviewed']:
461 missing_review = True
462
463 else:
464
465 if sub_result['you_are_responsible'] and not sub_result['review_by_you']:
466 missing_review = True
467
468
469 if len(sub_result['unified_val']) > 8:
470 tmp = u'%.7s%s' % (sub_result['unified_val'][:7], gmTools.u_ellipsis)
471 else:
472 tmp = u'%.8s' % sub_result['unified_val'][:8]
473
474
475 tmp = u'%s%.6s' % (tmp, abnormality_indicator)
476
477
478 has_sub_result_comment = gmTools.coalesce (
479 gmTools.coalesce(sub_result['note_test_org'], sub_result['comment']),
480 u''
481 ).strip() != u''
482 if has_sub_result_comment:
483 tmp = u'%s %s' % (tmp, gmTools.u_ellipsis)
484
485
486 if missing_review:
487 tmp = u'%s %s' % (tmp, gmTools.u_writing_hand)
488
489
490 if len(self.__cell_data[col][row]) > 1:
491 tmp = u'%s %s' % (sub_result['clin_when'].strftime('%H:%M'), tmp)
492
493 vals2display.append(tmp)
494
495 self.SetCellValue(row, col, u'\n'.join(vals2display))
496 self.SetCellAlignment(row, col, horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
497
498
499
500
501 if sub_result_relevant:
502 font = self.GetCellFont(row, col)
503 self.SetCellTextColour(row, col, 'firebrick')
504 font.SetWeight(wx.FONTWEIGHT_BOLD)
505 self.SetCellFont(row, col, font)
506
507
508 self.AutoSize()
509 self.EndBatch()
510 return
511
513 self.BeginBatch()
514 self.ClearGrid()
515
516
517 if self.GetNumberRows() > 0:
518 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
519 if self.GetNumberCols() > 0:
520 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
521 self.EndBatch()
522 self.__cell_data = {}
523 self.__row_label_data = []
524
563
811
812
813
815 self.CreateGrid(0, 1)
816 self.EnableEditing(0)
817 self.EnableDragGridSize(1)
818
819
820
821
822
823 self.SetRowLabelSize(150)
824 self.SetRowLabelAlignment(horiz = wx.ALIGN_LEFT, vert = wx.ALIGN_CENTRE)
825
826
827 dbcfg = gmCfg.cCfgSQL()
828 url = dbcfg.get2 (
829 option = u'external.urls.measurements_encyclopedia',
830 workplace = gmSurgery.gmCurrentPractice().active_workplace,
831 bias = 'user',
832 default = u'http://www.laborlexikon.de'
833 )
834
835 self.__WIN_corner = self.GetGridCornerLabelWindow()
836
837 LNK_lab = wx.lib.hyperlink.HyperLinkCtrl (
838 self.__WIN_corner,
839 -1,
840 label = _('Reference'),
841 style = wx.HL_DEFAULT_STYLE
842 )
843 LNK_lab.SetURL(url)
844 LNK_lab.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BACKGROUND))
845 LNK_lab.SetToolTipString(_(
846 'Navigate to an encyclopedia of measurements\n'
847 'and test methods on the web.\n'
848 '\n'
849 ' <%s>'
850 ) % url)
851
852 SZR_inner = wx.BoxSizer(wx.HORIZONTAL)
853 SZR_inner.Add((20, 20), 1, wx.EXPAND, 0)
854 SZR_inner.Add(LNK_lab, 0, wx.ALIGN_CENTER_VERTICAL, 0)
855 SZR_inner.Add((20, 20), 1, wx.EXPAND, 0)
856
857 SZR_corner = wx.BoxSizer(wx.VERTICAL)
858 SZR_corner.Add((20, 20), 1, wx.EXPAND, 0)
859 SZR_corner.AddWindow(SZR_inner, 0, wx.EXPAND)
860 SZR_corner.Add((20, 20), 1, wx.EXPAND, 0)
861
862 self.__WIN_corner.SetSizer(SZR_corner)
863 SZR_corner.Fit(self.__WIN_corner)
864
866 self.__WIN_corner.Layout()
867
868 - def __cells_to_data(self, cells=None, exclude_multi_cells=False, auto_include_multi_cells=False):
869 """List of <cells> must be in row / col order."""
870 data = []
871 for row, col in cells:
872 try:
873
874 data_list = self.__cell_data[col][row]
875 except KeyError:
876 continue
877
878 if len(data_list) == 1:
879 data.append(data_list[0])
880 continue
881
882 if exclude_multi_cells:
883 gmDispatcher.send(signal = u'statustext', msg = _('Excluding multi-result field from further processing.'))
884 continue
885
886 if auto_include_multi_cells:
887 data.extend(data_list)
888 continue
889
890 data_to_include = self.__get_choices_from_multi_cell(cell_data = data_list)
891 if data_to_include is None:
892 continue
893 data.extend(data_to_include)
894
895 return data
896
898 data = gmListWidgets.get_choices_from_list (
899 parent = self,
900 msg = _(
901 'Your selection includes a field with multiple results.\n'
902 '\n'
903 'Please select the individual results you want to work on:'
904 ),
905 caption = _('Selecting test results'),
906 choices = [ [d['clin_when'], d['unified_abbrev'], d['unified_name'], d['unified_val']] for d in cell_data ],
907 columns = [_('Date / Time'), _('Code'), _('Test'), _('Result')],
908 data = cell_data,
909 single_selection = single_selection
910 )
911 return data
912
913
914
916
917 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
918 self.GetGridRowLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_row_labels)
919
920
921
922 self.Bind(wx.EVT_SIZE, self.__resize_corner_window)
923
924
925 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
926
928 col = evt.GetCol()
929 row = evt.GetRow()
930
931
932 try:
933 self.__cell_data[col][row]
934 except KeyError:
935
936
937 return
938
939 if len(self.__cell_data[col][row]) > 1:
940 data = self.__get_choices_from_multi_cell(cell_data = self.__cell_data[col][row], single_selection = True)
941 else:
942 data = self.__cell_data[col][row][0]
943
944 if data is None:
945 return
946
947 edit_measurement(parent = self, measurement = data, single_entry = True)
948
949
950
951
952
953
954
956
957
958
959 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
960
961 row = self.YToRow(y)
962
963 if self.__prev_label_row == row:
964 return
965
966 self.__prev_label_row == row
967
968 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
969
970
971
972
973
974
975
976
978 """Calculate where the mouse is and set the tooltip dynamically."""
979
980
981
982 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
983
984
985
986
987
988
989
990
991
992
993
994
995
996 row, col = self.XYToCell(x, y)
997
998 if (row == self.__prev_row) and (col == self.__prev_col):
999 return
1000
1001 self.__prev_row = row
1002 self.__prev_col = col
1003
1004 evt.GetEventObject().SetToolTipString(self.get_cell_tooltip(col=col, row=row))
1005
1006
1007
1011
1012 patient = property(lambda x:x, _set_patient)
1013
1014 -class cMeasurementsPnl(wxgMeasurementsPnl.wxgMeasurementsPnl, gmRegetMixin.cRegetOnPaintMixin):
1015
1016 """Panel holding a grid with lab data. Used as notebook page."""
1017
1024
1025
1026
1028 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
1029 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
1030 gmDispatcher.connect(signal = u'test_result_mod_db', receiver = self._schedule_data_reget)
1031 gmDispatcher.connect(signal = u'reviewed_test_results_mod_db', receiver = self._schedule_data_reget)
1032
1034 wx.CallAfter(self.__on_post_patient_selection)
1035
1037 self._schedule_data_reget()
1038
1040 wx.CallAfter(self.__on_pre_patient_selection)
1041
1044
1047
1053
1056
1059
1062
1063
1064
1066 self.__action_button_popup = wx.Menu(title = _('Act on selected results'))
1067
1068 menu_id = wx.NewId()
1069 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Review and &sign')))
1070 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_sign_current_selection)
1071
1072 menu_id = wx.NewId()
1073 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Plot')))
1074 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_plot_current_selection)
1075
1076 menu_id = wx.NewId()
1077 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Export to &file')))
1078
1079 self.__action_button_popup.Enable(id = menu_id, enable = False)
1080
1081 menu_id = wx.NewId()
1082 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Export to &clipboard')))
1083
1084 self.__action_button_popup.Enable(id = menu_id, enable = False)
1085
1086 menu_id = wx.NewId()
1087 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('&Delete')))
1088 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_delete_current_selection)
1089
1090
1091
1100
1101
1102
1104
1106
1107 try:
1108 tests = kwargs['tests']
1109 del kwargs['tests']
1110 test_count = len(tests)
1111 try: del kwargs['test_count']
1112 except KeyError: pass
1113 except KeyError:
1114 tests = None
1115 test_count = kwargs['test_count']
1116 del kwargs['test_count']
1117
1118 wxgMeasurementsReviewDlg.wxgMeasurementsReviewDlg.__init__(self, *args, **kwargs)
1119
1120 if tests is None:
1121 msg = _('%s results selected. Too many to list individually.') % test_count
1122 else:
1123 msg = ' // '.join (
1124 [ u'%s: %s %s (%s)' % (
1125 t['unified_abbrev'],
1126 t['unified_val'],
1127 t['val_unit'],
1128 t['clin_when'].strftime('%x').decode(gmI18N.get_encoding())
1129 ) for t in tests
1130 ]
1131 )
1132
1133 self._LBL_tests.SetLabel(msg)
1134
1135 if test_count == 1:
1136 self._TCTRL_comment.Enable(True)
1137 self._TCTRL_comment.SetValue(gmTools.coalesce(tests[0]['review_comment'], u''))
1138 if tests[0]['you_are_responsible']:
1139 self._CHBOX_responsible.Enable(False)
1140
1141 self.Fit()
1142
1143
1144
1150
1151 -class cMeasurementEditAreaPnl(wxgMeasurementEditAreaPnl.wxgMeasurementEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
1152 """This edit area saves *new* measurements into the active patient only."""
1153
1168
1169
1170
1172 self._PRW_test.SetText(u'', None, True)
1173 self.__refresh_loinc_info()
1174 self.__update_units_context()
1175 self._TCTRL_result.SetValue(u'')
1176 self._PRW_units.SetText(u'', None, True)
1177 self._PRW_abnormality_indicator.SetText(u'', None, True)
1178 if self.__default_date is None:
1179 self._DPRW_evaluated.SetData(data = pyDT.datetime.now(tz = gmDateTime.gmCurrentLocalTimezone))
1180 else:
1181 self._DPRW_evaluated.SetData(data = None)
1182 self._TCTRL_note_test_org.SetValue(u'')
1183 self._PRW_intended_reviewer.SetData()
1184 self._PRW_problem.SetData()
1185 self._TCTRL_narrative.SetValue(u'')
1186 self._CHBOX_review.SetValue(False)
1187 self._CHBOX_abnormal.SetValue(False)
1188 self._CHBOX_relevant.SetValue(False)
1189 self._CHBOX_abnormal.Enable(False)
1190 self._CHBOX_relevant.Enable(False)
1191 self._TCTRL_review_comment.SetValue(u'')
1192 self._TCTRL_normal_min.SetValue(u'')
1193 self._TCTRL_normal_max.SetValue(u'')
1194 self._TCTRL_normal_range.SetValue(u'')
1195 self._TCTRL_target_min.SetValue(u'')
1196 self._TCTRL_target_max.SetValue(u'')
1197 self._TCTRL_target_range.SetValue(u'')
1198 self._TCTRL_norm_ref_group.SetValue(u'')
1199
1200 self._PRW_test.SetFocus()
1201
1203 self._PRW_test.SetData(data = self.data['pk_test_type'])
1204 self.__refresh_loinc_info()
1205 self.__update_units_context()
1206 self._TCTRL_result.SetValue(self.data['unified_val'])
1207 self._PRW_units.SetText(self.data['val_unit'], self.data['val_unit'], True)
1208 self._PRW_abnormality_indicator.SetText (
1209 gmTools.coalesce(self.data['abnormality_indicator'], u''),
1210 gmTools.coalesce(self.data['abnormality_indicator'], u''),
1211 True
1212 )
1213 self._DPRW_evaluated.SetData(data = self.data['clin_when'])
1214 self._TCTRL_note_test_org.SetValue(gmTools.coalesce(self.data['note_test_org'], u''))
1215 self._PRW_intended_reviewer.SetData(self.data['pk_intended_reviewer'])
1216 self._PRW_problem.SetData(self.data['pk_episode'])
1217 self._TCTRL_narrative.SetValue(gmTools.coalesce(self.data['comment'], u''))
1218 self._CHBOX_review.SetValue(False)
1219 self._CHBOX_abnormal.SetValue(gmTools.coalesce(self.data['is_technically_abnormal'], False))
1220 self._CHBOX_relevant.SetValue(gmTools.coalesce(self.data['is_clinically_relevant'], False))
1221 self._CHBOX_abnormal.Enable(False)
1222 self._CHBOX_relevant.Enable(False)
1223 self._TCTRL_review_comment.SetValue(gmTools.coalesce(self.data['review_comment'], u''))
1224 self._TCTRL_normal_min.SetValue(unicode(gmTools.coalesce(self.data['val_normal_min'], u'')))
1225 self._TCTRL_normal_max.SetValue(unicode(gmTools.coalesce(self.data['val_normal_max'], u'')))
1226 self._TCTRL_normal_range.SetValue(gmTools.coalesce(self.data['val_normal_range'], u''))
1227 self._TCTRL_target_min.SetValue(unicode(gmTools.coalesce(self.data['val_target_min'], u'')))
1228 self._TCTRL_target_max.SetValue(unicode(gmTools.coalesce(self.data['val_target_max'], u'')))
1229 self._TCTRL_target_range.SetValue(gmTools.coalesce(self.data['val_target_range'], u''))
1230 self._TCTRL_norm_ref_group.SetValue(gmTools.coalesce(self.data['norm_ref_group'], u''))
1231
1232 self._TCTRL_result.SetFocus()
1233
1235 self._refresh_from_existing()
1236
1237 self._PRW_test.SetText(u'', None, True)
1238 self.__refresh_loinc_info()
1239 self.__update_units_context()
1240 self._TCTRL_result.SetValue(u'')
1241 self._PRW_units.SetText(u'', None, True)
1242 self._PRW_abnormality_indicator.SetText(u'', None, True)
1243
1244 self._TCTRL_note_test_org.SetValue(u'')
1245 self._TCTRL_narrative.SetValue(u'')
1246 self._CHBOX_review.SetValue(False)
1247 self._CHBOX_abnormal.SetValue(False)
1248 self._CHBOX_relevant.SetValue(False)
1249 self._CHBOX_abnormal.Enable(False)
1250 self._CHBOX_relevant.Enable(False)
1251 self._TCTRL_review_comment.SetValue(u'')
1252 self._TCTRL_normal_min.SetValue(u'')
1253 self._TCTRL_normal_max.SetValue(u'')
1254 self._TCTRL_normal_range.SetValue(u'')
1255 self._TCTRL_target_min.SetValue(u'')
1256 self._TCTRL_target_max.SetValue(u'')
1257 self._TCTRL_target_range.SetValue(u'')
1258 self._TCTRL_norm_ref_group.SetValue(u'')
1259
1260 self._PRW_test.SetFocus()
1261
1263
1264 validity = True
1265
1266 if not self._DPRW_evaluated.is_valid_timestamp():
1267 self._DPRW_evaluated.display_as_valid(False)
1268 validity = False
1269 else:
1270 self._DPRW_evaluated.display_as_valid(True)
1271
1272 if self._TCTRL_result.GetValue().strip() == u'':
1273 self._TCTRL_result.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
1274 validity = False
1275 else:
1276 self._TCTRL_result.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
1277
1278 if self._PRW_problem.GetValue().strip() == u'':
1279 self._PRW_problem.display_as_valid(False)
1280 validity = False
1281 else:
1282 self._PRW_problem.display_as_valid(True)
1283
1284 if self._PRW_test.GetValue().strip() == u'':
1285 self._PRW_test.display_as_valid(False)
1286 validity = False
1287 else:
1288 self._PRW_test.display_as_valid(True)
1289
1290 if self._PRW_intended_reviewer.GetData() is None:
1291 self._PRW_intended_reviewer.display_as_valid(False)
1292 validity = False
1293 else:
1294 self._PRW_intended_reviewer.display_as_valid(True)
1295
1296 if self._PRW_units.GetValue().strip() == u'':
1297 self._PRW_units.display_as_valid(False)
1298 validity = False
1299 else:
1300 self._PRW_units.display_as_valid(True)
1301
1302 ctrls = [self._TCTRL_normal_min, self._TCTRL_normal_max, self._TCTRL_target_min, self._TCTRL_target_max]
1303 for widget in ctrls:
1304 val = widget.GetValue().strip()
1305 if val == u'':
1306 continue
1307 try:
1308 decimal.Decimal(val.replace(',', u'.', 1))
1309 widget.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
1310 except:
1311 widget.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
1312 validity = False
1313
1314 if validity is False:
1315 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save result. Invalid or missing essential input.'))
1316
1317 return validity
1318
1320
1321 emr = gmPerson.gmCurrentPatient().get_emr()
1322
1323 try:
1324 v_num = decimal.Decimal(self._TCTRL_result.GetValue().strip().replace(',', '.', 1))
1325 v_al = None
1326 except:
1327 v_num = None
1328 v_al = self._TCTRL_result.GetValue().strip()
1329
1330 pk_type = self._PRW_test.GetData()
1331 if pk_type is None:
1332 tt = gmPathLab.create_measurement_type (
1333 lab = None,
1334 abbrev = self._PRW_test.GetValue().strip(),
1335 name = self._PRW_test.GetValue().strip(),
1336 unit = gmTools.coalesce(self._PRW_units.GetData(), self._PRW_units.GetValue()).strip()
1337 )
1338 pk_type = tt['pk_test_type']
1339
1340 tr = emr.add_test_result (
1341 episode = self._PRW_problem.GetData(can_create=True, is_open=False),
1342 type = pk_type,
1343 intended_reviewer = self._PRW_intended_reviewer.GetData(),
1344 val_num = v_num,
1345 val_alpha = v_al,
1346 unit = self._PRW_units.GetValue()
1347 )
1348
1349 tr['clin_when'] = self._DPRW_evaluated.GetData().get_pydt()
1350
1351 ctrls = [
1352 ('abnormality_indicator', self._PRW_abnormality_indicator),
1353 ('note_test_org', self._TCTRL_note_test_org),
1354 ('comment', self._TCTRL_narrative),
1355 ('val_normal_range', self._TCTRL_normal_range),
1356 ('val_target_range', self._TCTRL_target_range),
1357 ('norm_ref_group', self._TCTRL_norm_ref_group)
1358 ]
1359 for field, widget in ctrls:
1360 tr[field] = widget.GetValue().strip()
1361
1362 ctrls = [
1363 ('val_normal_min', self._TCTRL_normal_min),
1364 ('val_normal_max', self._TCTRL_normal_max),
1365 ('val_target_min', self._TCTRL_target_min),
1366 ('val_target_max', self._TCTRL_target_max)
1367 ]
1368 for field, widget in ctrls:
1369 val = widget.GetValue().strip()
1370 if val == u'':
1371 tr[field] = None
1372 else:
1373 tr[field] = decimal.Decimal(val.replace(',', u'.', 1))
1374
1375 tr.save_payload()
1376
1377 if self._CHBOX_review.GetValue() is True:
1378 tr.set_review (
1379 technically_abnormal = self._CHBOX_abnormal.GetValue(),
1380 clinically_relevant = self._CHBOX_relevant.GetValue(),
1381 comment = gmTools.none_if(self._TCTRL_review_comment.GetValue().strip(), u''),
1382 make_me_responsible = False
1383 )
1384
1385 self.data = tr
1386
1387 return True
1388
1390
1391 success, result = gmTools.input2decimal(self._TCTRL_result.GetValue())
1392 if success:
1393 v_num = result
1394 v_al = None
1395 else:
1396 v_num = None
1397 v_al = self._TCTRL_result.GetValue().strip()
1398
1399 pk_type = self._PRW_test.GetData()
1400 if pk_type is None:
1401 tt = gmPathLab.create_measurement_type (
1402 lab = None,
1403 abbrev = self._PRW_test.GetValue().strip(),
1404 name = self._PRW_test.GetValue().strip(),
1405 unit = gmTools.none_if(self._PRW_units.GetValue().strip(), u'')
1406 )
1407 pk_type = tt['pk_test_type']
1408
1409 tr = self.data
1410
1411 tr['pk_episode'] = self._PRW_problem.GetData(can_create=True, is_open=False)
1412 tr['pk_test_type'] = pk_type
1413 tr['pk_intended_reviewer'] = self._PRW_intended_reviewer.GetData()
1414 tr['val_num'] = v_num
1415 tr['val_alpha'] = v_al
1416 tr['val_unit'] = gmTools.coalesce(self._PRW_units.GetData(), self._PRW_units.GetValue()).strip()
1417 tr['clin_when'] = self._DPRW_evaluated.GetData().get_pydt()
1418
1419 ctrls = [
1420 ('abnormality_indicator', self._PRW_abnormality_indicator),
1421 ('note_test_org', self._TCTRL_note_test_org),
1422 ('comment', self._TCTRL_narrative),
1423 ('val_normal_range', self._TCTRL_normal_range),
1424 ('val_target_range', self._TCTRL_target_range),
1425 ('norm_ref_group', self._TCTRL_norm_ref_group)
1426 ]
1427 for field, widget in ctrls:
1428 tr[field] = widget.GetValue().strip()
1429
1430 ctrls = [
1431 ('val_normal_min', self._TCTRL_normal_min),
1432 ('val_normal_max', self._TCTRL_normal_max),
1433 ('val_target_min', self._TCTRL_target_min),
1434 ('val_target_max', self._TCTRL_target_max)
1435 ]
1436 for field, widget in ctrls:
1437 val = widget.GetValue().strip()
1438 if val == u'':
1439 tr[field] = None
1440 else:
1441 tr[field] = decimal.Decimal(val.replace(',', u'.', 1))
1442
1443 tr.save_payload()
1444
1445 if self._CHBOX_review.GetValue() is True:
1446 tr.set_review (
1447 technically_abnormal = self._CHBOX_abnormal.GetValue(),
1448 clinically_relevant = self._CHBOX_relevant.GetValue(),
1449 comment = gmTools.none_if(self._TCTRL_review_comment.GetValue().strip(), u''),
1450 make_me_responsible = False
1451 )
1452
1453 return True
1454
1455
1456
1460
1462 self.__refresh_loinc_info()
1463 self.__update_units_context()
1464
1466
1467 if not self._CHBOX_review.GetValue():
1468 self._CHBOX_abnormal.SetValue(self._PRW_abnormality_indicator.GetValue().strip() != u'')
1469
1471 self._CHBOX_abnormal.Enable(self._CHBOX_review.GetValue())
1472 self._CHBOX_relevant.Enable(self._CHBOX_review.GetValue())
1473 self._TCTRL_review_comment.Enable(self._CHBOX_review.GetValue())
1474
1491
1492
1493
1495
1496 self._PRW_units.unset_context(context = u'loinc')
1497
1498 tt = self._PRW_test.GetData(as_instance = True)
1499
1500 if tt is None:
1501 self._PRW_units.unset_context(context = u'pk_type')
1502 if self._PRW_test.GetValue().strip() == u'':
1503 self._PRW_units.unset_context(context = u'test_name')
1504 else:
1505 self._PRW_units.set_context(context = u'test_name', val = self._PRW_test.GetValue().strip())
1506 return
1507
1508 self._PRW_units.set_context(context = u'pk_type', val = tt['pk_test_type'])
1509 self._PRW_units.set_context(context = u'test_name', val = tt['name'])
1510
1511 if tt['loinc'] is None:
1512 return
1513
1514 self._PRW_units.set_context(context = u'loinc', val = tt['loinc'])
1515
1517
1518 self._TCTRL_loinc.SetValue(u'')
1519
1520 if self._PRW_test.GetData() is None:
1521 return
1522
1523 tt = self._PRW_test.GetData(as_instance = True)
1524
1525 if tt['loinc'] is None:
1526 return
1527
1528 info = gmLOINC.loinc2info(loinc = tt['loinc'])
1529 if len(info) == 0:
1530 return
1531
1532 self._TCTRL_loinc.SetValue(u'%s: %s' % (tt['loinc'], info[0]))
1533
1534
1535
1537
1538 if parent is None:
1539 parent = wx.GetApp().GetTopWindow()
1540
1541
1542 def edit(test_type=None):
1543 ea = cMeasurementTypeEAPnl(parent = parent, id = -1, type = test_type)
1544 dlg = gmEditArea.cGenericEditAreaDlg2 (
1545 parent = parent,
1546 id = -1,
1547 edit_area = ea,
1548 single_entry = gmTools.bool2subst((test_type is None), False, True)
1549 )
1550 dlg.SetTitle(gmTools.coalesce(test_type, _('Adding measurement type'), _('Editing measurement type')))
1551
1552 if dlg.ShowModal() == wx.ID_OK:
1553 dlg.Destroy()
1554 return True
1555
1556 dlg.Destroy()
1557 return False
1558
1559 def refresh(lctrl):
1560 mtypes = gmPathLab.get_measurement_types(order_by = 'name, abbrev')
1561 items = [ [
1562 m['abbrev'],
1563 m['name'],
1564 gmTools.coalesce(m['loinc'], u''),
1565 gmTools.coalesce(m['conversion_unit'], u''),
1566 gmTools.coalesce(m['comment_type'], u''),
1567 gmTools.coalesce(m['internal_name_org'], _('in-house')),
1568 gmTools.coalesce(m['comment_org'], u''),
1569 m['pk_test_type']
1570 ] for m in mtypes ]
1571 lctrl.set_string_items(items)
1572 lctrl.set_data(mtypes)
1573
1574 def delete(measurement_type):
1575 if measurement_type.in_use:
1576 gmDispatcher.send (
1577 signal = 'statustext',
1578 beep = True,
1579 msg = _('Cannot delete measurement type [%s (%s)] because it is in use.') % (measurement_type['name'], measurement_type['abbrev'])
1580 )
1581 return False
1582 gmPathLab.delete_measurement_type(measurement_type = measurement_type['pk_test_type'])
1583 return True
1584
1585 msg = _(
1586 '\n'
1587 'These are the measurement types currently defined in GNUmed.\n'
1588 '\n'
1589 )
1590
1591 gmListWidgets.get_choices_from_list (
1592 parent = parent,
1593 msg = msg,
1594 caption = _('Showing measurement types.'),
1595 columns = [_('Abbrev'), _('Name'), _('LOINC'), _('Base unit'), _('Comment'), _('Org'), _('Comment'), u'#'],
1596 single_selection = True,
1597 refresh_callback = refresh,
1598 edit_callback = edit,
1599 new_callback = edit,
1600 delete_callback = delete
1601 )
1602
1604
1606
1607 query = u"""
1608 (
1609 select
1610 pk_test_type,
1611 name_tt
1612 || ' ('
1613 || coalesce (
1614 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1615 '%(in_house)s'
1616 )
1617 || ')'
1618 as name
1619 from clin.v_unified_test_types vcutt
1620 where
1621 name_meta %%(fragment_condition)s
1622
1623 ) union (
1624
1625 select
1626 pk_test_type,
1627 name_tt
1628 || ' ('
1629 || coalesce (
1630 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1631 '%(in_house)s'
1632 )
1633 || ')'
1634 as name
1635 from clin.v_unified_test_types vcutt
1636 where
1637 name_tt %%(fragment_condition)s
1638
1639 ) union (
1640
1641 select
1642 pk_test_type,
1643 name_tt
1644 || ' ('
1645 || coalesce (
1646 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1647 '%(in_house)s'
1648 )
1649 || ')'
1650 as name
1651 from clin.v_unified_test_types vcutt
1652 where
1653 abbrev_meta %%(fragment_condition)s
1654
1655 ) union (
1656
1657 select
1658 pk_test_type,
1659 name_tt
1660 || ' ('
1661 || coalesce (
1662 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1663 '%(in_house)s'
1664 )
1665 || ')'
1666 as name
1667 from clin.v_unified_test_types vcutt
1668 where
1669 code_tt %%(fragment_condition)s
1670 )
1671
1672 order by name
1673 limit 50""" % {'in_house': _('in house lab')}
1674
1675 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1676 mp.setThresholds(1, 2, 4)
1677 mp.word_separators = '[ \t:@]+'
1678 gmPhraseWheel.cPhraseWheel.__init__ (
1679 self,
1680 *args,
1681 **kwargs
1682 )
1683 self.matcher = mp
1684 self.SetToolTipString(_('Select the type of measurement.'))
1685 self.selection_only = False
1686
1692
1694
1696
1697 query = u"""
1698 select distinct on (internal_name)
1699 pk,
1700 internal_name
1701 from clin.test_org
1702 where
1703 internal_name %(fragment_condition)s
1704 order by internal_name
1705 limit 50"""
1706 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1707 mp.setThresholds(1, 2, 4)
1708
1709 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1710 self.matcher = mp
1711 self.SetToolTipString(_('The name of the path lab/diagnostic organisation.'))
1712 self.selection_only = False
1713
1726
1727 from Gnumed.wxGladeWidgets import wxgMeasurementTypeEAPnl
1728
1729 -class cMeasurementTypeEAPnl(wxgMeasurementTypeEAPnl.wxgMeasurementTypeEAPnl, gmEditArea.cGenericEditAreaMixin):
1730
1747
1748
1750
1751
1752 query = u"""
1753 select distinct on (name)
1754 pk,
1755 name
1756 from clin.test_type
1757 where
1758 name %(fragment_condition)s
1759 order by name
1760 limit 50"""
1761 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1762 mp.setThresholds(1, 2, 4)
1763 self._PRW_name.matcher = mp
1764 self._PRW_name.selection_only = False
1765 self._PRW_name.add_callback_on_lose_focus(callback = self._on_name_lost_focus)
1766
1767
1768 query = u"""
1769 select distinct on (abbrev)
1770 pk,
1771 abbrev
1772 from clin.test_type
1773 where
1774 abbrev %(fragment_condition)s
1775 order by abbrev
1776 limit 50"""
1777 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1778 mp.setThresholds(1, 2, 3)
1779 self._PRW_abbrev.matcher = mp
1780 self._PRW_abbrev.selection_only = False
1781
1782
1783 self._PRW_conversion_unit.selection_only = False
1784
1785
1786 query = u"""
1787 select distinct on (term)
1788 loinc,
1789 term
1790 from ((
1791 select
1792 loinc,
1793 (loinc || ': ' || abbrev || ' (' || name || ')') as term
1794 from clin.test_type
1795 where loinc %(fragment_condition)s
1796 limit 50
1797 ) union all (
1798 select
1799 code as loinc,
1800 (code || ': ' || term) as term
1801 from ref.v_coded_terms
1802 where
1803 coding_system = 'LOINC'
1804 and
1805 lang = i18n.get_curr_lang()
1806 and
1807 (code %(fragment_condition)s
1808 or
1809 term %(fragment_condition)s)
1810 limit 50
1811 ) union all (
1812 select
1813 code as loinc,
1814 (code || ': ' || term) as term
1815 from ref.v_coded_terms
1816 where
1817 coding_system = 'LOINC'
1818 and
1819 lang = 'en_EN'
1820 and
1821 (code %(fragment_condition)s
1822 or
1823 term %(fragment_condition)s)
1824 limit 50
1825 ) union all (
1826 select
1827 code as loinc,
1828 (code || ': ' || term) as term
1829 from ref.v_coded_terms
1830 where
1831 coding_system = 'LOINC'
1832 and
1833 (code %(fragment_condition)s
1834 or
1835 term %(fragment_condition)s)
1836 limit 50
1837 )
1838 ) as all_known_loinc
1839 order by term
1840 limit 50"""
1841 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
1842 mp.setThresholds(1, 2, 4)
1843 self._PRW_loinc.matcher = mp
1844 self._PRW_loinc.selection_only = False
1845 self._PRW_loinc.add_callback_on_lose_focus(callback = self._on_loinc_lost_focus)
1846
1848
1849 test = self._PRW_name.GetValue().strip()
1850
1851 if test == u'':
1852 self._PRW_conversion_unit.unset_context(context = u'test_name')
1853 return
1854
1855 self._PRW_conversion_unit.set_context(context = u'test_name', val = test)
1856
1858 loinc = self._PRW_loinc.GetData()
1859
1860 if loinc is None:
1861 self._TCTRL_loinc_info.SetValue(u'')
1862 self._PRW_conversion_unit.unset_context(context = u'loinc')
1863 return
1864
1865 self._PRW_conversion_unit.set_context(context = u'loinc', val = loinc)
1866
1867 info = gmLOINC.loinc2info(loinc = loinc)
1868 if len(info) == 0:
1869 self._TCTRL_loinc_info.SetValue(u'')
1870 return
1871
1872 self._TCTRL_loinc_info.SetValue(info[0])
1873
1874
1875
1877
1878 has_errors = False
1879 for field in [self._PRW_name, self._PRW_abbrev, self._PRW_conversion_unit]:
1880 if field.GetValue().strip() in [u'', None]:
1881 has_errors = True
1882 field.display_as_valid(valid = False)
1883 else:
1884 field.display_as_valid(valid = True)
1885 field.Refresh()
1886
1887 return (not has_errors)
1888
1914
1936
1938 self._PRW_name.SetText(u'', None, True)
1939 self._on_name_lost_focus()
1940 self._PRW_abbrev.SetText(u'', None, True)
1941 self._PRW_conversion_unit.SetText(u'', None, True)
1942 self._PRW_loinc.SetText(u'', None, True)
1943 self._on_loinc_lost_focus()
1944 self._TCTRL_comment_type.SetValue(u'')
1945 self._PRW_test_org.SetText(u'', None, True)
1946 self._TCTRL_comment_org.SetValue(u'')
1947
1949 self._PRW_name.SetText(self.data['name'], self.data['name'], True)
1950 self._on_name_lost_focus()
1951 self._PRW_abbrev.SetText(self.data['abbrev'], self.data['abbrev'], True)
1952 self._PRW_conversion_unit.SetText (
1953 gmTools.coalesce(self.data['conversion_unit'], u''),
1954 self.data['conversion_unit'],
1955 True
1956 )
1957 self._PRW_loinc.SetText (
1958 gmTools.coalesce(self.data['loinc'], u''),
1959 self.data['loinc'],
1960 True
1961 )
1962 self._on_loinc_lost_focus()
1963 self._TCTRL_comment_type.SetValue(gmTools.coalesce(self.data['comment_type'], u''))
1964 self._PRW_test_org.SetText (
1965 gmTools.coalesce(self.data['pk_test_org'], u'', self.data['internal_name_org']),
1966 self.data['pk_test_org'],
1967 True
1968 )
1969 self._TCTRL_comment_org.SetValue(gmTools.coalesce(self.data['comment_org'], u''))
1970
1979
1981
1983
1984 query = u"""
1985
1986 SELECT DISTINCT ON (data) data, unit FROM (
1987
1988 SELECT rank, data, unit FROM (
1989
1990 (
1991 -- via clin.v_test_results.pk_type (for types already used in results)
1992 SELECT
1993 val_unit as data,
1994 val_unit || ' (' || name_tt || ')' as unit,
1995 1 as rank
1996 FROM
1997 clin.v_test_results
1998 WHERE
1999 (
2000 val_unit %(fragment_condition)s
2001 OR
2002 conversion_unit %(fragment_condition)s
2003 )
2004 %(ctxt_type_pk)s
2005 %(ctxt_test_name)s
2006
2007 ) UNION ALL (
2008
2009 -- via clin.test_type (for types not yet used in results)
2010 SELECT
2011 conversion_unit as data,
2012 conversion_unit || ' (' || name || ')' as unit,
2013 2 as rank
2014 FROM
2015 clin.test_type
2016 WHERE
2017 conversion_unit %(fragment_condition)s
2018 %(ctxt_ctt)s
2019
2020 ) UNION ALL (
2021
2022 -- via ref.loinc.ipcc_units
2023 SELECT
2024 ipcc_units as data,
2025 ipcc_units || ' (' || term || ')' as unit,
2026 3 as rank
2027 FROM
2028 ref.loinc
2029 WHERE
2030 ipcc_units %(fragment_condition)s
2031 %(ctxt_loinc)s
2032 %(ctxt_loinc_term)s
2033
2034 ) UNION ALL (
2035
2036 -- via ref.loinc.submitted_units
2037 SELECT
2038 submitted_units as data,
2039 submitted_units || ' (' || term || ')' as unit,
2040 3 as rank
2041 FROM
2042 ref.loinc
2043 WHERE
2044 submitted_units %(fragment_condition)s
2045 %(ctxt_loinc)s
2046 %(ctxt_loinc_term)s
2047
2048 ) UNION ALL (
2049
2050 -- via ref.loinc.example_units
2051 SELECT
2052 example_units as data,
2053 example_units || ' (' || term || ')' as unit,
2054 3 as rank
2055 FROM
2056 ref.loinc
2057 WHERE
2058 example_units %(fragment_condition)s
2059 %(ctxt_loinc)s
2060 %(ctxt_loinc_term)s
2061 )
2062
2063 ) as all_matching_units
2064
2065 WHERE data IS NOT NULL
2066 ORDER BY rank
2067
2068 ) as ranked_matching_units
2069
2070 LIMIT 50"""
2071
2072 ctxt = {
2073 'ctxt_type_pk': {
2074 'where_part': u'AND pk_test_type = %(pk_type)s',
2075 'placeholder': u'pk_type'
2076 },
2077 'ctxt_test_name': {
2078 'where_part': u'AND %(test_name)s IN (name_tt, name_meta, code_tt, abbrev_meta)',
2079 'placeholder': u'test_name'
2080 },
2081 'ctxt_ctt': {
2082 'where_part': u'AND %(test_name)s IN (name, code, abbrev)',
2083 'placeholder': u'test_name'
2084 },
2085 'ctxt_loinc': {
2086 'where_part': u'AND code = %(loinc)s',
2087 'placeholder': u'loinc'
2088 },
2089 'ctxt_loinc_term': {
2090 'where_part': u'AND term ~* %(test_name)s',
2091 'placeholder': u'test_name'
2092 }
2093 }
2094
2095 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query, context=ctxt)
2096 mp.setThresholds(1, 2, 4)
2097
2098 gmPhraseWheel.cPhraseWheel.__init__ (
2099 self,
2100 *args,
2101 **kwargs
2102 )
2103 self.matcher = mp
2104 self.SetToolTipString(_('Select the unit of the test result.'))
2105 self.selection_only = False
2106 self.phrase_separators = u'[;|]+'
2107
2108
2109
2111
2113
2114 query = u"""
2115 select distinct abnormality_indicator,
2116 abnormality_indicator, abnormality_indicator
2117 from clin.v_test_results
2118 where
2119 abnormality_indicator %(fragment_condition)s
2120 order by abnormality_indicator
2121 limit 25"""
2122
2123 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
2124 mp.setThresholds(1, 1, 2)
2125 mp.ignored_chars = "[.'\\\[\]#$%_]+" + '"'
2126 mp.word_separators = '[ \t&:]+'
2127 gmPhraseWheel.cPhraseWheel.__init__ (
2128 self,
2129 *args,
2130 **kwargs
2131 )
2132 self.matcher = mp
2133 self.SetToolTipString(_('Select an indicator for the level of abnormality.'))
2134 self.selection_only = False
2135
2136
2137
2149
2151
2152 if parent is None:
2153 parent = wx.GetApp().GetTopWindow()
2154
2155
2156 def edit(org=None):
2157 return edit_measurement_org(parent = parent, org = org)
2158
2159 def refresh(lctrl):
2160 orgs = gmPathLab.get_test_orgs()
2161 lctrl.set_string_items ([
2162 (o['internal_name'], gmTools.coalesce(o['contact'], u''), gmTools.coalesce(o['comment']), o['pk'])
2163 for o in orgs
2164 ])
2165 lctrl.set_data(orgs)
2166
2167 def delete(measurement_type):
2168 if measurement_type.in_use:
2169 gmDispatcher.send (
2170 signal = 'statustext',
2171 beep = True,
2172 msg = _('Cannot delete measurement type [%s (%s)] because it is in use.') % (measurement_type['name'], measurement_type['abbrev'])
2173 )
2174 return False
2175 gmPathLab.delete_measurement_type(measurement_type = measurement_type['pk_test_type'])
2176 return True
2177
2178 gmListWidgets.get_choices_from_list (
2179 parent = parent,
2180 msg = _('\nThese are the diagnostic orgs (path labs etc) currently defined in GNUmed.\n\n'),
2181 caption = _('Showing diagnostic orgs.'),
2182 columns = [_('Name'), _('Contact'), _('Comment'), u'#'],
2183 single_selection = True,
2184 refresh_callback = refresh,
2185 edit_callback = edit,
2186 new_callback = edit
2187
2188 )
2189
2190
2191
2192 from Gnumed.wxGladeWidgets import wxgMeasurementOrgEAPnl
2193
2194 -class cMeasurementOrgEAPnl(wxgMeasurementOrgEAPnl.wxgMeasurementOrgEAPnl, gmEditArea.cGenericEditAreaMixin):
2195
2213
2214
2215
2216
2217
2218
2219
2220
2222 has_errors = False
2223 if self._PRW_name.GetValue().strip() == u'':
2224 has_errors = True
2225 self._PRW_name.display_as_valid(valid = False)
2226 else:
2227 self._PRW_name.display_as_valid(valid = True)
2228
2229 return (not has_errors)
2230
2232
2233 data = self._PRW_name.GetData(can_create = True)
2234
2235 data['contact'] = self._TCTRL_contact.GetValue().strip()
2236 data['comment'] = self._TCTRL_comment.GetValue().strip()
2237 data.save()
2238
2239
2240
2241
2242 self.data = data
2243
2244 return True
2245
2247 self.data['internal_name'] = self._PRW_name.GetValue().strip()
2248 self.data['contact'] = self._TCTRL_contact.GetValue().strip()
2249 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
2250 self.data.save()
2251 return True
2252
2257
2262
2264 self._refresh_as_new()
2265
2304
2305
2306
2307 if __name__ == '__main__':
2308
2309 from Gnumed.pycommon import gmLog2
2310
2311 gmI18N.activate_locale()
2312 gmI18N.install_domain()
2313 gmDateTime.init()
2314
2315
2323
2331
2332
2333
2334
2335
2336
2337
2338 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
2339
2340 test_test_ea_pnl()
2341
2342
2343
2344