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, gmPraxis 
 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 = gmPraxis.gmCurrentPraxisBranch().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