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, 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):
100
101
102
104 if not self.__pat.connected:
105 gmDispatcher.send(signal='statustext', msg=_('Cannot load clinical narrative. No active patient.'),)
106 return False
107
108 if not self.__populate_tree():
109 return False
110
111 return True
112
114 self.__details_display = narrative_display
115
117 self.__img_display = image_display
118
119
120
122 """Configures enabled event signals."""
123 wx.EVT_TREE_SEL_CHANGED (self, self.GetId(), self._on_tree_item_selected)
124 wx.EVT_TREE_ITEM_RIGHT_CLICK (self, self.GetId(), self._on_tree_item_right_clicked)
125
126
127
128 wx.EVT_TREE_ITEM_GETTOOLTIP(self, -1, self._on_tree_item_gettooltip)
129
130 gmDispatcher.connect(signal = 'narrative_mod_db', receiver = self._on_narrative_mod_db)
131 gmDispatcher.connect(signal = 'episode_mod_db', receiver = self._on_episode_mod_db)
132 gmDispatcher.connect(signal = 'health_issue_mod_db', receiver = self._on_issue_mod_db)
133
135 """Updates EMR browser data."""
136
137
138
139 wx.BeginBusyCursor()
140
141
142
143
144 self.DeleteAllItems()
145 root_item = self.AddRoot(_('EMR of %(lastnames)s, %(firstnames)s') % self.__pat.get_active_name())
146 self.SetPyData(root_item, None)
147 self.SetItemHasChildren(root_item, True)
148 self.__root_tooltip = self.__pat['description_gender'] + u'\n'
149 if self.__pat['deceased'] is None:
150 self.__root_tooltip += u' %s %s (%s)\n\n' % (
151 gmPerson.map_gender2symbol[self.__pat['gender']],
152 self.__pat.get_formatted_dob(format = '%d %b %Y', encoding = gmI18N.get_encoding()),
153 self.__pat['medical_age']
154 )
155 else:
156 template = u' %s %s - %s (%s)\n\n'
157 self.__root_tooltip += template % (
158 gmPerson.map_gender2symbol[self.__pat['gender']],
159 self.__pat.get_formatted_dob(format = '%d.%b %Y', encoding = gmI18N.get_encoding()),
160 self.__pat['deceased'].strftime('%d.%b %Y').decode(gmI18N.get_encoding()),
161 self.__pat['medical_age']
162 )
163 self.__root_tooltip += gmTools.coalesce(self.__pat['comment'], u'', u'%s\n\n')
164 doc = self.__pat.primary_provider
165 if doc is not None:
166 self.__root_tooltip += u'%s:\n' % _('Primary provider in this praxis')
167 self.__root_tooltip += u' %s %s %s (%s)%s\n\n' % (
168 gmTools.coalesce(doc['title'], gmPerson.map_gender2salutation(gender = doc['gender'])),
169 doc['firstnames'],
170 doc['lastnames'],
171 doc['short_alias'],
172 gmTools.bool2subst(doc['is_active'], u'', u' [%s]' % _('inactive'))
173 )
174 if not ((self.__pat['emergency_contact'] is None) and (self.__pat['pk_emergency_contact'] is None)):
175 self.__root_tooltip += _('In case of emergency contact:') + u'\n'
176 if self.__pat['emergency_contact'] is not None:
177 self.__root_tooltip += gmTools.wrap (
178 text = u'%s\n' % self.__pat['emergency_contact'],
179 width = 60,
180 initial_indent = u' ',
181 subsequent_indent = u' '
182 )
183 if self.__pat['pk_emergency_contact'] is not None:
184 contact = self.__pat.emergency_contact_in_database
185 self.__root_tooltip += u' %s\n' % contact['description_gender']
186 self.__root_tooltip = self.__root_tooltip.strip('\n')
187 if self.__root_tooltip == u'':
188 self.__root_tooltip = u' '
189
190
191 self.__exporter.get_historical_tree(self)
192 self.__curr_node = root_item
193
194 self.SelectItem(root_item)
195 self.Expand(root_item)
196 self.__update_text_for_selected_node()
197
198
199
200 wx.EndBusyCursor()
201 return True
202
204 """Displays information for the selected tree node."""
205
206 if self.__details_display is None:
207 self.__img_display.clear()
208 return
209
210 if self.__curr_node is None:
211 self.__img_display.clear()
212 return
213
214 node_data = self.GetPyData(self.__curr_node)
215 doc_folder = self.__pat.get_document_folder()
216
217 if isinstance(node_data, gmEMRStructItems.cHealthIssue):
218 if self.__details_display_mode == u'details':
219 txt = node_data.format(left_margin=1, patient = self.__pat)
220 else:
221 txt = node_data.format_as_journal(left_margin = 1)
222
223 self.__img_display.refresh (
224 document_folder = doc_folder,
225 episodes = [ epi['pk_episode'] for epi in node_data.episodes ]
226 )
227
228 elif isinstance(node_data, type({})):
229
230 txt = _('Pool of unassociated episodes:\n\n "%s"') % node_data['description']
231 self.__img_display.clear()
232
233 elif isinstance(node_data, gmEMRStructItems.cEpisode):
234 if self.__details_display_mode == u'details':
235 txt = node_data.format(left_margin = 1, patient = self.__pat)
236 else:
237 txt = node_data.format_as_journal(left_margin = 1)
238 self.__img_display.refresh (
239 document_folder = doc_folder,
240 episodes = [node_data['pk_episode']]
241 )
242
243 elif isinstance(node_data, gmEMRStructItems.cEncounter):
244 epi = self.GetPyData(self.GetItemParent(self.__curr_node))
245 txt = node_data.format (
246 episodes = [epi['pk_episode']],
247 with_soap = True,
248 left_margin = 1,
249 patient = self.__pat,
250 with_co_encountlet_hints = True
251 )
252 self.__img_display.refresh (
253 document_folder = doc_folder,
254 episodes = [epi['pk_episode']],
255 encounter = node_data['pk_encounter']
256 )
257
258 else:
259 emr = self.__pat.get_emr()
260 txt = emr.format_summary(dob = self.__pat['dob'])
261 self.__img_display.clear()
262
263 self.__details_display.Clear()
264 self.__details_display.WriteText(txt)
265
267
268
269 self.__epi_context_popup = wx.Menu(title = _('Episode Menu'))
270
271 menu_id = wx.NewId()
272 self.__epi_context_popup.AppendItem(wx.MenuItem(self.__epi_context_popup, menu_id, _('Edit details')))
273 wx.EVT_MENU(self.__epi_context_popup, menu_id, self.__edit_episode)
274
275 menu_id = wx.NewId()
276 self.__epi_context_popup.AppendItem(wx.MenuItem(self.__epi_context_popup, menu_id, _('Delete')))
277 wx.EVT_MENU(self.__epi_context_popup, menu_id, self.__delete_episode)
278
279 menu_id = wx.NewId()
280 self.__epi_context_popup.AppendItem(wx.MenuItem(self.__epi_context_popup, menu_id, _('Promote')))
281 wx.EVT_MENU(self.__epi_context_popup, menu_id, self.__promote_episode_to_issue)
282
283 menu_id = wx.NewId()
284 self.__epi_context_popup.AppendItem(wx.MenuItem(self.__epi_context_popup, menu_id, _('Move encounters')))
285 wx.EVT_MENU(self.__epi_context_popup, menu_id, self.__move_encounters)
286
287
288 self.__enc_context_popup = wx.Menu(title = _('Encounter Menu'))
289
290 menu_id = wx.NewId()
291 self.__enc_context_popup.AppendItem(wx.MenuItem(self.__enc_context_popup, menu_id, _('Move data to another episode')))
292 wx.EVT_MENU(self.__enc_context_popup, menu_id, self.__relink_encounter_data2episode)
293
294 menu_id = wx.NewId()
295 self.__enc_context_popup.AppendItem(wx.MenuItem(self.__enc_context_popup, menu_id, _('Edit details')))
296 wx.EVT_MENU(self.__enc_context_popup, menu_id, self.__edit_encounter_details)
297
298 item = self.__enc_context_popup.Append(-1, _('Edit progress notes'))
299 self.Bind(wx.EVT_MENU, self.__edit_progress_notes, item)
300
301 item = self.__enc_context_popup.Append(-1, _('Move progress notes'))
302 self.Bind(wx.EVT_MENU, self.__move_progress_notes, item)
303
304 item = self.__enc_context_popup.Append(-1, _('Export for Medistar'))
305 self.Bind(wx.EVT_MENU, self.__export_encounter_for_medistar, item)
306
307
308 self.__issue_context_popup = wx.Menu(title = _('Health Issue Menu'))
309
310 menu_id = wx.NewId()
311 self.__issue_context_popup.AppendItem(wx.MenuItem(self.__issue_context_popup, menu_id, _('Edit details')))
312 wx.EVT_MENU(self.__issue_context_popup, menu_id, self.__edit_issue)
313
314 menu_id = wx.NewId()
315 self.__issue_context_popup.AppendItem(wx.MenuItem(self.__issue_context_popup, menu_id, _('Delete')))
316 wx.EVT_MENU(self.__issue_context_popup, menu_id, self.__delete_issue)
317
318 self.__issue_context_popup.AppendSeparator()
319
320 menu_id = wx.NewId()
321 self.__issue_context_popup.AppendItem(wx.MenuItem(self.__issue_context_popup, menu_id, _('Open to encounter level')))
322 wx.EVT_MENU(self.__issue_context_popup, menu_id, self.__expand_issue_to_encounter_level)
323
324
325
326
327 self.__root_context_popup = wx.Menu(title = _('EMR Menu'))
328
329 menu_id = wx.NewId()
330 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Create health issue')))
331 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__create_issue)
332
333 menu_id = wx.NewId()
334 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage allergies')))
335 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__document_allergy)
336
337 menu_id = wx.NewId()
338 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage vaccinations')))
339 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__manage_vaccinations)
340
341 menu_id = wx.NewId()
342 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage procedures')))
343 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__manage_procedures)
344
345 menu_id = wx.NewId()
346 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage hospitalizations')))
347 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__manage_hospital_stays)
348
349 menu_id = wx.NewId()
350 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage occupation')))
351 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__manage_occupation)
352
353 self.__root_context_popup.AppendSeparator()
354
355
356 expand_menu = wx.Menu()
357 self.__root_context_popup.AppendMenu(wx.NewId(), _('Open EMR to ...'), expand_menu)
358
359 menu_id = wx.NewId()
360 expand_menu.AppendItem(wx.MenuItem(expand_menu, menu_id, _('... issue level')))
361 wx.EVT_MENU(expand_menu, menu_id, self.__expand_to_issue_level)
362
363 menu_id = wx.NewId()
364 expand_menu.AppendItem(wx.MenuItem(expand_menu, menu_id, _('... episode level')))
365 wx.EVT_MENU(expand_menu, menu_id, self.__expand_to_episode_level)
366
367 menu_id = wx.NewId()
368 expand_menu.AppendItem(wx.MenuItem(expand_menu, menu_id, _('... encounter level')))
369 wx.EVT_MENU(expand_menu, menu_id, self.__expand_to_encounter_level)
370
371 - def __handle_root_context(self, pos=wx.DefaultPosition):
372 self.PopupMenu(self.__root_context_popup, pos)
373
374 - def __handle_issue_context(self, pos=wx.DefaultPosition):
375
376 self.PopupMenu(self.__issue_context_popup, pos)
377
378 - def __handle_episode_context(self, pos=wx.DefaultPosition):
379 self.__epi_context_popup.SetTitle(_('Episode %s') % self.__curr_node_data['description'])
380 self.PopupMenu(self.__epi_context_popup, pos)
381
382 - def __handle_encounter_context(self, pos=wx.DefaultPosition):
383 self.PopupMenu(self.__enc_context_popup, pos)
384
385
386
395
398
402
404 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
405 parent = self,
406 id = -1,
407 caption = _('Deleting episode'),
408 button_defs = [
409 {'label': _('Yes, delete'), 'tooltip': _('Delete the episode if possible (it must be completely empty).')},
410 {'label': _('No, cancel'), 'tooltip': _('Cancel and do NOT delete the episode.')}
411 ],
412 question = _(
413 'Are you sure you want to delete this episode ?\n'
414 '\n'
415 ' "%s"\n'
416 ) % self.__curr_node_data['description']
417 )
418 result = dlg.ShowModal()
419 if result != wx.ID_YES:
420 return
421
422 try:
423 gmEMRStructItems.delete_episode(episode = self.__curr_node_data)
424 except gmExceptions.DatabaseObjectInUseError:
425 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete episode. There is still clinical data recorded for it.'))
426 return
427
428
429
440
442 encounter = self.GetPyData(self.__curr_node)
443 node_parent = self.GetItemParent(self.__curr_node)
444 episode = self.GetPyData(node_parent)
445
446 gmNarrativeWidgets.manage_progress_notes (
447 parent = self,
448 encounters = [encounter['pk_encounter']],
449 episodes = [episode['pk_episode']]
450 )
451
456
458
459 node_parent = self.GetItemParent(self.__curr_node)
460 owning_episode = self.GetPyData(node_parent)
461
462 episode_selector = gmNarrativeWidgets.cMoveNarrativeDlg (
463 self,
464 -1,
465 episode = owning_episode,
466 encounter = self.__curr_node_data
467 )
468
469 result = episode_selector.ShowModal()
470 episode_selector.Destroy()
471
472 if result == wx.ID_YES:
473 self.__populate_tree()
474
475
476
479
481 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
482 parent = self,
483 id = -1,
484 caption = _('Deleting health issue'),
485 button_defs = [
486 {'label': _('Yes, delete'), 'tooltip': _('Delete the health issue if possible (it must be completely empty).')},
487 {'label': _('No, cancel'), 'tooltip': _('Cancel and do NOT delete the health issue.')}
488 ],
489 question = _(
490 'Are you sure you want to delete this health issue ?\n'
491 '\n'
492 ' "%s"\n'
493 ) % self.__curr_node_data['description']
494 )
495 result = dlg.ShowModal()
496 if result != wx.ID_YES:
497 dlg.Destroy()
498 return
499
500 dlg.Destroy()
501
502 try:
503 gmEMRStructItems.delete_health_issue(health_issue = self.__curr_node_data)
504 except gmExceptions.DatabaseObjectInUseError:
505 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete health issue. There is still clinical data recorded for it.'))
506
508
509 if not self.__curr_node.IsOk():
510 return
511
512 self.Expand(self.__curr_node)
513
514 epi, epi_cookie = self.GetFirstChild(self.__curr_node)
515 while epi.IsOk():
516 self.Expand(epi)
517 epi, epi_cookie = self.GetNextChild(self.__curr_node, epi_cookie)
518
519
520
523
531
534
537
540
543
545
546 root_item = self.GetRootItem()
547
548 if not root_item.IsOk():
549 return
550
551 self.Expand(root_item)
552
553
554 issue, issue_cookie = self.GetFirstChild(root_item)
555 while issue.IsOk():
556 self.Collapse(issue)
557 epi, epi_cookie = self.GetFirstChild(issue)
558 while epi.IsOk():
559 self.Collapse(epi)
560 epi, epi_cookie = self.GetNextChild(issue, epi_cookie)
561 issue, issue_cookie = self.GetNextChild(root_item, issue_cookie)
562
564
565 root_item = self.GetRootItem()
566
567 if not root_item.IsOk():
568 return
569
570 self.Expand(root_item)
571
572
573 issue, issue_cookie = self.GetFirstChild(root_item)
574 while issue.IsOk():
575 self.Expand(issue)
576 epi, epi_cookie = self.GetFirstChild(issue)
577 while epi.IsOk():
578 self.Collapse(epi)
579 epi, epi_cookie = self.GetNextChild(issue, epi_cookie)
580 issue, issue_cookie = self.GetNextChild(root_item, issue_cookie)
581
583
584 root_item = self.GetRootItem()
585
586 if not root_item.IsOk():
587 return
588
589 self.Expand(root_item)
590
591
592 issue, issue_cookie = self.GetFirstChild(root_item)
593 while issue.IsOk():
594 self.Expand(issue)
595 epi, epi_cookie = self.GetFirstChild(issue)
596 while epi.IsOk():
597 self.Expand(epi)
598 epi, epi_cookie = self.GetNextChild(issue, epi_cookie)
599 issue, issue_cookie = self.GetNextChild(root_item, issue_cookie)
600
607
608
609
611 wx.CallAfter(self.__update_text_for_selected_node)
612
614 wx.CallAfter(self.__populate_tree)
615
617 wx.CallAfter(self.__populate_tree)
618
620 sel_item = event.GetItem()
621 self.__curr_node = sel_item
622 self.__update_text_for_selected_node()
623 return True
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
715
716
717
718
719
720
721
722
723
724
725
726
727
729 """Right button clicked: display the popup for the tree"""
730
731 node = event.GetItem()
732 self.SelectItem(node)
733 self.__curr_node_data = self.GetPyData(node)
734 self.__curr_node = node
735
736 pos = wx.DefaultPosition
737 if isinstance(self.__curr_node_data, gmEMRStructItems.cHealthIssue):
738 self.__handle_issue_context(pos=pos)
739 elif isinstance(self.__curr_node_data, gmEMRStructItems.cEpisode):
740 self.__handle_episode_context(pos=pos)
741 elif isinstance(self.__curr_node_data, gmEMRStructItems.cEncounter):
742 self.__handle_encounter_context(pos=pos)
743 elif node == self.GetRootItem():
744 self.__handle_root_context()
745 elif type(self.__curr_node_data) == type({}):
746
747 pass
748 else:
749 print "error: unknown node type, no popup menu"
750 event.Skip()
751
753 """Used in sorting items.
754
755 -1: 1 < 2
756 0: 1 = 2
757 1: 1 > 2
758 """
759
760
761 item1 = self.GetPyData(node1)
762 item2 = self.GetPyData(node2)
763
764
765 if isinstance(item1, type({})):
766 return -1
767 if isinstance(item2, type({})):
768 return 1
769
770
771 if isinstance(item1, gmEMRStructItems.cEncounter):
772 if item1['started'] == item2['started']:
773 return 0
774 if item1['started'] > item2['started']:
775 return -1
776 return 1
777
778
779 if isinstance(item1, gmEMRStructItems.cEpisode):
780 start1 = item1.get_access_range()[0]
781 start2 = item2.get_access_range()[0]
782 if start1 == start2:
783 return 0
784 if start1 < start2:
785 return -1
786 return 1
787
788
789 if isinstance(item1, gmEMRStructItems.cHealthIssue):
790
791
792 if item1['grouping'] is None:
793 if item2['grouping'] is not None:
794 return 1
795
796
797 if item1['grouping'] is not None:
798 if item2['grouping'] is None:
799 return -1
800
801
802 if (item1['grouping'] is None) and (item2['grouping'] is None):
803 if item1['description'].lower() < item2['description'].lower():
804 return -1
805 if item1['description'].lower() > item2['description'].lower():
806 return 1
807 return 0
808
809
810 if item1['grouping'] < item2['grouping']:
811 return -1
812
813 if item1['grouping'] > item2['grouping']:
814 return 1
815
816 if item1['description'].lower() < item2['description'].lower():
817 return -1
818
819 if item1['description'].lower() > item2['description'].lower():
820 return 1
821
822 return 0
823
824 _log.error('unknown item type during sorting EMR tree:')
825 _log.error('item1: %s', type(item1))
826 _log.error('item2: %s', type(item2))
827
828 return 0
829
830
831
833 return self.__details_display_mode
834
836 if mode not in [u'details', u'journal']:
837 raise ValueError('details display mode must be one of "details", "journal"')
838 if self.__details_display_mode == mode:
839 return
840 self.__details_display_mode = mode
841 self.__update_text_for_selected_node()
842
843 details_display_mode = property(_get_details_display_mode, _set_details_display_mode)
844
845 from Gnumed.wxGladeWidgets import wxgScrolledEMRTreePnl
846
860
861 from Gnumed.wxGladeWidgets import wxgSplittedEMRTreeBrowserPnl
862
864 """A splitter window holding an EMR tree.
865
866 The left hand side displays a scrollable EMR tree while
867 on the right details for selected items are displayed.
868
869 Expects to be put into a Notebook.
870 """
876
878 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
879 return True
880
881
882
884 if self.GetParent().GetCurrentPage() == self:
885 self.repopulate_ui()
886 return True
887
891
895
896
897
899 """Fills UI with data."""
900 self._pnl_emr_tree.repopulate_ui()
901 self._splitter_browser.SetSashPosition(self._splitter_browser.GetSizeTuple()[0]/3, True)
902 return True
903
906 wx.Panel.__init__(self, *args, **kwargs)
907
908 self.__do_layout()
909 self.__register_events()
910
912 self.__journal = wx.TextCtrl (
913 self,
914 -1,
915 _('No EMR data loaded.'),
916 style = wx.TE_MULTILINE | wx.TE_READONLY
917 )
918 self.__journal.SetFont(wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL))
919
920 szr_outer = wx.BoxSizer(wx.VERTICAL)
921 szr_outer.Add(self.__journal, 1, wx.EXPAND, 0)
922
923 self.SetAutoLayout(1)
924 self.SetSizer(szr_outer)
925 szr_outer.Fit(self)
926 szr_outer.SetSizeHints(self)
927 self.Layout()
928
930 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
931
933 """Expects to be in a Notebook."""
934 if self.GetParent().GetCurrentPage() == self:
935 self.repopulate_ui()
936 return True
937
938
939
941 txt = StringIO.StringIO()
942 exporter = gmPatientExporter.cEMRJournalExporter()
943
944
945 try:
946 exporter.export(txt)
947 self.__journal.SetValue(txt.getvalue())
948 except ValueError:
949 _log.exception('cannot get EMR journal')
950 self.__journal.SetValue (_(
951 'An error occurred while retrieving the EMR\n'
952 'in journal form for the active patient.\n\n'
953 'Please check the log file for details.'
954 ))
955 txt.close()
956 self.__journal.ShowPosition(self.__journal.GetLastPosition())
957 return True
958
959
960
961 if __name__ == '__main__':
962
963 _log.info("starting emr browser...")
964
965 try:
966
967 patient = gmPersonSearch.ask_for_patient()
968 if patient is None:
969 print "No patient. Exiting gracefully..."
970 sys.exit(0)
971 gmPatSearchWidgets.set_active_patient(patient = patient)
972
973
974 application = wx.PyWidgetTester(size=(800,600))
975 emr_browser = cEMRBrowserPanel(application.frame, -1)
976 emr_browser.refresh_tree()
977
978 application.frame.Show(True)
979 application.MainLoop()
980
981
982 if patient is not None:
983 try:
984 patient.cleanup()
985 except:
986 print "error cleaning up patient"
987 except StandardError:
988 _log.exception("unhandled exception caught !")
989
990 raise
991
992 _log.info("closing emr browser...")
993
994
995