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
16 from Gnumed.pycommon import gmExceptions
17 from Gnumed.pycommon import gmPG2
18 from Gnumed.pycommon import gmCfg
19 from Gnumed.pycommon import gmTools
20 from Gnumed.pycommon import gmDispatcher
21 from Gnumed.pycommon import gmMatchProvider
22
23 from Gnumed.business import gmPerson
24 from Gnumed.business import gmSurgery
25 from Gnumed.business import gmProviderInbox
26
27 from Gnumed.wxpython import gmGuiHelpers
28 from Gnumed.wxpython import gmListWidgets
29 from Gnumed.wxpython import gmPlugin
30 from Gnumed.wxpython import gmRegetMixin
31 from Gnumed.wxpython import gmPhraseWheel
32 from Gnumed.wxpython import gmEditArea
33 from Gnumed.wxpython import gmAuthWidgets
34 from Gnumed.wxpython import gmPatSearchWidgets
35 from Gnumed.wxpython import gmVaccWidgets
36 from Gnumed.wxpython import gmCfgWidgets
37
38
39 _log = logging.getLogger('gm.ui')
40 _log.info(__version__)
41
42 _indicator = {
43 -1: '',
44 0: '',
45 1: '*!!*'
46 }
47
48 from Gnumed.wxGladeWidgets import wxgTextExpansionEditAreaPnl
49
50 -class cTextExpansionEditAreaPnl(wxgTextExpansionEditAreaPnl.wxgTextExpansionEditAreaPnl):
51
52 - def __init__(self, *args, **kwds):
53
54 try:
55 self.__keyword = kwds['keyword']
56 del kwds['keyword']
57 except KeyError:
58 self.__keyword = None
59
60 wxgTextExpansionEditAreaPnl.wxgTextExpansionEditAreaPnl.__init__(self, *args, **kwds)
61
62 self.__init_ui()
63 self.__register_interests()
64
66 if not self.__valid_for_save():
67 return False
68
69 if self.__keyword is None:
70 result = gmPG2.add_text_expansion (
71 keyword = self._TCTRL_keyword.GetValue().strip(),
72 expansion = self._TCTRL_expansion.GetValue(),
73 public = self._RBTN_public.GetValue()
74 )
75 else:
76 gmPG2.edit_text_expansion (
77 keyword = self._TCTRL_keyword.GetValue().strip(),
78 expansion = self._TCTRL_expansion.GetValue()
79 )
80 result = True
81
82 return result
83
86
87
88
89
90
92 self._TCTRL_keyword.Bind(wx.EVT_TEXT, self._on_keyword_modified)
93
95 if self._TCTRL_keyword.GetValue().strip() == u'':
96 self._TCTRL_expansion.Enable(False)
97 else:
98 self._TCTRL_expansion.Enable(True)
99
100
101
103
104 kwd = self._TCTRL_keyword.GetValue().strip()
105 if kwd == u'':
106 self._TCTRL_keyword.SetBackgroundColour('pink')
107 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save text expansion without keyword.'), beep = True)
108 return False
109 self._TCTRL_keyword.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
110
111 if self._TCTRL_expansion.GetValue().strip() == u'':
112 self._TCTRL_expansion.SetBackgroundColour('pink')
113 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save text expansion without expansion text.'), beep = True)
114 return False
115 self._TCTRL_expansion.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
116
117 return True
118
119 - def __init_ui(self, keyword=None):
120
121 if keyword is not None:
122 self.__keyword = keyword
123
124 if self.__keyword is None:
125 self._TCTRL_keyword.SetValue(u'')
126 self._TCTRL_keyword.Enable(True)
127 self._TCTRL_expansion.SetValue(u'')
128 self._TCTRL_expansion.Enable(False)
129 self._RBTN_public.Enable(True)
130 self._RBTN_private.Enable(True)
131 self._RBTN_public.SetValue(1)
132 else:
133 expansion = gmPG2.expand_keyword(keyword = self.__keyword)
134 self._TCTRL_keyword.SetValue(self.__keyword)
135 self._TCTRL_keyword.Enable(False)
136 self._TCTRL_expansion.SetValue(gmTools.coalesce(expansion, u''))
137 self._TCTRL_expansion.Enable(True)
138 self._RBTN_public.Enable(False)
139 self._RBTN_private.Enable(False)
140
142
143 if parent is None:
144 parent = wx.GetApp().GetTopWindow()
145
146
147 def delete(keyword=None):
148 gmPG2.delete_text_expansion(keyword = keyword)
149 return True
150
151 def edit(keyword=None):
152
153 ea = cTextExpansionEditAreaPnl(parent, -1, keyword=keyword)
154 dlg = gmEditArea.cGenericEditAreaDlg(parent, -1, edit_area = ea)
155 dlg.SetTitle (
156 gmTools.coalesce(keyword, _('Adding text expansion'), _('Editing text expansion "%s"'))
157 )
158 if dlg.ShowModal() == wx.ID_OK:
159 return True
160
161 return False
162
163 def refresh(lctrl=None):
164 kwds = [ [
165 r[0],
166 gmTools.bool2subst(r[1], gmTools.u_checkmark_thick, u''),
167 gmTools.bool2subst(r[2], gmTools.u_checkmark_thick, u''),
168 r[3]
169 ] for r in gmPG2.get_text_expansion_keywords()
170 ]
171 data = [ r[0] for r in gmPG2.get_text_expansion_keywords() ]
172 lctrl.set_string_items(kwds)
173 lctrl.set_data(data)
174
175
176 gmListWidgets.get_choices_from_list (
177 parent = parent,
178 msg = _('\nSelect the keyword you want to edit !\n'),
179 caption = _('Editing keyword-based text expansions ...'),
180 columns = [_('Keyword'), _('Public'), _('Private'), _('Owner')],
181 single_selection = True,
182 edit_callback = edit,
183 new_callback = edit,
184 delete_callback = delete,
185 refresh_callback = refresh
186 )
187
224
237
238
239
241
242 if parent is None:
243 parent = wx.GetApp().GetTopWindow()
244
245 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('showing audit trail'))
246 if conn is None:
247 return False
248
249
250 def refresh(lctrl):
251 cmd = u'SELECT * FROM audit.v_audit_trail ORDER BY audit_when_ts'
252 rows, idx = gmPG2.run_ro_queries(link_obj = conn, queries = [{'cmd': cmd}], get_col_idx = False)
253 lctrl.set_string_items (
254 [ [
255 r['event_when'],
256 r['event_by'],
257 u'%s %s %s' % (
258 gmTools.coalesce(r['row_version_before'], gmTools.u_diameter),
259 gmTools.u_right_arrow,
260 gmTools.coalesce(r['row_version_after'], gmTools.u_diameter)
261 ),
262 r['event_table'],
263 r['event'],
264 r['pk_audit']
265 ] for r in rows ]
266 )
267
268 gmListWidgets.get_choices_from_list (
269 parent = parent,
270 msg = u'',
271 caption = _('GNUmed database audit log ...'),
272 columns = [ _('When'), _('Who'), _('Revisions'), _('Table'), _('Event'), '#' ],
273 single_selection = True,
274 refresh_callback = refresh
275 )
276
277
278
279
324
325 def edit(workplace=None):
326
327 dbcfg = gmCfg.cCfgSQL()
328
329 if workplace is None:
330 dlg = wx.TextEntryDialog (
331 parent = parent,
332 message = _('Enter a descriptive name for the new workplace:'),
333 caption = _('Configuring GNUmed workplaces ...'),
334 defaultValue = u'',
335 style = wx.OK | wx.CENTRE
336 )
337 dlg.ShowModal()
338 workplace = dlg.GetValue().strip()
339 if workplace == u'':
340 gmGuiHelpers.gm_show_error(_('Cannot save a new workplace without a name.'), _('Configuring GNUmed workplaces ...'))
341 return False
342 curr_plugins = []
343 else:
344 curr_plugins = gmTools.coalesce(dbcfg.get2 (
345 option = u'horstspace.notebook.plugin_load_order',
346 workplace = workplace,
347 bias = 'workplace'
348 ), []
349 )
350
351 msg = _(
352 'Pick the plugin(s) to be loaded the next time the client is restarted under the workplace:\n'
353 '\n'
354 ' [%s]\n'
355 ) % workplace
356
357 picker = gmListWidgets.cItemPickerDlg (
358 parent,
359 -1,
360 title = _('Configuring workplace plugins ...'),
361 msg = msg
362 )
363 picker.set_columns(['Available plugins'], ['Active plugins'])
364 available_plugins = gmPlugin.get_installed_plugins(plugin_dir = 'gui')
365 picker.set_choices(available_plugins)
366 picker.set_picks(picks = curr_plugins)
367 btn_pressed = picker.ShowModal()
368 if btn_pressed != wx.ID_OK:
369 picker.Destroy()
370 return False
371
372 new_plugins = picker.get_picks()
373 picker.Destroy()
374 if new_plugins == curr_plugins:
375 return True
376
377 if new_plugins is None:
378 return True
379
380 dbcfg.set (
381 option = u'horstspace.notebook.plugin_load_order',
382 value = new_plugins,
383 workplace = workplace
384 )
385
386 return True
387
388 def edit_old(workplace=None):
389
390 available_plugins = gmPlugin.get_installed_plugins(plugin_dir='gui')
391
392 dbcfg = gmCfg.cCfgSQL()
393
394 if workplace is None:
395 dlg = wx.TextEntryDialog (
396 parent = parent,
397 message = _('Enter a descriptive name for the new workplace:'),
398 caption = _('Configuring GNUmed workplaces ...'),
399 defaultValue = u'',
400 style = wx.OK | wx.CENTRE
401 )
402 dlg.ShowModal()
403 workplace = dlg.GetValue().strip()
404 if workplace == u'':
405 gmGuiHelpers.gm_show_error(_('Cannot save a new workplace without a name.'), _('Configuring GNUmed workplaces ...'))
406 return False
407 curr_plugins = []
408 choices = available_plugins
409 else:
410 curr_plugins = gmTools.coalesce(dbcfg.get2 (
411 option = u'horstspace.notebook.plugin_load_order',
412 workplace = workplace,
413 bias = 'workplace'
414 ), []
415 )
416 choices = curr_plugins[:]
417 for p in available_plugins:
418 if p not in choices:
419 choices.append(p)
420
421 sels = range(len(curr_plugins))
422 new_plugins = gmListWidgets.get_choices_from_list (
423 parent = parent,
424 msg = _(
425 '\n'
426 'Select the plugin(s) to be loaded the next time\n'
427 'the client is restarted under the workplace:\n'
428 '\n'
429 ' [%s]'
430 '\n'
431 ) % workplace,
432 caption = _('Configuring GNUmed workplaces ...'),
433 choices = choices,
434 selections = sels,
435 columns = [_('Plugins')],
436 single_selection = False
437 )
438
439 if new_plugins == curr_plugins:
440 return True
441
442 if new_plugins is None:
443 return True
444
445 dbcfg.set (
446 option = u'horstspace.notebook.plugin_load_order',
447 value = new_plugins,
448 workplace = workplace
449 )
450
451 return True
452
453 def clone(workplace=None):
454 if workplace is None:
455 return False
456
457 new_name = wx.GetTextFromUser (
458 message = _('Enter a name for the new workplace !'),
459 caption = _('Cloning workplace'),
460 default_value = u'%s-2' % workplace,
461 parent = parent
462 ).strip()
463
464 if new_name == u'':
465 return False
466
467 dbcfg = gmCfg.cCfgSQL()
468 opt = u'horstspace.notebook.plugin_load_order'
469
470 plugins = dbcfg.get2 (
471 option = opt,
472 workplace = workplace,
473 bias = 'workplace'
474 )
475
476 dbcfg.set (
477 option = opt,
478 value = plugins,
479 workplace = new_name
480 )
481
482
483
484 return True
485
486 def refresh(lctrl):
487 workplaces = gmSurgery.gmCurrentPractice().workplaces
488 curr_workplace = gmSurgery.gmCurrentPractice().active_workplace
489 try:
490 sels = [workplaces.index(curr_workplace)]
491 except ValueError:
492 sels = []
493
494 lctrl.set_string_items(workplaces)
495 lctrl.set_selections(selections = sels)
496
497 gmListWidgets.get_choices_from_list (
498 parent = parent,
499 msg = _(
500 '\nSelect the workplace to configure below.\n'
501 '\n'
502 'The currently active workplace is preselected.\n'
503 ),
504 caption = _('Configuring GNUmed workplaces ...'),
505 columns = [_('Workplace')],
506 single_selection = True,
507 refresh_callback = refresh,
508 edit_callback = edit,
509 new_callback = edit,
510 delete_callback = delete,
511 left_extra_button = (_('Clone'), _('Clone the selected workplace'), clone)
512 )
513
515
517
518 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
519
520 query = u"""
521 SELECT DISTINCT ON (label)
522 pk_type,
523 (l10n_type || ' (' || l10n_category || ')')
524 AS label
525 FROM
526 dem.v_inbox_item_type
527 WHERE
528 l10n_type %(fragment_condition)s
529 OR
530 type %(fragment_condition)s
531 OR
532 l10n_category %(fragment_condition)s
533 OR
534 category %(fragment_condition)s
535 ORDER BY label
536 LIMIT 50"""
537
538 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
539 mp.setThresholds(1, 2, 4)
540 self.matcher = mp
541 self.SetToolTipString(_('Select a message type.'))
542
555
556 from Gnumed.wxGladeWidgets import wxgInboxMessageEAPnl
557
558 -class cInboxMessageEAPnl(wxgInboxMessageEAPnl.wxgInboxMessageEAPnl, gmEditArea.cGenericEditAreaMixin):
559
579
585
586
587
589 validity = True
590
591 if self._TCTRL_subject.GetValue().strip() == u'':
592 validity = False
593 self.display_ctrl_as_valid(ctrl = self._TCTRL_subject, valid = False)
594 else:
595 self.display_ctrl_as_valid(ctrl = self._TCTRL_subject, valid = True)
596
597 if self._PRW_type.GetValue().strip() == u'':
598 validity = False
599 self._PRW_type.display_as_valid(False)
600 else:
601 self._PRW_type.display_as_valid(True)
602
603 missing_receiver = (
604 (self._CHBOX_send_to_me.IsChecked() is False)
605 and
606 (self._PRW_receiver.GetData() is None)
607 )
608
609 missing_patient = (
610 (self._CHBOX_active_patient.IsChecked() is False)
611 and
612 (self._PRW_patient.person is None)
613 )
614
615 if missing_receiver and missing_patient:
616 validity = False
617 self.display_ctrl_as_valid(ctrl = self._CHBOX_send_to_me, valid = False)
618 self._PRW_receiver.display_as_valid(False)
619 self.display_ctrl_as_valid(ctrl = self._CHBOX_active_patient, valid = False)
620 self.display_ctrl_as_valid(ctrl = self._PRW_patient, valid = False)
621 else:
622 self.display_ctrl_as_valid(ctrl = self._CHBOX_send_to_me, valid = True)
623 self._PRW_receiver.display_as_valid(True)
624 self.display_ctrl_as_valid(ctrl = self._CHBOX_active_patient, valid = True)
625 self.display_ctrl_as_valid(ctrl = self._PRW_patient, valid = True)
626
627 return validity
628
630
631 pat_id = None
632 if self._CHBOX_active_patient.GetValue() is True:
633 pat_id = gmPerson.gmCurrentPatient().ID
634 else:
635 if self._PRW_patient.person is not None:
636 pat_id = self._PRW_patient.person.ID
637
638 receiver = None
639 if self._CHBOX_send_to_me.IsChecked():
640 receiver = gmPerson.gmCurrentProvider()['pk_staff']
641 else:
642 if self._PRW_receiver.GetData() is not None:
643 receiver = self._PRW_receiver.GetData()
644
645 msg = gmProviderInbox.create_inbox_message (
646 patient = pat_id,
647 staff = receiver,
648 message_type = self._PRW_type.GetData(can_create = True),
649 subject = self._TCTRL_subject.GetValue().strip()
650 )
651
652 msg['data'] = self._TCTRL_message.GetValue().strip()
653
654 if self._RBTN_normal.GetValue() is True:
655 msg['importance'] = 0
656 elif self._RBTN_high.GetValue() is True:
657 msg['importance'] = 1
658 else:
659 msg['importance'] = -1
660
661 msg.save()
662 self.data = msg
663 return True
664
666
667 self.data['comment'] = self._TCTRL_subject.GetValue().strip()
668 self.data['pk_type'] = self._PRW_type.GetData(can_create = True)
669
670 if self._CHBOX_send_to_me.IsChecked():
671 self.data['pk_staff'] = gmPerson.gmCurrentProvider()['pk_staff']
672 else:
673 self.data['pk_staff'] = self._PRW_receiver.GetData()
674
675 self.data['data'] = self._TCTRL_message.GetValue().strip()
676
677 if self._CHBOX_active_patient.GetValue() is True:
678 self.data['pk_patient'] = gmPerson.gmCurrentPatient().ID
679 else:
680 if self._PRW_patient.person is None:
681 self.data['pk_patient'] = None
682 else:
683 self.data['pk_patient'] = self._PRW_patient.person.ID
684
685 if self._RBTN_normal.GetValue() is True:
686 self.data['importance'] = 0
687 elif self._RBTN_high.GetValue() is True:
688 self.data['importance'] = 1
689 else:
690 self.data['importance'] = -1
691
692 self.data.save()
693 return True
694
718
720 self._refresh_as_new()
721
769
770
771
773 if self._CHBOX_active_patient.IsChecked():
774 self._PRW_patient.Enable(False)
775 self._PRW_patient.person = None
776 else:
777 self._PRW_patient.Enable(True)
778
780 if self._CHBOX_send_to_me.IsChecked():
781 self._PRW_receiver.Enable(False)
782 self._PRW_receiver.SetData(data = gmPerson.gmCurrentProvider()['pk_staff'])
783 else:
784 self._PRW_receiver.Enable(True)
785 self._PRW_receiver.SetText(value = u'', data = None)
786
802
803 from Gnumed.wxGladeWidgets import wxgProviderInboxPnl
804
805 -class cProviderInboxPnl(wxgProviderInboxPnl.wxgProviderInboxPnl, gmRegetMixin.cRegetOnPaintMixin):
806
807 _item_handlers = {}
808
809 _patient_msg_types = ['clinical.review docs', 'clinical.review results', 'clinical.review vaccs']
810
826
827
828
830 self.__populate_inbox()
831 return True
832
833
834
836 gmDispatcher.connect(signal = u'message_inbox_generic_mod_db', receiver = self._on_message_inbox_mod_db)
837 gmDispatcher.connect(signal = u'message_inbox_mod_db', receiver = self._on_message_inbox_mod_db)
838
839 gmDispatcher.connect(signal = u'reviewed_test_results_mod_db', receiver = self._on_message_inbox_mod_db)
840 gmDispatcher.connect(signal = u'identity_mod_db', receiver = self._on_message_inbox_mod_db)
841 gmDispatcher.connect(signal = u'doc_mod_db', receiver = self._on_message_inbox_mod_db)
842 gmDispatcher.connect(signal = u'doc_obj_review_mod_db', receiver = self._on_message_inbox_mod_db)
843 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
844
862
887
888
889
891 wx.CallAfter(self._schedule_data_reget)
892 wx.CallAfter(self._RBTN_active_patient.Enable)
893
895 wx.CallAfter(self._schedule_data_reget)
896 gmDispatcher.send(signal = u'request_user_attention', msg = _('Please check your GNUmed Inbox !'))
897
899 msg = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
900 if msg is None:
901 return
902
903 handler_key = '%s.%s' % (msg['category'], msg['type'])
904 try:
905 handle_item = cProviderInboxPnl._item_handlers[handler_key]
906 except KeyError:
907 gmGuiHelpers.gm_show_warning (
908 _(
909 """No double-click action pre-programmed into
910 GNUmed for message category and type:
911
912 [%s]
913 """
914 ) % handler_key,
915 _('handling provider inbox item')
916 )
917 return False
918
919 if not handle_item(pk_context = msg['pk_context'], pk_patient = msg['pk_patient']):
920 _log.error('item handler returned "false"')
921 _log.error('handler key: [%s]', handler_key)
922 _log.error('message: %s', str(msg))
923 return False
924
925 return True
926
929
931 msg = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
932 if msg is None:
933 return
934
935 if msg['data'] is None:
936 tmp = _('Message: %s') % msg['comment']
937 else:
938 tmp = _('Message: %s\nData: %s') % (msg['comment'], msg['data'])
939
940 self._TXT_inbox_item_comment.SetValue(tmp)
941
943 tmp = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True)
944 if tmp is None:
945 return
946 self.__focussed_msg = tmp
947
948
949 menu = wx.Menu(title = _('Inbox Message Actions:'))
950
951 if not self.__focussed_msg['is_virtual']:
952
953 ID = wx.NewId()
954 menu.AppendItem(wx.MenuItem(menu, ID, _('Delete')))
955 wx.EVT_MENU(menu, ID, self._on_delete_focussed_msg)
956
957 ID = wx.NewId()
958 menu.AppendItem(wx.MenuItem(menu, ID, _('Edit')))
959 wx.EVT_MENU(menu, ID, self._on_edit_focussed_msg)
960
961
962
963
964
965
966
967
968 self.PopupMenu(menu, wx.DefaultPosition)
969 menu.Destroy()
970
975
980
983
1020
1021
1022
1024 if self.__focussed_msg['is_virtual']:
1025 gmDispatcher.send(signal = 'statustext', msg = _('You must deal with the reason for this message to remove it from your inbox.'), beep = True)
1026 return False
1027
1028 if not self.provider.inbox.delete_message(self.__focussed_msg['pk_inbox_message']):
1029 gmDispatcher.send(signal='statustext', msg=_('Problem removing message from Inbox.'))
1030 return False
1031 return True
1032
1034 if self.__focussed_msg['is_virtual']:
1035 gmDispatcher.send(signal = 'statustext', msg = _('This message cannot be edited because it is virtual.'))
1036 return False
1037 edit_inbox_message(parent = self, message = self.__focussed_msg, single_entry = True)
1038 return True
1039
1041 if self.__focussed_msg['pk_staff'] is None:
1042 gmDispatcher.send(signal = 'statustext', msg = _('This message is already visible to all providers.'))
1043 return False
1044 print "now distributing"
1045 return True
1046
1074
1076
1077 msg = _('Supposedly there are unreviewed results\n'
1078 'for patient [%s]. However, I cannot find\n'
1079 'that patient in the GNUmed database.'
1080 ) % pk_patient
1081
1082 wx.BeginBusyCursor()
1083
1084 try:
1085 pat = gmPerson.cIdentity(aPK_obj = pk_patient)
1086 except gmExceptions.ConstructorError:
1087 wx.EndBusyCursor()
1088 _log.exception('patient [%s] not found', pk_patient)
1089 gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
1090 return False
1091
1092 success = gmPatSearchWidgets.set_active_patient(patient = pat)
1093
1094 wx.EndBusyCursor()
1095
1096 if not success:
1097 gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item'))
1098 return False
1099
1100 wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = 'gmMeasurementsGridPlugin')
1101 return True
1102
1131
1132 if __name__ == '__main__':
1133
1134 if len(sys.argv) < 2:
1135 sys.exit()
1136
1137 if sys.argv[1] != 'test':
1138 sys.exit()
1139
1140 gmI18N.activate_locale()
1141 gmI18N.install_domain(domain = 'gnumed')
1142
1146
1148 app = wx.PyWidgetTester(size = (800, 600))
1149 app.SetWidget(cProviderInboxPnl, -1)
1150 app.MainLoop()
1151
1153 app = wx.PyWidgetTester(size = (800, 600))
1154 app.SetWidget(cInboxMessageEAPnl, -1)
1155 app.MainLoop()
1156
1157
1158
1159
1160 test_msg_ea()
1161
1162
1163