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
15
16 __version__ = "$Revision: 1.47 $"
17 __author__ = "H. Herb <hherb@gnumed.net>,\
18 K. Hilbert <Karsten.Hilbert@gmx.net>,\
19 I. Haywood <i.haywood@ugrad.unimelb.edu.au>"
20 __license__ = 'GPL (details at http://www.gnu.org)'
21
22 import os.path, os, sys, logging
23
24
25 import wx
26
27
28 from Gnumed.pycommon import gmGuiBroker, gmI18N, gmDispatcher, gmCfg
29 from Gnumed.wxpython import gmPlugin, gmTopPanel, gmGuiHelpers
30 from Gnumed.business import gmPerson, gmSurgery
31
32
33 _log = logging.getLogger('gm.ui')
34 _log.info(__version__)
35
36
38 """GnuMed inner-frame layout manager.
39
40 This implements a Horst-space notebook-only
41 "inner-frame" layout manager.
42 """
44
45 wx.Panel.__init__(
46 self,
47 parent = parent,
48 id = id,
49 pos = wx.DefaultPosition,
50 size = wx.DefaultSize,
51 style = wx.NO_BORDER,
52 name = 'HorstSpace.LayoutMgrPnl'
53 )
54
55 self.nb = wx.Notebook (
56 parent=self,
57 id = -1,
58 size = wx.Size(320,240),
59 style = wx.NB_BOTTOM
60 )
61
62 self.__gb = gmGuiBroker.GuiBroker()
63 self.__gb['horstspace.notebook'] = self.nb
64
65
66
67
68
69
70
71 self.top_panel = gmTopPanel.cMainTopPanel(self, -1)
72 self.__gb['horstspace.top_panel'] = self.top_panel
73 self.__load_plugins()
74
75
76 self.main_szr = wx.BoxSizer(wx.VERTICAL)
77 self.main_szr.Add(self.top_panel, 0, wx.EXPAND)
78 self.main_szr.Add(self.nb, 1, wx.EXPAND)
79 self.SetSizer(self.main_szr)
80
81
82
83
84 self.__register_events()
85
86
87
89
90 self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self._on_notebook_page_changing)
91
92 self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self._on_notebook_page_changed)
93
94 wx.EVT_RIGHT_UP(self.nb, self._on_right_click)
95
96 gmDispatcher.connect(self._on_post_patient_selection, u'post_patient_selection')
97
99
100 plugin_list = gmPlugin.GetPluginLoadList (
101 option = 'horstspace.notebook.plugin_load_order',
102 plugin_dir = 'gui',
103 defaults = ['gmProviderInboxPlugin']
104 )
105
106 nr_plugins = len(plugin_list)
107 wx.BeginBusyCursor()
108
109
110 progress_bar = gmPlugin.cLoadProgressBar(nr_plugins)
111
112
113 prev_plugin = ""
114 first_plugin = None
115 plugin = None
116 result = -1
117 for idx in range(nr_plugins):
118 curr_plugin = plugin_list[idx]
119 progress_bar.Update(result, curr_plugin)
120 try:
121 plugin = gmPlugin.instantiate_plugin('gui', curr_plugin)
122 if plugin:
123 plugin.register()
124 result = 1
125 else:
126 _log.error("plugin [%s] not loaded, see errors above", curr_plugin)
127 result = 1
128 except:
129 _log.exception('failed to load plugin %s', curr_plugin)
130 result = 0
131
132 if first_plugin is None:
133 first_plugin = plugin
134 prev_plugin = curr_plugin
135
136 progress_bar.Destroy()
137 wx.EndBusyCursor()
138
139
140 page = self.nb.GetPage(0)
141 page.Refresh()
142
143 return True
144
145
146
148 db_cfg = gmCfg.cCfgSQL()
149 default_plugin = db_cfg.get2 (
150 option = u'patient_search.plugin_to_raise_after_search',
151 workplace = gmSurgery.gmCurrentPractice().active_workplace,
152 bias = u'user',
153 default = u'gmEMRBrowserPlugin'
154 )
155 wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = default_plugin)
156
158 """Called before notebook page change is processed."""
159
160 _log.debug('just before switching notebook tabs')
161
162 self.__new_page_already_checked = False
163
164 self.__id_nb_page_before_switch = self.nb.GetSelection()
165 self.__id_evt_page_before_switch = event.GetOldSelection()
166 __id_evt_page_after_switch = event.GetSelection()
167
168 _log.debug('event.GetOldSelection()=%s* -> event.GetSelection()=%s', self.__id_evt_page_before_switch, __id_evt_page_after_switch)
169
170 if self.__id_evt_page_before_switch != self.__id_nb_page_before_switch:
171 _log.debug('the following two should match but do not:')
172 _log.debug(' event.GetOldSelection(): %s', self.__id_evt_page_before_switch)
173 _log.debug(' notebook.GetSelection(): %s', self.__id_nb_page_before_switch)
174
175
176 if __id_evt_page_after_switch == self.__id_evt_page_before_switch:
177
178
179
180 _log.debug('this system is: sys: [%s] wx: [%s]', sys.platform, wx.Platform)
181 _log.debug('it seems to be one of those platforms that have no clue which notebook page they are switching to')
182 _log.debug('(Windows is documented to return the old page from both evt.GetOldSelection() and evt.GetSelection())')
183 _log.debug('current notebook page : %s', self.__id_nb_page_before_switch)
184 _log.debug('source page from event: %s', self.__id_evt_page_before_switch)
185 _log.debug('target page from event: %s', __id_evt_page_after_switch)
186 _log.info('cannot check whether notebook page change needs to be vetoed')
187
188 pat = gmPerson.gmCurrentPatient()
189 if not pat.connected:
190 gmDispatcher.send(signal = 'statustext', msg =_('Cannot change notebook tabs. No active patient.'))
191 event.Veto()
192 return
193
194 event.Allow()
195 event.Skip()
196 return
197
198
199 new_page = self.__gb['horstspace.notebook.pages'][__id_evt_page_after_switch]
200 if not new_page.can_receive_focus():
201 _log.debug('veto()ing page change')
202 event.Veto()
203 return
204
205
206 self.__new_page_already_checked = True
207 event.Allow()
208 event.Skip()
209 return
210
212 """Called when notebook page changes."""
213
214 _log.debug('just after switching notebook tabs')
215
216 id_evt_page_before_switch = event.GetOldSelection()
217 id_evt_page_after_switch = event.GetSelection()
218 id_nb_page_after_switch = self.nb.GetSelection()
219
220 _log.debug('event.GetOldSelection()=%s -> event.GetSelection()=%s*', id_evt_page_before_switch, id_evt_page_after_switch)
221
222 if self.__id_nb_page_before_switch != id_evt_page_before_switch:
223 _log.debug('those two really *should* match:')
224 _log.debug(' wx.Notebook.GetSelection() (before switch) : %s' % self.__id_nb_page_before_switch)
225 _log.debug(' EVT_NOTEBOOK_PAGE_CHANGED.GetOldSelection(): %s' % id_evt_page_before_switch)
226
227 new_page = self.__gb['horstspace.notebook.pages'][id_evt_page_after_switch]
228
229
230 if self.__new_page_already_checked:
231 new_page.receive_focus()
232
233
234 self.__new_page_already_checked = False
235 event.Skip()
236 return
237
238
239 _log.debug('target page not checked for focussability yet')
240 _log.debug('EVT_NOTEBOOK_PAGE_CHANGED.GetOldSelection(): %s' % id_evt_page_before_switch)
241 _log.debug('EVT_NOTEBOOK_PAGE_CHANGED.GetSelection() : %s' % id_evt_page_after_switch)
242 _log.debug('wx.Notebook.GetSelection() (after switch) : %s' % id_nb_page_after_switch)
243
244
245 if new_page.can_receive_focus():
246 _log.debug('we are lucky: new page *can* receive focus')
247 new_page.receive_focus()
248
249
250 event.Skip()
251 return
252
253 _log.warning('new page cannot receive focus but too late for veto')
254 event.Skip()
255 return
256
258 evt.Skip()
259 return
260
261 load_menu = wx.Menu()
262 any_loadable = 0
263 plugin_list = gmPlugin.GetPluginLoadList('gui')
264 plugin = None
265 for plugin_name in plugin_list:
266 try:
267 plugin = gmPlugin.instantiate_plugin('gui', plugin_name)
268 except StandardError:
269 continue
270
271 if not isinstance(plugin, gmPlugin.cNotebookPlugin):
272 plugin = None
273 continue
274
275 if plugin.__class__.__name__ in self.guibroker['horstspace.notebook.gui'].keys():
276 plugin = None
277 continue
278
279 nid = wx.NewId()
280 load_menu.AppendItem(wx.MenuItem(load_menu, nid, plugin.name()))
281 wx.EVT_MENU(load_menu, nid, plugin.on_load)
282 any_loadable = 1
283
284 menu = wx.Menu()
285 ID_LOAD = wx.NewId()
286 ID_DROP = wx.NewId()
287 if any_loadable:
288 menu.AppendMenu(ID_LOAD, _('add plugin ...'), load_menu)
289 plugins = self.guibroker['horstspace.notebook.gui']
290 raised_plugin = plugins[self.nb.GetSelection()].name()
291 menu.AppendItem(wx.MenuItem(menu, ID_DROP, "drop [%s]" % raised_plugin))
292 wx.EVT_MENU (menu, ID_DROP, self._on_drop_plugin)
293 self.PopupMenu(menu, evt.GetPosition())
294 menu.Destroy()
295 evt.Skip()
296
298 """Unload plugin and drop from load list."""
299 pages = self.guibroker['horstspace.notebook.pages']
300 page = pages[self.nb.GetSelection()]
301 page.unregister()
302 self.nb.AdvanceSelection()
303
304
306 """Unload plugin but don't touch configuration."""
307
308 pages = self.guibroker['horstspace.notebook.pages']
309 page = pages[self.nb.GetSelection()]
310 page.unregister()
311
312 if __name__ == '__main__':
313 wx.InitAllImageHandlers()
314 pgbar = gmPluginLoadProgressBar(3)
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486