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 Actions:'))
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 Actions:'))
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 Actions:'))
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 Actions:'))
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
740
741
742
743
744
745
746
747
748
749
750
752 """Right button clicked: display the popup for the tree"""
753
754 node = event.GetItem()
755 self.SelectItem(node)
756 self.__curr_node_data = self.GetPyData(node)
757 self.__curr_node = node
758
759 pos = wx.DefaultPosition
760 if isinstance(self.__curr_node_data, gmEMRStructItems.cHealthIssue):
761 self.__handle_issue_context(pos=pos)
762 elif isinstance(self.__curr_node_data, gmEMRStructItems.cEpisode):
763 self.__handle_episode_context(pos=pos)
764 elif isinstance(self.__curr_node_data, gmEMRStructItems.cEncounter):
765 self.__handle_encounter_context(pos=pos)
766 elif node == self.GetRootItem():
767 self.__handle_root_context()
768 elif type(self.__curr_node_data) == type({}):
769
770 pass
771 else:
772 print "error: unknown node type, no popup menu"
773 event.Skip()
774
776 """Used in sorting items.
777
778 -1: 1 < 2
779 0: 1 = 2
780 1: 1 > 2
781 """
782
783
784 item1 = self.GetPyData(node1)
785 item2 = self.GetPyData(node2)
786
787
788 if isinstance(item1, type({})):
789 return -1
790 if isinstance(item2, type({})):
791 return 1
792
793
794 if isinstance(item1, gmEMRStructItems.cEncounter):
795 if item1['started'] == item2['started']:
796 return 0
797 if item1['started'] > item2['started']:
798 return -1
799 return 1
800
801
802 if isinstance(item1, gmEMRStructItems.cEpisode):
803 start1 = item1.get_access_range()[0]
804 start2 = item2.get_access_range()[0]
805 if start1 == start2:
806 return 0
807 if start1 < start2:
808 return -1
809 return 1
810
811
812 if isinstance(item1, gmEMRStructItems.cHealthIssue):
813
814
815 if item1['grouping'] is None:
816 if item2['grouping'] is not None:
817 return 1
818
819
820 if item1['grouping'] is not None:
821 if item2['grouping'] is None:
822 return -1
823
824
825 if (item1['grouping'] is None) and (item2['grouping'] is None):
826 if item1['description'].lower() < item2['description'].lower():
827 return -1
828 if item1['description'].lower() > item2['description'].lower():
829 return 1
830 return 0
831
832
833 if item1['grouping'] < item2['grouping']:
834 return -1
835
836 if item1['grouping'] > item2['grouping']:
837 return 1
838
839 if item1['description'].lower() < item2['description'].lower():
840 return -1
841
842 if item1['description'].lower() > item2['description'].lower():
843 return 1
844
845 return 0
846
847 _log.error('unknown item type during sorting EMR tree:')
848 _log.error('item1: %s', type(item1))
849 _log.error('item2: %s', type(item2))
850
851 return 0
852
853
854
856 return self.__details_display_mode
857
859 if mode not in [u'details', u'journal']:
860 raise ValueError('details display mode must be one of "details", "journal"')
861 if self.__details_display_mode == mode:
862 return
863 self.__details_display_mode = mode
864 self.__update_text_for_selected_node()
865
866 details_display_mode = property(_get_details_display_mode, _set_details_display_mode)
867
868 from Gnumed.wxGladeWidgets import wxgScrolledEMRTreePnl
869
883
884 from Gnumed.wxGladeWidgets import wxgSplittedEMRTreeBrowserPnl
885
887 """A splitter window holding an EMR tree.
888
889 The left hand side displays a scrollable EMR tree while
890 on the right details for selected items are displayed.
891
892 Expects to be put into a Notebook.
893 """
899
901 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
902 return True
903
904
905
907 if self.GetParent().GetCurrentPage() == self:
908 self.repopulate_ui()
909 return True
910
914
918
919
920
922 """Fills UI with data."""
923 self._pnl_emr_tree.repopulate_ui()
924 self._splitter_browser.SetSashPosition(self._splitter_browser.GetSizeTuple()[0]/3, True)
925 return True
926
929 wx.Panel.__init__(self, *args, **kwargs)
930
931 self.__do_layout()
932 self.__register_events()
933
935 self.__journal = wx.TextCtrl (
936 self,
937 -1,
938 _('No EMR data loaded.'),
939 style = wx.TE_MULTILINE | wx.TE_READONLY
940 )
941 self.__journal.SetFont(wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL))
942
943 szr_outer = wx.BoxSizer(wx.VERTICAL)
944 szr_outer.Add(self.__journal, 1, wx.EXPAND, 0)
945
946 self.SetAutoLayout(1)
947 self.SetSizer(szr_outer)
948 szr_outer.Fit(self)
949 szr_outer.SetSizeHints(self)
950 self.Layout()
951
953 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
954
956 """Expects to be in a Notebook."""
957 if self.GetParent().GetCurrentPage() == self:
958 self.repopulate_ui()
959 return True
960
961
962
964 txt = StringIO.StringIO()
965 exporter = gmPatientExporter.cEMRJournalExporter()
966
967
968 try:
969 exporter.export(txt)
970 self.__journal.SetValue(txt.getvalue())
971 except ValueError:
972 _log.exception('cannot get EMR journal')
973 self.__journal.SetValue (_(
974 'An error occurred while retrieving the EMR\n'
975 'in journal form for the active patient.\n\n'
976 'Please check the log file for details.'
977 ))
978 txt.close()
979 self.__journal.ShowPosition(self.__journal.GetLastPosition())
980 return True
981
982
983
984 if __name__ == '__main__':
985
986 _log.info("starting emr browser...")
987
988 try:
989
990 patient = gmPersonSearch.ask_for_patient()
991 if patient is None:
992 print "No patient. Exiting gracefully..."
993 sys.exit(0)
994 gmPatSearchWidgets.set_active_patient(patient = patient)
995
996
997 application = wx.PyWidgetTester(size=(800,600))
998 emr_browser = cEMRBrowserPanel(application.frame, -1)
999 emr_browser.refresh_tree()
1000
1001 application.frame.Show(True)
1002 application.MainLoop()
1003
1004
1005 if patient is not None:
1006 try:
1007 patient.cleanup()
1008 except:
1009 print "error cleaning up patient"
1010 except StandardError:
1011 _log.exception("unhandled exception caught !")
1012
1013 raise
1014
1015 _log.info("closing emr browser...")
1016
1017
1018