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 = parent, id = -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 = parent, id = -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.Destroy()
     65                  return True
     66          dlg.Destroy()
     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(u'')
    117                  self._PRW_zone.SetValue(u'')
    118                  self._SPCTRL_urgency.SetValue(0)
    119          #--------------------------------------------------------
    120 -        def _refresh_from_existing(self):
    121                  self._PRW_patient.person = gmPerson.cIdentity(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'], u''))
    126                  self._PRW_zone.SetValue(gmTools.coalesce(self.data['waiting_zone'], u''))
    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                          gmDispatcher.send(signal = 'statustext', msg = _('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(), u''),
    147                          zone = gmTools.none_if(self._PRW_zone.GetValue().strip(), u'')
    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'], u'').strip() != u'':
    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'], u'').strip() == u'':
    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 (
    225                                          entry['dob'],
    226                                          u'',
    227                                          function_initial = ('strftime', '%d %b %Y')
    228                                  ),
    229                                  u'',
    230                                  u' (%s)',
    231                                  function_initial = ('decode', gmI18N.get_encoding())
    232                  )
    233
    234                  tt = _(
    235                          '%s patients are waiting.\n'
    236                          '\n'
    237                          'Doubleclick to activate (entry will stay in list).'
    238                  ) % self._LCTRL_patients.GetItemCount()
    239
    240                  tt += _(
    241                          '\n'
    242                          '%s\n'
    243                          'Patient: %s%s\n'
    244                          '%s'
    245                          'Urgency: %s\n'
    246                          'Time: %s\n'
    247                          '%s'
    248                  ) % (
    249                          gmTools.u_box_horiz_single * 50,
    250                          u'%s, %s (%s)' % (entry['lastnames'], entry['firstnames'], entry['l10n_gender']),
    251                          dob,
    252                          gmTools.coalesce(entry['waiting_zone'], u'', _('Zone: %s\n')),
    253                          entry['urgency'],
    254                          gmDateTime.format_interval_medically(entry['waiting_time']),
    255                          gmTools.coalesce(entry['comment'], u'', u'\n%s')
    256                  )
    257
    258                  return tt
    259          #--------------------------------------------------------
    260 -        def __register_events(self):
    261                  gmDispatcher.connect(signal = u'clin.waiting_list_mod_db', receiver = self._on_waiting_list_modified)
    262                  gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
    263          #--------------------------------------------------------
    264 -        def __refresh_waiting_list(self):
    265                  self.__id_most_recently_activated_patient = None
    266                  col, ascending = self._LCTRL_patients.GetSortState()    # preserve sorting order
    267
    268                  praxis = gmPraxis.gmCurrentPraxisBranch()
    269                  pats = praxis.waiting_list_patients
    270
    271                  # set matcher to all zones currently in use
    272                  zones = {}
    273                  zones.update([ [p['waiting_zone'], None] for p in pats if p['waiting_zone'] is not None ])
    274                  self._PRW_zone.update_matcher(items = zones.keys())
    275
    276                  # filter patient list by zone and set waiting list
    277                  self.__current_zone = self._PRW_zone.GetValue().strip()
    278                  if self.__current_zone == u'':
    279                          pats = [ p for p in pats ]
    280                  else:
    281                          pats = [ p for p in pats if p['waiting_zone'] == self.__current_zone ]
    282
    283                  # filter by "active patient only"
    284                  curr_pat = gmPerson.gmCurrentPatient()
    285                  if curr_pat.connected:
    286                          if self._CHBOX_active_patient_only.IsChecked():
    287                                  pats = [ p for p in pats if p['pk_identity'] == curr_pat.ID ]
    288
    289                  old_pks = [ d['pk_waiting_list'] for d in self._LCTRL_patients.get_selected_item_data() ]
    290                  self._LCTRL_patients.set_string_items (
    291                          [ [
    292                                  gmTools.coalesce(p['waiting_zone'], u''),
    293                                  p['urgency'],
    294                                  gmDateTime.pydt_strftime(p['registered'], format='%Y %b %d %H:%M'),
    295                                  gmDateTime.format_interval_medically(p['waiting_time']),
    296                                  u'%s, %s (%s)' % (p['lastnames'], p['firstnames'], p['l10n_gender']),
    297                                  gmTools.coalesce (
    298                                          gmTools.coalesce (
    299                                                  p['dob'],
    300                                                  u'',
    301                                                  function_initial = ('strftime', '%d %b %Y')
    302                                          ),
    303                                          u'',
    304                                          function_initial = ('decode', gmI18N.get_encoding())
    305                                  ),
    306                                  gmTools.coalesce(p['comment'], u'').split('\n')[0]
    307                          ] for p in pats ]
    308                  )
    309                  self._LCTRL_patients.set_column_widths()
    310                  self._LCTRL_patients.set_data(pats)
    311                  new_selections = []
    312                  new_pks = [ p['pk_waiting_list'] for p in pats ]
    313                  for old_pk in old_pks:
    314                          if old_pk in new_pks:
    315                                  new_selections.append(new_pks.index(old_pk))
    316                  self._LCTRL_patients.selections = new_selections
    317                  self._LCTRL_patients.Refresh()
    318                  self._LCTRL_patients.SortListItems(col, ascending) # re-sort
    319
    320                  self._LBL_no_of_patients.SetLabel(_('(%s patients)') % len(pats))
    321
    322                  if len(pats) == 0:
    323                          self._BTN_activate.Enable(False)
    324                          self._BTN_activateplus.Enable(False)
    325                          self._BTN_remove.Enable(False)
    326                          self._BTN_edit.Enable(False)
    327                          self._BTN_up.Enable(False)
    328                          self._BTN_down.Enable(False)
    329                  else:
    330                          self._BTN_activate.Enable(True)
    331                          self._BTN_activateplus.Enable(True)
    332                          self._BTN_remove.Enable(True)
    333                          self._BTN_edit.Enable(True)
    334                  if len(pats) > 1:
    335                          self._BTN_up.Enable(True)
    336                          self._BTN_down.Enable(True)
    337          #--------------------------------------------------------
    338          # event handlers
    339          #--------------------------------------------------------
    340 -        def _on_zone_selected(self, zone=None):
    341                  self.__id_most_recently_activated_patient = None
    342                  if self.__current_zone == self._PRW_zone.GetValue().strip():
    343                          return True
    344                  wx.CallAfter(self.__refresh_waiting_list)
    345                  return True
    346          #--------------------------------------------------------
    347 -        def _on_waiting_list_modified(self, *args, **kwargs):
    348                  self.__id_most_recently_activated_patient = None
    349                  wx.CallAfter(self._schedule_data_reget)
    350          #--------------------------------------------------------
    351 -        def _on_post_patient_selection(self, *args, **kwargs):
    352                  wx.CallAfter(self.__on_post_patient_selection)
    353          #--------------------------------------------------------
    354 -        def __on_post_patient_selection(self):
    355                  self._CHBOX_active_patient_only.Enable()
    356                  self._check_RFE()
    357                  self._schedule_data_reget()
    358          #--------------------------------------------------------
    359 -        def _on_list_item_activated(self, evt):
    360                  self.__id_most_recently_activated_patient = None
    361                  item = self._LCTRL_patients.get_selected_item_data(only_one=True)
    362                  if item is None:
    363                          return
    364                  try:
    365                          pat = gmPerson.cIdentity(aPK_obj = item['pk_identity'])
    366                  except gmExceptions.ConstructorError:
    367                          gmGuiHelpers.gm_show_info (
    368                                  aTitle = _('Waiting list'),
    369                                  aMessage = _('Cannot activate patient.\n\nIt has probably been disabled.')
    370                          )
    371                          return
    372                  curr_pat = gmPerson.gmCurrentPatient()
    373                  if curr_pat.connected:
    374                          if curr_pat.ID == item['pk_identity']:
    375                                  edit_waiting_list_entry(parent = self, entry = item)
    376                                  return
    377                  wx.CallAfter(gmPatSearchWidgets.set_active_patient, patient = pat)
    378          #--------------------------------------------------------
    379 -        def _on_activate_button_pressed(self, evt):
    380                  self.__id_most_recently_activated_patient = None
    381                  item = self._LCTRL_patients.get_selected_item_data(only_one=True)
    382                  if item is None:
    383                          return
    384                  try:
    385                          pat = gmPerson.cIdentity(aPK_obj = item['pk_identity'])
    386                  except gmExceptions.ConstructorError:
    387                          gmGuiHelpers.gm_show_info (
    388                                  aTitle = _('Waiting list'),
    389                                  aMessage = _('Cannot activate patient.\n\nIt has probably been disabled.')
    390                          )
    391                          return
    392                  curr_pat = gmPerson.gmCurrentPatient()
    393                  if curr_pat.connected:
    394                          if curr_pat.ID == item['pk_identity']:
    395                                  return
    396                  wx.CallAfter(gmPatSearchWidgets.set_active_patient, patient = pat)
    397          #--------------------------------------------------------
    398 -        def _on_activateplus_button_pressed(self, evt):
    399                  item = self._LCTRL_patients.get_selected_item_data(only_one=True)
    400                  if item is None:
    401                          return
    402                  try:
    403                          pat = gmPerson.cIdentity(aPK_obj = item['pk_identity'])
    404                  except gmExceptions.ConstructorError:
    405                          gmGuiHelpers.gm_show_info (
    406                                  aTitle = _('Waiting list'),
    407                                  aMessage = _('Cannot activate patient.\n\nIt has probably been disabled.')
    408                          )
    409                          return
    410                  self.__id_most_recently_activated_patient = item['pk_identity']
    411                  self.__comment_most_recently_activated_patient = gmTools.coalesce(item['comment'], u'').strip()
    412                  gmPraxis.gmCurrentPraxisBranch().remove_from_waiting_list(pk = item['pk_waiting_list'])
    413                  curr_pat = gmPerson.gmCurrentPatient()
    414                  if curr_pat.connected:
    415                          if curr_pat.ID == item['pk_identity']:
    416                                  return
    417                  wx.CallAfter(gmPatSearchWidgets.set_active_patient, patient = pat)
    418          #--------------------------------------------------------
    419 -        def _on_add_patient_button_pressed(self, evt):
    420                  self.__id_most_recently_activated_patient = None
    421                  curr_pat = gmPerson.gmCurrentPatient()
    422                  if not curr_pat.connected:
    423                          gmDispatcher.send(signal = 'statustext', msg = _('Cannot add waiting list entry: No patient selected.'), beep = True)
    424                          return
    425                  edit_waiting_list_entry(parent = self, patient = curr_pat)
    426          #--------------------------------------------------------
    427 -        def _on_edit_button_pressed(self, event):
    428                  self.__id_most_recently_activated_patient = None
    429                  item = self._LCTRL_patients.get_selected_item_data(only_one=True)
    430                  if item is None:
    431                          return
    432                  edit_waiting_list_entry(parent = self, entry = item)
    433          #--------------------------------------------------------
    434 -        def _on_remove_button_pressed(self, evt):
    435                  self.__id_most_recently_activated_patient = None
    436                  item = self._LCTRL_patients.get_selected_item_data(only_one = True)
    437                  if item is None:
    438                          return
    439                  cmt = gmTools.coalesce(item['comment'], u'').split('\n')[0].strip()[:40]
    440                  if cmt != u'':
    441                          cmt += u'\n'
    442                  question = _(
    443                          'Are you sure you want to remove\n'
    444                          '\n'
    445                          ' %s, %s (%s)\n'
    446                          ' born: %s\n'
    447                          ' %s'
    448                          '\n'
    449                          'from the waiting list ?'
    450                  ) % (
    451                          item['lastnames'],
    452                          item['firstnames'],
    453                          item['l10n_gender'],
    454                          gmTools.coalesce (
    455                                  gmTools.coalesce (
    456                                          item['dob'],
    457                                          u'',
    458                                          function_initial = ('strftime', '%d %b %Y')
    459                                  ),
    460                                  u'',
    461                                  function_initial = ('decode', gmI18N.get_encoding())
    462                          ),
    463                          cmt
    464                  )
    465                  do_delete = gmGuiHelpers.gm_show_question (
    466                          title = _('Delete waiting list entry'),
    467                          question = question
    468                  )
    469                  if not do_delete:
    470                          return
    471                  gmPraxis.gmCurrentPraxisBranch().remove_from_waiting_list(pk = item['pk_waiting_list'])
    472          #--------------------------------------------------------
    473 -        def _on_up_button_pressed(self, evt):
    474                  self.__id_most_recently_activated_patient = None
    475                  item = self._LCTRL_patients.get_selected_item_data(only_one=True)
    476                  if item is None:
    477                          return
    478                  gmPraxis.gmCurrentPraxisBranch().raise_in_waiting_list(current_position = item['list_position'])
    479          #--------------------------------------------------------
    480 -        def _on_down_button_pressed(self, evt):
    481                  self.__id_most_recently_activated_patient = None
    482                  item = self._LCTRL_patients.get_selected_item_data(only_one=True)
    483                  if item is None:
    484                          return
    485                  gmPraxis.gmCurrentPraxisBranch().lower_in_waiting_list(current_position = item['list_position'])
    486          #--------------------------------------------------------
    487 -        def _on_active_patient_only_checked(self, evt):
    488                  self.__refresh_waiting_list()
    489          #--------------------------------------------------------
    490          # edit
    491          #--------------------------------------------------------
    492          # reget-on-paint API
    493          #--------------------------------------------------------
    494 -        def _populate_with_data(self):
    495                  self.__refresh_waiting_list()
    496                  return True
    497  #================================================================
    498  # main
    499  #----------------------------------------------------------------
    500  if __name__ == '__main__':
    501
    502          if len(sys.argv) < 2:
    503                  sys.exit()
    504
    505          if sys.argv[1] != 'test':
    506                  sys.exit()
    507
    508          gmI18N.activate_locale()
    509          gmI18N.install_domain()
    510
    511          #--------------------------------------------------------
    512  #       def test_generic_codes_prw():
    513  #               gmPG2.get_connection()
    514  #               app = wx.PyWidgetTester(size = (500, 40))
    515  #               pw = cGenericCodesPhraseWheel(app.frame, -1)
    516  #               #pw.set_context(context = u'zip', val = u'04318')
    517  #               app.frame.Show(True)
    518  #               app.MainLoop()
    519  #       #--------------------------------------------------------
    520  #       test_generic_codes_prw()
    521
    522          app = wx.PyWidgetTester(size = (200, 40))
    523          app.SetWidget(cWaitingListPnl, -1)
    524          app.MainLoop()
    525
    526  #================================================================
    527