1 """GNUmed patient EMR tree browser.
2 """
3
4 __version__ = "$Revision: 1.111 $"
5 __author__ = "cfmoro1976@yahoo.es, sjtan@swiftdsl.com.au, Karsten.Hilbert@gmx.net"
6 __license__ = "GPL"
7
8
9 import sys, types, os.path, StringIO, codecs, logging
10
11
12
13 import wx
14
15
16
17 from Gnumed.pycommon import gmI18N, gmDispatcher, gmExceptions, gmTools
18 from Gnumed.exporters import gmPatientExporter
19 from Gnumed.business import gmEMRStructItems, gmPerson, gmSOAPimporter, gmPersonSearch
20 from Gnumed.wxpython import gmGuiHelpers, gmEMRStructWidgets, gmSOAPWidgets
21 from Gnumed.wxpython import gmAllergyWidgets, gmNarrativeWidgets, gmPatSearchWidgets
22 from Gnumed.wxpython import gmDemographicsWidgets, gmVaccWidgets
23
24
25 _log = logging.getLogger('gm.ui')
26 _log.info(__version__)
27
28
30 """
31 Dump the patient's EMR from GUI client
32 @param parent - The parent widget
33 @type parent - A wx.Window instance
34 """
35
36 if parent is None:
37 raise TypeError('expected wx.Window instance as parent, got <None>')
38
39 pat = gmPerson.gmCurrentPatient()
40 if not pat.connected:
41 gmDispatcher.send(signal='statustext', msg=_('Cannot export EMR. No active patient.'))
42 return False
43
44
45 wc = "%s (*.txt)|*.txt|%s (*)|*" % (_("text files"), _("all files"))
46 defdir = os.path.abspath(os.path.expanduser(os.path.join('~', 'gnumed', 'export', 'EMR', pat['dirname'])))
47 gmTools.mkdir(defdir)
48 fname = '%s-%s_%s.txt' % (_('emr-export'), pat['lastnames'], pat['firstnames'])
49 dlg = wx.FileDialog (
50 parent = parent,
51 message = _("Save patient's EMR as..."),
52 defaultDir = defdir,
53 defaultFile = fname,
54 wildcard = wc,
55 style = wx.SAVE
56 )
57 choice = dlg.ShowModal()
58 fname = dlg.GetPath()
59 dlg.Destroy()
60 if choice != wx.ID_OK:
61 return None
62
63 _log.debug('exporting EMR to [%s]', fname)
64
65
66 output_file = codecs.open(fname, 'wb', encoding='utf8', errors='replace')
67 exporter = gmPatientExporter.cEmrExport(patient = pat)
68 exporter.set_output_file(output_file)
69 exporter.dump_constraints()
70 exporter.dump_demographic_record(True)
71 exporter.dump_clinical_record()
72 exporter.dump_med_docs()
73 output_file.close()
74
75 gmDispatcher.send('statustext', msg = _('EMR successfully exported to file: %s') % fname, beep = False)
76 return fname
77
78 -class cEMRTree(wx.TreeCtrl, gmGuiHelpers.cTreeExpansionHistoryMixin):
79 """This wx.TreeCtrl derivative displays a tree view of the medical record."""
80
81
82 - def __init__(self, parent, id, *args, **kwds):
83 """Set up our specialised tree.
84 """
85 kwds['style'] = wx.TR_HAS_BUTTONS | wx.NO_BORDER
86 wx.TreeCtrl.__init__(self, parent, id, *args, **kwds)
87
88 gmGuiHelpers.cTreeExpansionHistoryMixin.__init__(self)
89
90 try:
91 self.__narr_display = kwds['narr_display']
92 del kwds['narr_display']
93 except KeyError:
94 self.__narr_display = None
95
96 self.__pat = gmPerson.gmCurrentPatient()
97 self.__curr_node = None
98 self.__exporter = gmPatientExporter.cEmrExport(patient = self.__pat)
99
100 self._old_cursor_pos = None
101
102 self.__make_popup_menus()
103 self.__register_events()
104
105
106
108 if not self.__pat.connected:
109 gmDispatcher.send(signal='statustext', msg=_('Cannot load clinical narrative. No active patient.'),)
110 return False
111
112 if not self.__populate_tree():
113 return False
114
115 return True
116
118 self.__narr_display = narrative_display
119
121 self.__img_display = image_display
122
123
124
126 """Configures enabled event signals."""
127 wx.EVT_TREE_SEL_CHANGED (self, self.GetId(), self._on_tree_item_selected)
128 wx.EVT_TREE_ITEM_RIGHT_CLICK (self, self.GetId(), self._on_tree_item_right_clicked)
129
130
131
132 wx.EVT_TREE_ITEM_GETTOOLTIP(self, -1, self._on_tree_item_gettooltip)
133
134 gmDispatcher.connect(signal = 'narrative_mod_db', receiver = self._on_narrative_mod_db)
135 gmDispatcher.connect(signal = 'episode_mod_db', receiver = self._on_episode_mod_db)
136 gmDispatcher.connect(signal = 'health_issue_mod_db', receiver = self._on_issue_mod_db)
137
139 """Updates EMR browser data."""
140
141
142
143 wx.BeginBusyCursor()
144
145
146
147
148 self.DeleteAllItems()
149 root_item = self.AddRoot(_('EMR of %(lastnames)s, %(firstnames)s') % self.__pat.get_active_name())
150 self.SetPyData(root_item, None)
151 self.SetItemHasChildren(root_item, True)
152 self.__root_tooltip = self.__pat['description_gender'] + u'\n'
153 if self.__pat['deceased'] is None:
154 self.__root_tooltip += u' %s %s (%s)\n\n' % (
155 gmPerson.map_gender2symbol[self.__pat['gender']],
156 self.__pat.get_formatted_dob(format = '%d %b %Y', encoding = gmI18N.get_encoding()),
157 self.__pat['medical_age']
158 )
159 else:
160 template = u' %s %s - %s (%s)\n\n'
161 self.__root_tooltip += template % (
162 gmPerson.map_gender2symbol[self.__pat['gender']],
163 self.__pat.get_formatted_dob(format = '%d.%b %Y', encoding = gmI18N.get_encoding()),
164 self.__pat['deceased'].strftime('%d.%b %Y').decode(gmI18N.get_encoding()),
165 self.__pat['medical_age']
166 )
167 self.__root_tooltip += gmTools.coalesce(self.__pat['comment'], u'', u'%s\n\n')
168 doc = self.__pat.primary_provider
169 if doc is not None:
170 self.__root_tooltip += u'%s:\n' % _('Primary provider in this praxis')
171 self.__root_tooltip += u' %s %s %s (%s)%s\n\n' % (
172 gmTools.coalesce(doc['title'], gmPerson.map_gender2salutation(gender = doc['gender'])),
173 doc['firstnames'],
174 doc['lastnames'],
175 doc['short_alias'],
176 gmTools.bool2subst(doc['is_active'], u'', u' [%s]' % _('inactive'))
177 )
178 if not ((self.__pat['emergency_contact'] is None) and (self.__pat['pk_emergency_contact'] is None)):
179 self.__root_tooltip += _('In case of emergency contact:') + u'\n'
180 if self.__pat['emergency_contact'] is not None:
181 self.__root_tooltip += gmTools.wrap (
182 text = u'%s\n' % self.__pat['emergency_contact'],
183 width = 60,
184 initial_indent = u' ',
185 subsequent_indent = u' '
186 )
187 if self.__pat['pk_emergency_contact'] is not None:
188 contact = self.__pat.emergency_contact_in_database
189 self.__root_tooltip += u' %s\n' % contact['description_gender']
190 self.__root_tooltip = self.__root_tooltip.strip('\n')
191 if self.__root_tooltip == u'':
192 self.__root_tooltip = u' '
193
194
195 self.__exporter.get_historical_tree(self)
196 self.__curr_node = root_item
197
198 self.SelectItem(root_item)
199 self.Expand(root_item)
200 self.__update_text_for_selected_node()
201
202
203
204 wx.EndBusyCursor()
205 return True
206
208 """Displays information for the selected tree node."""
209
210 if self.__narr_display is None:
211 self.__img_display.clear()
212 return
213
214 if self.__curr_node is None:
215 self.__img_display.clear()
216 return
217
218 node_data = self.GetPyData(self.__curr_node)
219 doc_folder = self.__pat.get_document_folder()
220
221
222 if isinstance(node_data, (gmEMRStructItems.cHealthIssue, types.DictType)):
223
224 if node_data['pk_health_issue'] is None:
225 txt = _('Pool of unassociated episodes:\n\n "%s"') % node_data['description']
226 self.__img_display.clear()
227 else:
228 txt = node_data.format(left_margin=1, patient = self.__pat)
229 self.__img_display.refresh (
230 document_folder = doc_folder,
231 episodes = [ epi['pk_episode'] for epi in node_data.episodes ]
232 )
233
234 elif isinstance(node_data, gmEMRStructItems.cEpisode):
235 txt = node_data.format(left_margin = 1, patient = self.__pat)
236 self.__img_display.refresh (
237 document_folder = doc_folder,
238 episodes = [node_data['pk_episode']]
239 )
240
241 elif isinstance(node_data, gmEMRStructItems.cEncounter):
242 epi = self.GetPyData(self.GetItemParent(self.__curr_node))
243 txt = node_data.format (
244 episodes = [epi['pk_episode']],
245 with_soap = True,
246 left_margin = 1,
247 patient = self.__pat
248 )
249 self.__img_display.refresh (
250 document_folder = doc_folder,
251 episodes = [epi['pk_episode']],
252 encounter = node_data['pk_encounter']
253 )
254
255 else:
256 emr = self.__pat.get_emr()
257 txt = emr.format_summary(dob = self.__pat['dob'])
258 self.__img_display.clear()
259
260 self.__narr_display.Clear()
261 self.__narr_display.WriteText(txt)
262
264
265
266 self.__epi_context_popup = wx.Menu(title = _('Episode Menu'))
267
268 menu_id = wx.NewId()
269 self.__epi_context_popup.AppendItem(wx.MenuItem(self.__epi_context_popup, menu_id, _('Edit details')))
270 wx.EVT_MENU(self.__epi_context_popup, menu_id, self.__edit_episode)
271
272 menu_id = wx.NewId()
273 self.__epi_context_popup.AppendItem(wx.MenuItem(self.__epi_context_popup, menu_id, _('Delete')))
274 wx.EVT_MENU(self.__epi_context_popup, menu_id, self.__delete_episode)
275
276 menu_id = wx.NewId()
277 self.__epi_context_popup.AppendItem(wx.MenuItem(self.__epi_context_popup, menu_id, _('Promote')))
278 wx.EVT_MENU(self.__epi_context_popup, menu_id, self.__promote_episode_to_issue)
279
280 menu_id = wx.NewId()
281 self.__epi_context_popup.AppendItem(wx.MenuItem(self.__epi_context_popup, menu_id, _('Move encounters')))
282 wx.EVT_MENU(self.__epi_context_popup, menu_id, self.__move_encounters)
283
284
285 self.__enc_context_popup = wx.Menu(title = _('Encounter Menu'))
286
287 menu_id = wx.NewId()
288 self.__enc_context_popup.AppendItem(wx.MenuItem(self.__enc_context_popup, menu_id, _('Move data to another episode')))
289 wx.EVT_MENU(self.__enc_context_popup, menu_id, self.__relink_encounter_data2episode)
290
291 menu_id = wx.NewId()
292 self.__enc_context_popup.AppendItem(wx.MenuItem(self.__enc_context_popup, menu_id, _('Edit details')))
293 wx.EVT_MENU(self.__enc_context_popup, menu_id, self.__edit_encounter_details)
294
295 item = self.__enc_context_popup.Append(-1, _('Edit progress notes'))
296 self.Bind(wx.EVT_MENU, self.__edit_progress_notes, item)
297
298 item = self.__enc_context_popup.Append(-1, _('Move progress notes'))
299 self.Bind(wx.EVT_MENU, self.__move_progress_notes, item)
300
301 item = self.__enc_context_popup.Append(-1, _('Export for Medistar'))
302 self.Bind(wx.EVT_MENU, self.__export_encounter_for_medistar, item)
303
304
305 self.__issue_context_popup = wx.Menu(title = _('Health Issue Menu'))
306
307 menu_id = wx.NewId()
308 self.__issue_context_popup.AppendItem(wx.MenuItem(self.__issue_context_popup, menu_id, _('Edit details')))
309 wx.EVT_MENU(self.__issue_context_popup, menu_id, self.__edit_issue)
310
311 menu_id = wx.NewId()
312 self.__issue_context_popup.AppendItem(wx.MenuItem(self.__issue_context_popup, menu_id, _('Delete')))
313 wx.EVT_MENU(self.__issue_context_popup, menu_id, self.__delete_issue)
314
315 self.__issue_context_popup.AppendSeparator()
316
317 menu_id = wx.NewId()
318 self.__issue_context_popup.AppendItem(wx.MenuItem(self.__issue_context_popup, menu_id, _('Open to encounter level')))
319 wx.EVT_MENU(self.__issue_context_popup, menu_id, self.__expand_issue_to_encounter_level)
320
321
322
323
324 self.__root_context_popup = wx.Menu(title = _('EMR Menu'))
325
326 menu_id = wx.NewId()
327 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Create health issue')))
328 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__create_issue)
329
330 menu_id = wx.NewId()
331 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage allergies')))
332 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__document_allergy)
333
334 menu_id = wx.NewId()
335 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage vaccinations')))
336 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__manage_vaccinations)
337
338 menu_id = wx.NewId()
339 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage procedures')))
340 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__manage_procedures)
341
342 menu_id = wx.NewId()
343 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage hospitalizations')))
344 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__manage_hospital_stays)
345
346 menu_id = wx.NewId()
347 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage occupation')))
348 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__manage_occupation)
349
350 self.__root_context_popup.AppendSeparator()
351
352
353 expand_menu = wx.Menu()
354 self.__root_context_popup.AppendMenu(wx.NewId(), _('Open EMR to ...'), expand_menu)
355
356 menu_id = wx.NewId()
357 expand_menu.AppendItem(wx.MenuItem(expand_menu, menu_id, _('... issue level')))
358 wx.EVT_MENU(expand_menu, menu_id, self.__expand_to_issue_level)
359
360 menu_id = wx.NewId()
361 expand_menu.AppendItem(wx.MenuItem(expand_menu, menu_id, _('... episode level')))
362 wx.EVT_MENU(expand_menu, menu_id, self.__expand_to_episode_level)
363
364 menu_id = wx.NewId()
365 expand_menu.AppendItem(wx.MenuItem(expand_menu, menu_id, _('... encounter level')))
366 wx.EVT_MENU(expand_menu, menu_id, self.__expand_to_encounter_level)
367
368 - def __handle_root_context(self, pos=wx.DefaultPosition):
369 self.PopupMenu(self.__root_context_popup, pos)
370
371 - def __handle_issue_context(self, pos=wx.DefaultPosition):
372
373 self.PopupMenu(self.__issue_context_popup, pos)
374
375 - def __handle_episode_context(self, pos=wx.DefaultPosition):
376 self.__epi_context_popup.SetTitle(_('Episode %s') % self.__curr_node_data['description'])
377 self.PopupMenu(self.__epi_context_popup, pos)
378
379 - def __handle_encounter_context(self, pos=wx.DefaultPosition):
380 self.PopupMenu(self.__enc_context_popup, pos)
381
382
383
392
395
399
401 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
402 parent = self,
403 id = -1,
404 caption = _('Deleting episode'),
405 button_defs = [
406 {'label': _('Yes, delete'), 'tooltip': _('Delete the episode if possible (it must be completely empty).')},
407 {'label': _('No, cancel'), 'tooltip': _('Cancel and do NOT delete the episode.')}
408 ],
409 question = _(
410 'Are you sure you want to delete this episode ?\n'
411 '\n'
412 ' "%s"\n'
413 ) % self.__curr_node_data['description']
414 )
415 result = dlg.ShowModal()
416 if result != wx.ID_YES:
417 return
418
419 try:
420 gmEMRStructItems.delete_episode(episode = self.__curr_node_data)
421 except gmExceptions.DatabaseObjectInUseError:
422 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete episode. There is still clinical data recorded for it.'))
423 return
424
425
426
437
439 encounter = self.GetPyData(self.__curr_node)
440 node_parent = self.GetItemParent(self.__curr_node)
441 episode = self.GetPyData(node_parent)
442
443 gmNarrativeWidgets.manage_progress_notes (
444 parent = self,
445 encounters = [encounter['pk_encounter']],
446 episodes = [episode['pk_episode']]
447 )
448
453
455
456 node_parent = self.GetItemParent(self.__curr_node)
457 owning_episode = self.GetPyData(node_parent)
458
459 episode_selector = gmNarrativeWidgets.cMoveNarrativeDlg (
460 self,
461 -1,
462 episode = owning_episode,
463 encounter = self.__curr_node_data
464 )
465
466 result = episode_selector.ShowModal()
467 episode_selector.Destroy()
468
469 if result == wx.ID_YES:
470 self.__populate_tree()
471
472
473
476
478 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
479 parent = self,
480 id = -1,
481 caption = _('Deleting health issue'),
482 button_defs = [
483 {'label': _('Yes, delete'), 'tooltip': _('Delete the health issue if possible (it must be completely empty).')},
484 {'label': _('No, cancel'), 'tooltip': _('Cancel and do NOT delete the health issue.')}
485 ],
486 question = _(
487 'Are you sure you want to delete this health issue ?\n'
488 '\n'
489 ' "%s"\n'
490 ) % self.__curr_node_data['description']
491 )
492 result = dlg.ShowModal()
493 if result != wx.ID_YES:
494 dlg.Destroy()
495 return
496
497 dlg.Destroy()
498
499 try:
500 gmEMRStructItems.delete_health_issue(health_issue = self.__curr_node_data)
501 except gmExceptions.DatabaseObjectInUseError:
502 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete health issue. There is still clinical data recorded for it.'))
503
505
506 if not self.__curr_node.IsOk():
507 return
508
509 self.Expand(self.__curr_node)
510
511 epi, epi_cookie = self.GetFirstChild(self.__curr_node)
512 while epi.IsOk():
513 self.Expand(epi)
514 epi, epi_cookie = self.GetNextChild(self.__curr_node, epi_cookie)
515
516
517
520
528
531
534
537
540
542
543 root_item = self.GetRootItem()
544
545 if not root_item.IsOk():
546 return
547
548 self.Expand(root_item)
549
550
551 issue, issue_cookie = self.GetFirstChild(root_item)
552 while issue.IsOk():
553 self.Collapse(issue)
554 epi, epi_cookie = self.GetFirstChild(issue)
555 while epi.IsOk():
556 self.Collapse(epi)
557 epi, epi_cookie = self.GetNextChild(issue, epi_cookie)
558 issue, issue_cookie = self.GetNextChild(root_item, issue_cookie)
559
561
562 root_item = self.GetRootItem()
563
564 if not root_item.IsOk():
565 return
566
567 self.Expand(root_item)
568
569
570 issue, issue_cookie = self.GetFirstChild(root_item)
571 while issue.IsOk():
572 self.Expand(issue)
573 epi, epi_cookie = self.GetFirstChild(issue)
574 while epi.IsOk():
575 self.Collapse(epi)
576 epi, epi_cookie = self.GetNextChild(issue, epi_cookie)
577 issue, issue_cookie = self.GetNextChild(root_item, issue_cookie)
578
580
581 root_item = self.GetRootItem()
582
583 if not root_item.IsOk():
584 return
585
586 self.Expand(root_item)
587
588
589 issue, issue_cookie = self.GetFirstChild(root_item)
590 while issue.IsOk():
591 self.Expand(issue)
592 epi, epi_cookie = self.GetFirstChild(issue)
593 while epi.IsOk():
594 self.Expand(epi)
595 epi, epi_cookie = self.GetNextChild(issue, epi_cookie)
596 issue, issue_cookie = self.GetNextChild(root_item, issue_cookie)
597
604
605
606
608 wx.CallAfter(self.__update_text_for_selected_node)
609
611 wx.CallAfter(self.__populate_tree)
612
614 wx.CallAfter(self.__populate_tree)
615
617 sel_item = event.GetItem()
618 self.__curr_node = sel_item
619 self.__update_text_for_selected_node()
620 return True
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
712
713
714
715
716
717
718
719
720
721
722
723
724
726 """Right button clicked: display the popup for the tree"""
727
728 node = event.GetItem()
729 self.SelectItem(node)
730 self.__curr_node_data = self.GetPyData(node)
731 self.__curr_node = node
732
733 pos = wx.DefaultPosition
734 if isinstance(self.__curr_node_data, gmEMRStructItems.cHealthIssue):
735 self.__handle_issue_context(pos=pos)
736 elif isinstance(self.__curr_node_data, gmEMRStructItems.cEpisode):
737 self.__handle_episode_context(pos=pos)
738 elif isinstance(self.__curr_node_data, gmEMRStructItems.cEncounter):
739 self.__handle_encounter_context(pos=pos)
740 elif node == self.GetRootItem():
741 self.__handle_root_context()
742 elif type(self.__curr_node_data) == type({}):
743
744 pass
745 else:
746 print "error: unknown node type, no popup menu"
747 event.Skip()
748
750 """Used in sorting items.
751
752 -1: 1 < 2
753 0: 1 = 2
754 1: 1 > 2
755 """
756
757
758 item1 = self.GetPyData(node1)
759 item2 = self.GetPyData(node2)
760
761
762 if isinstance(item1, gmEMRStructItems.cEncounter):
763 if item1['started'] == item2['started']:
764 return 0
765 if item1['started'] > item2['started']:
766 return -1
767 return 1
768
769
770 if isinstance(item1, gmEMRStructItems.cEpisode):
771 start1 = item1.get_access_range()[0]
772 start2 = item2.get_access_range()[0]
773 if start1 == start2:
774 return 0
775 if start1 < start2:
776 return -1
777 return 1
778
779
780 if isinstance(item1, gmEMRStructItems.cHealthIssue):
781
782
783 if item1['grouping'] is None:
784 if item2['grouping'] is not None:
785 return 1
786
787
788 if item1['grouping'] is not None:
789 if item2['grouping'] is None:
790 return -1
791
792
793 if (item1['grouping'] is None) and (item2['grouping'] is None):
794 if item1['description'].lower() < item2['description'].lower():
795 return -1
796 if item1['description'].lower() > item2['description'].lower():
797 return 1
798 return 0
799
800
801 if item1['grouping'] < item2['grouping']:
802 return -1
803
804 if item1['grouping'] > item2['grouping']:
805 return 1
806
807 if item1['description'].lower() < item2['description'].lower():
808 return -1
809
810 if item1['description'].lower() > item2['description'].lower():
811 return 1
812
813 return 0
814
815
816 if isinstance(item1, type({})):
817 return -1
818
819 return 0
820
821 from Gnumed.wxGladeWidgets import wxgScrolledEMRTreePnl
822
840
841 from Gnumed.wxGladeWidgets import wxgSplittedEMRTreeBrowserPnl
842
844 """A splitter window holding an EMR tree.
845
846 The left hand side displays a scrollable EMR tree while
847 on the right details for selected items are displayed.
848
849 Expects to be put into a Notebook.
850 """
856
858 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
859 return True
860
862 if self.GetParent().GetCurrentPage() == self:
863 self.repopulate_ui()
864 return True
865
867 """Fills UI with data."""
868 self._pnl_emr_tree.repopulate_ui()
869 self._splitter_browser.SetSashPosition(self._splitter_browser.GetSizeTuple()[0]/3, True)
870 return True
871
874 wx.Panel.__init__(self, *args, **kwargs)
875
876 self.__do_layout()
877 self.__register_events()
878
880 self.__journal = wx.TextCtrl (
881 self,
882 -1,
883 _('No EMR data loaded.'),
884 style = wx.TE_MULTILINE | wx.TE_READONLY
885 )
886 self.__journal.SetFont(wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL))
887
888 szr_outer = wx.BoxSizer(wx.VERTICAL)
889 szr_outer.Add(self.__journal, 1, wx.EXPAND, 0)
890
891 self.SetAutoLayout(1)
892 self.SetSizer(szr_outer)
893 szr_outer.Fit(self)
894 szr_outer.SetSizeHints(self)
895 self.Layout()
896
898 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
899
901 """Expects to be in a Notebook."""
902 if self.GetParent().GetCurrentPage() == self:
903 self.repopulate_ui()
904 return True
905
906
907
909 txt = StringIO.StringIO()
910 exporter = gmPatientExporter.cEMRJournalExporter()
911
912
913 try:
914 exporter.export(txt)
915 self.__journal.SetValue(txt.getvalue())
916 except ValueError:
917 _log.exception('cannot get EMR journal')
918 self.__journal.SetValue (_(
919 'An error occurred while retrieving the EMR\n'
920 'in journal form for the active patient.\n\n'
921 'Please check the log file for details.'
922 ))
923 txt.close()
924 self.__journal.ShowPosition(self.__journal.GetLastPosition())
925 return True
926
927
928
929 if __name__ == '__main__':
930
931 _log.info("starting emr browser...")
932
933 try:
934
935 patient = gmPersonSearch.ask_for_patient()
936 if patient is None:
937 print "No patient. Exiting gracefully..."
938 sys.exit(0)
939 gmPatSearchWidgets.set_active_patient(patient = patient)
940
941
942 application = wx.PyWidgetTester(size=(800,600))
943 emr_browser = cEMRBrowserPanel(application.frame, -1)
944 emr_browser.refresh_tree()
945
946 application.frame.Show(True)
947 application.MainLoop()
948
949
950 if patient is not None:
951 try:
952 patient.cleanup()
953 except:
954 print "error cleaning up patient"
955 except StandardError:
956 _log.exception("unhandled exception caught !")
957
958 raise
959
960 _log.info("closing emr browser...")
961
962
963