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
36 """GnuMed inner-frame layout manager.
37
38 This implements a Horst-space notebook-only
39 "inner-frame" layout manager.
40 """
42
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
53 self.nb = wx.Notebook (
54 parent=self,
55 id = -1,
56 size = wx.Size(320,240),
57 style = wx.NB_BOTTOM
58 )
59
60 self.__gb = gmGuiBroker.GuiBroker()
61 self.__gb['horstspace.notebook'] = self.nb
62
63
64
65
66
67
68
69 self.top_panel = gmTopPanel.cMainTopPanel(self, -1)
70 self.__gb['horstspace.top_panel'] = self.top_panel
71 self.__load_plugins()
72
73
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
79
80
81
82 self.__register_events()
83
84
85
87
88 self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self._on_notebook_page_changing)
89
90 self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self._on_notebook_page_changed)
91
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
97
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
108 progress_bar = gmPlugin.cLoadProgressBar(nr_plugins)
109
110
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
138 page = self.nb.GetPage(0)
139 page.Refresh()
140
141 return True
142
143
144
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
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
174 if __id_evt_page_after_switch == self.__id_evt_page_before_switch:
175
176
177
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
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
192 event.Allow()
193 event.Skip()
194 return
195
196
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
204 self.__new_page_already_checked = True
205 event.Allow()
206 event.Skip()
207 return
208
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
228 if self.__new_page_already_checked:
229 new_page.receive_focus()
230
231
232 self.__new_page_already_checked = False
233 event.Skip()
234 return
235
236
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
243 if new_page.can_receive_focus():
244 _log.debug('we are lucky: new page *can* receive focus')
245 new_page.receive_focus()
246
247
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
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
269 if not isinstance(plugin, gmPlugin.cNotebookPlugin):
270 plugin = None
271 continue
272
273 if plugin.__class__.__name__ in self.guibroker['horstspace.notebook.gui'].keys():
274 plugin = None
275 continue
276
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
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
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
302
304 """Unload plugin but don't touch configuration."""
305
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