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

# Source Code for Module Gnumed.wxpython.gmHorstSpace

      1  """GNUmed Horst-space inner-frame layout manager.
      2
      3  This implements the simple wx.Notebook based layout as
      4  originally suggested by Horst Herb.
      5
      6  copyright: authors
      7  """
      8  #==============================================================================
      9  __version__ = "$Revision: 1.47 $"
     10  __author__  = "H. Herb <hherb@gnumed.net>,\
     11                             K. Hilbert <Karsten.Hilbert@gmx.net>,\
     12                             I. Haywood <i.haywood@ugrad.unimelb.edu.au>"
     13  __license__ = 'GPL v2 or later (details at http://www.gnu.org)'
     14
     15  import os.path, os, sys, logging
     16
     17
     18  import wx
     19
     20
     21  from Gnumed.pycommon import gmGuiBroker, gmI18N, gmDispatcher, gmCfg
     22  from Gnumed.wxpython import gmPlugin, gmTopPanel, gmGuiHelpers
     23  from Gnumed.business import gmPerson, gmSurgery
     24
     25
     26  _log = logging.getLogger('gm.ui')
     27  _log.info(__version__)
     28  #==============================================================================
     29  # finding the visible page from a notebook page: self.GetParent.GetCurrentPage == self
     30 -class cHorstSpaceLayoutMgr(wx.Panel):
     31          """GNUmed inner-frame layout manager.
     32
     33          This implements a Horst-space notebook-only
     34          "inner-frame" layout manager.
     35          """
     36 -        def __init__(self, parent, id):
     37                  # main panel
     38                  wx.Panel.__init__(
     39                          self,
     40                          parent = parent,
     41                          id = id,
     42                          pos = wx.DefaultPosition,
     43                          size = wx.DefaultSize,
     44                          style = wx.NO_BORDER,
     45                          name = 'HorstSpace.LayoutMgrPnl'
     46                  )
     47                  # notebook
     48                  self.nb = wx.Notebook (
     49                          parent=self,
     50                          id = -1,
     51                          size = wx.Size(320,240),
     52                          style = wx.NB_BOTTOM
     53                  )
     54                  # plugins
     55                  self.__gb = gmGuiBroker.GuiBroker()
     56                  self.__gb['horstspace.notebook'] = self.nb # FIXME: remove per Ian's API suggestion
     57
     58                  # top panel
     59                  #---------------------
     60                  # create the "top row"
     61                  #---------------------
     62                  # important patient data is always displayed there
     63                  self.top_panel = gmTopPanel.cTopPnl(self, -1)
     64                  self.__gb['horstspace.top_panel'] = self.top_panel
     65                  self.__load_plugins()
     66
     67                  # layout handling
     68                  self.main_szr = wx.BoxSizer(wx.VERTICAL)
     69                  self.main_szr.Add(self.top_panel, 0, wx.EXPAND)
     70                  self.main_szr.Add(self.nb, 1, wx.EXPAND)
     71                  self.SetSizer(self.main_szr)
     72  #               self.SetSizerAndFit(self.main_szr)
     73  #               self.Layout()
     74  #               self.Show(True)
     75
     76                  self.__register_events()
     77          #----------------------------------------------
     78          # internal API
     79          #----------------------------------------------
     80 -        def __register_events(self):
     81                  # - notebook page is about to change
     82                  self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self._on_notebook_page_changing)
     83                  # - notebook page has been changed
     84                  self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self._on_notebook_page_changed)
     85                  # - popup menu on right click in notebook
     86                  wx.EVT_RIGHT_UP(self.nb, self._on_right_click)
     87
     88                  gmDispatcher.connect(self._on_post_patient_selection, u'post_patient_selection')
     89          #----------------------------------------------
     90 -        def __load_plugins(self):
     91                  # get plugin list
     92                  plugin_list = gmPlugin.GetPluginLoadList (
     93                          option = 'horstspace.notebook.plugin_load_order',
     94                          plugin_dir = 'gui',
     95                          defaults = ['gmProviderInboxPlugin']
     96                  )
     97
     98                  nr_plugins = len(plugin_list)
     99                  wx.BeginBusyCursor()
    100
    101                  #  set up a progress bar
    102                  progress_bar = gmPlugin.cLoadProgressBar(nr_plugins)
    103
    104                  #  and load them
    105                  prev_plugin = ""
    106                  first_plugin = None
    107                  plugin = None
    108                  result = -1
    109                  for idx in range(nr_plugins):
    110                          curr_plugin = plugin_list[idx]
    111                          progress_bar.Update(result, curr_plugin)
    112                          try:
    113                                  plugin = gmPlugin.instantiate_plugin('gui', curr_plugin)
    114                                  if plugin:
    115                                          plugin.register()
    116                                          result = 1
    117                                  else:
    118                                          _log.error("plugin [%s] not loaded, see errors above", curr_plugin)
    119                                          result = 1
    120                          except:
    121                                  _log.exception('failed to load plugin %s', curr_plugin)
    122                                  result = 0
    123
    124                          if first_plugin is None:
    125                                  first_plugin = plugin
    126                          prev_plugin = curr_plugin
    127
    128                  progress_bar.Destroy()
    129                  wx.EndBusyCursor()
    130
    131                  # force-refresh first notebook page
    132                  page = self.nb.GetPage(0)
    133                  page.Refresh()
    134
    135                  return True
    136          #----------------------------------------------
    137          # external callbacks
    138          #----------------------------------------------
    139 -        def _on_post_patient_selection(self, **kwargs):
    140                  db_cfg = gmCfg.cCfgSQL()
    141                  default_plugin = db_cfg.get2 (
    142                          option = u'patient_search.plugin_to_raise_after_search',
    143                          workplace = gmSurgery.gmCurrentPractice().active_workplace,
    144                          bias = u'user',
    145                          default = u'gmPatientOverviewPlugin'
    146                  )
    147                  wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = default_plugin)
    148          #----------------------------------------------
    149 -        def _on_notebook_page_changing(self, event):
    150                  """Called before notebook page change is processed."""
    151
    152                  _log.debug('just before switching notebook tabs')
    153
    154                  self.__new_page_already_checked = False
    155
    156                  self.__id_nb_page_before_switch = self.nb.GetSelection()
    157                  self.__id_evt_page_before_switch = event.GetOldSelection()
    158                  __id_evt_page_after_switch = event.GetSelection()
    159
    160                  _log.debug('event.GetOldSelection()=%s* -> event.GetSelection()=%s', self.__id_evt_page_before_switch, __id_evt_page_after_switch)
    161
    162                  if self.__id_evt_page_before_switch != self.__id_nb_page_before_switch:
    163                          _log.debug('the following two should match but do not:')
    164                          _log.debug(' event.GetOldSelection(): %s', self.__id_evt_page_before_switch)
    165                          _log.debug(' notebook.GetSelection(): %s', self.__id_nb_page_before_switch)
    166
    167                  # can we check the target page ?
    168                  if __id_evt_page_after_switch == self.__id_evt_page_before_switch:
    169                          # no, so complain
    170                          # (the docs say that on Windows GetSelection() returns the
    171                          #  old page ID, eg. the same value GetOldSelection() returns)
    172                          _log.debug('this system is: sys: [%s] wx: [%s]', sys.platform, wx.Platform)
    173                          _log.debug('it seems to be one of those platforms that have no clue which notebook page they are switching to')
    174                          _log.debug('(Windows is documented to return the old page from both evt.GetOldSelection() and evt.GetSelection())')
    175                          _log.debug('current notebook page : %s', self.__id_nb_page_before_switch)
    176                          _log.debug('source page from event: %s', self.__id_evt_page_before_switch)
    177                          _log.debug('target page from event: %s', __id_evt_page_after_switch)
    178                          _log.info('cannot check whether notebook page change needs to be vetoed')
    179                          # but let's do a basic check anyways
    180                          pat = gmPerson.gmCurrentPatient()
    181                          if not pat.connected:
    182                                  gmDispatcher.send(signal = 'statustext', msg =_('Cannot change notebook tabs. No active patient.'))
    183                                  event.Veto()
    184                                  return
    185                          # that test passed, so let's hope things are fine
    186                          event.Allow()           # redundant ?
    187                          event.Skip()
    188                          return
    189
    190                  # check target page
    191                  new_page = self.__gb['horstspace.notebook.pages'][__id_evt_page_after_switch]
    192                  if not new_page.can_receive_focus():
    193                          _log.debug('veto()ing page change')
    194                          event.Veto()
    195                          return
    196
    197                  # everything seems fine so switch
    198                  self.__new_page_already_checked = True
    199                  event.Allow()           # redundant ?
    200                  event.Skip()
    201                  return
    202          #----------------------------------------------
    203 -        def _on_notebook_page_changed(self, event):
    204                  """Called when notebook page changes."""
    205
    206                  _log.debug('just after switching notebook tabs')
    207
    208                  id_evt_page_before_switch = event.GetOldSelection()
    209                  id_evt_page_after_switch = event.GetSelection()
    210                  id_nb_page_after_switch = self.nb.GetSelection()
    211
    212                  _log.debug('event.GetOldSelection()=%s -> event.GetSelection()=%s*', id_evt_page_before_switch, id_evt_page_after_switch)
    213
    214                  if self.__id_nb_page_before_switch != id_evt_page_before_switch:
    215                          _log.debug('those two really *should* match:')
    216                          _log.debug(' wx.Notebook.GetSelection() (before switch) : %s' % self.__id_nb_page_before_switch)
    217                          _log.debug(' EVT_NOTEBOOK_PAGE_CHANGED.GetOldSelection(): %s' % id_evt_page_before_switch)
    218
    219                  new_page = self.__gb['horstspace.notebook.pages'][id_evt_page_after_switch]
    220
    221                  # well-behaving wxPython port ?
    222                  if self.__new_page_already_checked:
    223                          new_page.receive_focus()
    224                          # activate toolbar of new page
    225  #                       self.__gb['horstspace.top_panel'].ShowBar(new_page.__class__.__name__)
    226                          self.__new_page_already_checked = False
    227                          event.Skip()
    228                          return
    229
    230                  # no, complain
    231                  _log.debug('target page not checked for focussability yet')
    232                  _log.debug('EVT_NOTEBOOK_PAGE_CHANGED.GetOldSelection(): %s' % id_evt_page_before_switch)
    233                  _log.debug('EVT_NOTEBOOK_PAGE_CHANGED.GetSelection()   : %s' % id_evt_page_after_switch)
    234                  _log.debug('wx.Notebook.GetSelection() (after switch)  : %s' % id_nb_page_after_switch)
    235
    236                  # check the new page just for good measure
    237                  if new_page.can_receive_focus():
    238                          _log.debug('we are lucky: new page *can* receive focus')
    239                          new_page.receive_focus()
    240                          # activate toolbar of new page
    241  #                       self.__gb['horstspace.top_panel'].ShowBar(new_page.__class__.__name__)
    242                          event.Skip()
    243                          return
    244
    245                  _log.warning('new page cannot receive focus but too late for veto')
    246                  event.Skip()
    247                  return
    248          #----------------------------------------------
    249 -        def _on_right_click(self, evt):
    250                  evt.Skip()
    251                  return
    252
    253                  load_menu = wx.Menu()
    254                  any_loadable = 0
    255                  plugin_list = gmPlugin.GetPluginLoadList('gui')
    256                  plugin = None
    257                  for plugin_name in plugin_list:
    258                          try:
    259                                  plugin = gmPlugin.instantiate_plugin('gui', plugin_name)
    260                          except StandardError:
    261                                  continue
    262                          # not a plugin
    263                          if not isinstance(plugin, gmPlugin.cNotebookPlugin):
    264                                  plugin = None
    265                                  continue
    266                          # already loaded ?
    267                          if plugin.__class__.__name__ in self.guibroker['horstspace.notebook.gui'].keys():
    268                                  plugin = None
    269                                  continue
    270                          # add to load menu
    271                          nid = wx.NewId()
    272                          load_menu.AppendItem(wx.MenuItem(load_menu, nid, plugin.name()))
    273                          wx.EVT_MENU(load_menu, nid, plugin.on_load)
    274                          any_loadable = 1
    275                  # make menus
    276                  menu = wx.Menu()
    277                  ID_LOAD = wx.NewId()
    278                  ID_DROP = wx.NewId()
    279                  if any_loadable:
    280                          menu.AppendMenu(ID_LOAD, _('add plugin ...'), load_menu)
    281                  plugins = self.guibroker['horstspace.notebook.gui']
    282                  raised_plugin = plugins[self.nb.GetSelection()].name()
    283                  menu.AppendItem(wx.MenuItem(menu, ID_DROP, "drop [%s]" % raised_plugin))
    284                  wx.EVT_MENU (menu, ID_DROP, self._on_drop_plugin)
    285                  self.PopupMenu(menu, evt.GetPosition())
    286                  menu.Destroy()
    287                  evt.Skip()
    288          #----------------------------------------------
    289 -        def _on_drop_plugin(self, evt):
    290                  """Unload plugin and drop from load list."""
    291                  pages = self.guibroker['horstspace.notebook.pages']
    292                  page = pages[self.nb.GetSelection()]
    293                  page.unregister()
    294                  self.nb.AdvanceSelection()
    295                  # FIXME:"dropping" means talking to configurator so not reloaded
    296          #----------------------------------------------
    297 -        def _on_hide_plugin (self, evt):
    298                  """Unload plugin but don't touch configuration."""
    299                  # this dictionary links notebook page numbers to plugin objects
    300                  pages = self.guibroker['horstspace.notebook.pages']
    301                  page = pages[self.nb.GetSelection()]
    302                  page.unregister()
    303  #==============================================================================
    304  if __name__ == '__main__':
    305          wx.InitAllImageHandlers()
    306          pgbar = gmPluginLoadProgressBar(3)
    307
    308  #==============================================================================
    309