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
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
17 from Gnumed.pycommon import gmTools, gmDispatcher, gmMatchProvider, gmDateTime, gmI18N, gmCfg, gmShellAPI
18 from Gnumed.wxpython import gmRegetMixin, gmPhraseWheel, gmEditArea, gmGuiHelpers, gmListWidgets, gmAuthWidgets, gmPatSearchWidgets
19 from Gnumed.wxGladeWidgets import wxgMeasurementsPnl, wxgMeasurementsReviewDlg
20 from Gnumed.wxGladeWidgets import wxgMeasurementEditAreaPnl
21
22
23 _log = logging.getLogger('gm.ui')
24 _log.info(__version__)
25
26
27
28
30
31 wx.BeginBusyCursor()
32
33 gmDispatcher.send(signal = 'statustext', msg = _('Updating LOINC data can take quite a while...'), beep = True)
34
35
36 downloaded = gmShellAPI.run_command_in_shell(command = 'gm-download_loinc', blocking = True)
37 if not downloaded:
38 wx.EndBusyCursor()
39 gmGuiHelpers.gm_show_warning (
40 aTitle = _('Downloading LOINC'),
41 aMessage = _(
42 'Running <gm-download_loinc> to retrieve\n'
43 'the latest LOINC data failed.\n'
44 )
45 )
46 return False
47
48
49 data_fname, license_fname = gmLOINC.split_LOINCDBTXT(input_fname = '/tmp/LOINCDB.TXT')
50
51 wx.EndBusyCursor()
52
53 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('importing LOINC reference data'))
54 if conn is None:
55 return False
56
57 wx.BeginBusyCursor()
58
59 if gmLOINC.loinc_import(data_fname = data_fname, license_fname = license_fname, conn = conn):
60 gmDispatcher.send(signal = 'statustext', msg = _('Successfully imported LOINC reference data.'))
61 try:
62 os.remove(data_fname)
63 os.remove(license_fname)
64 except OSError:
65 _log.error('unable to remove [%s] or [%s]', data_fname, license_fname)
66 else:
67 gmDispatcher.send(signal = 'statustext', msg = _('Importing LOINC reference data failed.'), beep = True)
68
69 wx.EndBusyCursor()
70 return True
71
72
73
75
76 dbcfg = gmCfg.cCfgSQL()
77
78 url = dbcfg.get (
79 option = u'external.urls.measurements_search',
80 workplace = gmSurgery.gmCurrentPractice().active_workplace,
81 bias = 'user',
82 default = u"http://www.google.de/search?as_oq=%(search_term)s&num=10&as_sitesearch=laborlexikon.de"
83 )
84
85 base_url = dbcfg.get2 (
86 option = u'external.urls.measurements_encyclopedia',
87 workplace = gmSurgery.gmCurrentPractice().active_workplace,
88 bias = 'user',
89 default = u'http://www.laborlexikon.de'
90 )
91
92 if measurement_type is None:
93 url = base_url
94
95 measurement_type = measurement_type.strip()
96
97 if measurement_type == u'':
98 url = base_url
99
100 url = url % {'search_term': measurement_type}
101
102 webbrowser.open (
103 url = url,
104 new = False,
105 autoraise = True
106 )
107
119
120
121
122
123
124
125
126
127
128
129
131 """A grid class for displaying measurment results.
132
133 - does NOT listen to the currently active patient
134 - thereby it can display any patient at any time
135 """
136
137
138
139
140
141
143
144 wx.grid.Grid.__init__(self, *args, **kwargs)
145
146 self.__patient = None
147 self.__cell_data = {}
148 self.__row_label_data = []
149
150 self.__prev_row = None
151 self.__prev_col = None
152 self.__prev_label_row = None
153 self.__date_format = str((_('lab_grid_date_format::%Y\n%b %d')).lstrip('lab_grid_date_format::'))
154
155 self.__init_ui()
156 self.__register_events()
157
158
159
161 if not self.IsSelection():
162 gmDispatcher.send(signal = u'statustext', msg = _('No results selected for deletion.'))
163 return True
164
165 selected_cells = self.get_selected_cells()
166 if len(selected_cells) > 20:
167 results = None
168 msg = _(
169 'There are %s results marked for deletion.\n'
170 '\n'
171 'Are you sure you want to delete these results ?'
172 ) % len(selected_cells)
173 else:
174 results = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
175 txt = u'\n'.join([ u'%s %s (%s): %s %s%s' % (
176 r['clin_when'].strftime('%x %H:%M').decode(gmI18N.get_encoding()),
177 r['unified_abbrev'],
178 r['unified_name'],
179 r['unified_val'],
180 r['val_unit'],
181 gmTools.coalesce(r['abnormality_indicator'], u'', u' (%s)')
182 ) for r in results
183 ])
184 msg = _(
185 'The following results are marked for deletion:\n'
186 '\n'
187 '%s\n'
188 '\n'
189 'Are you sure you want to delete these results ?'
190 ) % txt
191
192 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
193 self,
194 -1,
195 caption = _('Deleting test results'),
196 question = msg,
197 button_defs = [
198 {'label': _('Delete'), 'tooltip': _('Yes, delete all the results.'), 'default': False},
199 {'label': _('Cancel'), 'tooltip': _('No, do NOT delete any results.'), 'default': True}
200 ]
201 )
202 decision = dlg.ShowModal()
203
204 if decision == wx.ID_YES:
205 if results is None:
206 results = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
207 for result in results:
208 gmPathLab.delete_test_result(result)
209
211 if not self.IsSelection():
212 gmDispatcher.send(signal = u'statustext', msg = _('Cannot sign results. No results selected.'))
213 return True
214
215 selected_cells = self.get_selected_cells()
216 if len(selected_cells) > 10:
217 test_count = len(selected_cells)
218 tests = None
219 else:
220 test_count = None
221 tests = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
222
223 dlg = cMeasurementsReviewDlg (
224 self,
225 -1,
226 tests = tests,
227 test_count = test_count
228 )
229 decision = dlg.ShowModal()
230
231 if decision == wx.ID_APPLY:
232 wx.BeginBusyCursor()
233
234 if dlg._RBTN_confirm_abnormal.GetValue():
235 abnormal = None
236 elif dlg._RBTN_results_normal.GetValue():
237 abnormal = False
238 else:
239 abnormal = True
240
241 if dlg._RBTN_confirm_relevance.GetValue():
242 relevant = None
243 elif dlg._RBTN_results_not_relevant.GetValue():
244 relevant = False
245 else:
246 relevant = True
247
248 if tests is None:
249 tests = self.__cells_to_data(cells = selected_cells, exclude_multi_cells = False)
250
251 comment = None
252 if len(tests) == 1:
253 comment = dlg._TCTRL_comment.GetValue()
254
255 for test in tests:
256 test.set_review (
257 technically_abnormal = abnormal,
258 clinically_relevant = relevant,
259 comment = comment,
260 make_me_responsible = dlg._CHBOX_responsible.IsChecked()
261 )
262
263 wx.EndBusyCursor()
264
265 dlg.Destroy()
266
268
269 sel_block_top_left = self.GetSelectionBlockTopLeft()
270 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
271 sel_cols = self.GetSelectedCols()
272 sel_rows = self.GetSelectedRows()
273
274 selected_cells = []
275
276
277 selected_cells += self.GetSelectedCells()
278
279
280 selected_cells += list (
281 (row, col)
282 for row in sel_rows
283 for col in xrange(self.GetNumberCols())
284 )
285
286
287 selected_cells += list (
288 (row, col)
289 for row in xrange(self.GetNumberRows())
290 for col in sel_cols
291 )
292
293
294 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
295 selected_cells += [
296 (row, col)
297 for row in xrange(top_left[0], bottom_right[0] + 1)
298 for col in xrange(top_left[1], bottom_right[1] + 1)
299 ]
300
301 return set(selected_cells)
302
303 - def select_cells(self, unsigned_only=False, accountables_only=False, keep_preselections=False):
304 """Select a range of cells according to criteria.
305
306 unsigned_only: include only those which are not signed at all yet
307 accountable_only: include only those for which the current user is responsible
308 keep_preselections: broaden (rather than replace) the range of selected cells
309
310 Combinations are powerful !
311 """
312 wx.BeginBusyCursor()
313 self.BeginBatch()
314
315 if not keep_preselections:
316 self.ClearSelection()
317
318 for col_idx in self.__cell_data.keys():
319 for row_idx in self.__cell_data[col_idx].keys():
320
321
322 do_not_include = False
323 for result in self.__cell_data[col_idx][row_idx]:
324 if unsigned_only:
325 if result['reviewed']:
326 do_not_include = True
327 break
328 if accountables_only:
329 if not result['you_are_responsible']:
330 do_not_include = True
331 break
332 if do_not_include:
333 continue
334
335 self.SelectBlock(row_idx, col_idx, row_idx, col_idx, addToSelected = True)
336
337 self.EndBatch()
338 wx.EndBusyCursor()
339
341
342 self.empty_grid()
343 if self.__patient is None:
344 return
345
346 emr = self.__patient.get_emr()
347
348 self.__row_label_data = emr.get_test_types_for_results()
349 test_type_labels = [ u'%s (%s)' % (test['unified_abbrev'], test['unified_name']) for test in self.__row_label_data ]
350 if len(test_type_labels) == 0:
351 return
352
353 test_date_labels = [ date[0].strftime(self.__date_format) for date in emr.get_dates_for_results() ]
354 results = emr.get_test_results_by_date()
355
356 self.BeginBatch()
357
358
359 self.AppendRows(numRows = len(test_type_labels))
360 for row_idx in range(len(test_type_labels)):
361 self.SetRowLabelValue(row_idx, test_type_labels[row_idx])
362
363
364 self.AppendCols(numCols = len(test_date_labels))
365 for date_idx in range(len(test_date_labels)):
366 self.SetColLabelValue(date_idx, test_date_labels[date_idx])
367
368
369 for result in results:
370 row = test_type_labels.index(u'%s (%s)' % (result['unified_abbrev'], result['unified_name']))
371 col = test_date_labels.index(result['clin_when'].strftime(self.__date_format))
372
373 try:
374 self.__cell_data[col]
375 except KeyError:
376 self.__cell_data[col] = {}
377
378
379 if self.__cell_data[col].has_key(row):
380 self.__cell_data[col][row].append(result)
381 self.__cell_data[col][row].sort(key = lambda x: x['clin_when'], reverse = True)
382 else:
383 self.__cell_data[col][row] = [result]
384
385
386 vals2display = []
387 for sub_result in self.__cell_data[col][row]:
388
389
390 ind = gmTools.coalesce(sub_result['abnormality_indicator'], u'').strip()
391 if ind != u'':
392 lab_abnormality_indicator = u' (%s)' % ind[:3]
393 else:
394 lab_abnormality_indicator = u''
395
396 if sub_result['is_technically_abnormal'] is None:
397 abnormality_indicator = lab_abnormality_indicator
398
399 elif sub_result['is_technically_abnormal'] is False:
400 abnormality_indicator = u''
401
402 else:
403
404 if lab_abnormality_indicator == u'':
405
406 abnormality_indicator = u' (%s)' % gmTools.u_plus_minus
407
408 else:
409 abnormality_indicator = lab_abnormality_indicator
410
411
412
413 sub_result_relevant = sub_result['is_clinically_relevant']
414 if sub_result_relevant is None:
415
416 sub_result_relevant = False
417
418 missing_review = False
419
420
421 if not sub_result['reviewed']:
422 missing_review = True
423
424 else:
425
426 if sub_result['you_are_responsible'] and not sub_result['review_by_you']:
427 missing_review = True
428
429
430 if len(sub_result['unified_val']) > 8:
431 tmp = u'%.7s%s' % (sub_result['unified_val'][:7], gmTools.u_ellipsis)
432 else:
433 tmp = u'%.8s' % sub_result['unified_val'][:8]
434
435
436 tmp = u'%s%.6s' % (tmp, abnormality_indicator)
437
438
439 has_sub_result_comment = gmTools.coalesce (
440 gmTools.coalesce(sub_result['note_test_org'], sub_result['comment']),
441 u''
442 ).strip() != u''
443 if has_sub_result_comment:
444 tmp = u'%s %s' % (tmp, gmTools.u_ellipsis)
445
446
447 if missing_review:
448 tmp = u'%s %s' % (tmp, gmTools.u_writing_hand)
449
450
451 if len(self.__cell_data[col][row]) > 1:
452 tmp = u'%s %s' % (sub_result['clin_when'].strftime('%H:%M'), tmp)
453
454 vals2display.append(tmp)
455
456 self.SetCellValue(row, col, u'\n'.join(vals2display))
457 self.SetCellAlignment(row, col, horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
458
459
460
461
462 if sub_result_relevant:
463 font = self.GetCellFont(row, col)
464 self.SetCellTextColour(row, col, 'firebrick')
465 font.SetWeight(wx.FONTWEIGHT_BOLD)
466 self.SetCellFont(row, col, font)
467
468
469 self.AutoSize()
470 self.EndBatch()
471 return
472
474 self.BeginBatch()
475 self.ClearGrid()
476
477
478 if self.GetNumberRows() > 0:
479 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
480 if self.GetNumberCols() > 0:
481 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
482 self.EndBatch()
483 self.__cell_data = {}
484 self.__row_label_data = []
485
524
772
773
774
776 self.CreateGrid(0, 1)
777 self.EnableEditing(0)
778 self.EnableDragGridSize(1)
779
780
781
782
783
784 self.SetRowLabelSize(150)
785 self.SetRowLabelAlignment(horiz = wx.ALIGN_LEFT, vert = wx.ALIGN_CENTRE)
786
787
788 dbcfg = gmCfg.cCfgSQL()
789 url = dbcfg.get2 (
790 option = u'external.urls.measurements_encyclopedia',
791 workplace = gmSurgery.gmCurrentPractice().active_workplace,
792 bias = 'user',
793 default = u'http://www.laborlexikon.de'
794 )
795
796 self.__WIN_corner = self.GetGridCornerLabelWindow()
797
798 LNK_lab = wx.lib.hyperlink.HyperLinkCtrl (
799 self.__WIN_corner,
800 -1,
801 label = _('Reference'),
802 style = wx.HL_DEFAULT_STYLE
803 )
804 LNK_lab.SetURL(url)
805 LNK_lab.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BACKGROUND))
806 LNK_lab.SetToolTipString(_(
807 'Navigate to an encyclopedia of measurements\n'
808 'and test methods on the web.\n'
809 '\n'
810 ' <%s>'
811 ) % url)
812
813 SZR_inner = wx.BoxSizer(wx.HORIZONTAL)
814 SZR_inner.Add((20, 20), 1, wx.EXPAND, 0)
815 SZR_inner.Add(LNK_lab, 0, wx.ALIGN_CENTER_VERTICAL, 0)
816 SZR_inner.Add((20, 20), 1, wx.EXPAND, 0)
817
818 SZR_corner = wx.BoxSizer(wx.VERTICAL)
819 SZR_corner.Add((20, 20), 1, wx.EXPAND, 0)
820 SZR_corner.AddWindow(SZR_inner, 0, wx.EXPAND)
821 SZR_corner.Add((20, 20), 1, wx.EXPAND, 0)
822
823 self.__WIN_corner.SetSizer(SZR_corner)
824 SZR_corner.Fit(self.__WIN_corner)
825
827 self.__WIN_corner.Layout()
828
830 """List of <cells> must be in row / col order."""
831 data = []
832 for row, col in cells:
833 try:
834
835 data_list = self.__cell_data[col][row]
836 except KeyError:
837 continue
838
839 if len(data_list) == 1:
840 data.append(data_list[0])
841 continue
842
843 if exclude_multi_cells:
844 gmDispatcher.send(signal = u'statustext', msg = _('Excluding multi-result field from further processing.'))
845 continue
846
847 data_to_include = self.__get_choices_from_multi_cell(cell_data = data_list)
848
849 if data_to_include is None:
850 continue
851
852 data.extend(data_to_include)
853
854 return data
855
857 data = gmListWidgets.get_choices_from_list (
858 parent = self,
859 msg = _(
860 'Your selection includes a field with multiple results.\n'
861 '\n'
862 'Please select the individual results you want to work on:'
863 ),
864 caption = _('Selecting test results'),
865 choices = [ [d['clin_when'], d['unified_abbrev'], d['unified_name'], d['unified_val']] for d in cell_data ],
866 columns = [_('Date / Time'), _('Code'), _('Test'), _('Result')],
867 data = cell_data,
868 single_selection = single_selection
869 )
870 return data
871
872
873
875
876 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
877 self.GetGridRowLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_row_labels)
878
879
880
881 self.Bind(wx.EVT_SIZE, self.__resize_corner_window)
882
883
884 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
885
887 col = evt.GetCol()
888 row = evt.GetRow()
889
890
891 try:
892 self.__cell_data[col][row]
893 except KeyError:
894
895
896 return
897
898 if len(self.__cell_data[col][row]) > 1:
899 data = self.__get_choices_from_multi_cell(cell_data = self.__cell_data[col][row], single_selection = True)
900 else:
901 data = self.__cell_data[col][row][0]
902
903 if data is None:
904 return
905
906 edit_measurement(parent = self, measurement = data, single_entry = True)
907
908
909
910
911
912
913
915
916
917
918 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
919
920 row = self.YToRow(y)
921
922 if self.__prev_label_row == row:
923 return
924
925 self.__prev_label_row == row
926
927 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
928
929
930
931
932
933
934
935
937 """Calculate where the mouse is and set the tooltip dynamically."""
938
939
940
941 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
942
943
944
945
946
947
948
949
950
951
952
953
954
955 row, col = self.XYToCell(x, y)
956
957 if (row == self.__prev_row) and (col == self.__prev_col):
958 return
959
960 self.__prev_row = row
961 self.__prev_col = col
962
963 evt.GetEventObject().SetToolTipString(self.get_cell_tooltip(col=col, row=row))
964
965
966
970
971 patient = property(lambda x:x, _set_patient)
972
973 -class cMeasurementsPnl(wxgMeasurementsPnl.wxgMeasurementsPnl, gmRegetMixin.cRegetOnPaintMixin):
974
975 """Panel holding a grid with lab data. Used as notebook page."""
976
983
984
985
987 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
988 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
989 gmDispatcher.connect(signal = u'test_result_mod_db', receiver = self._schedule_data_reget)
990 gmDispatcher.connect(signal = u'reviewed_test_results_mod_db', receiver = self._schedule_data_reget)
991
993 wx.CallAfter(self.__on_post_patient_selection)
994
996 self._schedule_data_reget()
997
999 wx.CallAfter(self.__on_pre_patient_selection)
1000
1003
1006
1012
1015
1018
1019
1020
1022 self.__action_button_popup = wx.Menu(title = _('Act on selected results'))
1023
1024 menu_id = wx.NewId()
1025 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Review and &sign')))
1026 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_sign_current_selection)
1027
1028 menu_id = wx.NewId()
1029 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Export to &file')))
1030
1031 self.__action_button_popup.Enable(id = menu_id, enable = False)
1032
1033 menu_id = wx.NewId()
1034 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('Export to &clipboard')))
1035
1036 self.__action_button_popup.Enable(id = menu_id, enable = False)
1037
1038 menu_id = wx.NewId()
1039 self.__action_button_popup.AppendItem(wx.MenuItem(self.__action_button_popup, menu_id, _('&Delete')))
1040 wx.EVT_MENU(self.__action_button_popup, menu_id, self.__on_delete_current_selection)
1041
1042
1043
1052
1053
1054
1056
1058
1059 try:
1060 tests = kwargs['tests']
1061 del kwargs['tests']
1062 test_count = len(tests)
1063 try: del kwargs['test_count']
1064 except KeyError: pass
1065 except KeyError:
1066 tests = None
1067 test_count = kwargs['test_count']
1068 del kwargs['test_count']
1069
1070 wxgMeasurementsReviewDlg.wxgMeasurementsReviewDlg.__init__(self, *args, **kwargs)
1071
1072 if tests is None:
1073 msg = _('%s results selected. Too many to list individually.') % test_count
1074 else:
1075 msg = ' // '.join (
1076 [ u'%s: %s %s (%s)' % (
1077 t['unified_abbrev'],
1078 t['unified_val'],
1079 t['val_unit'],
1080 t['clin_when'].strftime('%x').decode(gmI18N.get_encoding())
1081 ) for t in tests
1082 ]
1083 )
1084
1085 self._LBL_tests.SetLabel(msg)
1086
1087 if test_count == 1:
1088 self._TCTRL_comment.Enable(True)
1089 self._TCTRL_comment.SetValue(gmTools.coalesce(tests[0]['review_comment'], u''))
1090 if tests[0]['you_are_responsible']:
1091 self._CHBOX_responsible.Enable(False)
1092
1093 self.Fit()
1094
1095
1096
1102
1103 -class cMeasurementEditAreaPnl(wxgMeasurementEditAreaPnl.wxgMeasurementEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
1104 """This edit area saves *new* measurements into the active patient only."""
1105
1120
1121
1122
1124 self._PRW_test.SetText(u'', None, True)
1125 self._TCTRL_result.SetValue(u'')
1126 self._PRW_units.SetText(u'', None, True)
1127 self._PRW_abnormality_indicator.SetText(u'', None, True)
1128 if self.__default_date is None:
1129 self._DPRW_evaluated.SetData(data = pyDT.datetime.now(tz = gmDateTime.gmCurrentLocalTimezone))
1130 else:
1131 self._DPRW_evaluated.SetData(data = None)
1132 self._TCTRL_note_test_org.SetValue(u'')
1133 self._PRW_intended_reviewer.SetData()
1134 self._PRW_problem.SetData()
1135 self._TCTRL_narrative.SetValue(u'')
1136 self._CHBOX_review.SetValue(False)
1137 self._CHBOX_abnormal.SetValue(False)
1138 self._CHBOX_relevant.SetValue(False)
1139 self._CHBOX_abnormal.Enable(False)
1140 self._CHBOX_relevant.Enable(False)
1141 self._TCTRL_review_comment.SetValue(u'')
1142 self._TCTRL_normal_min.SetValue(u'')
1143 self._TCTRL_normal_max.SetValue(u'')
1144 self._TCTRL_normal_range.SetValue(u'')
1145 self._TCTRL_target_min.SetValue(u'')
1146 self._TCTRL_target_max.SetValue(u'')
1147 self._TCTRL_target_range.SetValue(u'')
1148 self._TCTRL_norm_ref_group.SetValue(u'')
1149
1150 self._PRW_test.SetFocus()
1151
1153 self._PRW_test.SetData(data = self.data['pk_test_type'])
1154 self._TCTRL_result.SetValue(self.data['unified_val'])
1155 self._PRW_units.SetText(self.data['val_unit'], self.data['val_unit'], True)
1156 self._PRW_abnormality_indicator.SetText (
1157 gmTools.coalesce(self.data['abnormality_indicator'], u''),
1158 gmTools.coalesce(self.data['abnormality_indicator'], u''),
1159 True
1160 )
1161 self._DPRW_evaluated.SetData(data = self.data['clin_when'])
1162 self._TCTRL_note_test_org.SetValue(gmTools.coalesce(self.data['note_test_org'], u''))
1163 self._PRW_intended_reviewer.SetData(self.data['pk_intended_reviewer'])
1164 self._PRW_problem.SetData(self.data['pk_episode'])
1165 self._TCTRL_narrative.SetValue(gmTools.coalesce(self.data['comment'], u''))
1166 self._CHBOX_review.SetValue(False)
1167 self._CHBOX_abnormal.SetValue(gmTools.coalesce(self.data['is_technically_abnormal'], False))
1168 self._CHBOX_relevant.SetValue(gmTools.coalesce(self.data['is_clinically_relevant'], False))
1169 self._CHBOX_abnormal.Enable(False)
1170 self._CHBOX_relevant.Enable(False)
1171 self._TCTRL_review_comment.SetValue(gmTools.coalesce(self.data['review_comment'], u''))
1172 self._TCTRL_normal_min.SetValue(unicode(gmTools.coalesce(self.data['val_normal_min'], u'')))
1173 self._TCTRL_normal_max.SetValue(unicode(gmTools.coalesce(self.data['val_normal_max'], u'')))
1174 self._TCTRL_normal_range.SetValue(gmTools.coalesce(self.data['val_normal_range'], u''))
1175 self._TCTRL_target_min.SetValue(unicode(gmTools.coalesce(self.data['val_target_min'], u'')))
1176 self._TCTRL_target_max.SetValue(unicode(gmTools.coalesce(self.data['val_target_max'], u'')))
1177 self._TCTRL_target_range.SetValue(gmTools.coalesce(self.data['val_target_range'], u''))
1178 self._TCTRL_norm_ref_group.SetValue(gmTools.coalesce(self.data['norm_ref_group'], u''))
1179
1180 self._TCTRL_result.SetFocus()
1181
1183 self._refresh_from_existing()
1184
1185 self._PRW_test.SetText(u'', None, True)
1186 self._TCTRL_result.SetValue(u'')
1187 self._PRW_units.SetText(u'', None, True)
1188 self._PRW_abnormality_indicator.SetText(u'', None, True)
1189
1190 self._TCTRL_note_test_org.SetValue(u'')
1191 self._TCTRL_narrative.SetValue(u'')
1192 self._CHBOX_review.SetValue(False)
1193 self._CHBOX_abnormal.SetValue(False)
1194 self._CHBOX_relevant.SetValue(False)
1195 self._CHBOX_abnormal.Enable(False)
1196 self._CHBOX_relevant.Enable(False)
1197 self._TCTRL_review_comment.SetValue(u'')
1198 self._TCTRL_normal_min.SetValue(u'')
1199 self._TCTRL_normal_max.SetValue(u'')
1200 self._TCTRL_normal_range.SetValue(u'')
1201 self._TCTRL_target_min.SetValue(u'')
1202 self._TCTRL_target_max.SetValue(u'')
1203 self._TCTRL_target_range.SetValue(u'')
1204 self._TCTRL_norm_ref_group.SetValue(u'')
1205
1206 self._PRW_test.SetFocus()
1207
1209
1210 validity = True
1211
1212 if not self._DPRW_evaluated.is_valid_timestamp():
1213 self._DPRW_evaluated.display_as_valid(False)
1214 validity = False
1215 else:
1216 self._DPRW_evaluated.display_as_valid(True)
1217
1218 if self._TCTRL_result.GetValue().strip() == u'':
1219 self._TCTRL_result.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
1220 validity = False
1221 else:
1222 self._TCTRL_result.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
1223
1224 if self._PRW_problem.GetValue().strip() == u'':
1225 self._PRW_problem.display_as_valid(False)
1226 validity = False
1227 else:
1228 self._PRW_problem.display_as_valid(True)
1229
1230 if self._PRW_test.GetValue().strip() == u'':
1231 self._PRW_test.display_as_valid(False)
1232 validity = False
1233 else:
1234 self._PRW_test.display_as_valid(True)
1235
1236 if self._PRW_intended_reviewer.GetData() is None:
1237 self._PRW_intended_reviewer.display_as_valid(False)
1238 validity = False
1239 else:
1240 self._PRW_intended_reviewer.display_as_valid(True)
1241
1242 if self._PRW_units.GetValue().strip() == u'':
1243 self._PRW_units.display_as_valid(False)
1244 validity = False
1245 else:
1246 self._PRW_units.display_as_valid(True)
1247
1248 ctrls = [self._TCTRL_normal_min, self._TCTRL_normal_max, self._TCTRL_target_min, self._TCTRL_target_max]
1249 for widget in ctrls:
1250 val = widget.GetValue().strip()
1251 if val == u'':
1252 continue
1253 try:
1254 decimal.Decimal(val.replace(',', u'.', 1))
1255 widget.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
1256 except:
1257 widget.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
1258 validity = False
1259
1260 if validity is False:
1261 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save result. Invalid or missing essential input.'))
1262
1263 return validity
1264
1266
1267 emr = gmPerson.gmCurrentPatient().get_emr()
1268
1269 try:
1270 v_num = decimal.Decimal(self._TCTRL_result.GetValue().strip().replace(',', '.', 1))
1271 v_al = None
1272 except:
1273 v_num = None
1274 v_al = self._TCTRL_result.GetValue().strip()
1275
1276 pk_type = self._PRW_test.GetData()
1277 if pk_type is None:
1278 tt = gmPathLab.create_measurement_type (
1279 lab = None,
1280 abbrev = self._PRW_test.GetValue().strip(),
1281 name = self._PRW_test.GetValue().strip(),
1282 unit = gmTools.none_if(self._PRW_units.GetValue().strip(), u'')
1283 )
1284 pk_type = tt['pk_test_type']
1285
1286 tr = emr.add_test_result (
1287 episode = self._PRW_problem.GetData(can_create=True, is_open=False),
1288 type = pk_type,
1289 intended_reviewer = self._PRW_intended_reviewer.GetData(),
1290 val_num = v_num,
1291 val_alpha = v_al,
1292 unit = self._PRW_units.GetValue()
1293 )
1294
1295 tr['clin_when'] = self._DPRW_evaluated.GetData().get_pydt()
1296
1297 ctrls = [
1298 ('abnormality_indicator', self._PRW_abnormality_indicator),
1299 ('note_test_org', self._TCTRL_note_test_org),
1300 ('comment', self._TCTRL_narrative),
1301 ('val_normal_min', self._TCTRL_normal_min),
1302 ('val_normal_max', self._TCTRL_normal_max),
1303 ('val_normal_range', self._TCTRL_normal_range),
1304 ('val_target_min', self._TCTRL_target_min),
1305 ('val_target_max', self._TCTRL_target_max),
1306 ('val_target_range', self._TCTRL_target_range),
1307 ('norm_ref_group', self._TCTRL_norm_ref_group)
1308 ]
1309 for field, widget in ctrls:
1310 val = widget.GetValue().strip()
1311 if val != u'':
1312 tr[field] = val
1313
1314 tr.save_payload()
1315
1316 if self._CHBOX_review.GetValue() is True:
1317 tr.set_review (
1318 technically_abnormal = self._CHBOX_abnormal.GetValue(),
1319 clinically_relevant = self._CHBOX_relevant.GetValue(),
1320 comment = gmTools.none_if(self._TCTRL_review_comment.GetValue().strip(), u''),
1321 make_me_responsible = False
1322 )
1323
1324 self.data = tr
1325
1326 return True
1327
1329
1330 success, result = gmTools.input2decimal(self._TCTRL_result.GetValue())
1331 if success:
1332 v_num = result
1333 v_al = None
1334 else:
1335 v_num = None
1336 v_al = self._TCTRL_result.GetValue().strip()
1337
1338 pk_type = self._PRW_test.GetData()
1339 if pk_type is None:
1340 tt = gmPathLab.create_measurement_type (
1341 lab = None,
1342 abbrev = self._PRW_test.GetValue().strip(),
1343 name = self._PRW_test.GetValue().strip(),
1344 unit = gmTools.none_if(self._PRW_units.GetValue().strip(), u'')
1345 )
1346 pk_type = tt['pk_test_type']
1347
1348 tr = self.data
1349
1350 tr['pk_episode'] = self._PRW_problem.GetData(can_create=True, is_open=False)
1351 tr['pk_test_type'] = pk_type
1352 tr['pk_intended_reviewer'] = self._PRW_intended_reviewer.GetData()
1353 tr['val_num'] = v_num
1354 tr['val_alpha'] = v_al
1355 tr['val_unit'] = self._PRW_units.GetValue().strip()
1356 tr['clin_when'] = self._DPRW_evaluated.GetData().get_pydt()
1357 tr['abnormality_indicator'] = self._PRW_abnormality_indicator.GetValue().strip()
1358
1359 ctrls = [
1360 ('note_test_org', self._TCTRL_note_test_org),
1361 ('comment', self._TCTRL_narrative),
1362 ('val_normal_min', self._TCTRL_normal_min),
1363 ('val_normal_max', self._TCTRL_normal_max),
1364 ('val_normal_range', self._TCTRL_normal_range),
1365 ('val_target_min', self._TCTRL_target_min),
1366 ('val_target_max', self._TCTRL_target_max),
1367 ('val_target_range', self._TCTRL_target_range),
1368 ('norm_ref_group', self._TCTRL_norm_ref_group)
1369 ]
1370 for field, widget in ctrls:
1371 val = widget.GetValue().strip()
1372 if val != u'':
1373 tr[field] = val
1374
1375 tr.save_payload()
1376
1377 if self._CHBOX_review.GetValue() is True:
1378 tr.set_review (
1379 technically_abnormal = self._CHBOX_abnormal.GetValue(),
1380 clinically_relevant = self._CHBOX_relevant.GetValue(),
1381 comment = gmTools.none_if(self._TCTRL_review_comment.GetValue().strip(), u''),
1382 make_me_responsible = False
1383 )
1384
1385 return True
1386
1387
1388
1392
1394 pk_type = self._PRW_test.GetData()
1395
1396 if pk_type is None:
1397 self._PRW_units.unset_context(context = u'pk_type')
1398 else:
1399 self._PRW_units.set_context(context = u'pk_type', val = pk_type)
1400
1402
1403 if not self._CHBOX_review.GetValue():
1404 self._CHBOX_abnormal.SetValue(self._PRW_abnormality_indicator.GetValue().strip() != u'')
1405
1407 self._CHBOX_abnormal.Enable(self._CHBOX_review.GetValue())
1408 self._CHBOX_relevant.Enable(self._CHBOX_review.GetValue())
1409 self._TCTRL_review_comment.Enable(self._CHBOX_review.GetValue())
1410
1427
1428
1429
1431
1432 if parent is None:
1433 parent = wx.GetApp().GetTopWindow()
1434
1435
1436 def edit(test_type=None):
1437 ea = cMeasurementTypeEAPnl(parent = parent, id = -1, type = test_type)
1438 dlg = gmEditArea.cGenericEditAreaDlg2 (
1439 parent = parent,
1440 id = -1,
1441 edit_area = ea,
1442 single_entry = gmTools.bool2subst((test_type is None), False, True)
1443 )
1444 dlg.SetTitle(gmTools.coalesce(test_type, _('Adding measurement type'), _('Editing measurement type')))
1445
1446 if dlg.ShowModal() == wx.ID_OK:
1447 dlg.Destroy()
1448 return True
1449
1450 dlg.Destroy()
1451 return False
1452
1453 def refresh(lctrl):
1454 mtypes = gmPathLab.get_measurement_types(order_by = 'name, abbrev')
1455 items = [ [
1456 m['abbrev'],
1457 m['name'],
1458 gmTools.coalesce(m['loinc'], u''),
1459 gmTools.coalesce(m['conversion_unit'], u''),
1460 gmTools.coalesce(m['comment_type'], u''),
1461 gmTools.coalesce(m['internal_name_org'], _('in-house')),
1462 gmTools.coalesce(m['comment_org'], u''),
1463 m['pk_test_type']
1464 ] for m in mtypes ]
1465 lctrl.set_string_items(items)
1466 lctrl.set_data(mtypes)
1467
1468 def delete(measurement_type):
1469 if measurement_type.in_use:
1470 gmDispatcher.send (
1471 signal = 'statustext',
1472 beep = True,
1473 msg = _('Cannot delete measurement type [%s (%s)] because it is in use.') % (measurement_type['name'], measurement_type['abbrev'])
1474 )
1475 return False
1476 gmPathLab.delete_measurement_type(measurement_type = measurement_type['pk_test_type'])
1477 return True
1478
1479 msg = _(
1480 '\n'
1481 'These are the measurement types currently defined in GNUmed.\n'
1482 '\n'
1483 )
1484
1485 gmListWidgets.get_choices_from_list (
1486 parent = parent,
1487 msg = msg,
1488 caption = _('Showing measurement types.'),
1489 columns = [_('Abbrev'), _('Name'), _('LOINC'), _('Base unit'), _('Comment'), _('Org'), _('Comment'), u'#'],
1490 single_selection = True,
1491 refresh_callback = refresh,
1492 edit_callback = edit,
1493 new_callback = edit,
1494 delete_callback = delete
1495 )
1496
1498
1500
1501 query = u"""
1502 (
1503 select
1504 pk_test_type,
1505 name_tt
1506 || ' ('
1507 || coalesce (
1508 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1509 '%(in_house)s'
1510 )
1511 || ')'
1512 as name
1513 from clin.v_unified_test_types vcutt
1514 where
1515 name_meta %%(fragment_condition)s
1516
1517 ) union (
1518
1519 select
1520 pk_test_type,
1521 name_tt
1522 || ' ('
1523 || coalesce (
1524 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1525 '%(in_house)s'
1526 )
1527 || ')'
1528 as name
1529 from clin.v_unified_test_types vcutt
1530 where
1531 name_tt %%(fragment_condition)s
1532
1533 ) union (
1534
1535 select
1536 pk_test_type,
1537 name_tt
1538 || ' ('
1539 || coalesce (
1540 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1541 '%(in_house)s'
1542 )
1543 || ')'
1544 as name
1545 from clin.v_unified_test_types vcutt
1546 where
1547 abbrev_meta %%(fragment_condition)s
1548
1549 ) union (
1550
1551 select
1552 pk_test_type,
1553 name_tt
1554 || ' ('
1555 || coalesce (
1556 (select internal_name from clin.test_org cto where cto.pk = vcutt.pk_test_org),
1557 '%(in_house)s'
1558 )
1559 || ')'
1560 as name
1561 from clin.v_unified_test_types vcutt
1562 where
1563 code_tt %%(fragment_condition)s
1564 )
1565
1566 order by name
1567 limit 50""" % {'in_house': _('in house lab')}
1568
1569 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1570 mp.setThresholds(1, 2, 4)
1571 mp.word_separators = '[ \t:@]+'
1572 gmPhraseWheel.cPhraseWheel.__init__ (
1573 self,
1574 *args,
1575 **kwargs
1576 )
1577 self.matcher = mp
1578 self.SetToolTipString(_('Select the type of measurement.'))
1579 self.selection_only = False
1580
1582
1584
1585 query = u"""
1586 select distinct on (internal_name)
1587 pk,
1588 internal_name
1589 from clin.test_org
1590 where
1591 internal_name %(fragment_condition)s
1592 order by internal_name
1593 limit 50"""
1594 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1595 mp.setThresholds(1, 2, 4)
1596
1597 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1598 self.matcher = mp
1599 self.SetToolTipString(_('The name of the path lab/diagnostic organisation.'))
1600 self.selection_only = False
1601
1614
1615 from Gnumed.wxGladeWidgets import wxgMeasurementTypeEAPnl
1616
1617 -class cMeasurementTypeEAPnl(wxgMeasurementTypeEAPnl.wxgMeasurementTypeEAPnl, gmEditArea.cGenericEditAreaMixin):
1618
1635
1636
1638
1639
1640 query = u"""
1641 select distinct on (name)
1642 pk,
1643 name
1644 from clin.test_type
1645 where
1646 name %(fragment_condition)s
1647 order by name
1648 limit 50"""
1649 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1650 mp.setThresholds(1, 2, 4)
1651 self._PRW_name.matcher = mp
1652 self._PRW_name.selection_only = False
1653
1654
1655 query = u"""
1656 select distinct on (abbrev)
1657 pk,
1658 abbrev
1659 from clin.test_type
1660 where
1661 abbrev %(fragment_condition)s
1662 order by abbrev
1663 limit 50"""
1664 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1665 mp.setThresholds(1, 2, 3)
1666 self._PRW_abbrev.matcher = mp
1667 self._PRW_abbrev.selection_only = False
1668
1669
1670
1671 query = u"""
1672 select distinct on (conversion_unit)
1673 conversion_unit,
1674 conversion_unit
1675 from clin.test_type
1676 where
1677 conversion_unit %(fragment_condition)s
1678 order by conversion_unit
1679 limit 50"""
1680 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1681 mp.setThresholds(1, 2, 3)
1682 self._PRW_conversion_unit.matcher = mp
1683 self._PRW_conversion_unit.selection_only = False
1684
1685
1686 query = u"""
1687 select distinct on (term)
1688 loinc,
1689 term
1690 from ((
1691 select
1692 loinc,
1693 (loinc || ': ' || abbrev || ' (' || name || ')') as term
1694 from clin.test_type
1695 where loinc %(fragment_condition)s
1696 limit 50
1697 ) union all (
1698 select
1699 code as loinc,
1700 (code || ': ' || term) as term
1701 from ref.v_coded_terms
1702 where
1703 coding_system = 'LOINC'
1704 and
1705 lang = i18n.get_curr_lang()
1706 and
1707 (code %(fragment_condition)s
1708 or
1709 term %(fragment_condition)s)
1710 limit 50
1711 ) union all (
1712 select
1713 code as loinc,
1714 (code || ': ' || term) as term
1715 from ref.v_coded_terms
1716 where
1717 coding_system = 'LOINC'
1718 and
1719 lang = 'en_EN'
1720 and
1721 (code %(fragment_condition)s
1722 or
1723 term %(fragment_condition)s)
1724 limit 50
1725 ) union all (
1726 select
1727 code as loinc,
1728 (code || ': ' || term) as term
1729 from ref.v_coded_terms
1730 where
1731 coding_system = 'LOINC'
1732 and
1733 (code %(fragment_condition)s
1734 or
1735 term %(fragment_condition)s)
1736 limit 50
1737 )
1738 ) as all_known_loinc
1739 order by term
1740 limit 50"""
1741 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
1742 mp.setThresholds(1, 2, 4)
1743 self._PRW_loinc.matcher = mp
1744 self._PRW_loinc.selection_only = False
1745 self._PRW_loinc.add_callback_on_lose_focus(callback = self._on_loinc_lost_focus)
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1763 loinc = self._PRW_loinc.GetData()
1764
1765 if loinc is None:
1766 self._TCTRL_loinc_info.SetValue(u'')
1767 return
1768
1769 info = gmLOINC.loinc2info(loinc = loinc)
1770 if len(info) == 0:
1771 self._TCTRL_loinc_info.SetValue(u'')
1772 return
1773
1774 self._TCTRL_loinc_info.SetValue(info[0])
1775
1776
1777
1779
1780 has_errors = False
1781 for field in [self._PRW_name, self._PRW_abbrev, self._PRW_conversion_unit]:
1782 if field.GetValue().strip() in [u'', None]:
1783 has_errors = True
1784 field.display_as_valid(valid = False)
1785 else:
1786 field.display_as_valid(valid = True)
1787 field.Refresh()
1788
1789 return (not has_errors)
1790
1813
1832
1834 self._PRW_name.SetText(u'', None, True)
1835 self._PRW_abbrev.SetText(u'', None, True)
1836 self._PRW_conversion_unit.SetText(u'', None, True)
1837 self._PRW_loinc.SetText(u'', None, True)
1838 self._TCTRL_loinc_info.SetValue(u'')
1839 self._TCTRL_comment_type.SetValue(u'')
1840 self._PRW_test_org.SetText(u'', None, True)
1841 self._TCTRL_comment_org.SetValue(u'')
1842
1844 self._PRW_name.SetText(self.data['name'], self.data['name'], True)
1845 self._PRW_abbrev.SetText(self.data['abbrev'], self.data['abbrev'], True)
1846 self._PRW_conversion_unit.SetText (
1847 gmTools.coalesce(self.data['conversion_unit'], u''),
1848 self.data['conversion_unit'],
1849 True
1850 )
1851 self._PRW_loinc.SetText (
1852 gmTools.coalesce(self.data['loinc'], u''),
1853 self.data['loinc'],
1854 True
1855 )
1856 self._TCTRL_loinc_info.SetValue(u'')
1857 self._TCTRL_comment_type.SetValue(gmTools.coalesce(self.data['comment_type'], u''))
1858 self._PRW_test_org.SetText (
1859 gmTools.coalesce(self.data['pk_test_org'], u'', self.data['internal_name_org']),
1860 self.data['pk_test_org'],
1861 True
1862 )
1863 self._TCTRL_comment_org.SetValue(gmTools.coalesce(self.data['comment_org'], u''))
1864
1873
1875
1877
1878 query = u"""
1879 select distinct val_unit,
1880 val_unit, val_unit
1881 from clin.v_test_results
1882 where
1883 (
1884 val_unit %(fragment_condition)s
1885 or
1886 conversion_unit %(fragment_condition)s
1887 )
1888 %(ctxt_test_name)s
1889 %(ctxt_test_pk)s
1890 order by val_unit
1891 limit 25"""
1892
1893 ctxt = {
1894 'ctxt_test_name': {
1895 'where_part': u'and %(test)s in (name_tt, name_meta, code_tt, abbrev_meta)',
1896 'placeholder': u'test'
1897 },
1898 'ctxt_test_pk': {
1899 'where_part': u'and pk_test_type = %(pk_type)s',
1900 'placeholder': u'pk_type'
1901 }
1902 }
1903
1904 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query, context=ctxt)
1905 mp.setThresholds(1, 2, 4)
1906 gmPhraseWheel.cPhraseWheel.__init__ (
1907 self,
1908 *args,
1909 **kwargs
1910 )
1911 self.matcher = mp
1912 self.SetToolTipString(_('Select the unit of the test result.'))
1913 self.selection_only = False
1914
1915
1916
1917
1919
1921
1922 query = u"""
1923 select distinct abnormality_indicator,
1924 abnormality_indicator, abnormality_indicator
1925 from clin.v_test_results
1926 where
1927 abnormality_indicator %(fragment_condition)s
1928 order by abnormality_indicator
1929 limit 25"""
1930
1931 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
1932 mp.setThresholds(1, 1, 2)
1933 mp.ignored_chars = "[.'\\\[\]#$%_]+" + '"'
1934 mp.word_separators = '[ \t&:]+'
1935 gmPhraseWheel.cPhraseWheel.__init__ (
1936 self,
1937 *args,
1938 **kwargs
1939 )
1940 self.matcher = mp
1941 self.SetToolTipString(_('Select an indicator for the level of abnormality.'))
1942 self.selection_only = False
1943
1944
1945
1957
1959
1960 if parent is None:
1961 parent = wx.GetApp().GetTopWindow()
1962
1963
1964 def edit(org=None):
1965 return edit_measurement_org(parent = parent, org = org)
1966
1967 def refresh(lctrl):
1968 orgs = gmPathLab.get_test_orgs()
1969 lctrl.set_string_items ([
1970 (o['internal_name'], gmTools.coalesce(o['contact'], u''), gmTools.coalesce(o['comment']), o['pk'])
1971 for o in orgs
1972 ])
1973 lctrl.set_data(orgs)
1974
1975 def delete(measurement_type):
1976 if measurement_type.in_use:
1977 gmDispatcher.send (
1978 signal = 'statustext',
1979 beep = True,
1980 msg = _('Cannot delete measurement type [%s (%s)] because it is in use.') % (measurement_type['name'], measurement_type['abbrev'])
1981 )
1982 return False
1983 gmPathLab.delete_measurement_type(measurement_type = measurement_type['pk_test_type'])
1984 return True
1985
1986 gmListWidgets.get_choices_from_list (
1987 parent = parent,
1988 msg = _('\nThese are the diagnostic orgs (path labs etc) currently defined in GNUmed.\n\n'),
1989 caption = _('Showing diagnostic orgs.'),
1990 columns = [_('Name'), _('Contact'), _('Comment'), u'#'],
1991 single_selection = True,
1992 refresh_callback = refresh,
1993 edit_callback = edit,
1994 new_callback = edit
1995
1996 )
1997
1998
1999
2000 from Gnumed.wxGladeWidgets import wxgMeasurementOrgEAPnl
2001
2002 -class cMeasurementOrgEAPnl(wxgMeasurementOrgEAPnl.wxgMeasurementOrgEAPnl, gmEditArea.cGenericEditAreaMixin):
2003
2021
2022
2023
2024
2025
2026
2027
2028
2030 has_errors = False
2031 if self._PRW_name.GetValue().strip() == u'':
2032 has_errors = True
2033 self._PRW_name.display_as_valid(valid = False)
2034 else:
2035 self._PRW_name.display_as_valid(valid = True)
2036
2037 return (not has_errors)
2038
2040
2041 data = self._PRW_name.GetData(can_create = True)
2042
2043 data['contact'] = self._TCTRL_contact.GetValue().strip()
2044 data['comment'] = self._TCTRL_comment.GetValue().strip()
2045 data.save()
2046
2047
2048
2049
2050 self.data = data
2051
2052 return True
2053
2055 self.data['internal_name'] = self._PRW_name.GetValue().strip()
2056 self.data['contact'] = self._TCTRL_contact.GetValue().strip()
2057 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
2058 self.data.save()
2059 return True
2060
2065
2070
2072 self._refresh_as_new()
2073
2112
2113
2114
2115 if __name__ == '__main__':
2116
2117 from Gnumed.pycommon import gmLog2
2118
2119 gmI18N.activate_locale()
2120 gmI18N.install_domain()
2121 gmDateTime.init()
2122
2123
2131
2139
2140
2141
2142
2143
2144
2145
2146 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
2147
2148 test_test_ea_pnl()
2149
2150
2151
2152