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

Source Code for Module Gnumed.wxpython.gmEMRStructWidgets

   1  """GNUmed EMR structure editors 
   2   
   3          This module contains widgets to create and edit EMR structural 
   4          elements (issues, enconters, episodes). 
   5   
   6          This is based on initial work and ideas by Syan <kittylitter@swiftdsl.com.au> 
   7          and Karsten <Karsten.Hilbert@gmx.net>. 
   8  """ 
   9  #================================================================ 
  10  __author__ = "cfmoro1976@yahoo.es, karsten.hilbert@gmx.net" 
  11  __license__ = "GPL v2 or later" 
  12   
  13  # stdlib 
  14  import sys 
  15  import time 
  16  import logging 
  17  import datetime as pydt 
  18   
  19   
  20  # 3rd party 
  21  import wx 
  22   
  23   
  24  # GNUmed 
  25  if __name__ == '__main__': 
  26          sys.path.insert(0, '../../') 
  27   
  28  from Gnumed.pycommon import gmI18N 
  29  from Gnumed.pycommon import gmDateTime 
  30   
  31  if __name__ == '__main__': 
  32          gmI18N.activate_locale() 
  33          gmI18N.install_domain() 
  34          gmDateTime.init() 
  35   
  36  from Gnumed.pycommon import gmExceptions 
  37  from Gnumed.pycommon import gmCfg 
  38  from Gnumed.pycommon import gmTools 
  39  from Gnumed.pycommon import gmDispatcher 
  40  from Gnumed.pycommon import gmMatchProvider 
  41   
  42  from Gnumed.business import gmEMRStructItems 
  43  from Gnumed.business import gmPraxis 
  44  from Gnumed.business import gmPerson 
  45   
  46  from Gnumed.wxpython import gmPhraseWheel 
  47  from Gnumed.wxpython import gmGuiHelpers 
  48  from Gnumed.wxpython import gmListWidgets 
  49  from Gnumed.wxpython import gmEditArea 
  50   
  51   
  52  _log = logging.getLogger('gm.ui') 
  53   
  54  #================================================================ 
  55  # EMR access helper functions 
  56  #---------------------------------------------------------------- 
