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._TCTRL_result.SetValue(u'')
1170 self._PRW_units.SetText(u'', None, True)
1171 self._PRW_abnormality_indicator.SetText(u'', None, True)
1172 if self.__default_date is None:
1173 self._DPRW_evaluated.SetData(data = pyDT.datetime.now(tz = gmDateTime.gmCurrentLocalTimezone))
1174 else:
1175 self._DPRW_evaluated.SetData(data = None)
1176 self._TCTRL_note_test_org.SetValue(u'')
1177 self._PRW_intended_reviewer.SetData()
1178 self._PRW_problem.SetData()
1179 self._TCTRL_narrative.SetValue(u'')
1180 self._CHBOX_review.SetValue(False)
1181 self._CHBOX_abnormal.SetValue(False)
1182 self._CHBOX_relevant.SetValue(False)
1183 self._CHBOX_abnormal.Enable(False)
1184 self._CHBOX_relevant.Enable(False)
1185 self._TCTRL_review_comment.SetValue(u'')
1186 self._TCTRL_normal_min.SetValue(u'')
1187 self._TCTRL_normal_max.SetValue(u'')
1188 self._TCTRL_normal_range.SetValue(u'')
1189 self._TCTRL_target_min.SetValue(u'')
1190 self._TCTRL_target_max.SetValue(u'')
1191 self._TCTRL_target_range.SetValue(u'')
1192 self._TCTRL_norm_ref_group.SetValue(u'')
1193
1194 self._PRW_test.SetFocus()
1195
1197 self._PRW_test.SetData(data = self.data['pk_test_type'])
1198 self._TCTRL_result.SetValue(self.data['unified_val'])
1199 self._PRW_units.SetText(self.data['val_unit'], self.data['val_unit'], True)
1200 self._PRW_abnormality_indicator.SetText (
1201 gmTools.coalesce(self.data['abnormality_indicator'], u''),
1202 gmTools.coalesce(self.data['abnormality_indicator'], u''),
1203 True
1204 )
1205 self._DPRW_evaluated.SetData(data = self.data['clin_when'])
1206 self._TCTRL_note_test_org.SetValue(gmTools.coalesce(self.data['note_test_org'], u''))
1207 self._PRW_intended_reviewer.SetData(self.data['pk_intended_reviewer'])
1208 self._PRW_problem.SetData(self.data['pk_episode'])
1209 self._TCTRL_narrative.SetValue(gmTools.coalesce(self.data['comment'], u''))
1210 self._CHBOX_review.SetValue(False)
1211 self._CHBOX_abnormal.SetValue(gmTools.coalesce(self.data['is_technically_abnormal'], False))
1212 self._CHBOX_relevant.SetValue(gmTools.coalesce(self.data['is_clinically_relevant'], False))
1213 self._CHBOX_abnormal.Enable(False)
1214 self._CHBOX_relevant.Enable(False)
1215 self._TCTRL_review_comment.SetValue(gmTools.coalesce(self.data['review_comment'], u''))
1216 self._TCTRL_normal_min.SetValue(unicode(gmTools.coalesce(self.data['val_normal_min'], u'')))
1217 self._TCTRL_normal_max.SetValue(unicode(gmTools.coalesce(self.data['val_normal_max'], u'')))
1218 self._TCTRL_normal_range.SetValue(gmTools.coalesce(self.data['val_normal_range'], u''))
1219 self._TCTRL_target_min.SetValue(unicode(gmTools.coalesce(self.data['val_target_min'], u'')))
1220 self._TCTRL_target_max.SetValue(unicode(gmTools.coalesce(self.data['val_target_max'], u'')))
1221 self._TCTRL_target_range.SetValue(gmTools.coalesce(self.data['val_target_range'], u''))
1222 self._TCTRL_norm_ref_group.SetValue(gmTools.coalesce(self.data['norm_ref_group'], u''))
1223
1224 self._TCTRL_result.SetFocus()
1225
1227 self._refresh_from_existing()
1228
1229 self._PRW_test.SetText(u'', None, True)
1230 self._TCTRL_result.SetValue(u'')
1231 self._PRW_units.SetText(u'', None, True)
1232 self._PRW_abnormality_indicator.SetText(u'', None, True)
1233
1234 self._TCTRL_note_test_org.SetValue(u'')
1235 self._TCTRL_narrative.SetValue(u'')
1236 self._CHBOX_review.SetValue(False)
1237 self._CHBOX_abnormal.SetValue(False)
1238 self._CHBOX_relevant.SetValue(False)
1239 self._CHBOX_abnormal.Enable(False)
1240 self._CHBOX_relevant.Enable(False)
1241 self._TCTRL_review_comment.SetValue(u'')
1242 self._TCTRL_normal_min.SetValue(u'')
1243 self._TCTRL_normal_max.SetValue(u'')
1244 self._TCTRL_normal_range.SetValue(u'')
1245 self._TCTRL_target_min.SetValue(u'')
1246 self._TCTRL_target_max.SetValue(u'')
1247 self._TCTRL_target_range.SetValue(u'')
1248 self._TCTRL_norm_ref_group.SetValue(u'')
1249
1250 self._PRW_test.SetFocus()
1251
1253
1254 validity = True
1255
1256 if not self._DPRW_evaluated.is_valid_timestamp():
1257 self._DPRW_evaluated.display_as_valid(False)
1258 validity = False
1259 else:
1260 self._DPRW_evaluated.display_as_valid(True)
1261
1262 if self._TCTRL_result.GetValue().strip() == u'':
1263 self._TCTRL_result.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
1264 validity = False
1265 else:
1266 self._TCTRL_result.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
1267
1268 if self._PRW_problem.GetValue().strip() == u'':
1269 self._PRW_problem.display_as_valid(False)
1270 validity = False
1271 else:
1272 self._PRW_problem.display_as_valid(True)
1273
1274 if self._PRW_test.GetValue().strip() == u'':
1275 self._PRW_test.display_as_valid(False)
1276 validity = False
1277 else:
1278 self._PRW_test.display_as_valid(True)
1279
1280 if self._PRW_intended_reviewer.GetData() is None:
1281 self._PRW_intended_reviewer.display_as_valid(False)
1282 validity = False
1283 else:
1284 self._PRW_intended_reviewer.display_as_valid(True)
1285
1286 if self._PRW_units.GetValue().strip() == u'':
1287 self._PRW_units.display_as_valid(False)
1288 validity = False
1289 else:
1290 self._PRW_units.display_as_valid(True)
1291
1292 ctrls = [self._TCTRL_normal_min, self._TCTRL_normal_max, self._TCTRL_target_min, self._TCTRL_target_max]
1293 for widget in ctrls:
1294 val = widget.GetValue().strip()
1295 if val == u'':
1296 continue
1297 try:
1298 decimal.Decimal(val.replace(',', u'.', 1))
1299 widget.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
1300 except:
1301 widget.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
1302 validity = False
1303
1304 if validity is False:
1305 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save result. Invalid or missing essential input.'))
1306
1307 return validity
1308
1310
1311 emr = gmPerson.gmCurrentPatient().get_emr()
1312
1313 try:
1314 v_num = decimal.Decimal(self._TCTRL_result.GetValue().strip().replace(',', '.', 1))
1315 v_al = None
1316 except:
1317 v_num = None
1318 v_al = self._TCTRL_result.GetValue().strip()
1319
1320 pk_type = self._PRW_test.GetData()
1321 if pk_type is None:
1322 tt = gmPathLab.create_measurement_type (
1323 lab = None,
1324 abbrev = self._PRW_test.GetValue().strip(),
1325 name = self._PRW_test.GetValue().strip(),
1326 unit = gmTools.none_if(self._PRW_units.GetValue().strip(), u'')
1327 )
1328 pk_type = tt['pk_test_type']
1329
1330 tr = emr.add_test_result (
1331 episode = self._PRW_problem.GetData(can_create=True, is_open=False),
1332 type = pk_type,
1333 intended_reviewer = self._PRW_intended_reviewer.GetData(),
1334 val_num = v_num,
1335 val_alpha = v_al,
1336 unit = self._PRW_units.GetValue()
1337 )
1338
1339 tr['clin_when'] = self._DPRW_evaluated.GetData().get_pydt()
1340
1341 ctrls = [
1342 ('abnormality_indicator', self._PRW_abnormality_indicator),
1343 ('note_test_org', self._TCTRL_note_test_org),
1344 ('comment', self._TCTRL_narrative),
1345 ('val_normal_range', self._TCTRL_normal_range),
1346 ('val_target_range', self._TCTRL_target_range),
1347 ('norm_ref_group', self._TCTRL_norm_ref_group)
1348 ]
1349 for field, widget in ctrls:
1350 tr[field] = widget.GetValue().strip()
1351
1352 ctrls = [
1353 ('val_normal_min', self._TCTRL_normal_min),
1354 ('val_normal_max', self._TCTRL_normal_max),
1355 ('val_target_min', self._TCTRL_target_min),
1356 ('val_target_max', self._TCTRL_target_max)
1357 ]
1358 for field, widget in ctrls:
1359 val = widget.GetValue().strip()
1360 if val == u'':
1361 tr[field] = None
1362 else:
1363 tr[field] = decimal.Decimal(val.replace(',', u'.', 1))
1364
1365 tr.save_payload()
1366
1367 if self._CHBOX_review.GetValue() is True:
1368 tr.set_review (
1369 technically_abnormal = self._CHBOX_abnormal.GetValue(),
1370 clinically_relevant = self._CHBOX_relevant.GetValue(),
1371 comment = gmTools.none_if(self._TCTRL_review_comment.GetValue().strip(), u''),
1372 make_me_responsible = False
1373 )
1374
1375 self.data = tr
1376
1377 return True
1378
1380
1381 success, result = gmTools.input2decimal(self._TCTRL_result.GetValue())
1382 if success:
1383 v_num = result
1384 v_al = None
1385 else:
1386 v_num = None
1387 v_al = self._TCTRL_result.GetValue().strip()
1388
1389 pk_type = self._PRW_test.GetData()
1390 if pk_type is None:
1391 tt = gmPathLab.create_measurement_type (
1392 lab = None,
1393 abbrev = self._PRW_test.GetValue().strip(),
1394 name = self._PRW_test.GetValue().strip(),
1395 unit = gmTools.none_if(self._PRW_units.GetValue().strip(), u'')
1396 )
1397 pk_type = tt['pk_test_type']
1398
1399 tr = self.data
1400
1401 tr['pk_episode'] = self._PRW_problem.GetData(can_create=True, is_open=False)
1402 tr['pk_test_type'] = pk_type
1403 tr['pk_intended_reviewer'] = self._PRW_intended_reviewer.GetData()
1404 tr['val_num'] = v_num
1405 tr['val_alpha'] = v_al
1406 tr['val_unit'] = self._PRW_units.GetValue().strip()
1407 tr['clin_when'] = self._DPRW_evaluated.GetData().get_pydt()
1408
1409 ctrls = [
1410 ('abnormality_indicator', self._PRW_abnormality_indicator),
1411 ('note_test_org', self._TCTRL_note_test_org),
1412 ('comment', self._TCTRL_narrative),
1413 ('val_normal_range', self._TCTRL_normal_range),
1414 ('val_target_range', self._TCTRL_target_range),
1415 ('norm_ref_group', self._TCTRL_norm_ref_group)
1416 ]
1417 for field, widget in ctrls:
1418 tr[field] = widget.GetValue().strip()
1419
1420 ctrls = [
1421 ('val_normal_min', self._TCTRL_normal_min),
1422 ('val_normal_max', self._TCTRL_normal_max),
1423 ('val_target_min', self._TCTRL_target_min),
1424 ('val_target_max', self._TCTRL_target_max)
1425 ]
1426 for field, widget in ctrls:
1427 val = widget.GetValue().strip()
1428 if val == u'':
1429 tr[field] = None
1430 else:
1431 tr[field] = decimal.Decimal(val.replace(',', u'.', 1))
1432
1433 tr.save_payload()
1434
1435 if self._CHBOX_review.GetValue() is True:
1436 tr.set_review (
1437 technically_abnormal = self._CHBOX_abnormal.GetValue(),
1438 clinically_relevant = self._CHBOX_relevant.GetValue(),
1439 comment = gmTools.none_if(self._TCTRL_review_comment.GetValue().strip(), u''),
1440 make_me_responsible = False
1441 )
1442
1443 return True
1444
1445
1446
1450
1452 pk_type = self._PRW_test.GetData()
1453
1454 if pk_type is None:
1455 self._PRW_units.unset_context(context = u'pk_type')
1456 else:
1457 self._PRW_units.set_context(context = u'pk_type', val = pk_type)
1458
1460
1461 if not self._CHBOX_review.GetValue():
1462 self._CHBOX_abnormal.SetValue(self._PRW_abnormality_indicator.GetValue().strip() != u'')
1463
1465 self._CHBOX_abnormal.Enable(self._CHBOX_review.GetValue())
1466 self._CHBOX_relevant.Enable(self._CHBOX_review.GetValue())
1467 self._TCTRL_review_comment.Enable(self._CHBOX_review.GetValue())
1468
1485
1486
1487
1489
1490 if parent is None:
1491 parent = wx.GetApp().GetTopWindow()
1492
1493
1494 def edit(test_type=None):
1495 ea = cMeasurementTypeEAPnl(parent = parent, id = -1, type = test_type)
1496 dlg = gmEditArea.cGenericEditAreaDlg2 (
1497 parent = parent,
1498 id = -1,
1499 edit_area = ea,
1500 single_entry = gmTools.bool2subst((test_type is None), False, True)
1501 )
1502 dlg.SetTitle(gmTools.coalesce(test_type, _('Adding measurement type'), _('Editing measurement type')))
1503
1504 if dlg.ShowModal() == wx.ID_OK:
1505 dlg.Destroy()
1506 return True
1507
1508 dlg.Destroy()
1509 return False
1510
1511 def refresh(lctrl):
1512 mtypes = gmPathLab.get_measurement_types(order_by = 'name, abbrev')
1513 items = [ [
1514 m['abbrev'],
1515 m['name'],
1516 gmTools.coalesce(m['loinc'], u''),
1517 gmTools.coalesce(m['conversion_unit'], u''),
1518 gmTools.coalesce(m['comment_type'], u''),
1519 gmTools.coalesce(m['internal_name_org'], _('in-house')),
1520 gmTools.coalesce(m['comment_org'], u''),
1521 m['pk_test_type']
1522 ] for m in mtypes ]
1523 lctrl.set_string_items(items)
1524 lctrl.set_data(mtypes)
1525
1526 def delete(measurement_type):
1527 if measurement_type.in_use:
1528 gmDispatcher.send (
1529 signal = 'statustext',
1530 beep = True,
1531 msg = _('Cannot delete measurement type [%s (%s)] because it is in use.') % (measurement_type['name'], measurement_type['abbrev'])
1532 )
1533 return False
1534 gmPathLab.delete_measurement_type(measurement_type = measurement_type['pk_test_type'])
1535 return True
1536
1537 msg = _(
1538 '\n'
1539 'These are the measurement types currently defined in GNUmed.\n'
1540 '\n'
1541 )
1542
1543 gmListWidgets.get_choices_from_list (
1544 parent = parent,
1545 msg = msg,
1546 caption = _('Showing measurement types.'),
1547 columns = [_('Abbrev'), _('Name'), _('LOINC'), _('Base unit'), _('Comment'), _('Org'), _('Comment'), u'#'],
1548 single_selection = True,
1549 refresh_callback = refresh,
1550 edit_callback = edit,
1551 new_callback = edit,
1552 delete_callback = delete
1553 )
1554
1556
1558
1559 query = u"""
1560 (
1561 select
1562 pk_test_type,
1563 name_tt
1564 || ' ('
1565 || coalesce (
1566 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1567 '%(in_house)s'
1568 )
1569 || ')'
1570 as name
1571 from clin.v_unified_test_types vcutt
1572 where
1573 name_meta %%(fragment_condition)s
1574
1575 ) union (
1576
1577 select
1578 pk_test_type,
1579 name_tt
1580 || ' ('
1581 || coalesce (
1582 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1583 '%(in_house)s'
1584 )
1585 || ')'
1586 as name
1587 from clin.v_unified_test_types vcutt
1588 where
1589 name_tt %%(fragment_condition)s
1590
1591 ) union (
1592
1593 select
1594 pk_test_type,
1595 name_tt
1596 || ' ('
1597 || coalesce (
1598 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1599 '%(in_house)s'
1600 )
1601 || ')'
1602 as name
1603 from clin.v_unified_test_types vcutt
1604 where
1605 abbrev_meta %%(fragment_condition)s
1606
1607 ) union (
1608
1609 select
1610 pk_test_type,
1611 name_tt
1612 || ' ('
1613 || coalesce (
1614 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1615 '%(in_house)s'
1616 )
1617 || ')'
1618 as name
1619 from clin.v_unified_test_types vcutt
1620 where
1621 code_tt %%(fragment_condition)s
1622 )
1623
1624 order by name
1625 limit 50""" % {'in_house': _('in house lab')}
1626
1627 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1628 mp.setThresholds(1, 2, 4)
1629 mp.word_separators = '[ \t:@]+'
1630 gmPhraseWheel.cPhraseWheel.__init__ (
1631 self,
1632 *args,
1633 **kwargs
1634 )
1635 self.matcher = mp
1636 self.SetToolTipString(_('Select the type of measurement.'))
1637 self.selection_only = False
1638
1640
1642
1643 query = u"""
1644 select distinct on (internal_name)
1645 pk,
1646 internal_name
1647 from clin.test_org
1648 where
1649 internal_name %(fragment_condition)s
1650 order by internal_name
1651 limit 50"""
1652 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1653 mp.setThresholds(1, 2, 4)
1654
1655 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1656 self.matcher = mp
1657 self.SetToolTipString(_('The name of the path lab/diagnostic organisation.'))
1658 self.selection_only = False
1659
1672
1673 from Gnumed.wxGladeWidgets import wxgMeasurementTypeEAPnl
1674
1675 -class cMeasurementTypeEAPnl(wxgMeasurementTypeEAPnl.wxgMeasurementTypeEAPnl, gmEditArea.cGenericEditAreaMixin):
1676
1693
1694
1696
1697
1698 query = u"""
1699 select distinct on (name)
1700 pk,
1701 name
1702 from clin.test_type
1703 where
1704 name %(fragment_condition)s
1705 order by name
1706 limit 50"""
1707 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1708 mp.setThresholds(1, 2, 4)
1709 self._PRW_name.matcher = mp
1710 self._PRW_name.selection_only = False
1711
1712
1713 query = u"""
1714 select distinct on (abbrev)
1715 pk,
1716 abbrev
1717 from clin.test_type
1718 where
1719 abbrev %(fragment_condition)s
1720 order by abbrev
1721 limit 50"""
1722 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1723 mp.setThresholds(1, 2, 3)
1724 self._PRW_abbrev.matcher = mp
1725 self._PRW_abbrev.selection_only = False
1726
1727
1728
1729 query = u"""
1730 select distinct on (conversion_unit)
1731 conversion_unit,
1732 conversion_unit
1733 from clin.test_type
1734 where
1735 conversion_unit %(fragment_condition)s
1736 order by conversion_unit
1737 limit 50"""
1738 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1739 mp.setThresholds(1, 2, 3)
1740 self._PRW_conversion_unit.matcher = mp
1741 self._PRW_conversion_unit.selection_only = False
1742
1743
1744 query = u"""
1745 select distinct on (term)
1746 loinc,
1747 term
1748 from ((
1749 select
1750 loinc,
1751 (loinc || ': ' || abbrev || ' (' || name || ')') as term
1752 from clin.test_type
1753 where loinc %(fragment_condition)s
1754 limit 50
1755 ) union all (
1756 select
1757 code as loinc,
1758 (code || ': ' || term) as term
1759 from ref.v_coded_terms
1760 where
1761 coding_system = 'LOINC'
1762 and
1763 lang = i18n.get_curr_lang()
1764 and
1765 (code %(fragment_condition)s
1766 or
1767 term %(fragment_condition)s)
1768 limit 50
1769 ) union all (
1770 select
1771 code as loinc,
1772 (code || ': ' || term) as term
1773 from ref.v_coded_terms
1774 where
1775 coding_system = 'LOINC'
1776 and
1777 lang = 'en_EN'
1778 and
1779 (code %(fragment_condition)s
1780 or
1781 term %(fragment_condition)s)
1782 limit 50
1783 ) union all (
1784 select
1785 code as loinc,
1786 (code || ': ' || term) as term
1787 from ref.v_coded_terms
1788 where
1789 coding_system = 'LOINC'
1790 and
1791 (code %(fragment_condition)s
1792 or
1793 term %(fragment_condition)s)
1794 limit 50
1795 )
1796 ) as all_known_loinc
1797 order by term
1798 limit 50"""
1799 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
1800 mp.setThresholds(1, 2, 4)
1801 self._PRW_loinc.matcher = mp
1802 self._PRW_loinc.selection_only = False
1803 self._PRW_loinc.add_callback_on_lose_focus(callback = self._on_loinc_lost_focus)
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1821 loinc = self._PRW_loinc.GetData()
1822
1823 if loinc is None:
1824 self._TCTRL_loinc_info.SetValue(u'')
1825 return
1826
1827 info = gmLOINC.loinc2info(loinc = loinc)
1828 if len(info) == 0:
1829 self._TCTRL_loinc_info.SetValue(u'')
1830 return
1831
1832 self._TCTRL_loinc_info.SetValue(info[0])
1833
1834
1835
1837
1838 has_errors = False
1839 for field in [self._PRW_name, self._PRW_abbrev, self._PRW_conversion_unit]:
1840 if field.GetValue().strip() in [u'', None]:
1841 has_errors = True
1842 field.display_as_valid(valid = False)
1843 else:
1844 field.display_as_valid(valid = True)
1845 field.Refresh()
1846
1847 return (not has_errors)
1848
1871
1890
1892 self._PRW_name.SetText(u'', None, True)
1893 self._PRW_abbrev.SetText(u'', None, True)
1894 self._PRW_conversion_unit.SetText(u'', None, True)
1895 self._PRW_loinc.SetText(u'', None, True)
1896 self._TCTRL_loinc_info.SetValue(u'')
1897 self._TCTRL_comment_type.SetValue(u'')
1898 self._PRW_test_org.SetText(u'', None, True)
1899 self._TCTRL_comment_org.SetValue(u'')
1900
1902 self._PRW_name.SetText(self.data['name'], self.data['name'], True)
1903 self._PRW_abbrev.SetText(self.data['abbrev'], self.data['abbrev'], True)
1904 self._PRW_conversion_unit.SetText (
1905 gmTools.coalesce(self.data['conversion_unit'], u''),
1906 self.data['conversion_unit'],
1907 True
1908 )
1909 self._PRW_loinc.SetText (
1910 gmTools.coalesce(self.data['loinc'], u''),
1911 self.data['loinc'],
1912 True
1913 )
1914 self._TCTRL_loinc_info.SetValue(u'')
1915 self._TCTRL_comment_type.SetValue(gmTools.coalesce(self.data['comment_type'], u''))
1916 self._PRW_test_org.SetText (
1917 gmTools.coalesce(self.data['pk_test_org'], u'', self.data['internal_name_org']),
1918 self.data['pk_test_org'],
1919 True
1920 )
1921 self._TCTRL_comment_org.SetValue(gmTools.coalesce(self.data['comment_org'], u''))
1922
1931
1933
1935
1936 query = u"""
1937 select distinct val_unit,
1938 val_unit, val_unit
1939 from clin.v_test_results
1940 where
1941 (
1942 val_unit %(fragment_condition)s
1943 or
1944 conversion_unit %(fragment_condition)s
1945 )
1946 %(ctxt_test_name)s
1947 %(ctxt_test_pk)s
1948 order by val_unit
1949 limit 25"""
1950
1951 ctxt = {
1952 'ctxt_test_name': {
1953 'where_part': u'and %(test)s in (name_tt, name_meta, code_tt, abbrev_meta)',
1954 'placeholder': u'test'
1955 },
1956 'ctxt_test_pk': {
1957 'where_part': u'and pk_test_type = %(pk_type)s',
1958 'placeholder': u'pk_type'
1959 }
1960 }
1961
1962 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query, context=ctxt)
1963 mp.setThresholds(1, 2, 4)
1964 gmPhraseWheel.cPhraseWheel.__init__ (
1965 self,
1966 *args,
1967 **kwargs
1968 )
1969 self.matcher = mp
1970 self.SetToolTipString(_('Select the unit of the test result.'))
1971 self.selection_only = False
1972
1973
1974
1975
1977
1979
1980 query = u"""
1981 select distinct abnormality_indicator,
1982 abnormality_indicator, abnormality_indicator
1983 from clin.v_test_results
1984 where
1985 abnormality_indicator %(fragment_condition)s
1986 order by abnormality_indicator
1987 limit 25"""
1988
1989 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1990 mp.setThresholds(1, 1, 2)
1991 mp.ignored_chars = "[.'\\\[\]#$%_]+" + '"'
1992 mp.word_separators = '[ \t&:]+'
1993 gmPhraseWheel.cPhraseWheel.__init__ (
1994 self,
1995 *args,
1996 **kwargs
1997 )
1998 self.matcher = mp
1999 self.SetToolTipString(_('Select an indicator for the level of abnormality.'))
2000 self.selection_only = False
2001
2002
2003
2015
2017
2018 if parent is None:
2019 parent = wx.GetApp().GetTopWindow()
2020
2021
2022 def edit(org=None):
2023 return edit_measurement_org(parent = parent, org = org)
2024
2025 def refresh(lctrl):
2026 orgs = gmPathLab.get_test_orgs()
2027 lctrl.set_string_items ([
2028 (o['internal_name'], gmTools.coalesce(o['contact'], u''), gmTools.coalesce(o['comment']), o['pk'])
2029 for o in orgs
2030 ])
2031 lctrl.set_data(orgs)
2032
2033 def delete(measurement_type):
2034 if measurement_type.in_use:
2035 gmDispatcher.send (
2036 signal = 'statustext',
2037 beep = True,
2038 msg = _('Cannot delete measurement type [%s (%s)] because it is in use.') % (measurement_type['name'], measurement_type['abbrev'])
2039 )
2040 return False
2041 gmPathLab.delete_measurement_type(measurement_type = measurement_type['pk_test_type'])
2042 return True
2043
2044 gmListWidgets.get_choices_from_list (
2045 parent = parent,
2046 msg = _('\nThese are the diagnostic orgs (path labs etc) currently defined in GNUmed.\n\n'),
2047 caption = _('Showing diagnostic orgs.'),
2048 columns = [_('Name'), _('Contact'), _('Comment'), u'#'],
2049 single_selection = True,
2050 refresh_callback = refresh,
2051 edit_callback = edit,
2052 new_callback = edit
2053
2054 )
2055
2056
2057
2058 from Gnumed.wxGladeWidgets import wxgMeasurementOrgEAPnl
2059
2060 -class cMeasurementOrgEAPnl(wxgMeasurementOrgEAPnl.wxgMeasurementOrgEAPnl, gmEditArea.cGenericEditAreaMixin):
2061
2079
2080
2081
2082
2083
2084
2085
2086
2088 has_errors = False
2089 if self._PRW_name.GetValue().strip() == u'':
2090 has_errors = True
2091 self._PRW_name.display_as_valid(valid = False)
2092 else:
2093 self._PRW_name.display_as_valid(valid = True)
2094
2095 return (not has_errors)
2096
2098
2099 data = self._PRW_name.GetData(can_create = True)
2100
2101 data['contact'] = self._TCTRL_contact.GetValue().strip()
2102 data['comment'] = self._TCTRL_comment.GetValue().strip()
2103 data.save()
2104
2105
2106
2107
2108 self.data = data
2109
2110 return True
2111
2113 self.data['internal_name'] = self._PRW_name.GetValue().strip()
2114 self.data['contact'] = self._TCTRL_contact.GetValue().strip()
2115 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
2116 self.data.save()
2117 return True
2118
2123
2128
2130 self._refresh_as_new()
2131
2170
2171
2172
2173 if __name__ == '__main__':
2174
2175 from Gnumed.pycommon import gmLog2
2176
2177 gmI18N.activate_locale()
2178 gmI18N.install_domain()
2179 gmDateTime.init()
2180
2181
2189
2197
2198
2199
2200
2201
2202
2203
2204 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
2205
2206 test_test_ea_pnl()
2207
2208
2209
2210