Gnumed.wxpython.gmNarrativeWidgets

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

# Source Code for Module Gnumed.wxpython.gmNarrativeWidgets

       1  """GNUmed narrative handling widgets."""
       2  #================================================================
       3  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
       4  __license__ = "GPL v2 or later (details at http://www.gnu.org)"
       5
       6  import sys
       7  import logging
       8  import os.path
       9  import time
      10
      11
      12  import wx
      13
      14
      15  if __name__ == '__main__':
      16          sys.path.insert(0, '../../')
      17
      18  from Gnumed.pycommon import gmI18N
      19
      20  if __name__ == '__main__':
      21          gmI18N.activate_locale()
      22          gmI18N.install_domain()
      23
      24  from Gnumed.pycommon import gmDispatcher
      25  from Gnumed.pycommon import gmTools
      26  from Gnumed.pycommon import gmDateTime
      27  from Gnumed.pycommon import gmCfg
      28
      29  from Gnumed.business import gmPerson
      30  from Gnumed.business import gmStaff
      31  from Gnumed.business import gmEMRStructItems
      32  from Gnumed.business import gmSoapDefs
      33  from Gnumed.business import gmPraxis
      34  from Gnumed.business import gmPersonSearch
      35
      36  from Gnumed.wxpython import gmListWidgets
      37  from Gnumed.wxpython import gmEMRStructWidgets
      38  from Gnumed.wxpython import gmEncounterWidgets
      39  from Gnumed.wxpython import gmRegetMixin
      40  from Gnumed.wxpython import gmGuiHelpers
      41  from Gnumed.wxpython import gmVisualProgressNoteWidgets
      42  from Gnumed.wxpython import gmProgressNotesEAWidgets
      43  from Gnumed.wxpython.gmPatSearchWidgets import set_active_patient
      44
      45  from Gnumed.exporters import gmPatientExporter
      46
      47
      48  _log = logging.getLogger('gm.ui')
      49  #============================================================
      50  # narrative related widgets
      51  #------------------------------------------------------------
      52 -class cNarrativeListSelectorDlg(gmListWidgets.cGenericListSelectorDlg):
      53
      54 -        def __init__(self, *args, **kwargs):
      55
      56                  narrative = kwargs['narrative']
      57                  del kwargs['narrative']
      58
      59                  gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs)
      60
      61                  self.SetTitle(_('Select the narrative you are interested in ...'))
      62                  # FIXME: add epi/issue
      63                  self._LCTRL_items.set_columns([_('when'), _('who'), _('type'), _('entry')]) #, _('Episode'), u'', _('Health Issue')])
      64                  # FIXME: date used should be date of encounter, not date_modified
      65                  self._LCTRL_items.set_string_items (
      66                          items = [ [narr['date'].strftime('%x %H:%M'), narr['modified_by'], gmSoapDefs.soap_cat2l10n[narr['soap_cat']], narr['narrative'].replace('\n', '/').replace('\r', '/')] for narr in narrative ]
      67                  )
      68                  self._LCTRL_items.set_column_widths()
      69                  self._LCTRL_items.set_data(data = narrative)
      70
      71  #------------------------------------------------------------
      72  from Gnumed.wxGladeWidgets import wxgMoveNarrativeDlg
      73
      74 -class cMoveNarrativeDlg(wxgMoveNarrativeDlg.wxgMoveNarrativeDlg):
      75
      76 -        def __init__(self, *args, **kwargs):
      77
      78                  self.encounter = kwargs['encounter']
      79                  self.source_episode = kwargs['episode']
      80                  del kwargs['encounter']
      81                  del kwargs['episode']
      82
      83                  wxgMoveNarrativeDlg.wxgMoveNarrativeDlg.__init__(self, *args, **kwargs)
      84
      85                  self.LBL_source_episode.SetLabel('%s%s' % (self.source_episode['description'], gmTools.coalesce(self.source_episode['health_issue'], '', ' (%s)')))
      86                  self.LBL_encounter.SetLabel('%s: %s %s - %s' % (
      87                          gmDateTime.pydt_strftime(self.encounter['started'], '%Y %b %d'),
      88                          self.encounter['l10n_type'],
      89                          gmDateTime.pydt_strftime(self.encounter['started'], '%H:%M'),
      90                          gmDateTime.pydt_strftime(self.encounter['last_affirmed'], '%H:%M')
      91                  ))
      92                  pat = gmPerson.gmCurrentPatient()
      93                  emr = pat.emr
      94                  narr = emr.get_clin_narrative(episodes=[self.source_episode['pk_episode']], encounters=[self.encounter['pk_encounter']])
      95                  if len(narr) == 0:
      96                          narr = [{'narrative': _('There is no narrative for this episode in this encounter.')}]
      97                  self.LBL_narrative.SetLabel('\n'.join([n['narrative'] for n in narr]))
      98
      99          #------------------------------------------------------------
     100 -        def _on_move_button_pressed(self, event):
     101
     102                  target_episode = self._PRW_episode_selector.GetData(can_create = False)
     103
     104                  if target_episode is None:
     105                          gmDispatcher.send(signal='statustext', msg=_('Must select episode to move narrative to first.'))
     106                          # FIXME: set to pink
     107                          self._PRW_episode_selector.SetFocus()
     108                          return False
     109
     110                  target_episode = gmEMRStructItems.cEpisode(aPK_obj=target_episode)
     111
     112                  self.encounter.transfer_clinical_data (
     113                          source_episode = self.source_episode,
     114                          target_episode = target_episode
     115                  )
     116
     117                  if self.IsModal():
     118                          self.EndModal(wx.ID_OK)
     119                  else:
     120                          self.Close()
     121
     122  #============================================================
     123  #============================================================
     124  from Gnumed.wxGladeWidgets import wxgSoapPluginPnl
     125
     126 -class cSoapPluginPnl(wxgSoapPluginPnl.wxgSoapPluginPnl, gmRegetMixin.cRegetOnPaintMixin):
     127          """A panel for in-context editing of progress notes.
     128
     129          Expects to be used as a notebook page.
     130
     131          Left hand side:
     132          - problem list (health issues and active episodes)
     133          - previous notes
     134
     135          Right hand side:
     136          - panel handling
     137                  - encounter details fields
     138                  - notebook with progress note editors
     139                  - visual progress notes
     140
     141          Listens to patient change signals, thus acts on the current patient.
     142          """
     143 -        def __init__(self, *args, **kwargs):
     144
     145                  wxgSoapPluginPnl.wxgSoapPluginPnl.__init__(self, *args, **kwargs)
     146                  gmRegetMixin.cRegetOnPaintMixin.__init__(self)
     147
     148                  self.__pat = gmPerson.gmCurrentPatient()
     149                  self.__init_ui()
     150                  self.__reset_ui_content()
     151                  self.__register_interests()
     152          #--------------------------------------------------------
     153          # internal helpers
     154          #--------------------------------------------------------
     155 -        def __init_ui(self):
     156                  self._LCTRL_active_problems.set_columns([_('Last'), _('Problem'), _('In health issue')])
     157                  self._LCTRL_active_problems.set_string_items()
     158                  self._LCTRL_active_problems.extend_popup_menu_callback = self._extend_popup_menu
     159
     160                  self._splitter_main.SetSashGravity(0.5)
     161                  self._splitter_left.SetSashGravity(0.5)
     162
     163                  splitter_size = self._splitter_main.GetSize()[0]
     164                  self._splitter_main.SetSashPosition(splitter_size * 3 // 10, True)
     165
     166                  splitter_size = self._splitter_left.GetSize()[1]
     167                  self._splitter_left.SetSashPosition(splitter_size * 6 // 20, True)
     168
     169          #--------------------------------------------------------
     181
     182          #--------------------------------------------------------
     183 -        def __reset_ui_content(self):
     184                  """Clear all information from input panel."""
     185
     186                  self._LCTRL_active_problems.set_string_items()
     187
     188                  self._TCTRL_recent_notes.SetValue('')
     189                  self._SZR_recent_notes.StaticBox.SetLabel(_('Most recent notes on selected problem'))
     190
     191                  self._PNL_editors.patient = None
     192          #--------------------------------------------------------
     193 -        def __refresh_problem_list(self):
     194                  """Update health problems list."""
     195
     196                  self._LCTRL_active_problems.set_string_items()
     197
     198                  emr = self.__pat.emr
     199                  problems = emr.get_problems (
     200                          include_closed_episodes = self._CHBOX_show_closed_episodes.IsChecked(),
     201                          include_irrelevant_issues = self._CHBOX_irrelevant_issues.IsChecked()
     202                  )
     203
     204                  list_items = []
     205                  active_problems = []
     206                  for problem in problems:
     207                          if not problem['problem_active']:
     208                                  if not problem['is_potential_problem']:
     209                                          continue
     210
     211                          active_problems.append(problem)
     212
     213                          if problem['type'] == 'issue':
     214                                  issue = emr.problem2issue(problem)
     215                                  last_encounter = emr.get_last_encounter(issue_id = issue['pk_health_issue'])
     216                                  if last_encounter is None:
     217                                          last = issue['modified_when'].strftime('%m/%Y')
     218                                  else:
     219                                          last = last_encounter['last_affirmed'].strftime('%m/%Y')
     220
     221                                  list_items.append([last, problem['problem'], gmTools.u_left_arrow_with_tail])
     222
     223                          elif problem['type'] == 'episode':
     224                                  epi = emr.problem2episode(problem)
     225                                  last_encounter = emr.get_last_encounter(episode_id = epi['pk_episode'])
     226                                  if last_encounter is None:
     227                                          last = epi['episode_modified_when'].strftime('%m/%Y')
     228                                  else:
     229                                          last = last_encounter['last_affirmed'].strftime('%m/%Y')
     230
     231                                  list_items.append ([
     232                                          last,
     233                                          problem['problem'],
     234                                          gmTools.coalesce(value2test = epi['health_issue'], return_instead = '?')                #gmTools.u_diameter
     235                                  ])
     236
     237                  self._LCTRL_active_problems.set_string_items(items = list_items)
     238                  self._LCTRL_active_problems.set_column_widths()
     239                  self._LCTRL_active_problems.set_data(data = active_problems)
     240
     241                  showing_potential_problems = (
     242                          self._CHBOX_show_closed_episodes.IsChecked()
     243                                  or
     244                          self._CHBOX_irrelevant_issues.IsChecked()
     245                  )
     246                  if showing_potential_problems:
     247                          self._SZR_problem_list.StaticBox.SetLabel(_('%s (active+potential) problems') % len(list_items))
     248                  else:
     249                          self._SZR_problem_list.StaticBox.SetLabel(_('%s active problems') % len(list_items))
     250
     251                  return True
     252          #--------------------------------------------------------
     253 -        def __get_info_for_issue_problem(self, problem=None, fancy=False):
     254                  soap = ''
     255                  emr = self.__pat.emr
     256                  prev_enc = emr.get_last_but_one_encounter(issue_id = problem['pk_health_issue'])
     257                  if prev_enc is not None:
     258                          soap += prev_enc.format (
     259                                  issues = [ problem['pk_health_issue'] ],
     260                                  with_soap = True,
     261                                  with_docs = fancy,
     262                                  with_tests = fancy,
     263                                  patient = self.__pat,
     264                                  fancy_header = False,
     265                                  with_rfe_aoe = True
     266                          )
     267
     268                  tmp = emr.active_encounter.format_soap (
     269                          soap_cats = 'soapu',
     270                          emr = emr,
     271                          issues = [ problem['pk_health_issue'] ],
     272                  )
     273                  if len(tmp) > 0:
     274                          soap += _('Current encounter:') + '\n'
     275                          soap += '\n'.join(tmp) + '\n'
     276
     277                  if problem['summary'] is not None:
     278                          soap += '\n-- %s ----------\n%s' % (
     279                                  _('Cumulative summary'),
     280                                  gmTools.wrap (
     281                                          text = problem['summary'],
     282                                          width = 45,
     283                                          initial_indent = ' ',
     284                                          subsequent_indent = ' '
     285                                  ).strip('\n')
     286                          )
     287
     288                  return soap
     289          #--------------------------------------------------------
     290 -        def __get_info_for_episode_problem(self, problem=None, fancy=False):
     291                  soap = ''
     292                  emr = self.__pat.emr
     293                  prev_enc = emr.get_last_but_one_encounter(episode_id = problem['pk_episode'])
     294                  if prev_enc is not None:
     295                          soap += prev_enc.format (
     296                                  episodes = [ problem['pk_episode'] ],
     297                                  with_soap = True,
     298                                  with_docs = fancy,
     299                                  with_tests = fancy,
     300                                  patient = self.__pat,
     301                                  fancy_header = False,
     302                                  with_rfe_aoe = True
     303                          )
     304                  else:
     305                          if problem['pk_health_issue'] is not None:
     306                                  prev_enc = emr.get_last_but_one_encounter(episode_id = problem['pk_health_issue'])
     307                                  if prev_enc is not None:
     308                                          soap += prev_enc.format (
     309                                                  with_soap = True,
     310                                                  with_docs = fancy,
     311                                                  with_tests = fancy,
     312                                                  patient = self.__pat,
     313                                                  issues = [ problem['pk_health_issue'] ],
     314                                                  fancy_header = False,
     315                                                  with_rfe_aoe = True
     316                                          )
     317
     318                  if problem['pk_health_issue'] is None:
     319                          tmp = emr.active_encounter.format_soap(soap_cats = 'soapu', emr = emr)
     320                  else:
     321                          tmp = emr.active_encounter.format_soap(soap_cats = 'soapu', emr = emr, issues = [problem['pk_health_issue']])
     322                  if len(tmp) > 0:
     323                          soap += _('Current encounter:') + '\n'
     324                          soap += '\n'.join(tmp) + '\n'
     325
     326                  if problem['summary'] is not None:
     327                          soap += '\n-- %s ----------\n%s' % (
     328                                  _('Cumulative summary'),
     329                                  gmTools.wrap (
     330                                          text = problem['summary'],
     331                                          width = 45,
     332                                          initial_indent = ' ',
     333                                          subsequent_indent = ' '
     334                                  ).strip('\n')
     335                          )
     336
     337                  return soap
     338          #--------------------------------------------------------
     339 -        def __refresh_recent_notes(self, problem=None):
     340                  """This refreshes the recent-notes part."""
     341
     342                  if problem is None:
     343                          caption = '<?>'
     344                          txt = ''
     345                  elif problem['type'] == 'issue':
     346                          caption = problem['problem'][:35]
     347                          txt = self.__get_info_for_issue_problem(problem = problem, fancy = not self._RBTN_notes_only.GetValue())
     348                  elif problem['type'] == 'episode':
     349                          caption = problem['problem'][:35]
     350                          txt = self.__get_info_for_episode_problem(problem = problem, fancy = not self._RBTN_notes_only.GetValue())
     351
     352                  self._TCTRL_recent_notes.SetValue(txt)
     353                  self._TCTRL_recent_notes.ShowPosition(self._TCTRL_recent_notes.GetLastPosition())
     354                  self._SZR_recent_notes.StaticBox.SetLabel(_('Most recent info on %s%s%s') % (
     355                          gmTools.u_left_double_angle_quote,
     356                          caption,
     357                          gmTools.u_right_double_angle_quote
     358                  ))
     359
     360                  self._TCTRL_recent_notes.Refresh()
     361
     362                  return True
     363          #--------------------------------------------------------
     364          # event handling
     365          #--------------------------------------------------------
     366 -        def __register_interests(self):
     367                  """Configure enabled event signals."""
     368                  # client internal signals
     369                  gmDispatcher.connect(signal = 'pre_patient_unselection', receiver = self._on_pre_patient_unselection)
     370                  gmDispatcher.connect(signal = 'post_patient_selection', receiver = self._on_post_patient_selection)
     371                  gmDispatcher.connect(signal = 'clin.episode_mod_db', receiver = self._on_episode_issue_mod_db)
     372                  gmDispatcher.connect(signal = 'clin.health_issue_mod_db', receiver = self._on_episode_issue_mod_db)
     373                  gmDispatcher.connect(signal = 'clin.episode_code_mod_db', receiver = self._on_episode_issue_mod_db)
     374          #--------------------------------------------------------
     375 -        def _on_pre_patient_unselection(self):
     376                  self.__reset_ui_content()
     377          #--------------------------------------------------------
     378 -        def _on_post_patient_selection(self):
     379                  self._schedule_data_reget()
     380                  self._PNL_editors.patient = self.__pat
     381          #--------------------------------------------------------
     382 -        def _on_episode_issue_mod_db(self):
     383                  self._schedule_data_reget()
     384          #--------------------------------------------------------
     385          # problem list specific events
     386          #--------------------------------------------------------
     387 -        def _on_problem_focused(self, event):
     388                  """Show related note at the bottom."""
     389                  pass
     390          #--------------------------------------------------------
     391 -        def _on_edit_issue(self, evt):
     392                  gmEMRStructWidgets.edit_health_issue(parent = self, issue = self.__focussed_problem.get_as_health_issue())
     393
     394          #--------------------------------------------------------
     395 -        def _on_edit_episode(self, evt):
     396                  gmEMRStructWidgets.edit_episode(parent = self, episode = self.__focussed_problem.get_as_episode())
     397
     398          #--------------------------------------------------------
     399 -        def _on_problem_selected(self, event):
     400                  """Show related note at the bottom."""
     401                  self.__refresh_recent_notes (
     402                          problem = self._LCTRL_active_problems.get_selected_item_data(only_one = True)
     403                  )
     404          #--------------------------------------------------------
     405 -        def _on_problem_activated(self, event):
     406                  """Open progress note editor for this problem.
     407                  """
     408                  problem = self._LCTRL_active_problems.get_selected_item_data(only_one = True)
     409                  if problem is None:
     410                          return True
     411
     412                  dbcfg = gmCfg.cCfgSQL()
     413                  allow_duplicate_editors = bool(dbcfg.get2 (
     414                          option = 'horstspace.soap_editor.allow_same_episode_multiple_times',
     415                          workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
     416                          bias = 'user',
     417                          default = False
     418                  ))
     419                  if self._PNL_editors.add_editor(problem = problem, allow_same_problem = allow_duplicate_editors):
     420                          return True
     421
     422                  gmGuiHelpers.gm_show_error (
     423                          aMessage = _(
     424                                  'Cannot open progress note editor for\n\n'
     425                                  '[%s].\n\n'
     426                          ) % problem['problem'],
     427                          aTitle = _('opening progress note editor')
     428                  )
     429                  return False
     430          #--------------------------------------------------------
     431 -        def _on_show_closed_episodes_checked(self, event):
     432                  self.__refresh_problem_list()
     433          #--------------------------------------------------------
     434 -        def _on_irrelevant_issues_checked(self, event):
     435                  self.__refresh_problem_list()
     436          #--------------------------------------------------------
     437          # recent-notes specific events
     438          #--------------------------------------------------------
     439 -        def _on_notes_only_selected(self, event):
     440                  self.__refresh_recent_notes (
     441                          problem = self._LCTRL_active_problems.get_selected_item_data(only_one = True)
     442                  )
     443          #--------------------------------------------------------
     444 -        def _on_full_encounter_selected(self, event):
     445                  self.__refresh_recent_notes (
     446                          problem = self._LCTRL_active_problems.get_selected_item_data(only_one = True)
     447                  )
     448          #--------------------------------------------------------
     449          # reget mixin API
     450          #--------------------------------------------------------
     451          # only needed for debugging:
     452          #def _schedule_data_reget(self):
     453          #       gmRegetMixin.cRegetOnPaintMixin._schedule_data_reget(self)
     454          #--------------------------------------------------------
     455 -        def _populate_with_data(self):
     456                  self.__refresh_problem_list()
     457                  return True
     458
     459  #============================================================
     460  from Gnumed.wxGladeWidgets import wxgFancySoapEditorPnl
     461
     462 -class cFancySoapEditorPnl(wxgFancySoapEditorPnl.wxgFancySoapEditorPnl):
     463          """A panel holding everything needed to edit in context:
     464
     465                  - encounter metadata
     466                  - progress notes
     467                          - textual
     468                          - visual
     469                  - episode summary
     470
     471          Does NOT act on the current patient.
     472          """
     473 -        def __init__(self, *args, **kwargs):
     474
     475                  wxgFancySoapEditorPnl.wxgFancySoapEditorPnl.__init__(self, *args, **kwargs)
     476
     477                  self.__init_ui()
     478                  self.patient = None
     479                  self.__register_interests()
     480          #--------------------------------------------------------
     481          # public API
     482          #--------------------------------------------------------
     483 -        def add_editor(self, problem=None, allow_same_problem=False):
     484                  return self._NB_soap_editors.add_editor(problem = problem, allow_same_problem = allow_same_problem)
     485          #--------------------------------------------------------
     486 -        def _get_patient(self):
     487                  return self.__pat
     488
     489 -        def _set_patient(self, patient):
     490                  #self.__pat.register_before_switching_from_patient_callback(callback = self._before_switching_from_patient_callback)
     491                  self.__pat = patient
     492                  self.__refresh_encounter()
     493                  self.__refresh_soap_notebook()
     494
     495          patient = property(_get_patient, _set_patient)
     496          #--------------------------------------------------------
     497 -        def save_encounter(self):
     498
     499                  if self.__pat is None:
     500                          return True
     501
     502                  if not self.__encounter_valid_for_save():
     503                          return False
     504
     505                  enc = self.__pat.emr.active_encounter
     506
     507                  rfe = self._TCTRL_rfe.GetValue().strip()
     508                  if len(rfe) == 0:
     509                          enc['reason_for_encounter'] = None
     510                  else:
     511                          enc['reason_for_encounter'] = rfe
     512                  aoe = self._TCTRL_aoe.GetValue().strip()
     513                  if len(aoe) == 0:
     514                          enc['assessment_of_encounter'] = None
     515                  else:
     516                          enc['assessment_of_encounter'] = aoe
     517
     518                  enc.save_payload()
     519
     520                  enc.generic_codes_rfe = [ c['data'] for c in self._PRW_rfe_codes.GetData() ]
     521                  enc.generic_codes_aoe = [ c['data'] for c in self._PRW_aoe_codes.GetData() ]
     522
     523                  return True
     524          #--------------------------------------------------------
     525          # internal helpers
     526          #--------------------------------------------------------
     527 -        def __init_ui(self):
     528                  self._NB_soap_editors.MoveAfterInTabOrder(self._PRW_aoe_codes)
     529          #--------------------------------------------------------
     530 -        def __reset_soap_notebook(self):
     531                  self._NB_soap_editors.DeleteAllPages()
     532                  self._NB_soap_editors.add_editor()
     533          #--------------------------------------------------------
     534 -        def __refresh_soap_notebook(self):
     535                  self.__reset_soap_notebook()
     536
     537                  if self.__pat is None:
     538                          return
     539
     540                  dbcfg = gmCfg.cCfgSQL()
     541                  auto_open_recent_problems = bool(dbcfg.get2 (
     542                          option = 'horstspace.soap_editor.auto_open_latest_episodes',
     543                          workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
     544                          bias = 'user',
     545                          default = True
     546                  ))
     547
     548                  emr = self.__pat.emr
     549                  recent_epis = emr.active_encounter.get_episodes()
     550                  prev_enc = emr.get_last_but_one_encounter()
     551                  if prev_enc is not None:
     552                          recent_epis.extend(prev_enc.get_episodes())
     553
     554                  for epi in recent_epis:
     555                          if not epi['episode_open']:
     556                                  continue
     557                          self._NB_soap_editors.add_editor(problem = epi)
     558
     559          #--------------------------------------------------------
     560 -        def __reset_encounter_fields(self):
     561                  self._TCTRL_rfe.SetValue('')
     562                  self._PRW_rfe_codes.SetText(suppress_smarts = True)
     563                  self._TCTRL_aoe.SetValue('')
     564                  self._PRW_aoe_codes.SetText(suppress_smarts = True)
     565
     566          #--------------------------------------------------------
     567 -        def __refresh_encounter(self):
     568                  """Update encounter fields."""
     569
     570                  self.__reset_encounter_fields()
     571
     572                  if self.__pat is None:
     573                          return
     574
     575                  enc = self.__pat.emr.active_encounter
     576
     577                  self._TCTRL_rfe.SetValue(gmTools.coalesce(enc['reason_for_encounter'], ''))
     578                  val, data = self._PRW_rfe_codes.generic_linked_codes2item_dict(enc.generic_codes_rfe)
     579                  self._PRW_rfe_codes.SetText(val, data)
     580
     581                  self._TCTRL_aoe.SetValue(gmTools.coalesce(enc['assessment_of_encounter'], ''))
     582                  val, data = self._PRW_aoe_codes.generic_linked_codes2item_dict(enc.generic_codes_aoe)
     583                  self._PRW_aoe_codes.SetText(val, data)
     584
     585                  self._TCTRL_rfe.Refresh()
     586                  self._PRW_rfe_codes.Refresh()
     587                  self._TCTRL_aoe.Refresh()
     588                  self._PRW_aoe_codes.Refresh()
     589
     590          #--------------------------------------------------------
     591 -        def __refresh_current_editor(self):
     592                  self._NB_soap_editors.refresh_current_editor()
     593
     594  #       #--------------------------------------------------------
     595  #       def __encounter_modified(self):
     596  #               """Assumes that the field data is valid."""
     597  #
     598  #               emr = self.__pat.emr
     599  #               enc = emr.active_encounter
     600  #
     601  #               data = {
     602  #                       'pk_type': enc['pk_type'],
     603  #                       'reason_for_encounter': gmTools.none_if(self._TCTRL_rfe.GetValue().strip(), u''),
     604  #                       'assessment_of_encounter': gmTools.none_if(self._TCTRL_aoe.GetValue().strip(), u''),
     605  #                       'pk_location': enc['pk_org_unit'],
     606  #                       'pk_patient': enc['pk_patient'],
     607  #                       'pk_generic_codes_rfe': self._PRW_rfe_codes.GetData(),
     608  #                       'pk_generic_codes_aoe': self._PRW_aoe_codes.GetData(),
     609  #                       'started': enc['started'],
     610  #                       'last_affirmed': enc['last_affirmed']
     611  #               }
     612  #
     613  #               return not enc.same_payload(another_object = data)
     614          #--------------------------------------------------------
     615 -        def __encounter_valid_for_save(self):
     616                  return True
     617          #--------------------------------------------------------
     618          # event handling
     619          #--------------------------------------------------------
     620 -        def __register_interests(self):
     621                  """Configure enabled event signals."""
     622                  # synchronous signals
     623                  gmDispatcher.send(signal = 'register_pre_exit_callback', callback = self._pre_exit_callback)
     624
     625                  # client internal signals
     626                  gmDispatcher.connect(signal = 'blobs.doc_med_mod_db', receiver = self._on_doc_mod_db)                   # visual progress notes
     627                  gmDispatcher.connect(signal = 'current_encounter_modified', receiver = self._on_current_encounter_modified)
     628                  gmDispatcher.connect(signal = 'current_encounter_switched', receiver = self._on_current_encounter_switched)
     629                  gmDispatcher.connect(signal = 'clin.rfe_code_mod_db', receiver = self._on_encounter_code_modified)
     630                  gmDispatcher.connect(signal = 'clin.aoe_code_mod_db', receiver = self._on_encounter_code_modified)
     631          #--------------------------------------------------------
     632 -        def _before_switching_from_patient_callback(self):
     633                  """Another patient is about to be activated.
     634
     635                  Patient change will not proceed before this returns True.
     636                  """
     637                  # don't worry about the encounter here - it will be offered
     638                  # for editing higher up if anything was saved to the EMR
     639                  if self.__pat is None:
     640                          return True
     641                  return self._NB_soap_editors.warn_on_unsaved_soap()
     642          #--------------------------------------------------------
     643 -        def _pre_exit_callback(self):
     644                  """The client is about to (be) shut down.
     645
     646                  Shutdown will not proceed before this returns.
     647                  """
     648                  if self.__pat is None:
     649                          return True
     650
     651  #               if self.__encounter_modified():
     652  #                       do_save_enc = gmGuiHelpers.gm_show_question (
     653  #                               aMessage = _(
     654  #                                       'You have modified the details\n'
     655  #                                       'of the current encounter.\n'
     656  #                                       '\n'
     657  #                                       'Do you want to save those changes ?'
     658  #                               ),
     659  #                               aTitle = _('Starting new encounter')
     660  #                       )
     661  #                       if do_save_enc:
     662  #                               if not self.save_encounter():
     663  #                                       gmDispatcher.send(signal = u'statustext', msg = _('Error saving current encounter.'), beep = True)
     664
     665                  saved = self._NB_soap_editors.save_all_editors (
     666                          emr = self.__pat.emr,
     667                          episode_name_candidates = [
     668                                  gmTools.none_if(self._TCTRL_aoe.GetValue().strip(), ''),
     669                                  gmTools.none_if(self._TCTRL_rfe.GetValue().strip(), '')
     670                          ]
     671                  )
     672                  if not saved:
     673                          gmDispatcher.send(signal = 'statustext', msg = _('Cannot save all editors. Some were kept open.'), beep = True)
     674                  return True
     675          #--------------------------------------------------------
     676 -        def _on_doc_mod_db(self):
     677                  self.__refresh_current_editor()
     678          #--------------------------------------------------------
     679 -        def _on_encounter_code_modified(self):
     680                  self.__pat.emr.active_encounter.refetch_payload()
     681                  self.__refresh_encounter()
     682          #--------------------------------------------------------
     683 -        def _on_current_encounter_modified(self):
     684                  self.__refresh_encounter()
     685          #--------------------------------------------------------
     686 -        def _on_current_encounter_switched(self):
     687                  self.__refresh_encounter()
     688          #--------------------------------------------------------
     689          # SOAP editor specific buttons
     690          #--------------------------------------------------------
     691 -        def _on_discard_editor_button_pressed(self, event):
     692                  self._NB_soap_editors.close_current_editor()
     693                  event.Skip()
     694          #--------------------------------------------------------
     695 -        def _on_new_editor_button_pressed(self, event):
     696                  self._NB_soap_editors.add_editor(allow_same_problem = True)
     697                  event.Skip()
     698          #--------------------------------------------------------
     699 -        def _on_clear_editor_button_pressed(self, event):
     700                  self._NB_soap_editors.clear_current_editor()
     701                  event.Skip()
     702          #--------------------------------------------------------
     703 -        def _on_save_note_button_pressed(self, event):
     704                  self._NB_soap_editors.save_current_editor (
     705                          emr = self.__pat.emr,
     706                          episode_name_candidates = [
     707                                  gmTools.none_if(self._TCTRL_aoe.GetValue().strip(), ''),
     708                                  gmTools.none_if(self._TCTRL_rfe.GetValue().strip(), '')
     709                          ]
     710                  )
     711                  event.Skip()
     712          #--------------------------------------------------------
     713 -        def _on_save_note_under_button_pressed(self, event):
     714                  encounter = gmEncounterWidgets.select_encounters (
     715                          parent = self,
     716                          patient = self.__pat,
     717                          single_selection = True
     718                  )
     719                  # cancelled or None selected:
     720                  if encounter is None:
     721                          return
     722
     723                  self._NB_soap_editors.save_current_editor (
     724                          emr = self.__pat.emr,
     725                          encounter = encounter['pk_encounter'],
     726                          episode_name_candidates = [
     727                                  gmTools.none_if(self._TCTRL_aoe.GetValue().strip(), ''),
     728                                  gmTools.none_if(self._TCTRL_rfe.GetValue().strip(), '')
     729                          ]
     730                  )
     731                  event.Skip()
     732          #--------------------------------------------------------
     733 -        def _on_image_button_pressed(self, event):
     734                  self._NB_soap_editors.add_visual_progress_note_to_current_problem()
     735                  event.Skip()
     736          #--------------------------------------------------------
     737          # encounter specific buttons
     738          #--------------------------------------------------------
     739 -        def _on_save_encounter_button_pressed(self, event):
     740                  self.save_encounter()
     741                  event.Skip()
     742          #--------------------------------------------------------
     743          # other buttons
     744          #--------------------------------------------------------
     745 -        def _on_save_all_button_pressed(self, event):
     746                  self.save_encounter()
     747                  time.sleep(0.3)
     748                  event.Skip()
     749                  wx.SafeYield()
     750
     751                  wx.CallAfter(self._save_all_button_pressed_bottom_half)
     752                  wx.SafeYield()
     753          #--------------------------------------------------------
     754 -        def _save_all_button_pressed_bottom_half(self):
     755                  emr = self.__pat.emr
     756                  saved = self._NB_soap_editors.save_all_editors (
     757                          emr = emr,
     758                          episode_name_candidates = [
     759                                  gmTools.none_if(self._TCTRL_aoe.GetValue().strip(), ''),
     760                                  gmTools.none_if(self._TCTRL_rfe.GetValue().strip(), '')
     761                          ]
     762                  )
     763                  if not saved:
     764                          gmDispatcher.send(signal = 'statustext', msg = _('Cannot save all editors. Some were kept open.'), beep = True)
     765
     766  #============================================================
     767 -class cSoapNoteInputNotebook(wx.Notebook):
     768          """A notebook holding panels with progress note editors.
     769
     770          There can be one or several progress note editor panels
     771          for each episode being worked on. The editor class in
     772          each panel is configurable.
     773
     774          There will always be one open editor.
     775          """
     776 -        def __init__(self, *args, **kwargs):
     777
     778                  kwargs['style'] = wx.NB_TOP | wx.NB_MULTILINE | wx.NO_BORDER
     779
     780                  wx.Notebook.__init__(self, *args, **kwargs)
     781
     782                  _log.debug('created wx.Notebook: %s with ID %s', self.__class__.__name__, self.Id)
     783          #--------------------------------------------------------
     784          # public API
     785          #--------------------------------------------------------
     786 -        def add_editor(self, problem=None, allow_same_problem=False):
     787                  """Add a progress note editor page.
     788
     789                  The way <allow_same_problem> is currently used in callers
     790                  it only applies to unassociated episodes.
     791                  """
     792                  problem_to_add = problem
     793
     794                  # determine label
     795                  if problem_to_add is None:
     796                          label = _('new problem')
     797                  else:
     798                          # normalize problem type
     799                          if isinstance(problem_to_add, gmEMRStructItems.cEpisode):
     800                                  problem_to_add = gmEMRStructItems.episode2problem(episode = problem_to_add, allow_closed = True)
     801
     802                          elif isinstance(problem_to_add, gmEMRStructItems.cHealthIssue):
     803                                  problem_to_add = gmEMRStructItems.health_issue2problem(health_issue = problem_to_add, allow_irrelevant = True)
     804
     805                          if not isinstance(problem_to_add, gmEMRStructItems.cProblem):
     806                                  raise TypeError('cannot open progress note editor for [%s]' % problem_to_add)
     807
     808                          label = problem_to_add['problem']
     809                          # FIXME: configure maximum length
     810                          if len(label) > 23:
     811                                  label = label[:21] + gmTools.u_ellipsis
     812
     813                  # new unassociated problem or dupes allowed
     814                  if allow_same_problem:
     815                          new_page = gmProgressNotesEAWidgets.cProgressNotesEAPnl(self, -1, problem = problem_to_add)
     816                          result = self.AddPage (
     817                                  page = new_page,
     818                                  text = label,
     819                                  select = True
     820                          )
     821                          return result
     822
     823                  # real problem, no dupes allowed
     824                  # - raise existing editor
     825                  for page_idx in range(self.GetPageCount()):
     826                          page = self.GetPage(page_idx)
     827
     828                          if problem_to_add is None:
     829                                  if page.problem is None:
     830                                          self.SetSelection(page_idx)
     831                                          gmDispatcher.send(signal = 'statustext', msg = 'Raising existing editor.', beep = True)
     832                                          return True
     833                                  continue
     834
     835                          # editor is for unassociated new problem
     836                          if page.problem is None:
     837                                  continue
     838
     839                          # editor is for episode
     840                          if page.problem['type'] == 'episode':
     841                                  if page.problem['pk_episode'] == problem_to_add['pk_episode']:
     842                                          self.SetSelection(page_idx)
     843                                          gmDispatcher.send(signal = 'statustext', msg = 'Raising existing editor.', beep = True)
     844                                          return True
     845                                  continue
     846
     847                          # editor is for health issue
     848                          if page.problem['type'] == 'issue':
     849                                  if page.problem['pk_health_issue'] == problem_to_add['pk_health_issue']:
     850                                          self.SetSelection(page_idx)
     851                                          gmDispatcher.send(signal = 'statustext', msg = 'Raising existing editor.', beep = True)
     852                                          return True
     853                                  continue
     854
     855                  # - or add new editor
     856                  new_page = gmProgressNotesEAWidgets.cProgressNotesEAPnl(parent = self, problem = problem_to_add)
     857                  result = self.AddPage (
     858                          page = new_page,
     859                          text = label,
     860                          select = True
     861                  )
     862
     863                  return result
     864          #--------------------------------------------------------
     865 -        def close_current_editor(self):
     866
     867                  page_idx = self.GetSelection()
     868                  page = self.GetPage(page_idx)
     869
     870                  if not page.empty:
     871                          really_discard = gmGuiHelpers.gm_show_question (
     872                                  _('Are you sure you really want to\n'
     873                                    'discard this progress note ?\n'
     874                                  ),
     875                                  _('Discarding progress note')
     876                          )
     877                          if really_discard is False:
     878                                  return
     879
     880                  self.DeletePage(page_idx)
     881
     882                  # always keep one unassociated editor open
     883                  if self.GetPageCount() == 0:
     884                          self.add_editor()
     885          #--------------------------------------------------------
     886 -        def save_current_editor(self, emr=None, episode_name_candidates=None, encounter=None):
     887                  page_idx = self.GetSelection()
     888                  _log.debug('saving editor on current page (#%s)', page_idx)
     889                  page = self.GetPage(page_idx)
     890                  if not page.save(emr = emr, episode_name_candidates = episode_name_candidates, encounter = encounter):
     891                          _log.debug('not saved, not deleting')
     892                          return False
     893
     894                  _log.debug('deleting')
     895                  self.DeletePage(page_idx)
     896
     897                  # always keep one unassociated editor open
     898                  if self.GetPageCount() == 0:
     899                          self.add_editor()
     900                  return True
     901          #--------------------------------------------------------
     902 -        def warn_on_unsaved_soap(self):
     903                  for page_idx in range(self.GetPageCount()):
     904                          page = self.GetPage(page_idx)
     905                          if page.empty:
     906                                  continue
     907
     908                          gmGuiHelpers.gm_show_warning (
     909                                  _('There are unsaved progress notes !\n'),
     910                                  _('Unsaved progress notes')
     911                          )
     912                          return False
     913
     914                  return True
     915          #--------------------------------------------------------
     916 -        def save_all_editors(self, emr=None, episode_name_candidates=None):
     917
     918                  _log.debug('saving editors: %s', self.GetPageCount())
     919
     920                  # always keep one unassociated editor open
     921                  if self.GetPageCount() == 0:
     922                          self.add_editor()
     923                          return True
     924
     925                  # first of all save the current editor such
     926                  # as not to confuse the user by switching away
     927                  # from the page she invoked [save all] from
     928                  idx_of_current_page = self.GetSelection()
     929                  _log.debug('saving editor on current page (#%s)', idx_of_current_page)
     930                  all_closed = self.GetPage(idx_of_current_page).save(emr = emr, episode_name_candidates = episode_name_candidates)
     931                  if all_closed:
     932                          _log.debug('deleting')
     933                          self.DeletePage(idx_of_current_page)
     934                          idx_of_current_page = None
     935                  else:
     936                          _log.debug('not saved, not deleting')
     937
     938                  # now save remaining editors from right to left
     939                  for page_idx in range((self.GetPageCount() - 1), -1, -1):
     940                          # skip current ?
     941                          if page_idx == idx_of_current_page:
     942                                  # we tried and failed, no need to retry
     943                                  continue
     944                          _log.debug('saving editor on page %s of %s', page_idx, self.GetPageCount())
     945                          try:
     946                                  self.ChangeSelection(page_idx)
     947                                  _log.debug('editor raised')
     948                          except Exception:
     949                                  _log.exception('cannot raise editor')
     950                          page = self.GetPage(page_idx)
     951                          if page.save(emr = emr, episode_name_candidates = episode_name_candidates):
     952                                  _log.debug('saved, deleting')
     953                                  self.DeletePage(page_idx)
     954                          else:
     955                                  _log.debug('not saved, not deleting')
     956                                  all_closed = False
     957
     958                  # always keep one unassociated editor open
     959                  if self.GetPageCount() == 0:
     960                          self.add_editor()
     961
     962                  return (all_closed is True)
     963          #--------------------------------------------------------
     964 -        def clear_current_editor(self):
     965                  self.GetCurrentPage().clear()
     966          #--------------------------------------------------------
     967 -        def get_current_problem(self):
     968                  return self.GetCurrentPage().problem
     969          #--------------------------------------------------------
     970 -        def refresh_current_editor(self):
     971                  self.GetCurrentPage().refresh()
     972          #--------------------------------------------------------
     973 -        def add_visual_progress_note_to_current_problem(self):
     974                  self.GetCurrentPage().add_visual_progress_note()
     975
     976  #============================================================
     977  #============================================================
     978  from Gnumed.wxGladeWidgets import wxgSimpleSoapPluginPnl
     979
     980 -class cSimpleSoapPluginPnl(wxgSimpleSoapPluginPnl.wxgSimpleSoapPluginPnl, gmRegetMixin.cRegetOnPaintMixin):
     981 -        def __init__(self, *args, **kwargs):
     982
     983                  wxgSimpleSoapPluginPnl.wxgSimpleSoapPluginPnl.__init__(self, *args, **kwargs)
     984                  gmRegetMixin.cRegetOnPaintMixin.__init__(self)
     985
     986                  self.__curr_pat = gmPerson.gmCurrentPatient()
     987                  self.__problem = None
     988                  self.__init_ui()
     989                  self.__register_interests()
     990          #-----------------------------------------------------
     991          # internal API
     992          #-----------------------------------------------------
     993 -        def __init_ui(self):
     994                  self._LCTRL_problems.set_columns(columns = [_('Problem list')])
     995                  self._LCTRL_problems.activate_callback = self._on_problem_activated
     996                  self._LCTRL_problems.item_tooltip_callback = self._on_get_problem_tooltip
     997
     998                  self._splitter_main.SetSashGravity(0.5)
     999                  splitter_width = self._splitter_main.GetSize()[0]
    1000                  self._splitter_main.SetSashPosition(splitter_width // 2, True)
    1001
    1002                  self._TCTRL_soap.Disable()
    1003                  self._BTN_save_soap.Disable()
    1004                  self._BTN_clear_soap.Disable()
    1005          #-----------------------------------------------------
    1006 -        def __reset_ui(self):
    1007                  self._LCTRL_problems.set_string_items()
    1008                  self._TCTRL_soap_problem.SetValue(_('<above, double-click problem to start entering SOAP note>'))
    1009                  self._TCTRL_soap.SetValue('')
    1010                  self._CHBOX_filter_by_problem.SetLabel(_('&Filter by problem'))
    1011                  self._TCTRL_journal.SetValue('')
    1012
    1013                  self._TCTRL_soap.Disable()
    1014                  self._BTN_save_soap.Disable()
    1015                  self._BTN_clear_soap.Disable()
    1016          #-----------------------------------------------------
    1017 -        def __save_soap(self):
    1018                  if not self.__curr_pat.connected:
    1019                          return None
    1020
    1021                  if self.__problem is None:
    1022                          return None
    1023
    1024                  saved = self.__curr_pat.emr.add_clin_narrative (
    1025                          note = self._TCTRL_soap.GetValue().strip(),
    1026                          soap_cat = 'u',
    1027                          episode = self.__problem
    1028                  )
    1029
    1030                  if saved is None:
    1031                          return False
    1032
    1033                  self._TCTRL_soap.SetValue('')
    1034                  self.__refresh_journal()
    1035                  return True
    1036          #-----------------------------------------------------
    1037 -        def __perhaps_save_soap(self):
    1038                  if self._TCTRL_soap.GetValue().strip() == '':
    1039                          return True
    1040                  if self.__problem is None:
    1041                          # FIXME: this could potentially lose input
    1042                          self._TCTRL_soap.SetValue('')
    1043                          return None
    1044                  save_it = gmGuiHelpers.gm_show_question (
    1045                          title = _('Saving SOAP note'),
    1046                          question = _('Do you want to save the SOAP note ?')
    1047                  )
    1048                  if save_it:
    1049                          return self.__save_soap()
    1050                  return False
    1051          #-----------------------------------------------------
    1052 -        def __refresh_problem_list(self):
    1053                  self._LCTRL_problems.set_string_items()
    1054                  emr = self.__curr_pat.emr
    1055                  epis = emr.get_episodes(open_status = True)
    1056                  if len(epis) > 0:
    1057                          self._LCTRL_problems.set_string_items(items = [ '%s%s' % (
    1058                                  e['description'],
    1059                                  gmTools.coalesce(e['health_issue'], '', ' (%s)')
    1060                          ) for e in epis ])
    1061                          self._LCTRL_problems.set_data(epis)
    1062          #-----------------------------------------------------
    1063 -        def __refresh_journal(self):
    1064                  self._TCTRL_journal.SetValue('')
    1065                  epi = self._LCTRL_problems.get_selected_item_data(only_one = True)
    1066
    1067                  if epi is not None:
    1068                          self._CHBOX_filter_by_problem.SetLabel(_('&Filter by problem %s%s%s') % (
    1069                                  gmTools.u_left_double_angle_quote,
    1070                                  epi['description'],
    1071                                  gmTools.u_right_double_angle_quote
    1072                          ))
    1073                          self._CHBOX_filter_by_problem.Refresh()
    1074
    1075                  if not self._CHBOX_filter_by_problem.IsChecked():
    1076                          self._TCTRL_journal.SetValue(self.__curr_pat.emr.format_summary())
    1077                          return
    1078
    1079                  if epi is None:
    1080                          return
    1081
    1082                  self._TCTRL_journal.SetValue(epi.format_as_journal())
    1083          #-----------------------------------------------------
    1084          # event handling
    1085          #-----------------------------------------------------
    1086 -        def __register_interests(self):
    1087                  """Configure enabled event signals."""
    1088                  # client internal signals
    1089                  gmDispatcher.connect(signal = 'pre_patient_unselection', receiver = self._on_pre_patient_unselection)
    1090                  gmDispatcher.connect(signal = 'post_patient_selection', receiver = self._on_post_patient_selection)
    1091                  gmDispatcher.connect(signal = 'clin.episode_mod_db', receiver = self._on_episode_issue_mod_db)
    1092                  gmDispatcher.connect(signal = 'clin.health_issue_mod_db', receiver = self._on_episode_issue_mod_db)
    1093
    1094                  # synchronous signals
    1095                  self.__curr_pat.register_before_switching_from_patient_callback(callback = self._before_switching_from_patient_callback)
    1096                  gmDispatcher.send(signal = 'register_pre_exit_callback', callback = self._pre_exit_callback)
    1097          #-----------------------------------------------------
    1098 -        def _before_switching_from_patient_callback(self):
    1099                  """Another patient is about to be activated.
    1100
    1101                  Patient change will not proceed before this returns True.
    1102                  """
    1103                  if not self.__curr_pat.connected:
    1104                          return True
    1105                  self.__perhaps_save_soap()
    1106                  self.__problem = None
    1107                  return True
    1108          #-----------------------------------------------------
    1109 -        def _pre_exit_callback(self):
    1110                  """The client is about to be shut down.
    1111
    1112                  Shutdown will not proceed before this returns.
    1113                  """
    1114                  if not self.__curr_pat.connected:
    1115                          return
    1116                  if not self.__save_soap():
    1117                          gmDispatcher.send(signal = 'statustext', msg = _('Cannot save SimpleNotes SOAP note.'), beep = True)
    1118                  return
    1119          #-----------------------------------------------------
    1120 -        def _on_pre_patient_unselection(self):
    1121                  self.__reset_ui()
    1122          #-----------------------------------------------------
    1123 -        def _on_post_patient_selection(self):
    1124                  self._schedule_data_reget()
    1125          #-----------------------------------------------------
    1126 -        def _on_episode_issue_mod_db(self):
    1127                  self._schedule_data_reget()
    1128          #-----------------------------------------------------
    1129 -        def _on_problem_activated(self, event):
    1130                  self.__perhaps_save_soap()
    1131                  epi = self._LCTRL_problems.get_selected_item_data(only_one = True)
    1132                  self._TCTRL_soap_problem.SetValue(_('Progress note: %s%s') % (
    1133                          epi['description'],
    1134                          gmTools.coalesce(epi['health_issue'], '', ' (%s)')
    1135                  ))
    1136                  self.__problem = epi
    1137                  self._TCTRL_soap.SetValue('')
    1138
    1139                  self._TCTRL_soap.Enable()
    1140                  self._BTN_save_soap.Enable()
    1141                  self._BTN_clear_soap.Enable()
    1142          #-----------------------------------------------------
    1143 -        def _on_get_problem_tooltip(self, episode):
    1144                  return episode.format (
    1145                          patient = self.__curr_pat,
    1146                          with_summary = False,
    1147                          with_codes = True,
    1148                          with_encounters = False,
    1149                          with_documents = False,
    1150                          with_hospital_stays = False,
    1151                          with_procedures = False,
    1152                          with_family_history = False,
    1153                          with_tests = False,
    1154                          with_vaccinations = False,
    1155                          with_health_issue = True
    1156                  )
    1157          #-----------------------------------------------------
    1158 -        def _on_list_item_selected(self, event):
    1159                  event.Skip()
    1160                  self.__refresh_journal()
    1161          #-----------------------------------------------------
    1162 -        def _on_filter_by_problem_checked(self, event):
    1163                  event.Skip()
    1164                  self.__refresh_journal()
    1165          #-----------------------------------------------------
    1166 -        def _on_add_problem_button_pressed(self, event):
    1167                  event.Skip()
    1168                  epi_name = wx.GetTextFromUser (
    1169                          _('Please enter a name for the new problem:'),
    1170                          caption = _('Adding a problem'),
    1171                          parent = self
    1172                  ).strip()
    1173                  if epi_name == '':
    1174                          return
    1175                  self.__curr_pat.emr.add_episode (
    1176                          episode_name = epi_name,
    1177                          pk_health_issue = None,
    1178                          is_open = True
    1179                  )
    1180          #-----------------------------------------------------
    1181 -        def _on_edit_problem_button_pressed(self, event):
    1182                  event.Skip()
    1183                  epi = self._LCTRL_problems.get_selected_item_data(only_one = True)
    1184                  if epi is None:
    1185                          return
    1186                  gmEMRStructWidgets.edit_episode(parent = self, episode = epi)
    1187          #-----------------------------------------------------
    1188 -        def _on_delete_problem_button_pressed(self, event):
    1189                  event.Skip()
    1190                  epi = self._LCTRL_problems.get_selected_item_data(only_one = True)
    1191                  if epi is None:
    1192                          return
    1193                  if not gmEMRStructItems.delete_episode(episode = epi):
    1194                          gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete problem. There is still clinical data recorded for it.'))
    1195          #-----------------------------------------------------
    1196 -        def _on_save_soap_button_pressed(self, event):
    1197                  event.Skip()
    1198                  self.__save_soap()
    1199          #-----------------------------------------------------
    1200 -        def _on_clear_soap_button_pressed(self, event):
    1201                  event.Skip()
    1202                  self._TCTRL_soap.SetValue('')
    1203          #-----------------------------------------------------
    1204          # reget-on-paint mixin API
    1205          #-----------------------------------------------------
    1206 -        def _populate_with_data(self):
    1207                  self.__refresh_problem_list()
    1208                  self.__refresh_journal()
    1209                  self._TCTRL_soap.SetValue('')
    1210                  return True
    1211
    1212  #============================================================
    1213  # main
    1214  #------------------------------------------------------------
    1215  if __name__ == '__main__':
    1216
    1217          if len(sys.argv) < 2:
    1218                  sys.exit()
    1219
    1220          if sys.argv[1] != 'test':
    1221                  sys.exit()
    1222
    1223          gmI18N.activate_locale()
    1224          gmI18N.install_domain(domain = 'gnumed')
    1225
    1226          #----------------------------------------
    1227 -        def test_cSoapPluginPnl():
    1228                  patient = gmPersonSearch.ask_for_patient()
    1229                  if patient is None:
    1230                          print("No patient. Exiting gracefully...")
    1231                          return
    1232                  set_active_patient(patient=patient)
    1233
    1234                  application = wx.PyWidgetTester(size=(800,500))
    1235                  soap_input = cSoapPluginPnl(application.frame, -1)
    1236                  application.frame.Show(True)
    1237                  soap_input._schedule_data_reget()
    1238                  application.MainLoop()
    1239          #----------------------------------------
    1240          #test_cSoapPluginPnl()
    1241