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