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 self.__details_display.ShowPosition(0)
266
268
269
270 self.__epi_context_popup = wx.Menu(title = _('Episode Menu'))
271
272 menu_id = wx.NewId()
273 self.__epi_context_popup.AppendItem(wx.MenuItem(self.__epi_context_popup, menu_id, _('Edit details')))
274 wx.EVT_MENU(self.__epi_context_popup, menu_id, self.__edit_episode)
275
276 menu_id = wx.NewId()
277 self.__epi_context_popup.AppendItem(wx.MenuItem(self.__epi_context_popup, menu_id, _('Delete')))
278 wx.EVT_MENU(self.__epi_context_popup, menu_id, self.__delete_episode)
279
280 menu_id = wx.NewId()
281 self.__epi_context_popup.AppendItem(wx.MenuItem(self.__epi_context_popup, menu_id, _('Promote')))
282 wx.EVT_MENU(self.__epi_context_popup, menu_id, self.__promote_episode_to_issue)
283
284 menu_id = wx.NewId()
285 self.__epi_context_popup.AppendItem(wx.MenuItem(self.__epi_context_popup, menu_id, _('Move encounters')))
286 wx.EVT_MENU(self.__epi_context_popup, menu_id, self.__move_encounters)
287
288
289 self.__enc_context_popup = wx.Menu(title = _('Encounter Menu'))
290
291 menu_id = wx.NewId()
292 self.__enc_context_popup.AppendItem(wx.MenuItem(self.__enc_context_popup, menu_id, _('Move data to another episode')))
293 wx.EVT_MENU(self.__enc_context_popup, menu_id, self.__relink_encounter_data2episode)
294
295 menu_id = wx.NewId()
296 self.__enc_context_popup.AppendItem(wx.MenuItem(self.__enc_context_popup, menu_id, _('Edit details')))
297 wx.EVT_MENU(self.__enc_context_popup, menu_id, self.__edit_encounter_details)
298
299 item = self.__enc_context_popup.Append(-1, _('Edit progress notes'))
300 self.Bind(wx.EVT_MENU, self.__edit_progress_notes, item)
301
302 item = self.__enc_context_popup.Append(-1, _('Move progress notes'))
303 self.Bind(wx.EVT_MENU, self.__move_progress_notes, item)
304
305 item = self.__enc_context_popup.Append(-1, _('Export for Medistar'))
306 self.Bind(wx.EVT_MENU, self.__export_encounter_for_medistar, item)
307
308
309 self.__issue_context_popup = wx.Menu(title = _('Health Issue Menu'))
310
311 menu_id = wx.NewId()
312 self.__issue_context_popup.AppendItem(wx.MenuItem(self.__issue_context_popup, menu_id, _('Edit details')))
313 wx.EVT_MENU(self.__issue_context_popup, menu_id, self.__edit_issue)
314
315 menu_id = wx.NewId()
316 self.__issue_context_popup.AppendItem(wx.MenuItem(self.__issue_context_popup, menu_id, _('Delete')))
317 wx.EVT_MENU(self.__issue_context_popup, menu_id, self.__delete_issue)
318
319 self.__issue_context_popup.AppendSeparator()
320
321 menu_id = wx.NewId()
322 self.__issue_context_popup.AppendItem(wx.MenuItem(self.__issue_context_popup, menu_id, _('Open to encounter level')))
323 wx.EVT_MENU(self.__issue_context_popup, menu_id, self.__expand_issue_to_encounter_level)
324
325
326
327
328 self.__root_context_popup = wx.Menu(title = _('EMR Menu'))
329
330 menu_id = wx.NewId()
331 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Create health issue')))
332 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__create_issue)
333
334 menu_id = wx.NewId()
335 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage allergies')))
336 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__document_allergy)
337
338 menu_id = wx.NewId()
339 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage vaccinations')))
340 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__manage_vaccinations)
341
342 menu_id = wx.NewId()
343 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage procedures')))
344 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__manage_procedures)
345
346 menu_id = wx.NewId()
347 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage hospitalizations')))
348 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__manage_hospital_stays)
349
350 menu_id = wx.NewId()
351 self.__root_context_popup.AppendItem(wx.MenuItem(self.__root_context_popup, menu_id, _('Manage occupation')))
352 wx.EVT_MENU(self.__root_context_popup, menu_id, self.__manage_occupation)
353
354 self.__root_context_popup.AppendSeparator()
355
356
357 expand_menu = wx.Menu()
358 self.__root_context_popup.AppendMenu(wx.NewId(), _('Open EMR to ...'), expand_menu)
359
360 menu_id = wx.NewId()
361 expand_menu.AppendItem(wx.MenuItem(expand_menu, menu_id, _('... issue level')))
362 wx.EVT_MENU(expand_menu, menu_id, self.__expand_to_issue_level)
363
364 menu_id = wx.NewId()
365 expand_menu.AppendItem(wx.MenuItem(expand_menu, menu_id, _('... episode level')))
366 wx.EVT_MENU(expand_menu, menu_id, self.__expand_to_episode_level)
367
368 menu_id = wx.NewId()
369 expand_menu.AppendItem(wx.MenuItem(expand_menu, menu_id, _('... encounter level')))
370 wx.EVT_MENU(expand_menu, menu_id, self.__expand_to_encounter_level)
371
372 - def __handle_root_context(self, pos=wx.DefaultPosition):
373 self.PopupMenu(self.__root_context_popup, pos)
374
375 - def __handle_issue_context(self, pos=wx.DefaultPosition):
376
377 self.PopupMenu(self.__issue_context_popup, pos)
378
379 - def __handle_episode_context(self, pos=wx.DefaultPosition):
380 self.__epi_context_popup.SetTitle(_('Episode %s') % self.__curr_node_data['description'])
381 self.PopupMenu(self.__epi_context_popup, pos)
382
383 - def __handle_encounter_context(self, pos=wx.DefaultPosition):
384 self.PopupMenu(self.__enc_context_popup, pos)
385
386
387
396
399
403
405 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
406 parent = self,
407 id = -1,
408 caption = _('Deleting episode'),
409 button_defs = [
410 {'label': _('Yes, delete'), 'tooltip': _('Delete the episode if possible (it must be completely empty).')},
411 {'label': _('No, cancel'), 'tooltip': _('Cancel and do NOT delete the episode.')}
412 ],
413 question = _(
414 'Are you sure you want to delete this episode ?\n'
415 '\n'
416 ' "%s"\n'
417 ) % self.__curr_node_data['description']
418 )
419 result = dlg.ShowModal()
420 if result != wx.ID_YES:
421 return
422
423 try:
424 gmEMRStructItems.delete_episode(episode = self.__curr_node_data)
425 except gmExceptions.DatabaseObjectInUseError:
426 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete episode. There is still clinical data recorded for it.'))
427 return
428
429
430
441
443 encounter = self.GetPyData(self.__curr_node)
444 node_parent = self.GetItemParent(self.__curr_node)
445 episode = self.GetPyData(node_parent)
446
447 gmNarrativeWidgets.manage_progress_notes (
448 parent = self,
449 encounters = [encounter['pk_encounter']],
450 episodes = [episode['pk_episode']]
451 )
452
457
459
460 node_parent = self.GetItemParent(self.__curr_node)
461 owning_episode = self.GetPyData(node_parent)
462
463 episode_selector = gmNarrativeWidgets.cMoveNarrativeDlg (
464 self,
465 -1,
466 episode = owning_episode,
467 encounter = self.__curr_node_data
468 )
469
470 result = episode_selector.ShowModal()
471 episode_selector.Destroy()
472
473 if result == wx.ID_YES:
474 self.__populate_tree()
475
476
477
480
482 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
483 parent = self,
484 id = -1,
485 caption = _('Deleting health issue'),
486 button_defs = [
487 {'label': _('Yes, delete'), 'tooltip': _('Delete the health issue if possible (it must be completely empty).')},
488 {'label': _('No, cancel'), 'tooltip': _('Cancel and do NOT delete the health issue.')}
489 ],
490 question = _(
491 'Are you sure you want to delete this health issue ?\n'
492 '\n'
493 ' "%s"\n'
494 ) % self.__curr_node_data['description']
495 )
496 result = dlg.ShowModal()
497 if result != wx.ID_YES:
498 dlg.Destroy()
499 return
500
501 dlg.Destroy()
502
503 try:
504 gmEMRStructItems.delete_health_issue(health_issue = self.__curr_node_data)
505 except gmExceptions.DatabaseObjectInUseError:
506 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete health issue. There is still clinical data recorded for it.'))
507
509
510 if not self.__curr_node.IsOk():
511 return
512
513 self.Expand(self.__curr_node)
514
515 epi, epi_cookie = self.GetFirstChild(self.__curr_node)
516 while epi.IsOk():
517 self.Expand(epi)
518 epi, epi_cookie = self.GetNextChild(self.__curr_node, epi_cookie)
519
520
521
524
532
535
538
541
544
546
547 root_item = self.GetRootItem()
548
549 if not root_item.IsOk():
550 return
551
552 self.Expand(root_item)
553
554
555 issue, issue_cookie = self.GetFirstChild(root_item)
556 while issue.IsOk():
557 self.Collapse(issue)
558 epi, epi_cookie = self.GetFirstChild(issue)
559 while epi.IsOk():
560 self.Collapse(epi)
561 epi, epi_cookie = self.GetNextChild(issue, epi_cookie)
562 issue, issue_cookie = self.GetNextChild(root_item, issue_cookie)
563
565
566 root_item = self.GetRootItem()
567
568 if not root_item.IsOk():
569 return
570
571 self.Expand(root_item)
572
573
574 issue, issue_cookie = self.GetFirstChild(root_item)
575 while issue.IsOk():
576 self.Expand(issue)
577 epi, epi_cookie = self.GetFirstChild(issue)
578 while epi.IsOk():
579 self.Collapse(epi)
580 epi, epi_cookie = self.GetNextChild(issue, epi_cookie)
581 issue, issue_cookie = self.GetNextChild(root_item, issue_cookie)
582
584
585 root_item = self.GetRootItem()
586
587 if not root_item.IsOk():
588 return
589
590 self.Expand(root_item)
591
592
593 issue, issue_cookie = self.GetFirstChild(root_item)
594 while issue.IsOk():
595 self.Expand(issue)
596 epi, epi_cookie = self.GetFirstChild(issue)
597 while epi.IsOk():
598 self.Expand(epi)
599 epi, epi_cookie = self.GetNextChild(issue, epi_cookie)
600 issue, issue_cookie = self.GetNextChild(root_item, issue_cookie)
601
608
609
610
612 wx.CallAfter(self.__update_text_for_selected_node)
613
615 wx.CallAfter(self.__populate_tree)
616
618 wx.CallAfter(self.__populate_tree)
619
621 sel_item = event.GetItem()
622 self.__curr_node = sel_item
623 self.__update_text_for_selected_node()
624 return True
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
716
717
718
719
720
721
722
723
724
725
726
727
728
730 """Right button clicked: display the popup for the tree"""
731
732 node = event.GetItem()
733 self.SelectItem(node)
734 self.__curr_node_data = self.GetPyData(node)
735 self.__curr_node = node
736
737 pos = wx.DefaultPosition
738 if isinstance(self.__curr_node_data, gmEMRStructItems.cHealthIssue):
739 self.__handle_issue_context(pos=pos)
740 elif isinstance(self.__curr_node_data, gmEMRStructItems.cEpisode):
741 self.__handle_episode_context(pos=pos)
742 elif isinstance(self.__curr_node_data, gmEMRStructItems.cEncounter):
743 self.__handle_encounter_context(pos=pos)
744 elif node == self.GetRootItem():
745 self.__handle_root_context()
746 elif type(self.__curr_node_data) == type({}):
747
748 pass
749 else:
750 print "error: unknown node type, no popup menu"
751 event.Skip()
752
754 """Used in sorting items.
755
756 -1: 1 < 2
757 0: 1 = 2
758 1: 1 > 2
759 """
760
761
762 item1 = self.GetPyData(node1)
763 item2 = self.GetPyData(node2)
764
765
766 if isinstance(item1, type({})):
767 return -1
768 if isinstance(item2, type({})):
769 return 1
770
771
772 if isinstance(item1, gmEMRStructItems.cEncounter):
773 if item1['started'] == item2['started']:
774 return 0
775 if item1['started'] > item2['started']:
776 return -1
777 return 1
778
779
780 if isinstance(item1, gmEMRStructItems.cEpisode):
781 start1 = item1.get_access_range()[0]
782 start2 = item2.get_access_range()[0]
783 if start1 == start2:
784 return 0
785 if start1 < start2:
786 return -1
787 return 1
788
789
790 if isinstance(item1, gmEMRStructItems.cHealthIssue):
791
792
793 if item1['grouping'] is None:
794 if item2['grouping'] is not None:
795 return 1
796
797
798 if item1['grouping'] is not None:
799 if item2['grouping'] is None:
800 return -1
801
802
803 if (item1['grouping'] is None) and (item2['grouping'] is None):
804 if item1['description'].lower() < item2['description'].lower():
805 return -1
806 if item1['description'].lower() > item2['description'].lower():
807 return 1
808 return 0
809
810
811 if item1['grouping'] < item2['grouping']:
812 return -1
813
814 if item1['grouping'] > item2['grouping']:
815 return 1
816
817 if item1['description'].lower() < item2['description'].lower():
818 return -1
819
820 if item1['description'].lower() > item2['description'].lower():
821 return 1
822
823 return 0
824
825 _log.error('unknown item type during sorting EMR tree:')
826 _log.error('item1: %s', type(item1))
827 _log.error('item2: %s', type(item2))
828
829 return 0
830
831
832
834 return self.__details_display_mode
835
837 if mode not in [u'details', u'journal']:
838 raise ValueError('details display mode must be one of "details", "journal"')
839 if self.__details_display_mode == mode:
840 return
841 self.__details_display_mode = mode
842 self.__update_text_for_selected_node()
843
844 details_display_mode = property(_get_details_display_mode, _set_details_display_mode)
845
846 from Gnumed.wxGladeWidgets import wxgScrolledEMRTreePnl
847
861
862 from Gnumed.wxGladeWidgets import wxgSplittedEMRTreeBrowserPnl
863
865 """A splitter window holding an EMR tree.
866
867 The left hand side displays a scrollable EMR tree while
868 on the right details for selected items are displayed.
869
870 Expects to be put into a Notebook.
871 """
877
879 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
880 return True
881
882
883
885 if self.GetParent().GetCurrentPage() == self:
886 self.repopulate_ui()
887 return True
888
892
896
897
898
900 """Fills UI with data."""
901 self._pnl_emr_tree.repopulate_ui()
902 self._splitter_browser.SetSashPosition(self._splitter_browser.GetSizeTuple()[0]/3, True)
903 return True
904
907 wx.Panel.__init__(self, *args, **kwargs)
908
909 self.__do_layout()
910 self.__register_events()
911
913 self.__journal = wx.TextCtrl (
914 self,
915 -1,
916 _('No EMR data loaded.'),
917 style = wx.TE_MULTILINE | wx.TE_READONLY
918 )
919 self.__journal.SetFont(wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL))
920
921 szr_outer = wx.BoxSizer(wx.VERTICAL)
922 szr_outer.Add(self.__journal, 1, wx.EXPAND, 0)
923
924 self.SetAutoLayout(1)
925 self.SetSizer(szr_outer)
926 szr_outer.Fit(self)
927 szr_outer.SetSizeHints(self)
928 self.Layout()
929
931 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
932
934 """Expects to be in a Notebook."""
935 if self.GetParent().GetCurrentPage() == self:
936 self.repopulate_ui()
937 return True
938
939
940
942 txt = StringIO.StringIO()
943 exporter = gmPatientExporter.cEMRJournalExporter()
944
945
946 try:
947 exporter.export(txt)
948 self.__journal.SetValue(txt.getvalue())
949 except ValueError:
950 _log.exception('cannot get EMR journal')
951 self.__journal.SetValue (_(
952 'An error occurred while retrieving the EMR\n'
953 'in journal form for the active patient.\n\n'
954 'Please check the log file for details.'
955 ))
956 txt.close()
957 self.__journal.ShowPosition(self.__journal.GetLastPosition())
958 return True
959
960
961
962 if __name__ == '__main__':
963
964 _log.info("starting emr browser...")
965
966 try:
967
968 patient = gmPersonSearch.ask_for_patient()
969 if patient is None:
970 print "No patient. Exiting gracefully..."
971 sys.exit(0)
972 gmPatSearchWidgets.set_active_patient(patient = patient)
973
974
975 application = wx.PyWidgetTester(size=(800,600))
976 emr_browser = cEMRBrowserPanel(application.frame, -1)
977 emr_browser.refresh_tree()
978
979 application.frame.Show(True)
980 application.MainLoop()
981
982
983 if patient is not None:
984 try:
985 patient.cleanup()
986 except:
987 print "error cleaning up patient"
988 except StandardError:
989 _log.exception("unhandled exception caught !")
990
991 raise
992
993 _log.info("closing emr browser...")
994
995
996