Package Gnumed :: Package CherryPy :: Module gmGuiHelpersWeb |
[frames] | no frames]

# Source Code for Module Gnumed.CherryPy.gmGuiHelpersWeb

      1  """GNUmed GUI helper classes and functions.
      2
      3  This module provides some convenient wxPython GUI
      4  helper thingies that are widely used throughout
      5  GNUmed.
      6  """
      7  # ========================================================================
      8  __version__ = "$Revision: 1.106 $"
      9  __author__  = "K. Hilbert <Karsten.Hilbert@gmx.net>"
     10  __license__ = "GPL v2 or later (details at http://www.gnu.org)"
     11
     12  import os
     13
     14
     15  import wx
     16
     17
     18  from Gnumed.business import gmSurgery
     19  from Gnumed.wxGladeWidgets import wxg3ButtonQuestionDlg, wxg2ButtonQuestionDlg, wxgGreetingEditorDlg
     20
     21  # ========================================================================
     22 -class c2ButtonQuestionDlg(wxg2ButtonQuestionDlg.wxg2ButtonQuestionDlg):
     23
     24 -        def __init__(self, *args, **kwargs):
     25
     26                  caption = kwargs['caption']
     27                  question = kwargs['question']
     28                  button_defs = kwargs['button_defs'][:2]
     29                  del kwargs['caption']
     30                  del kwargs['question']
     31                  del kwargs['button_defs']
     32
     33                  try:
     34                          show_checkbox = kwargs['show_checkbox']
     35                          del kwargs['show_checkbox']
     36                  except KeyError:
     37                          show_checkbox = False
     38
     39                  try:
     40                          checkbox_msg = kwargs['checkbox_msg']
     41                          del kwargs['checkbox_msg']
     42                  except KeyError:
     43                          checkbox_msg = None
     44
     45                  try:
     46                          checkbox_tooltip = kwargs['checkbox_tooltip']
     47                          del kwargs['checkbox_tooltip']
     48                  except KeyError:
     49                          checkbox_tooltip = None
     50
     51                  wxg2ButtonQuestionDlg.wxg2ButtonQuestionDlg.__init__(self, *args, **kwargs)
     52
     53                  self.SetTitle(title = caption)
     54                  self._LBL_question.SetLabel(label = question)
     55
     56                  if not show_checkbox:
     57                          self._CHBOX_dont_ask_again.Hide()
     58                  else:
     59                          if checkbox_msg is not None:
     60                                  self._CHBOX_dont_ask_again.SetLabel(checkbox_msg)
     61                          if checkbox_tooltip is not None:
     62                                  self._CHBOX_dont_ask_again.SetToolTipString(checkbox_tooltip)
     63
     64                  buttons = [self._BTN_1, self._BTN_2]
     65                  for idx in range(len(button_defs)):
     66                          buttons[idx].SetLabel(label = button_defs[idx]['label'])
     67                          buttons[idx].SetToolTipString(button_defs[idx]['tooltip'])
     68                          try:
     69                                  if button_defs[idx]['default'] is True:
     70                                          buttons[idx].SetDefault()
     71                                          buttons[idx].SetFocus()
     72                          except KeyError:
     73                                  pass
     74
     75                  self.Fit()
     76          #--------------------------------------------------------
     77 -        def checkbox_is_checked(self):
     78                  return self._CHBOX_dont_ask_again.IsChecked()
     79          #--------------------------------------------------------
     80          # event handlers
     81          #--------------------------------------------------------
     82 -        def _on_BTN_1_pressed(self, evt):
     83                  if self.IsModal():
     84                          self.EndModal(wx.ID_YES)
     85                  else:
     86                          self.Close()
     87          #--------------------------------------------------------
     88 -        def _on_BTN_2_pressed(self, evt):
     89                  if self.IsModal():
     90                          self.EndModal(wx.ID_NO)
     91                  else:
     92                          self.Close()
     93  # ========================================================================
     94 -class c3ButtonQuestionDlg(wxg3ButtonQuestionDlg.wxg3ButtonQuestionDlg):
     95
     96 -        def __init__(self, *args, **kwargs):
     97
     98                  caption = kwargs['caption']
     99                  question = kwargs['question']
    100                  button_defs = kwargs['button_defs'][:3]
    101
    102                  del kwargs['caption']
    103                  del kwargs['question']
    104                  del kwargs['button_defs']
    105
    106                  wxg3ButtonQuestionDlg.wxg3ButtonQuestionDlg.__init__(self, *args, **kwargs)
    107
    108                  self.SetTitle(title = caption)
    109                  self._LBL_question.SetLabel(label = question)
    110
    111                  buttons = [self._BTN_1, self._BTN_2, self._BTN_3]
    112                  for idx in range(len(button_defs)):
    113                          buttons[idx].SetLabel(label = button_defs[idx]['label'])
    114                          buttons[idx].SetToolTipString(button_defs[idx]['tooltip'])
    115                          try:
    116                                  if button_defs[idx]['default'] is True:
    117                                          buttons[idx].SetDefault()
    118                                          buttons[idx].SetFocus()
    119                          except KeyError:
    120                                  pass
    121
    122                  self.Fit()
    123          #--------------------------------------------------------
    124          # event handlers
    125          #--------------------------------------------------------
    126 -        def _on_BTN_1_pressed(self, evt):
    127                  if self.IsModal():
    128                          self.EndModal(wx.ID_YES)
    129                  else:
    130                          self.Close()
    131          #--------------------------------------------------------
    132 -        def _on_BTN_2_pressed(self, evt):
    133                  if self.IsModal():
    134                          self.EndModal(wx.ID_NO)
    135                  else:
    136                          self.Close()
    137  # ========================================================================
    138  from Gnumed.wxGladeWidgets import wxgMultilineTextEntryDlg
    139
    140 -class cMultilineTextEntryDlg(wxgMultilineTextEntryDlg.wxgMultilineTextEntryDlg):
    141          """Editor for a bit of text."""
    142
    143 -        def __init__(self, *args, **kwargs):
    144
    145                  try:
    146                          title = kwargs['title']
    147                          del kwargs['title']
    148                  except KeyError:
    149                          title = None
    150
    151                  try:
    152                          msg = kwargs['msg']
    153                          del kwargs['msg']
    154                  except KeyError:
    155                          msg = None
    156
    157                  try:
    158                          data = kwargs['data']
    159                          del kwargs['data']
    160                  except KeyError:
    161                          data = None
    162
    163                  try:
    164                          self.original_text = kwargs['text']
    165                          del kwargs['text']
    166                  except KeyError:
    167                          self.original_text = None
    168
    169                  wxgMultilineTextEntryDlg.wxgMultilineTextEntryDlg.__init__(self, *args, **kwargs)
    170
    171                  if title is not None:
    172                          self.SetTitle(title)
    173
    174                  if self.original_text is not None:
    175                          self._TCTRL_text.SetValue(self.original_text)
    176                          self._BTN_restore.Enable(True)
    177
    178                  if msg is None:
    179                          self._LBL_msg.Hide()
    180                  else:
    181                          self._LBL_msg.SetLabel(msg)
    182                          self.Layout()
    183                          self.Refresh()
    184
    185                  if data is None:
    186                          self._TCTRL_data.Hide()
    187                  else:
    188                          self._TCTRL_data.SetValue(data)
    189                          self.Layout()
    190                          self.Refresh()
    191          #--------------------------------------------------------
    192 -        def _get_value(self):
    193                  return self._TCTRL_text.GetValue()
    194
    195          value = property(_get_value, lambda x:x)
    196          #--------------------------------------------------------
    197          # event handlers
    198          #--------------------------------------------------------
    199 -        def _on_save_button_pressed(self, evt):
    200
    201                  if self.IsModal():
    202                          self.EndModal(wx.ID_SAVE)
    203                  else:
    204                          self.Close()
    205          #--------------------------------------------------------
    206 -        def _on_clear_button_pressed(self, evt):
    207                  self._TCTRL_text.SetValue(u'')
    208          #--------------------------------------------------------
    209 -        def _on_restore_button_pressed(self, evt):
    210                  if self.original_text is not None:
    211                          self._TCTRL_text.SetValue(self.original_text)
    212  # ========================================================================
    213 -class cGreetingEditorDlg(wxgGreetingEditorDlg.wxgGreetingEditorDlg):
    214
    215 -        def __init__(self, *args, **kwargs):
    216                  wxgGreetingEditorDlg.wxgGreetingEditorDlg.__init__(self, *args, **kwargs)
    217
    218                  self.surgery = gmSurgery.gmCurrentPractice()
    219                  self._TCTRL_message.SetValue(self.surgery.db_logon_banner)
    220          #--------------------------------------------------------
    221          # event handlers
    222          #--------------------------------------------------------
    223 -        def _on_save_button_pressed(self, evt):
    224                  self.surgery.db_logon_banner = self._TCTRL_message.GetValue().strip()
    225                  if self.IsModal():
    226                          self.EndModal(wx.ID_SAVE)
    227                  else:
    228                          self.Close()
    229  # ========================================================================
    230 -class cTreeExpansionHistoryMixin:
    231          """TreeCtrl mixin class to record expansion history."""
    232 -        def __init__(self):
    233                  if not isinstance(self, wx.TreeCtrl):
    234                          raise TypeError('[%s]: mixin can only be applied to wx.TreeCtrl, not [%s]' % (cTreeExpansionHistoryMixin, self.__class__.__name__))
    235                  self.expansion_state = {}
    236          #--------------------------------------------------------
    237          # public API
    238          #--------------------------------------------------------
    239 -        def snapshot_expansion(self):
    240                  self.__record_subtree_expansion(start_node_id = self.GetRootItem())
    241          #--------------------------------------------------------
    242 -        def restore_expansion(self):
    243                  if len(self.expansion_state) == 0:
    244                          return True
    245                  self.__restore_subtree_expansion(start_node_id = self.GetRootItem())
    246          #--------------------------------------------------------
    247 -        def print_expansion(self):
    248                  if len(self.expansion_state) == 0:
    249                          print "currently no expansion snapshot available"
    250                          return True
    251                  print "last snapshot of state of expansion"
    252                  print "-----------------------------------"
    253                  print "listing expanded nodes:"
    254                  for node_id in self.expansion_state.keys():
    255                          print "node ID:", node_id
    256                          print "  selected:", self.expansion_state[node_id]
    257          #--------------------------------------------------------
    258          # internal API
    259          #--------------------------------------------------------
    260 -        def __record_subtree_expansion(self, start_node_id=None):
    261                  """This records node expansion states based on the item label.
    262
    263                  A side effect of this is that identically named items can
    264                  become unduly synchronized in their expand state after a
    265                  snapshot/restore cycle.
    266
    267                  Better choices might be
    268
    269                          id(item.GetPyData()) or
    270                          item.GetPyData().get_tree_uid()
    271
    272                  where get_tree_uid():
    273
    274                          '[%s:%s]' % (self.__class__.__name__, id(self))
    275
    276                  or some such. This would survive renaming of the item.
    277
    278                  For database items it may be useful to include the
    279                  primary key which would - contrary to id() - survive
    280                  reloads from the database.
    281                  """
    282                  # protect against empty tree where not even
    283                  # a root node exists
    284                  if not start_node_id.IsOk():
    285                          return True
    286
    287                  if not self.IsExpanded(start_node_id):
    288                          return True
    289
    290                  self.expansion_state[self.GetItemText(start_node_id)] = self.IsSelected(start_node_id)
    291
    292                  child_id, cookie = self.GetFirstChild(start_node_id)
    293                  while child_id.IsOk():
    294                          self.__record_subtree_expansion(start_node_id = child_id)
    295                          child_id, cookie = self.GetNextChild(start_node_id, cookie)
    296
    297                  return
    298          #--------------------------------------------------------
    299 -        def __restore_subtree_expansion(self, start_node_id=None):
    300                  start_node_label = self.GetItemText(start_node_id)
    301                  try:
    302                          node_selected = self.expansion_state[start_node_label]
    303                  except KeyError:
    304                          return
    305
    306                  self.Expand(start_node_id)
    307                  if node_selected:
    308                          self.SelectItem(start_node_id)
    309
    310                  child_id, cookie = self.GetFirstChild(start_node_id)
    311                  while child_id.IsOk():
    312                          self.__restore_subtree_expansion(start_node_id = child_id)
    313                          child_id, cookie = self.GetNextChild(start_node_id, cookie)
    314
    315                  return
    316  # ========================================================================
    317 -class cFileDropTarget(wx.FileDropTarget):
    318          """Generic file drop target class.
    319
    320          Protocol:
    321                  Widgets being declared file drop targets
    322                  must provide the method:
    323
    324                          add_filenames(filenames)
    325          """
    326          #-----------------------------------------------
    327 -        def __init__(self, target):
    328                  wx.FileDropTarget.__init__(self)
    329                  self.target = target
    330          #-----------------------------------------------
    331 -        def OnDropFiles(self, x, y, filenames):
    332                  self.target.add_filenames(filenames)
    333  # ========================================================================
    334 -def gm_show_error(aMessage = None, aTitle = None):
    335          if aMessage is None:
    336                  aMessage = _('programmer forgot to specify error message')
    337
    338          aMessage += _("\n\nPlease consult the error log for all the gory details !")
    339
    340          if aTitle is None:
    341                  aTitle = _('generic error message')
    342
    343          message = aMessage
    344          print message
    345
    346          #dlg = wx.MessageDialog (
    347          #       parent = None,
    348          #       message = aMessage,
    349          #       caption = aTitle,
    350          #       style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP
    351          #)
    352          #dlg.ShowModal()
    353          #dlg.Destroy()
    354          #return True
    355  #-------------------------------------------------------------------------
    356 -def gm_show_info(aMessage = None, aTitle = None):
    357          if aMessage is None:
    358                  aMessage = _('programmer forgot to specify info message')
    359
    360          if aTitle is None:
    361                  aTitle = _('generic info message')
    362
    363          dlg = wx.MessageDialog (
    364                  parent = None,
    365                  message = aMessage,
    366                  caption = aTitle,
    367                  style = wx.OK | wx.ICON_INFORMATION | wx.STAY_ON_TOP
    368          )
    369          dlg.ShowModal()
    370          dlg.Destroy()
    371          return True
    372  #-------------------------------------------------------------------------
    373 -def gm_show_warning(aMessage=None, aTitle=None):
    374          if aMessage is None:
    375                  aMessage = _('programmer forgot to specify warning')
    376
    377          if aTitle is None:
    378                  aTitle = _('generic warning message')
    379
    380          dlg = wx.MessageDialog (
    381                  parent = None,
    382                  message = aMessage,
    383                  caption = aTitle,
    384                  style = wx.OK | wx.ICON_EXCLAMATION | wx.STAY_ON_TOP
    385          )
    386          dlg.ShowModal()
    387          dlg.Destroy()
    388          return True
    389  #-------------------------------------------------------------------------
    390 -def gm_show_question(aMessage='programmer forgot to specify question', aTitle='generic user question dialog', cancel_button=False):
    391          if cancel_button:
    392                  style = wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION | wx.STAY_ON_TOP
    393          else:
    394                  style = wx.YES_NO | wx.ICON_QUESTION | wx.STAY_ON_TOP
    395
    396          dlg = wx.MessageDialog (
    397                  None,
    398                  aMessage,
    399                  aTitle,
    400                  style
    401          )
    402          btn_pressed = dlg.ShowModal()
    403          dlg.Destroy()
    404
    405          if btn_pressed == wx.ID_YES:
    406                  return True
    407          elif btn_pressed == wx.ID_NO:
    408                  return False
    409          else:
    410                  return None
    411  #----------------------------------------------------------------------
    412 -def makePageTitle(wizPg, title):
    413          """
    414          Utility function to create the main sizer of a wizard's page.
    415
    416          @param wizPg The wizard page widget
    417          @type wizPg A wx.WizardPageSimple instance
    418          @param title The wizard page's descriptive title
    419          @type title A StringType instance
    420          """
    421          sizer = wx.BoxSizer(wx.VERTICAL)
    422          wizPg.SetSizer(sizer)
    423          title = wx.StaticText(wizPg, -1, title)
    424          title.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
    425          sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 2)
    426          sizer.Add(wx.StaticLine(wizPg, -1), 0, wx.EXPAND|wx.ALL, 2)
    427          return sizer
    428  #============================================================
    429