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
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
152 """A grid class for displaying measurment results.
153
154 - does NOT listen to the currently active patient
155 - thereby it can display any patient at any time
156 """
157
158
159
160
161
162
164
165 wx.grid.Grid.__init__(self, *args, **kwargs)
166
167 self.__patient = None
168 self.__cell_data = {}
169 self.__row_label_data = []
170
171 self.__prev_row = None
172 self.__prev_col = None
173 self.__prev_label_row = None
174 self.__date_format = str((_('lab_grid_date_format::%Y\n%b %d')).lstrip('lab_grid_date_format::'))
175
176 self.__init_ui()
177 self.__register_events()
178
179
180
182 if not self.IsSelection():
183 gmDispatcher.send(signal = u'statustext', msg = _('No results selected for deletion.'))
184 return True
185
186 selected_cells = self.get_selected_cells()
187 if len(selected_cells) > 20:
188 results = None
189 msg = _(
190 'There are %s results marked for deletion.\n'
191 '\n'
192 'Are you sure you want to delete these results ?'
193 ) % len(selected_cells)
194 else:
195 results = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
196 txt = u'\n'.join([ u'%s %s (%s): %s %s%s' % (
197 r['clin_when'].strftime('%x %H:%M').decode(gmI18N.get_encoding()),
198 r['unified_abbrev'],
199 r['unified_name'],
200 r['unified_val'],
201 r['val_unit'],
202 gmTools.coalesce(r['abnormality_indicator'], u'', u' (%s)')
203 ) for r in results
204 ])
205 msg = _(
206 'The following results are marked for deletion:\n'
207 '\n'
208 '%s\n'
209 '\n'
210 'Are you sure you want to delete these results ?'
211 ) % txt
212
213 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
214 self,
215 -1,
216 caption = _('Deleting test results'),
217 question = msg,
218 button_defs = [
219 {'label': _('Delete'), 'tooltip': _('Yes, delete all the results.'), 'default': False},
220 {'label': _('Cancel'), 'tooltip': _('No, do NOT delete any results.'), 'default': True}
221 ]
222 )
223 decision = dlg.ShowModal()
224
225 if decision == wx.ID_YES:
226 if results is None:
227 results = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
228 for result in results:
229 gmPathLab.delete_test_result(result)
230
232 if not self.IsSelection():
233 gmDispatcher.send(signal = u'statustext', msg = _('Cannot sign results. No results selected.'))
234 return True
235
236 selected_cells = self.get_selected_cells()
237 if len(selected_cells) > 10:
238 test_count = len(selected_cells)
239 tests = None
240 else:
241 test_count = None
242 tests = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
243
244 dlg = cMeasurementsReviewDlg (
245 self,
246 -1,
247 tests = tests,
248 test_count = test_count
249 )
250 decision = dlg.ShowModal()
251
252 if decision == wx.ID_APPLY:
253 wx.BeginBusyCursor()
254
255 if dlg._RBTN_confirm_abnormal.GetValue():
256 abnormal = None
257 elif dlg._RBTN_results_normal.GetValue():
258 abnormal = False
259 else:
260 abnormal = True
261
262 if dlg._RBTN_confirm_relevance.GetValue():
263 relevant = None
264 elif dlg._RBTN_results_not_relevant.GetValue():
265 relevant = False
266 else:
267 relevant = True
268
269 if tests is None:
270 tests = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
271
272 comment = None
273 if len(tests) == 1:
274 comment = dlg._TCTRL_comment.GetValue()
275
276 for test in tests:
277 test.set_review (
278 technically_abnormal = abnormal,
279 clinically_relevant = relevant,
280 comment = comment,
281 make_me_responsible = dlg._CHBOX_responsible.IsChecked()
282 )
283
284 wx.EndBusyCursor()
285
286 dlg.Destroy()
287
289
290 if not self.IsSelection():
291 gmDispatcher.send(signal = u'statustext', msg = _('Cannot plot results. No results selected.'))
292 return True
293
294 tests = self.__cells_to_data (
295 cells = self.get_selected_cells(),
296 exclude_multi_cells = False,
297 auto_include_multi_cells = True
298 )
299
300 plot_measurements(parent = self, tests = tests)
301
303
304 sel_block_top_left = self.GetSelectionBlockTopLeft()
305 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
306 sel_cols = self.GetSelectedCols()
307 sel_rows = self.GetSelectedRows()
308
309 selected_cells = []
310
311
312 selected_cells += self.GetSelectedCells()
313
314
315 selected_cells += list (
316 (row, col)
317 for row in sel_rows
318 for col in xrange(self.GetNumberCols())
319 )
320
321
322 selected_cells += list (
323 (row, col)
324 for row in xrange(self.GetNumberRows())
325 for col in sel_cols
326 )
327
328
329 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
330 selected_cells += [
331 (row, col)
332 for row in xrange(top_left[0], bottom_right[0] + 1)
333 for col in xrange(top_left[1], bottom_right[1] + 1)
334 ]
335
336 return set(selected_cells)
337
338 - def select_cells(self, unsigned_only=False, accountables_only=False, keep_preselections=False):
339 """Select a range of cells according to criteria.
340
341 unsigned_only: include only those which are not signed at all yet
342 accountable_only: include only those for which the current user is responsible
343 keep_preselections: broaden (rather than replace) the range of selected cells
344
345 Combinations are powerful !
346 """
347 wx.BeginBusyCursor()
348 self.BeginBatch()
349
350 if not keep_preselections:
351 self.ClearSelection()
352
353 for col_idx in self.__cell_data.keys():
354 for row_idx in self.__cell_data[col_idx].keys():
355
356
357 do_not_include = False
358 for result in self.__cell_data[col_idx][row_idx]:
359 if unsigned_only:
360 if result['reviewed']:
361 do_not_include = True
362 break
363 if accountables_only:
364 if not result['you_are_responsible']:
365 do_not_include = True
366 break
367 if do_not_include:
368 continue
369
370 self.SelectBlock(row_idx, col_idx, row_idx, col_idx, addToSelected = True)
371
372 self.EndBatch()
373 wx.EndBusyCursor()
374
376
377 self.empty_grid()
378 if self.__patient is None:
379 return
380
381 emr = self.__patient.get_emr()
382
383 self.__row_label_data = emr.get_test_types_for_results()
384 test_type_labels = [ u'%s (%s)' % (test['unified_abbrev'], test['unified_name']) for test in self.__row_label_data ]
385 if len(test_type_labels) == 0:
386 return
387
388 test_date_labels = [ date[0].strftime(self.__date_format) for date in emr.get_dates_for_results() ]
389 results = emr.get_test_results_by_date()
390
391 self.BeginBatch()
392
393
394 self.AppendRows(numRows = len(test_type_labels))
395 for row_idx in range(len(test_type_labels)):
396 self.SetRowLabelValue(row_idx, test_type_labels[row_idx])
397
398
399 self.AppendCols(numCols = len(test_date_labels))
400 for date_idx in range(len(test_date_labels)):
401 self.SetColLabelValue(date_idx, test_date_labels[date_idx])
402
403
404 for result in results:
405 row = test_type_labels.index(u'%s (%s)' % (result['unified_abbrev'], result['unified_name']))
406 col = test_date_labels.index(result['clin_when'].strftime(self.__date_format))
407
408 try:
409 self.__cell_data[col]
410 except KeyError:
411 self.__cell_data[col] = {}
412
413
414 if self.__cell_data[col].has_key(row):
415 self.__cell_data[col][row].append(result)
416 self.__cell_data[col][row].sort(key = lambda x: x['clin_when'], reverse = True)
417 else:
418 self.__cell_data[col][row] = [result]
419
420
421 vals2display = []
422 for sub_result in self.__cell_data[col][row]:
423
424
425 ind = gmTools.coalesce(sub_result['abnormality_indicator'], u'').strip()
426 if ind != u'':
427 lab_abnormality_indicator = u' (%s)' % ind[:3]
428 else:
429 lab_abnormality_indicator = u''
430
431 if sub_result['is_technically_abnormal'] is None:
432 abnormality_indicator = lab_abnormality_indicator
433
434 elif sub_result['is_technically_abnormal'] is False:
435 abnormality_indicator = u''
436
437 else:
438
439 if lab_abnormality_indicator == u'':
440
441 abnormality_indicator = u' (%s)' % gmTools.u_plus_minus
442
443 else:
444 abnormality_indicator = lab_abnormality_indicator
445
446
447
448 sub_result_relevant = sub_result['is_clinically_relevant']
449 if sub_result_relevant is None:
450
451 sub_result_relevant = False
452
453 missing_review = False
454
455
456 if not sub_result['reviewed']:
457 missing_review = True
458
459 else:
460
461 if sub_result['you_are_responsible'] and not sub_result['review_by_you']:
462 missing_review = True
463
464
465 if len(sub_result['unified_val']) > 8:
466 tmp = u'%.7s%s' % (sub_result['unified_val'][:7], gmTools.u_ellipsis)
467 else:
468 tmp = u'%.8s' % sub_result['unified_val'][:8]
469
470
471 tmp = u'%s%.6s' % (tmp, abnormality_indicator)
472
473
474 has_sub_result_comment = gmTools.coalesce (
475 gmTools.coalesce(sub_result['note_test_org'], sub_result['comment']),
476 u''
477 ).strip() != u''
478 if has_sub_result_comment:
479 tmp = u'%s %s' % (tmp, gmTools.u_ellipsis)
480
481
482 if missing_review:
483 tmp = u'%s %s' % (tmp, gmTools.u_writing_hand)
484
485
486 if len(self.__cell_data[col][row]) > 1:
487 tmp = u'%s %s' % (sub_result['clin_when'].strftime('%H:%M'), tmp)
488
489 vals2display.append(tmp)
490
491 self.SetCellValue(row, col, u'\n'.join(vals2display))
492 self.SetCellAlignment(row, col, horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
493
494
495
496
497 if sub_result_relevant:
498 font = self.GetCellFont(row, col)
499 self.SetCellTextColour(row, col, 'firebrick')
500 font.SetWeight(wx.FONTWEIGHT_BOLD)
501 self.SetCellFont(row, col, font)
502
503
504 self.AutoSize()
505 self.EndBatch()
506 return
507
509 self.BeginBatch()
510 self.ClearGrid()
511
512
513 if self.GetNumberRows() > 0:
514 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
515 if self.GetNumberCols() > 0:
516 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
517 self.EndBatch()
518 self.__cell_data = {}
519 self.__row_label_data = []
520
559
807
808
809
811 self.CreateGrid(0, 1)
812 self.EnableEditing(0)
813 self.EnableDragGridSize(1)
814
815
816
817
818
819 self.SetRowLabelSize(150)
820 self.SetRowLabelAlignment(horiz = wx.ALIGN_LEFT, vert = wx.ALIGN_CENTRE)
821
822
823 dbcfg = gmCfg.cCfgSQL()
824 url = dbcfg.get2 (
825 option = u'external.urls.measurements_encyclopedia',
826 workplace = gmSurgery.gmCurrentPractice().active_workplace,
827 bias = 'user',
828 default = u'http://www.laborlexikon.de'
829 )
830
831 self.__WIN_corner = self.GetGridCornerLabelWindow()
832
833 LNK_lab = wx.lib.hyperlink.HyperLinkCtrl (
834 self.__WIN_corner,
835 -1,
836 label = _('Reference'),
837 style = wx.HL_DEFAULT_STYLE
838 )
839 LNK_lab.SetURL(url)
840 LNK_lab.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BACKGROUND))
841 LNK_lab.SetToolTipString(_(
842 'Navigate to an encyclopedia of measurements\n'
843 'and test methods on the web.\n'
844 '\n'
845 ' <%s>'
846 ) % url)
847
848 SZR_inner = wx.BoxSizer(wx.HORIZONTAL)
849 SZR_inner.Add((20, 20), 1, wx.EXPAND, 0)
850 SZR_inner.Add(LNK_lab, 0, wx.ALIGN_CENTER_VERTICAL, 0)
851 SZR_inner.Add((20, 20), 1, wx.EXPAND, 0)
852
853 SZR_corner = wx.BoxSizer(wx.VERTICAL)
854 SZR_corner.Add((20, 20), 1, wx.EXPAND, 0)
855 SZR_corner.AddWindow(SZR_inner, 0, wx.EXPAND)
856 SZR_corner.Add((20, 20), 1, wx.EXPAND, 0)
857
858 self.__WIN_corner.SetSizer(SZR_corner)
859 SZR_corner.Fit(self.__WIN_corner)
860
862 self.__WIN_corner.Layout()
863
864 - def __cells_to_data(self, cells=None, exclude_multi_cells=False, auto_include_multi_cells=False):
865 """List of <cells> must be in row / col order."""
866 data = []
867 for row, col in cells:
868 try:
869
870 data_list = self.__cell_data[col][row]
871 except KeyError:
872 continue
873
874 if len(data_list) == 1:
875 data.append(data_list[0])
876 continue
877
878 if exclude_multi_cells:
879 gmDispatcher.send(signal = u'statustext', msg = _('Excluding multi-result field from further processing.'))
880 continue
881
882 if auto_include_multi_cells:
883 data.extend(data_list)
884 continue
885
886 data_to_include = self.__get_choices_from_multi_cell(cell_data = data_list)
887 if data_to_include is None:
888 continue
889 data.extend(data_to_include)
890
891 return data
892
894 data = gmListWidgets.get_choices_from_list (
895 parent = self,
896 msg = _(
897 'Your selection includes a field with multiple results.\n'
898 '\n'
899 'Please select the individual results you want to work on:'
900 ),
901 caption = _('Selecting test results'),
902 choices = [ [d['clin_when'], d['unified_abbrev'], d['unified_name'], d['unified_val']] for d in cell_data ],
903 columns = [_('Date / Time'), _('Code'), _('Test'), _('Result')],
904 data = cell_data,
905 single_selection = single_selection
906 )
907 return data
908
909
910
912
913 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
914 self.GetGridRowLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_row_labels)
915
916
917
918 self.Bind(wx.EVT_SIZE, self.__resize_corner_window)
919
920
921 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
922
924 col = evt.GetCol()
925 row = evt.GetRow()
926
927
928 try:
929 self.__cell_data[col][row]
930 except KeyError:
931
932
933 return
934
935 if len(self.__cell_data[col][row]) > 1:
936 data = self.__get_choices_from_multi_cell(cell_data = self.__cell_data[col][row], single_selection = True)
937 else:
938 data = self.__cell_data[col][row][0]
939
940 if data is None:
941 return
942
943 edit_measurement(parent = self, measurement = data, single_entry = True)
944
945
946
947
948
949
950
952
953
954
955 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
956
957 row = self.YToRow(y)
958
959 if self.__prev_label_row == row:
960 return
961
962 self.__prev_label_row == row
963
964 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
965
966
967
968
969
970
971
972
974 """Calculate where the mouse is and set the tooltip dynamically."""
975
976
977
978 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
979
980
981
982
983
984
985
986
987
988
989
990
991
992 row, col = self.XYToCell(x, y)
993
994 if (row == self.__prev_row) and (col == self.__prev_col):
995 return
996
997 self.__prev_row = row
998 self.__prev_col = col
999
1000 evt.GetEventObject().SetToolTipString(self.get_cell_tooltip(col=col, row=row))
1001
1002
1003
1007
1008 patient = property(lambda x:x, _set_patient)
1009
1010 -class cMeasurementsPnl(wxgMeasurementsPnl.wxgMeasurementsPnl, gmRegetMixin.cRegetOnPaintMixin):
1011
1012 """Panel holding a grid with lab data. Used as notebook page."""
1013
1020
1021
1022
1024 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
1025 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
1026 gmDispatcher.connect(signal = u'test_result_mod_db', receiver = self._schedule_data_reget)
1027 gmDispatcher.connect(signal = u'reviewed_test_results_mod_db', receiver = self._schedule_data_reget)
1028
1030 wx.CallAfter(self.__on_post_patient_selection)
1031
1033 self._schedule_data_reget()
1034
1036 wx.CallAfter(self.__on_pre_patient_selection)
1037
1040
1043
1049
1052
1055
1058
1059
1060
1062 self.__action_button_popup = wx.Menu(title = _('Act on selected results'))
1063
1064 menu_id = wx.NewId()
1065 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Review and &sign')))
1066 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_sign_current_selection)
1067
1068 menu_id = wx.NewId()
1069 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Plot')))
1070 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_plot_current_selection)
1071
1072 menu_id = wx.NewId()
1073 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Export to &file')))
1074
1075 self.__action_button_popup.Enable(id = menu_id, enable = False)
1076
1077 menu_id = wx.NewId()
1078 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Export to &clipboard')))
1079
1080 self.__action_button_popup.Enable(id = menu_id, enable = False)
1081
1082 menu_id = wx.NewId()
1083 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('&Delete')))
1084 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_delete_current_selection)
1085
1086
1087
1096
1097
1098
1100
1102
1103 try:
1104 tests = kwargs['tests']
1105 del kwargs['tests']
1106 test_count = len(tests)
1107 try: del kwargs['test_count']
1108 except KeyError: pass
1109 except KeyError:
1110 tests = None
1111 test_count = kwargs['test_count']
1112 del kwargs['test_count']
1113
1114 wxgMeasurementsReviewDlg.wxgMeasurementsReviewDlg.__init__(self, *args, **kwargs)
1115
1116 if tests is None:
1117 msg = _('%s results selected. Too many to list individually.') % test_count
1118 else:
1119 msg = ' // '.join (
1120 [ u'%s: %s %s (%s)' % (
1121 t['unified_abbrev'],
1122 t['unified_val'],
1123 t['val_unit'],
1124 t['clin_when'].strftime('%x').decode(gmI18N.get_encoding())
1125 ) for t in tests
1126 ]
1127 )
1128
1129 self._LBL_tests.SetLabel(msg)
1130
1131 if test_count == 1:
1132 self._TCTRL_comment.Enable(True)
1133 self._TCTRL_comment.SetValue(gmTools.coalesce(tests[0]['review_comment'], u''))
1134 if tests[0]['you_are_responsible']:
1135 self._CHBOX_responsible.Enable(False)
1136
1137 self.Fit()
1138
1139
1140
1146
1147 -class cMeasurementEditAreaPnl(wxgMeasurementEditAreaPnl.wxgMeasurementEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
1148 """This edit area saves *new* measurements into the active patient only."""
1149
1164
1165
1166
1168 self._PRW_test.SetText(u'', None, True)
1169 self.__refresh_loinc_info()
1170 self.__update_units_context()
1171 self._TCTRL_result.SetValue(u'')
1172 self._PRW_units.SetText(u'', None, True)
1173 self._PRW_abnormality_indicator.SetText(u'', None, True)
1174 if self.__default_date is None:
1175 self._DPRW_evaluated.SetData(data = pyDT.datetime.now(tz = gmDateTime.gmCurrentLocalTimezone))
1176 else:
1177 self._DPRW_evaluated.SetData(data = None)
1178 self._TCTRL_note_test_org.SetValue(u'')
1179 self._PRW_intended_reviewer.SetData()
1180 self._PRW_problem.SetData()
1181 self._TCTRL_narrative.SetValue(u'')
1182 self._CHBOX_review.SetValue(False)
1183 self._CHBOX_abnormal.SetValue(False)
1184 self._CHBOX_relevant.SetValue(False)
1185 self._CHBOX_abnormal.Enable(False)
1186 self._CHBOX_relevant.Enable(False)
1187 self._TCTRL_review_comment.SetValue(u'')
1188 self._TCTRL_normal_min.SetValue(u'')
1189 self._TCTRL_normal_max.SetValue(u'')
1190 self._TCTRL_normal_range.SetValue(u'')
1191 self._TCTRL_target_min.SetValue(u'')
1192 self._TCTRL_target_max.SetValue(u'')
1193 self._TCTRL_target_range.SetValue(u'')
1194 self._TCTRL_norm_ref_group.SetValue(u'')
1195
1196 self._PRW_test.SetFocus()
1197
1199 self._PRW_test.SetData(data = self.data['pk_test_type'])
1200 self.__refresh_loinc_info()
1201 self.__update_units_context()
1202 self._TCTRL_result.SetValue(self.data['unified_val'])
1203 self._PRW_units.SetText(self.data['val_unit'], self.data['val_unit'], True)
1204 self._PRW_abnormality_indicator.SetText (
1205 gmTools.coalesce(self.data['abnormality_indicator'], u''),
1206 gmTools.coalesce(self.data['abnormality_indicator'], u''),
1207 True
1208 )
1209 self._DPRW_evaluated.SetData(data = self.data['clin_when'])
1210 self._TCTRL_note_test_org.SetValue(gmTools.coalesce(self.data['note_test_org'], u''))
1211 self._PRW_intended_reviewer.SetData(self.data['pk_intended_reviewer'])
1212 self._PRW_problem.SetData(self.data['pk_episode'])
1213 self._TCTRL_narrative.SetValue(gmTools.coalesce(self.data['comment'], u''))
1214 self._CHBOX_review.SetValue(False)
1215 self._CHBOX_abnormal.SetValue(gmTools.coalesce(self.data['is_technically_abnormal'], False))
1216 self._CHBOX_relevant.SetValue(gmTools.coalesce(self.data['is_clinically_relevant'], False))
1217 self._CHBOX_abnormal.Enable(False)
1218 self._CHBOX_relevant.Enable(False)
1219 self._TCTRL_review_comment.SetValue(gmTools.coalesce(self.data['review_comment'], u''))
1220 self._TCTRL_normal_min.SetValue(unicode(gmTools.coalesce(self.data['val_normal_min'], u'')))
1221 self._TCTRL_normal_max.SetValue(unicode(gmTools.coalesce(self.data['val_normal_max'], u'')))
1222 self._TCTRL_normal_range.SetValue(gmTools.coalesce(self.data['val_normal_range'], u''))
1223 self._TCTRL_target_min.SetValue(unicode(gmTools.coalesce(self.data['val_target_min'], u'')))
1224 self._TCTRL_target_max.SetValue(unicode(gmTools.coalesce(self.data['val_target_max'], u'')))
1225 self._TCTRL_target_range.SetValue(gmTools.coalesce(self.data['val_target_range'], u''))
1226 self._TCTRL_norm_ref_group.SetValue(gmTools.coalesce(self.data['norm_ref_group'], u''))
1227
1228 self._TCTRL_result.SetFocus()
1229
1231 self._refresh_from_existing()
1232
1233 self._PRW_test.SetText(u'', None, True)
1234 self.__refresh_loinc_info()
1235 self.__update_units_context()
1236 self._TCTRL_result.SetValue(u'')
1237 self._PRW_units.SetText(u'', None, True)
1238 self._PRW_abnormality_indicator.SetText(u'', None, True)
1239
1240 self._TCTRL_note_test_org.SetValue(u'')
1241 self._TCTRL_narrative.SetValue(u'')
1242 self._CHBOX_review.SetValue(False)
1243 self._CHBOX_abnormal.SetValue(False)
1244 self._CHBOX_relevant.SetValue(False)
1245 self._CHBOX_abnormal.Enable(False)
1246 self._CHBOX_relevant.Enable(False)
1247 self._TCTRL_review_comment.SetValue(u'')
1248 self._TCTRL_normal_min.SetValue(u'')
1249 self._TCTRL_normal_max.SetValue(u'')
1250 self._TCTRL_normal_range.SetValue(u'')
1251 self._TCTRL_target_min.SetValue(u'')
1252 self._TCTRL_target_max.SetValue(u'')
1253 self._TCTRL_target_range.SetValue(u'')
1254 self._TCTRL_norm_ref_group.SetValue(u'')
1255
1256 self._PRW_test.SetFocus()
1257
1259
1260 validity = True
1261
1262 if not self._DPRW_evaluated.is_valid_timestamp():
1263 self._DPRW_evaluated.display_as_valid(False)
1264 validity = False
1265 else:
1266 self._DPRW_evaluated.display_as_valid(True)
1267
1268 if self._TCTRL_result.GetValue().strip() == u'':
1269 self._TCTRL_result.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
1270 validity = False
1271 else:
1272 self._TCTRL_result.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
1273
1274 if self._PRW_problem.GetValue().strip() == u'':
1275 self._PRW_problem.display_as_valid(False)
1276 validity = False
1277 else:
1278 self._PRW_problem.display_as_valid(True)
1279
1280 if self._PRW_test.GetValue().strip() == u'':
1281 self._PRW_test.display_as_valid(False)
1282 validity = False
1283 else:
1284 self._PRW_test.display_as_valid(True)
1285
1286 if self._PRW_intended_reviewer.GetData() is None:
1287 self._PRW_intended_reviewer.display_as_valid(False)
1288 validity = False
1289 else:
1290 self._PRW_intended_reviewer.display_as_valid(True)
1291
1292 if self._PRW_units.GetValue().strip() == u'':
1293 self._PRW_units.display_as_valid(False)
1294 validity = False
1295 else:
1296 self._PRW_units.display_as_valid(True)
1297
1298 ctrls = [self._TCTRL_normal_min, self._TCTRL_normal_max, self._TCTRL_target_min, self._TCTRL_target_max]
1299 for widget in ctrls:
1300 val = widget.GetValue().strip()
1301 if val == u'':
1302 continue
1303 try:
1304 decimal.Decimal(val.replace(',', u'.', 1))
1305 widget.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
1306 except:
1307 widget.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
1308 validity = False
1309
1310 if validity is False:
1311 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save result. Invalid or missing essential input.'))
1312
1313 return validity
1314
1316
1317 emr = gmPerson.gmCurrentPatient().get_emr()
1318
1319 try:
1320 v_num = decimal.Decimal(self._TCTRL_result.GetValue().strip().replace(',', '.', 1))
1321 v_al = None
1322 except:
1323 v_num = None
1324 v_al = self._TCTRL_result.GetValue().strip()
1325
1326 pk_type = self._PRW_test.GetData()
1327 if pk_type is None:
1328 tt = gmPathLab.create_measurement_type (
1329 lab = None,
1330 abbrev = self._PRW_test.GetValue().strip(),
1331 name = self._PRW_test.GetValue().strip(),
1332 unit = gmTools.coalesce(self._PRW_units.GetData(), self._PRW_units.GetValue()).strip()
1333 )
1334 pk_type = tt['pk_test_type']
1335
1336 tr = emr.add_test_result (
1337 episode = self._PRW_problem.GetData(can_create=True, is_open=False),
1338 type = pk_type,
1339 intended_reviewer = self._PRW_intended_reviewer.GetData(),
1340 val_num = v_num,
1341 val_alpha = v_al,
1342 unit = self._PRW_units.GetValue()
1343 )
1344
1345 tr['clin_when'] = self._DPRW_evaluated.GetData().get_pydt()
1346
1347 ctrls = [
1348 ('abnormality_indicator', self._PRW_abnormality_indicator),
1349 ('note_test_org', self._TCTRL_note_test_org),
1350 ('comment', self._TCTRL_narrative),
1351 ('val_normal_range', self._TCTRL_normal_range),
1352 ('val_target_range', self._TCTRL_target_range),
1353 ('norm_ref_group', self._TCTRL_norm_ref_group)
1354 ]
1355 for field, widget in ctrls:
1356 tr[field] = widget.GetValue().strip()
1357
1358 ctrls = [
1359 ('val_normal_min', self._TCTRL_normal_min),
1360 ('val_normal_max', self._TCTRL_normal_max),
1361 ('val_target_min', self._TCTRL_target_min),
1362 ('val_target_max', self._TCTRL_target_max)
1363 ]
1364 for field, widget in ctrls:
1365 val = widget.GetValue().strip()
1366 if val == u'':
1367 tr[field] = None
1368 else:
1369 tr[field] = decimal.Decimal(val.replace(',', u'.', 1))
1370
1371 tr.save_payload()
1372
1373 if self._CHBOX_review.GetValue() is True:
1374 tr.set_review (
1375 technically_abnormal = self._CHBOX_abnormal.GetValue(),
1376 clinically_relevant = self._CHBOX_relevant.GetValue(),
1377 comment = gmTools.none_if(self._TCTRL_review_comment.GetValue().strip(), u''),
1378 make_me_responsible = False
1379 )
1380
1381 self.data = tr
1382
1383 return True
1384
1386
1387 success, result = gmTools.input2decimal(self._TCTRL_result.GetValue())
1388 if success:
1389 v_num = result
1390 v_al = None
1391 else:
1392 v_num = None
1393 v_al = self._TCTRL_result.GetValue().strip()
1394
1395 pk_type = self._PRW_test.GetData()
1396 if pk_type is None:
1397 tt = gmPathLab.create_measurement_type (
1398 lab = None,
1399 abbrev = self._PRW_test.GetValue().strip(),
1400 name = self._PRW_test.GetValue().strip(),
1401 unit = gmTools.none_if(self._PRW_units.GetValue().strip(), u'')
1402 )
1403 pk_type = tt['pk_test_type']
1404
1405 tr = self.data
1406
1407 tr['pk_episode'] = self._PRW_problem.GetData(can_create=True, is_open=False)
1408 tr['pk_test_type'] = pk_type
1409 tr['pk_intended_reviewer'] = self._PRW_intended_reviewer.GetData()
1410 tr['val_num'] = v_num
1411 tr['val_alpha'] = v_al
1412 tr['val_unit'] = gmTools.coalesce(self._PRW_units.GetData(), self._PRW_units.GetValue()).strip()
1413 tr['clin_when'] = self._DPRW_evaluated.GetData().get_pydt()
1414
1415 ctrls = [
1416 ('abnormality_indicator', self._PRW_abnormality_indicator),
1417 ('note_test_org', self._TCTRL_note_test_org),
1418 ('comment', self._TCTRL_narrative),
1419 ('val_normal_range', self._TCTRL_normal_range),
1420 ('val_target_range', self._TCTRL_target_range),
1421 ('norm_ref_group', self._TCTRL_norm_ref_group)
1422 ]
1423 for field, widget in ctrls:
1424 tr[field] = widget.GetValue().strip()
1425
1426 ctrls = [
1427 ('val_normal_min', self._TCTRL_normal_min),
1428 ('val_normal_max', self._TCTRL_normal_max),
1429 ('val_target_min', self._TCTRL_target_min),
1430 ('val_target_max', self._TCTRL_target_max)
1431 ]
1432 for field, widget in ctrls:
1433 val = widget.GetValue().strip()
1434 if val == u'':
1435 tr[field] = None
1436 else:
1437 tr[field] = decimal.Decimal(val.replace(',', u'.', 1))
1438
1439 tr.save_payload()
1440
1441 if self._CHBOX_review.GetValue() is True:
1442 tr.set_review (
1443 technically_abnormal = self._CHBOX_abnormal.GetValue(),
1444 clinically_relevant = self._CHBOX_relevant.GetValue(),
1445 comment = gmTools.none_if(self._TCTRL_review_comment.GetValue().strip(), u''),
1446 make_me_responsible = False
1447 )
1448
1449 return True
1450
1451
1452
1456
1458 self.__refresh_loinc_info()
1459 self.__update_units_context()
1460
1462
1463 if not self._CHBOX_review.GetValue():
1464 self._CHBOX_abnormal.SetValue(self._PRW_abnormality_indicator.GetValue().strip() != u'')
1465
1467 self._CHBOX_abnormal.Enable(self._CHBOX_review.GetValue())
1468 self._CHBOX_relevant.Enable(self._CHBOX_review.GetValue())
1469 self._TCTRL_review_comment.Enable(self._CHBOX_review.GetValue())
1470
1487
1488
1489
1491
1492 self._PRW_units.unset_context(context = u'loinc')
1493
1494 tt = self._PRW_test.GetData(as_instance = True)
1495
1496 if tt is None:
1497 self._PRW_units.unset_context(context = u'pk_type')
1498 if self._PRW_test.GetValue().strip() == u'':
1499 self._PRW_units.unset_context(context = u'test_name')
1500 else:
1501 self._PRW_units.set_context(context = u'test_name', val = self._PRW_test.GetValue().strip())
1502 return
1503
1504 self._PRW_units.set_context(context = u'pk_type', val = tt['pk_test_type'])
1505 self._PRW_units.set_context(context = u'test_name', val = tt['name'])
1506
1507 if tt['loinc'] is None:
1508 return
1509
1510 self._PRW_units.set_context(context = u'loinc', val = tt['loinc'])
1511
1513
1514 self._TCTRL_loinc.SetValue(u'')
1515
1516 if self._PRW_test.GetData() is None:
1517 return
1518
1519 tt = self._PRW_test.GetData(as_instance = True)
1520
1521 if tt['loinc'] is None:
1522 return
1523
1524 info = gmLOINC.loinc2info(loinc = tt['loinc'])
1525 if len(info) == 0:
1526 return
1527
1528 self._TCTRL_loinc.SetValue(u'%s: %s' % (tt['loinc'], info[0]))
1529
1530
1531
1533
1534 if parent is None:
1535 parent = wx.GetApp().GetTopWindow()
1536
1537
1538 def edit(test_type=None):
1539 ea = cMeasurementTypeEAPnl(parent = parent, id = -1, type = test_type)
1540 dlg = gmEditArea.cGenericEditAreaDlg2 (
1541 parent = parent,
1542 id = -1,
1543 edit_area = ea,
1544 single_entry = gmTools.bool2subst((test_type is None), False, True)
1545 )
1546 dlg.SetTitle(gmTools.coalesce(test_type, _('Adding measurement type'), _('Editing measurement type')))
1547
1548 if dlg.ShowModal() == wx.ID_OK:
1549 dlg.Destroy()
1550 return True
1551
1552 dlg.Destroy()
1553 return False
1554
1555 def refresh(lctrl):
1556 mtypes = gmPathLab.get_measurement_types(order_by = 'name, abbrev')
1557 items = [ [
1558 m['abbrev'],
1559 m['name'],
1560 gmTools.coalesce(m['loinc'], u''),
1561 gmTools.coalesce(m['conversion_unit'], u''),
1562 gmTools.coalesce(m['comment_type'], u''),
1563 gmTools.coalesce(m['internal_name_org'], _('in-house')),
1564 gmTools.coalesce(m['comment_org'], u''),
1565 m['pk_test_type']
1566 ] for m in mtypes ]
1567 lctrl.set_string_items(items)
1568 lctrl.set_data(mtypes)
1569
1570 def delete(measurement_type):
1571 if measurement_type.in_use:
1572 gmDispatcher.send (
1573 signal = 'statustext',
1574 beep = True,
1575 msg = _('Cannot delete measurement type [%s (%s)] because it is in use.') % (measurement_type['name'], measurement_type['abbrev'])
1576 )
1577 return False
1578 gmPathLab.delete_measurement_type(measurement_type = measurement_type['pk_test_type'])
1579 return True
1580
1581 msg = _(
1582 '\n'
1583 'These are the measurement types currently defined in GNUmed.\n'
1584 '\n'
1585 )
1586
1587 gmListWidgets.get_choices_from_list (
1588 parent = parent,
1589 msg = msg,
1590 caption = _('Showing measurement types.'),
1591 columns = [_('Abbrev'), _('Name'), _('LOINC'), _('Base unit'), _('Comment'), _('Org'), _('Comment'), u'#'],
1592 single_selection = True,
1593 refresh_callback = refresh,
1594 edit_callback = edit,
1595 new_callback = edit,
1596 delete_callback = delete
1597 )
1598
1600
1602
1603 query = u"""
1604 (
1605 select
1606 pk_test_type,
1607 name_tt
1608 || ' ('
1609 || coalesce (
1610 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1611 '%(in_house)s'
1612 )
1613 || ')'
1614 as name
1615 from clin.v_unified_test_types vcutt
1616 where
1617 name_meta %%(fragment_condition)s
1618
1619 ) union (
1620
1621 select
1622 pk_test_type,
1623 name_tt
1624 || ' ('
1625 || coalesce (
1626 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1627 '%(in_house)s'
1628 )
1629 || ')'
1630 as name
1631 from clin.v_unified_test_types vcutt
1632 where
1633 name_tt %%(fragment_condition)s
1634
1635 ) union (
1636
1637 select
1638 pk_test_type,
1639 name_tt
1640 || ' ('
1641 || coalesce (
1642 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1643 '%(in_house)s'
1644 )
1645 || ')'
1646 as name
1647 from clin.v_unified_test_types vcutt
1648 where
1649 abbrev_meta %%(fragment_condition)s
1650
1651 ) union (
1652
1653 select
1654 pk_test_type,
1655 name_tt
1656 || ' ('
1657 || coalesce (
1658 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1659 '%(in_house)s'
1660 )
1661 || ')'
1662 as name
1663 from clin.v_unified_test_types vcutt
1664 where
1665 code_tt %%(fragment_condition)s
1666 )
1667
1668 order by name
1669 limit 50""" % {'in_house': _('in house lab')}
1670
1671 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1672 mp.setThresholds(1, 2, 4)
1673 mp.word_separators = '[ \t:@]+'
1674 gmPhraseWheel.cPhraseWheel.__init__ (
1675 self,
1676 *args,
1677 **kwargs
1678 )
1679 self.matcher = mp
1680 self.SetToolTipString(_('Select the type of measurement.'))
1681 self.selection_only = False
1682
1688
1690
1692
1693 query = u"""
1694 select distinct on (internal_name)
1695 pk,
1696 internal_name
1697 from clin.test_org
1698 where
1699 internal_name %(fragment_condition)s
1700 order by internal_name
1701 limit 50"""
1702 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1703 mp.setThresholds(1, 2, 4)
1704
1705 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1706 self.matcher = mp
1707 self.SetToolTipString(_('The name of the path lab/diagnostic organisation.'))
1708 self.selection_only = False
1709
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 unit of the test result.'))
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)
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