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 # - top panel with toolbars 64 self.top_panel = gmTopPanel.cMainTopPanel(self, -1) 65 self.__gb['horstspace.top_panel'] = self.top_panel 66 self.__load_plugins() 67 68 # layout handling 69 self.main_szr = wx.BoxSizer(wx.VERTICAL) 70 self.main_szr.Add(self.top_panel, 0, wx.EXPAND) 71 self.main_szr.Add(self.nb, 1, wx.EXPAND) 72 self.SetSizer(self.main_szr) 73 # self.SetSizerAndFit(self.main_szr) 74 # self.Layout() 75 # self.Show(True) 76 77 self.__register_events()
78 #---------------------------------------------- 79 # internal API 80 #----------------------------------------------
81 - def __register_events(self):
82 # - notebook page is about to change 83 self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self._on_notebook_page_changing) 84 # - notebook page has been changed 85 self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self._on_notebook_page_changed) 86 # - popup menu on right click in notebook 87 wx.EVT_RIGHT_UP(self.nb, self._on_right_click) 88 89 gmDispatcher.connect(self._on_post_patient_selection, u'post_patient_selection')
90 #----------------------------------------------
91 - def __load_plugins(self):
92 # get plugin list 93 plugin_list = gmPlugin.GetPluginLoadList ( 94 option = 'horstspace.notebook.plugin_load_order', 95 plugin_dir = 'gui', 96 defaults = ['gmProviderInboxPlugin'] 97 ) 98 99 nr_plugins = len(plugin_list) 100 wx.BeginBusyCursor() 101 102 # set up a progress bar 103 progress_bar = gmPlugin.cLoadProgressBar(nr_plugins) 104 105 # and load them 106 prev_plugin = "" 107 first_plugin = None 108 plugin = None 109 result = -1 110 for idx in range(nr_plugins): 111 curr_plugin = plugin_list[idx] 112 progress_bar.Update(result, curr_plugin) 113 try: 114 plugin = gmPlugin.instantiate_plugin('gui', curr_plugin) 115 if plugin: 116 plugin.register() 117 result = 1 118 else: 119 _log.error("plugin [%s] not loaded, see errors above", curr_plugin) 120 result = 1 121 except: 122 _log.exception('failed to load plugin %s', curr_plugin) 123 result = 0 124 125 if first_plugin is None: 126 first_plugin = plugin 127 prev_plugin = curr_plugin 128 129 progress_bar.Destroy() 130 wx.EndBusyCursor() 131 132 # force-refresh first notebook page 133 page = self.nb.GetPage(0) 134 page.Refresh() 135 136 return True
137 #---------------------------------------------- 138 # external callbacks 139 #----------------------------------------------
140 - def _on_post_patient_selection(self, **kwargs):
141 db_cfg = gmCfg.cCfgSQL() 142 default_plugin = db_cfg.get2 ( 143 option = u'patient_search.plugin_to_raise_after_search', 144 workplace = gmSurgery.gmCurrentPractice().active_workplace, 145 bias = u'user', 146 default = u'gmEMRBrowserPlugin' 147 ) 148 wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = default_plugin)
149 #----------------------------------------------
150 - def _on_notebook_page_changing(self, event):
151 """Called before notebook page change is processed.""" 152 153 _log.debug('just before switching notebook tabs') 154 155 self.__new_page_already_checked = False 156 157 self.__id_nb_page_before_switch = self.nb.GetSelection() 158 self.__id_evt_page_before_switch = event.GetOldSelection() 159 __id_evt_page_after_switch = event.GetSelection() 160 161 _log.debug('event.GetOldSelection()=%s* -> event.GetSelection()=%s', self.__id_evt_page_before_switch, __id_evt_page_after_switch) 162 163 if self.__id_evt_page_before_switch != self.__id_nb_page_before_switch: 164 _log.debug('the following two should match but do not:') 165 _log.debug(' event.GetOldSelection(): %s', self.__id_evt_page_before_switch) 166 _log.debug(' notebook.GetSelection(): %s', self.__id_nb_page_before_switch) 167 168 # can we check the target page ? 169 if __id_evt_page_after_switch == self.__id_evt_page_before_switch: 170 # no, so complain 171 # (the docs say that on Windows GetSelection() returns the 172 # old page ID, eg. the same value GetOldSelection() returns) 173 _log.debug('this system is: sys: [%s] wx: [%s]', sys.platform, wx.Platform) 174 _log.debug('it seems to be one of those platforms that have no clue which notebook page they are switching to') 175 _log.debug('(Windows is documented to return the old page from both evt.GetOldSelection() and evt.GetSelection())') 176 _log.debug('current notebook page : %s', self.__id_nb_page_before_switch) 177 _log.debug('source page from event: %s', self.__id_evt_page_before_switch) 178 _log.debug('target page from event: %s', __id_evt_page_after_switch) 179 _log.info('cannot check whether notebook page change needs to be vetoed') 180 # but let's do a basic check anyways 181 pat = gmPerson.gmCurrentPatient() 182 if not pat.connected: 183 gmDispatcher.send(signal = 'statustext', msg =_('Cannot change notebook tabs. No active patient.')) 184 event.Veto() 185 return 186 # that test passed, so let's hope things are fine 187 event.Allow() # redundant ? 188 event.Skip() 189 return 190 191 # check target page 192 new_page = self.__gb['horstspace.notebook.pages'][__id_evt_page_after_switch] 193 if not new_page.can_receive_focus(): 194 _log.debug('veto()ing page change') 195 event.Veto() 196 return 197 198 # everything seems fine so switch 199 self.__new_page_already_checked = True 200 event.Allow() # redundant ? 201 event.Skip() 202 return
203 #----------------------------------------------
204 - def _on_notebook_page_changed(self, event):
205 """Called when notebook page changes.""" 206 207 _log.debug('just after switching notebook tabs') 208 209 id_evt_page_before_switch = event.GetOldSelection() 210 id_evt_page_after_switch = event.GetSelection() 211 id_nb_page_after_switch = self.nb.GetSelection() 212 213 _log.debug('event.GetOldSelection()=%s -> event.GetSelection()=%s*', id_evt_page_before_switch, id_evt_page_after_switch) 214 215 if self.__id_nb_page_before_switch != id_evt_page_before_switch: 216 _log.debug('those two really *should* match:') 217 _log.debug(' wx.Notebook.GetSelection() (before switch) : %s' % self.__id_nb_page_before_switch) 218 _log.debug(' EVT_NOTEBOOK_PAGE_CHANGED.GetOldSelection(): %s' % id_evt_page_before_switch) 219 220 new_page = self.__gb['horstspace.notebook.pages'][id_evt_page_after_switch] 221 222 # well-behaving wxPython port ? 223 if self.__new_page_already_checked: 224 new_page.receive_focus() 225 # activate toolbar of new page 226 # self.__gb['horstspace.top_panel'].ShowBar(new_page.__class__.__name__) 227 self.__new_page_already_checked = False 228 event.Skip() 229 return 230 231 # no, complain 232 _log.debug('target page not checked for focussability yet') 233 _log.debug('EVT_NOTEBOOK_PAGE_CHANGED.GetOldSelection(): %s' % id_evt_page_before_switch) 234 _log.debug('EVT_NOTEBOOK_PAGE_CHANGED.GetSelection() : %s' % id_evt_page_after_switch) 235 _log.debug('wx.Notebook.GetSelection() (after switch) : %s' % id_nb_page_after_switch) 236 237 # check the new page just for good measure 238 if new_page.can_receive_focus(): 239 _log.debug('we are lucky: new page *can* receive focus') 240 new_page.receive_focus() 241 # activate toolbar of new page 242 # self.__gb['horstspace.top_panel'].ShowBar(new_page.__class__.__name__) 243 event.Skip() 244 return 245 246 _log.warning('new page cannot receive focus but too late for veto') 247 event.Skip() 248 return
249 #----------------------------------------------
250 - def _on_right_click(self, evt):
251 evt.Skip() 252 return 253 254 load_menu = wx.Menu() 255 any_loadable = 0 256 plugin_list = gmPlugin.GetPluginLoadList('gui') 257 plugin = None 258 for plugin_name in plugin_list: 259 try: 260 plugin = gmPlugin.instantiate_plugin('gui', plugin_name) 261 except StandardError: 262 continue 263 # not a plugin 264 if not isinstance(plugin, gmPlugin.cNotebookPlugin): 265 plugin = None 266 continue 267 # already loaded ? 268 if plugin.__class__.__name__ in self.guibroker['horstspace.notebook.gui'].keys(): 269 plugin = None 270 continue 271 # add to load menu 272 nid = wx.NewId() 273 load_menu.AppendItem(wx.MenuItem(load_menu, nid, plugin.name())) 274 wx.EVT_MENU(load_menu, nid, plugin.on_load) 275 any_loadable = 1 276 # make menus 277 menu = wx.Menu() 278 ID_LOAD = wx.NewId() 279 ID_DROP = wx.NewId() 280 if any_loadable: 281 menu.AppendMenu(ID_LOAD, _('add plugin ...'), load_menu) 282 plugins = self.guibroker['horstspace.notebook.gui'] 283 raised_plugin = plugins[self.nb.GetSelection()].name() 284 menu.AppendItem(wx.MenuItem(menu, ID_DROP, "drop [%s]" % raised_plugin)) 285 wx.EVT_MENU (menu, ID_DROP, self._on_drop_plugin) 286 self.PopupMenu(menu, evt.GetPosition()) 287 menu.Destroy() 288 evt.Skip()
289 #----------------------------------------------
290 - def _on_drop_plugin(self, evt):
291 """Unload plugin and drop from load list.""" 292 pages = self.guibroker['horstspace.notebook.pages'] 293 page = pages[self.nb.GetSelection()] 294 page.unregister() 295 self.nb.AdvanceSelection()
296 # FIXME:"dropping" means talking to configurator so not reloaded 297 #----------------------------------------------
298 - def _on_hide_plugin (self, evt):
299 """Unload plugin but don't touch configuration.""" 300 # this dictionary links notebook page numbers to plugin objects 301 pages = self.guibroker['horstspace.notebook.pages'] 302 page = pages[self.nb.GetSelection()] 303 page.unregister()
304 #============================================================================== 305 if __name__ == '__main__': 306 wx.InitAllImageHandlers() 307 pgbar = gmPluginLoadProgressBar(3) 308 309 #============================================================================== 310