Package Gnumed :: Package wxpython :: Module gmAllergyWidgets
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gmAllergyWidgets

  1  """GNUmed allergy related widgets.""" 
  2  ############################################################################ 
  3  __version__ = "$Revision: 1.36 $" 
  4  __author__  = "R.Terry <rterry@gnumed.net>, H.Herb <hherb@gnumed.net>, K.Hilbert <Karsten.Hilbert@gmx.net>" 
  5  __license__ = 'GPL v2 or later (details at http://www.gnu.org)' 
  6   
  7  import sys, time, datetime as pyDT, logging 
  8   
  9   
 10  import wx 
 11   
 12   
 13  if __name__ == '__main__': 
 14          sys.path.insert(0, '../../') 
 15  from Gnumed.pycommon import gmDispatcher, gmI18N, gmDateTime, gmTools, gmMatchProvider 
 16  from Gnumed.wxpython import gmDateTimeInput, gmTerryGuiParts, gmRegetMixin, gmPatSearchWidgets 
 17  from Gnumed.business import gmPerson, gmAllergy, gmPersonSearch 
 18  from Gnumed.wxGladeWidgets import wxgAllergyEditAreaPnl, wxgAllergyEditAreaDlg, wxgAllergyManagerDlg 
 19   
 20  _log = logging.getLogger('gm.ui') 
 21  _log.info(__version__) 
 22   
 23  #====================================================================== 
