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
31 """GNUmed inner-frame layout manager.
32
33 This implements a Horst-space notebook-only
34 "inner-frame" layout manager.
35 """
37
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
48 self.nb = wx.Notebook (
49 parent=self,
50 id = -1,
51 size = wx.Size(320,240),
52 style = wx.NB_BOTTOM
53 )
54
55 self.__gb = gmGuiBroker.GuiBroker()
56 self.__gb['horstspace.notebook'] = self.nb
57
58
59
60
61
62
63
64 self.top_panel = gmTopPanel.cMainTopPanel(self, -1)
65 self.__gb['horstspace.top_panel'] = self.top_panel
66 self.__load_plugins()
67
68
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
74
75
76
77 self.__register_events()
78
79
80
82
83 self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self._on_notebook_page_changing)
84
85 self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self._on_notebook_page_changed)
86
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
92
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
103 progress_bar = gmPlugin.cLoadProgressBar(nr_plugins)
104
105
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
133 page = self.nb.GetPage(0)
134 page.Refresh()
135
136 return True
137
138
139
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
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
169 if __id_evt_page_after_switch == self.__id_evt_page_before_switch:
170
171
172
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
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
187 event.Allow()
188 event.Skip()
189 return
190
191
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
199 self.__new_page_already_checked = True
200 event.Allow()
201 event.Skip()
202 return
203
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
223 if self.__new_page_already_checked:
224 new_page.receive_focus()
225
226
227 self.__new_page_already_checked = False
228 event.Skip()
229 return
230
231
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
238 if new_page.can_receive_focus():
239 _log.debug('we are lucky: new page *can* receive focus')
240 new_page.receive_focus()
241
242
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
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
264 if not isinstance(plugin, gmPlugin.cNotebookPlugin):
265 plugin = None
266 continue
267
268 if plugin.__class__.__name__ in self.guibroker['horstspace.notebook.gui'].keys():
269 plugin = None
270 continue
271
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
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
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
297
299 """Unload plugin but don't touch configuration."""
300
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