57 -def emr_access_spinner(time2spin=0):
58 """Spin time in seconds but let wx go on.""" 59 if time2spin == 0: 60 return 61 sleep_time = 0.1 # 100ms 62 total_rounds = int(time2spin / sleep_time) 63 if total_rounds < 1: 64 wx.Yield() 65 time.sleep(sleep_time) 66 return 67 rounds = 0 68 while rounds < total_rounds: 69 wx.Yield() 70 time.sleep(sleep_time) 71 rounds += 1
72 73 #================================================================ 74 # episode related widgets/functions 75 #----------------------------------------------------------------
76 -def edit_episode(parent=None, episode=None):
77 ea = cEpisodeEditAreaPnl(parent, -1) 78 ea.data = episode 79 ea.mode = gmTools.coalesce(episode, 'new', 'edit') 80 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = True) 81 dlg.SetTitle(gmTools.coalesce(episode, _('Adding a new episode'), _('Editing an episode'))) 82 if dlg.ShowModal() == wx.ID_OK: 83 return True 84 return False
85 86 #----------------------------------------------------------------
87 -def manage_episodes(parent=None):
88 89 pat = gmPerson.gmCurrentPatient() 90 emr = pat.emr 91 92 if parent is None: 93 parent = wx.GetApp().GetTopWindow() 94 #----------------------------------------- 95 def edit(episode=None): 96 return edit_episode(parent = parent, episode = episode)
97 #----------------------------------------- 98 def delete(episode=None): 99 if gmEMRStructItems.delete_episode(episode = episode): 100 return True 101 gmDispatcher.send ( 102 signal = 'statustext', 103 msg = _('Cannot delete episode.'), 104 beep = True 105 ) 106 return False 107 #----------------------------------------- 108 def manage_issues(episode=None): 109 return select_health_issues(parent = None, emr = emr) 110 #----------------------------------------- 111 def get_tooltip(data): 112 if data is None: 113 return None 114 return data.format ( 115 patient = pat, 116 with_summary = True, 117 with_codes = True, 118 with_encounters = False, 119 with_documents = False, 120 with_hospital_stays = False, 121 with_procedures = False, 122 with_family_history = False, 123 with_tests = False, 124 with_vaccinations = False, 125 with_health_issue = True 126 ) 127 #----------------------------------------- 128 def refresh(lctrl): 129 epis = emr.get_episodes(order_by = 'description') 130 items = [ 131 [ e['description'], 132 gmTools.bool2subst(e['episode_open'], _('ongoing'), _('closed'), '<unknown>'), 133 gmDateTime.pydt_strftime(e.best_guess_clinical_start_date, '%Y %b %d'), 134 gmTools.coalesce(e['health_issue'], '') 135 ] for e in epis 136 ] 137 lctrl.set_string_items(items = items) 138 lctrl.set_data(data = epis) 139 #----------------------------------------- 140 gmListWidgets.get_choices_from_list ( 141 parent = parent, 142 msg = _('\nSelect the episode you want to edit !\n'), 143 caption = _('Editing episodes ...'), 144 columns = [_('Episode'), _('Status'), _('Started'), _('Health issue')], 145 single_selection = True, 146 edit_callback = edit, 147 new_callback = edit, 148 delete_callback = delete, 149 refresh_callback = refresh, 150 list_tooltip_callback = get_tooltip, 151 left_extra_button = (_('Manage issues'), _('Manage health issues'), manage_issues) 152 ) 153 154 #----------------------------------------------------------------
155 -def promote_episode_to_issue(parent=None, episode=None, emr=None):
156 157 created_new_issue = False 158 159 try: 160 issue = gmEMRStructItems.cHealthIssue(name = episode['description'], patient = episode['pk_patient']) 161 except gmExceptions.NoSuchBusinessObjectError: 162 issue = None 163 164 if issue is None: 165 issue = emr.add_health_issue(issue_name = episode['description']) 166 created_new_issue = True 167 else: 168 # issue exists already, so ask user 169 dlg = gmGuiHelpers.c3ButtonQuestionDlg ( 170 parent, 171 -1, 172 caption = _('Promoting episode to health issue'), 173 question = _( 174 'There already is a health issue\n' 175 '\n' 176 ' %s\n' 177 '\n' 178 'What do you want to do ?' 179 ) % issue['description'], 180 button_defs = [ 181 {'label': _('Use existing'), 'tooltip': _('Move episode into existing health issue'), 'default': False}, 182 {'label': _('Create new'), 'tooltip': _('Create a new health issue with another name'), 'default': True} 183 ] 184 ) 185 use_existing = dlg.ShowModal() 186 dlg.Destroy() 187 188 if use_existing == wx.ID_CANCEL: 189 return 190 191 # user wants to create new issue with alternate name 192 if use_existing == wx.ID_NO: 193 # loop until name modified but non-empty or cancelled 194 issue_name = episode['description'] 195 while issue_name == episode['description']: 196 dlg = wx.TextEntryDialog ( 197 parent = parent, 198 message = _('Enter a short descriptive name for the new health issue:'), 199 caption = _('Creating a new health issue ...'), 200 defaultValue = issue_name, 201 style = wx.OK | wx.CANCEL | wx.CENTRE 202 ) 203 decision = dlg.ShowModal() 204 if decision != wx.ID_OK: 205 dlg.Destroy() 206 return 207 issue_name = dlg.GetValue().strip() 208 dlg.Destroy() 209 if issue_name == '': 210 issue_name = episode['description'] 211 212 issue = emr.add_health_issue(issue_name = issue_name) 213 created_new_issue = True 214 215 # eventually move the episode to the issue 216 if not move_episode_to_issue(episode = episode, target_issue = issue, save_to_backend = True): 217 # user cancelled the move so delete just-created issue 218 if created_new_issue: 219 # shouldn't fail as it is completely new 220 gmEMRStructItems.delete_health_issue(health_issue = issue) 221 return 222 223 return
224 225 #----------------------------------------------------------------
226 -def move_episode_to_issue(episode=None, target_issue=None, save_to_backend=False):
227 """Prepare changing health issue for an episode. 228 229 Checks for two-open-episodes conflict. When this 230 function succeeds, the pk_health_issue has been set 231 on the episode instance and the episode should - for 232 all practical purposes - be ready for save_payload(). 233 """ 234 # episode is closed: should always work 235 if not episode['episode_open']: 236 episode['pk_health_issue'] = target_issue['pk_health_issue'] 237 if save_to_backend: 238 episode.save_payload() 239 return True 240 241 # un-associate: should always work, too 242 if target_issue is None: 243 episode['pk_health_issue'] = None 244 if save_to_backend: 245 episode.save_payload() 246 return True 247 248 # try closing possibly expired episode on target issue if any 249 db_cfg = gmCfg.cCfgSQL() 250 epi_ttl = int(db_cfg.get2 ( 251 option = 'episode.ttl', 252 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, 253 bias = 'user', 254 default = 60 # 2 months 255 )) 256 if target_issue.close_expired_episode(ttl=epi_ttl) is True: 257 gmDispatcher.send(signal='statustext', msg=_('Closed episodes older than %s days on health issue [%s]') % (epi_ttl, target_issue['description'])) 258 existing_epi = target_issue.get_open_episode() 259 260 # no more open episode on target issue: should work now 261 if existing_epi is None: 262 episode['pk_health_issue'] = target_issue['pk_health_issue'] 263 if save_to_backend: 264 episode.save_payload() 265 return True 266 267 # don't conflict on SELF ;-) 268 if existing_epi['pk_episode'] == episode['pk_episode']: 269 episode['pk_health_issue'] = target_issue['pk_health_issue'] 270 if save_to_backend: 271 episode.save_payload() 272 return True 273 274 # we got two open episodes at once, ask user 275 move_range = (episode.best_guess_clinical_start_date, episode.best_guess_clinical_end_date) 276 if move_range[1] is None: 277 move_range_end = '?' 278 else: 279 move_range_end = move_range[1].strftime('%m/%y') 280 exist_range = (existing_epi.best_guess_clinical_start_date, existing_epi.best_guess_clinical_end_date) 281 if exist_range[1] is None: 282 exist_range_end = '?' 283 else: 284 exist_range_end = exist_range[1].strftime('%m/%y') 285 question = _( 286 'You want to associate the running episode:\n\n' 287 ' "%(new_epi_name)s" (%(new_epi_start)s - %(new_epi_end)s)\n\n' 288 'with the health issue:\n\n' 289 ' "%(issue_name)s"\n\n' 290 'There already is another episode running\n' 291 'for this health issue:\n\n' 292 ' "%(old_epi_name)s" (%(old_epi_start)s - %(old_epi_end)s)\n\n' 293 'However, there can only be one running\n' 294 'episode per health issue.\n\n' 295 'Which episode do you want to close ?' 296 ) % { 297 'new_epi_name': episode['description'], 298 'new_epi_start': move_range[0].strftime('%m/%y'), 299 'new_epi_end': move_range_end, 300 'issue_name': target_issue['description'], 301 'old_epi_name': existing_epi['description'], 302 'old_epi_start': exist_range[0].strftime('%m/%y'), 303 'old_epi_end': exist_range_end 304 } 305 dlg = gmGuiHelpers.c3ButtonQuestionDlg ( 306 parent = None, 307 id = -1, 308 caption = _('Resolving two-running-episodes conflict'), 309 question = question, 310 button_defs = [ 311 {'label': _('old episode'), 'default': True, 'tooltip': _('close existing episode "%s"') % existing_epi['description']}, 312 {'label': _('new episode'), 'default': False, 'tooltip': _('close moving (new) episode "%s"') % episode['description']} 313 ] 314 ) 315 decision = dlg.ShowModal() 316 317 if decision == wx.ID_CANCEL: 318 # button 3: move cancelled by user 319 return False 320 321 elif decision == wx.ID_YES: 322 # button 1: close old episode 323 existing_epi['episode_open'] = False 324 existing_epi.save_payload() 325 326 elif decision == wx.ID_NO: 327 # button 2: close new episode 328 episode['episode_open'] = False 329 330 else: 331 raise ValueError('invalid result from c3ButtonQuestionDlg: [%s]' % decision) 332 333 episode['pk_health_issue'] = target_issue['pk_health_issue'] 334 if save_to_backend: 335 episode.save_payload() 336 return True
337 338 #----------------------------------------------------------------
339 -class cEpisodeListSelectorDlg(gmListWidgets.cGenericListSelectorDlg):
340 341 # FIXME: support pre-selection 342
343 - def __init__(self, *args, **kwargs):
344 345 episodes = kwargs['episodes'] 346 del kwargs['episodes'] 347 348 gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs) 349 350 self.SetTitle(_('Select the episodes you are interested in ...')) 351 self._LCTRL_items.set_columns([_('Episode'), _('Status'), _('Health Issue')]) 352 self._LCTRL_items.set_string_items ( 353 items = [ 354 [ epi['description'], 355 gmTools.bool2str(epi['episode_open'], _('ongoing'), ''), 356 gmTools.coalesce(epi['health_issue'], '') 357 ] 358 for epi in episodes ] 359 ) 360 self._LCTRL_items.set_column_widths() 361 self._LCTRL_items.set_data(data = episodes)
362 363 #----------------------------------------------------------------
364 -class cEpisodeDescriptionPhraseWheel(gmPhraseWheel.cPhraseWheel):
365 """Let user select an episode *description*. 366 367 The user can select an episode description from the previously 368 used descriptions across all episodes across all patients. 369 370 Selection is done with a phrasewheel so the user can 371 type the episode name and matches will be shown. Typing 372 "*" will show the entire list of episodes. 373 374 If the user types a description not existing yet a 375 new episode description will be returned. 376 """
377 - def __init__(self, *args, **kwargs):
378 379 mp = gmMatchProvider.cMatchProvider_SQL2 ( 380 queries = [ 381 """ 382 SELECT DISTINCT ON (description) 383 description 384 AS data, 385 description 386 AS field_label, 387 description || ' (' 388 || CASE 389 WHEN is_open IS TRUE THEN _('ongoing') 390 ELSE _('closed') 391 END 392 || ')' 393 AS list_label 394 FROM 395 clin.episode 396 WHERE 397 description %(fragment_condition)s 398 ORDER BY description 399 LIMIT 30 400 """ 401 ] 402 ) 403 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 404 self.matcher = mp
405 406 #----------------------------------------------------------------
407 -class cEpisodeSelectionPhraseWheel(gmPhraseWheel.cPhraseWheel):
408 """Let user select an episode. 409 410 The user can select an episode from the existing episodes of a 411 patient. Selection is done with a phrasewheel so the user 412 can type the episode name and matches will be shown. Typing 413 "*" will show the entire list of episodes. Closed episodes 414 will be marked as such. If the user types an episode name not 415 in the list of existing episodes a new episode can be created 416 from it if the programmer activated that feature. 417 418 If keyword <patient_id> is set to None or left out the control 419 will listen to patient change signals and therefore act on 420 gmPerson.gmCurrentPatient() changes. 421 """
422 - def __init__(self, *args, **kwargs):
423 424 ctxt = {'ctxt_pat': {'where_part': 'and pk_patient = %(pat)s', 'placeholder': 'pat'}} 425 426 mp = gmMatchProvider.cMatchProvider_SQL2 ( 427 queries = [ 428 """( 429 430 SELECT 431 pk_episode 432 as data, 433 description 434 as field_label, 435 coalesce ( 436 description || ' - ' || health_issue, 437 description 438 ) as list_label, 439 1 as rank 440 from 441 clin.v_pat_episodes 442 where 443 episode_open is true and 444 description %(fragment_condition)s 445 %(ctxt_pat)s 446 447 ) union all ( 448 449 SELECT 450 pk_episode 451 as data, 452 description 453 as field_label, 454 coalesce ( 455 description || _(' (closed)') || ' - ' || health_issue, 456 description || _(' (closed)') 457 ) as list_label, 458 2 as rank 459 from 460 clin.v_pat_episodes 461 where 462 description %(fragment_condition)s and 463 episode_open is false 464 %(ctxt_pat)s 465 466 ) 467 468 order by rank, list_label 469 limit 30""" 470 ], 471 context = ctxt 472 ) 473 474 try: 475 kwargs['patient_id'] 476 except KeyError: 477 kwargs['patient_id'] = None 478 479 if kwargs['patient_id'] is None: 480 self.use_current_patient = True 481 self.__register_patient_change_signals() 482 pat = gmPerson.gmCurrentPatient() 483 if pat.connected: 484 mp.set_context('pat', pat.ID) 485 else: 486 self.use_current_patient = False 487 self.__patient_id = int(kwargs['patient_id']) 488 mp.set_context('pat', self.__patient_id) 489 490 del kwargs['patient_id'] 491 492 gmPhraseWheel.cPhraseWheel.__init__ ( 493 self, 494 *args, 495 **kwargs 496 ) 497 self.matcher = mp
498 #-------------------------------------------------------- 499 # external API 500 #--------------------------------------------------------
501 - def set_patient(self, patient_id=None):
502 if self.use_current_patient: 503 return False 504 self.__patient_id = int(patient_id) 505 self.set_context('pat', self.__patient_id) 506 return True
507 #--------------------------------------------------------
508 - def GetData(self, can_create=False, as_instance=False, is_open=False):
509 self.__is_open_for_create_data = is_open # used (only) in _create_data() 510 return gmPhraseWheel.cPhraseWheel.GetData(self, can_create = can_create, as_instance = as_instance)
511 #--------------------------------------------------------
512 - def _create_data(self):
513 514 epi_name = self.GetValue().strip() 515 if epi_name == '': 516 gmDispatcher.send(signal = 'statustext', msg = _('Cannot create episode without name.'), beep = True) 517 _log.debug('cannot create episode without name') 518 return 519 520 if self.use_current_patient: 521 pat = gmPerson.gmCurrentPatient() 522 else: 523 pat = gmPerson.cPatient(aPK_obj = self.__patient_id) 524 525 emr = pat.emr 526 epi = emr.add_episode(episode_name = epi_name, is_open = self.__is_open_for_create_data) 527 if epi is None: 528 self.data = {} 529 else: 530 self.SetText ( 531 value = epi_name, 532 data = epi['pk_episode'] 533 )
534 #--------------------------------------------------------
535 - def _data2instance(self):
536 return gmEMRStructItems.cEpisode(aPK_obj = self.GetData())
537 #-------------------------------------------------------- 538 # internal API 539 #--------------------------------------------------------
541 gmDispatcher.connect(self._pre_patient_unselection, 'pre_patient_unselection') 542 gmDispatcher.connect(self._post_patient_selection, 'post_patient_selection')
543 #--------------------------------------------------------
544 - def _pre_patient_unselection(self):
545 self.__patient_id = None 546 self.unset_context('pat') 547 self.SetData() 548 return True
549 #--------------------------------------------------------
550 - def _post_patient_selection(self):
551 if self.use_current_patient: 552 patient = gmPerson.gmCurrentPatient() 553 self.set_context('pat', patient.ID) 554 return True
555 556 #---------------------------------------------------------------- 557 from Gnumed.wxGladeWidgets import wxgEpisodeEditAreaPnl 558
559 -class cEpisodeEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgEpisodeEditAreaPnl.wxgEpisodeEditAreaPnl):
560
561 - def __init__(self, *args, **kwargs):
562 563 try: 564 episode = kwargs['episode'] 565 del kwargs['episode'] 566 except KeyError: 567 episode = None 568 569 wxgEpisodeEditAreaPnl.wxgEpisodeEditAreaPnl.__init__(self, *args, **kwargs) 570 gmEditArea.cGenericEditAreaMixin.__init__(self) 571 572 self.data = episode
573 574 #---------------------------------------------------------------- 575 # generic Edit Area mixin API 576 #----------------------------------------------------------------
577 - def _valid_for_save(self):
578 579 errors = False 580 581 if len(self._PRW_description.GetValue().strip()) == 0: 582 errors = True 583 self._PRW_description.display_as_valid(False) 584 self._PRW_description.SetFocus() 585 else: 586 self._PRW_description.display_as_valid(True) 587 self._PRW_description.Refresh() 588 589 return not errors
590 591 #----------------------------------------------------------------
592 - def _save_as_new(self):
593 594 pat = gmPerson.gmCurrentPatient() 595 emr = pat.emr 596 597 epi = emr.add_episode(episode_name = self._PRW_description.GetValue().strip()) 598 epi['summary'] = self._TCTRL_status.GetValue().strip() 599 epi['episode_open'] = not self._CHBOX_closed.IsChecked() 600 epi['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 601 602 issue_name = self._PRW_issue.GetValue().strip() 603 if len(issue_name) != 0: 604 epi['pk_health_issue'] = self._PRW_issue.GetData(can_create = True) 605 issue = gmEMRStructItems.cHealthIssue(aPK_obj = epi['pk_health_issue']) 606 607 if not move_episode_to_issue(episode = epi, target_issue = issue, save_to_backend = False): 608 gmDispatcher.send ( 609 signal = 'statustext', 610 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % ( 611 epi['description'], 612 issue['description'] 613 ) 614 ) 615 gmEMRStructItems.delete_episode(episode = epi) 616 return False 617 618 epi.save() 619 620 epi.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 621 622 self.data = epi 623 return True
624 625 #----------------------------------------------------------------
626 - def _save_as_update(self):
627 628 self.data['description'] = self._PRW_description.GetValue().strip() 629 self.data['summary'] = self._TCTRL_status.GetValue().strip() 630 self.data['episode_open'] = not self._CHBOX_closed.IsChecked() 631 self.data['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 632 633 issue_name = self._PRW_issue.GetValue().strip() 634 if len(issue_name) == 0: 635 self.data['pk_health_issue'] = None 636 else: 637 self.data['pk_health_issue'] = self._PRW_issue.GetData(can_create = True) 638 issue = gmEMRStructItems.cHealthIssue(aPK_obj = self.data['pk_health_issue']) 639 640 if not move_episode_to_issue(episode = self.data, target_issue = issue, save_to_backend = False): 641 gmDispatcher.send ( 642 signal = 'statustext', 643 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % ( 644 self.data['description'], 645 issue['description'] 646 ) 647 ) 648 return False 649 650 self.data.save() 651 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 652 653 return True
654 655 #----------------------------------------------------------------
656 - def _refresh_as_new(self):
657 if self.data is None: 658 ident = gmPerson.gmCurrentPatient() 659 else: 660 ident = gmPerson.cPerson(aPK_obj = self.data['pk_patient']) 661 self._TCTRL_patient.SetValue(ident.get_description_gender()) 662 self._PRW_issue.SetText() 663 self._PRW_description.SetText() 664 self._TCTRL_status.SetValue('') 665 self._PRW_certainty.SetText() 666 self._CHBOX_closed.SetValue(False) 667 self._PRW_codes.SetText() 668 669 self._PRW_issue.SetFocus()
670 671 #----------------------------------------------------------------
672 - def _refresh_from_existing(self):
673 ident = gmPerson.cPerson(aPK_obj = self.data['pk_patient']) 674 self._TCTRL_patient.SetValue(ident.get_description_gender()) 675 676 if self.data['pk_health_issue'] is not None: 677 self._PRW_issue.SetText ( 678 self.data['health_issue'], 679 data = self.data['pk_health_issue'] 680 ) 681 682 self._PRW_description.SetText ( 683 self.data['description'], 684 data = self.data['description'] 685 ) 686 687 self._TCTRL_status.SetValue(gmTools.coalesce(self.data['summary'], '')) 688 689 if self.data['diagnostic_certainty_classification'] is not None: 690 self._PRW_certainty.SetData(data = self.data['diagnostic_certainty_classification']) 691 692 self._CHBOX_closed.SetValue(not self.data['episode_open']) 693 694 val, data = self._PRW_codes.generic_linked_codes2item_dict(self.data.generic_codes) 695 self._PRW_codes.SetText(val, data) 696 697 if self.data['pk_health_issue'] is None: 698 self._PRW_issue.SetFocus() 699 else: 700 self._PRW_description.SetFocus()
701 702 #----------------------------------------------------------------
704 self._refresh_as_new()
705 706 #================================================================ 707 # health issue related widgets/functions 708 #----------------------------------------------------------------
709 -def edit_health_issue(parent=None, issue=None):
710 ea = cHealthIssueEditAreaPnl(parent, -1) 711 ea.data = issue 712 ea.mode = gmTools.coalesce(issue, 'new', 'edit') 713 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = (issue is not None)) 714 dlg.SetTitle(gmTools.coalesce(issue, _('Adding a new health issue'), _('Editing a health issue'))) 715 if dlg.ShowModal() == wx.ID_OK: 716 dlg.Destroy() 717 return True 718 dlg.Destroy() 719 return False
720 #----------------------------------------------------------------
721 -def select_health_issues(parent=None, emr=None):
722 723 if parent is None: 724 parent = wx.GetApp().GetTopWindow() 725 #----------------------------------------- 726 def edit(issue=None): 727 return edit_health_issue(parent = parent, issue = issue)
728 #----------------------------------------- 729 def delete(issue=None): 730 if gmEMRStructItems.delete_health_issue(health_issue = issue): 731 return True 732 gmDispatcher.send ( 733 signal = 'statustext', 734 msg = _('Cannot delete health issue.'), 735 beep = True 736 ) 737 return False 738 #----------------------------------------- 739 def get_tooltip(data): 740 if data is None: 741 return None 742 patient = gmPerson.cPatient(data['pk_patient']) 743 return data.format ( 744 patient = patient, 745 with_summary = True, 746 with_codes = True, 747 with_episodes = True, 748 with_encounters = True, 749 with_medications = False, 750 with_hospital_stays = False, 751 with_procedures = False, 752 with_family_history = False, 753 with_documents = False, 754 with_tests = False, 755 with_vaccinations = False 756 ) 757 #----------------------------------------- 758 def refresh(lctrl): 759 issues = emr.get_health_issues() 760 items = [ 761 [ 762 gmTools.bool2subst(i['is_confidential'], _('CONFIDENTIAL'), '', ''), 763 i['description'], 764 gmTools.bool2subst(i['clinically_relevant'], _('relevant'), '', ''), 765 gmTools.bool2subst(i['is_active'], _('active'), '', ''), 766 gmTools.bool2subst(i['is_cause_of_death'], _('fatal'), '', '') 767 ] for i in issues 768 ] 769 lctrl.set_string_items(items = items) 770 lctrl.set_data(data = issues) 771 #----------------------------------------- 772 return gmListWidgets.get_choices_from_list ( 773 parent = parent, 774 msg = _('\nSelect the health issues !\n'), 775 caption = _('Showing health issues ...'), 776 columns = ['', _('Health issue'), '', '', ''], 777 single_selection = False, 778 edit_callback = edit, 779 new_callback = edit, 780 delete_callback = delete, 781 refresh_callback = refresh 782 ) 783 #----------------------------------------------------------------
784 -class cIssueListSelectorDlg(gmListWidgets.cGenericListSelectorDlg):
785 786 # FIXME: support pre-selection 787
788 - def __init__(self, *args, **kwargs):
789 790 issues = kwargs['issues'] 791 del kwargs['issues'] 792 793 gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs) 794 795 self.SetTitle(_('Select the health issues you are interested in ...')) 796 self._LCTRL_items.set_columns(['', _('Health Issue'), '', '', '']) 797 798 for issue in issues: 799 if issue['is_confidential']: 800 row_num = self._LCTRL_items.InsertItem(sys.maxsize, label = _('confidential')) 801 self._LCTRL_items.SetItemTextColour(row_num, col=wx.Colour('RED')) 802 else: 803 row_num = self._LCTRL_items.InsertItem(sys.maxsize, label = '') 804 805 self._LCTRL_items.SetItem(index = row_num, column = 1, label = issue['description']) 806 if issue['clinically_relevant']: 807 self._LCTRL_items.SetItem(index = row_num, column = 2, label = _('relevant')) 808 if issue['is_active']: 809 self._LCTRL_items.SetItem(index = row_num, column = 3, label = _('active')) 810 if issue['is_cause_of_death']: 811 self._LCTRL_items.SetItem(index = row_num, column = 4, label = _('fatal')) 812 813 self._LCTRL_items.set_column_widths() 814 self._LCTRL_items.set_data(data = issues)
815 816 #----------------------------------------------------------------
817 -class cIssueSelectionPhraseWheel(gmPhraseWheel.cPhraseWheel):
818 """Let the user select a health issue. 819 820 The user can select a health issue from the existing issues 821 of a patient. Selection is done with a phrasewheel so the user 822 can type the issue name and matches will be shown. Typing 823 "*" will show the entire list of issues. Inactive issues 824 will be marked as such. If the user types an issue name not 825 in the list of existing issues a new issue can be created 826 from it if the programmer activated that feature. 827 828 If keyword <patient_id> is set to None or left out the control 829 will listen to patient change signals and therefore act on 830 gmPerson.gmCurrentPatient() changes. 831 """
832 - def __init__(self, *args, **kwargs):
833 834 ctxt = {'ctxt_pat': {'where_part': 'pk_patient=%(pat)s', 'placeholder': 'pat'}} 835 836 mp = gmMatchProvider.cMatchProvider_SQL2 ( 837 # FIXME: consider clin.health_issue.clinically_relevant 838 queries = [""" 839 SELECT 840 data, 841 field_label, 842 list_label 843 FROM (( 844 SELECT 845 pk_health_issue AS data, 846 description AS field_label, 847 description AS list_label 848 FROM clin.v_health_issues 849 WHERE 850 is_active IS true 851 AND 852 description %(fragment_condition)s 853 AND 854 %(ctxt_pat)s 855 856 ) UNION ( 857 858 SELECT 859 pk_health_issue AS data, 860 description AS field_label, 861 description || _(' (inactive)') AS list_label 862 FROM clin.v_health_issues 863 WHERE 864 is_active IS false 865 AND 866 description %(fragment_condition)s 867 AND 868 %(ctxt_pat)s 869 )) AS union_query 870 ORDER BY 871 list_label""" 872 ], 873 context = ctxt 874 ) 875 try: kwargs['patient_id'] 876 except KeyError: kwargs['patient_id'] = None 877 878 if kwargs['patient_id'] is None: 879 self.use_current_patient = True 880 self.__register_patient_change_signals() 881 pat = gmPerson.gmCurrentPatient() 882 if pat.connected: 883 mp.set_context('pat', pat.ID) 884 else: 885 self.use_current_patient = False 886 self.__patient_id = int(kwargs['patient_id']) 887 mp.set_context('pat', self.__patient_id) 888 889 del kwargs['patient_id'] 890 891 gmPhraseWheel.cPhraseWheel.__init__ ( 892 self, 893 *args, 894 **kwargs 895 ) 896 self.matcher = mp
897 #-------------------------------------------------------- 898 # external API 899 #--------------------------------------------------------
900 - def set_patient(self, patient_id=None):
901 if self.use_current_patient: 902 return False 903 self.__patient_id = int(patient_id) 904 self.set_context('pat', self.__patient_id) 905 return True
906 #--------------------------------------------------------
907 - def _create_data(self):
908 issue_name = self.GetValue().strip() 909 if issue_name == '': 910 gmDispatcher.send(signal = 'statustext', msg = _('Cannot create health issue without name.'), beep = True) 911 _log.debug('cannot create health issue without name') 912 return 913 914 if self.use_current_patient: 915 pat = gmPerson.gmCurrentPatient() 916 else: 917 pat = gmPerson.cPatient(aPK_obj = self.__patient_id) 918 919 emr = pat.emr 920 issue = emr.add_health_issue(issue_name = issue_name) 921 922 if issue is None: 923 self.data = {} 924 else: 925 self.SetText ( 926 value = issue_name, 927 data = issue['pk_health_issue'] 928 )
929 #--------------------------------------------------------
930 - def _data2instance(self):
931 return gmEMRStructItems.cHealthIssue(aPK_obj = self.GetData())
932 #--------------------------------------------------------
933 - def _get_data_tooltip(self):
934 if self.GetData() is None: 935 return None 936 issue = self._data2instance() 937 if issue is None: 938 return None 939 return issue.format ( 940 patient = None, 941 with_summary = True, 942 with_codes = False, 943 with_episodes = True, 944 with_encounters = True, 945 with_medications = False, 946 with_hospital_stays = False, 947 with_procedures = False, 948 with_family_history = False, 949 with_documents = False, 950 with_tests = False, 951 with_vaccinations = False, 952 with_external_care = True 953 )
954 #-------------------------------------------------------- 955 # internal API 956 #--------------------------------------------------------
958 gmDispatcher.connect(self._pre_patient_unselection, 'pre_patient_unselection') 959 gmDispatcher.connect(self._post_patient_selection, 'post_patient_selection')
960 #--------------------------------------------------------
961 - def _pre_patient_unselection(self):
962 return True
963 #--------------------------------------------------------
964 - def _post_patient_selection(self):
965 if self.use_current_patient: 966 patient = gmPerson.gmCurrentPatient() 967 self.set_context('pat', patient.ID) 968 return True
969 #------------------------------------------------------------ 970 from Gnumed.wxGladeWidgets import wxgIssueSelectionDlg 971
972 -class cIssueSelectionDlg(wxgIssueSelectionDlg.wxgIssueSelectionDlg):
973
974 - def __init__(self, *args, **kwargs):
975 try: 976 msg = kwargs['message'] 977 except KeyError: 978 msg = None 979 del kwargs['message'] 980 wxgIssueSelectionDlg.wxgIssueSelectionDlg.__init__(self, *args, **kwargs) 981 if msg is not None: 982 self._lbl_message.SetLabel(label=msg)
983 #--------------------------------------------------------
984 - def _on_OK_button_pressed(self, event):
985 event.Skip() 986 pk_issue = self._PhWheel_issue.GetData(can_create=True) 987 if pk_issue is None: 988 gmGuiHelpers.gm_show_error ( 989 _('Cannot create new health issue:\n [%(issue)s]') % {'issue': self._PhWheel_issue.GetValue().strip()}, 990 _('Selecting health issue') 991 ) 992 return False 993 return True
994 #------------------------------------------------------------ 995 from Gnumed.wxGladeWidgets import wxgHealthIssueEditAreaPnl 996
997 -class cHealthIssueEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl):
998 """Panel encapsulating health issue edit area functionality.""" 999
1000 - def __init__(self, *args, **kwargs):
1001 1002 try: 1003 data = kwargs['issue'] 1004 del kwargs['issue'] 1005 except KeyError: 1006 data = None 1007 1008 wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl.__init__(self, *args, **kwargs) 1009 gmEditArea.cGenericEditAreaMixin.__init__(self) 1010 1011 self.mode = 'new' 1012 self.data = data 1013 if data is not None: 1014 self.mode = 'edit' 1015 1016 self.__init_ui()
1017 #----------------------------------------------------------------
1018 - def __init_ui(self):
1019 1020 # FIXME: include more sources: coding systems/other database columns 1021 mp = gmMatchProvider.cMatchProvider_SQL2 ( 1022 queries = ["SELECT DISTINCT ON (description) description, description FROM clin.health_issue WHERE description %(fragment_condition)s LIMIT 50"] 1023 ) 1024 mp.setThresholds(1, 3, 5) 1025 self._PRW_condition.matcher = mp 1026 1027 mp = gmMatchProvider.cMatchProvider_SQL2 ( 1028 queries = [""" 1029 SELECT DISTINCT ON (grouping) grouping, grouping from ( 1030 1031 SELECT rank, grouping from (( 1032 1033 SELECT 1034 grouping, 1035 1 as rank 1036 from 1037 clin.health_issue 1038 where 1039 grouping %%(fragment_condition)s 1040 and 1041 (SELECT True from clin.encounter where fk_patient = %s and pk = clin.health_issue.fk_encounter) 1042 1043 ) union ( 1044 1045 SELECT 1046 grouping, 1047 2 as rank 1048 from 1049 clin.health_issue 1050 where 1051 grouping %%(fragment_condition)s 1052 1053 )) as union_result 1054 1055 order by rank 1056 1057 ) as order_result 1058 1059 limit 50""" % gmPerson.gmCurrentPatient().ID 1060 ] 1061 ) 1062 mp.setThresholds(1, 3, 5) 1063 self._PRW_grouping.matcher = mp 1064 1065 self._PRW_age_noted.add_callback_on_lose_focus(self._on_leave_age_noted) 1066 self._PRW_year_noted.add_callback_on_lose_focus(self._on_leave_year_noted) 1067 1068 # self._PRW_age_noted.add_callback_on_modified(self._on_modified_age_noted) 1069 # self._PRW_year_noted.add_callback_on_modified(self._on_modified_year_noted) 1070 1071 self._PRW_year_noted.Enable(True) 1072 1073 self._PRW_codes.add_callback_on_lose_focus(self._on_leave_codes)
1074 1075 #---------------------------------------------------------------- 1076 # generic Edit Area mixin API 1077 #----------------------------------------------------------------
1078 - def _valid_for_save(self):
1079 1080 if self._PRW_condition.GetValue().strip() == '': 1081 self._PRW_condition.display_as_valid(False) 1082 self._PRW_condition.SetFocus() 1083 return False 1084 self._PRW_condition.display_as_valid(True) 1085 self._PRW_condition.Refresh() 1086 1087 # FIXME: sanity check age/year diagnosed 1088 age_noted = self._PRW_age_noted.GetValue().strip() 1089 if age_noted != '': 1090 if gmDateTime.str2interval(str_interval = age_noted) is None: 1091 self._PRW_age_noted.display_as_valid(False) 1092 self._PRW_age_noted.SetFocus() 1093 return False 1094 self._PRW_age_noted.display_as_valid(True) 1095 return True
1096 #----------------------------------------------------------------
1097 - def _save_as_new(self):
1098 pat = gmPerson.gmCurrentPatient() 1099 emr = pat.emr 1100 1101 issue = emr.add_health_issue(issue_name = self._PRW_condition.GetValue().strip()) 1102 1103 side = '' 1104 if self._ChBOX_left.GetValue(): 1105 side += 's' 1106 if self._ChBOX_right.GetValue(): 1107 side += 'd' 1108 issue['laterality'] = side 1109 1110 issue['summary'] = self._TCTRL_status.GetValue().strip() 1111 issue['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 1112 issue['grouping'] = self._PRW_grouping.GetValue().strip() 1113 issue['is_active'] = self._ChBOX_active.GetValue() 1114 issue['clinically_relevant'] = self._ChBOX_relevant.GetValue() 1115 issue['is_confidential'] = self._ChBOX_confidential.GetValue() 1116 issue['is_cause_of_death'] = self._ChBOX_caused_death.GetValue() 1117 1118 age_noted = self._PRW_age_noted.GetData() 1119 if age_noted is not None: 1120 issue['age_noted'] = age_noted 1121 1122 issue.save() 1123 1124 issue.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 1125 1126 self.data = issue 1127 return True
1128 #----------------------------------------------------------------
1129 - def _save_as_update(self):
1130 1131 self.data['description'] = self._PRW_condition.GetValue().strip() 1132 1133 side = '' 1134 if self._ChBOX_left.GetValue(): 1135 side += 's' 1136 if self._ChBOX_right.GetValue(): 1137 side += 'd' 1138 self.data['laterality'] = side 1139 1140 self.data['summary'] = self._TCTRL_status.GetValue().strip() 1141 self.data['diagnostic_certainty_classification'] = self._PRW_certainty.GetData() 1142 self.data['grouping'] = self._PRW_grouping.GetValue().strip() 1143 self.data['is_active'] = bool(self._ChBOX_active.GetValue()) 1144 self.data['clinically_relevant'] = bool(self._ChBOX_relevant.GetValue()) 1145 self.data['is_confidential'] = bool(self._ChBOX_confidential.GetValue()) 1146 self.data['is_cause_of_death'] = bool(self._ChBOX_caused_death.GetValue()) 1147 1148 age_noted = self._PRW_age_noted.GetData() 1149 if age_noted is not None: 1150 self.data['age_noted'] = age_noted 1151 1152 self.data.save() 1153 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ] 1154 1155 return True
1156 #----------------------------------------------------------------
1157 - def _refresh_as_new(self):
1158 self._PRW_condition.SetText() 1159 self._ChBOX_left.SetValue(0) 1160 self._ChBOX_right.SetValue(0) 1161 self._PRW_codes.SetText() 1162 self._on_leave_codes() 1163 self._PRW_certainty.SetText() 1164 self._PRW_grouping.SetText() 1165 self._TCTRL_status.SetValue('') 1166 self._PRW_age_noted.SetText() 1167 self._PRW_year_noted.SetText() 1168 self._ChBOX_active.SetValue(1) 1169 self._ChBOX_relevant.SetValue(1) 1170 self._ChBOX_confidential.SetValue(0) 1171 self._ChBOX_caused_death.SetValue(0) 1172 1173 self._PRW_condition.SetFocus() 1174 return True
1175 #----------------------------------------------------------------
1176 - def _refresh_from_existing(self):
1177 self._PRW_condition.SetText(self.data['description']) 1178 1179 lat = gmTools.coalesce(self.data['laterality'], '') 1180 if lat.find('s') == -1: 1181 self._ChBOX_left.SetValue(0) 1182 else: 1183 self._ChBOX_left.SetValue(1) 1184 if lat.find('d') == -1: 1185 self._ChBOX_right.SetValue(0) 1186 else: 1187 self._ChBOX_right.SetValue(1) 1188 1189 val, data = self._PRW_codes.generic_linked_codes2item_dict(self.data.generic_codes) 1190 self._PRW_codes.SetText(val, data) 1191 self._on_leave_codes() 1192 1193 if self.data['diagnostic_certainty_classification'] is not None: 1194 self._PRW_certainty.SetData(data = self.data['diagnostic_certainty_classification']) 1195 self._PRW_grouping.SetText(gmTools.coalesce(self.data['grouping'], '')) 1196 self._TCTRL_status.SetValue(gmTools.coalesce(self.data['summary'], '')) 1197 1198 if self.data['age_noted'] is None: 1199 self._PRW_age_noted.SetText() 1200 else: 1201 self._PRW_age_noted.SetText ( 1202 value = '%sd' % self.data['age_noted'].days, 1203 data = self.data['age_noted'] 1204 ) 1205 1206 self._ChBOX_active.SetValue(self.data['is_active']) 1207 self._ChBOX_relevant.SetValue(self.data['clinically_relevant']) 1208 self._ChBOX_confidential.SetValue(self.data['is_confidential']) 1209 self._ChBOX_caused_death.SetValue(self.data['is_cause_of_death']) 1210 1211 self._TCTRL_status.SetFocus() 1212 1213 return True
1214 #----------------------------------------------------------------
1216 return self._refresh_as_new()
1217 #-------------------------------------------------------- 1218 # internal helpers 1219 #--------------------------------------------------------
1220 - def _on_leave_codes(self, *args, **kwargs):
1221 if not self._PRW_codes.IsModified(): 1222 return True 1223 1224 self._TCTRL_code_details.SetValue('- ' + '\n- '.join([ c['list_label'] for c in self._PRW_codes.GetData() ]))
1225 #--------------------------------------------------------
1226 - def _on_leave_age_noted(self, *args, **kwargs):
1227 1228 if not self._PRW_age_noted.IsModified(): 1229 return True 1230 1231 age_str = self._PRW_age_noted.GetValue().strip() 1232 1233 if age_str == '': 1234 return True 1235 1236 issue_age = gmDateTime.str2interval(str_interval = age_str) 1237 1238 if issue_age is None: 1239 self.status_message = _('Cannot parse [%s] into valid interval.') % age_str 1240 self._PRW_age_noted.display_as_valid(False) 1241 return True 1242 1243 pat = gmPerson.gmCurrentPatient() 1244 if pat['dob'] is not None: 1245 max_issue_age = pydt.datetime.now(tz=pat['dob'].tzinfo) - pat['dob'] 1246 if issue_age >= max_issue_age: 1247 self.status_message = _('Health issue cannot have been noted at age %s. Patient is only %s old.') % (issue_age, pat.get_medical_age()) 1248 self._PRW_age_noted.display_as_valid(False) 1249 return True 1250 1251 self._PRW_age_noted.display_as_valid(True) 1252 self._PRW_age_noted.SetText(value = age_str, data = issue_age) 1253 1254 if pat['dob'] is not None: 1255 fts = gmDateTime.cFuzzyTimestamp ( 1256 timestamp = pat['dob'] + issue_age, 1257 accuracy = gmDateTime.acc_months 1258 ) 1259 self._PRW_year_noted.SetText(value = str(fts), data = fts) 1260 1261 return True
1262 #--------------------------------------------------------
1263 - def _on_leave_year_noted(self, *args, **kwargs):
1264 1265 if not self._PRW_year_noted.IsModified(): 1266 return True 1267 1268 year_noted = self._PRW_year_noted.GetData() 1269 1270 if year_noted is None: 1271 if self._PRW_year_noted.GetValue().strip() == '': 1272 self._PRW_year_noted.display_as_valid(True) 1273 return True 1274 self._PRW_year_noted.display_as_valid(False) 1275 return True 1276 1277 year_noted = year_noted.get_pydt() 1278 1279 if year_noted >= pydt.datetime.now(tz = year_noted.tzinfo): 1280 self.status_message = _('Condition diagnosed in the future.') 1281 self._PRW_year_noted.display_as_valid(False) 1282 return True 1283 1284 self._PRW_year_noted.display_as_valid(True) 1285 1286 pat = gmPerson.gmCurrentPatient() 1287 if pat['dob'] is not None: 1288 issue_age = year_noted - pat['dob'] 1289 age_str = gmDateTime.format_interval_medically(interval = issue_age) 1290 self._PRW_age_noted.SetText(age_str, issue_age, True) 1291 1292 return True
1293 #--------------------------------------------------------
1294 - def _on_modified_age_noted(self, *args, **kwargs):
1295 wx.CallAfter(self._PRW_year_noted.SetText, '', None, True) 1296 return True
1297 #--------------------------------------------------------
1298 - def _on_modified_year_noted(self, *args, **kwargs):
1299 wx.CallAfter(self._PRW_age_noted.SetText, '', None, True) 1300 return True
1301 #================================================================ 1302 # diagnostic certainty related widgets/functions 1303 #----------------------------------------------------------------
1304 -class cDiagnosticCertaintyClassificationPhraseWheel(gmPhraseWheel.cPhraseWheel):
1305
1306 - def __init__(self, *args, **kwargs):
1307 1308 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1309 1310 self.selection_only = False # can be NULL, too 1311 1312 mp = gmMatchProvider.cMatchProvider_FixedList ( 1313 aSeq = [ 1314 {'data': 'A', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str('A'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str('A'), 'weight': 1}, 1315 {'data': 'B', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str('B'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str('B'), 'weight': 1}, 1316 {'data': 'C', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str('C'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str('C'), 'weight': 1}, 1317 {'data': 'D', 'list_label': gmEMRStructItems.diagnostic_certainty_classification2str('D'), 'field_label': gmEMRStructItems.diagnostic_certainty_classification2str('D'), 'weight': 1} 1318 ] 1319 ) 1320 mp.setThresholds(1, 2, 4) 1321 self.matcher = mp 1322 1323 self.SetToolTip(_( 1324 "The diagnostic classification or grading of this assessment.\n" 1325 "\n" 1326 "This documents how certain one is about this being a true diagnosis." 1327 ))
1328 1329 #================================================================ 1330 # MAIN 1331 #---------------------------------------------------------------- 1332 if __name__ == '__main__': 1333 1334 if len(sys.argv) < 2: 1335 sys.exit() 1336 1337 if sys.argv[1] != 'test': 1338 sys.exit() 1339 1340 from Gnumed.business import gmPersonSearch 1341 from Gnumed.wxpython import gmPatSearchWidgets 1342 1343 #================================================================
1344 - class testapp (wx.App):
1345 """ 1346 Test application for testing EMR struct widgets 1347 """ 1348 #--------------------------------------------------------
1349 - def OnInit (self):
1350 """ 1351 Create test application UI 1352 """ 1353 frame = wx.Frame ( 1354 None, 1355 -4, 1356 'Testing EMR struct widgets', 1357 size=wx.Size(600, 400), 1358 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE 1359 ) 1360 filemenu = wx.Menu() 1361 filemenu.AppendSeparator() 1362 item = filemenu.Append(ID_EXIT, "E&xit"," Terminate test application") 1363 self.Bind(wx.EVT_MENU, self.OnCloseWindow, item) 1364 1365 # Creating the menubar. 1366 menuBar = wx.MenuBar() 1367 menuBar.Append(filemenu,"&File") 1368 1369 frame.SetMenuBar(menuBar) 1370 1371 txt = wx.StaticText( frame, -1, _("Select desired test option from the 'File' menu"), 1372 wx.DefaultPosition, wx.DefaultSize, 0 ) 1373 1374 # patient EMR 1375 self.__pat = gmPerson.gmCurrentPatient() 1376 1377 frame.Show(1) 1378 return 1
1379 #--------------------------------------------------------
1380 - def OnCloseWindow (self, e):
1381 """ 1382 Close test aplication 1383 """ 1384 self.ExitMainLoop ()
1385 1386 #----------------------------------------------------------------
1387 - def test_epsiode_edit_area_pnl():
1388 app = wx.PyWidgetTester(size = (200, 300)) 1389 emr = pat.emr 1390 epi = emr.get_episodes()[0] 1391 pnl = cEpisodeEditAreaPnl(app.frame, -1, episode=epi) 1392 app.frame.Show(True) 1393 app.MainLoop()
1394 #----------------------------------------------------------------
1395 - def test_episode_edit_area_dialog():
1396 app = wx.PyWidgetTester(size = (200, 300)) 1397 emr = pat.emr 1398 epi = emr.get_episodes()[0] 1399 edit_episode(parent=app.frame, episode=epi)
1400 1401 #----------------------------------------------------------------
1402 - def test_episode_selection_prw():
1403 app = wx.PyWidgetTester(size = (400, 40)) 1404 app.SetWidget(cEpisodeSelectionPhraseWheel, id=-1, size=(180,20), pos=(10,20)) 1405 # app.SetWidget(cEpisodeSelectionPhraseWheel, id=-1, size=(350,20), pos=(10,20), patient_id=pat.ID) 1406 app.MainLoop()
1407 1408 #----------------------------------------------------------------
1409 - def test_health_issue_edit_area_dlg():
1410 app = wx.PyWidgetTester(size = (200, 300)) 1411 edit_health_issue(parent=app.frame, issue=None)
1412 1413 #----------------------------------------------------------------
1414 - def test_health_issue_edit_area_pnl():
1415 app = wx.PyWidgetTester(size = (200, 300)) 1416 app.SetWidget(cHealthIssueEditAreaPnl, id=-1, size = (400,400)) 1417 app.MainLoop()
1418 1419 #================================================================ 1420 1421 # obtain patient 1422 pat = gmPersonSearch.ask_for_patient() 1423 if pat is None: 1424 print("No patient. Exiting gracefully...") 1425 sys.exit(0) 1426 gmPatSearchWidgets.set_active_patient(patient=pat) 1427 1428 # try: 1429 # lauch emr dialogs test application 1430 # app = testapp(0) 1431 # app.MainLoop() 1432 # except Exception: 1433 # _log.exception("unhandled exception caught !") 1434 # but re-raise them 1435 # raise 1436 1437 #test_epsiode_edit_area_pnl() 1438 #test_episode_edit_area_dialog() 1439 #test_health_issue_edit_area_dlg() 1440 test_episode_selection_prw() 1441