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

# Source Code for Module Gnumed.wxpython.gmWaitingListWidgets

      1  """GNUmed waiting list widgets."""
      2  #================================================================
      3  __author__ = 'karsten.hilbert@gmx.net'
      4  __license__ = 'GPL v2 or later (details at http://www.gnu.org)'
      5
      6  # stdlib
      7  import logging
      8  import sys
      9
     10
     11  # 3rd party
     12  import wx
     13
     14  # GNUmed
     15  if __name__ == '__main__':
     16          sys.path.insert(0, '../../')
     17
     18  from Gnumed.pycommon import gmDispatcher
     19  from Gnumed.pycommon import gmTools
     20  from Gnumed.pycommon import gmMatchProvider
     21  from Gnumed.pycommon import gmI18N
     22  from Gnumed.pycommon import gmExceptions
     23  from Gnumed.pycommon import gmDateTime
     24
     25  from Gnumed.business import gmPraxis
     26  from Gnumed.business import gmPerson
     27
     28  from Gnumed.wxpython import gmEditArea
     29  from Gnumed.wxpython import gmPhraseWheel
     30  from Gnumed.wxpython import gmRegetMixin
     31  from Gnumed.wxpython import gmPatSearchWidgets
     32  from Gnumed.wxpython import gmGuiHelpers
     33
     34
     35  _log = logging.getLogger('gm.ui')
     36  #============================================================
     37  # waiting list widgets
     38  #============================================================
     39 -class cWaitingZonePhraseWheel(gmPhraseWheel.cPhraseWheel):
     40
     41 -        def __init__(self, *args, **kwargs):
     42
     43                  gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
     44
     45                  mp = gmMatchProvider.cMatchProvider_FixedList(aSeq = [])
     46                  mp.setThresholds(1, 2, 2)
     47                  self.matcher = mp
     48                  self.selection_only = False
     49
     50          #--------------------------------------------------------
     51 -        def update_matcher(self, items):
     52                  self.matcher.set_items([ {'data': i, 'list_label': i, 'field_label': i, 'weight': 1} for i in items ])
     53
     54  #============================================================
     55 -def edit_waiting_list_entry(parent=None, entry=None, patient=None):
     56          if parent is None:
     57                  parent = wx.GetApp().GetTopWindow()
     58          ea = cWaitingListEntryEditAreaPnl(parent, -1, patient = gmTools.bool2subst((entry is None), patient, None))
     59          ea.data = entry
     60          ea.mode = gmTools.coalesce(entry, 'new', 'edit')
     61          dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = True)
     62          dlg.SetTitle(gmTools.coalesce(entry, _('Adding new waiting list entry'), _('Editing waiting list entry')))
     63          if dlg.ShowModal() == wx.ID_OK:
     64                  dlg.DestroyLater()
     65                  return True
     66          dlg.DestroyLater()
     67          return False
     68
     69  #============================================================
     70  from Gnumed.wxGladeWidgets import wxgWaitingListEntryEditAreaPnl
     71
     72 -class cWaitingListEntryEditAreaPnl(wxgWaitingListEntryEditAreaPnl.wxgWaitingListEntryEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
     73
     74 -        def __init__ (self, *args, **kwargs):
     75
     76                  try:
     77                          self.patient = kwargs['patient']
     78                          del kwargs['patient']
     79                  except KeyError:
     80                          self.patient = None
     81
     82                  try:
     83                          data = kwargs['entry']
     84                          del kwargs['entry']
     85                  except KeyError:
     86                          data = None
     87
     88                  wxgWaitingListEntryEditAreaPnl.wxgWaitingListEntryEditAreaPnl.__init__(self, *args, **kwargs)
     89                  gmEditArea.cGenericEditAreaMixin.__init__(self)
     90
     91                  if data is None:
     92                          self.mode = 'new'
     93                  else:
     94                          self.data = data
     95                          self.mode = 'edit'
     96
     97                  praxis = gmPraxis.gmCurrentPraxisBranch()
     98                  pats = praxis.waiting_list_patients
     99                  zones = {}
    100                  zones.update([ [p['waiting_zone'], None] for p in pats if p['waiting_zone'] is not None ])
    101                  self._PRW_zone.update_matcher(items = zones.keys())
    102          #--------------------------------------------------------
    103          # edit area mixin API
    104          #--------------------------------------------------------
    105 -        def _refresh_as_new(self):
    106                  if self.patient is None:
    107                          self._PRW_patient.person = None
    108                          self._PRW_patient.Enable(True)
    109                          self._PRW_patient.SetFocus()
    110                  else:
    111                          self._PRW_patient.person = self.patient
    112                          self._PRW_patient.Enable(False)
    113                          self._TCTRL_comment.SetFocus()
    114                  self._PRW_patient._display_name()
    115
    116                  self._TCTRL_comment.SetValue('')
    117                  self._PRW_zone.SetValue('')
    118                  self._SPCTRL_urgency.SetValue(0)
    119          #--------------------------------------------------------
    120 -        def _refresh_from_existing(self):
    121                  self._PRW_patient.person = gmPerson.cPerson(aPK_obj = self.data['pk_identity'])
    122                  self._PRW_patient.Enable(False)
    123                  self._PRW_patient._display_name()
    124
    125                  self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], ''))
    126                  self._PRW_zone.SetValue(gmTools.coalesce(self.data['waiting_zone'], ''))
    127                  self._SPCTRL_urgency.SetValue(self.data['urgency'])
    128
    129                  self._TCTRL_comment.SetFocus()
    130          #--------------------------------------------------------
    131 -        def _valid_for_save(self):
    132                  validity = True
    133
    134                  self.display_tctrl_as_valid(tctrl = self._PRW_patient, valid = (self._PRW_patient.person is not None))
    135                  validity = (self._PRW_patient.person is not None)
    136
    137                  if validity is False:
    138                          self.StatusText = _('Cannot add to waiting list. Missing essential input.')
    139
    140                  return validity
    141          #----------------------------------------------------------------
    142 -        def _save_as_new(self):
    143                  # FIXME: filter out dupes ?
    144                  self._PRW_patient.person.put_on_waiting_list (
    145                          urgency = self._SPCTRL_urgency.GetValue(),
    146                          comment = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), ''),
    147                          zone = gmTools.none_if(self._PRW_zone.GetValue().strip(), '')
    148                  )
    149                  # dummy:
    150                  self.data = {'pk_identity': self._PRW_patient.person.ID, 'comment': None, 'waiting_zone': None, 'urgency': 0}
    151                  return True
    152          #----------------------------------------------------------------
    153 -        def _save_as_update(self):
    154                  gmPraxis.gmCurrentPraxisBranch().update_in_waiting_list (
    155                          pk = self.data['pk_waiting_list'],
    156                          urgency = self._SPCTRL_urgency.GetValue(),
    157                          comment = self._TCTRL_comment.GetValue().strip(),
    158                          zone = self._PRW_zone.GetValue().strip()
    159                  )
    160                  return True
    161  #============================================================
    162  from Gnumed.wxGladeWidgets import wxgWaitingListPnl
    163
    164 -class cWaitingListPnl(wxgWaitingListPnl.wxgWaitingListPnl, gmRegetMixin.cRegetOnPaintMixin):
    165
    166 -        def __init__ (self, *args, **kwargs):
    167
    168                  wxgWaitingListPnl.wxgWaitingListPnl.__init__(self, *args, **kwargs)
    169                  gmRegetMixin.cRegetOnPaintMixin.__init__(self)
    170
    171                  self.__current_zone = None
    172                  self.__id_most_recently_activated_patient = None
    173                  self.__comment_most_recently_activated_patient = None
    174
    175                  self.__init_ui()
    176                  self.__register_events()
    177          #--------------------------------------------------------
    178          # interal helpers
    179          #--------------------------------------------------------
    180 -        def __init_ui(self):
    181                  self._LCTRL_patients.set_columns ([
    182                          _('Zone'),
    183                          _('Urgency'),
    184                          _('Registered'),
    185                          _('Waiting time'),
    186                          _('Patient'),
    187                          _('Born'),
    188                          _('Comment')
    189                  ])
    190                  self._LCTRL_patients.set_column_widths(widths = [wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE_USEHEADER, wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE])
    191                  self._LCTRL_patients.item_tooltip_callback = self._on_get_list_tooltip
    192                  self._PRW_zone.add_callback_on_selection(callback = self._on_zone_selected)
    193                  self._PRW_zone.add_callback_on_lose_focus(callback = self._on_zone_selected)
    194          #--------------------------------------------------------
    195 -        def _check_RFE(self):
    196                  """
    197                  This gets called when a patient has been activated, but
    198                  only when the waiting list is actually in use (that is,
    199                  the plugin is loaded)
    200                  """
    201                  pat = gmPerson.gmCurrentPatient()
    202                  enc = pat.emr.active_encounter
    203                  if gmTools.coalesce(enc['reason_for_encounter'], '').strip() != '':
    204                          return
    205                  entries = pat.waiting_list_entries
    206                  if len(entries) == 0:
    207                          if self.__id_most_recently_activated_patient is None:
    208                                  return
    209                          if self.__id_most_recently_activated_patient != pat.ID:
    210                                  return
    211                          rfe = self.__comment_most_recently_activated_patient
    212                  else:
    213                          entry = entries[0]
    214                          if gmTools.coalesce(entry['comment'], '').strip() == '':
    215                                  return
    216                          rfe = entry['comment'].strip()
    217                  enc['reason_for_encounter'] = rfe
    218                  enc.save()
    219                  self.__id_most_recently_activated_patient = None
    220          #--------------------------------------------------------
    221 -        def _on_get_list_tooltip(self, entry):
    222
    223                  dob = gmTools.coalesce (
    224                          gmTools.coalesce(entry['dob'], '', function4value = ('strftime', '%d %b %Y')),
    225                          '',
    226                          ' (%s)'
    227                  )
    228
    229                  tt = _(
    230                          '%s patients are waiting.\n'
    231                          '\n'
    232                          'Doubleclick to activate (entry will stay in list).'
    233                  ) % self._LCTRL_patients.GetItemCount()
    234
    235                  tt += _(
    236                          '\n'
    237                          '%s\n'
    238                          'Patient: %s%s\n'
    239                          '%s'
    240                          'Urgency: %s\n'
    241                          'Time: %s\n'
    242                          '%s'
    243                  ) % (
    244                          gmTools.u_box_horiz_single * 50,
    245                          '%s, %s (%s)' % (entry['lastnames'], entry['firstnames'], entry['l10n_gender']),
    246                          dob,
    247                          gmTools.coalesce(entry['waiting_zone'], '', _('Zone: %s\n')),
    248                          entry['urgency'],
    249                          gmDateTime.format_interval_medically(entry['waiting_time']),
    250                          gmTools.coalesce(entry['comment'], '', '\n%s')
    251                  )
    252
    253                  return tt
    254          #--------------------------------------------------------
    255 -        def __register_events(self):
    256                  gmDispatcher.connect(signal = 'clin.waiting_list_mod_db', receiver = self._on_waiting_list_modified)
    257                  gmDispatcher.connect(signal = 'post_patient_selection', receiver = self._on_post_patient_selection)
    258          #--------------------------------------------------------
    259 -        def __refresh_waiting_list(self):
    260                  self.__id_most_recently_activated_patient = None
    261                  col, ascending = self._LCTRL_patients.GetSortState()    # preserve sorting order
    262
    263                  praxis = gmPraxis.gmCurrentPraxisBranch()
    264                  pats = praxis.waiting_list_patients
    265
    266                  # set matcher to all zones currently in use
    267                  zones = {}
    268                  zones.update([ [p['waiting_zone'], None] for p in pats if p['waiting_zone'] is not None ])
    269                  self._PRW_zone.update_matcher(items = zones.keys())
    270
    271                  # filter patient list by zone and set waiting list
    272                  self.__current_zone = self._PRW_zone.GetValue().strip()
    273                  if self.__current_zone == '':
    274                          pats = [ p for p in pats ]
    275                  else:
    276                          pats = [ p for p in pats if p['waiting_zone'] == self.__current_zone ]
    277
    278                  # filter by "active patient only"
    279                  curr_pat = gmPerson.gmCurrentPatient()
    280                  if curr_pat.connected:
    281                          if self._CHBOX_active_patient_only.IsChecked():
    282                                  pats = [ p for p in pats if p['pk_identity'] == curr_pat.ID ]
    283
    284                  old_pks = [ d['pk_waiting_list'] for d in self._LCTRL_patients.get_selected_item_data() ]
    285                  self._LCTRL_patients.set_string_items (
    286                          [ [
    287                                  gmTools.coalesce(p['waiting_zone'], ''),
    288                                  p['urgency'],
    289                                  gmDateTime.pydt_strftime(p['registered'], format='%Y %b %d %H:%M'),
    290                                  gmDateTime.format_interval_medically(p['waiting_time']),
    291                                  '%s, %s (%s)' % (p['lastnames'], p['firstnames'], p['l10n_gender']),
    292                                  gmTools.coalesce (
    293                                          gmTools.coalesce (p['dob'], '', function4value = ('strftime', '%d %b %Y')),
    294                                          ''
    295                                  ),
    296                                  gmTools.coalesce(p['comment'], '').split('\n')[0]
    297                          ] for p in pats ]
    298                  )
    299                  self._LCTRL_patients.set_column_widths()
    300                  self._LCTRL_patients.set_data(pats)
    301                  new_selections = []
    302                  new_pks = [ p['pk_waiting_list'] for p in pats ]
    303                  for old_pk in old_pks:
    304                          if old_pk in new_pks:
    305                                  new_selections.append(new_pks.index(old_pk))
    306                  self._LCTRL_patients.selections = new_selections
    307                  self._LCTRL_patients.Refresh()
    308                  self._LCTRL_patients.SortListItems(col, ascending) # re-sort
    309
    310                  self._LBL_no_of_patients.SetLabel(_('(%s patients)') % len(pats))
    311
    312                  if len(pats) == 0:
    313                          self._BTN_activate.Enable(False)
    314                          self._BTN_activateplus.Enable(False)
    315                          self._BTN_remove.Enable(False)
    316                          self._BTN_edit.Enable(False)
    317                          self._BTN_up.Enable(False)
    318                          self._BTN_down.Enable(False)
    319                  else:
    320                          self._BTN_activate.Enable(True)
    321                          self._BTN_activateplus.Enable(True)
    322                          self._BTN_remove.Enable(True)
    323                          self._BTN_edit.Enable(True)
    324                  if len(pats) > 1:
    325                          self._BTN_up.Enable(True)
    326                          self._BTN_down.Enable(True)
    327          #--------------------------------------------------------
    328          # event handlers
    329          #--------------------------------------------------------
    330 -        def _on_zone_selected(self, zone=None):
    331                  self.__id_most_recently_activated_patient = None
    332                  if self.__current_zone == self._PRW_zone.GetValue().strip():
    333                          return True
    334                  wx.CallAfter(self.__refresh_waiting_list)
    335                  return True
    336          #--------------------------------------------------------
    337 -        def _on_waiting_list_modified(self, *args, **kwargs):
    338                  self.__id_most_recently_activated_patient = None
    339                  self._schedule_data_reget()
    340          #--------------------------------------------------------
    341 -        def _on_post_patient_selection(self, *args, **kwargs):
    342                  self._CHBOX_active_patient_only.Enable()
    343                  self._check_RFE()
    344                  self._schedule_data_reget()
    345          #--------------------------------------------------------
    346 -        def _on_list_item_activated(self, evt):
    347                  self.__id_most_recently_activated_patient = None
    348                  item = self._LCTRL_patients.get_selected_item_data(only_one=True)
    349                  if item is None:
    350                          return
    351                  try:
    352                          pat = gmPerson.cPerson(aPK_obj = item['pk_identity'])
    353                  except gmExceptions.ConstructorError:
    354                          gmGuiHelpers.gm_show_info (
    355                                  aTitle = _('Waiting list'),
    356                                  aMessage = _('Cannot activate patient.\n\nIt has probably been disabled.')
    357                          )
    358                          return
    359                  curr_pat = gmPerson.gmCurrentPatient()
    360                  if curr_pat.connected:
    361                          if curr_pat.ID == item['pk_identity']:
    362                                  edit_waiting_list_entry(parent = self, entry = item)
    363                                  return
    364                  wx.CallAfter(gmPatSearchWidgets.set_active_patient, patient = pat)
    365          #--------------------------------------------------------
    366 -        def _on_activate_button_pressed(self, evt):
    367                  self.__id_most_recently_activated_patient = None
    368                  item = self._LCTRL_patients.get_selected_item_data(only_one=True)
    369                  if item is None:
    370                          return
    371                  try:
    372                          pat = gmPerson.cPerson(aPK_obj = item['pk_identity'])
    373                  except gmExceptions.ConstructorError:
    374                          gmGuiHelpers.gm_show_info (
    375                                  aTitle = _('Waiting list'),
    376                                  aMessage = _('Cannot activate patient.\n\nIt has probably been disabled.')
    377                          )
    378                          return
    379                  curr_pat = gmPerson.gmCurrentPatient()
    380                  if curr_pat.connected:
    381                          if curr_pat.ID == item['pk_identity']:
    382                                  return
    383                  wx.CallAfter(gmPatSearchWidgets.set_active_patient, patient = pat)
    384          #--------------------------------------------------------
    385 -        def _on_activateplus_button_pressed(self, evt):
    386                  item = self._LCTRL_patients.get_selected_item_data(only_one=True)
    387                  if item is None:
    388                          return
    389                  try:
    390                          pat = gmPerson.cPerson(aPK_obj = item['pk_identity'])
    391                  except gmExceptions.ConstructorError:
    392                          gmGuiHelpers.gm_show_info (
    393                                  aTitle = _('Waiting list'),
    394                                  aMessage = _('Cannot activate patient.\n\nIt has probably been disabled.')
    395                          )
    396                          return
    397                  self.__id_most_recently_activated_patient = item['pk_identity']
    398                  self.__comment_most_recently_activated_patient = gmTools.coalesce(item['comment'], '').strip()
    399                  gmPraxis.gmCurrentPraxisBranch().remove_from_waiting_list(pk = item['pk_waiting_list'])
    400                  curr_pat = gmPerson.gmCurrentPatient()
    401                  if curr_pat.connected:
    402                          if curr_pat.ID == item['pk_identity']:
    403                                  return
    404                  wx.CallAfter(gmPatSearchWidgets.set_active_patient, patient = pat)
    405          #--------------------------------------------------------
    406 -        def _on_add_patient_button_pressed(self, evt):
    407                  self.__id_most_recently_activated_patient = None
    408                  curr_pat = gmPerson.gmCurrentPatient()
    409                  if not curr_pat.connected:
    410                          gmDispatcher.send(signal = 'statustext', msg = _('Cannot add waiting list entry: No patient selected.'), beep = True)
    411                          return
    412                  edit_waiting_list_entry(parent = self, patient = curr_pat)
    413          #--------------------------------------------------------
    414 -        def _on_edit_button_pressed(self, event):
    415                  self.__id_most_recently_activated_patient = None
    416                  item = self._LCTRL_patients.get_selected_item_data(only_one=True)
    417                  if item is None:
    418                          return
    419                  edit_waiting_list_entry(parent = self, entry = item)
    420          #--------------------------------------------------------
    421 -        def _on_remove_button_pressed(self, evt):
    422                  self.__id_most_recently_activated_patient = None
    423                  item = self._LCTRL_patients.get_selected_item_data(only_one = True)
    424                  if item is None:
    425                          return
    426                  cmt = gmTools.coalesce(item['comment'], '').split('\n')[0].strip()[:40]
    427                  if cmt != '':
    428                          cmt += '\n'
    429                  question = _(
    430                          'Are you sure you want to remove\n'
    431                          '\n'
    432                          ' %s, %s (%s)\n'
    433                          ' born: %s\n'
    434                          ' %s'
    435                          '\n'
    436                          'from the waiting list ?'
    437                  ) % (
    438                          item['lastnames'],
    439                          item['firstnames'],
    440                          item['l10n_gender'],
    441                          gmTools.coalesce (
    442                                  gmTools.coalesce (
    443                                          item['dob'],
    444                                          '',
    445                                          function4value = ('strftime', '%d %b %Y')
    446                                  ),
    447                                  '',
    448                                  function4value = ('decode', gmI18N.get_encoding())
    449                          ),
    450                          cmt
    451                  )
    452                  do_delete = gmGuiHelpers.gm_show_question (
    453                          title = _('Delete waiting list entry'),
    454                          question = question
    455                  )
    456                  if not do_delete:
    457                          return
    458                  gmPraxis.gmCurrentPraxisBranch().remove_from_waiting_list(pk = item['pk_waiting_list'])
    459          #--------------------------------------------------------
    460 -        def _on_up_button_pressed(self, evt):
    461                  self.__id_most_recently_activated_patient = None
    462                  item = self._LCTRL_patients.get_selected_item_data(only_one=True)
    463                  if item is None:
    464                          return
    465                  gmPraxis.gmCurrentPraxisBranch().raise_in_waiting_list(current_position = item['list_position'])
    466          #--------------------------------------------------------
    467 -        def _on_down_button_pressed(self, evt):
    468                  self.__id_most_recently_activated_patient = None
    469                  item = self._LCTRL_patients.get_selected_item_data(only_one=True)
    470                  if item is None:
    471                          return
    472                  gmPraxis.gmCurrentPraxisBranch().lower_in_waiting_list(current_position = item['list_position'])
    473          #--------------------------------------------------------
    474 -        def _on_active_patient_only_checked(self, evt):
    475                  self.__refresh_waiting_list()
    476          #--------------------------------------------------------
    477          # edit
    478          #--------------------------------------------------------
    479          # reget-on-paint API
    480          #--------------------------------------------------------
    481 -        def _populate_with_data(self):
    482                  self.__refresh_waiting_list()
    483                  return True
    484  #================================================================
    485  # main
    486  #----------------------------------------------------------------
    487  if __name__ == '__main__':
    488
    489          if len(sys.argv) < 2:
    490                  sys.exit()
    491
    492          if sys.argv[1] != 'test':
    493                  sys.exit()
    494
    495          gmI18N.activate_locale()
    496          gmI18N.install_domain()
    497
    498          #--------------------------------------------------------
    499  #       def test_generic_codes_prw():
    500  #               gmPG2.get_connection()
    501  #               app = wx.PyWidgetTester(size = (500, 40))
    502  #               pw = cGenericCodesPhraseWheel(app.frame, -1)
    503  #               #pw.set_context(context = u'zip', val = u'04318')
    504  #               app.frame.Show(True)
    505  #               app.MainLoop()
    506  #       #--------------------------------------------------------
    507  #       test_generic_codes_prw()
    508
    509          app = wx.PyWidgetTester(size = (200, 40))
    510          app.SetWidget(cWaitingListPnl, -1)
    511          app.MainLoop()
    512
    513  #================================================================
    514