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