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
     15  # GNUmed
     16  if __name__ == '__main__':
     17          sys.path.insert(0, '../../')
     18
     19  from Gnumed.pycommon import gmDispatcher
     20  from Gnumed.pycommon import gmTools
     21  from Gnumed.pycommon import gmMatchProvider
     22  from Gnumed.pycommon import gmI18N
     23  from Gnumed.pycommon import gmExceptions
     24  from Gnumed.pycommon import gmDateTime
     25
     26  from Gnumed.business import gmPraxis
     27  from Gnumed.business import gmPerson
     28
     29  from Gnumed.wxpython import gmEditArea
     30  from Gnumed.wxpython import gmPhraseWheel
     31  from Gnumed.wxpython import gmRegetMixin
     32  from Gnumed.wxpython import gmPatSearchWidgets
     33  from Gnumed.wxpython import gmGuiHelpers
     34
     35
     36  _log = logging.getLogger('gm.ui')
     37  #============================================================
     38  # waiting list widgets
     39  #============================================================
     40 -class cWaitingZonePhraseWheel(gmPhraseWheel.cPhraseWheel):
     41
     42 -        def __init__(self, *args, **kwargs):
     43
     44                  gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
     45
     46                  mp = gmMatchProvider.cMatchProvider_FixedList(aSeq = [])
     47                  mp.setThresholds(1, 2, 2)
     48                  self.matcher = mp
     49                  self.selection_only = False
     50
     51          #--------------------------------------------------------
     52 -        def update_matcher(self, items):
     53                  self.matcher.set_items([ {'data': i, 'list_label': i, 'field_label': i, 'weight': 1} for i in items ])
     54
     55  #============================================================
     56 -def edit_waiting_list_entry(parent=None, entry=None, patient=None):
     57          if parent is None:
     58                  parent = wx.GetApp().GetTopWindow()
     59          ea = cWaitingListEntryEditAreaPnl(parent = parent, id = -1, patient = gmTools.bool2subst((entry is None), patient, None))
     60          ea.data = entry
     61          ea.mode = gmTools.coalesce(entry, 'new', 'edit')
     62          dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = True)
     63          dlg.SetTitle(gmTools.coalesce(entry, _('Adding new waiting list entry'), _('Editing waiting list entry')))
     64          if dlg.ShowModal() == wx.ID_OK:
     65                  dlg.Destroy()
     66                  return True
     67          dlg.Destroy()
     68          return False
     69
     70  #============================================================
     71  from Gnumed.wxGladeWidgets import wxgWaitingListEntryEditAreaPnl
     72
     73 -class cWaitingListEntryEditAreaPnl(wxgWaitingListEntryEditAreaPnl.wxgWaitingListEntryEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
     74
     75 -        def __init__ (self, *args, **kwargs):
     76
     77                  try:
     78                          self.patient = kwargs['patient']
     79                          del kwargs['patient']
     80                  except KeyError:
     81                          self.patient = None
     82
     83                  try:
     84                          data = kwargs['entry']
     85                          del kwargs['entry']
     86                  except KeyError:
     87                          data = None
     88
     89                  wxgWaitingListEntryEditAreaPnl.wxgWaitingListEntryEditAreaPnl.__init__(self, *args, **kwargs)
     90                  gmEditArea.cGenericEditAreaMixin.__init__(self)
     91
     92                  if data is None:
     93                          self.mode = 'new'
     94                  else:
     95                          self.data = data
     96                          self.mode = 'edit'
     97
     98                  praxis = gmPraxis.gmCurrentPraxisBranch()
     99                  pats = praxis.waiting_list_patients
    100                  zones = {}
    101                  zones.update([ [p['waiting_zone'], None] for p in pats if p['waiting_zone'] is not None ])
    102                  self._PRW_zone.update_matcher(items = zones.keys())
    103          #--------------------------------------------------------
    104          # edit area mixin API
    105          #--------------------------------------------------------
    106 -        def _refresh_as_new(self):
    107                  if self.patient is None:
    108                          self._PRW_patient.person = None
    109                          self._PRW_patient.Enable(True)
    110                          self._PRW_patient.SetFocus()
    111                  else:
    112                          self._PRW_patient.person = self.patient
    113                          self._PRW_patient.Enable(False)
    114                          self._TCTRL_comment.SetFocus()
    115                  self._PRW_patient._display_name()
    116
    117                  self._TCTRL_comment.SetValue(u'')
    118                  self._PRW_zone.SetValue(u'')
    119                  self._SPCTRL_urgency.SetValue(0)
    120          #--------------------------------------------------------
    121 -        def _refresh_from_existing(self):
    122                  self._PRW_patient.person = gmPerson.cIdentity(aPK_obj = self.data['pk_identity'])
    123                  self._PRW_patient.Enable(False)
    124                  self._PRW_patient._display_name()
    125
    126                  self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
    127                  self._PRW_zone.SetValue(gmTools.coalesce(self.data['waiting_zone'], u''))
    128                  self._SPCTRL_urgency.SetValue(self.data['urgency'])
    129
    130                  self._TCTRL_comment.SetFocus()
    131          #--------------------------------------------------------
    132 -        def _valid_for_save(self):
    133                  validity = True
    134
    135                  self.display_tctrl_as_valid(tctrl = self._PRW_patient, valid = (self._PRW_patient.person is not None))
    136                  validity = (self._PRW_patient.person is not None)
    137
    138                  if validity is False:
    139                          gmDispatcher.send(signal = 'statustext', msg = _('Cannot add to waiting list. Missing essential input.'))
    140
    141                  return validity
    142          #----------------------------------------------------------------
    143 -        def _save_as_new(self):
    144                  # FIXME: filter out dupes ?
    145                  self._PRW_patient.person.put_on_waiting_list (
    146                          urgency = self._SPCTRL_urgency.GetValue(),
    147                          comment = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u''),
    148                          zone = gmTools.none_if(self._PRW_zone.GetValue().strip(), u'')
    149                  )
    150                  # dummy:
    151                  self.data = {'pk_identity': self._PRW_patient.person.ID, 'comment': None, 'waiting_zone': None, 'urgency': 0}
    152                  return True
    153          #----------------------------------------------------------------
    154 -        def _save_as_update(self):
    155                  gmPraxis.gmCurrentPraxisBranch().update_in_waiting_list (
    156                          pk = self.data['pk_waiting_list'],
    157                          urgency = self._SPCTRL_urgency.GetValue(),
    158                          comment = self._TCTRL_comment.GetValue().strip(),
    159                          zone = self._PRW_zone.GetValue().strip()
    160                  )
    161                  return True
    162  #============================================================
    163  from Gnumed.wxGladeWidgets import wxgWaitingListPnl
    164
    165 -class cWaitingListPnl(wxgWaitingListPnl.wxgWaitingListPnl, gmRegetMixin.cRegetOnPaintMixin):
    166
    167 -        def __init__ (self, *args, **kwargs):
    168
    169                  wxgWaitingListPnl.wxgWaitingListPnl.__init__(self, *args, **kwargs)
    170                  gmRegetMixin.cRegetOnPaintMixin.__init__(self)
    171
    172                  self.__current_zone = None
    173                  self.__id_most_recently_activated_patient = None
    174                  self.__comment_most_recently_activated_patient = None
    175
    176                  self.__init_ui()
    177                  self.__register_events()
    178          #--------------------------------------------------------
    179          # interal helpers
    180          #--------------------------------------------------------
    181 -        def __init_ui(self):
    182                  self._LCTRL_patients.set_columns ([
    183                          _('Zone'),
    184                          _('Urgency'),
    185                          #' ! ',
    186                          _('Waiting time'),
    187                          _('Patient'),
    188                          _('Born'),
    189                          _('Comment')
    190                  ])
    191                  self._LCTRL_patients.set_column_widths(widths = [wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE_USEHEADER, wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE])
    192                  self._LCTRL_patients.item_tooltip_callback = self._on_get_list_tooltip
    193                  self._PRW_zone.add_callback_on_selection(callback = self._on_zone_selected)
    194                  self._PRW_zone.add_callback_on_lose_focus(callback = self._on_zone_selected)
    195          #--------------------------------------------------------
    196 -        def _check_RFE(self):
    197                  """
    198                  This gets called when a patient has been activated, but
    199                  only when the waiting list is actually in use (that is,
    200                  the plugin is loaded)
    201                  """
    202                  pat = gmPerson.gmCurrentPatient()
    203                  enc = pat.emr.active_encounter
    204                  if gmTools.coalesce(enc['reason_for_encounter'], u'').strip() != u'':
    205                          return
    206                  entries = pat.waiting_list_entries
    207                  if len(entries) == 0:
    208                          if self.__id_most_recently_activated_patient is None:
    209                                  return
    210                          if self.__id_most_recently_activated_patient != pat.ID:
    211                                  return
    212                          rfe = self.__comment_most_recently_activated_patient
    213                  else:
    214                          entry = entries[0]
    215                          if gmTools.coalesce(entry['comment'], u'').strip() == u'':
    216                                  return
    217                          rfe = entry['comment'].strip()
    218                  enc['reason_for_encounter'] = rfe
    219                  enc.save()
    220                  self.__id_most_recently_activated_patient = None
    221          #--------------------------------------------------------
    222 -        def _on_get_list_tooltip(self, entry):
    223
    224                  dob = gmTools.coalesce (
    225                                  gmTools.coalesce (
    226                                          entry['dob'],
    227                                          u'',
    228                                          function_initial = ('strftime', '%d %b %Y')
    229                                  ),
    230                                  u'',
    231                                  u' (%s)',
    232                                  function_initial = ('decode', gmI18N.get_encoding())
    233                  )
    234
    235                  tt = _(
    236                          '%s patients are waiting.\n'
    237                          '\n'
    238                          'Doubleclick to activate (entry will stay in list).'
    239                  ) % self._LCTRL_patients.GetItemCount()
    240
    241                  tt += _(
    242                          '\n'
    243                          '%s\n'
    244                          'Patient: %s%s\n'
    245                          '%s'
    246                          'Urgency: %s\n'
    247                          'Time: %s\n'
    248                          '%s'
    249                  ) % (
    250                          gmTools.u_box_horiz_single * 50,
    251                          u'%s, %s (%s)' % (entry['lastnames'], entry['firstnames'], entry['l10n_gender']),
    252                          dob,
    253                          gmTools.coalesce(entry['waiting_zone'], u'', _('Zone: %s\n')),
    254                          entry['urgency'],
    255                          gmDateTime.format_interval_medically(entry['waiting_time']),
    256                          gmTools.coalesce(entry['comment'], u'', u'\n%s')
    257                  )
    258
    259                  return tt
    260          #--------------------------------------------------------
    261 -        def __register_events(self):
    262                  gmDispatcher.connect(signal = u'waiting_list_generic_mod_db', receiver = self._on_waiting_list_modified)
    263                  gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
    264          #--------------------------------------------------------
    265 -        def __refresh_waiting_list(self):
    266                  self.__id_most_recently_activated_patient = None
    267                  col, ascending = self._LCTRL_patients.GetSortState()    # preserve sorting order
    268
    269                  praxis = gmPraxis.gmCurrentPraxisBranch()
    270                  pats = praxis.waiting_list_patients
    271
    272                  # set matcher to all zones currently in use
    273                  zones = {}
    274                  zones.update([ [p['waiting_zone'], None] for p in pats if p['waiting_zone'] is not None ])
    275                  self._PRW_zone.update_matcher(items = zones.keys())
    276
    277                  # filter patient list by zone and set waiting list
    278                  self.__current_zone = self._PRW_zone.GetValue().strip()
    279                  if self.__current_zone == u'':
    280                          pats = [ p for p in pats ]
    281                  else:
    282                          pats = [ p for p in pats if p['waiting_zone'] == self.__current_zone ]
    283
    284                  # filter by "active patient only"
    285                  curr_pat = gmPerson.gmCurrentPatient()
    286                  if curr_pat.connected:
    287                          if self._CHBOX_active_patient_only.IsChecked():
    288                                  pats = [ p for p in pats if p['pk_identity'] == curr_pat.ID ]
    289
    290                  old_pks = [ d['pk_waiting_list'] for d in self._LCTRL_patients.get_selected_item_data() ]
    291                  self._LCTRL_patients.set_string_items (
    292                          [ [
    293                                  gmTools.coalesce(p['waiting_zone'], u''),
    294                                  p['urgency'],
    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