1 """Widgets dealing with patient demographics."""
2
3 __author__ = "R.Terry, SJ Tan, I Haywood, Carlos Moro <cfmoro1976@yahoo.es>"
4 __license__ = 'GPL v2 or later (details at http://www.gnu.org)'
5
6
7 import sys
8 import sys
9 import codecs
10 import re as regex
11 import logging
12 import os
13 import datetime as pydt
14
15
16 import wx
17 import wx.wizard
18 import wx.lib.imagebrowser as wx_imagebrowser
19 import wx.lib.statbmp as wx_genstatbmp
20
21
22
23 if __name__ == '__main__':
24 sys.path.insert(0, '../../')
25 from Gnumed.pycommon import gmDispatcher
26 from Gnumed.pycommon import gmI18N
27 from Gnumed.pycommon import gmMatchProvider
28 from Gnumed.pycommon import gmPG2
29 from Gnumed.pycommon import gmTools
30 from Gnumed.pycommon import gmCfg
31 from Gnumed.pycommon import gmDateTime
32 from Gnumed.pycommon import gmShellAPI
33 from Gnumed.pycommon import gmNetworkTools
34
35 from Gnumed.business import gmDemographicRecord
36 from Gnumed.business import gmPersonSearch
37 from Gnumed.business import gmSurgery
38 from Gnumed.business import gmPerson
39
40 from Gnumed.wxpython import gmPhraseWheel
41 from Gnumed.wxpython import gmRegetMixin
42 from Gnumed.wxpython import gmAuthWidgets
43 from Gnumed.wxpython import gmPersonContactWidgets
44 from Gnumed.wxpython import gmEditArea
45 from Gnumed.wxpython import gmListWidgets
46 from Gnumed.wxpython import gmDateTimeInput
47 from Gnumed.wxpython import gmDataMiningWidgets
48 from Gnumed.wxpython import gmGuiHelpers
49
50
51
52 _log = logging.getLogger('gm.ui')
53
54
55 try:
56 _('dummy-no-need-to-translate-but-make-epydoc-happy')
57 except NameError:
58 _ = lambda x:x
59
60
61
62
64 if tag_image is not None:
65 if tag_image['is_in_use']:
66 gmGuiHelpers.gm_show_info (
67 aTitle = _('Editing tag'),
68 aMessage = _(
69 'Cannot edit the image tag\n'
70 '\n'
71 ' "%s"\n'
72 '\n'
73 'because it is currently in use.\n'
74 ) % tag_image['l10n_description']
75 )
76 return False
77
78 ea = cTagImageEAPnl(parent = parent, id = -1)
79 ea.data = tag_image
80 ea.mode = gmTools.coalesce(tag_image, 'new', 'edit')
81 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
82 dlg.SetTitle(gmTools.coalesce(tag_image, _('Adding new tag'), _('Editing tag')))
83 if dlg.ShowModal() == wx.ID_OK:
84 dlg.Destroy()
85 return True
86 dlg.Destroy()
87 return False
88
98
99 def edit(tag_image=None):
100 return edit_tag_image(parent = parent, tag_image = tag_image, single_entry = (tag_image is not None))
101
102 def delete(tag):
103 if tag['is_in_use']:
104 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete this tag. It is in use.'), beep = True)
105 return False
106
107 return gmDemographicRecord.delete_tag_image(tag_image = tag['pk_tag_image'])
108
109 def refresh(lctrl):
110 tags = gmDemographicRecord.get_tag_images(order_by = u'l10n_description')
111 items = [ [
112 t['l10n_description'],
113 gmTools.bool2subst(t['is_in_use'], u'X', u''),
114 u'%s' % t['size'],
115 t['pk_tag_image']
116 ] for t in tags ]
117 lctrl.set_string_items(items)
118 lctrl.set_column_widths(widths = [wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE_USEHEADER, wx.LIST_AUTOSIZE_USEHEADER, wx.LIST_AUTOSIZE])
119 lctrl.set_data(tags)
120
121 msg = _('\nTags with images registered with GNUmed.\n')
122
123 tag = gmListWidgets.get_choices_from_list (
124 parent = parent,
125 msg = msg,
126 caption = _('Showing tags with images.'),
127 columns = [_('Tag name'), _('In use'), _('Image size'), u'#'],
128 single_selection = True,
129 new_callback = edit,
130 edit_callback = edit,
131 delete_callback = delete,
132 refresh_callback = refresh,
133 left_extra_button = (_('WWW'), _('Go to www.openclipart.org for images.'), go_to_openclipart_org)
134 )
135
136 return tag
137
138 from Gnumed.wxGladeWidgets import wxgTagImageEAPnl
139
140 -class cTagImageEAPnl(wxgTagImageEAPnl.wxgTagImageEAPnl, gmEditArea.cGenericEditAreaMixin):
141
159
160
161
163
164 valid = True
165
166 if self.mode == u'new':
167 if self.__selected_image_file is None:
168 valid = False
169 gmDispatcher.send(signal = 'statustext', msg = _('Must pick an image file for a new tag.'), beep = True)
170 self._BTN_pick_image.SetFocus()
171
172 if self.__selected_image_file is not None:
173 try:
174 open(self.__selected_image_file).close()
175 except StandardError:
176 valid = False
177 self.__selected_image_file = None
178 gmDispatcher.send(signal = 'statustext', msg = _('Cannot open the image file [%s].') % self.__selected_image_file, beep = True)
179 self._BTN_pick_image.SetFocus()
180
181 if self._TCTRL_description.GetValue().strip() == u'':
182 valid = False
183 self.display_tctrl_as_valid(self._TCTRL_description, False)
184 self._TCTRL_description.SetFocus()
185 else:
186 self.display_tctrl_as_valid(self._TCTRL_description, True)
187
188 return (valid is True)
189
208
228
230 self._TCTRL_description.SetValue(u'')
231 self._TCTRL_filename.SetValue(u'')
232 self._BMP_image.SetBitmap(bitmap = wx.EmptyBitmap(100, 100))
233
234 self.__selected_image_file = None
235
236 self._TCTRL_description.SetFocus()
237
239 self._refresh_as_new()
240
253
254
255
267
268
269 from Gnumed.wxGladeWidgets import wxgVisualSoapPresenterPnl
270
272
274 wxgVisualSoapPresenterPnl.wxgVisualSoapPresenterPnl.__init__(self, *args, **kwargs)
275 self._SZR_bitmaps = self.GetSizer()
276 self.__bitmaps = []
277
278 self.__context_popup = wx.Menu()
279
280 item = self.__context_popup.Append(-1, _('&Edit comment'))
281 self.Bind(wx.EVT_MENU, self.__edit_tag, item)
282
283 item = self.__context_popup.Append(-1, _('&Remove tag'))
284 self.Bind(wx.EVT_MENU, self.__remove_tag, item)
285
286
287
289
290 self.clear()
291
292 for tag in patient.get_tags(order_by = u'l10n_description'):
293 fname = tag.export_image2file()
294 if fname is None:
295 _log.warning('cannot export image data of tag [%s]', tag['l10n_description'])
296 continue
297 img = gmGuiHelpers.file2scaled_image(filename = fname, height = 20)
298 bmp = wx_genstatbmp.GenStaticBitmap(self, -1, img, style = wx.NO_BORDER)
299 bmp.SetToolTipString(u'%s%s' % (
300 tag['l10n_description'],
301 gmTools.coalesce(tag['comment'], u'', u'\n\n%s')
302 ))
303 bmp.tag = tag
304 bmp.Bind(wx.EVT_RIGHT_UP, self._on_bitmap_rightclicked)
305
306 self._SZR_bitmaps.Add(bmp, 0, wx.LEFT | wx.RIGHT | wx.TOP | wx.BOTTOM, 1)
307 self.__bitmaps.append(bmp)
308
309 self.GetParent().Layout()
310
312 while len(self._SZR_bitmaps.GetChildren()) > 0:
313 self._SZR_bitmaps.Detach(0)
314
315
316 for bmp in self.__bitmaps:
317 bmp.Destroy()
318 self.__bitmaps = []
319
320
321
329
331 if self.__current_tag is None:
332 return
333
334 msg = _('Edit the comment on tag [%s]') % self.__current_tag['l10n_description']
335 comment = wx.GetTextFromUser (
336 message = msg,
337 caption = _('Editing tag comment'),
338 default_value = gmTools.coalesce(self.__current_tag['comment'], u''),
339 parent = self
340 )
341
342 if comment == u'':
343 return
344
345 if comment.strip() == self.__current_tag['comment']:
346 return
347
348 if comment == u' ':
349 self.__current_tag['comment'] = None
350 else:
351 self.__current_tag['comment'] = comment.strip()
352
353 self.__current_tag.save()
354
355
356
358 self.__current_tag = evt.GetEventObject().tag
359 self.PopupMenu(self.__context_popup, pos = wx.DefaultPosition)
360 self.__current_tag = None
361
362
364
366
367 kwargs['message'] = _("Today's KOrganizer appointments ...")
368 kwargs['button_defs'] = [
369 {'label': _('Reload'), 'tooltip': _('Reload appointments from KOrganizer')},
370 {'label': u''},
371 {'label': u''},
372 {'label': u''},
373 {'label': u'KOrganizer', 'tooltip': _('Launch KOrganizer')}
374 ]
375 gmDataMiningWidgets.cPatientListingPnl.__init__(self, *args, **kwargs)
376
377 self.fname = os.path.expanduser(os.path.join('~', '.gnumed', 'tmp', 'korganizer2gnumed.csv'))
378 self.reload_cmd = 'konsolekalendar --view --export-type csv --export-file %s' % self.fname
379
380
384
394
396 try: os.remove(self.fname)
397 except OSError: pass
398 gmShellAPI.run_command_in_shell(command=self.reload_cmd, blocking=True)
399 try:
400 csv_file = codecs.open(self.fname , mode = 'rU', encoding = 'utf8', errors = 'replace')
401 except IOError:
402 gmDispatcher.send(signal = u'statustext', msg = _('Cannot access KOrganizer transfer file [%s]') % self.fname, beep = True)
403 return
404
405 csv_lines = gmTools.unicode_csv_reader (
406 csv_file,
407 delimiter = ','
408 )
409
410 self._LCTRL_items.set_columns ([
411 _('Place'),
412 _('Start'),
413 u'',
414 u'',
415 _('Patient'),
416 _('Comment')
417 ])
418 items = []
419 data = []
420 for line in csv_lines:
421 items.append([line[5], line[0], line[1], line[3], line[4], line[6]])
422 data.append([line[4], line[7]])
423
424 self._LCTRL_items.set_string_items(items = items)
425 self._LCTRL_items.set_column_widths()
426 self._LCTRL_items.set_data(data = data)
427 self._LCTRL_items.patient_key = 0
428
429
430
433
434
435
437
438 pat = gmPerson.gmCurrentPatient()
439 curr_jobs = pat.get_occupations()
440 if len(curr_jobs) > 0:
441 old_job = curr_jobs[0]['l10n_occupation']
442 update = curr_jobs[0]['modified_when'].strftime('%m/%Y')
443 else:
444 old_job = u''
445 update = u''
446
447 msg = _(
448 'Please enter the primary occupation of the patient.\n'
449 '\n'
450 'Currently recorded:\n'
451 '\n'
452 ' %s (last updated %s)'
453 ) % (old_job, update)
454
455 new_job = wx.GetTextFromUser (
456 message = msg,
457 caption = _('Editing primary occupation'),
458 default_value = old_job,
459 parent = None
460 )
461 if new_job.strip() == u'':
462 return
463
464 for job in curr_jobs:
465
466 if job['l10n_occupation'] != new_job:
467 pat.unlink_occupation(occupation = job['l10n_occupation'])
468
469 pat.link_occupation(occupation = new_job)
470
471
486
487
488
489
491
492 go_ahead = gmGuiHelpers.gm_show_question (
493 _('Are you sure you really, positively want\n'
494 'to disable the following person ?\n'
495 '\n'
496 ' %s %s %s\n'
497 ' born %s\n'
498 '\n'
499 '%s\n'
500 ) % (
501 identity['firstnames'],
502 identity['lastnames'],
503 identity['gender'],
504 identity.get_formatted_dob(),
505 gmTools.bool2subst (
506 identity.is_patient,
507 _('This patient DID receive care.'),
508 _('This person did NOT receive care.')
509 )
510 ),
511 _('Disabling person')
512 )
513 if not go_ahead:
514 return True
515
516
517 conn = gmAuthWidgets.get_dbowner_connection (
518 procedure = _('Disabling patient')
519 )
520
521 if conn is False:
522 return True
523
524 if conn is None:
525 return False
526
527
528 gmPG2.run_rw_queries(queries = [{'cmd': u"update dem.identity set deleted=True where pk=%s", 'args': [identity['pk_identity']]}])
529
530 return True
531
532
533
534
549
551
553 query = u"""
554 (SELECT distinct firstnames, firstnames from dem.names where firstnames %(fragment_condition)s order by firstnames limit 20)
555 union
556 (SELECT distinct name, name from dem.name_gender_map where name %(fragment_condition)s order by name limit 20)"""
557 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
558 mp.setThresholds(3, 5, 9)
559 gmPhraseWheel.cPhraseWheel.__init__ (
560 self,
561 *args,
562 **kwargs
563 )
564 self.SetToolTipString(_("Type or select a first name (forename/Christian name/given name)."))
565 self.capitalisation_mode = gmTools.CAPS_NAMES
566 self.matcher = mp
567
569
571 query = u"""
572 (SELECT distinct preferred, preferred from dem.names where preferred %(fragment_condition)s order by preferred limit 20)
573 union
574 (SELECT distinct firstnames, firstnames from dem.names where firstnames %(fragment_condition)s order by firstnames limit 20)
575 union
576 (SELECT distinct name, name from dem.name_gender_map where name %(fragment_condition)s order by name limit 20)"""
577 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
578 mp.setThresholds(3, 5, 9)
579 gmPhraseWheel.cPhraseWheel.__init__ (
580 self,
581 *args,
582 **kwargs
583 )
584 self.SetToolTipString(_("Type or select an alias (nick name, preferred name, call name, warrior name, artist name)."))
585
586
587 self.matcher = mp
588
590
592 query = u"SELECT distinct title, title from dem.identity where title %(fragment_condition)s"
593 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
594 mp.setThresholds(1, 3, 9)
595 gmPhraseWheel.cPhraseWheel.__init__ (
596 self,
597 *args,
598 **kwargs
599 )
600 self.SetToolTipString(_("Type or select a title. Note that the title applies to the person, not to a particular name !"))
601 self.matcher = mp
602
604 """Let user select a gender."""
605
606 _gender_map = None
607
609
610 if cGenderSelectionPhraseWheel._gender_map is None:
611 cmd = u"""
612 SELECT tag, l10n_label, sort_weight
613 from dem.v_gender_labels
614 order by sort_weight desc"""
615 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx=True)
616 cGenderSelectionPhraseWheel._gender_map = {}
617 for gender in rows:
618 cGenderSelectionPhraseWheel._gender_map[gender[idx['tag']]] = {
619 'data': gender[idx['tag']],
620 'field_label': gender[idx['l10n_label']],
621 'list_label': gender[idx['l10n_label']],
622 'weight': gender[idx['sort_weight']]
623 }
624
625 mp = gmMatchProvider.cMatchProvider_FixedList(aSeq = cGenderSelectionPhraseWheel._gender_map.values())
626 mp.setThresholds(1, 1, 3)
627
628 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
629 self.selection_only = True
630 self.matcher = mp
631 self.picklist_delay = 50
632
634
636 query = u"""
637 SELECT DISTINCT ON (list_label)
638 pk AS data,
639 name AS field_label,
640 name || coalesce(' (' || issuer || ')', '') as list_label
641 FROM dem.enum_ext_id_types
642 WHERE name %(fragment_condition)s
643 ORDER BY list_label
644 LIMIT 25
645 """
646 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
647 mp.setThresholds(1, 3, 5)
648 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
649 self.SetToolTipString(_("Enter or select a type for the external ID."))
650 self.matcher = mp
651
656
671
672
673
674 from Gnumed.wxGladeWidgets import wxgExternalIDEditAreaPnl
675
676 -class cExternalIDEditAreaPnl(wxgExternalIDEditAreaPnl.wxgExternalIDEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
677 """An edit area for editing/creating external IDs.
678
679 Does NOT act on/listen to the current patient.
680 """
700
703
704
705
726
744
760
766
768 self._refresh_as_new()
769 self._PRW_issuer.SetText(self.data['issuer'])
770
776
777
778
780 """Set the issuer according to the selected type.
781
782 Matches are fetched from existing records in backend.
783 """
784 pk_curr_type = self._PRW_type.GetData()
785 if pk_curr_type is None:
786 return True
787 rows, idx = gmPG2.run_ro_queries(queries = [{
788 'cmd': u"SELECT issuer from dem.enum_ext_id_types where pk = %s",
789 'args': [pk_curr_type]
790 }])
791 if len(rows) == 0:
792 return True
793 wx.CallAfter(self._PRW_issuer.SetText, rows[0][0])
794 return True
795
796
797
798
800 allow_empty_dob = gmGuiHelpers.gm_show_question (
801 _(
802 'Are you sure you want to leave this person\n'
803 'without a valid date of birth ?\n'
804 '\n'
805 'This can be useful for temporary staff members\n'
806 'but will provoke nag screens if this person\n'
807 'becomes a patient.\n'
808 ),
809 _('Validating date of birth')
810 )
811 return allow_empty_dob
812
814
815
816 if dob_prw.is_valid_timestamp(allow_empty = False):
817 dob = dob_prw.date
818
819 if (dob.year > 1899) and (dob < gmDateTime.pydt_now_here()):
820 return True
821
822 if dob.year < 1900:
823 msg = _(
824 'DOB: %s\n'
825 '\n'
826 'While this is a valid point in time Python does\n'
827 'not know how to deal with it.\n'
828 '\n'
829 'We suggest using January 1st 1901 instead and adding\n'
830 'the true date of birth to the patient comment.\n'
831 '\n'
832 'Sorry for the inconvenience %s'
833 ) % (dob, gmTools.u_frowning_face)
834 else:
835 msg = _(
836 'DOB: %s\n'
837 '\n'
838 'Date of birth in the future !'
839 ) % dob
840 gmGuiHelpers.gm_show_error (
841 msg,
842 _('Validating date of birth')
843 )
844 dob_prw.display_as_valid(False)
845 dob_prw.SetFocus()
846 return False
847
848
849 if dob_prw.GetValue().strip() != u'':
850 dob_prw.display_as_valid(False)
851 gmDispatcher.send(signal = u'statustext', msg = _('Invalid date of birth.'))
852 dob_prw.SetFocus()
853 return False
854
855
856 dob_prw.display_as_valid(False)
857 return True
858
859
861
862 val = ctrl.GetValue().strip()
863
864 if val == u'':
865 return True
866
867 converted, hours = gmTools.input2int(val[:2], 0, 23)
868 if not converted:
869 return False
870
871 converted, minutes = gmTools.input2int(val[3:5], 0, 59)
872 if not converted:
873 return False
874
875 return True
876
877
878 from Gnumed.wxGladeWidgets import wxgIdentityEAPnl
879
880 -class cIdentityEAPnl(wxgIdentityEAPnl.wxgIdentityEAPnl, gmEditArea.cGenericEditAreaMixin):
881 """An edit area for editing/creating title/gender/dob/dod etc."""
882
898
899
900
901
902
903
904
905
907
908 has_error = False
909
910 if self._PRW_gender.GetData() is None:
911 self._PRW_gender.SetFocus()
912 has_error = True
913
914 if self.data is not None:
915 if not _validate_dob_field(self._PRW_dob):
916 has_error = True
917
918
919 if _validate_tob_field(self._TCTRL_tob):
920 self.display_ctrl_as_valid(ctrl = self._TCTRL_tob, valid = True)
921 else:
922 has_error = True
923 self.display_ctrl_as_valid(ctrl = self._TCTRL_tob, valid = False)
924
925 if not self._PRW_dod.is_valid_timestamp(allow_empty = True):
926 gmDispatcher.send(signal = u'statustext', msg = _('Invalid date of death.'))
927 self._PRW_dod.SetFocus()
928 has_error = True
929
930 return (has_error is False)
931
935
937
938 if self._PRW_dob.GetValue().strip() == u'':
939 if not _empty_dob_allowed():
940 return False
941 self.data['dob'] = None
942 else:
943 self.data['dob'] = self._PRW_dob.GetData()
944 self.data['dob_is_estimated'] = self._CHBOX_estimated_dob.GetValue()
945 val = self._TCTRL_tob.GetValue().strip()
946 if val == u'':
947 self.data['tob'] = None
948 else:
949 self.data['tob'] = pydt.time(int(val[:2]), int(val[3:5]))
950 self.data['gender'] = self._PRW_gender.GetData()
951 self.data['title'] = gmTools.none_if(self._PRW_title.GetValue().strip(), u'')
952 self.data['deceased'] = self._PRW_dod.GetData()
953 self.data['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
954
955 self.data.save()
956 return True
957
960
994
997
998 from Gnumed.wxGladeWidgets import wxgPersonNameEAPnl
999
1000 -class cPersonNameEAPnl(wxgPersonNameEAPnl.wxgPersonNameEAPnl, gmEditArea.cGenericEditAreaMixin):
1001 """An edit area for editing/creating names of people.
1002
1003 Does NOT act on/listen to the current patient.
1004 """
1025
1026
1027
1028
1029
1030
1031
1032
1034 validity = True
1035
1036 if self._PRW_lastname.GetValue().strip() == u'':
1037 validity = False
1038 self._PRW_lastname.display_as_valid(False)
1039 self._PRW_lastname.SetFocus()
1040 else:
1041 self._PRW_lastname.display_as_valid(True)
1042
1043 if self._PRW_firstname.GetValue().strip() == u'':
1044 validity = False
1045 self._PRW_firstname.display_as_valid(False)
1046 self._PRW_firstname.SetFocus()
1047 else:
1048 self._PRW_firstname.display_as_valid(True)
1049
1050 return validity
1051
1053
1054 first = self._PRW_firstname.GetValue().strip()
1055 last = self._PRW_lastname.GetValue().strip()
1056 active = self._CHBOX_active.GetValue()
1057
1058 data = self.__identity.add_name(first, last, active)
1059
1060 old_nick = self.__identity['active_name']['preferred']
1061 new_nick = gmTools.none_if(self._PRW_nick.GetValue().strip(), u'')
1062 if active:
1063 data['preferred'] = gmTools.coalesce(new_nick, old_nick)
1064 else:
1065 data['preferred'] = new_nick
1066 data['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
1067 data.save()
1068
1069 self.data = data
1070 return True
1071
1073 """The knack here is that we can only update a few fields.
1074
1075 Otherwise we need to clone the name and update that.
1076 """
1077 first = self._PRW_firstname.GetValue().strip()
1078 last = self._PRW_lastname.GetValue().strip()
1079 active = self._CHBOX_active.GetValue()
1080
1081 current_name = self.data['firstnames'].strip() + self.data['lastnames'].strip()
1082 new_name = first + last
1083
1084
1085 if new_name == current_name:
1086 self.data['active_name'] = self._CHBOX_active.GetValue()
1087 self.data['preferred'] = gmTools.none_if(self._PRW_nick.GetValue().strip(), u'')
1088 self.data['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
1089 self.data.save()
1090
1091 else:
1092 name = self.__identity.add_name(first, last, active)
1093 name['preferred'] = gmTools.none_if(self._PRW_nick.GetValue().strip(), u'')
1094 name['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
1095 name.save()
1096 self.data = name
1097
1098 return True
1099
1108
1115
1124
1125
1126
1128 """A list for managing a person's names.
1129
1130 Does NOT act on/listen to the current patient.
1131 """
1149
1150
1151
1152 - def refresh(self, *args, **kwargs):
1169
1170
1171
1173 self._LCTRL_items.set_columns(columns = [
1174 _('Active'),
1175 _('Lastname'),
1176 _('Firstname(s)'),
1177 _('Preferred Name'),
1178 _('Comment')
1179 ])
1180
1191
1201
1203
1204 if len(self.__identity.get_names()) == 1:
1205 gmDispatcher.send(signal = u'statustext', msg = _('Cannot delete the only name of a person.'), beep = True)
1206 return False
1207
1208 if name['active_name']:
1209 gmDispatcher.send(signal = u'statustext', msg = _('Cannot delete the active name of a person.'), beep = True)
1210 return False
1211
1212 go_ahead = gmGuiHelpers.gm_show_question (
1213 _( 'It is often advisable to keep old names around and\n'
1214 'just create a new "currently active" name.\n'
1215 '\n'
1216 'This allows finding the patient by both the old\n'
1217 'and the new name (think before/after marriage).\n'
1218 '\n'
1219 'Do you still want to really delete\n'
1220 "this name from the patient ?"
1221 ),
1222 _('Deleting name')
1223 )
1224 if not go_ahead:
1225 return False
1226
1227 self.__identity.delete_name(name = name)
1228 return True
1229
1230
1231
1233 return self.__identity
1234
1238
1239 identity = property(_get_identity, _set_identity)
1240
1242 """A list for managing a person's external IDs.
1243
1244 Does NOT act on/listen to the current patient.
1245 """
1263
1264
1265
1266 - def refresh(self, *args, **kwargs):
1283
1284
1285
1287 self._LCTRL_items.set_columns(columns = [
1288 _('ID type'),
1289 _('Value'),
1290 _('Issuer'),
1291 _('Comment')
1292 ])
1293
1304
1315
1317 go_ahead = gmGuiHelpers.gm_show_question (
1318 _( 'Do you really want to delete this\n'
1319 'external ID from the patient ?'),
1320 _('Deleting external ID')
1321 )
1322 if not go_ahead:
1323 return False
1324 self.__identity.delete_external_id(pk_ext_id = ext_id['pk_id'])
1325 return True
1326
1327
1328
1330 return self.__identity
1331
1335
1336 identity = property(_get_identity, _set_identity)
1337
1338
1339
1340 from Gnumed.wxGladeWidgets import wxgPersonIdentityManagerPnl
1341
1343 """A panel for editing identity data for a person.
1344
1345 - provides access to:
1346 - identity EA
1347 - name list manager
1348 - external IDs list manager
1349
1350 Does NOT act on/listen to the current patient.
1351 """
1358
1359
1360
1362 self._PNL_names.identity = self.__identity
1363 self._PNL_ids.identity = self.__identity
1364
1365 self._PNL_identity.mode = 'new'
1366 self._PNL_identity.data = self.__identity
1367 if self.__identity is not None:
1368 self._PNL_identity.mode = 'edit'
1369 self._PNL_identity._refresh_from_existing()
1370
1371
1372
1374 return self.__identity
1375
1379
1380 identity = property(_get_identity, _set_identity)
1381
1382
1383
1387
1388
1391
1392
1393 from Gnumed.wxGladeWidgets import wxgPersonSocialNetworkManagerPnl
1394
1403
1404
1405
1407
1408 tt = _('Link another person in this database as the emergency contact:\n\nEnter person name part or identifier and hit <enter>.')
1409
1410 if self.__identity is None:
1411 self._TCTRL_er_contact.SetValue(u'')
1412 self._TCTRL_person.person = None
1413 self._TCTRL_person.SetToolTipString(tt)
1414
1415 self._PRW_provider.SetText(value = u'', data = None)
1416 return
1417
1418 self._TCTRL_er_contact.SetValue(gmTools.coalesce(self.__identity['emergency_contact'], u''))
1419 if self.__identity['pk_emergency_contact'] is not None:
1420 ident = gmPerson.cIdentity(aPK_obj = self.__identity['pk_emergency_contact'])
1421 self._TCTRL_person.person = ident
1422 tt = u'%s\n\n%s\n\n%s' % (
1423 tt,
1424 ident['description_gender'],
1425 u'\n'.join([
1426 u'%s: %s%s' % (
1427 c['l10n_comm_type'],
1428 c['url'],
1429 gmTools.bool2subst(c['is_confidential'], _(' (confidential !)'), u'', u'')
1430 )
1431 for c in ident.get_comm_channels()
1432 ])
1433 )
1434 else:
1435 self._TCTRL_person.person = None
1436
1437 self._TCTRL_person.SetToolTipString(tt)
1438
1439 if self.__identity['pk_primary_provider'] is None:
1440 self._PRW_provider.SetText(value = u'', data = None)
1441 else:
1442 self._PRW_provider.SetData(data = self.__identity['pk_primary_provider'])
1443
1444
1445
1447 return self.__identity
1448
1452
1453 identity = property(_get_identity, _set_identity)
1454
1455
1456
1471
1474
1485
1493
1494
1495
1497
1498 dbcfg = gmCfg.cCfgSQL()
1499
1500 def_region = dbcfg.get2 (
1501 option = u'person.create.default_region',
1502 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1503 bias = u'user'
1504 )
1505 def_country = None
1506
1507 if def_region is None:
1508 def_country = dbcfg.get2 (
1509 option = u'person.create.default_country',
1510 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1511 bias = u'user'
1512 )
1513 else:
1514 countries = gmDemographicRecord.get_country_for_region(region = def_region)
1515 if len(countries) == 1:
1516 def_country = countries[0]['code_country']
1517
1518 if parent is None:
1519 parent = wx.GetApp().GetTopWindow()
1520
1521 ea = cNewPatientEAPnl(parent = parent, id = -1, country = def_country, region = def_region)
1522 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = True)
1523 dlg.SetTitle(_('Adding new person'))
1524 ea._PRW_lastname.SetFocus()
1525 result = dlg.ShowModal()
1526 pat = ea.data
1527 dlg.Destroy()
1528
1529 if result != wx.ID_OK:
1530 return False
1531
1532 _log.debug('created new person [%s]', pat.ID)
1533
1534 if activate:
1535 from Gnumed.wxpython import gmPatSearchWidgets
1536 gmPatSearchWidgets.set_active_patient(patient = pat)
1537
1538 gmDispatcher.send(signal = 'display_widget', name = 'gmNotebookedPatientEditionPlugin')
1539
1540 return True
1541
1542 from Gnumed.wxGladeWidgets import wxgNewPatientEAPnl
1543
1544 -class cNewPatientEAPnl(wxgNewPatientEAPnl.wxgNewPatientEAPnl, gmEditArea.cGenericEditAreaMixin):
1545
1547
1548 try:
1549 self.default_region = kwargs['region']
1550 del kwargs['region']
1551 except KeyError:
1552 self.default_region = None
1553
1554 try:
1555 self.default_country = kwargs['country']
1556 del kwargs['country']
1557 except KeyError:
1558 self.default_country = None
1559
1560 wxgNewPatientEAPnl.wxgNewPatientEAPnl.__init__(self, *args, **kwargs)
1561 gmEditArea.cGenericEditAreaMixin.__init__(self)
1562
1563 self.mode = 'new'
1564 self.data = None
1565 self._address = None
1566
1567 self.__init_ui()
1568 self.__register_interests()
1569
1570
1571
1573 self._PRW_lastname.final_regex = '.+'
1574 self._PRW_firstnames.final_regex = '.+'
1575 self._PRW_address_searcher.selection_only = False
1576
1577
1578
1579
1580 if self.default_country is not None:
1581 match = self._PRW_country._data2match(data = self.default_country)
1582 if match is not None:
1583 self._PRW_country.SetText(value = match['field_label'], data = match['data'])
1584
1585 if self.default_region is not None:
1586 self._PRW_region.SetText(value = self.default_region)
1587
1588 self._PRW_type.SetText(value = u'home')
1589
1591
1592 adr = self._PRW_address_searcher.address
1593 if adr is None:
1594 return True
1595
1596 if ctrl.GetValue().strip() != adr[field]:
1597 wx.CallAfter(self._PRW_address_searcher.SetText, value = u'', data = None)
1598 return True
1599
1600 return False
1601
1603 adr = self._PRW_address_searcher.address
1604 if adr is None:
1605 return True
1606
1607 self._PRW_zip.SetText(value = adr['postcode'], data = adr['postcode'])
1608
1609 self._PRW_street.SetText(value = adr['street'], data = adr['street'])
1610 self._PRW_street.set_context(context = u'zip', val = adr['postcode'])
1611
1612 self._PRW_urb.SetText(value = adr['urb'], data = adr['urb'])
1613 self._PRW_urb.set_context(context = u'zip', val = adr['postcode'])
1614
1615 self._PRW_region.SetText(value = adr['l10n_state'], data = adr['code_state'])
1616 self._PRW_region.set_context(context = u'zip', val = adr['postcode'])
1617
1618 self._PRW_country.SetText(value = adr['l10n_country'], data = adr['code_country'])
1619 self._PRW_country.set_context(context = u'zip', val = adr['postcode'])
1620
1622 error = False
1623
1624
1625 if self._PRW_lastname.GetValue().strip() == u'':
1626 error = True
1627 gmDispatcher.send(signal = 'statustext', msg = _('Must enter lastname.'))
1628 self._PRW_lastname.display_as_valid(False)
1629 else:
1630 self._PRW_lastname.display_as_valid(True)
1631
1632 if self._PRW_firstnames.GetValue().strip() == '':
1633 error = True
1634 gmDispatcher.send(signal = 'statustext', msg = _('Must enter first name.'))
1635 self._PRW_firstnames.display_as_valid(False)
1636 else:
1637 self._PRW_firstnames.display_as_valid(True)
1638
1639
1640 if self._PRW_gender.GetData() is None:
1641 error = True
1642 gmDispatcher.send(signal = 'statustext', msg = _('Must select gender.'))
1643 self._PRW_gender.display_as_valid(False)
1644 else:
1645 self._PRW_gender.display_as_valid(True)
1646
1647
1648 if not _validate_dob_field(self._PRW_dob):
1649 error = True
1650
1651
1652 if _validate_tob_field(self._TCTRL_tob):
1653 self.display_ctrl_as_valid(ctrl = self._TCTRL_tob, valid = True)
1654 else:
1655 error = True
1656 self.display_ctrl_as_valid(ctrl = self._TCTRL_tob, valid = False)
1657
1658 return (not error)
1659
1661
1662
1663 if self._PRW_address_searcher.GetData() is not None:
1664 wx.CallAfter(self.__set_fields_from_address_searcher)
1665 return True
1666
1667
1668 fields_to_fill = (
1669 self._TCTRL_number,
1670 self._PRW_zip,
1671 self._PRW_street,
1672 self._PRW_urb,
1673 self._PRW_type
1674 )
1675 no_of_filled_fields = 0
1676
1677 for field in fields_to_fill:
1678 if field.GetValue().strip() != u'':
1679 no_of_filled_fields += 1
1680 field.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
1681 field.Refresh()
1682
1683
1684 if no_of_filled_fields == 0:
1685 if empty_address_is_valid:
1686 return True
1687 else:
1688 return None
1689
1690
1691 if no_of_filled_fields != len(fields_to_fill):
1692 for field in fields_to_fill:
1693 if field.GetValue().strip() == u'':
1694 field.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
1695 field.SetFocus()
1696 field.Refresh()
1697 msg = _('To properly create an address, all the related fields must be filled in.')
1698 gmGuiHelpers.gm_show_error(msg, _('Required fields'))
1699 return False
1700
1701
1702
1703
1704 strict_fields = (
1705 self._PRW_type,
1706 self._PRW_region,
1707 self._PRW_country
1708 )
1709 error = False
1710 for field in strict_fields:
1711 if field.GetData() is None:
1712 error = True
1713 field.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
1714 field.SetFocus()
1715 else:
1716 field.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
1717 field.Refresh()
1718
1719 if error:
1720 msg = _('This field must contain an item selected from the dropdown list.')
1721 gmGuiHelpers.gm_show_error(msg, _('Required fields'))
1722 return False
1723
1724 return True
1725
1743
1744
1745
1747 """Set the gender according to entered firstname.
1748
1749 Matches are fetched from existing records in backend.
1750 """
1751
1752
1753 if self._PRW_gender.GetData() is not None:
1754 return True
1755
1756 firstname = self._PRW_firstnames.GetValue().strip()
1757 if firstname == u'':
1758 return True
1759
1760 gender = gmPerson.map_firstnames2gender(firstnames = firstname)
1761 if gender is None:
1762 return True
1763
1764 wx.CallAfter(self._PRW_gender.SetData, gender)
1765 return True
1766
1768 self.__perhaps_invalidate_address_searcher(self._PRW_zip, 'postcode')
1769
1770 zip_code = gmTools.none_if(self._PRW_zip.GetValue().strip(), u'')
1771 self._PRW_street.set_context(context = u'zip', val = zip_code)
1772 self._PRW_urb.set_context(context = u'zip', val = zip_code)
1773 self._PRW_region.set_context(context = u'zip', val = zip_code)
1774 self._PRW_country.set_context(context = u'zip', val = zip_code)
1775
1776 return True
1777
1779 self.__perhaps_invalidate_address_searcher(self._PRW_country, 'l10n_country')
1780
1781 country = gmTools.none_if(self._PRW_country.GetValue().strip(), u'')
1782 self._PRW_region.set_context(context = u'country', val = country)
1783
1784 return True
1785
1787 if self._TCTRL_number.GetValue().strip() == u'':
1788 adr = self._PRW_address_searcher.address
1789 if adr is None:
1790 return True
1791 self._TCTRL_number.SetValue(adr['number'])
1792 return True
1793
1794 self.__perhaps_invalidate_address_searcher(self._TCTRL_number, 'number')
1795 return True
1796
1798 if self._TCTRL_unit.GetValue().strip() == u'':
1799 adr = self._PRW_address_searcher.address
1800 if adr is None:
1801 return True
1802 self._TCTRL_unit.SetValue(gmTools.coalesce(adr['subunit'], u''))
1803 return True
1804
1805 self.__perhaps_invalidate_address_searcher(self._TCTRL_unit, 'subunit')
1806 return True
1807
1809 mapping = [
1810 (self._PRW_street, 'street'),
1811 (self._PRW_urb, 'urb'),
1812 (self._PRW_region, 'l10n_state')
1813 ]
1814
1815 for ctrl, field in mapping:
1816 if self.__perhaps_invalidate_address_searcher(ctrl, field):
1817 return True
1818
1819 return True
1820
1822 if self._PRW_address_searcher.address is None:
1823 return True
1824
1825 wx.CallAfter(self.__set_fields_from_address_searcher)
1826 return True
1827
1828
1829
1831 if self._PRW_primary_provider.GetValue().strip() == u'':
1832 self._PRW_primary_provider.display_as_valid(True)
1833 else:
1834 if self._PRW_primary_provider.GetData() is None:
1835 self._PRW_primary_provider.display_as_valid(False)
1836 else:
1837 self._PRW_primary_provider.display_as_valid(True)
1838 return (self.__identity_valid_for_save() and self.__address_valid_for_save(empty_address_is_valid = True))
1839
1841
1842 if self._PRW_dob.GetValue().strip() == u'':
1843 if not _empty_dob_allowed():
1844 self._PRW_dob.display_as_valid(False)
1845 self._PRW_dob.SetFocus()
1846 return False
1847
1848
1849 new_identity = gmPerson.create_identity (
1850 gender = self._PRW_gender.GetData(),
1851 dob = self._PRW_dob.GetData(),
1852 lastnames = self._PRW_lastname.GetValue().strip(),
1853 firstnames = self._PRW_firstnames.GetValue().strip()
1854 )
1855 _log.debug('identity created: %s' % new_identity)
1856
1857 new_identity['dob_is_estimated'] = self._CHBOX_estimated_dob.GetValue()
1858 val = self._TCTRL_tob.GetValue().strip()
1859 if val != u'':
1860 new_identity['tob'] = pydt.time(int(val[:2]), int(val[3:5]))
1861 new_identity['title'] = gmTools.none_if(self._PRW_title.GetValue().strip())
1862 new_identity.set_nickname(nickname = gmTools.none_if(self._PRW_nickname.GetValue().strip(), u''))
1863
1864 prov = self._PRW_primary_provider.GetData()
1865 if prov is not None:
1866 new_identity['pk_primary_provider'] = prov
1867 new_identity['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
1868 new_identity.save()
1869
1870
1871
1872 is_valid = self.__address_valid_for_save(empty_address_is_valid = False)
1873 if is_valid is True:
1874
1875
1876 try:
1877 new_identity.link_address (
1878 number = self._TCTRL_number.GetValue().strip(),
1879 street = self._PRW_street.GetValue().strip(),
1880 postcode = self._PRW_zip.GetValue().strip(),
1881 urb = self._PRW_urb.GetValue().strip(),
1882 state = self._PRW_region.GetData(),
1883 country = self._PRW_country.GetData(),
1884 subunit = gmTools.none_if(self._TCTRL_unit.GetValue().strip(), u''),
1885 id_type = self._PRW_type.GetData()
1886 )
1887 except gmPG2.dbapi.InternalError:
1888 _log.debug('number: >>%s<<', self._TCTRL_number.GetValue().strip())
1889 _log.debug('(sub)unit: >>%s<<', self._TCTRL_unit.GetValue().strip())
1890 _log.debug('street: >>%s<<', self._PRW_street.GetValue().strip())
1891 _log.debug('postcode: >>%s<<', self._PRW_zip.GetValue().strip())
1892 _log.debug('urb: >>%s<<', self._PRW_urb.GetValue().strip())
1893 _log.debug('state: >>%s<<', self._PRW_region.GetData().strip())
1894 _log.debug('country: >>%s<<', self._PRW_country.GetData().strip())
1895 _log.exception('cannot link address')
1896 gmGuiHelpers.gm_show_error (
1897 aTitle = _('Saving address'),
1898 aMessage = _(
1899 'Cannot save this address.\n'
1900 '\n'
1901 'You will have to add it via the Demographics plugin.\n'
1902 )
1903 )
1904 elif is_valid is False:
1905 gmGuiHelpers.gm_show_error (
1906 aTitle = _('Saving address'),
1907 aMessage = _(
1908 'Address not saved.\n'
1909 '\n'
1910 'You will have to add it via the Demographics plugin.\n'
1911 )
1912 )
1913
1914
1915
1916 channel_name = self._PRW_channel_type.GetValue().strip()
1917 pk_channel_type = self._PRW_channel_type.GetData()
1918 if pk_channel_type is None:
1919 if channel_name == u'':
1920 channel_name = u'homephone'
1921 new_identity.link_comm_channel (
1922 comm_medium = channel_name,
1923 pk_channel_type = pk_channel_type,
1924 url = gmTools.none_if(self._TCTRL_phone.GetValue().strip(), u''),
1925 is_confidential = False
1926 )
1927
1928
1929 pk_type = self._PRW_external_id_type.GetData()
1930 id_value = self._TCTRL_external_id_value.GetValue().strip()
1931 if (pk_type is not None) and (id_value != u''):
1932 new_identity.add_external_id(value = id_value, pk_type = pk_type)
1933
1934
1935 new_identity.link_occupation (
1936 occupation = gmTools.none_if(self._PRW_occupation.GetValue().strip(), u'')
1937 )
1938
1939 self.data = new_identity
1940 return True
1941
1943 raise NotImplementedError('[%s]: not expected to be used' % self.__class__.__name__)
1944
1948
1951
1953 raise NotImplementedError('[%s]: not expected to be used' % self.__class__.__name__)
1954
1955
1956
1957
1959 """Notebook displaying demographics editing pages:
1960
1961 - Identity (as per Jim/Rogerio 12/2011)
1962 - Contacts (addresses, phone numbers, etc)
1963 - Social network (significant others, GP, etc)
1964
1965 Does NOT act on/listen to the current patient.
1966 """
1967
1969
1970 wx.Notebook.__init__ (
1971 self,
1972 parent = parent,
1973 id = id,
1974 style = wx.NB_TOP | wx.NB_MULTILINE | wx.NO_BORDER,
1975 name = self.__class__.__name__
1976 )
1977
1978 self.__identity = None
1979 self.__do_layout()
1980 self.SetSelection(0)
1981
1982
1983
1985 """Populate fields in pages with data from model."""
1986 for page_idx in range(self.GetPageCount()):
1987 page = self.GetPage(page_idx)
1988 page.identity = self.__identity
1989
1990 return True
1991
1992
1993
1995 """Build patient edition notebook pages."""
1996
1997
1998 new_page = cPersonIdentityManagerPnl(self, -1)
1999 new_page.identity = self.__identity
2000 self.AddPage (
2001 page = new_page,
2002 text = _('Identity'),
2003 select = False
2004 )
2005
2006
2007 new_page = gmPersonContactWidgets.cPersonContactsManagerPnl(self, -1)
2008 new_page.identity = self.__identity
2009 self.AddPage (
2010 page = new_page,
2011 text = _('Contacts'),
2012 select = True
2013 )
2014
2015
2016 new_page = cPersonSocialNetworkManagerPnl(self, -1)
2017 new_page.identity = self.__identity
2018 self.AddPage (
2019 page = new_page,
2020 text = _('Social network'),
2021 select = False
2022 )
2023
2024
2025
2027 return self.__identity
2028
2031
2032 identity = property(_get_identity, _set_identity)
2033
2034
2035
2036
2037
2038
2040 """Page containing patient occupations edition fields.
2041 """
2042 - def __init__(self, parent, id, ident=None):
2043 """
2044 Creates a new instance of BasicPatDetailsPage
2045 @param parent - The parent widget
2046 @type parent - A wx.Window instance
2047 @param id - The widget id
2048 @type id - An integer
2049 """
2050 wx.Panel.__init__(self, parent, id)
2051 self.__ident = ident
2052 self.__do_layout()
2053
2055 PNL_form = wx.Panel(self, -1)
2056
2057 STT_occupation = wx.StaticText(PNL_form, -1, _('Occupation'))
2058 self.PRW_occupation = cOccupationPhraseWheel(parent = PNL_form, id = -1)
2059 self.PRW_occupation.SetToolTipString(_("primary occupation of the patient"))
2060
2061 STT_occupation_updated = wx.StaticText(PNL_form, -1, _('Last updated'))
2062 self.TTC_occupation_updated = wx.TextCtrl(PNL_form, -1, style = wx.TE_READONLY)
2063
2064
2065 SZR_input = wx.FlexGridSizer(cols = 2, rows = 5, vgap = 4, hgap = 4)
2066 SZR_input.AddGrowableCol(1)
2067 SZR_input.Add(STT_occupation, 0, wx.SHAPED)
2068 SZR_input.Add(self.PRW_occupation, 1, wx.EXPAND)
2069 SZR_input.Add(STT_occupation_updated, 0, wx.SHAPED)
2070 SZR_input.Add(self.TTC_occupation_updated, 1, wx.EXPAND)
2071 PNL_form.SetSizerAndFit(SZR_input)
2072
2073
2074 SZR_main = wx.BoxSizer(wx.VERTICAL)
2075 SZR_main.Add(PNL_form, 1, wx.EXPAND)
2076 self.SetSizer(SZR_main)
2077
2080
2081 - def refresh(self, identity=None):
2082 if identity is not None:
2083 self.__ident = identity
2084 jobs = self.__ident.get_occupations()
2085 if len(jobs) > 0:
2086 self.PRW_occupation.SetText(jobs[0]['l10n_occupation'])
2087 self.TTC_occupation_updated.SetValue(jobs[0]['modified_when'].strftime('%m/%Y'))
2088 return True
2089
2091 if self.PRW_occupation.IsModified():
2092 new_job = self.PRW_occupation.GetValue().strip()
2093 jobs = self.__ident.get_occupations()
2094 for job in jobs:
2095 if job['l10n_occupation'] == new_job:
2096 continue
2097 self.__ident.unlink_occupation(occupation = job['l10n_occupation'])
2098 self.__ident.link_occupation(occupation = new_job)
2099 return True
2100
2102 """Patient demographics plugin for main notebook.
2103
2104 Hosts another notebook with pages for Identity, Contacts, etc.
2105
2106 Acts on/listens to the currently active patient.
2107 """
2108
2114
2115
2116
2117
2118
2119
2121 """Arrange widgets."""
2122 self.__patient_notebook = cPersonDemographicsEditorNb(self, -1)
2123
2124 szr_main = wx.BoxSizer(wx.VERTICAL)
2125 szr_main.Add(self.__patient_notebook, 1, wx.EXPAND)
2126 self.SetSizerAndFit(szr_main)
2127
2128
2129
2131 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
2132 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
2133
2135 self._schedule_data_reget()
2136
2138 self._schedule_data_reget()
2139
2140
2150
2151
2152 if __name__ == "__main__":
2153
2154
2156 app = wx.PyWidgetTester(size = (600, 400))
2157 app.SetWidget(cKOrganizerSchedulePnl)
2158 app.MainLoop()
2159
2161 app = wx.PyWidgetTester(size = (600, 400))
2162 widget = cPersonNamesManagerPnl(app.frame, -1)
2163 widget.identity = activate_patient()
2164 app.frame.Show(True)
2165 app.MainLoop()
2166
2168 app = wx.PyWidgetTester(size = (600, 400))
2169 widget = cPersonIDsManagerPnl(app.frame, -1)
2170 widget.identity = activate_patient()
2171 app.frame.Show(True)
2172 app.MainLoop()
2173
2175 app = wx.PyWidgetTester(size = (600, 400))
2176 widget = cPersonIdentityManagerPnl(app.frame, -1)
2177 widget.identity = activate_patient()
2178 app.frame.Show(True)
2179 app.MainLoop()
2180
2185
2187 app = wx.PyWidgetTester(size = (600, 400))
2188 widget = cPersonDemographicsEditorNb(app.frame, -1)
2189 widget.identity = activate_patient()
2190 widget.refresh()
2191 app.frame.Show(True)
2192 app.MainLoop()
2193
2202
2203 if len(sys.argv) > 1 and sys.argv[1] == 'test':
2204
2205 gmI18N.activate_locale()
2206 gmI18N.install_domain(domain='gnumed')
2207 gmPG2.get_connection()
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219 test_person_ids_pnl()
2220
2221
2222
2223
2224
2225
2226