| Home | Trees | Indices | Help |
|
|---|
|
|
1 """GNUmed provider inbox handling widgets.
2 """
3 #================================================================
4 __version__ = "$Revision: 1.48 $"
5 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
6
7 import sys, logging
8
9
10 import wx
11
12
13 if __name__ == '__main__':
14 sys.path.insert(0, '../../')
15 from Gnumed.pycommon import gmI18N, gmDispatcher, gmTools, gmCfg, gmPG2, gmExceptions
16 from Gnumed.business import gmPerson, gmSurgery
17 from Gnumed.wxpython import gmGuiHelpers, gmListWidgets, gmPlugin, gmRegetMixin, gmPhraseWheel
18 from Gnumed.wxpython import gmEditArea, gmAuthWidgets, gmPatSearchWidgets, gmVaccWidgets, gmCfgWidgets
19 from Gnumed.wxGladeWidgets import wxgProviderInboxPnl, wxgTextExpansionEditAreaPnl
20
21
22 _log = logging.getLogger('gm.ui')
23 _log.info(__version__)
24
25 _indicator = {
26 -1: '',
27 0: '',
28 1: '*!!*'
29 }
30 #============================================================
32
34
35 try:
36 self.__keyword = kwds['keyword']
37 del kwds['keyword']
38 except KeyError:
39 self.__keyword = None
40
41 wxgTextExpansionEditAreaPnl.wxgTextExpansionEditAreaPnl.__init__(self, *args, **kwds)
42
43 self.__init_ui()
44 self.__register_interests()
45 #--------------------------------------------------------
47 if not self.__valid_for_save():
48 return False
49
50 if self.__keyword is None:
51 result = gmPG2.add_text_expansion (
52 keyword = self._TCTRL_keyword.GetValue().strip(),
53 expansion = self._TCTRL_expansion.GetValue(),
54 public = self._RBTN_public.GetValue()
55 )
56 else:
57 gmPG2.edit_text_expansion (
58 keyword = self._TCTRL_keyword.GetValue().strip(),
59 expansion = self._TCTRL_expansion.GetValue()
60 )
61 result = True
62
63 return result
64 #--------------------------------------------------------
67 # if self.__keyword is not None:
68 # self._TCTRL_expansion.SetValue(u'')
69 #--------------------------------------------------------
70 # event handling
71 #--------------------------------------------------------
74 #--------------------------------------------------------
76 if self._TCTRL_keyword.GetValue().strip() == u'':
77 self._TCTRL_expansion.Enable(False)
78 else:
79 self._TCTRL_expansion.Enable(True)
80 #--------------------------------------------------------
81 # internal API
82 #--------------------------------------------------------
84
85 kwd = self._TCTRL_keyword.GetValue().strip()
86 if kwd == u'':
87 self._TCTRL_keyword.SetBackgroundColour('pink')
88 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save text expansion without keyword.'), beep = True)
89 return False
90 self._TCTRL_keyword.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
91
92 if self._TCTRL_expansion.GetValue().strip() == u'':
93 self._TCTRL_expansion.SetBackgroundColour('pink')
94 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save text expansion without expansion text.'), beep = True)
95 return False
96 self._TCTRL_expansion.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
97
98 return True
99 #--------------------------------------------------------
101
102 if keyword is not None:
103 self.__keyword = keyword
104
105 if self.__keyword is None:
106 self._TCTRL_keyword.SetValue(u'')
107 self._TCTRL_keyword.Enable(True)
108 self._TCTRL_expansion.SetValue(u'')
109 self._TCTRL_expansion.Enable(False)
110 self._RBTN_public.Enable(True)
111 self._RBTN_private.Enable(True)
112 self._RBTN_public.SetValue(1)
113 else:
114 expansion = gmPG2.expand_keyword(keyword = self.__keyword)
115 self._TCTRL_keyword.SetValue(self.__keyword)
116 self._TCTRL_keyword.Enable(False)
117 self._TCTRL_expansion.SetValue(gmTools.coalesce(expansion, u''))
118 self._TCTRL_expansion.Enable(True)
119 self._RBTN_public.Enable(False)
120 self._RBTN_private.Enable(False)
121 #============================================================
123
124 if parent is None:
125 parent = wx.GetApp().GetTopWindow()
126
127 #----------------------
128 def delete(keyword=None):
129 gmPG2.delete_text_expansion(keyword = keyword)
130 return True
131 #----------------------
132 def edit(keyword=None):
133 # add new keyword
134 ea = cTextExpansionEditAreaPnl(parent, -1, keyword=keyword)
135 dlg = gmEditArea.cGenericEditAreaDlg(parent, -1, edit_area = ea)
136 dlg.SetTitle (
137 gmTools.coalesce(keyword, _('Adding text expansion'), _('Editing text expansion "%s"'))
138 )
139 if dlg.ShowModal() == wx.ID_OK:
140 return True
141
142 return False
143 #----------------------
144 def refresh(lctrl=None):
145 kwds = [ [
146 r[0],
147 gmTools.bool2subst(r[1], gmTools.u_checkmark_thick, u''),
148 gmTools.bool2subst(r[2], gmTools.u_checkmark_thick, u''),
149 r[3]
150 ] for r in gmPG2.get_text_expansion_keywords()
151 ]
152 data = [ r[0] for r in gmPG2.get_text_expansion_keywords() ]
153 lctrl.set_string_items(kwds)
154 lctrl.set_data(data)
155 #----------------------
156
157 gmListWidgets.get_choices_from_list (
158 parent = parent,
159 msg = _('\nSelect the keyword you want to edit !\n'),
160 caption = _('Editing keyword-based text expansions ...'),
161 columns = [_('Keyword'), _('Public'), _('Private'), _('Owner')],
162 single_selection = True,
163 edit_callback = edit,
164 new_callback = edit,
165 delete_callback = delete,
166 refresh_callback = refresh
167 )
168 #============================================================
170
171 if parent is None:
172 parent = wx.GetApp().GetTopWindow()
173
174 staff = gmPerson.get_staff_list()
175 choices = [ [
176 s[u'short_alias'],
177 u'%s%s %s' % (
178 gmTools.coalesce(s['title'], u'', u'%s '),
179 s['firstnames'],
180 s['lastnames']
181 ),
182 s['role'],
183 gmTools.coalesce(s['comment'], u'')
184 ]
185 for s in staff
186 if s['is_active'] is True
187 ]
188 data = [ s['pk_staff'] for s in staff if s['is_active'] is True ]
189
190 gmCfgWidgets.configure_string_from_list_option (
191 parent = parent,
192 message = _(
193 '\n'
194 'Please select the provider to fall back to in case\n'
195 'no primary provider is configured for a patient.\n'
196 ),
197 option = 'patient.fallback_primary_provider',
198 bias = 'user',
199 default_value = None,
200 choices = choices,
201 columns = [_('Alias'), _('Provider'), _('Role'), _('Comment')],
202 data = data,
203 caption = _('Configuring fallback primary provider')
204 )
205 #============================================================
207
209
210 gmPhraseWheel.cPhraseWheel.__init__ (
211 self,
212 *args,
213 **kwargs
214 )
215 self.matcher = gmPerson.cMatchProvider_Provider()
216 self.SetToolTipString(_('Select a healthcare provider.'))
217 self.selection_only = True
218 #============================================================
219 # practice related widgets
220 #============================================================
222
223 if parent is None:
224 parent = wx.GetApp().GetTopWindow()
225
226 #-----------------------------------
227 def refresh(lctrl):
228
229 cmd = u'SELECT * FROM audit.v_audit_trail ORDER BY audit_when_ts'
230 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
231
232
233
234 lctrl.set_string_items (
235 [ [
236 r['event_when'],
237 r['event_by'],
238 u'%s %s %s' % (
239 gmTools.coalesce(r['row_version_before'], gmTools.u_diameter),
240 gmTools.u_right_arrow,
241 gmTools.coalesce(r['row_version_after'], gmTools.u_diameter)
242 ),
243 r['event_table'],
244 r['event'],
245 r['pk_audit']
246 ] for r in rows ]
247 )
248 #lctrl.set_selections(selections = sels)
249 #-----------------------------------
250 gmListWidgets.get_choices_from_list (
251 parent = parent,
252 msg = u'',
253 caption = _('GNUmed database audit log ...'),
254 columns = [ _('When'), _('Who'), _('Revisions'), _('Table'), _('Event'), '#' ],
255 single_selection = True,
256 refresh_callback = refresh
257 )
258
259 #============================================================
260 # FIXME: this should be moved elsewhere !
262
263 if parent is None:
264 parent = wx.GetApp().GetTopWindow()
265
266 #-----------------------------------
267 def delete(workplace):
268
269 curr_workplace = gmSurgery.gmCurrentPractice().active_workplace
270 if workplace == curr_workplace:
271 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete the active workplace.'), beep = True)
272 return False
273
274 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
275 parent,
276 -1,
277 caption = _('Deleting workplace ...'),
278 question = _('Are you sure you want to delete this workplace ?\n\n "%s"\n') % workplace,
279 show_checkbox = True,
280 checkbox_msg = _('delete configuration, too'),
281 checkbox_tooltip = _(
282 'Check this if you want to delete all configuration items\n'
283 'for this workplace along with the workplace itself.'
284 ),
285 button_defs = [
286 {'label': _('Delete'), 'tooltip': _('Yes, delete this workplace.'), 'default': True},
287 {'label': _('Do NOT delete'), 'tooltip': _('No, do NOT delete this workplace'), 'default': False}
288 ]
289 )
290
291 decision = dlg.ShowModal()
292 if decision != wx.ID_YES:
293 dlg.Destroy()
294 return False
295
296 include_cfg = dlg.checkbox_is_checked()
297 dlg.Destroy()
298
299 dbo_conn = gmAuthWidgets.get_dbowner_connection(procedure = _('delete workplace'))
300 if not dbo_conn:
301 return False
302
303 gmSurgery.delete_workplace(workplace = workplace, conn = dbo_conn, delete_config = include_cfg)
304 return True
305 #-----------------------------------
306 def edit(workplace=None):
307
308 available_plugins = gmPlugin.get_installed_plugins(plugin_dir='gui')
309
310 dbcfg = gmCfg.cCfgSQL()
311
312 if workplace is None:
313 dlg = wx.TextEntryDialog (
314 parent = parent,
315 message = _('Enter a descriptive name for the new workplace:'),
316 caption = _('Configuring GNUmed workplaces ...'),
317 defaultValue = u'',
318 style = wx.OK | wx.CENTRE
319 )
320 dlg.ShowModal()
321 workplace = dlg.GetValue().strip()
322 if workplace == u'':
323 gmGuiHelpers.gm_show_error(_('Cannot save a new workplace without a name.'), _('Configuring GNUmed workplaces ...'))
324 return False
325 curr_plugins = []
326 choices = available_plugins
327 else:
328 curr_plugins = gmTools.coalesce(dbcfg.get2 (
329 option = u'horstspace.notebook.plugin_load_order',
330 workplace = workplace,
331 bias = 'workplace'
332 ), []
333 )
334 choices = curr_plugins[:]
335 for p in available_plugins:
336 if p not in choices:
337 choices.append(p)
338
339 sels = range(len(curr_plugins))
340 new_plugins = gmListWidgets.get_choices_from_list (
341 parent = parent,
342 msg = _(
343 '\n'
344 'Select the plugin(s) to be loaded the next time\n'
345 'the client is restarted under the workplace:\n'
346 '\n'
347 ' [%s]'
348 '\n'
349 ) % workplace,
350 caption = _('Configuring GNUmed workplaces ...'),
351 choices = choices,
352 selections = sels,
353 columns = [_('Plugins')],
354 single_selection = False
355 )
356
357 if new_plugins == curr_plugins:
358 return True
359
360 if new_plugins is None:
361 return True
362
363 dbcfg.set (
364 option = u'horstspace.notebook.plugin_load_order',
365 value = new_plugins,
366 workplace = workplace
367 )
368
369 return True
370 #-----------------------------------
371 def refresh(lctrl):
372 workplaces = gmSurgery.gmCurrentPractice().workplaces
373 curr_workplace = gmSurgery.gmCurrentPractice().active_workplace
374 try:
375 sels = [workplaces.index(curr_workplace)]
376 except ValueError:
377 sels = []
378
379 lctrl.set_string_items(workplaces)
380 lctrl.set_selections(selections = sels)
381 #-----------------------------------
382 gmListWidgets.get_choices_from_list (
383 parent = parent,
384 msg = _(
385 '\nSelect the workplace to configure below.\n'
386 '\n'
387 'The currently active workplace is preselected.\n'
388 ),
389 caption = _('Configuring GNUmed workplaces ...'),
390 columns = [_('Workplace')],
391 single_selection = True,
392 refresh_callback = refresh,
393 edit_callback = edit,
394 new_callback = edit,
395 delete_callback = delete
396 )
397 #============================================================
398 -class cProviderInboxPnl(wxgProviderInboxPnl.wxgProviderInboxPnl, gmRegetMixin.cRegetOnPaintMixin):
399
400 _item_handlers = {}
401 _patient_msg_types = ['clinical.review docs', 'clinical.review results', 'clinical.review vaccs']
402 #--------------------------------------------------------
404
405 wxgProviderInboxPnl.wxgProviderInboxPnl.__init__(self, *args, **kwds)
406 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
407
408 self.provider = gmPerson.gmCurrentProvider()
409 self.filter_mode = 'all'
410 self.__init_ui()
411
412 cProviderInboxPnl._item_handlers['clinical.review docs'] = self._goto_doc_review
413 cProviderInboxPnl._item_handlers['clinical.review results'] = self._goto_measurements_review
414 cProviderInboxPnl._item_handlers['clinical.review vaccs'] = self._goto_vaccination_review
415
416 self.__register_interests()
417 #--------------------------------------------------------
418 # reget-on-paint API
419 #--------------------------------------------------------
423 #--------------------------------------------------------
424 # internal helpers
425 #--------------------------------------------------------
427 gmDispatcher.connect(signal = u'message_inbox_generic_mod_db', receiver = self._on_message_inbox_mod_db)
428 gmDispatcher.connect(signal = u'message_inbox_mod_db', receiver = self._on_message_inbox_mod_db)
429 # FIXME: listen for results insertion/deletion
430 gmDispatcher.connect(signal = u'reviewed_test_results_mod_db', receiver = self._on_message_inbox_mod_db)
431 # FIXME: listen for doc insertion/deletion
432 # FIXME: listen for doc reviews
433 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
434 #--------------------------------------------------------
436 self._LCTRL_provider_inbox.set_columns([u'', _('date'), _('category'), _('type'), _('message')])
437
438 msg = _('\n Inbox of %(title)s %(lname)s.\n') % {
439 'title': gmTools.coalesce (
440 self.provider['title'],
441 gmPerson.map_gender2salutation(self.provider['gender'])
442 ),
443 'lname': self.provider['lastnames']
444 }
445
446 self._msg_welcome.SetLabel(msg)
447
448 if gmPerson.gmCurrentPatient().connected:
449 self._RBTN_active_patient.Enable()
450 #--------------------------------------------------------
452
453 """Fill UI with data."""
454 self.__msgs = self.provider.inbox.messages
455
456 if self.filter_mode == 'active':
457 if gmPerson.gmCurrentPatient().connected:
458 curr_pat_id = gmPerson.gmCurrentPatient().ID
459 self.__msgs = [ m for m in self.__msgs if m['pk_patient'] == curr_pat_id ]
460 else:
461 self.__msgs = []
462
463 items = [
464 [
465 _indicator[m['importance']],
466 m['received_when'].strftime('%Y-%m-%d'),
467 m['l10n_category'],
468 m['l10n_type'],
469 m['comment']
470 ] for m in self.__msgs
471 ]
472 self._LCTRL_provider_inbox.set_string_items(items = items)
473 self._LCTRL_provider_inbox.set_data(data = self.__msgs)
474 self._LCTRL_provider_inbox.set_column_widths()
475 #--------------------------------------------------------
476 # event handlers
477 #--------------------------------------------------------
481 #--------------------------------------------------------
483 wx.CallAfter(self._schedule_data_reget)
484 gmDispatcher.send(signal = u'request_user_attention', msg = _('Please check your GNUmed Inbox !'))
485 #--------------------------------------------------------
487 msg = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
488 if msg is None:
489 return
490
491 handler_key = '%s.%s' % (msg['category'], msg['type'])
492 try:
493 handle_item = cProviderInboxPnl._item_handlers[handler_key]
494 except KeyError:
495 gmGuiHelpers.gm_show_warning (
496 _(
497 """No double-click action pre-programmed into
498 GNUmed for message category and type:
499
500 [%s]
501 """
502 ) % handler_key,
503 _('handling provider inbox item')
504 )
505 return False
506
507 if not handle_item(pk_context = msg['pk_context'], pk_patient = msg['pk_patient']):
508 _log.error('item handler returned "false"')
509 _log.error('handler key: [%s]', handler_key)
510 _log.error('message: %s', str(msg))
511 return False
512
513 return True
514 #--------------------------------------------------------
517 #--------------------------------------------------------
519 msg = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
520 if msg is None:
521 return
522
523 if msg['data'] is None:
524 tmp = _('Message: %s') % msg['comment']
525 else:
526 tmp = _('Message: %s\nData: %s') % (msg['comment'], msg['data'])
527
528 self._TXT_inbox_item_comment.SetValue(tmp)
529 #--------------------------------------------------------
531 tmp = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
532 if tmp is None:
533 return
534 self.__focussed_msg = tmp
535
536 # build menu
537 menu = wx.Menu(title = _('Inbox Message menu'))
538 # - delete message
539 if not self.__focussed_msg['is_virtual']:
540 ID = wx.NewId()
541 menu.AppendItem(wx.MenuItem(menu, ID, _('delete message')))
542 wx.EVT_MENU(menu, ID, self._on_delete_focussed_msg)
543
544 # show menu
545 self.PopupMenu(menu, wx.DefaultPosition)
546 menu.Destroy()
547 #--------------------------------------------------------
552 #--------------------------------------------------------
557 #--------------------------------------------------------
558 # item handlers
559 #--------------------------------------------------------
561 if self.__focussed_msg['is_virtual']:
562 gmDispatcher.send(signal = 'statustext', msg = _('You must deal with the reason for this message to remove it from your inbox.'), beep = True)
563 return False
564
565 if not self.provider.inbox.delete_message(self.__focussed_msg['pk_message_inbox']):
566 gmDispatcher.send(signal='statustext', msg=_('Problem removing message from Inbox.'))
567 return False
568 return True
569 #--------------------------------------------------------
571 wx.BeginBusyCursor()
572
573 try:
574 pat = gmPerson.cIdentity(aPK_obj = pk_patient)
575 except gmExceptions.ConstructorError:
576 wx.EndBusyCursor()
577 _log.exception('patient [%s] not found', pk_patient)
578 gmGuiHelpers.gm_show_error (
579 _('Supposedly there are unreviewed documents\n'
580 'for patient [%s]. However, I cannot find\n'
581 'that patient in the GNUmed database.'
582 ) % pk_patient,
583 _('handling provider inbox item')
584 )
585 return False
586
587 success = gmPatSearchWidgets.set_active_patient(patient = pat)
588
589 wx.EndBusyCursor()
590
591 if not success:
592 gmGuiHelpers.gm_show_error (
593 _('Supposedly there are unreviewed documents\n'
594 'for patient [%s]. However, I cannot find\n'
595 'that patient in the GNUmed database.'
596 ) % pk_patient,
597 _('handling provider inbox item')
598 )
599 return False
600
601 wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = 'gmShowMedDocs', sort_mode = 'review')
602 return True
603 #--------------------------------------------------------
605 wx.BeginBusyCursor()
606 success = gmPatSearchWidgets.set_active_patient(patient=gmPerson.cIdentity(aPK_obj=pk_patient))
607 wx.EndBusyCursor()
608 if not success:
609 gmGuiHelpers.gm_show_error (
610 _('Supposedly there are unreviewed results\n'
611 'for patient [%s]. However, I cannot find\n'
612 'that patient in the GNUmed database.'
613 ) % pk_patient,
614 _('handling provider inbox item')
615 )
616 return False
617
618 wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = 'gmMeasurementsGridPlugin')
619 return True
620 #--------------------------------------------------------
622 wx.BeginBusyCursor()
623 success = gmPatSearchWidgets.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = pk_patient))
624 wx.EndBusyCursor()
625 if not success:
626 gmGuiHelpers.gm_show_error (
627 _('Supposedly there are conflicting vaccinations\n'
628 'for patient [%s]. However, I cannot find\n'
629 'that patient in the GNUmed database.'
630 ) % pk_patient,
631 _('handling provider inbox item')
632 )
633 return False
634
635 wx.CallAfter(gmVaccWidgets.manage_vaccinations)
636
637 return True
638 #============================================================
639 if __name__ == '__main__':
640
641 gmI18N.activate_locale()
642 gmI18N.install_domain(domain = 'gnumed')
643
647
649 app = wx.PyWidgetTester(size = (800, 600))
650 app.SetWidget(cProviderInboxPnl, -1)
651 app.MainLoop()
652
653 if len(sys.argv) > 1 and sys.argv[1] == 'test':
654 #test_configure_wp_plugins()
655 test_message_inbox()
656
657 #============================================================
658
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Thu Sep 9 04:08:10 2010 | http://epydoc.sourceforge.net |