1 """GNUmed provider inbox handling widgets.
2 """
3
4
5
6 __version__ = "$Revision: 1.48 $"
7 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
8
9 import sys, logging
10
11
12 import wx
13
14
15 if __name__ == '__main__':
16 sys.path.insert(0, '../../')
17 from Gnumed.pycommon import gmI18N, gmDispatcher, gmTools, gmCfg, gmPG2, gmExceptions
18 from Gnumed.business import gmPerson, gmSurgery
19 from Gnumed.wxpython import gmGuiHelpers, gmListWidgets, gmPlugin, gmRegetMixin, gmPhraseWheel, gmEditArea, gmAuthWidgets, gmPatSearchWidgets
20 from Gnumed.wxGladeWidgets import wxgProviderInboxPnl, wxgTextExpansionEditAreaPnl
21
22
23 _log = logging.getLogger('gm.ui')
24 _log.info(__version__)
25
26 _indicator = {
27 -1: '',
28 0: '',
29 1: '!'
30 }
31
32 -class cTextExpansionEditAreaPnl(wxgTextExpansionEditAreaPnl.wxgTextExpansionEditAreaPnl):
33
34 - def __init__(self, *args, **kwds):
35
36 try:
37 self.__keyword = kwds['keyword']
38 del kwds['keyword']
39 except KeyError:
40 self.__keyword = None
41
42 wxgTextExpansionEditAreaPnl.wxgTextExpansionEditAreaPnl.__init__(self, *args, **kwds)
43
44 self.__init_ui()
45 self.__register_interests()
46
48 if not self.__valid_for_save():
49 return False
50
51 if self.__keyword is None:
52 result = gmPG2.add_text_expansion (
53 keyword = self._TCTRL_keyword.GetValue().strip(),
54 expansion = self._TCTRL_expansion.GetValue(),
55 public = self._RBTN_public.GetValue()
56 )
57 else:
58 gmPG2.edit_text_expansion (
59 keyword = self._TCTRL_keyword.GetValue().strip(),
60 expansion = self._TCTRL_expansion.GetValue()
61 )
62 result = True
63
64 return result
65
68
69
70
71
72
74 self._TCTRL_keyword.Bind(wx.EVT_TEXT, self._on_keyword_modified)
75
77 if self._TCTRL_keyword.GetValue().strip() == u'':
78 self._TCTRL_expansion.Enable(False)
79 else:
80 self._TCTRL_expansion.Enable(True)
81
82
83
85
86 kwd = self._TCTRL_keyword.GetValue().strip()
87 if kwd == u'':
88 self._TCTRL_keyword.SetBackgroundColour('pink')
89 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save text expansion without keyword.'), beep = True)
90 return False
91 self._TCTRL_keyword.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
92
93 if self._TCTRL_expansion.GetValue().strip() == u'':
94 self._TCTRL_expansion.SetBackgroundColour('pink')
95 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save text expansion without expansion text.'), beep = True)
96 return False
97 self._TCTRL_expansion.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
98
99 return True
100
101 - def __init_ui(self, keyword=None):
102
103 if keyword is not None:
104 self.__keyword = keyword
105
106 if self.__keyword is None:
107 self._TCTRL_keyword.SetValue(u'')
108 self._TCTRL_keyword.Enable(True)
109 self._TCTRL_expansion.SetValue(u'')
110 self._TCTRL_expansion.Enable(False)
111 self._RBTN_public.Enable(True)
112 self._RBTN_private.Enable(True)
113 self._RBTN_public.SetValue(1)
114 else:
115 expansion = gmPG2.expand_keyword(keyword = self.__keyword)
116 self._TCTRL_keyword.SetValue(self.__keyword)
117 self._TCTRL_keyword.Enable(False)
118 self._TCTRL_expansion.SetValue(gmTools.coalesce(expansion, u''))
119 self._TCTRL_expansion.Enable(True)
120 self._RBTN_public.Enable(False)
121 self._RBTN_private.Enable(False)
122
124
125 if parent is None:
126 parent = wx.GetApp().GetTopWindow()
127
128
129 def delete(keyword=None):
130 gmPG2.delete_text_expansion(keyword = keyword)
131 return True
132
133 def edit(keyword=None):
134
135 ea = cTextExpansionEditAreaPnl(parent, -1, keyword=keyword)
136 dlg = gmEditArea.cGenericEditAreaDlg(parent, -1, edit_area = ea)
137 dlg.SetTitle (
138 gmTools.coalesce(keyword, _('Adding text expansion'), _('Editing text expansion "%s"'))
139 )
140 if dlg.ShowModal() == wx.ID_OK:
141 return True
142
143 return False
144
145 def refresh(lctrl=None):
146 kwds = [ [
147 r[0],
148 gmTools.bool2subst(r[1], gmTools.u_checkmark_thick, u''),
149 gmTools.bool2subst(r[2], gmTools.u_checkmark_thick, u''),
150 r[3]
151 ] for r in gmPG2.get_text_expansion_keywords()
152 ]
153 data = [ r[0] for r in gmPG2.get_text_expansion_keywords() ]
154 lctrl.set_string_items(kwds)
155 lctrl.set_data(data)
156
157
158 gmListWidgets.get_choices_from_list (
159 parent = parent,
160 msg = _('\nSelect the keyword you want to edit !\n'),
161 caption = _('Editing keyword-based text expansions ...'),
162 columns = [_('Keyword'), _('Public'), _('Private'), _('Owner')],
163 single_selection = True,
164 edit_callback = edit,
165 new_callback = edit,
166 delete_callback = delete,
167 refresh_callback = refresh
168 )
169
182
183
184
185
230
231 def edit(workplace=None):
232
233 available_plugins = gmPlugin.get_installed_plugins(plugin_dir='gui')
234
235 dbcfg = gmCfg.cCfgSQL()
236
237 if workplace is None:
238 dlg = wx.TextEntryDialog (
239 parent = parent,
240 message = _('Enter a descriptive name for the new workplace:'),
241 caption = _('Configuring GNUmed workplaces ...'),
242 defaultValue = u'',
243 style = wx.OK | wx.CENTRE
244 )
245 dlg.ShowModal()
246 workplace = dlg.GetValue().strip()
247 if workplace == u'':
248 gmGuiHelpers.gm_show_error(_('Cannot save a new workplace without a name.'), _('Configuring GNUmed workplaces ...'))
249 return False
250 curr_plugins = []
251 choices = available_plugins
252 else:
253 curr_plugins = gmTools.coalesce(dbcfg.get2 (
254 option = u'horstspace.notebook.plugin_load_order',
255 workplace = workplace,
256 bias = 'workplace'
257 ), []
258 )
259 choices = curr_plugins[:]
260 for p in available_plugins:
261 if p not in choices:
262 choices.append(p)
263
264 sels = range(len(curr_plugins))
265 new_plugins = gmListWidgets.get_choices_from_list (
266 parent = parent,
267 msg = _(
268 '\n'
269 'Select the plugin(s) to be loaded the next time\n'
270 'the client is restarted under the workplace:\n'
271 '\n'
272 ' [%s]'
273 '\n'
274 ) % workplace,
275 caption = _('Configuring GNUmed workplaces ...'),
276 choices = choices,
277 selections = sels,
278 columns = [_('Plugins')],
279 single_selection = False
280 )
281
282 if new_plugins == curr_plugins:
283 return True
284
285 if new_plugins is None:
286 return True
287
288 dbcfg.set (
289 option = u'horstspace.notebook.plugin_load_order',
290 value = new_plugins,
291 workplace = workplace
292 )
293
294 return True
295
296 def refresh(lctrl):
297 workplaces = gmSurgery.gmCurrentPractice().workplaces
298 curr_workplace = gmSurgery.gmCurrentPractice().active_workplace
299 try:
300 sels = [workplaces.index(curr_workplace)]
301 except ValueError:
302 sels = []
303
304 lctrl.set_string_items(workplaces)
305 lctrl.set_selections(selections = sels)
306
307 gmListWidgets.get_choices_from_list (
308 parent = parent,
309 msg = _(
310 '\nSelect the workplace to configure below.\n'
311 '\n'
312 'The currently active workplace is preselected.\n'
313 ),
314 caption = _('Configuring GNUmed workplaces ...'),
315 columns = [_('Workplace')],
316 single_selection = True,
317 refresh_callback = refresh,
318 edit_callback = edit,
319 new_callback = edit,
320 delete_callback = delete
321 )
322
323 -class cProviderInboxPnl(wxgProviderInboxPnl.wxgProviderInboxPnl, gmRegetMixin.cRegetOnPaintMixin):
324
325 _item_handlers = {}
326 _patient_msg_types = ['clinical.review docs', 'clinical.review results']
327
341
342
343
345 self.__populate_inbox()
346 return True
347
348
349
351 gmDispatcher.connect(signal = u'message_inbox_generic_mod_db', receiver = self._on_message_inbox_mod_db)
352 gmDispatcher.connect(signal = u'message_inbox_mod_db', receiver = self._on_message_inbox_mod_db)
353
354 gmDispatcher.connect(signal = u'reviewed_test_results_mod_db', receiver = self._on_message_inbox_mod_db)
355
356
357 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
358
374
399
400
401
403 wx.CallAfter(self._schedule_data_reget)
404 wx.CallAfter(self._RBTN_active_patient.Enable)
405
407 wx.CallAfter(self._schedule_data_reget)
408 gmDispatcher.send(signal = u'request_user_attention', msg = _('Please check your GNUmed Inbox !'))
409
411 msg = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
412 if msg is None:
413 return
414
415 handler_key = '%s.%s' % (msg['category'], msg['type'])
416 try:
417 handle_item = cProviderInboxPnl._item_handlers[handler_key]
418 except KeyError:
419 gmGuiHelpers.gm_show_warning (
420 _(
421 """No double-click action pre-programmed into
422 GNUmed for message category and type:
423
424 [%s]
425 """
426 ) % handler_key,
427 _('handling provider inbox item')
428 )
429 return False
430
431 if not handle_item(pk_context = msg['pk_context'], pk_patient = msg['pk_patient']):
432 _log.error('item handler returned "false"')
433 _log.error('handler key: [%s]', handler_key)
434 _log.error('message: %s', str(msg))
435 return False
436
437 return True
438
441
443 msg = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
444 if msg is None:
445 return
446
447 if msg['data'] is None:
448 tmp = _('Message: %s') % msg['comment']
449 else:
450 tmp = _('Message: %s\nData: %s') % (msg['comment'], msg['data'])
451
452 self._TXT_inbox_item_comment.SetValue(tmp)
453
455 tmp = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
456 if tmp is None:
457 return
458 self.__focussed_msg = tmp
459
460
461 menu = wx.Menu(title = _('Inbox Message menu'))
462
463 if not self.__focussed_msg['is_virtual']:
464 ID = wx.NewId()
465 menu.AppendItem(wx.MenuItem(menu, ID, _('delete message')))
466 wx.EVT_MENU(menu, ID, self._on_delete_focussed_msg)
467
468
469 self.PopupMenu(menu, wx.DefaultPosition)
470 menu.Destroy()
471
476
481
482
483
485 if self.__focussed_msg['is_virtual']:
486 gmDispatcher.send(signal = 'statustext', msg = _('You must deal with the reason for this message to remove it from your inbox.'), beep = True)
487 return False
488
489 if not self.provider.inbox.delete_message(self.__focussed_msg['pk_message_inbox']):
490 gmDispatcher.send(signal='statustext', msg=_('Problem removing message from Inbox.'))
491 return False
492 return True
493
495 wx.BeginBusyCursor()
496
497 try:
498 pat = gmPerson.cIdentity(aPK_obj = pk_patient)
499 except gmExceptions.ConstructorError:
500 wx.EndBusyCursor()
501 _log.exception('patient [%s] not found', pk_patient)
502 gmGuiHelpers.gm_show_error (
503 _('Supposedly there are unreviewed documents\n'
504 'for patient [%s]. However, I cannot find\n'
505 'that patient in the GNUmed database.'
506 ) % pk_patient,
507 _('handling provider inbox item')
508 )
509 return False
510
511 success = gmPatSearchWidgets.set_active_patient(patient = pat)
512
513 wx.EndBusyCursor()
514
515 if not success:
516 gmGuiHelpers.gm_show_error (
517 _('Supposedly there are unreviewed documents\n'
518 'for patient [%s]. However, I cannot find\n'
519 'that patient in the GNUmed database.'
520 ) % pk_patient,
521 _('handling provider inbox item')
522 )
523 return False
524
525 wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = 'gmShowMedDocs', sort_mode = 'review')
526 return True
527
529 wx.BeginBusyCursor()
530 success = gmPatSearchWidgets.set_active_patient(patient=gmPerson.cIdentity(aPK_obj=pk_patient))
531 wx.EndBusyCursor()
532 if not success:
533 gmGuiHelpers.gm_show_error (
534 _('Supposedly there are unreviewed results\n'
535 'for patient [%s]. However, I cannot find\n'
536 'that patient in the GNUmed database.'
537 ) % pk_patient,
538 _('handling provider inbox item')
539 )
540 return False
541
542 wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = 'gmMeasurementsGridPlugin')
543 return True
544
545 if __name__ == '__main__':
546
547 gmI18N.activate_locale()
548 gmI18N.install_domain(domain = 'gnumed')
549
553
555 app = wx.PyWidgetTester(size = (800, 600))
556 app.SetWidget(cProviderInboxPnl, -1)
557 app.MainLoop()
558
559 if len(sys.argv) > 1 and sys.argv[1] == 'test':
560
561 test_message_inbox()
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735