24 -class cAllergyEditAreaPnl(wxgAllergyEditAreaPnl.wxgAllergyEditAreaPnl):
25
26 - def __init__(self, *args, **kwargs):
27 wxgAllergyEditAreaPnl.wxgAllergyEditAreaPnl.__init__(self, *args, **kwargs) 28 29 try: 30 self.__allergy = kwargs['allergy'] 31 except KeyError: 32 self.__allergy = None 33 34 mp = gmMatchProvider.cMatchProvider_SQL2 ( 35 queries = [u""" 36 select substance, substance 37 from clin.allergy 38 where substance %(fragment_condition)s 39 40 union 41 42 select generics, generics 43 from clin.allergy 44 where generics %(fragment_condition)s 45 46 union 47 48 select allergene, allergene 49 from clin.allergy 50 where allergene %(fragment_condition)s 51 52 union 53 54 select atc_code, atc_code 55 from clin.allergy 56 where atc_code %(fragment_condition)s 57 """ 58 ] 59 ) 60 mp.setThresholds(2, 3, 5) 61 self._PRW_trigger.matcher = mp 62 63 mp = gmMatchProvider.cMatchProvider_SQL2 ( 64 queries = [u""" 65 select narrative, narrative 66 from clin.allergy 67 where narrative %(fragment_condition)s 68 """] 69 ) 70 mp.setThresholds(2, 3, 5) 71 self._PRW_reaction.matcher = mp 72 self._PRW_reaction.enable_default_spellchecker() 73 74 # self._RBTN_type_sensitivity.MoveAfterInTabOrder(self._RBTN_type_allergy) 75 # self._ChBOX_definite.MoveAfterInTabOrder(self._RBTN_type_sensitivity) 76 77 self.refresh()
78 #-------------------------------------------------------- 79 # external API 80 #--------------------------------------------------------
81 - def clear(self):
82 self.__allergy = None 83 return self.refresh()
84 #--------------------------------------------------------
85 - def refresh(self, allergy=None):
86 87 if allergy is not None: 88 self.__allergy = allergy 89 90 if self.__allergy is None: 91 ts = gmDateTime.cFuzzyTimestamp ( 92 timestamp = pyDT.datetime.now(tz=gmDateTime.gmCurrentLocalTimezone), 93 accuracy = gmDateTime.acc_days 94 ) 95 self._DPRW_date_noted.SetData(data = ts) 96 self._PRW_trigger.SetText() 97 self._TCTRL_brand_name.SetValue('') 98 self._TCTRL_generic.SetValue('') 99 self._ChBOX_generic_specific.SetValue(0) 100 self._TCTRL_atc_classes.SetValue('') 101 self._PRW_reaction.SetText() 102 self._RBTN_type_allergy.SetValue(1) 103 self._RBTN_type_sensitivity.SetValue(0) 104 self._ChBOX_definite.SetValue(1) 105 return True 106 107 if not isinstance(self.__allergy, gmAllergy.cAllergy): 108 raise ValueError('[%s].refresh(): expected gmAllergy.cAllergy instance, got [%s] instead' % (self.__class__.__name__, self.__allergy)) 109 110 ts = gmDateTime.cFuzzyTimestamp ( 111 timestamp = self.__allergy['date'], 112 accuracy = gmDateTime.acc_days 113 ) 114 self._DPRW_date_noted.SetData(data=ts) 115 self._PRW_trigger.SetText(value = self.__allergy['allergene']) 116 self._TCTRL_brand_name.SetValue(self.__allergy['substance']) 117 self._TCTRL_generic.SetValue(gmTools.coalesce(self.__allergy['generics'], '')) 118 self._ChBOX_generic_specific.SetValue(self.__allergy['generic_specific']) 119 self._TCTRL_atc_classes.SetValue(gmTools.coalesce(self.__allergy['atc_code'], '')) 120 self._PRW_reaction.SetText(value = gmTools.coalesce(self.__allergy['reaction'], '')) 121 if self.__allergy['type'] == 'allergy': 122 self._RBTN_type_allergy.SetValue(1) 123 else: 124 self._RBTN_type_sensitivity.SetValue(1) 125 self._ChBOX_definite.SetValue(self.__allergy['definite'])
126 #--------------------------------------------------------
127 - def __is_valid_for_save(self):
128 129 if self._PRW_trigger.GetValue().strip() == '': 130 self._PRW_trigger.SetBackgroundColour('pink') 131 self._PRW_trigger.Refresh() 132 self._PRW_trigger.SetFocus() 133 return False 134 self._PRW_trigger.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) 135 self._PRW_trigger.Refresh() 136 137 return True
138 #--------------------------------------------------------
139 - def save(self, can_create=True):
140 if not self.__is_valid_for_save(): 141 return False 142 143 if self.__allergy is None: 144 if not can_create: 145 gmDispatcher.send(signal='statustext', msg=_('Creating new allergy not allowed.')) 146 return False 147 148 pat = gmPerson.gmCurrentPatient() 149 emr = pat.get_emr() 150 151 if self._RBTN_type_allergy.GetValue(): 152 allg_type = 'allergy' 153 else: 154 allg_type = 'sensitivity' 155 self.__allergy = emr.add_allergy ( 156 allergene = self._PRW_trigger.GetValue().strip(), 157 allg_type = allg_type 158 ) 159 160 # and update it with known data 161 self.__allergy['date'] = self._DPRW_date_noted.GetData().get_pydt() 162 self.__allergy['allergene'] = self._PRW_trigger.GetValue().strip() 163 # FIXME: determine brandname/generic/etc from substance (trigger field) 164 self.__allergy['generic_specific'] = (True and self._ChBOX_generic_specific.GetValue()) 165 self.__allergy['reaction'] = self._PRW_reaction.GetValue().strip() 166 self.__allergy['definite'] = (True and self._ChBOX_definite.GetValue()) 167 if self._RBTN_type_allergy.GetValue(): 168 self.__allergy['pk_type'] = 'allergy' 169 else: 170 self.__allergy['pk_type'] = 'sensitivity' 171 172 self.__allergy.save_payload() 173 174 return True
175 #======================================================================
176 -class cAllergyEditAreaDlg(wxgAllergyEditAreaDlg.wxgAllergyEditAreaDlg):
177
178 - def __init__(self, *args, **kwargs):
179 180 try: 181 allergy = kwargs['allergy'] 182 del kwargs['allergy'] 183 except KeyError: 184 allergy = None 185 186 wxgAllergyEditAreaDlg.wxgAllergyEditAreaDlg.__init__(self, *args, **kwargs) 187 188 if allergy is None: 189 # self._BTN_save.SetLabel(_('&Save')) 190 self._BTN_clear.SetLabel(_('&Clear')) 191 else: 192 # self._BTN_save.SetLabel(_('Update')) 193 self._BTN_clear.SetLabel(_('&Restore')) 194 195 self._PNL_edit_area.refresh(allergy = allergy)
196 #--------------------------------------------------------
197 - def _on_save_button_pressed(self, evt):
198 if self._PNL_edit_area.save(): 199 if self.IsModal(): 200 self.EndModal(wx.ID_OK) 201 else: 202 self.Close()
203 #--------------------------------------------------------
204 - def _on_clear_button_pressed(self, evt):
205 self._PNL_edit_area.refresh()
206 #======================================================================
207 -class cAllergyManagerDlg(wxgAllergyManagerDlg.wxgAllergyManagerDlg):
208
209 - def __init__(self, *args, **kwargs):
210 211 wxgAllergyManagerDlg.wxgAllergyManagerDlg.__init__(self, *args, **kwargs) 212 213 self.Centre(direction = wx.BOTH) 214 215 self.__set_columns() 216 # MacOSX crashes on this with: 217 # exception type : wx._core.PyAssertionError 218 # exception value: C++ assertion "i" failed at /BUILD/wxPython-src-2.8.3.0/src/common/wincmn.cpp(2634) in DoMoveInTabOrder(): MoveBefore/AfterInTabOrder(): win is not a sibling 219 # while Win/Linux work just fine 220 #self._PNL_edit_area._ChBOX_definite.MoveAfterInTabOrder(self._BTN_save) 221 self.__refresh_state_ui() 222 self.__refresh_details_ui()
223 #-------------------------------------------------------- 224 # internal helpers 225 #--------------------------------------------------------
226 - def __set_columns(self):
227 self._LCTRL_allergies.set_columns (columns = [ 228 _('Type'), 229 _('Certainty'), 230 _('Trigger'), 231 _('Reaction') 232 ])
233 #--------------------------------------------------------
234 - def __refresh_state_ui(self):
235 236 pat = gmPerson.gmCurrentPatient() 237 emr = pat.get_emr() 238 state = emr.allergy_state 239 240 self._TXT_current_state.SetLabel(state.state_string) 241 242 if state['last_confirmed'] is None: 243 self._TXT_last_confirmed.SetLabel(_('<allergy state unasked>')) 244 else: 245 self._TXT_last_confirmed.SetLabel(state['last_confirmed'].strftime('%x %H:%M')) 246 247 if state['has_allergy'] is None: 248 self._RBTN_unknown.SetValue(True) 249 self._RBTN_none.SetValue(False) 250 self._RBTN_some.SetValue(False) 251 252 self._RBTN_unknown.Enable(True) 253 self._RBTN_none.Enable(True) 254 255 elif state['has_allergy'] == 0: 256 self._RBTN_unknown.SetValue(False) 257 self._RBTN_none.SetValue(True) 258 self._RBTN_some.SetValue(False) 259 260 self._RBTN_unknown.Enable(True) 261 self._RBTN_none.Enable(True) 262 263 elif state['has_allergy'] == 1: 264 self._RBTN_unknown.SetValue(False) 265 self._RBTN_none.SetValue(False) 266 self._RBTN_some.SetValue(True) 267 268 self._RBTN_unknown.Enable(True) 269 self._RBTN_none.Enable(False) 270 271 else: 272 self._RBTN_unknown.SetValue(True) 273 self._RBTN_none.SetValue(False) 274 self._RBTN_some.SetValue(False) 275 276 self._RBTN_unknown.Enable(True) 277 self._RBTN_none.Enable(True) 278 279 gmDispatcher.send(signal=u'statustext', msg=_('invalid allergy state [%s]') % state, beep=True) 280 281 if state['comment'] is not None: 282 self._TCTRL_state_comment.SetValue(state['comment'])
283 #--------------------------------------------------------
284 - def __refresh_details_ui(self):
285 286 pat = gmPerson.gmCurrentPatient() 287 emr = pat.get_emr() 288 allergies = emr.get_allergies() 289 no_of_allergies = len(allergies) 290 291 # display allergies 292 self._LCTRL_allergies.DeleteAllItems() 293 if no_of_allergies > 0: 294 emr.allergy_state = 1 295 296 for allergy in allergies: 297 row_idx = self._LCTRL_allergies.InsertStringItem(no_of_allergies, label = allergy['l10n_type']) 298 if allergy['definite']: 299 label = _('definite') 300 else: 301 label = u'' 302 self._LCTRL_allergies.SetStringItem(index = row_idx, col = 1, label = label) 303 self._LCTRL_allergies.SetStringItem(index = row_idx, col = 2, label = allergy['descriptor']) 304 self._LCTRL_allergies.SetStringItem(index = row_idx, col = 3, label = gmTools.coalesce(allergy['reaction'], u'')) 305 self._LCTRL_allergies.set_data(data=allergies) 306 307 self._LCTRL_allergies.Enable(True) 308 self._RBTN_some.SetValue(True) 309 self._RBTN_unknown.Enable(False) 310 self._RBTN_none.Enable(False) 311 else: 312 self._LCTRL_allergies.Enable(False) 313 self._RBTN_unknown.Enable(True) 314 self._RBTN_none.Enable(True) 315 316 self._LCTRL_allergies.set_column_widths (widths = [ 317 wx.LIST_AUTOSIZE, 318 wx.LIST_AUTOSIZE, 319 wx.LIST_AUTOSIZE, 320 wx.LIST_AUTOSIZE 321 ]) 322 323 self._PNL_edit_area.clear() 324 self._BTN_delete.Enable(False)
325 #-------------------------------------------------------- 326 # event handlers 327 #--------------------------------------------------------
328 - def _on_dismiss_button_pressed(self, evt):
329 if self.IsModal(): 330 self.EndModal(wx.ID_OK) 331 else: 332 self.Close()
333 #--------------------------------------------------------
334 - def _on_clear_button_pressed(self, evt):
335 self._LCTRL_allergies.deselect_selected_item() 336 self._PNL_edit_area.clear() 337 self._BTN_delete.Enable(False)
338 #--------------------------------------------------------
339 - def _on_delete_button_pressed(self, evt):
340 pat = gmPerson.gmCurrentPatient() 341 emr = pat.get_emr() 342 343 allergy = self._LCTRL_allergies.get_selected_item_data(only_one=True) 344 if allergy is None: 345 return 346 emr.delete_allergy(pk_allergy = allergy['pk_allergy']) 347 348 state = emr.allergy_state 349 state['last_confirmed'] = u'now' 350 state.save_payload() 351 352 self.__refresh_state_ui() 353 self.__refresh_details_ui()
354 #--------------------------------------------------------
355 - def _on_list_item_selected(self, evt):
356 allergy = self._LCTRL_allergies.get_selected_item_data(only_one=True) 357 if allergy is None: 358 return 359 self._PNL_edit_area.refresh(allergy=allergy) 360 self._BTN_delete.Enable(True)
361 #--------------------------------------------------------
362 - def _on_confirm_button_pressed(self, evt):
363 pat = gmPerson.gmCurrentPatient() 364 emr = pat.get_emr() 365 allergies = emr.get_allergies() 366 state = emr.allergy_state 367 368 cmt = self._TCTRL_state_comment.GetValue().strip() 369 370 if self._RBTN_unknown.GetValue(): 371 if len(allergies) > 0: 372 gmDispatcher.send(signal = u'statustext', msg = _('Cannot set allergy state to <unknown> because there are allergies stored for this patient.'), beep = True) 373 self._RBTN_some.SetValue(True) 374 state['has_allergy'] = 1 375 return False 376 else: 377 state['has_allergy'] = None 378 379 elif self._RBTN_none.GetValue(): 380 if len(allergies) > 0: 381 gmDispatcher.send(signal = u'statustext', msg = _('Cannot set allergy state to <None> because there are allergies stored for this patient.'), beep = True) 382 self._RBTN_some.SetValue(True) 383 state['has_allergy'] = 1 384 return False 385 else: 386 state['has_allergy'] = 0 387 388 elif self._RBTN_some.GetValue(): 389 if (len(allergies) == 0) and (cmt == u''): 390 gmDispatcher.send(signal = u'statustext', msg = _('Cannot set allergy state to <some> because there are neither allergies nor a comment available for this patient.'), beep = True) 391 return False 392 else: 393 state['has_allergy'] = 1 394 395 state['comment'] = cmt 396 state['last_confirmed'] = u'now' 397 398 state.save_payload() 399 self.__refresh_state_ui()
400 #--------------------------------------------------------
401 - def _on_save_details_button_pressed(self, evt):
402 403 if not self._PNL_edit_area.save(): 404 return False 405 406 pat = gmPerson.gmCurrentPatient() 407 emr = pat.get_emr() 408 state = emr.allergy_state 409 state['last_confirmed'] = u'now' 410 state.save_payload() 411 412 self.__refresh_state_ui() 413 self.__refresh_details_ui()
414 #======================================================================
415 -class cAllergyPanel(wx.Panel, gmRegetMixin.cRegetOnPaintMixin):
416 """Allergy details panel. 417 418 This panel will hold all the allergy details and 419 allow entry of those details via the editing area. 420 """ 421 #----------------------------------------------------
422 - def __init__(self, parent, id=-1):
423 wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER) 424 gmRegetMixin.cRegetOnPaintMixin.__init__(self) 425 self.__do_layout() 426 self.__pat = gmPerson.gmCurrentPatient() 427 self.__register_interests() 428 self.__reset_ui_content()
429 #----------------------------------------------------
430 - def __do_layout(self):
431 # -- top part -- 432 pnl_UpperCaption = gmTerryGuiParts.cHeadingCaption(self, -1, _("ALLERGIES")) 433 self.editarea = gmAllergyEditArea(self, -1) 434 435 # -- middle part -- 436 # divider headings below edit area 437 pnl_MiddleCaption = gmTerryGuiParts.cDividerCaption(self, -1, _("Allergy and Sensitivity - Summary")) 438 # self.sizer_divider_drug_generic = wx.BoxSizer(wxHORIZONTAL) 439 # self.sizer_divider_drug_generic.Add(pnl_MiddleCaption, 1, wxEXPAND) 440 self.LCTRL_allergies = wx.ListCtrl ( 441 parent = self, 442 id = ID_ALLERGY_LIST, 443 pos = wx.DefaultPosition, 444 size = wx.DefaultSize, 445 style = wx.LC_SINGLE_SEL | wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_HRULES | wx.LC_VRULES | wx.VSCROLL 446 ) 447 self.LCTRL_allergies.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, '')) 448 self.LCTRL_allergies.InsertColumn(0, _("Type")) 449 self.LCTRL_allergies.InsertColumn(1, _("Status")) 450 self.LCTRL_allergies.InsertColumn(2, _("ATC/Class")) 451 self.LCTRL_allergies.InsertColumn(3, _("Substance")) 452 self.LCTRL_allergies.InsertColumn(4, _("Generics")) 453 self.LCTRL_allergies.InsertColumn(5, _("Reaction")) 454 455 # -- bottom part -- 456 pnl_LowerCaption = gmTerryGuiParts.cDividerCaption(self, -1, _('Class notes')) 457 #add a richtext control or a wxTextCtrl multiline to display the class text information 458 #e.g. would contain say information re the penicillins 459 self.class_notes = wx.TextCtrl ( 460 self, 461 -1, 462 "A member of a new class of nonsteroidal anti-inflammatory agents (COX-2 selective NSAIDs) which have a mechanism of action that inhibits prostaglandin synthesis primarily by inhibition of cyclooxygenase 2 (COX-2). At therapeutic doses these have no effect on prostanoids synthesised by activation of COX-1 thereby not interfering with normal COX-1 related physiological processes in tissues, particularly the stomach, intestine and platelets.", 463 size = (200, 100), 464 style = wx.TE_MULTILINE | wx.TE_READONLY 465 ) 466 self.class_notes.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, '')) 467 468 # -- add elements to main background sizer -- 469 self.mainsizer = wx.BoxSizer(wx.VERTICAL) 470 self.mainsizer.Add(pnl_UpperCaption, 0, wx.EXPAND) 471 self.mainsizer.Add(self.editarea, 6, wx.EXPAND) 472 # self.mainsizer.Add(self.sizer_divider_drug_generic,0,wxEXPAND) 473 self.mainsizer.Add(pnl_MiddleCaption, 0, wx.EXPAND) 474 self.mainsizer.Add(self.LCTRL_allergies, 5, wx.EXPAND) 475 self.mainsizer.Add(pnl_LowerCaption, 0, wx.EXPAND) 476 self.mainsizer.Add(self.class_notes, 4, wx.EXPAND) 477 478 self.SetAutoLayout(True) 479 self.SetSizer(self.mainsizer) 480 self.mainsizer.Fit(self)
481 #-----------------------------------------------
482 - def __register_interests(self):
483 wx.EVT_LIST_ITEM_ACTIVATED(self, ID_ALLERGY_LIST, self._on_allergy_activated) 484 485 # client internal signals 486 gmDispatcher.connect(signal = u'post_patient_selection', receiver=self._schedule_data_reget)
487 # gmDispatcher.connect(signal = u'vaccinations_updated', receiver=self._schedule_data_reget) 488 #-----------------------------------------------
489 - def __reset_ui_content(self):
490 self.editarea.set_data() 491 self.LCTRL_allergies.DeleteAllItems()
492 #-----------------------------------------------
493 - def _populate_with_data(self):
494 if not self.__pat.connected: 495 return False 496 497 self.LCTRL_allergies.DeleteAllItems() 498 499 emr = self.__pat.get_emr() 500 allergies = emr.get_allergies() 501 if allergies is None: 502 return False 503 for list_line in range(len(allergies)): 504 allg = allergies[list_line] 505 list_line = self.LCTRL_allergies.InsertStringItem(list_line, allg['l10n_type']) 506 # FIXME: check with Richard design specs 507 if allg['definite']: 508 self.LCTRL_allergies.SetStringItem(list_line, 1, _('definite')) 509 else: 510 self.LCTRL_allergies.SetStringItem(list_line, 1, _('likely')) 511 if allg['atc_code'] is not None: 512 self.LCTRL_allergies.SetStringItem(list_line, 2, allg['atc_code']) 513 self.LCTRL_allergies.SetStringItem(list_line, 3, allg['substance']) 514 if allg['generics'] is not None: 515 self.LCTRL_allergies.SetStringItem(list_line, 4, allg['generics']) 516 self.LCTRL_allergies.SetStringItem(list_line, 5, allg['reaction']) 517 self.LCTRL_allergies.SetItemData(list_line, allg['pk_allergy']) 518 for col in range(5): 519 self.LCTRL_allergies.SetColumnWidth(col, wx.LIST_AUTOSIZE) 520 # FIXME: resize event needed ? 521 return True
522 #-----------------------------------------------
523 - def _on_allergy_activated(self, evt):
524 pk_allg = evt.GetData() 525 emr = self.__pat.get_emr() 526 allgs = emr.get_allergies(ID_list=[pk_allg]) 527 self.editarea.set_data(allergy = allgs[0])
528 #====================================================================== 529 # main 530 #---------------------------------------------------------------------- 531 if __name__ == "__main__": 532 533 gmI18N.activate_locale() 534 gmI18N.install_domain(domain='gnumed') 535 536 #-----------------------------------------------
537 - def test_allergy_edit_area_dlg():
538 app = wx.PyWidgetTester(size = (600, 600)) 539 dlg = cAllergyEditAreaDlg(parent=app.frame, id=-1) 540 dlg.ShowModal() 541 # emr = pat.get_emr() 542 # allergy = emr.get_allergies()[0] 543 # dlg = cAllergyEditAreaDlg(parent=app.frame, id=-1, allergy=allergy) 544 # dlg.ShowModal() 545 return
546 #-----------------------------------------------
547 - def test_allergy_manager_dlg():
548 app = wx.PyWidgetTester(size = (800, 600)) 549 dlg = cAllergyManagerDlg(parent=app.frame, id=-1) 550 dlg.ShowModal() 551 return
552 #----------------------------------------------- 553 if len(sys.argv) > 1 and sys.argv[1] == 'test': 554 555 pat = gmPersonSearch.ask_for_patient() 556 if pat is None: 557 sys.exit(0) 558 gmPatSearchWidgets.set_active_patient(pat) 559 560 #test_allergy_edit_area_dlg() 561 test_allergy_manager_dlg() 562 563 # app = wxPyWidgetTester(size = (600, 600)) 564 # app.SetWidget(cAllergyPanel, -1) 565 # app.MainLoop() 566 #====================================================================== 567