| Home | Trees | Indices | Help |
|
|---|
|
|
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 # standard library
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 # GNUmed specific
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 # constant defs
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 # image tags related widgets
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 #------------------------------------------------------------
90
91 if parent is None:
92 parent = wx.GetApp().GetTopWindow()
93 #------------------------------------------------------------
94 def go_to_openclipart_org(tag_image):
95 gmNetworkTools.open_url_in_browser(url = u'http://www.openclipart.org')
96 gmNetworkTools.open_url_in_browser(url = u'http://commons.wikimedia.org/wiki/Category:Symbols_of_disabilities')
97 gmNetworkTools.open_url_in_browser(url = u'http://www.duckduckgo.com')
98 gmNetworkTools.open_url_in_browser(url = u'http://images.google.com')
99 return True
100 #------------------------------------------------------------
101 def edit(tag_image=None):
102 return edit_tag_image(parent = parent, tag_image = tag_image, single_entry = (tag_image is not None))
103 #------------------------------------------------------------
104 def delete(tag):
105 if tag['is_in_use']:
106 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete this tag. It is in use.'), beep = True)
107 return False
108
109 return gmDemographicRecord.delete_tag_image(tag_image = tag['pk_tag_image'])
110 #------------------------------------------------------------
111 def refresh(lctrl):
112 tags = gmDemographicRecord.get_tag_images(order_by = u'l10n_description')
113 items = [ [
114 t['l10n_description'],
115 gmTools.bool2subst(t['is_in_use'], u'X', u''),
116 u'%s' % t['size'],
117 t['pk_tag_image']
118 ] for t in tags ]
119 lctrl.set_string_items(items)
120 lctrl.set_column_widths(widths = [wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE_USEHEADER, wx.LIST_AUTOSIZE_USEHEADER, wx.LIST_AUTOSIZE])
121 lctrl.set_data(tags)
122 #------------------------------------------------------------
123 msg = _('\nTags with images registered with GNUmed.\n')
124
125 tag = gmListWidgets.get_choices_from_list (
126 parent = parent,
127 msg = msg,
128 caption = _('Showing tags with images.'),
129 columns = [_('Tag name'), _('In use'), _('Image size'), u'#'],
130 single_selection = True,
131 new_callback = edit,
132 edit_callback = edit,
133 delete_callback = delete,
134 refresh_callback = refresh,
135 left_extra_button = (_('WWW'), _('Go to www.openclipart.org for images.'), go_to_openclipart_org)
136 )
137
138 return tag
139 #------------------------------------------------------------
140 from Gnumed.wxGladeWidgets import wxgTagImageEAPnl
141
143
145
146 try:
147 data = kwargs['tag_image']
148 del kwargs['tag_image']
149 except KeyError:
150 data = None
151
152 wxgTagImageEAPnl.wxgTagImageEAPnl.__init__(self, *args, **kwargs)
153 gmEditArea.cGenericEditAreaMixin.__init__(self)
154
155 self.mode = 'new'
156 self.data = data
157 if data is not None:
158 self.mode = 'edit'
159
160 self.__selected_image_file = None
161 #----------------------------------------------------------------
162 # generic Edit Area mixin API
163 #----------------------------------------------------------------
165
166 valid = True
167
168 if self.mode == u'new':
169 if self.__selected_image_file is None:
170 valid = False
171 gmDispatcher.send(signal = 'statustext', msg = _('Must pick an image file for a new tag.'), beep = True)
172 self._BTN_pick_image.SetFocus()
173
174 if self.__selected_image_file is not None:
175 try:
176 open(self.__selected_image_file).close()
177 except StandardError:
178 valid = False
179 self.__selected_image_file = None
180 gmDispatcher.send(signal = 'statustext', msg = _('Cannot open the image file [%s].') % self.__selected_image_file, beep = True)
181 self._BTN_pick_image.SetFocus()
182
183 if self._TCTRL_description.GetValue().strip() == u'':
184 valid = False
185 self.display_tctrl_as_valid(self._TCTRL_description, False)
186 self._TCTRL_description.SetFocus()
187 else:
188 self.display_tctrl_as_valid(self._TCTRL_description, True)
189
190 return (valid is True)
191 #----------------------------------------------------------------
193
194 dbo_conn = gmAuthWidgets.get_dbowner_connection(procedure = _('Creating tag with image'))
195 if dbo_conn is None:
196 return False
197
198 data = gmDemographicRecord.create_tag_image(description = self._TCTRL_description.GetValue().strip(), link_obj = dbo_conn)
199 dbo_conn.close()
200
201 data['filename'] = self._TCTRL_filename.GetValue().strip()
202 data.save()
203 data.update_image_from_file(filename = self.__selected_image_file)
204
205 # must be done very late or else the property access
206 # will refresh the display such that later field
207 # access will return empty values
208 self.data = data
209 return True
210 #----------------------------------------------------------------
212
213 # this is somewhat fake as it never actually uses the gm-dbo conn
214 # (although it does verify it)
215 dbo_conn = gmAuthWidgets.get_dbowner_connection(procedure = _('Updating tag with image'))
216 if dbo_conn is None:
217 return False
218 dbo_conn.close()
219
220 self.data['description'] = self._TCTRL_description.GetValue().strip()
221 self.data['filename'] = self._TCTRL_filename.GetValue().strip()
222 self.data.save()
223
224 if self.__selected_image_file is not None:
225 open(self.__selected_image_file).close()
226 self.data.update_image_from_file(filename = self.__selected_image_file)
227 self.__selected_image_file = None
228
229 return True
230 #----------------------------------------------------------------
232 self._TCTRL_description.SetValue(u'')
233 self._TCTRL_filename.SetValue(u'')
234 self._BMP_image.SetBitmap(bitmap = wx.EmptyBitmap(100, 100))
235
236 self.__selected_image_file = None
237
238 self._TCTRL_description.SetFocus()
239 #----------------------------------------------------------------
242 #----------------------------------------------------------------
244 self._TCTRL_description.SetValue(self.data['l10n_description'])
245 self._TCTRL_filename.SetValue(gmTools.coalesce(self.data['filename'], u''))
246 fname = self.data.export_image2file()
247 if fname is None:
248 self._BMP_image.SetBitmap(bitmap = wx.EmptyBitmap(100, 100))
249 else:
250 self._BMP_image.SetBitmap(bitmap = gmGuiHelpers.file2scaled_image(filename = fname, height = 100))
251
252 self.__selected_image_file = None
253
254 self._TCTRL_description.SetFocus()
255 #----------------------------------------------------------------
256 # event handlers
257 #----------------------------------------------------------------
269
270 #============================================================
285 #--------------------------------------------------------
286 def delete(tag):
287 do_delete = gmGuiHelpers.gm_show_question (
288 title = _('Deleting patient tag'),
289 question = _('Do you really want to delete this patient tag ?')
290 )
291 if not do_delete:
292 return False
293 patient.remove_tag(tag = tag['pk_identity_tag'])
294 return True
295 #--------------------------------------------------------
296 def manage_available_tags(tag):
297 manage_tag_images(parent = parent)
298 return False
299 #--------------------------------------------------------
300 msg = _('Tags of patient: %s\n') % patient['description_gender']
301
302 return gmListWidgets.get_choices_from_list (
303 parent = parent,
304 msg = msg,
305 caption = _('Showing patient tags'),
306 columns = [_('Tag'), _('Comment')],
307 single_selection = False,
308 delete_callback = delete,
309 refresh_callback = refresh,
310 left_extra_button = (_('Manage'), _('Manage available tags.'), manage_available_tags)
311 )
312 #============================================================
313 from Gnumed.wxGladeWidgets import wxgVisualSoapPresenterPnl
314
316
318 wxgVisualSoapPresenterPnl.wxgVisualSoapPresenterPnl.__init__(self, *args, **kwargs)
319 self._SZR_bitmaps = self.GetSizer()
320 self.__bitmaps = []
321
322 self.__context_popup = wx.Menu()
323
324 item = self.__context_popup.Append(-1, _('&Edit comment'))
325 self.Bind(wx.EVT_MENU, self.__edit_tag, item)
326
327 item = self.__context_popup.Append(-1, _('&Remove tag'))
328 self.Bind(wx.EVT_MENU, self.__remove_tag, item)
329 #--------------------------------------------------------
330 # external API
331 #--------------------------------------------------------
333
334 self.clear()
335
336 for tag in patient.get_tags(order_by = u'l10n_description'):
337 fname = tag.export_image2file()
338 if fname is None:
339 _log.warning('cannot export image data of tag [%s]', tag['l10n_description'])
340 continue
341 img = gmGuiHelpers.file2scaled_image(filename = fname, height = 20)
342 bmp = wx_genstatbmp.GenStaticBitmap(self, -1, img, style = wx.NO_BORDER)
343 bmp.SetToolTipString(u'%s%s' % (
344 tag['l10n_description'],
345 gmTools.coalesce(tag['comment'], u'', u'\n\n%s')
346 ))
347 bmp.tag = tag
348 bmp.Bind(wx.EVT_RIGHT_UP, self._on_bitmap_rightclicked)
349 # FIXME: add context menu for Delete/Clone/Add/Configure
350 self._SZR_bitmaps.Add(bmp, 0, wx.LEFT | wx.RIGHT | wx.TOP | wx.BOTTOM, 1) # | wx.EXPAND
351 self.__bitmaps.append(bmp)
352
353 self.GetParent().Layout()
354 #--------------------------------------------------------
356 while len(self._SZR_bitmaps.GetChildren()) > 0:
357 self._SZR_bitmaps.Detach(0)
358 # for child_idx in range(len(self._SZR_bitmaps.GetChildren())):
359 # self._SZR_bitmaps.Detach(child_idx)
360 for bmp in self.__bitmaps:
361 bmp.Destroy()
362 self.__bitmaps = []
363 #--------------------------------------------------------
364 # internal helpers
365 #--------------------------------------------------------
367 if self.__current_tag is None:
368 return
369 pat = gmPerson.gmCurrentPatient()
370 if not pat.connected:
371 return
372 pat.remove_tag(tag = self.__current_tag['pk_identity_tag'])
373 #--------------------------------------------------------
375 if self.__current_tag is None:
376 return
377
378 msg = _('Edit the comment on tag [%s]') % self.__current_tag['l10n_description']
379 comment = wx.GetTextFromUser (
380 message = msg,
381 caption = _('Editing tag comment'),
382 default_value = gmTools.coalesce(self.__current_tag['comment'], u''),
383 parent = self
384 )
385
386 if comment == u'':
387 return
388
389 if comment.strip() == self.__current_tag['comment']:
390 return
391
392 if comment == u' ':
393 self.__current_tag['comment'] = None
394 else:
395 self.__current_tag['comment'] = comment.strip()
396
397 self.__current_tag.save()
398 #--------------------------------------------------------
399 # event handlers
400 #--------------------------------------------------------
405 #============================================================
406 #============================================================
408
410
411 kwargs['message'] = _("Today's KOrganizer appointments ...")
412 kwargs['button_defs'] = [
413 {'label': _('Reload'), 'tooltip': _('Reload appointments from KOrganizer')},
414 {'label': u''},
415 {'label': u''},
416 {'label': u''},
417 {'label': u'KOrganizer', 'tooltip': _('Launch KOrganizer')}
418 ]
419 gmDataMiningWidgets.cPatientListingPnl.__init__(self, *args, **kwargs)
420
421 self.fname = os.path.expanduser(os.path.join('~', '.gnumed', 'tmp', 'korganizer2gnumed.csv'))
422 self.reload_cmd = 'konsolekalendar --view --export-type csv --export-file %s' % self.fname
423
424 #--------------------------------------------------------
428 #--------------------------------------------------------
430 """Reload appointments from KOrganizer."""
431 found, cmd = gmShellAPI.detect_external_binary(binary = 'korganizer')
432
433 if not found:
434 gmDispatcher.send(signal = 'statustext', msg = _('KOrganizer is not installed.'), beep = True)
435 return
436
437 gmShellAPI.run_command_in_shell(command = cmd, blocking = False)
438 #--------------------------------------------------------
440 try: os.remove(self.fname)
441 except OSError: pass
442 gmShellAPI.run_command_in_shell(command=self.reload_cmd, blocking=True)
443 try:
444 csv_file = codecs.open(self.fname , mode = 'rU', encoding = 'utf8', errors = 'replace')
445 except IOError:
446 gmDispatcher.send(signal = u'statustext', msg = _('Cannot access KOrganizer transfer file [%s]') % self.fname, beep = True)
447 return
448
449 csv_lines = gmTools.unicode_csv_reader (
450 csv_file,
451 delimiter = ','
452 )
453 # start_date, start_time, end_date, end_time, title (patient), ort, comment, UID
454 self._LCTRL_items.set_columns ([
455 _('Place'),
456 _('Start'),
457 u'',
458 u'',
459 _('Patient'),
460 _('Comment')
461 ])
462 items = []
463 data = []
464 for line in csv_lines:
465 items.append([line[5], line[0], line[1], line[3], line[4], line[6]])
466 data.append([line[4], line[7]])
467
468 self._LCTRL_items.set_string_items(items = items)
469 self._LCTRL_items.set_column_widths()
470 self._LCTRL_items.set_data(data = data)
471 self._LCTRL_items.patient_key = 0
472 #--------------------------------------------------------
473 # notebook plugins API
474 #--------------------------------------------------------
476 self.reload_appointments()
477 #============================================================
478 # occupation related widgets / functions
479 #============================================================
481
482 pat = gmPerson.gmCurrentPatient()
483 curr_jobs = pat.get_occupations()
484 if len(curr_jobs) > 0:
485 old_job = curr_jobs[0]['l10n_occupation']
486 update = curr_jobs[0]['modified_when'].strftime('%m/%Y')
487 else:
488 old_job = u''
489 update = u''
490
491 msg = _(
492 'Please enter the primary occupation of the patient.\n'
493 '\n'
494 'Currently recorded:\n'
495 '\n'
496 ' %s (last updated %s)'
497 ) % (old_job, update)
498
499 new_job = wx.GetTextFromUser (
500 message = msg,
501 caption = _('Editing primary occupation'),
502 default_value = old_job,
503 parent = None
504 )
505 if new_job.strip() == u'':
506 return
507
508 for job in curr_jobs:
509 # unlink all but the new job
510 if job['l10n_occupation'] != new_job:
511 pat.unlink_occupation(occupation = job['l10n_occupation'])
512 # and link the new one
513 pat.link_occupation(occupation = new_job)
514
515 #------------------------------------------------------------
517
519 query = u"SELECT distinct name, _(name) from dem.occupation where _(name) %(fragment_condition)s"
520 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
521 mp.setThresholds(1, 3, 5)
522 gmPhraseWheel.cPhraseWheel.__init__ (
523 self,
524 *args,
525 **kwargs
526 )
527 self.SetToolTipString(_("Type or select an occupation."))
528 self.capitalisation_mode = gmTools.CAPS_FIRST
529 self.matcher = mp
530
531 #============================================================
532 # identity widgets / functions
533 #============================================================
535 # ask user for assurance
536 go_ahead = gmGuiHelpers.gm_show_question (
537 _('Are you sure you really, positively want\n'
538 'to disable the following person ?\n'
539 '\n'
540 ' %s %s %s\n'
541 ' born %s\n'
542 '\n'
543 '%s\n'
544 ) % (
545 identity['firstnames'],
546 identity['lastnames'],
547 identity['gender'],
548 identity.get_formatted_dob(),
549 gmTools.bool2subst (
550 identity.is_patient,
551 _('This patient DID receive care.'),
552 _('This person did NOT receive care.')
553 )
554 ),
555 _('Disabling person')
556 )
557 if not go_ahead:
558 return True
559
560 # get admin connection
561 conn = gmAuthWidgets.get_dbowner_connection (
562 procedure = _('Disabling patient')
563 )
564 # - user cancelled
565 if conn is False:
566 return True
567 # - error
568 if conn is None:
569 return False
570
571 # now disable patient
572 gmPG2.run_rw_queries(queries = [{'cmd': u"update dem.identity set deleted=True where pk=%s", 'args': [identity['pk_identity']]}])
573
574 return True
575
576 #------------------------------------------------------------
577 # phrasewheels
578 #------------------------------------------------------------
580
582 query = u"SELECT distinct lastnames, lastnames from dem.names where lastnames %(fragment_condition)s order by lastnames limit 25"
583 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
584 mp.setThresholds(3, 5, 9)
585 gmPhraseWheel.cPhraseWheel.__init__ (
586 self,
587 *args,
588 **kwargs
589 )
590 self.SetToolTipString(_("Type or select a last name (family name/surname)."))
591 self.capitalisation_mode = gmTools.CAPS_NAMES
592 self.matcher = mp
593 #------------------------------------------------------------
595
597 query = u"""
598 (SELECT distinct firstnames, firstnames from dem.names where firstnames %(fragment_condition)s order by firstnames limit 20)
599 union
600 (SELECT distinct name, name from dem.name_gender_map where name %(fragment_condition)s order by name limit 20)"""
601 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
602 mp.setThresholds(3, 5, 9)
603 gmPhraseWheel.cPhraseWheel.__init__ (
604 self,
605 *args,
606 **kwargs
607 )
608 self.SetToolTipString(_("Type or select a first name (forename/Christian name/given name)."))
609 self.capitalisation_mode = gmTools.CAPS_NAMES
610 self.matcher = mp
611 #------------------------------------------------------------
613
615 query = u"""
616 (SELECT distinct preferred, preferred from dem.names where preferred %(fragment_condition)s order by preferred limit 20)
617 union
618 (SELECT distinct firstnames, firstnames from dem.names where firstnames %(fragment_condition)s order by firstnames limit 20)
619 union
620 (SELECT distinct name, name from dem.name_gender_map where name %(fragment_condition)s order by name limit 20)"""
621 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
622 mp.setThresholds(3, 5, 9)
623 gmPhraseWheel.cPhraseWheel.__init__ (
624 self,
625 *args,
626 **kwargs
627 )
628 self.SetToolTipString(_("Type or select an alias (nick name, preferred name, call name, warrior name, artist name)."))
629 # nicknames CAN start with lower case !
630 #self.capitalisation_mode = gmTools.CAPS_NAMES
631 self.matcher = mp
632 #------------------------------------------------------------
634
636 query = u"SELECT distinct title, title from dem.identity where title %(fragment_condition)s"
637 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
638 mp.setThresholds(1, 3, 9)
639 gmPhraseWheel.cPhraseWheel.__init__ (
640 self,
641 *args,
642 **kwargs
643 )
644 self.SetToolTipString(_("Type or select a title. Note that the title applies to the person, not to a particular name !"))
645 self.matcher = mp
646 #------------------------------------------------------------
648 """Let user select a gender."""
649
650 _gender_map = None
651
653
654 if cGenderSelectionPhraseWheel._gender_map is None:
655 cmd = u"""
656 SELECT tag, l10n_label, sort_weight
657 from dem.v_gender_labels
658 order by sort_weight desc"""
659 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx=True)
660 cGenderSelectionPhraseWheel._gender_map = {}
661 for gender in rows:
662 cGenderSelectionPhraseWheel._gender_map[gender[idx['tag']]] = {
663 'data': gender[idx['tag']],
664 'field_label': gender[idx['l10n_label']],
665 'list_label': gender[idx['l10n_label']],
666 'weight': gender[idx['sort_weight']]
667 }
668
669 mp = gmMatchProvider.cMatchProvider_FixedList(aSeq = cGenderSelectionPhraseWheel._gender_map.values())
670 mp.setThresholds(1, 1, 3)
671
672 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
673 self.selection_only = True
674 self.matcher = mp
675 self.picklist_delay = 50
676 #------------------------------------------------------------
678
680 query = u"""
681 SELECT DISTINCT ON (list_label)
682 pk AS data,
683 name AS field_label,
684 name || coalesce(' (' || issuer || ')', '') as list_label
685 FROM dem.enum_ext_id_types
686 WHERE name %(fragment_condition)s
687 ORDER BY list_label
688 LIMIT 25
689 """
690 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
691 mp.setThresholds(1, 3, 5)
692 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
693 self.SetToolTipString(_("Enter or select a type for the external ID."))
694 self.matcher = mp
695 #--------------------------------------------------------
700 #------------------------------------------------------------
702
704 query = u"""
705 SELECT distinct issuer, issuer
706 from dem.enum_ext_id_types
707 where issuer %(fragment_condition)s
708 order by issuer limit 25"""
709 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
710 mp.setThresholds(1, 3, 5)
711 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
712 self.SetToolTipString(_("Type or select an ID issuer."))
713 self.capitalisation_mode = gmTools.CAPS_FIRST
714 self.matcher = mp
715 #------------------------------------------------------------
716 # edit areas
717 #------------------------------------------------------------
718 from Gnumed.wxGladeWidgets import wxgExternalIDEditAreaPnl
719
720 -class cExternalIDEditAreaPnl(wxgExternalIDEditAreaPnl.wxgExternalIDEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
721 """An edit area for editing/creating external IDs.
722
723 Does NOT act on/listen to the current patient.
724 """
726
727 try:
728 data = kwargs['external_id']
729 del kwargs['external_id']
730 except:
731 data = None
732
733 wxgExternalIDEditAreaPnl.wxgExternalIDEditAreaPnl.__init__(self, *args, **kwargs)
734 gmEditArea.cGenericEditAreaMixin.__init__(self)
735
736 self.identity = None
737
738 self.mode = 'new'
739 self.data = data
740 if data is not None:
741 self.mode = 'edit'
742
743 self.__init_ui()
744 #--------------------------------------------------------
746 self._PRW_type.add_callback_on_lose_focus(self._on_type_set)
747 #----------------------------------------------------------------
748 # generic Edit Area mixin API
749 #----------------------------------------------------------------
751 validity = True
752
753 # do not test .GetData() because adding external
754 # IDs will create types as necessary
755 #if self._PRW_type.GetData() is None:
756 if self._PRW_type.GetValue().strip() == u'':
757 validity = False
758 self._PRW_type.display_as_valid(False)
759 self._PRW_type.SetFocus()
760 else:
761 self._PRW_type.display_as_valid(True)
762
763 if self._TCTRL_value.GetValue().strip() == u'':
764 validity = False
765 self.display_tctrl_as_valid(tctrl = self._TCTRL_value, valid = False)
766 else:
767 self.display_tctrl_as_valid(tctrl = self._TCTRL_value, valid = True)
768
769 return validity
770 #----------------------------------------------------------------
772 data = {}
773 data['pk_type'] = None
774 data['name'] = self._PRW_type.GetValue().strip()
775 data['value'] = self._TCTRL_value.GetValue().strip()
776 data['issuer'] = gmTools.none_if(self._PRW_issuer.GetValue().strip(), u'')
777 data['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
778
779 self.identity.add_external_id (
780 type_name = data['name'],
781 value = data['value'],
782 issuer = data['issuer'],
783 comment = data['comment']
784 )
785
786 self.data = data
787 return True
788 #----------------------------------------------------------------
790 self.data['name'] = self._PRW_type.GetValue().strip()
791 self.data['value'] = self._TCTRL_value.GetValue().strip()
792 self.data['issuer'] = gmTools.none_if(self._PRW_issuer.GetValue().strip(), u'')
793 self.data['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
794
795 self.identity.update_external_id (
796 pk_id = self.data['pk_id'],
797 type = self.data['name'],
798 value = self.data['value'],
799 issuer = self.data['issuer'],
800 comment = self.data['comment']
801 )
802
803 return True
804 #----------------------------------------------------------------
806 self._PRW_type.SetText(value = u'', data = None)
807 self._TCTRL_value.SetValue(u'')
808 self._PRW_issuer.SetText(value = u'', data = None)
809 self._TCTRL_comment.SetValue(u'')
810 #----------------------------------------------------------------
814 #----------------------------------------------------------------
816 self._PRW_type.SetText(value = self.data['name'], data = self.data['pk_type'])
817 self._TCTRL_value.SetValue(self.data['value'])
818 self._PRW_issuer.SetText(self.data['issuer'])
819 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
820 #----------------------------------------------------------------
821 # internal helpers
822 #----------------------------------------------------------------
824 """Set the issuer according to the selected type.
825
826 Matches are fetched from existing records in backend.
827 """
828 pk_curr_type = self._PRW_type.GetData()
829 if pk_curr_type is None:
830 return True
831 rows, idx = gmPG2.run_ro_queries(queries = [{
832 'cmd': u"SELECT issuer from dem.enum_ext_id_types where pk = %s",
833 'args': [pk_curr_type]
834 }])
835 if len(rows) == 0:
836 return True
837 wx.CallAfter(self._PRW_issuer.SetText, rows[0][0])
838 return True
839
840 #============================================================
841 # identity widgets
842 #------------------------------------------------------------
844 allow_empty_dob = gmGuiHelpers.gm_show_question (
845 _(
846 'Are you sure you want to leave this person\n'
847 'without a valid date of birth ?\n'
848 '\n'
849 'This can be useful for temporary staff members\n'
850 'but will provoke nag screens if this person\n'
851 'becomes a patient.\n'
852 ),
853 _('Validating date of birth')
854 )
855 return allow_empty_dob
856 #------------------------------------------------------------
858
859 # valid timestamp ?
860 if dob_prw.is_valid_timestamp(allow_empty = False): # properly colors the field
861 dob = dob_prw.date
862 # but year also usable ?
863 if (dob.year > 1899) and (dob < gmDateTime.pydt_now_here()):
864 return True
865
866 if dob.year < 1900:
867 msg = _(
868 'DOB: %s\n'
869 '\n'
870 'While this is a valid point in time Python does\n'
871 'not know how to deal with it.\n'
872 '\n'
873 'We suggest using January 1st 1901 instead and adding\n'
874 'the true date of birth to the patient comment.\n'
875 '\n'
876 'Sorry for the inconvenience %s'
877 ) % (dob, gmTools.u_frowning_face)
878 else:
879 msg = _(
880 'DOB: %s\n'
881 '\n'
882 'Date of birth in the future !'
883 ) % dob
884 gmGuiHelpers.gm_show_error (
885 msg,
886 _('Validating date of birth')
887 )
888 dob_prw.display_as_valid(False)
889 dob_prw.SetFocus()
890 return False
891
892 # invalid timestamp but not empty
893 if dob_prw.GetValue().strip() != u'':
894 dob_prw.display_as_valid(False)
895 gmDispatcher.send(signal = u'statustext', msg = _('Invalid date of birth.'))
896 dob_prw.SetFocus()
897 return False
898
899 # empty DOB field
900 dob_prw.display_as_valid(False)
901 return True
902
903 #------------------------------------------------------------
905
906 val = ctrl.GetValue().strip()
907
908 if val == u'':
909 return True
910
911 converted, hours = gmTools.input2int(val[:2], 0, 23)
912 if not converted:
913 return False
914
915 converted, minutes = gmTools.input2int(val[3:5], 0, 59)
916 if not converted:
917 return False
918
919 return True
920
921 #------------------------------------------------------------
922 from Gnumed.wxGladeWidgets import wxgIdentityEAPnl
923
925 """An edit area for editing/creating title/gender/dob/dod etc."""
926
928
929 try:
930 data = kwargs['identity']
931 del kwargs['identity']
932 except KeyError:
933 data = None
934
935 wxgIdentityEAPnl.wxgIdentityEAPnl.__init__(self, *args, **kwargs)
936 gmEditArea.cGenericEditAreaMixin.__init__(self)
937
938 self.mode = 'new'
939 self.data = data
940 if data is not None:
941 self.mode = 'edit'
942
943 # self.__init_ui()
944 #----------------------------------------------------------------
945 # def __init_ui(self):
946 # # adjust phrasewheels etc
947 #----------------------------------------------------------------
948 # generic Edit Area mixin API
949 #----------------------------------------------------------------
951
952 has_error = False
953
954 if self._PRW_gender.GetData() is None:
955 self._PRW_gender.SetFocus()
956 has_error = True
957
958 if self.data is not None:
959 if not _validate_dob_field(self._PRW_dob):
960 has_error = True
961
962 # TOB validation
963 if _validate_tob_field(self._TCTRL_tob):
964 self.display_ctrl_as_valid(ctrl = self._TCTRL_tob, valid = True)
965 else:
966 has_error = True
967 self.display_ctrl_as_valid(ctrl = self._TCTRL_tob, valid = False)
968
969 if not self._PRW_dod.is_valid_timestamp(allow_empty = True):
970 gmDispatcher.send(signal = u'statustext', msg = _('Invalid date of death.'))
971 self._PRW_dod.SetFocus()
972 has_error = True
973
974 return (has_error is False)
975 #----------------------------------------------------------------
979 #----------------------------------------------------------------
981
982 if self._PRW_dob.GetValue().strip() == u'':
983 if not _empty_dob_allowed():
984 return False
985 self.data['dob'] = None
986 else:
987 self.data['dob'] = self._PRW_dob.GetData()
988 self.data['dob_is_estimated'] = self._CHBOX_estimated_dob.GetValue()
989 val = self._TCTRL_tob.GetValue().strip()
990 if val == u'':
991 self.data['tob'] = None
992 else:
993 self.data['tob'] = pydt.time(int(val[:2]), int(val[3:5]))
994 self.data['gender'] = self._PRW_gender.GetData()
995 self.data['title'] = gmTools.none_if(self._PRW_title.GetValue().strip(), u'')
996 self.data['deceased'] = self._PRW_dod.GetData()
997 self.data['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
998
999 self.data.save()
1000 return True
1001 #----------------------------------------------------------------
1004 #----------------------------------------------------------------
1006
1007 self._LBL_info.SetLabel(u'ID: #%s' % (
1008 self.data.ID
1009 # FIXME: add 'deleted' status
1010 ))
1011 if self.data['dob'] is None:
1012 val = u''
1013 else:
1014 val = gmDateTime.pydt_strftime (
1015 self.data['dob'],
1016 format = '%Y-%m-%d',
1017 accuracy = gmDateTime.acc_minutes
1018 )
1019 self._PRW_dob.SetText(value = val, data = self.data['dob'])
1020 self._CHBOX_estimated_dob.SetValue(self.data['dob_is_estimated'])
1021 if self.data['tob'] is None:
1022 self._TCTRL_tob.SetValue(u'')
1023 else:
1024 self._TCTRL_tob.SetValue(self.data['tob'].strftime('%H:%M'))
1025 if self.data['deceased'] is None:
1026 val = u''
1027 else:
1028 val = gmDateTime.pydt_strftime (
1029 self.data['deceased'],
1030 format = '%Y-%m-%d %H:%M',
1031 accuracy = gmDateTime.acc_minutes
1032 )
1033 self._PRW_dod.SetText(value = val, data = self.data['deceased'])
1034 self._PRW_gender.SetData(self.data['gender'])
1035 #self._PRW_ethnicity.SetValue()
1036 self._PRW_title.SetText(gmTools.coalesce(self.data['title'], u''))
1037 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
1038 #----------------------------------------------------------------
1041 #------------------------------------------------------------
1042 from Gnumed.wxGladeWidgets import wxgPersonNameEAPnl
1043
1044 -class cPersonNameEAPnl(wxgPersonNameEAPnl.wxgPersonNameEAPnl, gmEditArea.cGenericEditAreaMixin):
1045 """An edit area for editing/creating names of people.
1046
1047 Does NOT act on/listen to the current patient.
1048 """
1050
1051 try:
1052 data = kwargs['name']
1053 identity = gmPerson.cIdentity(aPK_obj = data['pk_identity'])
1054 del kwargs['name']
1055 except KeyError:
1056 data = None
1057 identity = kwargs['identity']
1058 del kwargs['identity']
1059
1060 wxgPersonNameEAPnl.wxgPersonNameEAPnl.__init__(self, *args, **kwargs)
1061 gmEditArea.cGenericEditAreaMixin.__init__(self)
1062
1063 self.__identity = identity
1064
1065 self.mode = 'new'
1066 self.data = data
1067 if data is not None:
1068 self.mode = 'edit'
1069
1070 #self.__init_ui()
1071 #----------------------------------------------------------------
1072 # def __init_ui(self):
1073 # # adjust phrasewheels etc
1074 #----------------------------------------------------------------
1075 # generic Edit Area mixin API
1076 #----------------------------------------------------------------
1078 validity = True
1079
1080 if self._PRW_lastname.GetValue().strip() == u'':
1081 validity = False
1082 self._PRW_lastname.display_as_valid(False)
1083 self._PRW_lastname.SetFocus()
1084 else:
1085 self._PRW_lastname.display_as_valid(True)
1086
1087 if self._PRW_firstname.GetValue().strip() == u'':
1088 validity = False
1089 self._PRW_firstname.display_as_valid(False)
1090 self._PRW_firstname.SetFocus()
1091 else:
1092 self._PRW_firstname.display_as_valid(True)
1093
1094 return validity
1095 #----------------------------------------------------------------
1097
1098 first = self._PRW_firstname.GetValue().strip()
1099 last = self._PRW_lastname.GetValue().strip()
1100 active = self._CHBOX_active.GetValue()
1101
1102 data = self.__identity.add_name(first, last, active)
1103
1104 old_nick = self.__identity['active_name']['preferred']
1105 new_nick = gmTools.none_if(self._PRW_nick.GetValue().strip(), u'')
1106 if active:
1107 data['preferred'] = gmTools.coalesce(new_nick, old_nick)
1108 else:
1109 data['preferred'] = new_nick
1110 data['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
1111 data.save()
1112
1113 self.data = data
1114 return True
1115 #----------------------------------------------------------------
1117 """The knack here is that we can only update a few fields.
1118
1119 Otherwise we need to clone the name and update that.
1120 """
1121 first = self._PRW_firstname.GetValue().strip()
1122 last = self._PRW_lastname.GetValue().strip()
1123 active = self._CHBOX_active.GetValue()
1124
1125 current_name = self.data['firstnames'].strip() + self.data['lastnames'].strip()
1126 new_name = first + last
1127
1128 # editable fields only ?
1129 if new_name == current_name:
1130 self.data['active_name'] = self._CHBOX_active.GetValue()
1131 self.data['preferred'] = gmTools.none_if(self._PRW_nick.GetValue().strip(), u'')
1132 self.data['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
1133 self.data.save()
1134 # else clone name and update that
1135 else:
1136 name = self.__identity.add_name(first, last, active)
1137 name['preferred'] = gmTools.none_if(self._PRW_nick.GetValue().strip(), u'')
1138 name['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
1139 name.save()
1140 self.data = name
1141
1142 return True
1143 #----------------------------------------------------------------
1145 self._PRW_firstname.SetText(value = u'', data = None)
1146 self._PRW_lastname.SetText(value = u'', data = None)
1147 self._PRW_nick.SetText(value = u'', data = None)
1148 self._TCTRL_comment.SetValue(u'')
1149 self._CHBOX_active.SetValue(False)
1150
1151 self._PRW_firstname.SetFocus()
1152 #----------------------------------------------------------------
1154 self._refresh_as_new()
1155 self._PRW_firstname.SetText(value = u'', data = None)
1156 self._PRW_nick.SetText(gmTools.coalesce(self.data['preferred'], u''))
1157
1158 self._PRW_lastname.SetFocus()
1159 #----------------------------------------------------------------
1161 self._PRW_firstname.SetText(self.data['firstnames'])
1162 self._PRW_lastname.SetText(self.data['lastnames'])
1163 self._PRW_nick.SetText(gmTools.coalesce(self.data['preferred'], u''))
1164 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
1165 self._CHBOX_active.SetValue(self.data['active_name'])
1166
1167 self._TCTRL_comment.SetFocus()
1168 #------------------------------------------------------------
1169 # list manager
1170 #------------------------------------------------------------
1172 """A list for managing a person's names.
1173
1174 Does NOT act on/listen to the current patient.
1175 """
1177
1178 try:
1179 self.__identity = kwargs['identity']
1180 del kwargs['identity']
1181 except KeyError:
1182 self.__identity = None
1183
1184 gmListWidgets.cGenericListManagerPnl.__init__(self, *args, **kwargs)
1185
1186 self.new_callback = self._add_name
1187 self.edit_callback = self._edit_name
1188 self.delete_callback = self._del_name
1189 self.refresh_callback = self.refresh
1190
1191 self.__init_ui()
1192 self.refresh()
1193 #--------------------------------------------------------
1194 # external API
1195 #--------------------------------------------------------
1197 if self.__identity is None:
1198 self._LCTRL_items.set_string_items()
1199 return
1200
1201 names = self.__identity.get_names()
1202 self._LCTRL_items.set_string_items (
1203 items = [ [
1204 gmTools.bool2str(n['active_name'], 'X', ''),
1205 n['lastnames'],
1206 n['firstnames'],
1207 gmTools.coalesce(n['preferred'], u''),
1208 gmTools.coalesce(n['comment'], u'')
1209 ] for n in names ]
1210 )
1211 self._LCTRL_items.set_column_widths()
1212 self._LCTRL_items.set_data(data = names)
1213 #--------------------------------------------------------
1214 # internal helpers
1215 #--------------------------------------------------------
1217 self._LCTRL_items.set_columns(columns = [
1218 _('Active'),
1219 _('Lastname'),
1220 _('Firstname(s)'),
1221 _('Preferred Name'),
1222 _('Comment')
1223 ])
1224 #--------------------------------------------------------
1226 #ea = cPersonNameEAPnl(self, -1, name = self.__identity.get_active_name())
1227 ea = cPersonNameEAPnl(self, -1, identity = self.__identity)
1228 dlg = gmEditArea.cGenericEditAreaDlg2(self, -1, edit_area = ea, single_entry = True)
1229 dlg.SetTitle(_('Adding new name'))
1230 if dlg.ShowModal() == wx.ID_OK:
1231 dlg.Destroy()
1232 return True
1233 dlg.Destroy()
1234 return False
1235 #--------------------------------------------------------
1237 ea = cPersonNameEAPnl(self, -1, name = name)
1238 dlg = gmEditArea.cGenericEditAreaDlg2(self, -1, edit_area = ea, single_entry = True)
1239 dlg.SetTitle(_('Editing name'))
1240 if dlg.ShowModal() == wx.ID_OK:
1241 dlg.Destroy()
1242 return True
1243 dlg.Destroy()
1244 return False
1245 #--------------------------------------------------------
1247
1248 if len(self.__identity.get_names()) == 1:
1249 gmDispatcher.send(signal = u'statustext', msg = _('Cannot delete the only name of a person.'), beep = True)
1250 return False
1251
1252 if name['active_name']:
1253 gmDispatcher.send(signal = u'statustext', msg = _('Cannot delete the active name of a person.'), beep = True)
1254 return False
1255
1256 go_ahead = gmGuiHelpers.gm_show_question (
1257 _( 'It is often advisable to keep old names around and\n'
1258 'just create a new "currently active" name.\n'
1259 '\n'
1260 'This allows finding the patient by both the old\n'
1261 'and the new name (think before/after marriage).\n'
1262 '\n'
1263 'Do you still want to really delete\n'
1264 "this name from the patient ?"
1265 ),
1266 _('Deleting name')
1267 )
1268 if not go_ahead:
1269 return False
1270
1271 self.__identity.delete_name(name = name)
1272 return True
1273 #--------------------------------------------------------
1274 # properties
1275 #--------------------------------------------------------
1278
1282
1283 identity = property(_get_identity, _set_identity)
1284 #------------------------------------------------------------
1286 """A list for managing a person's external IDs.
1287
1288 Does NOT act on/listen to the current patient.
1289 """
1291
1292 try:
1293 self.__identity = kwargs['identity']
1294 del kwargs['identity']
1295 except KeyError:
1296 self.__identity = None
1297
1298 gmListWidgets.cGenericListManagerPnl.__init__(self, *args, **kwargs)
1299
1300 self.new_callback = self._add_id
1301 self.edit_callback = self._edit_id
1302 self.delete_callback = self._del_id
1303 self.refresh_callback = self.refresh
1304
1305 self.__init_ui()
1306 self.refresh()
1307 #--------------------------------------------------------
1308 # external API
1309 #--------------------------------------------------------
1311 if self.__identity is None:
1312 self._LCTRL_items.set_string_items()
1313 return
1314
1315 ids = self.__identity.get_external_ids()
1316 self._LCTRL_items.set_string_items (
1317 items = [ [
1318 i['name'],
1319 i['value'],
1320 gmTools.coalesce(i['issuer'], u''),
1321 gmTools.coalesce(i['comment'], u'')
1322 ] for i in ids
1323 ]
1324 )
1325 self._LCTRL_items.set_column_widths()
1326 self._LCTRL_items.set_data(data = ids)
1327 #--------------------------------------------------------
1328 # internal helpers
1329 #--------------------------------------------------------
1331 self._LCTRL_items.set_columns(columns = [
1332 _('ID type'),
1333 _('Value'),
1334 _('Issuer'),
1335 _('Comment')
1336 ])
1337 #--------------------------------------------------------
1339 ea = cExternalIDEditAreaPnl(self, -1)
1340 ea.identity = self.__identity
1341 dlg = gmEditArea.cGenericEditAreaDlg2(self, -1, edit_area = ea)
1342 dlg.SetTitle(_('Adding new external ID'))
1343 if dlg.ShowModal() == wx.ID_OK:
1344 dlg.Destroy()
1345 return True
1346 dlg.Destroy()
1347 return False
1348 #--------------------------------------------------------
1350 ea = cExternalIDEditAreaPnl(self, -1, external_id = ext_id)
1351 ea.identity = self.__identity
1352 dlg = gmEditArea.cGenericEditAreaDlg2(self, -1, edit_area = ea, single_entry = True)
1353 dlg.SetTitle(_('Editing external ID'))
1354 if dlg.ShowModal() == wx.ID_OK:
1355 dlg.Destroy()
1356 return True
1357 dlg.Destroy()
1358 return False
1359 #--------------------------------------------------------
1361 go_ahead = gmGuiHelpers.gm_show_question (
1362 _( 'Do you really want to delete this\n'
1363 'external ID from the patient ?'),
1364 _('Deleting external ID')
1365 )
1366 if not go_ahead:
1367 return False
1368 self.__identity.delete_external_id(pk_ext_id = ext_id['pk_id'])
1369 return True
1370 #--------------------------------------------------------
1371 # properties
1372 #--------------------------------------------------------
1375
1379
1380 identity = property(_get_identity, _set_identity)
1381 #------------------------------------------------------------
1382 # integrated panels
1383 #------------------------------------------------------------
1384 from Gnumed.wxGladeWidgets import wxgPersonIdentityManagerPnl
1385
1387 """A panel for editing identity data for a person.
1388
1389 - provides access to:
1390 - identity EA
1391 - name list manager
1392 - external IDs list manager
1393
1394 Does NOT act on/listen to the current patient.
1395 """
1397
1398 wxgPersonIdentityManagerPnl.wxgPersonIdentityManagerPnl.__init__(self, *args, **kwargs)
1399
1400 self.__identity = None
1401 self.refresh()
1402 #--------------------------------------------------------
1403 # external API
1404 #--------------------------------------------------------
1406 self._PNL_names.identity = self.__identity
1407 self._PNL_ids.identity = self.__identity
1408 # this is an Edit Area:
1409 self._PNL_identity.mode = 'new'
1410 self._PNL_identity.data = self.__identity
1411 if self.__identity is not None:
1412 self._PNL_identity.mode = 'edit'
1413 self._PNL_identity._refresh_from_existing()
1414 #--------------------------------------------------------
1415 # properties
1416 #--------------------------------------------------------
1419
1423
1424 identity = property(_get_identity, _set_identity)
1425 #--------------------------------------------------------
1426 # event handlers
1427 #--------------------------------------------------------
1431 #self._PNL_identity.refresh()
1432 #--------------------------------------------------------
1435
1436 #============================================================
1437 from Gnumed.wxGladeWidgets import wxgPersonSocialNetworkManagerPnl
1438
1439 -class cPersonSocialNetworkManagerPnl(wxgPersonSocialNetworkManagerPnl.wxgPersonSocialNetworkManagerPnl):
1441
1442 wxgPersonSocialNetworkManagerPnl.wxgPersonSocialNetworkManagerPnl.__init__(self, *args, **kwargs)
1443
1444 self.__identity = None
1445 self._PRW_provider.selection_only = False
1446 self.refresh()
1447 #--------------------------------------------------------
1448 # external API
1449 #--------------------------------------------------------
1451
1452 tt = _('Link another person in this database as the emergency contact:\n\nEnter person name part or identifier and hit <enter>.')
1453
1454 if self.__identity is None:
1455 self._TCTRL_er_contact.SetValue(u'')
1456 self._TCTRL_person.person = None
1457 self._TCTRL_person.SetToolTipString(tt)
1458
1459 self._PRW_provider.SetText(value = u'', data = None)
1460 return
1461
1462 self._TCTRL_er_contact.SetValue(gmTools.coalesce(self.__identity['emergency_contact'], u''))
1463 if self.__identity['pk_emergency_contact'] is not None:
1464 ident = gmPerson.cIdentity(aPK_obj = self.__identity['pk_emergency_contact'])
1465 self._TCTRL_person.person = ident
1466 tt = u'%s\n\n%s\n\n%s' % (
1467 tt,
1468 ident['description_gender'],
1469 u'\n'.join([
1470 u'%s: %s%s' % (
1471 c['l10n_comm_type'],
1472 c['url'],
1473 gmTools.bool2subst(c['is_confidential'], _(' (confidential !)'), u'', u'')
1474 )
1475 for c in ident.get_comm_channels()
1476 ])
1477 )
1478 else:
1479 self._TCTRL_person.person = None
1480
1481 self._TCTRL_person.SetToolTipString(tt)
1482
1483 if self.__identity['pk_primary_provider'] is None:
1484 self._PRW_provider.SetText(value = u'', data = None)
1485 else:
1486 self._PRW_provider.SetData(data = self.__identity['pk_primary_provider'])
1487 #--------------------------------------------------------
1488 # properties
1489 #--------------------------------------------------------
1492
1496
1497 identity = property(_get_identity, _set_identity)
1498 #--------------------------------------------------------
1499 # event handlers
1500 #--------------------------------------------------------
1515 #--------------------------------------------------------
1518 #--------------------------------------------------------
1529 #--------------------------------------------------------
1537 #============================================================
1538 # new-patient widgets
1539 #============================================================
1541
1542 dbcfg = gmCfg.cCfgSQL()
1543
1544 def_region = dbcfg.get2 (
1545 option = u'person.create.default_region',
1546 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1547 bias = u'user'
1548 )
1549 def_country = None
1550
1551 if def_region is None:
1552 def_country = dbcfg.get2 (
1553 option = u'person.create.default_country',
1554 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1555 bias = u'user'
1556 )
1557 else:
1558 countries = gmDemographicRecord.get_country_for_region(region = def_region)
1559 if len(countries) == 1:
1560 def_country = countries[0]['code_country']
1561
1562 if parent is None:
1563 parent = wx.GetApp().GetTopWindow()
1564
1565 ea = cNewPatientEAPnl(parent = parent, id = -1, country = def_country, region = def_region)
1566 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = True)
1567 dlg.SetTitle(_('Adding new person'))
1568 ea._PRW_lastname.SetFocus()
1569 result = dlg.ShowModal()
1570 pat = ea.data
1571 dlg.Destroy()
1572
1573 if result != wx.ID_OK:
1574 return False
1575
1576 _log.debug('created new person [%s]', pat.ID)
1577
1578 if activate:
1579 from Gnumed.wxpython import gmPatSearchWidgets
1580 gmPatSearchWidgets.set_active_patient(patient = pat)
1581
1582 gmDispatcher.send(signal = 'display_widget', name = 'gmNotebookedPatientEditionPlugin')
1583
1584 return True
1585 #============================================================
1586 from Gnumed.wxGladeWidgets import wxgNewPatientEAPnl
1587
1588 -class cNewPatientEAPnl(wxgNewPatientEAPnl.wxgNewPatientEAPnl, gmEditArea.cGenericEditAreaMixin):
1589
1591
1592 try:
1593 self.default_region = kwargs['region']
1594 del kwargs['region']
1595 except KeyError:
1596 self.default_region = None
1597
1598 try:
1599 self.default_country = kwargs['country']
1600 del kwargs['country']
1601 except KeyError:
1602 self.default_country = None
1603
1604 wxgNewPatientEAPnl.wxgNewPatientEAPnl.__init__(self, *args, **kwargs)
1605 gmEditArea.cGenericEditAreaMixin.__init__(self)
1606
1607 self.mode = 'new'
1608 self.data = None
1609 self._address = None
1610
1611 self.__init_ui()
1612 self.__register_interests()
1613 #----------------------------------------------------------------
1614 # internal helpers
1615 #----------------------------------------------------------------
1617 self._PRW_lastname.final_regex = '.+'
1618 self._PRW_firstnames.final_regex = '.+'
1619 self._PRW_address_searcher.selection_only = False
1620
1621 # only if we would support None on selection_only's:
1622 # self._PRW_external_id_type.selection_only = True
1623
1624 if self.default_country is not None:
1625 match = self._PRW_country._data2match(data = self.default_country)
1626 if match is not None:
1627 self._PRW_country.SetText(value = match['field_label'], data = match['data'])
1628
1629 if self.default_region is not None:
1630 self._PRW_region.SetText(value = self.default_region)
1631
1632 self._PRW_type.SetText(value = u'home')
1633 #----------------------------------------------------------------
1635
1636 adr = self._PRW_address_searcher.address
1637 if adr is None:
1638 return True
1639
1640 if ctrl.GetValue().strip() != adr[field]:
1641 wx.CallAfter(self._PRW_address_searcher.SetText, value = u'', data = None)
1642 return True
1643
1644 return False
1645 #----------------------------------------------------------------
1647 adr = self._PRW_address_searcher.address
1648 if adr is None:
1649 return True
1650
1651 self._PRW_zip.SetText(value = adr['postcode'], data = adr['postcode'])
1652
1653 self._PRW_street.SetText(value = adr['street'], data = adr['street'])
1654 self._PRW_street.set_context(context = u'zip', val = adr['postcode'])
1655
1656 self._PRW_urb.SetText(value = adr['urb'], data = adr['urb'])
1657 self._PRW_urb.set_context(context = u'zip', val = adr['postcode'])
1658
1659 self._PRW_region.SetText(value = adr['l10n_state'], data = adr['code_state'])
1660 self._PRW_region.set_context(context = u'zip', val = adr['postcode'])
1661
1662 self._PRW_country.SetText(value = adr['l10n_country'], data = adr['code_country'])
1663 self._PRW_country.set_context(context = u'zip', val = adr['postcode'])
1664 #----------------------------------------------------------------
1666 error = False
1667
1668 # name fields
1669 if self._PRW_lastname.GetValue().strip() == u'':
1670 error = True
1671 gmDispatcher.send(signal = 'statustext', msg = _('Must enter lastname.'))
1672 self._PRW_lastname.display_as_valid(False)
1673 else:
1674 self._PRW_lastname.display_as_valid(True)
1675
1676 if self._PRW_firstnames.GetValue().strip() == '':
1677 error = True
1678 gmDispatcher.send(signal = 'statustext', msg = _('Must enter first name.'))
1679 self._PRW_firstnames.display_as_valid(False)
1680 else:
1681 self._PRW_firstnames.display_as_valid(True)
1682
1683 # gender
1684 if self._PRW_gender.GetData() is None:
1685 error = True
1686 gmDispatcher.send(signal = 'statustext', msg = _('Must select gender.'))
1687 self._PRW_gender.display_as_valid(False)
1688 else:
1689 self._PRW_gender.display_as_valid(True)
1690
1691 # dob validation
1692 if not _validate_dob_field(self._PRW_dob):
1693 error = True
1694
1695 # TOB validation
1696 if _validate_tob_field(self._TCTRL_tob):
1697 self.display_ctrl_as_valid(ctrl = self._TCTRL_tob, valid = True)
1698 else:
1699 error = True
1700 self.display_ctrl_as_valid(ctrl = self._TCTRL_tob, valid = False)
1701
1702 return (not error)
1703 #----------------------------------------------------------------
1705
1706 # existing address ? if so set other fields
1707 if self._PRW_address_searcher.GetData() is not None:
1708 wx.CallAfter(self.__set_fields_from_address_searcher)
1709 return True
1710
1711 # must either all contain something or none of them
1712 fields_to_fill = (
1713 self._TCTRL_number,
1714 self._PRW_zip,
1715 self._PRW_street,
1716 self._PRW_urb,
1717 self._PRW_type
1718 )
1719 no_of_filled_fields = 0
1720
1721 for field in fields_to_fill:
1722 if field.GetValue().strip() != u'':
1723 no_of_filled_fields += 1
1724 field.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
1725 field.Refresh()
1726
1727 # empty address ?
1728 if no_of_filled_fields == 0:
1729 if empty_address_is_valid:
1730 return True
1731 else:
1732 return None
1733
1734 # incompletely filled address ?
1735 if no_of_filled_fields != len(fields_to_fill):
1736 for field in fields_to_fill:
1737 if field.GetValue().strip() == u'':
1738 field.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
1739 field.SetFocus()
1740 field.Refresh()
1741 msg = _('To properly create an address, all the related fields must be filled in.')
1742 gmGuiHelpers.gm_show_error(msg, _('Required fields'))
1743 return False
1744
1745 # fields which must contain a selected item
1746 # FIXME: they must also contain an *acceptable combination* which
1747 # FIXME: can only be tested against the database itself ...
1748 strict_fields = (
1749 self._PRW_type,
1750 self._PRW_region,
1751 self._PRW_country
1752 )
1753 error = False
1754 for field in strict_fields:
1755 if field.GetData() is None:
1756 error = True
1757 field.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
1758 field.SetFocus()
1759 else:
1760 field.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
1761 field.Refresh()
1762
1763 if error:
1764 msg = _('This field must contain an item selected from the dropdown list.')
1765 gmGuiHelpers.gm_show_error(msg, _('Required fields'))
1766 return False
1767
1768 return True
1769 #----------------------------------------------------------------
1771
1772 # identity
1773 self._PRW_firstnames.add_callback_on_lose_focus(self._on_leaving_firstname)
1774
1775 # address
1776 self._PRW_address_searcher.add_callback_on_lose_focus(self._on_leaving_adress_searcher)
1777
1778 # invalidate address searcher when any field edited
1779 self._PRW_street.add_callback_on_lose_focus(self._invalidate_address_searcher)
1780 wx.EVT_KILL_FOCUS(self._TCTRL_number, self._on_leaving_number)
1781 wx.EVT_KILL_FOCUS(self._TCTRL_unit, self._on_leaving_unit)
1782 self._PRW_urb.add_callback_on_lose_focus(self._invalidate_address_searcher)
1783 self._PRW_region.add_callback_on_lose_focus(self._invalidate_address_searcher)
1784
1785 self._PRW_zip.add_callback_on_lose_focus(self._on_leaving_zip)
1786 self._PRW_country.add_callback_on_lose_focus(self._on_leaving_country)
1787 #----------------------------------------------------------------
1788 # event handlers
1789 #----------------------------------------------------------------
1791 """Set the gender according to entered firstname.
1792
1793 Matches are fetched from existing records in backend.
1794 """
1795 # only set if not already set so as to not
1796 # overwrite a change by the user
1797 if self._PRW_gender.GetData() is not None:
1798 return True
1799
1800 firstname = self._PRW_firstnames.GetValue().strip()
1801 if firstname == u'':
1802 return True
1803
1804 gender = gmPerson.map_firstnames2gender(firstnames = firstname)
1805 if gender is None:
1806 return True
1807
1808 wx.CallAfter(self._PRW_gender.SetData, gender)
1809 return True
1810 #----------------------------------------------------------------
1812 self.__perhaps_invalidate_address_searcher(self._PRW_zip, 'postcode')
1813
1814 zip_code = gmTools.none_if(self._PRW_zip.GetValue().strip(), u'')
1815 self._PRW_street.set_context(context = u'zip', val = zip_code)
1816 self._PRW_urb.set_context(context = u'zip', val = zip_code)
1817 self._PRW_region.set_context(context = u'zip', val = zip_code)
1818 self._PRW_country.set_context(context = u'zip', val = zip_code)
1819
1820 return True
1821 #----------------------------------------------------------------
1823 self.__perhaps_invalidate_address_searcher(self._PRW_country, 'l10n_country')
1824
1825 country = gmTools.none_if(self._PRW_country.GetValue().strip(), u'')
1826 self._PRW_region.set_context(context = u'country', val = country)
1827
1828 return True
1829 #----------------------------------------------------------------
1831 if self._TCTRL_number.GetValue().strip() == u'':
1832 adr = self._PRW_address_searcher.address
1833 if adr is None:
1834 return True
1835 self._TCTRL_number.SetValue(adr['number'])
1836 return True
1837
1838 self.__perhaps_invalidate_address_searcher(self._TCTRL_number, 'number')
1839 return True
1840 #----------------------------------------------------------------
1842 if self._TCTRL_unit.GetValue().strip() == u'':
1843 adr = self._PRW_address_searcher.address
1844 if adr is None:
1845 return True
1846 self._TCTRL_unit.SetValue(gmTools.coalesce(adr['subunit'], u''))
1847 return True
1848
1849 self.__perhaps_invalidate_address_searcher(self._TCTRL_unit, 'subunit')
1850 return True
1851 #----------------------------------------------------------------
1853 mapping = [
1854 (self._PRW_street, 'street'),
1855 (self._PRW_urb, 'urb'),
1856 (self._PRW_region, 'l10n_state')
1857 ]
1858 # loop through fields and invalidate address searcher if different
1859 for ctrl, field in mapping:
1860 if self.__perhaps_invalidate_address_searcher(ctrl, field):
1861 return True
1862
1863 return True
1864 #----------------------------------------------------------------
1866 if self._PRW_address_searcher.address is None:
1867 return True
1868
1869 wx.CallAfter(self.__set_fields_from_address_searcher)
1870 return True
1871 #----------------------------------------------------------------
1872 # generic Edit Area mixin API
1873 #----------------------------------------------------------------
1875 if self._PRW_primary_provider.GetValue().strip() == u'':
1876 self._PRW_primary_provider.display_as_valid(True)
1877 else:
1878 if self._PRW_primary_provider.GetData() is None:
1879 self._PRW_primary_provider.display_as_valid(False)
1880 else:
1881 self._PRW_primary_provider.display_as_valid(True)
1882 return (self.__identity_valid_for_save() and self.__address_valid_for_save(empty_address_is_valid = True))
1883 #----------------------------------------------------------------
1885
1886 if self._PRW_dob.GetValue().strip() == u'':
1887 if not _empty_dob_allowed():
1888 self._PRW_dob.display_as_valid(False)
1889 self._PRW_dob.SetFocus()
1890 return False
1891
1892 # identity
1893 new_identity = gmPerson.create_identity (
1894 gender = self._PRW_gender.GetData(),
1895 dob = self._PRW_dob.GetData(),
1896 lastnames = self._PRW_lastname.GetValue().strip(),
1897 firstnames = self._PRW_firstnames.GetValue().strip()
1898 )
1899 _log.debug('identity created: %s' % new_identity)
1900
1901 new_identity['dob_is_estimated'] = self._CHBOX_estimated_dob.GetValue()
1902 val = self._TCTRL_tob.GetValue().strip()
1903 if val != u'':
1904 new_identity['tob'] = pydt.time(int(val[:2]), int(val[3:5]))
1905 new_identity['title'] = gmTools.none_if(self._PRW_title.GetValue().strip())
1906 new_identity.set_nickname(nickname = gmTools.none_if(self._PRW_nickname.GetValue().strip(), u''))
1907
1908 prov = self._PRW_primary_provider.GetData()
1909 if prov is not None:
1910 new_identity['pk_primary_provider'] = prov
1911 new_identity['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
1912 new_identity.save()
1913
1914 # address
1915 # if we reach this the address cannot be completely empty
1916 is_valid = self.__address_valid_for_save(empty_address_is_valid = False)
1917 if is_valid is True:
1918 # because we currently only check for non-emptiness
1919 # we must still deal with database errors
1920 try:
1921 new_identity.link_address (
1922 number = self._TCTRL_number.GetValue().strip(),
1923 street = self._PRW_street.GetValue().strip(),
1924 postcode = self._PRW_zip.GetValue().strip(),
1925 urb = self._PRW_urb.GetValue().strip(),
1926 state = self._PRW_region.GetData(),
1927 country = self._PRW_country.GetData(),
1928 subunit = gmTools.none_if(self._TCTRL_unit.GetValue().strip(), u''),
1929 id_type = self._PRW_type.GetData()
1930 )
1931 except gmPG2.dbapi.InternalError:
1932 _log.debug('number: >>%s<<', self._TCTRL_number.GetValue().strip())
1933 _log.debug('(sub)unit: >>%s<<', self._TCTRL_unit.GetValue().strip())
1934 _log.debug('street: >>%s<<', self._PRW_street.GetValue().strip())
1935 _log.debug('postcode: >>%s<<', self._PRW_zip.GetValue().strip())
1936 _log.debug('urb: >>%s<<', self._PRW_urb.GetValue().strip())
1937 _log.debug('state: >>%s<<', self._PRW_region.GetData().strip())
1938 _log.debug('country: >>%s<<', self._PRW_country.GetData().strip())
1939 _log.exception('cannot link address')
1940 gmGuiHelpers.gm_show_error (
1941 aTitle = _('Saving address'),
1942 aMessage = _(
1943 'Cannot save this address.\n'
1944 '\n'
1945 'You will have to add it via the Demographics plugin.\n'
1946 )
1947 )
1948 elif is_valid is False:
1949 gmGuiHelpers.gm_show_error (
1950 aTitle = _('Saving address'),
1951 aMessage = _(
1952 'Address not saved.\n'
1953 '\n'
1954 'You will have to add it via the Demographics plugin.\n'
1955 )
1956 )
1957 # else it is None which means empty address which we ignore
1958
1959 # phone
1960 channel_name = self._PRW_channel_type.GetValue().strip()
1961 pk_channel_type = self._PRW_channel_type.GetData()
1962 if pk_channel_type is None:
1963 if channel_name == u'':
1964 channel_name = u'homephone'
1965 new_identity.link_comm_channel (
1966 comm_medium = channel_name,
1967 pk_channel_type = pk_channel_type,
1968 url = gmTools.none_if(self._TCTRL_phone.GetValue().strip(), u''),
1969 is_confidential = False
1970 )
1971
1972 # external ID
1973 pk_type = self._PRW_external_id_type.GetData()
1974 id_value = self._TCTRL_external_id_value.GetValue().strip()
1975 if (pk_type is not None) and (id_value != u''):
1976 new_identity.add_external_id(value = id_value, pk_type = pk_type)
1977
1978 # occupation
1979 new_identity.link_occupation (
1980 occupation = gmTools.none_if(self._PRW_occupation.GetValue().strip(), u'')
1981 )
1982
1983 self.data = new_identity
1984 return True
1985 #----------------------------------------------------------------
1988 #----------------------------------------------------------------
1992 #----------------------------------------------------------------
1995 #----------------------------------------------------------------
1998
1999 #============================================================
2000 # patient demographics editing classes
2001 #============================================================
2003 """Notebook displaying demographics editing pages:
2004
2005 - Identity (as per Jim/Rogerio 12/2011)
2006 - Contacts (addresses, phone numbers, etc)
2007 - Social network (significant others, GP, etc)
2008
2009 Does NOT act on/listen to the current patient.
2010 """
2011 #--------------------------------------------------------
2013
2014 wx.Notebook.__init__ (
2015 self,
2016 parent = parent,
2017 id = id,
2018 style = wx.NB_TOP | wx.NB_MULTILINE | wx.NO_BORDER,
2019 name = self.__class__.__name__
2020 )
2021
2022 self.__identity = None
2023 self.__do_layout()
2024 self.SetSelection(0)
2025 #--------------------------------------------------------
2026 # public API
2027 #--------------------------------------------------------
2029 """Populate fields in pages with data from model."""
2030 for page_idx in range(self.GetPageCount()):
2031 page = self.GetPage(page_idx)
2032 page.identity = self.__identity
2033
2034 return True
2035 #--------------------------------------------------------
2036 # internal API
2037 #--------------------------------------------------------
2039 """Build patient edition notebook pages."""
2040
2041 # identity page
2042 new_page = cPersonIdentityManagerPnl(self, -1)
2043 new_page.identity = self.__identity
2044 self.AddPage (
2045 page = new_page,
2046 text = _('Identity'),
2047 select = False
2048 )
2049
2050 # contacts page
2051 new_page = gmPersonContactWidgets.cPersonContactsManagerPnl(self, -1)
2052 new_page.identity = self.__identity
2053 self.AddPage (
2054 page = new_page,
2055 text = _('Contacts'),
2056 select = True
2057 )
2058
2059 # social network page
2060 new_page = cPersonSocialNetworkManagerPnl(self, -1)
2061 new_page.identity = self.__identity
2062 self.AddPage (
2063 page = new_page,
2064 text = _('Social network'),
2065 select = False
2066 )
2067 #--------------------------------------------------------
2068 # properties
2069 #--------------------------------------------------------
2072
2074 self.__identity = identity
2075
2076 identity = property(_get_identity, _set_identity)
2077 #============================================================
2078 # old occupation widgets
2079 #============================================================
2080 # FIXME: support multiple occupations
2081 # FIXME: redo with wxGlade
2082
2084 """Page containing patient occupations edition fields.
2085 """
2087 """
2088 Creates a new instance of BasicPatDetailsPage
2089 @param parent - The parent widget
2090 @type parent - A wx.Window instance
2091 @param id - The widget id
2092 @type id - An integer
2093 """
2094 wx.Panel.__init__(self, parent, id)
2095 self.__ident = ident
2096 self.__do_layout()
2097 #--------------------------------------------------------
2099 PNL_form = wx.Panel(self, -1)
2100 # occupation
2101 STT_occupation = wx.StaticText(PNL_form, -1, _('Occupation'))
2102 self.PRW_occupation = cOccupationPhraseWheel(parent = PNL_form, id = -1)
2103 self.PRW_occupation.SetToolTipString(_("primary occupation of the patient"))
2104 # known since
2105 STT_occupation_updated = wx.StaticText(PNL_form, -1, _('Last updated'))
2106 self.TTC_occupation_updated = wx.TextCtrl(PNL_form, -1, style = wx.TE_READONLY)
2107
2108 # layout input widgets
2109 SZR_input = wx.FlexGridSizer(cols = 2, rows = 5, vgap = 4, hgap = 4)
2110 SZR_input.AddGrowableCol(1)
2111 SZR_input.Add(STT_occupation, 0, wx.SHAPED)
2112 SZR_input.Add(self.PRW_occupation, 1, wx.EXPAND)
2113 SZR_input.Add(STT_occupation_updated, 0, wx.SHAPED)
2114 SZR_input.Add(self.TTC_occupation_updated, 1, wx.EXPAND)
2115 PNL_form.SetSizerAndFit(SZR_input)
2116
2117 # layout page
2118 SZR_main = wx.BoxSizer(wx.VERTICAL)
2119 SZR_main.Add(PNL_form, 1, wx.EXPAND)
2120 self.SetSizer(SZR_main)
2121 #--------------------------------------------------------
2124 #--------------------------------------------------------
2126 if identity is not None:
2127 self.__ident = identity
2128 jobs = self.__ident.get_occupations()
2129 if len(jobs) > 0:
2130 self.PRW_occupation.SetText(jobs[0]['l10n_occupation'])
2131 self.TTC_occupation_updated.SetValue(jobs[0]['modified_when'].strftime('%m/%Y'))
2132 return True
2133 #--------------------------------------------------------
2135 if self.PRW_occupation.IsModified():
2136 new_job = self.PRW_occupation.GetValue().strip()
2137 jobs = self.__ident.get_occupations()
2138 for job in jobs:
2139 if job['l10n_occupation'] == new_job:
2140 continue
2141 self.__ident.unlink_occupation(occupation = job['l10n_occupation'])
2142 self.__ident.link_occupation(occupation = new_job)
2143 return True
2144 #============================================================
2146 """Patient demographics plugin for main notebook.
2147
2148 Hosts another notebook with pages for Identity, Contacts, etc.
2149
2150 Acts on/listens to the currently active patient.
2151 """
2152 #--------------------------------------------------------
2154 wx.Panel.__init__ (self, parent = parent, id = id, style = wx.NO_BORDER)
2155 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
2156 self.__do_layout()
2157 self.__register_interests()
2158 #--------------------------------------------------------
2159 # public API
2160 #--------------------------------------------------------
2161 #--------------------------------------------------------
2162 # internal helpers
2163 #--------------------------------------------------------
2165 """Arrange widgets."""
2166 self.__patient_notebook = cPersonDemographicsEditorNb(self, -1)
2167
2168 szr_main = wx.BoxSizer(wx.VERTICAL)
2169 szr_main.Add(self.__patient_notebook, 1, wx.EXPAND)
2170 self.SetSizerAndFit(szr_main)
2171 #--------------------------------------------------------
2172 # event handling
2173 #--------------------------------------------------------
2175 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
2176 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
2177 #--------------------------------------------------------
2180 #--------------------------------------------------------
2183 # reget mixin API
2184 #--------------------------------------------------------
2194 #============================================================
2195 #============================================================
2196 if __name__ == "__main__":
2197
2198 #--------------------------------------------------------
2200 app = wx.PyWidgetTester(size = (600, 400))
2201 app.SetWidget(cKOrganizerSchedulePnl)
2202 app.MainLoop()
2203 #--------------------------------------------------------
2205 app = wx.PyWidgetTester(size = (600, 400))
2206 widget = cPersonNamesManagerPnl(app.frame, -1)
2207 widget.identity = activate_patient()
2208 app.frame.Show(True)
2209 app.MainLoop()
2210 #--------------------------------------------------------
2212 app = wx.PyWidgetTester(size = (600, 400))
2213 widget = cPersonIDsManagerPnl(app.frame, -1)
2214 widget.identity = activate_patient()
2215 app.frame.Show(True)
2216 app.MainLoop()
2217 #--------------------------------------------------------
2219 app = wx.PyWidgetTester(size = (600, 400))
2220 widget = cPersonIdentityManagerPnl(app.frame, -1)
2221 widget.identity = activate_patient()
2222 app.frame.Show(True)
2223 app.MainLoop()
2224 #--------------------------------------------------------
2226 app = wx.PyWidgetTester(size = (600, 400))
2227 app.SetWidget(cPersonNameEAPnl, name = activate_patient().get_active_name())
2228 app.MainLoop()
2229 #--------------------------------------------------------
2231 app = wx.PyWidgetTester(size = (600, 400))
2232 widget = cPersonDemographicsEditorNb(app.frame, -1)
2233 widget.identity = activate_patient()
2234 widget.refresh()
2235 app.frame.Show(True)
2236 app.MainLoop()
2237 #--------------------------------------------------------
2239 patient = gmPersonSearch.ask_for_patient()
2240 if patient is None:
2241 print "No patient. Exiting gracefully..."
2242 sys.exit(0)
2243 from Gnumed.wxpython import gmPatSearchWidgets
2244 gmPatSearchWidgets.set_active_patient(patient=patient)
2245 return patient
2246 #--------------------------------------------------------
2247 if len(sys.argv) > 1 and sys.argv[1] == 'test':
2248
2249 gmI18N.activate_locale()
2250 gmI18N.install_domain(domain='gnumed')
2251 gmPG2.get_connection()
2252
2253 # app = wx.PyWidgetTester(size = (400, 300))
2254 # app.SetWidget(cNotebookedPatEditionPanel, -1)
2255 # app.frame.Show(True)
2256 # app.MainLoop()
2257
2258 # phrasewheels
2259 # test_organizer_pnl()
2260
2261 # identity related widgets
2262 #test_person_names_pnl()
2263 test_person_ids_pnl()
2264 #test_pat_ids_pnl()
2265 #test_name_ea_pnl()
2266
2267 #test_cPersonDemographicsEditorNb()
2268
2269 #============================================================
2270
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Wed Jun 13 03:58:54 2012 | http://epydoc.sourceforge.net |