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
31 -class cTextExpansionEditAreaPnl(wxgTextExpansionEditAreaPnl.wxgTextExpansionEditAreaPnl):
32
33 - def __init__(self, *args, **kwds):
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
68
69
70
71
73 self._TCTRL_keyword.Bind(wx.EVT_TEXT, self._on_keyword_modified)
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
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
100 - def __init_ui(self, keyword=None):
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
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
205
218
219
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
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
261
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
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
452
453
454
456 self.__populate_inbox()
457 return True
458
459
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
465 gmDispatcher.connect(signal = u'reviewed_test_results_mod_db', receiver = self._on_message_inbox_mod_db)
466
467
468 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
469
485
510
511
512
514 wx.CallAfter(self._schedule_data_reget)
515 wx.CallAfter(self._RBTN_active_patient.Enable)
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
572 menu = wx.Menu(title = _('Inbox Message menu'))
573
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
580 self.PopupMenu(menu, wx.DefaultPosition)
581 menu.Destroy()
582
587
592
593
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
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
690 test_message_inbox()
691
692
693