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

# Source Code for Module Gnumed.wxpython.gmAutoHintWidgets

      1  """GNUmed auto/dynamic hints widgets.
      2  """
      3  #================================================================
      4  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
      5  __license__ = "GPL v2 or later"
      6
      7  import sys
      8  import logging
      9
     10
     11  import wx
     12
     13
     14  if __name__ == '__main__':
     15          sys.path.insert(0, '../../')
     16  from Gnumed.pycommon import gmTools
     17  from Gnumed.pycommon import gmDispatcher
     18  from Gnumed.pycommon import gmDateTime
     19  from Gnumed.pycommon import gmNetworkTools
     20
     21  from Gnumed.business import gmPerson
     22  from Gnumed.business import gmAutoHints
     23
     24  from Gnumed.wxpython import gmListWidgets
     25  from Gnumed.wxpython import gmAuthWidgets
     26  from Gnumed.wxpython import gmDataPackWidgets
     27  from Gnumed.wxpython import gmGuiHelpers
     28  from Gnumed.wxpython import gmEditArea
     29
     30
     31  _log = logging.getLogger('gm.auto_hints')
     32
     33  #================================================================
     34 -def _display_clinical_reminders():
     35
     36          pat = gmPerson.gmCurrentPatient()
     37          if not pat.connected:
     38                  return
     39
     40          # reminders
     41          for msg in pat.overdue_messages:
     42                  if msg['expiry_date'] is None:
     43                          exp = ''
     44                  else:
     45                          exp = _(' - expires %s') % gmDateTime.pydt_strftime (
     46                                  msg['expiry_date'],
     47                                  '%Y %b %d',
     48                                  accuracy = gmDateTime.acc_days
     49                          )
     50                  txt = _(
     51                          'Due for %s (since %s%s):\n'
     52                          '%s'
     53                          '%s'
     54                          '\n'
     55                          'Patient: %s\n'
     56                          'Reminder by: %s'
     57                  ) % (
     58                          gmDateTime.format_interval_medically(msg['interval_due']),
     59                          gmDateTime.pydt_strftime(msg['due_date'], '%Y %b %d', accuracy = gmDateTime.acc_days),
     60                          exp,
     61                          gmTools.coalesce(msg['comment'], '', '\n%s\n'),
     62                          gmTools.coalesce(msg['data'], '', '\n%s\n'),
     63                          pat['description_gender'],
     64                          msg['modified_by']
     65                  )
     66                  gmGuiHelpers.gm_show_warning (
     67                          aTitle = _('Clinical reminder'),
     68                          aMessage = txt
     69                  )
     70
     71          # dynamic hints
     72          hints2aggregate = []
     73          emr = pat.emr
     74          hint_dlg = cDynamicHintDlg(wx.GetApp().GetTopWindow(), -1)
     75          # single-hint popups
     76          for hint in emr.dynamic_hints:
     77                  if hint['popup_type'] == 0:
     78                          continue
     79                  if hint['popup_type'] == 2:
     80                          hints2aggregate.append(hint)
     81                          continue
     82                  hint_dlg.hint = hint
     83                  if hint_dlg.ShowModal() == wx.ID_APPLY:
     84                          hint.suppress (
     85                                  rationale = hint_dlg.rationale.strip(),
     86                                  pk_encounter = emr.current_encounter['pk_encounter']
     87                          )
     88          hint_dlg.DestroyLater()
     89          # aggregate popup
     90          if len(hints2aggregate) > 0:
     91                  hints_dlg = cDynamicHintListDlg(wx.GetApp().GetTopWindow(), -1)
     92                  hints_dlg.pk_encounter = emr.current_encounter['pk_encounter']
     93                  hints_dlg.hints = hints2aggregate
     94                  hints_dlg.ShowModal()
     95                  hints_dlg.DestroyLater()
     96
     97          return
     98
     99  gmDispatcher.connect(signal = 'post_patient_selection', receiver = _display_clinical_reminders)
    100
    101  #================================================================
    102 -def edit_dynamic_hint(parent=None, hint=None, single_entry=True):
    103
    104          if parent is None:
    105                  parent = wx.GetApp().GetTopWindow()
    106
    107          ea = cAutoHintEAPnl(parent, -1)
    108          ea.data = hint
    109          ea.mode = gmTools.coalesce(hint, 'new', 'edit')
    110          dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry)
    111          dlg.SetTitle(gmTools.coalesce(hint, _('Adding automatic dynamic hint'), _('Editing automatic dynamic hint')))
    112          if dlg.ShowModal() == wx.ID_OK:
    113                  dlg.DestroyLater()
    114                  return True
    115          dlg.DestroyLater()
    116          return False
    117
    118  #================================================================
    119 -def manage_dynamic_hints(parent=None):
    120
    121          if parent is None:
    122                  parent = wx.GetApp().GetTopWindow()
    123          #------------------------------------------------------------
    124          def get_tooltip(item):
    125                  if item is None:
    126                          return None
    127                  return item.format()
    128          #------------------------------------------------------------
    129          def manage_data_packs(item):
    130                  gmDataPackWidgets.manage_data_packs(parent = parent)
    131                  return True
    132          #------------------------------------------------------------
    133          def edit_hint(hint=None):
    134                  return edit_dynamic_hint(parent = parent, hint = hint, single_entry = (hint is not None))
    135          #------------------------------------------------------------
    136          def del_hint(hint=None):
    137                  if hint is None:
    138                          return False
    139                  really_delete = gmGuiHelpers.gm_show_question (
    140                          title = _('Deleting automatic dynamic hint'),
    141                          question = _('Really delete this dynamic hint ?\n\n [%s]') % hint['title']
    142                  )
    143                  if not really_delete:
    144                          return False
    145
    146                  conn = gmAuthWidgets.get_dbowner_connection(procedure = _('deleting a dynamic hint'))
    147                  if conn is None:
    148                          return False
    149                  gmAutoHints.delete_dynamic_hint(link_obj = conn, pk_hint = hint['pk_auto_hint'])
    150                  conn.commit()
    151                  conn.close()
    152                  return True
    153          #------------------------------------------------------------
    154          def refresh(lctrl):
    155                  hints = gmAutoHints.get_dynamic_hints(order_by = 'is_active DESC, source, hint')
    156                  items = [ [
    157                          gmTools.bool2subst(h['is_active'], gmTools.u_checkmark_thin, ''),
    158                          h['title'],
    159                          h['source'][:30],
    160                          h['hint'][:60],
    161                          gmTools.coalesce(h['url'], '')[:60],
    162                          h['lang'],
    163                          h['pk_auto_hint']
    164                  ] for h in hints ]
    165                  lctrl.set_string_items(items)
    166                  lctrl.set_data(hints)
    167
    168          #------------------------------------------------------------
    169          gmListWidgets.get_choices_from_list (
    170                  parent = parent,
    171                  msg = _('\nDynamic hints registered with GNUmed.\n'),
    172                  caption = _('Showing dynamic hints.'),
    173                  columns = [ _('Active'), _('Title'), _('Source'), _('Hint'), 'URL', _('Language'), '#' ],
    174                  single_selection = True,
    175                  refresh_callback = refresh,
    176                  edit_callback = edit_hint,
    177                  new_callback = edit_hint,
    178                  delete_callback = del_hint,
    179  #               left_extra_button = (
    180  #                       _('(De)-Activate'),
    181  #                       _('Toggle activation of the selected hint'),
    182  #                       toggle_activation
    183  #               ),
    184                  # button to show DB schema
    185                  right_extra_button = (
    186                          _('Data packs'),
    187                          _('Browse and install automatic dynamic hints data packs'),
    188                          manage_data_packs
    189                  ),
    190                  list_tooltip_callback = get_tooltip
    191          )
    192
    193  #================================================================
    194  from Gnumed.wxGladeWidgets import wxgDynamicHintDlg
    195
    196 -class cDynamicHintDlg(wxgDynamicHintDlg.wxgDynamicHintDlg):
    197
    198 -        def __init__(self, *args, **kwargs):
    199
    200                  try:
    201                          self.__hint = kwargs['hint']
    202                          del kwargs['hint']
    203                  except KeyError:
    204                          self.__hint = None
    205                  wxgDynamicHintDlg.wxgDynamicHintDlg.__init__(self, *args, **kwargs)
    206                  self.__init_ui()
    207          #------------------------------------------------------------
    208 -        def _get_hint(self):
    209                  return self.__hint
    210
    211 -        def _set_hint(self, hint):
    212                  self.__hint = hint
    213                  self.__refresh()
    214
    215          hint = property(_get_hint, _set_hint)
    216          #------------------------------------------------------------
    217 -        def _get_rationale(self):
    218                  return self._TCTRL_rationale.GetValue().strip()
    219
    220          rationale = property(_get_rationale, lambda x:x)
    221
    222          #------------------------------------------------------------
    223          # internal helpers
    224          #------------------------------------------------------------
    225 -        def __init_ui(self):
    226                  self._TCTRL_rationale.add_callback_on_modified(callback = self._on_rationale_modified)
    227
    228          #------------------------------------------------------------
    229 -        def __refresh(self):
    230                  if self.__hint is None:
    231                          self._TCTRL_title.SetValue('')
    232                          self._TCTRL_hint.SetValue('')
    233                          self._URL_info.SetURL('')
    234                          self._URL_info.Disable()
    235                          self._TCTRL_source.SetValue('')
    236                          self._LBL_previous_rationale.Hide()
    237                          self._TCTRL_previous_rationale.Hide()
    238                  else:
    239                          self._TCTRL_title.SetValue(self.__hint['title'])
    240                          self._TCTRL_hint.SetValue('%s%s' % (
    241                                  self.__hint['hint'],
    242                                  gmTools.coalesce(self.__hint['recommendation'], '', '\n\n%s')
    243                          ))
    244                          if self.__hint['url'] is None:
    245                                  self._URL_info.SetURL('')
    246                                  self._URL_info.Disable()
    247                          else:
    248                                  self._URL_info.SetURL(self.__hint['url'])
    249                                  self._URL_info.Enable()
    250                          self._TCTRL_source.SetValue(_('By: %s') % self.__hint['source'])
    251                          if self.__hint['rationale4suppression'] is None:
    252                                  self._LBL_previous_rationale.Hide()
    253                                  self._TCTRL_previous_rationale.Hide()
    254                                  self._BTN_transfer_previous_rationale.Hide()
    255                                  self._BTN_transfer_previous_rationale.Disable()
    256                          else:
    257                                  self._LBL_previous_rationale.Show()
    258                                  self._TCTRL_previous_rationale.Show()
    259                                  self._TCTRL_previous_rationale.SetValue(self.__hint['rationale4suppression'])
    260                                  self._BTN_transfer_previous_rationale.Show()
    261                                  self._BTN_transfer_previous_rationale.Enable()
    262
    263                  self._TCTRL_rationale.SetValue('')
    264                  self._BTN_suppress.Disable()
    265                  self._TCTRL_rationale.SetFocus()
    266
    267          #------------------------------------------------------------
    268          # event handlers
    269          #------------------------------------------------------------
    270 -        def _on_rationale_modified(self):
    271                  if self._TCTRL_rationale.GetValue().strip() == '':
    272                          self._BTN_suppress.Disable()
    273                          self._BTN_OK.SetDefault()
    274                  else:
    275                          self._BTN_suppress.Enable()
    276                          self._BTN_suppress.SetDefault()
    277
    278          #------------------------------------------------------------
    279 -        def _on_suppress_button_pressed(self, event):
    280                  event.Skip()
    281                  if self.__hint is None:
    282                          return
    283                  val = self._TCTRL_rationale.GetValue().strip()
    284                  if val == '':
    285                          return
    286                  if self.IsModal():
    287                          self.EndModal(wx.ID_APPLY)
    288                  else:
    289                          self.Close()
    290
    291          #------------------------------------------------------------
    292 -        def _on_manage_hints_button_pressed(self, event):
    293                  event.Skip()
    294                  manage_dynamic_hints(parent = self)
    295
    296          #------------------------------------------------------------
    297 -        def _on_transfer_previous_rationale_button_pressed(self, event):
    298                  event.Skip()
    299                  prev = self._TCTRL_previous_rationale.Value.strip()
    300                  if prev == u'':
    301                          return
    302                  self._TCTRL_rationale.Value = prev
    303
    304  #================================================================
    305  from Gnumed.wxGladeWidgets import wxgDynamicHintListDlg
    306
    307 -class cDynamicHintListDlg(wxgDynamicHintListDlg.wxgDynamicHintListDlg):
    308
    309 -        def __init__(self, *args, **kwargs):
    310
    311                  try:
    312                          self.__hints = kwargs['hints']
    313                          del kwargs['hints']
    314                  except KeyError:
    315                          self.__hints = None
    316                  wxgDynamicHintListDlg.wxgDynamicHintListDlg.__init__(self, *args, **kwargs)
    317                  self.__pk_encounter = None
    318                  self.__init_ui()
    319
    320          #------------------------------------------------------------
    321 -        def _get_hints(self):
    322                  return self.__hints
    323
    324 -        def _set_hints(self, hints):
    325                  if len(hints) == 0:
    326                          hints = None
    327                  self.__hints = hints
    328                  self.__refresh()
    329
    330          hints = property(_get_hints, _set_hints)
    331
    332          #------------------------------------------------------------
    333 -        def _set_pk_encounter(self, pk_encounter):
    334                  self.__pk_encounter = pk_encounter
    335
    336          pk_encounter = property(lambda x:x, _set_pk_encounter)
    337
    338          #------------------------------------------------------------
    339          # internal helpers
    340          #------------------------------------------------------------
    341 -        def __init_ui(self):
    342                  self._LCTRL_hints.set_columns([_('Hint'), _('Source')])
    343                  self._LCTRL_hints.set_column_widths([wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE])
    344                  self._LCTRL_hints.set_resize_column(column = 0)
    345                  self._LCTRL_hints.select_callback = self._on_hint_selected
    346                  self._LCTRL_hints.deselect_callback = self._on_hint_deselected
    347                  self._TCTRL_rationale.add_callback_on_modified(callback = self._on_rationale_modified)
    348
    349          #------------------------------------------------------------
    350 -        def __refresh(self):
    351                  if self.__hints is None:
    352                          self._LCTRL_hints.set_string_items()
    353                          self._TCTRL_hint.SetValue('')
    354                          self._URL_info.SetURL('')
    355                          self._URL_info.Disable()
    356                          self._TCTRL_source.SetValue('')
    357                          self._TCTRL_rationale.SetValue('')
    358                          self._BTN_suppress.Disable()
    359                          self._LBL_previous_rationale.Hide()
    360                          self._TCTRL_previous_rationale.Hide()
    361                          self._LCTRL_hints.SetFocus()
    362                          return
    363
    364                  priority_hints = []
    365                  non_priority_hints = []
    366                  for hint in self.__hints:
    367                          if hint['highlight_as_priority']:
    368                                  priority_hints.append(hint)
    369                          else:
    370                                  non_priority_hints.append(hint)
    371
    372                  ordered_hints = []
    373                  ordered_hints.extend(priority_hints)
    374                  ordered_hints.extend(non_priority_hints)
    375
    376                  self._LCTRL_hints.set_string_items([ [h['title'], h['source']] for h in ordered_hints ])
    377                  self._LCTRL_hints.set_data(ordered_hints)
    378                  for idx in range(len(priority_hints)):
    379                          self._LCTRL_hints.SetItemTextColour(idx, wx.Colour('YELLOW'))
    380                  self._LCTRL_hints.Select(0)
    381
    382          #------------------------------------------------------------
    383 -        def _on_hint_selected(self, evt):
    384                  hint = self._LCTRL_hints.get_selected_item_data(only_one = True)
    385
    386                  self._TCTRL_hint.SetValue('%s%s' % (
    387                          hint['hint'],
    388                          gmTools.coalesce(hint['recommendation'], '', '\n\n%s')
    389                  ))
    390                  if hint['url'] is None:
    391                          self._URL_info.SetURL('')
    392                          self._URL_info.Disable()
    393                  else:
    394                          self._URL_info.SetURL(hint['url'])
    395                          self._URL_info.Enable()
    396                  self._TCTRL_source.SetValue(_('By: %s') % hint['source'])
    397                  self._TCTRL_rationale.SetValue('')
    398                  self._BTN_suppress.Disable()
    399
    400                  if hint['rationale4suppression'] is None:
    401                          self._LBL_previous_rationale.Hide()
    402                          self._TCTRL_previous_rationale.Hide()
    403                          self._TCTRL_previous_rationale.SetValue('')
    404                  else:
    405                          self._LBL_previous_rationale.Show()
    406                          self._TCTRL_previous_rationale.SetValue(hint['rationale4suppression'])
    407                          self._TCTRL_previous_rationale.Show()
    408
    409                  self._TCTRL_rationale.SetFocus()
    410
    411          #------------------------------------------------------------
    412 -        def _on_hint_deselected(self, evt):
    413                  self._TCTRL_hint.SetValue('')
    414                  self._URL_info.SetURL('')
    415                  self._URL_info.Disable()
    416                  self._TCTRL_source.SetValue('')
    417                  self._TCTRL_rationale.SetValue('')
    418                  self._LBL_previous_rationale.Hide()
    419                  self._TCTRL_previous_rationale.Hide()
    420                  self._TCTRL_previous_rationale.SetValue('')
    421                  self._BTN_suppress.Disable()
    422
    423          #------------------------------------------------------------
    424          # event handlers
    425          #------------------------------------------------------------
    426 -        def _on_rationale_modified(self):
    427                  if self._TCTRL_rationale.GetValue().strip() == '':
    428                          self._BTN_suppress.Disable()
    429                  else:
    430                          self._BTN_suppress.Enable()
    431
    432          #------------------------------------------------------------
    433 -        def _on_suppress_button_pressed(self, event):
    434                  event.Skip()
    435                  val = self._TCTRL_rationale.GetValue().strip()
    436                  if val == '':
    437                          return
    438                  hint = self._LCTRL_hints.get_selected_item_data(only_one = True)
    439                  suppressed = hint.suppress (
    440                          rationale = val,
    441                          pk_encounter = self.__pk_encounter
    442                  )
    443                  if not suppressed:
    444                          self.StatusText = _('Cannot suppress hint.')
    445                          return False
    446                  if len(self.__hints) == 1:
    447                          # singular hint now suppressed -> close
    448                          if self.IsModal():
    449                                  self.EndModal(wx.ID_APPLY)
    450                          else:
    451                                  self.Close()
    452                  self.StatusText = _('Hint now suppressed in this patient.')
    453                  pk_of_suppressed_hint = hint['pk_auto_hint']
    454                  remaining_hints = [ h for h in self.__hints if h['pk_auto_hint'] != pk_of_suppressed_hint ]
    455                  self.hints = remaining_hints
    456
    457          #------------------------------------------------------------
    458 -        def _on_manage_hints_button_pressed(self, event):
    459                  event.Skip()
    460                  manage_dynamic_hints(parent = self)
    461
    462  #================================================================
    463  from Gnumed.wxGladeWidgets import wxgAutoHintEAPnl
    464
    465 -class cAutoHintEAPnl(wxgAutoHintEAPnl.wxgAutoHintEAPnl, gmEditArea.cGenericEditAreaMixin):
    466
    467 -        def __init__(self, *args, **kwargs):
    468
    469                  try:
    470                          data = kwargs['hint']
    471                          del kwargs['hint']
    472                  except KeyError:
    473                          data = None
    474
    475                  wxgAutoHintEAPnl.wxgAutoHintEAPnl.__init__(self, *args, **kwargs)
    476                  gmEditArea.cGenericEditAreaMixin.__init__(self)
    477
    478                  # Code using this mixin should set mode and data
    479                  # after instantiating the class:
    480                  self.mode = 'new'
    481                  self.data = data
    482                  if data is not None:
    483                          self.mode = 'edit'
    484
    485                  #self.__init_ui()
    486          #----------------------------------------------------------------
    487  #       def __init_ui(self):
    488  #               # adjust phrasewheels etc
    489          #----------------------------------------------------------------
    490          # generic Edit Area mixin API
    491          #----------------------------------------------------------------
    492 -        def _valid_for_save(self):
    493
    494                  validity = True
    495
    496                  if self._TCTRL_source.GetValue().strip() == '':
    497                          validity = False
    498                          self.display_tctrl_as_valid(tctrl = self._TCTRL_source, valid = False)
    499                          self.StatusText = _('No entry in field <Source>.')
    500                          self._TCTRL_source.SetFocus()
    501                  else:
    502                          self.display_tctrl_as_valid(tctrl = self._TCTRL_source, valid = True)
    503
    504                  if self._TCTRL_query.GetValue().strip() == '':
    505                          validity = False
    506                          self.display_tctrl_as_valid(tctrl = self._TCTRL_query, valid = False)
    507                          self.StatusText = _('No entry in field <Conditions>.')
    508                          self._TCTRL_query.SetFocus()
    509                  else:
    510                          # FIXME: run SQL
    511                          self.display_tctrl_as_valid(tctrl = self._TCTRL_query, valid = True)
    512
    513                  if self._TCTRL_hint.GetValue().strip() == '':
    514                          validity = False
    515                          self.display_tctrl_as_valid(tctrl = self._TCTRL_hint, valid = False)
    516                          self.StatusText = _('No entry in field <Description>.')
    517                          self._TCTRL_hint.SetFocus()
    518                  else:
    519                          self.display_tctrl_as_valid(tctrl = self._TCTRL_hint, valid = True)
    520
    521                  if self._TCTRL_title.GetValue().strip() == '':
    522                          validity = False
    523                          self.display_tctrl_as_valid(tctrl = self._TCTRL_title, valid = False)
    524                          self.StatusText = _('No entry in field <Title>.')
    525                          self._TCTRL_title.SetFocus()
    526                  else:
    527                          self.display_tctrl_as_valid(tctrl = self._TCTRL_title, valid = True)
    528
    529                  return validity
    530
    531          #----------------------------------------------------------------
    532 -        def _save_as_new(self):
    533                  conn = gmAuthWidgets.get_dbowner_connection(procedure = _('creating a new dynamic hint'))
    534                  if conn is None:
    535                          return False
    536
    537                  curs = conn.cursor()
    538                  data = gmAutoHints.create_dynamic_hint (
    539                          link_obj = curs,                # it seems this MUST be a cursor or else the successfully created row will not show up -- but why ?!?
    540                          query = self._TCTRL_query.GetValue().strip(),
    541                          title = self._TCTRL_title.GetValue().strip(),
    542                          hint = self._TCTRL_hint.GetValue().strip(),
    543                          source = self._TCTRL_source.GetValue().strip()
    544                  )
    545                  curs.close()
    546                  data['url'] = self._TCTRL_url.GetValue().strip()
    547                  data['recommendation_query'] = self._TCTRL_recommendation_query.GetValue().strip()
    548                  data['is_active'] = self._CHBOX_is_active.GetValue()
    549                  data['highlight_as_priority'] = self._CHBOX_highlight.GetValue()
    550                  if self._RBTN_popup_none.GetValue() is True:
    551                          data['popup_type'] = 0
    552                  elif self._RBTN_popup_single.GetValue() is True:
    553                          data['popup_type'] = 1
    554                  elif self._RBTN_popup_multiple.GetValue() is True:
    555                          data['popup_type'] = 2
    556                  else:
    557                          raise ValueError('no popup type radio button selected - should be impossible')
    558                  data.save(conn = conn)
    559                  conn.commit()
    560                  conn.close()
    561
    562                  self.data = data
    563
    564                  return True
    565
    566          #----------------------------------------------------------------
    567 -        def _save_as_update(self):
    568                  conn = gmAuthWidgets.get_dbowner_connection(procedure = _('updating an existing dynamic hint'))
    569                  if conn is None:
    570                          return False
    571
    572                  self.data['title'] = self._TCTRL_title.GetValue().strip()
    573                  self.data['hint'] = self._TCTRL_hint.GetValue().strip()
    574                  self.data['query'] = self._TCTRL_query.GetValue().strip()
    575                  self.data['source'] = self._TCTRL_source.GetValue().strip()
    576                  self.data['url'] = self._TCTRL_url.GetValue().strip()
    577                  self.data['recommendation_query'] = self._TCTRL_recommendation_query.GetValue().strip()
    578                  self.data['is_active'] = self._CHBOX_is_active.GetValue()
    579                  self.data['highlight_as_priority'] = self._CHBOX_highlight.GetValue()
    580                  if self._RBTN_popup_none.GetValue() is True:
    581                          self.data['popup_type'] = 0
    582                  elif self._RBTN_popup_single.GetValue() is True:
    583                          self.data['popup_type'] = 1
    584                  elif self._RBTN_popup_multiple.GetValue() is True:
    585                          self.data['popup_type'] = 2
    586                  else:
    587                          raise ValueError('no popup type radio button selected - should be impossible')
    588                  self.data.save(conn = conn)
    589                  conn.commit()
    590                  conn.close()
    591
    592                  return True
    593
    594          #----------------------------------------------------------------
    595 -        def _refresh_as_new(self):
    596                  self._TCTRL_title.SetValue('')
    597                  self._TCTRL_hint.SetValue('')
    598                  self._TCTRL_query.SetValue('')
    599                  self._TCTRL_recommendation_query.SetValue('')
    600                  self._TCTRL_source.SetValue('')
    601                  self._TCTRL_url.SetValue('')
    602                  self._CHBOX_is_active.SetValue(True)
    603                  self._CHBOX_highlight.SetValue(True)
    604                  self._RBTN_popup_single.SetValue(True)
    605
    606                  self._TCTRL_title.SetFocus()
    607
    608          #----------------------------------------------------------------
    609 -        def _refresh_as_new_from_existing(self):
    610                  self._refresh_as_new()
    611                  self._TCTRL_source.SetValue(self.data['source'])
    612
    613                  self._TCTRL_title.SetFocus()
    614
    615          #----------------------------------------------------------------
    616 -        def _refresh_from_existing(self):
    617                  self._TCTRL_title.SetValue(self.data['title'])
    618                  self._TCTRL_hint.SetValue(self.data['hint'])
    619                  self._TCTRL_query.SetValue(self.data['query'])
    620                  self._TCTRL_recommendation_query.SetValue(gmTools.coalesce(self.data['recommendation_query'], ''))
    621                  self._TCTRL_source.SetValue(self.data['source'])
    622                  self._TCTRL_url.SetValue(gmTools.coalesce(self.data['url'], ''))
    623                  self._CHBOX_is_active.SetValue(self.data['is_active'])
    624                  self._CHBOX_highlight.SetValue(self.data['highlight_as_priority'])
    625                  if self.data['popup_type'] == 0:
    626                          self._RBTN_popup_none.SetValue(True)
    627                  elif self.data['popup_type'] == 1:
    628                          self._RBTN_popup_single.SetValue(True)
    629                  elif self.data['popup_type'] == 2:
    630                          self._RBTN_popup_multiple.SetValue(True)
    631                  else:
    632                          raise ValueError('invalid popup type value [%s] - should be impossible' % self.data['popup_type'])
    633
    634                  self._TCTRL_query.SetFocus()
    635
    636          #----------------------------------------------------------------
    637          # event handlers
    638          #----------------------------------------------------------------
    639 -        def _on_check_url_button_pressed(self, event):
    640                  url = self._TCTRL_url.GetValue().strip()
    641                  if url == '':
    642                          return
    643                  if not gmNetworkTools.open_url_in_browser(url, new = 2, autoraise = True):
    644                          self.display_tctrl_as_valid(tctrl = self._TCTRL_url, valid = False)
    645                  else:
    646                          self.display_tctrl_as_valid(tctrl = self._TCTRL_url, valid = True)
    647
    648  #================================================================
    649 -def manage_suppressed_hints(parent=None, pk_identity=None):
    650
    651          if parent is None:
    652                  parent = wx.GetApp().GetTopWindow()
    653          #------------------------------------------------------------
    654          def get_tooltip(item):
    655                  if item is None:
    656                          return None
    657                  return item.format()
    658          #------------------------------------------------------------
    659          def manage_hints(item):
    660                  manage_dynamic_hints(parent = parent)
    661                  return True
    662          #------------------------------------------------------------
    663          def del_hint(hint=None):
    664                  if hint is None:
    665                          return False
    666                  really_delete = gmGuiHelpers.gm_show_question (
    667                          title = _('Deleting suppressed dynamic hint'),
    668                          question = _('Really delete the suppression of this dynamic hint ?\n\n [%s]') % hint['title']
    669                  )
    670                  if not really_delete:
    671                          return False
    672                  gmAutoHints.delete_suppressed_hint(pk_suppressed_hint = hint['pk_suppressed_hint'])
    673                  return True
    674          #------------------------------------------------------------
    675          def refresh(lctrl):
    676                  hints = gmAutoHints.get_suppressed_hints(pk_identity = pk_identity, order_by = 'title')
    677                  items = [ [
    678                          h['title'],
    679                          gmDateTime.pydt_strftime(h['suppressed_when'], '%Y %b %d'),
    680                          h['suppressed_by'],
    681                          h['rationale'],
    682                          gmTools.bool2subst(h['is_active'], gmTools.u_checkmark_thin, ''),
    683                          h['source'][:30],
    684                          gmTools.coalesce(h['url'], '')[:60],
    685                          h['pk_hint']
    686                  ] for h in hints ]
    687                  lctrl.set_string_items(items)
    688                  lctrl.set_data(hints)
    689          #------------------------------------------------------------
    690          gmListWidgets.get_choices_from_list (
    691                  parent = parent,
    692                  msg = _('\nDynamic hints suppressed in this patient.\n'),
    693                  caption = _('Showing suppressed dynamic hints.'),
    694                  columns = [ _('Title'), _('When'), _('By'), _('Rationale'), _('Active'), _('Source'), 'URL', 'Hint #' ],
    695                  single_selection = True,
    696                  ignore_OK_button = True,
    697                  refresh_callback = refresh,
    698                  delete_callback = del_hint,
    699                  right_extra_button = (
    700                          _('Manage hints'),
    701                          _('Manage automatic dynamic hints'),
    702                          manage_hints
    703                  ),
    704                  list_tooltip_callback = get_tooltip
    705          )
    706
    707  #================================================================
    708  # main
    709  #================================================================
    710  if __name__ == '__main__':
    711
    712          if len(sys.argv) < 2:
    713                  sys.exit()
    714
    715          if sys.argv[1] != 'test':
    716                  sys.exit()
    717
    718          gmI18N.activate_locale()
    719          gmI18N.install_domain(domain = 'gnumed')
    720
    721  #       def test_message_inbox():
    722  #               app = wx.PyWidgetTester(size = (800, 600))
    723  #               app.SetWidget(cProviderInboxPnl, -1)
    724  #               app.MainLoop()
    725
    726  #       def test_msg_ea():
    727  #               app = wx.PyWidgetTester(size = (800, 600))
    728  #               app.SetWidget(cInboxMessageEAPnl, -1)
    729  #               app.MainLoop()
    730
    731          #test_message_inbox()
    732          #test_msg_ea()
    733