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