| 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 !
261 #------------------------------------------------------------
263
264 if parent is None:
265 parent = wx.GetApp().GetTopWindow()
266
267 #-----------------------------------
268 def delete(workplace):
269
270 curr_workplace = gmSurgery.gmCurrentPractice().active_workplace
271 if workplace == curr_workplace:
272 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete the active workplace.'), beep = True)
273 return False
274
275 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
276 parent,
277 -1,
278 caption = _('Deleting workplace ...'),
279 question = _('Are you sure you want to delete this workplace ?\n\n "%s"\n') % workplace,
280 show_checkbox = True,
281 checkbox_msg = _('delete configuration, too'),
282 checkbox_tooltip = _(
283 'Check this if you want to delete all configuration items\n'
284 'for this workplace along with the workplace itself.'
285 ),
286 button_defs = [
287 {'label': _('Delete'), 'tooltip': _('Yes, delete this workplace.'), 'default': True},
288 {'label': _('Do NOT delete'), 'tooltip': _('No, do NOT delete this workplace'), 'default': False}
289 ]
290 )
291
292 decision = dlg.ShowModal()
293 if decision != wx.ID_YES:
294 dlg.Destroy()
295 return False
296
297 include_cfg = dlg.checkbox_is_checked()
298 dlg.Destroy()
299
300 dbo_conn = gmAuthWidgets.get_dbowner_connection(procedure = _('delete workplace'))
301 if not dbo_conn:
302 return False
303
304 gmSurgery.delete_workplace(workplace = workplace, conn = dbo_conn, delete_config = include_cfg)
305 return True
306 #-----------------------------------
307 def edit(workplace=None):
308
309 available_plugins = gmPlugin.get_installed_plugins(plugin_dir='gui')
310
311 dbcfg = gmCfg.cCfgSQL()
312
313 if workplace is None:
314 dlg = wx.TextEntryDialog (
315 parent = parent,
316 message = _('Enter a descriptive name for the new workplace:'),
317 caption = _('Configuring GNUmed workplaces ...'),
318 defaultValue = u'',
319 style = wx.OK | wx.CENTRE
320 )
321 dlg.ShowModal()
322 workplace = dlg.GetValue().strip()
323 if workplace == u'':
324 gmGuiHelpers.gm_show_error(_('Cannot save a new workplace without a name.'), _('Configuring GNUmed workplaces ...'))
325 return False
326 curr_plugins = []
327 choices = available_plugins
328 else:
329 curr_plugins = gmTools.coalesce(dbcfg.get2 (
330 option = u'horstspace.notebook.plugin_load_order',
331 workplace = workplace,
332 bias = 'workplace'
333 ), []
334 )
335 choices = curr_plugins[:]
336 for p in available_plugins:
337 if p not in choices:
338 choices.append(p)
339
340 sels = range(len(curr_plugins))
341 new_plugins = gmListWidgets.get_choices_from_list (
342 parent = parent,
343 msg = _(
344 '\n'
345 'Select the plugin(s) to be loaded the next time\n'
346 'the client is restarted under the workplace:\n'
347 '\n'
348 ' [%s]'
349 '\n'
350 ) % workplace,
351 caption = _('Configuring GNUmed workplaces ...'),
352 choices = choices,
353 selections = sels,
354 columns = [_('Plugins')],
355 single_selection = False
356 )
357
358 if new_plugins == curr_plugins:
359 return True
360
361 if new_plugins is None:
362 return True
363
364 dbcfg.set (
365 option = u'horstspace.notebook.plugin_load_order',
366 value = new_plugins,
367 workplace = workplace
368 )
369
370 return True
371 #-----------------------------------
372 def clone(workplace=None):
373 if workplace is None:
374 return False
375
376 new_name = wx.GetTextFromUser (
377 message = _('Enter a name for the new workplace !'),
378 caption = _('Cloning workplace'),
379 default_value = u'%s-2' % workplace,
380 parent = parent
381 ).strip()
382
383 if new_name == u'':
384 return False
385
386 dbcfg = gmCfg.cCfgSQL()
387 opt = u'horstspace.notebook.plugin_load_order'
388
389 plugins = dbcfg.get2 (
390 option = opt,
391 workplace = workplace,
392 bias = 'workplace'
393 )
394
395 dbcfg.set (
396 option = opt,
397 value = plugins,
398 workplace = new_name
399 )
400
401 # FIXME: clone cfg, too
402
403 return True
404 #-----------------------------------
405 def refresh(lctrl):
406 workplaces = gmSurgery.gmCurrentPractice().workplaces
407 curr_workplace = gmSurgery.gmCurrentPractice().active_workplace
408 try:
409 sels = [workplaces.index(curr_workplace)]
410 except ValueError:
411 sels = []
412
413 lctrl.set_string_items(workplaces)
414 lctrl.set_selections(selections = sels)
415 #-----------------------------------
416 gmListWidgets.get_choices_from_list (
417 parent = parent,
418 msg = _(
419 '\nSelect the workplace to configure below.\n'
420 '\n'
421 'The currently active workplace is preselected.\n'
422 ),
423 caption = _('Configuring GNUmed workplaces ...'),
424 columns = [_('Workplace')],
425 single_selection = True,
426 refresh_callback = refresh,
427 edit_callback = edit,
428 new_callback = edit,
429 delete_callback = delete,
430 left_extra_button = (_('Clone'), _('Clone the selected workplace'), clone)
431 )
432 #============================================================
433 -class cProviderInboxPnl(wxgProviderInboxPnl.wxgProviderInboxPnl, gmRegetMixin.cRegetOnPaintMixin):
434
435 _item_handlers = {}
436 _patient_msg_types = ['clinical.review docs', 'clinical.review results', 'clinical.review vaccs']
437 #--------------------------------------------------------
439
440 wxgProviderInboxPnl.wxgProviderInboxPnl.__init__(self, *args, **kwds)
441 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
442
443 self.provider = gmPerson.gmCurrentProvider()
444 self.filter_mode = 'all'
445 self.__init_ui()
446
447 cProviderInboxPnl._item_handlers['clinical.review docs'] = self._goto_doc_review
448 cProviderInboxPnl._item_handlers['clinical.review results'] = self._goto_measurements_review
449 cProviderInboxPnl._item_handlers['clinical.review vaccs'] = self._goto_vaccination_review
450
451 self.__register_interests()
452 #--------------------------------------------------------
453 # reget-on-paint API
454 #--------------------------------------------------------
458 #--------------------------------------------------------
459 # internal helpers
460 #--------------------------------------------------------
462 gmDispatcher.connect(signal = u'message_inbox_generic_mod_db', receiver = self._on_message_inbox_mod_db)
463 gmDispatcher.connect(signal = u'message_inbox_mod_db', receiver = self._on_message_inbox_mod_db)
464 # FIXME: listen for results insertion/deletion
465 gmDispatcher.connect(signal = u'reviewed_test_results_mod_db', receiver = self._on_message_inbox_mod_db)
466 # FIXME: listen for doc insertion/deletion
467 # FIXME: listen for doc reviews
468 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
469 #--------------------------------------------------------
471 self._LCTRL_provider_inbox.set_columns([u'', _('date'), _('category'), _('type'), _('message')])
472
473 msg = _('\n Inbox of %(title)s %(lname)s.\n') % {
474 'title': gmTools.coalesce (
475 self.provider['title'],
476 gmPerson.map_gender2salutation(self.provider['gender'])
477 ),
478 'lname': self.provider['lastnames']
479 }
480
481 self._msg_welcome.SetLabel(msg)
482
483 if gmPerson.gmCurrentPatient().connected:
484 self._RBTN_active_patient.Enable()
485 #--------------------------------------------------------
487
488 """Fill UI with data."""
489 self.__msgs = self.provider.inbox.messages
490
491 if self.filter_mode == 'active':
492 if gmPerson.gmCurrentPatient().connected:
493 curr_pat_id = gmPerson.gmCurrentPatient().ID
494 self.__msgs = [ m for m in self.__msgs if m['pk_patient'] == curr_pat_id ]
495 else:
496 self.__msgs = []
497
498 items = [
499 [
500 _indicator[m['importance']],
501 m['received_when'].strftime('%Y-%m-%d'),
502 m['l10n_category'],
503 m['l10n_type'],
504 m['comment']
505 ] for m in self.__msgs
506 ]
507 self._LCTRL_provider_inbox.set_string_items(items = items)
508 self._LCTRL_provider_inbox.set_data(data = self.__msgs)
509 self._LCTRL_provider_inbox.set_column_widths()
510 #--------------------------------------------------------
511 # event handlers
512 #--------------------------------------------------------
516 #--------------------------------------------------------
518 wx.CallAfter(self._schedule_data_reget)
519 gmDispatcher.send(signal = u'request_user_attention', msg = _('Please check your GNUmed Inbox !'))
520 #--------------------------------------------------------
522 msg = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
523 if msg is None:
524 return
525
526 handler_key = '%s.%s' % (msg['category'], msg['type'])
527 try:
528 handle_item = cProviderInboxPnl._item_handlers[handler_key]
529 except KeyError:
530 gmGuiHelpers.gm_show_warning (
531 _(
532 """No double-click action pre-programmed into
533 GNUmed for message category and type:
534
535 [%s]
536 """
537 ) % handler_key,
538 _('handling provider inbox item')
539 )
540 return False
541
542 if not handle_item(pk_context = msg['pk_context'], pk_patient = msg['pk_patient']):
543 _log.error('item handler returned "false"')
544 _log.error('handler key: [%s]', handler_key)
545 _log.error('message: %s', str(msg))
546 return False
547
548 return True
549 #--------------------------------------------------------
552 #--------------------------------------------------------
554 msg = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
555 if msg is None:
556 return
557
558 if msg['data'] is None:
559 tmp = _('Message: %s') % msg['comment']
560 else:
561 tmp = _('Message: %s\nData: %s') % (msg['comment'], msg['data'])
562
563 self._TXT_inbox_item_comment.SetValue(tmp)
564 #--------------------------------------------------------
566 tmp = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
567 if tmp is None:
568 return
569 self.__focussed_msg = tmp
570
571 # build menu
572 menu = wx.Menu(title = _('Inbox Message menu'))
573 # - delete message
574 if not self.__focussed_msg['is_virtual']:
575 ID = wx.NewId()
576 menu.AppendItem(wx.MenuItem(menu, ID, _('delete message')))
577 wx.EVT_MENU(menu, ID, self._on_delete_focussed_msg)
578
579 # show menu
580 self.PopupMenu(menu, wx.DefaultPosition)
581 menu.Destroy()
582 #--------------------------------------------------------
587 #--------------------------------------------------------
592 #--------------------------------------------------------
593 # item handlers
594 #--------------------------------------------------------
596 if self.__focussed_msg['is_virtual']:
597 gmDispatcher.send(signal = 'statustext', msg = _('You must deal with the reason for this message to remove it from your inbox.'), beep = True)
598 return False
599
600 if not self.provider.inbox.delete_message(self.__focussed_msg['pk_message_inbox']):
601 gmDispatcher.send(signal='statustext', msg=_('Problem removing message from Inbox.'))
602 return False
603 return True
604 #--------------------------------------------------------
606 wx.BeginBusyCursor()
607
608 try:
609 pat = gmPerson.cIdentity(aPK_obj = pk_patient)
610 except gmExceptions.ConstructorError:
611 wx.EndBusyCursor()
612 _log.exception('patient [%s] not found', pk_patient)
613 gmGuiHelpers.gm_show_error (
614 _('Supposedly there are unreviewed documents\n'
615 'for patient [%s]. However, I cannot find\n'
616 'that patient in the GNUmed database.'
617 ) % pk_patient,
618 _('handling provider inbox item')
619 )
620 return False
621
622 success = gmPatSearchWidgets.set_active_patient(patient = pat)
623
624 wx.EndBusyCursor()
625
626 if not success:
627 gmGuiHelpers.gm_show_error (
628 _('Supposedly there are unreviewed documents\n'
629 'for patient [%s]. However, I cannot find\n'
630 'that patient in the GNUmed database.'
631 ) % pk_patient,
632 _('handling provider inbox item')
633 )
634 return False
635
636 wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = 'gmShowMedDocs', sort_mode = 'review')
637 return True
638 #--------------------------------------------------------
640 wx.BeginBusyCursor()
641 success = gmPatSearchWidgets.set_active_patient(patient=gmPerson.cIdentity(aPK_obj=pk_patient))
642 wx.EndBusyCursor()
643 if not success:
644 gmGuiHelpers.gm_show_error (
645 _('Supposedly there are unreviewed results\n'
646 'for patient [%s]. However, I cannot find\n'
647 'that patient in the GNUmed database.'
648 ) % pk_patient,
649 _('handling provider inbox item')
650 )
651 return False
652
653 wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = 'gmMeasurementsGridPlugin')
654 return True
655 #--------------------------------------------------------
657 wx.BeginBusyCursor()
658 success = gmPatSearchWidgets.set_active_patient(patient = gmPerson.cIdentity(aPK_obj = pk_patient))
659 wx.EndBusyCursor()
660 if not success:
661 gmGuiHelpers.gm_show_error (
662 _('Supposedly there are conflicting vaccinations\n'
663 'for patient [%s]. However, I cannot find\n'
664 'that patient in the GNUmed database.'
665 ) % pk_patient,
666 _('handling provider inbox item')
667 )
668 return False
669
670 wx.CallAfter(gmVaccWidgets.manage_vaccinations)
671
672 return True
673 #============================================================
674 if __name__ == '__main__':
675
676 gmI18N.activate_locale()
677 gmI18N.install_domain(domain = 'gnumed')
678
682
684 app = wx.PyWidgetTester(size = (800, 600))
685 app.SetWidget(cProviderInboxPnl, -1)
686 app.MainLoop()
687
688 if len(sys.argv) > 1 and sys.argv[1] == 'test':
689 #test_configure_wp_plugins()
690 test_message_inbox()
691
692 #============================================================
693
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Nov 29 04:04:51 2010 | http://epydoc.sourceforge.net |