1 """GNUmed measurement widgets.
2 """
3
4
5
6 __version__ = "$Revision: 1.66 $"
7 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
8 __license__ = "GPL"
9
10
11 import sys, logging, datetime as pyDT, decimal, os
12
13
14 import wx, wx.grid, wx.lib.hyperlink
15
16
17 if __name__ == '__main__':
18 sys.path.insert(0, '../../')
19 from Gnumed.business import gmPerson, gmPathLab, gmSurgery, gmLOINC
20 from Gnumed.pycommon import gmTools, gmDispatcher, gmMatchProvider, gmDateTime, gmI18N, gmCfg, gmShellAPI
21 from Gnumed.wxpython import gmRegetMixin, gmPhraseWheel, gmEditArea, gmGuiHelpers, gmListWidgets, gmAuthWidgets, gmPatSearchWidgets
22 from Gnumed.wxGladeWidgets import wxgMeasurementsPnl, wxgMeasurementsReviewDlg
23 from Gnumed.wxGladeWidgets import wxgMeasurementEditAreaPnl
24
25
26 _log = logging.getLogger('gm.ui')
27 _log.info(__version__)
28
29
30
32
33 wx.BeginBusyCursor()
34
35 gmDispatcher.send(signal = 'statustext', msg = _('Updating LOINC data can take quite a while...'), beep = True)
36
37
38 downloaded = gmShellAPI.run_command_in_shell(command = 'gm-download_loinc', blocking = True)
39 if not downloaded:
40 wx.EndBusyCursor()
41 gmGuiHelpers.gm_show_warning (
42 aTitle = _('Downloading LOINC'),
43 aMessage = _(
44 'Running <gm-download_loinc> to retrieve\n'
45 'the latest LOINC data failed.\n'
46 )
47 )
48 return False
49
50
51 data_fname, license_fname = gmLOINC.split_LOINCDBTXT(input_fname = '/tmp/LOINCDB.TXT')
52
53 wx.EndBusyCursor()
54
55 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('importing LOINC reference data'))
56 if conn is None:
57 return False
58
59 wx.BeginBusyCursor()
60
61 if gmLOINC.loinc_import(data_fname = data_fname, license_fname = license_fname, conn = conn):
62 gmDispatcher.send(signal = 'statustext', msg = _('Successfully imported LOINC reference data.'))
63 try:
64 os.remove(data_fname)
65 os.remove(license_fname)
66 except OSError:
67 _log.error('unable to remove [%s] or [%s]', data_fname, license_fname)
68 else:
69 gmDispatcher.send(signal = 'statustext', msg = _('Importing LOINC reference data failed.'), beep = True)
70
71 wx.EndBusyCursor()
72 return True
73
74
75
87
88
89
90
91
92
93
94
95
96
97
99 """A grid class for displaying measurment results.
100
101 - does NOT listen to the currently active patient
102 - thereby it can display any patient at any time
103 """
104
105
106
107
108
109
111
112 wx.grid.Grid.__init__(self, *args, **kwargs)
113
114 self.__patient = None
115 self.__cell_data = {}
116 self.__row_label_data = []
117
118 self.__prev_row = None
119 self.__prev_col = None
120 self.__prev_label_row = None
121 self.__date_format = str((_('lab_grid_date_format::%Y\n%b %d')).lstrip('lab_grid_date_format::'))
122
123 self.__init_ui()
124 self.__register_events()
125
126
127
129 if not self.IsSelection():
130 gmDispatcher.send(signal = u'statustext', msg = _('No results selected for deletion.'))
131 return True
132
133 selected_cells = self.get_selected_cells()
134 if len(selected_cells) > 20:
135 results = None
136 msg = _(
137 'There are %s results marked for deletion.\n'
138 '\n'
139 'Are you sure you want to delete these results ?'
140 ) % len(selected_cells)
141 else:
142 results = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
143 txt = u'\n'.join([ u'%s %s (%s): %s %s%s' % (
144 r['clin_when'].strftime('%x %H:%M').decode(gmI18N.get_encoding()),
145 r['unified_abbrev'],
146 r['unified_name'],
147 r['unified_val'],
148 r['val_unit'],
149 gmTools.coalesce(r['abnormality_indicator'], u'', u' (%s)')
150 ) for r in results
151 ])
152 msg = _(
153 'The following results are marked for deletion:\n'
154 '\n'
155 '%s\n'
156 '\n'
157 'Are you sure you want to delete these results ?'
158 ) % txt
159
160 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
161 self,
162 -1,
163 caption = _('Deleting test results'),
164 question = msg,
165 button_defs = [
166 {'label': _('Delete'), 'tooltip': _('Yes, delete all the results.'), 'default': False},
167 {'label': _('Cancel'), 'tooltip': _('No, do NOT delete any results.'), 'default': True}
168 ]
169 )
170 decision = dlg.ShowModal()
171
172 if decision == wx.ID_YES:
173 if results is None:
174 results = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
175 for result in results:
176 gmPathLab.delete_test_result(result)
177
179 if not self.IsSelection():
180 gmDispatcher.send(signal = u'statustext', msg = _('Cannot sign results. No results selected.'))
181 return True
182
183 selected_cells = self.get_selected_cells()
184 if len(selected_cells) > 10:
185 test_count = len(selected_cells)
186 tests = None
187 else:
188 test_count = None
189 tests = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
190
191 dlg = cMeasurementsReviewDlg (
192 self,
193 -1,
194 tests = tests,
195 test_count = test_count
196 )
197 decision = dlg.ShowModal()
198
199 if decision == wx.ID_APPLY:
200 wx.BeginBusyCursor()
201
202 if dlg._RBTN_confirm_abnormal.GetValue():
203 abnormal = None
204 elif dlg._RBTN_results_normal.GetValue():
205 abnormal = False
206 else:
207 abnormal = True
208
209 if dlg._RBTN_confirm_relevance.GetValue():
210 relevant = None
211 elif dlg._RBTN_results_not_relevant.GetValue():
212 relevant = False
213 else:
214 relevant = True
215
216 if tests is None:
217 tests = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
218
219 comment = None
220 if len(tests) == 1:
221 comment = dlg._TCTRL_comment.GetValue()
222
223 for test in tests:
224 test.set_review (
225 technically_abnormal = abnormal,
226 clinically_relevant = relevant,
227 comment = comment,
228 make_me_responsible = dlg._CHBOX_responsible.IsChecked()
229 )
230
231 wx.EndBusyCursor()
232
233 dlg.Destroy()
234
236
237 sel_block_top_left = self.GetSelectionBlockTopLeft()
238 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
239 sel_cols = self.GetSelectedCols()
240 sel_rows = self.GetSelectedRows()
241
242 selected_cells = []
243
244
245 selected_cells += self.GetSelectedCells()
246
247
248 selected_cells += list (
249 (row, col)
250 for row in sel_rows
251 for col in xrange(self.GetNumberCols())
252 )
253
254
255 selected_cells += list (
256 (row, col)
257 for row in xrange(self.GetNumberRows())
258 for col in sel_cols
259 )
260
261
262 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
263 selected_cells += [
264 (row, col)
265 for row in xrange(top_left[0], bottom_right[0] + 1)
266 for col in xrange(top_left[1], bottom_right[1] + 1)
267 ]
268
269 return set(selected_cells)
270
271 - def select_cells(self, unsigned_only=False, accountables_only=False, keep_preselections=False):
272 """Select a range of cells according to criteria.
273
274 unsigned_only: include only those which are not signed at all yet
275 accountable_only: include only those for which the current user is responsible
276 keep_preselections: broaden (rather than replace) the range of selected cells
277
278 Combinations are powerful !
279 """
280 wx.BeginBusyCursor()
281 self.BeginBatch()
282
283 if not keep_preselections:
284 self.ClearSelection()
285
286 for col_idx in self.__cell_data.keys():
287 for row_idx in self.__cell_data[col_idx].keys():
288
289
290 do_not_include = False
291 for result in self.__cell_data[col_idx][row_idx]:
292 if unsigned_only:
293 if result['reviewed']:
294 do_not_include = True
295 break
296 if accountables_only:
297 if not result['you_are_responsible']:
298 do_not_include = True
299 break
300 if do_not_include:
301 continue
302
303 self.SelectBlock(row_idx, col_idx, row_idx, col_idx, addToSelected = True)
304
305 self.EndBatch()
306 wx.EndBusyCursor()
307
309
310 self.empty_grid()
311 if self.__patient is None:
312 return
313
314 emr = self.__patient.get_emr()
315
316 self.__row_label_data = emr.get_test_types_for_results()
317 test_type_labels = [ u'%s (%s)' % (test['unified_abbrev'], test['unified_name']) for test in self.__row_label_data ]
318 if len(test_type_labels) == 0:
319 return
320
321 test_date_labels = [ date[0].strftime(self.__date_format) for date in emr.get_dates_for_results() ]
322 results = emr.get_test_results_by_date()
323
324 self.BeginBatch()
325
326
327 self.AppendRows(numRows = len(test_type_labels))
328 for row_idx in range(len(test_type_labels)):
329 self.SetRowLabelValue(row_idx, test_type_labels[row_idx])
330
331
332 self.AppendCols(numCols = len(test_date_labels))
333 for date_idx in range(len(test_date_labels)):
334 self.SetColLabelValue(date_idx, test_date_labels[date_idx])
335
336
337 for result in results:
338 row = test_type_labels.index(u'%s (%s)' % (result['unified_abbrev'], result['unified_name']))
339 col = test_date_labels.index(result['clin_when'].strftime(self.__date_format))
340
341 try:
342 self.__cell_data[col]
343 except KeyError:
344 self.__cell_data[col] = {}
345
346
347 if self.__cell_data[col].has_key(row):
348 self.__cell_data[col][row].append(result)
349 self.__cell_data[col][row].sort(key = lambda x: x['clin_when'], reverse = True)
350 else:
351 self.__cell_data[col][row] = [result]
352
353
354 vals2display = []
355 for sub_result in self.__cell_data[col][row]:
356
357
358 ind = gmTools.coalesce(sub_result['abnormality_indicator'], u'').strip()
359 if ind != u'':
360 lab_abnormality_indicator = u' (%s)' % ind[:3]
361 else:
362 lab_abnormality_indicator = u''
363
364 if sub_result['is_technically_abnormal'] is None:
365 abnormality_indicator = lab_abnormality_indicator
366
367 elif sub_result['is_technically_abnormal'] is False:
368 abnormality_indicator = u''
369
370 else:
371
372 if lab_abnormality_indicator == u'':
373
374 abnormality_indicator = u' (%s)' % gmTools.u_plus_minus
375
376 else:
377 abnormality_indicator = lab_abnormality_indicator
378
379
380
381 sub_result_relevant = sub_result['is_clinically_relevant']
382 if sub_result_relevant is None:
383
384 sub_result_relevant = False
385
386 missing_review = False
387
388
389 if not sub_result['reviewed']:
390 missing_review = True
391
392 else:
393
394 if sub_result['you_are_responsible'] and not sub_result['review_by_you']:
395 missing_review = True
396
397
398 if len(sub_result['unified_val']) > 8:
399 tmp = u'%.7s%s' % (sub_result['unified_val'][:7], gmTools.u_ellipsis)
400 else:
401 tmp = u'%.8s' % sub_result['unified_val'][:8]
402
403
404 tmp = u'%s%.6s' % (tmp, abnormality_indicator)
405
406
407 has_sub_result_comment = gmTools.coalesce (
408 gmTools.coalesce(sub_result['note_test_org'], sub_result['comment']),
409 u''
410 ).strip() != u''
411 if has_sub_result_comment:
412 tmp = u'%s %s' % (tmp, gmTools.u_ellipsis)
413
414
415 if missing_review:
416 tmp = u'%s %s' % (tmp, gmTools.u_writing_hand)
417
418
419 if len(self.__cell_data[col][row]) > 1:
420 tmp = u'%s %s' % (sub_result['clin_when'].strftime('%H:%M'), tmp)
421
422 vals2display.append(tmp)
423
424 self.SetCellValue(row, col, u'\n'.join(vals2display))
425 self.SetCellAlignment(row, col, horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
426
427
428
429
430 if sub_result_relevant:
431 font = self.GetCellFont(row, col)
432 self.SetCellTextColour(row, col, 'firebrick')
433 font.SetWeight(wx.FONTWEIGHT_BOLD)
434 self.SetCellFont(row, col, font)
435
436
437 self.AutoSize()
438 self.EndBatch()
439 return
440
442 self.BeginBatch()
443 self.ClearGrid()
444
445
446 if self.GetNumberRows() > 0:
447 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
448 if self.GetNumberCols() > 0:
449 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
450 self.EndBatch()
451 self.__cell_data = {}
452 self.__row_label_data = []
453
486
734
735
736
738 self.CreateGrid(0, 1)
739 self.EnableEditing(0)
740 self.EnableDragGridSize(1)
741
742
743
744
745
746 self.SetRowLabelSize(150)
747 self.SetRowLabelAlignment(horiz = wx.ALIGN_LEFT, vert = wx.ALIGN_CENTRE)
748
749
750 dbcfg = gmCfg.cCfgSQL()
751 url = dbcfg.get2 (
752 option = u'external.urls.measurements_encyclopedia',
753 workplace = gmSurgery.gmCurrentPractice().active_workplace,
754 bias = 'user',
755 default = u'http://www.laborlexikon.de'
756 )
757
758 self.__WIN_corner = self.GetGridCornerLabelWindow()
759
760 LNK_lab = wx.lib.hyperlink.HyperLinkCtrl (
761 self.__WIN_corner,
762 -1,
763 label = _('Reference'),
764 style = wx.HL_DEFAULT_STYLE
765 )
766 LNK_lab.SetURL(url)
767 LNK_lab.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BACKGROUND))
768 LNK_lab.SetToolTipString(_(
769 'Navigate to an encyclopedia of measurements\n'
770 'and test methods on the web.\n'
771 '\n'
772 ' <%s>'
773 ) % url)
774
775 SZR_inner = wx.BoxSizer(wx.HORIZONTAL)
776 SZR_inner.Add((20, 20), 1, wx.EXPAND, 0)
777 SZR_inner.Add(LNK_lab, 0, wx.ALIGN_CENTER_VERTICAL, 0)
778 SZR_inner.Add((20, 20), 1, wx.EXPAND, 0)
779
780 SZR_corner = wx.BoxSizer(wx.VERTICAL)
781 SZR_corner.Add((20, 20), 1, wx.EXPAND, 0)
782 SZR_corner.AddWindow(SZR_inner, 0, wx.EXPAND)
783 SZR_corner.Add((20, 20), 1, wx.EXPAND, 0)
784
785 self.__WIN_corner.SetSizer(SZR_corner)
786 SZR_corner.Fit(self.__WIN_corner)
787
789 self.__WIN_corner.Layout()
790
792 """List of <cells> must be in row / col order."""
793 data = []
794 for row, col in cells:
795 try:
796
797 data_list = self.__cell_data[col][row]
798 except KeyError:
799 continue
800
801 if len(data_list) == 1:
802 data.append(data_list[0])
803 continue
804
805 if exclude_multi_cells:
806 gmDispatcher.send(signal = u'statustext', msg = _('Excluding multi-result field from further processing.'))
807 continue
808
809 data_to_include = self.__get_choices_from_multi_cell(cell_data = data_list)
810
811 if data_to_include is None:
812 continue
813
814 data.extend(data_to_include)
815
816 return data
817
819 data = gmListWidgets.get_choices_from_list (
820 parent = self,
821 msg = _(
822 'Your selection includes a field with multiple results.\n'
823 '\n'
824 'Please select the individual results you want to work on:'
825 ),
826 caption = _('Selecting test results'),
827 choices = [ [d['clin_when'], d['unified_abbrev'], d['unified_name'], d['unified_val']] for d in cell_data ],
828 columns = [_('Date / Time'), _('Code'), _('Test'), _('Result')],
829 data = cell_data,
830 single_selection = single_selection
831 )
832 return data
833
834
835
837
838 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
839 self.GetGridRowLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_row_labels)
840
841
842
843 self.Bind(wx.EVT_SIZE, self.__resize_corner_window)
844
845
846 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
847
849 col = evt.GetCol()
850 row = evt.GetRow()
851
852
853 try:
854 self.__cell_data[col][row]
855 except KeyError:
856
857
858 return
859
860 if len(self.__cell_data[col][row]) > 1:
861 data = self.__get_choices_from_multi_cell(cell_data = self.__cell_data[col][row], single_selection = True)
862 else:
863 data = self.__cell_data[col][row][0]
864
865 if data is None:
866 return
867
868 edit_measurement(parent = self, measurement = data)
869
870
871
872
873
874
875
877
878
879
880 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
881
882 row = self.YToRow(y)
883
884 if self.__prev_label_row == row:
885 return
886
887 self.__prev_label_row == row
888
889 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
890
891
892
893
894
895
896
897
899 """Calculate where the mouse is and set the tooltip dynamically."""
900
901
902
903 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
904
905
906
907
908
909
910
911
912
913
914
915
916
917 row, col = self.XYToCell(x, y)
918
919 if (row == self.__prev_row) and (col == self.__prev_col):
920 return
921
922 self.__prev_row = row
923 self.__prev_col = col
924
925 evt.GetEventObject().SetToolTipString(self.get_cell_tooltip(col=col, row=row))
926
927
928
932
933 patient = property(lambda x:x, _set_patient)
934
935 -class cMeasurementsPnl(wxgMeasurementsPnl.wxgMeasurementsPnl, gmRegetMixin.cRegetOnPaintMixin):
936
937 """Panel holding a grid with lab data. Used as notebook page."""
938
945
946
947
949 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
950 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
951 gmDispatcher.connect(signal = u'test_result_mod_db', receiver = self._schedule_data_reget)
952 gmDispatcher.connect(signal = u'reviewed_test_results_mod_db', receiver = self._schedule_data_reget)
953
955 wx.CallAfter(self.__on_post_patient_selection)
956
958 self._schedule_data_reget()
959
961 wx.CallAfter(self.__on_pre_patient_selection)
962
965
968
974
977
980
981
982
984 self.__action_button_popup = wx.Menu(title = _('Act on selected results'))
985
986 menu_id = wx.NewId()
987 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Review and &sign')))
988 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_sign_current_selection)
989
990 menu_id = wx.NewId()
991 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Export to &file')))
992
993 self.__action_button_popup.Enable(id = menu_id, enable = False)
994
995 menu_id = wx.NewId()
996 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Export to &clipboard')))
997
998 self.__action_button_popup.Enable(id = menu_id, enable = False)
999
1000 menu_id = wx.NewId()
1001 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('&Delete')))
1002 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_delete_current_selection)
1003
1004
1005
1014
1015
1016
1018
1020
1021 try:
1022 tests = kwargs['tests']
1023 del kwargs['tests']
1024 test_count = len(tests)
1025 try: del kwargs['test_count']
1026 except KeyError: pass
1027 except KeyError:
1028 tests = None
1029 test_count = kwargs['test_count']
1030 del kwargs['test_count']
1031
1032 wxgMeasurementsReviewDlg.wxgMeasurementsReviewDlg.__init__(self, *args, **kwargs)
1033
1034 if tests is None:
1035 msg = _('%s results selected. Too many to list individually.') % test_count
1036 else:
1037 msg = ' // '.join (
1038 [ u'%s: %s %s (%s)' % (
1039 t['unified_abbrev'],
1040 t['unified_val'],
1041 t['val_unit'],
1042 t['clin_when'].strftime('%x').decode(gmI18N.get_encoding())
1043 ) for t in tests
1044 ]
1045 )
1046
1047 self._LBL_tests.SetLabel(msg)
1048
1049 if test_count == 1:
1050 self._TCTRL_comment.Enable(True)
1051 self._TCTRL_comment.SetValue(gmTools.coalesce(tests[0]['review_comment'], u''))
1052 if tests[0]['you_are_responsible']:
1053 self._CHBOX_responsible.Enable(False)
1054
1055 self.Fit()
1056
1057
1058
1064
1065 -class cMeasurementEditAreaPnl(wxgMeasurementEditAreaPnl.wxgMeasurementEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
1066 """This edit area saves *new* measurements into the active patient only."""
1067
1069
1070 try:
1071 self.__default_date = kwargs['date']
1072 del kwargs['date']
1073 except KeyError:
1074 self.__default_date = None
1075
1076 wxgMeasurementEditAreaPnl.wxgMeasurementEditAreaPnl.__init__(self, *args, **kwargs)
1077 gmEditArea.cGenericEditAreaMixin.__init__(self)
1078
1079 self.__register_interests()
1080
1081 self.successful_save_msg = _('Successfully saved measurement.')
1082
1083
1084
1086 self._PRW_test.SetText(u'', None, True)
1087 self._TCTRL_result.SetValue(u'')
1088 self._PRW_units.SetText(u'', None, True)
1089 self._PRW_abnormality_indicator.SetText(u'', None, True)
1090 if self.__default_date is None:
1091 self._DPRW_evaluated.SetData(data = pyDT.datetime.now(tz = gmDateTime.gmCurrentLocalTimezone))
1092 else:
1093 self._DPRW_evaluated.SetData(data = None)
1094 self._TCTRL_note_test_org.SetValue(u'')
1095 self._PRW_intended_reviewer.SetData()
1096 self._PRW_problem.SetData()
1097 self._TCTRL_narrative.SetValue(u'')
1098 self._CHBOX_review.SetValue(False)
1099 self._CHBOX_abnormal.SetValue(False)
1100 self._CHBOX_relevant.SetValue(False)
1101 self._CHBOX_abnormal.Enable(False)
1102 self._CHBOX_relevant.Enable(False)
1103 self._TCTRL_review_comment.SetValue(u'')
1104 self._TCTRL_normal_min.SetValue(u'')
1105 self._TCTRL_normal_max.SetValue(u'')
1106 self._TCTRL_normal_range.SetValue(u'')
1107 self._TCTRL_target_min.SetValue(u'')
1108 self._TCTRL_target_max.SetValue(u'')
1109 self._TCTRL_target_range.SetValue(u'')
1110 self._TCTRL_norm_ref_group.SetValue(u'')
1111
1112 self._PRW_test.SetFocus()
1113
1115 self._PRW_test.SetData(data = self.data['pk_test_type'])
1116 self._TCTRL_result.SetValue(self.data['unified_val'])
1117 self._PRW_units.SetText(self.data['val_unit'], self.data['val_unit'], True)
1118 self._PRW_abnormality_indicator.SetText (
1119 gmTools.coalesce(self.data['abnormality_indicator'], u''),
1120 gmTools.coalesce(self.data['abnormality_indicator'], u''),
1121 True
1122 )
1123 self._DPRW_evaluated.SetData(data = self.data['clin_when'])
1124 self._TCTRL_note_test_org.SetValue(gmTools.coalesce(self.data['note_test_org'], u''))
1125 self._PRW_intended_reviewer.SetData(self.data['pk_intended_reviewer'])
1126 self._PRW_problem.SetData(self.data['pk_episode'])
1127 self._TCTRL_narrative.SetValue(gmTools.coalesce(self.data['comment'], u''))
1128 self._CHBOX_review.SetValue(False)
1129 self._CHBOX_abnormal.SetValue(gmTools.coalesce(self.data['is_technically_abnormal'], False))
1130 self._CHBOX_relevant.SetValue(gmTools.coalesce(self.data['is_clinically_relevant'], False))
1131 self._CHBOX_abnormal.Enable(False)
1132 self._CHBOX_relevant.Enable(False)
1133 self._TCTRL_review_comment.SetValue(gmTools.coalesce(self.data['review_comment'], u''))
1134 self._TCTRL_normal_min.SetValue(unicode(gmTools.coalesce(self.data['val_normal_min'], u'')))
1135 self._TCTRL_normal_max.SetValue(unicode(gmTools.coalesce(self.data['val_normal_max'], u'')))
1136 self._TCTRL_normal_range.SetValue(gmTools.coalesce(self.data['val_normal_range'], u''))
1137 self._TCTRL_target_min.SetValue(unicode(gmTools.coalesce(self.data['val_target_min'], u'')))
1138 self._TCTRL_target_max.SetValue(unicode(gmTools.coalesce(self.data['val_target_max'], u'')))
1139 self._TCTRL_target_range.SetValue(gmTools.coalesce(self.data['val_target_range'], u''))
1140 self._TCTRL_norm_ref_group.SetValue(gmTools.coalesce(self.data['norm_ref_group'], u''))
1141
1142 self._TCTRL_result.SetFocus()
1143
1145 self._refresh_from_existing()
1146
1147 self._PRW_test.SetText(u'', None, True)
1148 self._TCTRL_result.SetValue(u'')
1149 self._PRW_units.SetText(u'', None, True)
1150 self._PRW_abnormality_indicator.SetText(u'', None, True)
1151
1152 self._TCTRL_note_test_org.SetValue(u'')
1153 self._TCTRL_narrative.SetValue(u'')
1154 self._CHBOX_review.SetValue(False)
1155 self._CHBOX_abnormal.SetValue(False)
1156 self._CHBOX_relevant.SetValue(False)
1157 self._CHBOX_abnormal.Enable(False)
1158 self._CHBOX_relevant.Enable(False)
1159 self._TCTRL_review_comment.SetValue(u'')
1160 self._TCTRL_normal_min.SetValue(u'')
1161 self._TCTRL_normal_max.SetValue(u'')
1162 self._TCTRL_normal_range.SetValue(u'')
1163 self._TCTRL_target_min.SetValue(u'')
1164 self._TCTRL_target_max.SetValue(u'')
1165 self._TCTRL_target_range.SetValue(u'')
1166 self._TCTRL_norm_ref_group.SetValue(u'')
1167
1168 self._PRW_test.SetFocus()
1169
1171
1172 validity = True
1173
1174 if not self._DPRW_evaluated.is_valid_timestamp():
1175 self._DPRW_evaluated.display_as_valid(False)
1176 validity = False
1177 else:
1178 self._DPRW_evaluated.display_as_valid(True)
1179
1180 if self._TCTRL_result.GetValue().strip() == u'':
1181 self._TCTRL_result.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
1182 validity = False
1183 else:
1184 self._TCTRL_result.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
1185
1186 if self._PRW_problem.GetValue().strip() == u'':
1187 self._PRW_problem.display_as_valid(False)
1188 validity = False
1189 else:
1190 self._PRW_problem.display_as_valid(True)
1191
1192 if self._PRW_test.GetValue().strip() == u'':
1193 self._PRW_test.display_as_valid(False)
1194 validity = False
1195 else:
1196 self._PRW_test.display_as_valid(True)
1197
1198 if self._PRW_intended_reviewer.GetData() is None:
1199 self._PRW_intended_reviewer.display_as_valid(False)
1200 validity = False
1201 else:
1202 self._PRW_intended_reviewer.display_as_valid(True)
1203
1204 if self._PRW_units.GetValue().strip() == u'':
1205 self._PRW_units.display_as_valid(False)
1206 validity = False
1207 else:
1208 self._PRW_units.display_as_valid(True)
1209
1210 ctrls = [self._TCTRL_normal_min, self._TCTRL_normal_max, self._TCTRL_target_min, self._TCTRL_target_max]
1211 for widget in ctrls:
1212 val = widget.GetValue().strip()
1213 if val == u'':
1214 continue
1215 try:
1216 decimal.Decimal(val.replace(',', u'.', 1))
1217 widget.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
1218 except:
1219 widget.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
1220 validity = False
1221
1222 if validity is False:
1223 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save result. Invalid or missing essential input.'))
1224
1225 return validity
1226
1228
1229 emr = gmPerson.gmCurrentPatient().get_emr()
1230
1231 try:
1232 v_num = decimal.Decimal(self._TCTRL_result.GetValue().strip().replace(',', '.', 1))
1233 v_al = None
1234 except:
1235 v_num = None
1236 v_al = self._TCTRL_result.GetValue().strip()
1237
1238 pk_type = self._PRW_test.GetData()
1239 if pk_type is None:
1240 tt = gmPathLab.create_measurement_type (
1241 lab = None,
1242 abbrev = self._PRW_test.GetValue().strip(),
1243 name = self._PRW_test.GetValue().strip(),
1244 unit = gmTools.none_if(self._PRW_units.GetValue().strip(), u'')
1245 )
1246 pk_type = tt['pk_test_type']
1247
1248 tr = emr.add_test_result (
1249 episode = self._PRW_problem.GetData(can_create=True, is_open=False),
1250 type = pk_type,
1251 intended_reviewer = self._PRW_intended_reviewer.GetData(),
1252 val_num = v_num,
1253 val_alpha = v_al,
1254 unit = self._PRW_units.GetValue()
1255 )
1256
1257 tr['clin_when'] = self._DPRW_evaluated.GetData().get_pydt()
1258
1259 ctrls = [
1260 ('abnormality_indicator', self._PRW_abnormality_indicator),
1261 ('note_test_org', self._TCTRL_note_test_org),
1262 ('comment', self._TCTRL_narrative),
1263 ('val_normal_min', self._TCTRL_normal_min),
1264 ('val_normal_max', self._TCTRL_normal_max),
1265 ('val_normal_range', self._TCTRL_normal_range),
1266 ('val_target_min', self._TCTRL_target_min),
1267 ('val_target_max', self._TCTRL_target_max),
1268 ('val_target_range', self._TCTRL_target_range),
1269 ('norm_ref_group', self._TCTRL_norm_ref_group)
1270 ]
1271 for field, widget in ctrls:
1272 val = widget.GetValue().strip()
1273 if val != u'':
1274 tr[field] = val
1275
1276 tr.save_payload()
1277
1278 if self._CHBOX_review.GetValue() is True:
1279 tr.set_review (
1280 technically_abnormal = self._CHBOX_abnormal.GetValue(),
1281 clinically_relevant = self._CHBOX_relevant.GetValue(),
1282 comment = gmTools.none_if(self._TCTRL_review_comment.GetValue().strip(), u''),
1283 make_me_responsible = False
1284 )
1285
1286 self.data = tr
1287
1288 return True
1289
1291
1292 success, result = gmTools.input2decimal(self._TCTRL_result.GetValue())
1293 if success:
1294 v_num = result
1295 v_al = None
1296 else:
1297 v_num = None
1298 v_al = self._TCTRL_result.GetValue().strip()
1299
1300 pk_type = self._PRW_test.GetData()
1301 if pk_type is None:
1302 tt = gmPathLab.create_measurement_type (
1303 lab = None,
1304 abbrev = self._PRW_test.GetValue().strip(),
1305 name = self._PRW_test.GetValue().strip(),
1306 unit = gmTools.none_if(self._PRW_units.GetValue().strip(), u'')
1307 )
1308 pk_type = tt['pk_test_type']
1309
1310 tr = self.data
1311
1312 tr['pk_episode'] = self._PRW_problem.GetData(can_create=True, is_open=False)
1313 tr['pk_test_type'] = pk_type
1314 tr['pk_intended_reviewer'] = self._PRW_intended_reviewer.GetData()
1315 tr['val_num'] = v_num
1316 tr['val_alpha'] = v_al
1317 tr['val_unit'] = self._PRW_units.GetValue().strip()
1318 tr['clin_when'] = self._DPRW_evaluated.GetData().get_pydt()
1319 tr['abnormality_indicator'] = self._PRW_abnormality_indicator.GetValue().strip()
1320
1321 ctrls = [
1322 ('note_test_org', self._TCTRL_note_test_org),
1323 ('comment', self._TCTRL_narrative),
1324 ('val_normal_min', self._TCTRL_normal_min),
1325 ('val_normal_max', self._TCTRL_normal_max),
1326 ('val_normal_range', self._TCTRL_normal_range),
1327 ('val_target_min', self._TCTRL_target_min),
1328 ('val_target_max', self._TCTRL_target_max),
1329 ('val_target_range', self._TCTRL_target_range),
1330 ('norm_ref_group', self._TCTRL_norm_ref_group)
1331 ]
1332 for field, widget in ctrls:
1333 val = widget.GetValue().strip()
1334 if val != u'':
1335 tr[field] = val
1336
1337 tr.save_payload()
1338
1339 if self._CHBOX_review.GetValue() is True:
1340 tr.set_review (
1341 technically_abnormal = self._CHBOX_abnormal.GetValue(),
1342 clinically_relevant = self._CHBOX_relevant.GetValue(),
1343 comment = gmTools.none_if(self._TCTRL_review_comment.GetValue().strip(), u''),
1344 make_me_responsible = False
1345 )
1346
1347 return True
1348
1349
1350
1354
1356 pk_type = self._PRW_test.GetData()
1357
1358 if pk_type is None:
1359 self._PRW_units.unset_context(context = u'pk_type')
1360 else:
1361 self._PRW_units.set_context(context = u'pk_type', val = pk_type)
1362
1364
1365 if not self._CHBOX_review.GetValue():
1366 self._CHBOX_abnormal.SetValue(self._PRW_abnormality_indicator.GetValue().strip() != u'')
1367
1369 self._CHBOX_abnormal.Enable(self._CHBOX_review.GetValue())
1370 self._CHBOX_relevant.Enable(self._CHBOX_review.GetValue())
1371 self._TCTRL_review_comment.Enable(self._CHBOX_review.GetValue())
1372
1373
1374
1376
1377 if parent is None:
1378 parent = wx.GetApp().GetTopWindow()
1379
1380
1381 def edit(test_type=None):
1382 ea = cMeasurementTypeEAPnl(parent = parent, id = -1, type = test_type)
1383 dlg = gmEditArea.cGenericEditAreaDlg2 (
1384 parent = parent,
1385 id = -1,
1386 edit_area = ea,
1387 single_entry = gmTools.bool2subst((test_type is None), False, True)
1388 )
1389 dlg.SetTitle(gmTools.coalesce(test_type, _('Adding measurement type'), _('Editing measurement type')))
1390
1391 if dlg.ShowModal() == wx.ID_OK:
1392 dlg.Destroy()
1393 return True
1394
1395 dlg.Destroy()
1396 return False
1397
1398 def refresh(lctrl):
1399 mtypes = gmPathLab.get_measurement_types(order_by = 'name, abbrev')
1400 items = [ [
1401 m['abbrev'],
1402 m['name'],
1403 gmTools.coalesce(m['loinc'], u''),
1404 gmTools.coalesce(m['conversion_unit'], u''),
1405 gmTools.coalesce(m['comment_type'], u''),
1406 gmTools.coalesce(m['internal_name_org'], _('in-house')),
1407 gmTools.coalesce(m['comment_org'], u''),
1408 m['pk_test_type']
1409 ] for m in mtypes ]
1410 lctrl.set_string_items(items)
1411 lctrl.set_data(mtypes)
1412
1413 def delete(measurement_type):
1414 if measurement_type.in_use:
1415 gmDispatcher.send (
1416 signal = 'statustext',
1417 beep = True,
1418 msg = _('Cannot delete measurement type [%s (%s)] because it is in use.') % (measurement_type['name'], measurement_type['abbrev'])
1419 )
1420 return False
1421 gmPathLab.delete_measurement_type(measurement_type = measurement_type['pk_test_type'])
1422 return True
1423
1424 msg = _(
1425 '\n'
1426 'These are the measurement types currently defined in GNUmed.\n'
1427 '\n'
1428 )
1429
1430 gmListWidgets.get_choices_from_list (
1431 parent = parent,
1432 msg = msg,
1433 caption = _('Showing measurement types.'),
1434 columns = [_('Abbrev'), _('Name'), _('LOINC'), _('Base unit'), _('Comment'), _('Org'), _('Comment'), u'#'],
1435 single_selection = True,
1436 refresh_callback = refresh,
1437 edit_callback = edit,
1438 new_callback = edit,
1439 delete_callback = delete
1440 )
1441
1443
1445
1446 query = u"""
1447 (
1448 select
1449 pk_test_type,
1450 name_tt
1451 || ' ('
1452 || coalesce (
1453 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1454 '%(in_house)s'
1455 )
1456 || ')'
1457 as name
1458 from clin.v_unified_test_types vcutt
1459 where
1460 name_meta %%(fragment_condition)s
1461
1462 ) union (
1463
1464 select
1465 pk_test_type,
1466 name_tt
1467 || ' ('
1468 || coalesce (
1469 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1470 '%(in_house)s'
1471 )
1472 || ')'
1473 as name
1474 from clin.v_unified_test_types vcutt
1475 where
1476 name_tt %%(fragment_condition)s
1477
1478 ) union (
1479
1480 select
1481 pk_test_type,
1482 name_tt
1483 || ' ('
1484 || coalesce (
1485 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1486 '%(in_house)s'
1487 )
1488 || ')'
1489 as name
1490 from clin.v_unified_test_types vcutt
1491 where
1492 abbrev_meta %%(fragment_condition)s
1493
1494 ) union (
1495
1496 select
1497 pk_test_type,
1498 name_tt
1499 || ' ('
1500 || coalesce (
1501 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1502 '%(in_house)s'
1503 )
1504 || ')'
1505 as name
1506 from clin.v_unified_test_types vcutt
1507 where
1508 code_tt %%(fragment_condition)s
1509 )
1510
1511 order by name
1512 limit 50""" % {'in_house': _('in house lab')}
1513
1514 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1515 mp.setThresholds(1, 2, 4)
1516 mp.word_separators = '[ \t:@]+'
1517 gmPhraseWheel.cPhraseWheel.__init__ (
1518 self,
1519 *args,
1520 **kwargs
1521 )
1522 self.matcher = mp
1523 self.SetToolTipString(_('Select the type of measurement.'))
1524 self.selection_only = False
1525
1527
1529
1530 query = u"""
1531 select distinct on (internal_name)
1532 pk,
1533 internal_name
1534 from clin.test_org
1535 where
1536 internal_name %(fragment_condition)s
1537 order by internal_name
1538 limit 50"""
1539 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1540 mp.setThresholds(1, 2, 4)
1541
1542 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1543 self.matcher = mp
1544 self.SetToolTipString(_('The name of the path lab/diagnostic organisation.'))
1545 self.selection_only = False
1546
1559
1560 from Gnumed.wxGladeWidgets import wxgMeasurementTypeEAPnl
1561
1562 -class cMeasurementTypeEAPnl(wxgMeasurementTypeEAPnl.wxgMeasurementTypeEAPnl, gmEditArea.cGenericEditAreaMixin):
1563
1580
1581
1583
1584
1585 query = u"""
1586 select distinct on (name)
1587 pk,
1588 name
1589 from clin.test_type
1590 where
1591 name %(fragment_condition)s
1592 order by name
1593 limit 50"""
1594 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1595 mp.setThresholds(1, 2, 4)
1596 self._PRW_name.matcher = mp
1597 self._PRW_name.selection_only = False
1598
1599
1600 query = u"""
1601 select distinct on (abbrev)
1602 pk,
1603 abbrev
1604 from clin.test_type
1605 where
1606 abbrev %(fragment_condition)s
1607 order by abbrev
1608 limit 50"""
1609 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1610 mp.setThresholds(1, 2, 3)
1611 self._PRW_abbrev.matcher = mp
1612 self._PRW_abbrev.selection_only = False
1613
1614
1615
1616 query = u"""
1617 select distinct on (conversion_unit)
1618 conversion_unit,
1619 conversion_unit
1620 from clin.test_type
1621 where
1622 conversion_unit %(fragment_condition)s
1623 order by conversion_unit
1624 limit 50"""
1625 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1626 mp.setThresholds(1, 2, 3)
1627 self._PRW_conversion_unit.matcher = mp
1628 self._PRW_conversion_unit.selection_only = False
1629
1630
1631 query = u"""
1632 select distinct on (term)
1633 loinc,
1634 term
1635 from ((
1636 select
1637 loinc,
1638 (loinc || ': ' || abbrev || ' (' || name || ')') as term
1639 from clin.test_type
1640 where loinc %(fragment_condition)s
1641 limit 50
1642 ) union all (
1643 select
1644 code as loinc,
1645 (code || ': ' || term) as term
1646 from ref.v_coded_terms
1647 where
1648 coding_system = 'LOINC'
1649 and
1650 lang = i18n.get_curr_lang()
1651 and
1652 (code %(fragment_condition)s
1653 or
1654 term %(fragment_condition)s)
1655 limit 50
1656 ) union all (
1657 select
1658 code as loinc,
1659 (code || ': ' || term) as term
1660 from ref.v_coded_terms
1661 where
1662 coding_system = 'LOINC'
1663 and
1664 lang = 'en_EN'
1665 and
1666 (code %(fragment_condition)s
1667 or
1668 term %(fragment_condition)s)
1669 limit 50
1670 ) union all (
1671 select
1672 code as loinc,
1673 (code || ': ' || term) as term
1674 from ref.v_coded_terms
1675 where
1676 coding_system = 'LOINC'
1677 and
1678 (code %(fragment_condition)s
1679 or
1680 term %(fragment_condition)s)
1681 limit 50
1682 )
1683 ) as all_known_loinc
1684 order by term
1685 limit 50"""
1686 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
1687 mp.setThresholds(1, 2, 4)
1688 self._PRW_loinc.matcher = mp
1689 self._PRW_loinc.selection_only = False
1690 self._PRW_loinc.add_callback_on_lose_focus(callback = self._on_loinc_lost_focus)
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1708 loinc = self._PRW_loinc.GetData()
1709
1710 if loinc is None:
1711 self._TCTRL_loinc_info.SetValue(u'')
1712 return
1713
1714 info = gmLOINC.loinc2info(loinc = loinc)
1715 if len(info) == 0:
1716 self._TCTRL_loinc_info.SetValue(u'')
1717 return
1718
1719 self._TCTRL_loinc_info.SetValue(info[0])
1720
1721
1722
1724
1725 has_errors = False
1726 for field in [self._PRW_name, self._PRW_abbrev, self._PRW_conversion_unit]:
1727 if field.GetValue().strip() in [u'', None]:
1728 has_errors = True
1729 field.display_as_valid(valid = False)
1730 else:
1731 field.display_as_valid(valid = True)
1732 field.Refresh()
1733
1734 return (not has_errors)
1735
1758
1777
1779 self._PRW_name.SetText(u'', None, True)
1780 self._PRW_abbrev.SetText(u'', None, True)
1781 self._PRW_conversion_unit.SetText(u'', None, True)
1782 self._PRW_loinc.SetText(u'', None, True)
1783 self._TCTRL_loinc_info.SetValue(u'')
1784 self._TCTRL_comment_type.SetValue(u'')
1785 self._PRW_test_org.SetText(u'', None, True)
1786 self._TCTRL_comment_org.SetValue(u'')
1787
1789 self._PRW_name.SetText(self.data['name'], self.data['name'], True)
1790 self._PRW_abbrev.SetText(self.data['abbrev'], self.data['abbrev'], True)
1791 self._PRW_conversion_unit.SetText (
1792 gmTools.coalesce(self.data['conversion_unit'], u''),
1793 self.data['conversion_unit'],
1794 True
1795 )
1796 self._PRW_loinc.SetText (
1797 gmTools.coalesce(self.data['loinc'], u''),
1798 self.data['loinc'],
1799 True
1800 )
1801 self._TCTRL_loinc_info.SetValue(u'')
1802 self._TCTRL_comment_type.SetValue(gmTools.coalesce(self.data['comment_type'], u''))
1803 self._PRW_test_org.SetText (
1804 gmTools.coalesce(self.data['pk_test_org'], u'', self.data['internal_name_org']),
1805 self.data['pk_test_org'],
1806 True
1807 )
1808 self._TCTRL_comment_org.SetValue(gmTools.coalesce(self.data['comment_org'], u''))
1809
1818
1820
1822
1823 query = u"""
1824 select distinct val_unit,
1825 val_unit, val_unit
1826 from clin.v_test_results
1827 where
1828 (
1829 val_unit %(fragment_condition)s
1830 or
1831 conversion_unit %(fragment_condition)s
1832 )
1833 %(ctxt_test_name)s
1834 %(ctxt_test_pk)s
1835 order by val_unit
1836 limit 25"""
1837
1838 ctxt = {
1839 'ctxt_test_name': {
1840 'where_part': u'and %(test)s in (name_tt, name_meta, code_tt, abbrev_meta)',
1841 'placeholder': u'test'
1842 },
1843 'ctxt_test_pk': {
1844 'where_part': u'and pk_test_type = %(pk_type)s',
1845 'placeholder': u'pk_type'
1846 }
1847 }
1848
1849 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query, context=ctxt)
1850 mp.setThresholds(1, 2, 4)
1851 gmPhraseWheel.cPhraseWheel.__init__ (
1852 self,
1853 *args,
1854 **kwargs
1855 )
1856 self.matcher = mp
1857 self.SetToolTipString(_('Select the unit of the test result.'))
1858 self.selection_only = False
1859
1860
1861
1862
1864
1866
1867 query = u"""
1868 select distinct abnormality_indicator,
1869 abnormality_indicator, abnormality_indicator
1870 from clin.v_test_results
1871 where
1872 abnormality_indicator %(fragment_condition)s
1873 order by abnormality_indicator
1874 limit 25"""
1875
1876 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1877 mp.setThresholds(1, 1, 2)
1878 mp.ignored_chars = "[.'\\\[\]#$%_]+" + '"'
1879 mp.word_separators = '[ \t&:]+'
1880 gmPhraseWheel.cPhraseWheel.__init__ (
1881 self,
1882 *args,
1883 **kwargs
1884 )
1885 self.matcher = mp
1886 self.SetToolTipString(_('Select an indicator for the level of abnormality.'))
1887 self.selection_only = False
1888
1889
1890
1902
1904
1905 if parent is None:
1906 parent = wx.GetApp().GetTopWindow()
1907
1908
1909 def edit(org=None):
1910 return edit_measurement_org(parent = parent, org = org)
1911
1912 def refresh(lctrl):
1913 orgs = gmPathLab.get_test_orgs()
1914 lctrl.set_string_items ([
1915 (o['internal_name'], gmTools.coalesce(o['contact'], u''), gmTools.coalesce(o['comment']), o['pk'])
1916 for o in orgs
1917 ])
1918 lctrl.set_data(orgs)
1919
1920 def delete(measurement_type):
1921 if measurement_type.in_use:
1922 gmDispatcher.send (
1923 signal = 'statustext',
1924 beep = True,
1925 msg = _('Cannot delete measurement type [%s (%s)] because it is in use.') % (measurement_type['name'], measurement_type['abbrev'])
1926 )
1927 return False
1928 gmPathLab.delete_measurement_type(measurement_type = measurement_type['pk_test_type'])
1929 return True
1930
1931 gmListWidgets.get_choices_from_list (
1932 parent = parent,
1933 msg = _('\nThese are the diagnostic orgs (path labs etc) currently defined in GNUmed.\n\n'),
1934 caption = _('Showing diagnostic orgs.'),
1935 columns = [_('Name'), _('Contact'), _('Comment'), u'#'],
1936 single_selection = True,
1937 refresh_callback = refresh,
1938 edit_callback = edit,
1939 new_callback = edit
1940
1941 )
1942
1943
1944
1945 from Gnumed.wxGladeWidgets import wxgMeasurementOrgEAPnl
1946
1947 -class cMeasurementOrgEAPnl(wxgMeasurementOrgEAPnl.wxgMeasurementOrgEAPnl, gmEditArea.cGenericEditAreaMixin):
1948
1966
1967
1968
1969
1970
1971
1972
1973
1975 has_errors = False
1976 if self._PRW_name.GetValue().strip() == u'':
1977 has_errors = True
1978 self._PRW_name.display_as_valid(valid = False)
1979 else:
1980 self._PRW_name.display_as_valid(valid = True)
1981
1982 return (not has_errors)
1983
1985
1986 data = self._PRW_name.GetData(can_create = True)
1987
1988 data['contact'] = self._TCTRL_contact.GetValue().strip()
1989 data['comment'] = self._TCTRL_comment.GetValue().strip()
1990 data.save()
1991
1992
1993
1994
1995 self.data = data
1996
1997 return True
1998
2000 self.data['internal_name'] = self._PRW_name.GetValue().strip()
2001 self.data['contact'] = self._TCTRL_contact.GetValue().strip()
2002 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
2003 self.data.save()
2004 return True
2005
2010
2015
2017 self._refresh_as_new()
2018
2057
2058
2059
2060 if __name__ == '__main__':
2061
2062 from Gnumed.pycommon import gmLog2
2063
2064 gmI18N.activate_locale()
2065 gmI18N.install_domain()
2066 gmDateTime.init()
2067
2068
2076
2084
2085
2086
2087
2088
2089
2090
2091 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
2092
2093 test_test_ea_pnl()
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353