| 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 gmPerson
38 from Gnumed.business import gmStaff
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(gmTools.gmPaths().tmp_dir, '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 #============================================================
536
537 #------------------------------------------------------------
539 # ask user for assurance
540 go_ahead = gmGuiHelpers.gm_show_question (
541 _('Are you sure you really, positively want\n'
542 'to disable the following person ?\n'
543 '\n'
544 ' %s %s %s\n'
545 ' born %s\n'
546 '\n'
547 '%s\n'
548 ) % (
549 identity['firstnames'],
550 identity['lastnames'],
551 identity['gender'],
552 identity.get_formatted_dob(),
553 gmTools.bool2subst (
554 identity.is_patient,
555 _('This patient DID receive care.'),
556 _('This person did NOT receive care.')
557 )
558 ),
559 _('Disabling person')
560 )
561 if not go_ahead:
562 return True
563
564 # get admin connection
565 conn = gmAuthWidgets.get_dbowner_connection (
566 procedure = _('Disabling patient')
567 )
568 # - user cancelled
569 if conn is False:
570 return True
571 # - error
572 if conn is None:
573 return False
574
575 # now disable patient
576 gmPG2.run_rw_queries(queries = [{'cmd': u"update dem.identity set deleted=True where pk=%s", 'args': [identity['pk_identity']]}])
577
578 return True
579
580 #------------------------------------------------------------
581 # phrasewheels
582 #------------------------------------------------------------
584
586 query = u"SELECT distinct lastnames, lastnames from dem.names where lastnames %(fragment_condition)s order by lastnames limit 25"
587 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
588 mp.setThresholds(3, 5, 9)
589 gmPhraseWheel.cPhraseWheel.__init__ (
590 self,
591 *args,
592 **kwargs
593 )
594 self.SetToolTipString(_("Type or select a last name (family name/surname)."))
595 self.capitalisation_mode = gmTools.CAPS_NAMES
596 self.matcher = mp
597 #------------------------------------------------------------
599
601 query = u"""
602 (SELECT distinct firstnames, firstnames from dem.names where firstnames %(fragment_condition)s order by firstnames limit 20)
603 union
604 (SELECT distinct name, name from dem.name_gender_map where name %(fragment_condition)s order by name limit 20)"""
605 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
606 mp.setThresholds(3, 5, 9)
607 gmPhraseWheel.cPhraseWheel.__init__ (
608 self,
609 *args,
610 **kwargs
611 )
612 self.SetToolTipString(_("Type or select a first name (forename/Christian name/given name)."))
613 self.capitalisation_mode = gmTools.CAPS_NAMES
614 self.matcher = mp
615 #------------------------------------------------------------
617
619 query = u"""
620 (SELECT distinct preferred, preferred from dem.names where preferred %(fragment_condition)s order by preferred limit 20)
621 union
622 (SELECT distinct firstnames, firstnames from dem.names where firstnames %(fragment_condition)s order by firstnames limit 20)
623 union
624 (SELECT distinct name, name from dem.name_gender_map where name %(fragment_condition)s order by name limit 20)"""
625 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
626 mp.setThresholds(3, 5, 9)
627 gmPhraseWheel.cPhraseWheel.__init__ (
628 self,
629 *args,
630 **kwargs
631 )
632 self.SetToolTipString(_("Type or select an alias (nick name, preferred name, call name, warrior name, artist name)."))
633 # nicknames CAN start with lower case !
634 #self.capitalisation_mode = gmTools.CAPS_NAMES
635 self.matcher = mp
636 #------------------------------------------------------------
638
640 query = u"SELECT distinct title, title from dem.identity where title %(fragment_condition)s"
641 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
642 mp.setThresholds(1, 3, 9)
643 gmPhraseWheel.cPhraseWheel.__init__ (
644 self,
645 *args,
646 **kwargs
647 )
648 self.SetToolTipString(_("Type or select a title. Note that the title applies to the person, not to a particular name !"))
649 self.matcher = mp
650 #------------------------------------------------------------
652 """Let user select a gender."""
653
654 _gender_map = None
655
657
658 if cGenderSelectionPhraseWheel._gender_map is None:
659 cmd = u"""
660 SELECT tag, l10n_label, sort_weight
661 from dem.v_gender_labels
662 order by sort_weight desc"""
663 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx=True)
664 cGenderSelectionPhraseWheel._gender_map = {}
665 for gender in rows:
666 cGenderSelectionPhraseWheel._gender_map[gender[idx['tag']]] = {
667 'data': gender[idx['tag']],
668 'field_label': gender[idx['l10n_label']],
669 'list_label': gender[idx['l10n_label']],
670 'weight': gender[idx['sort_weight']]
671 }
672
673 mp = gmMatchProvider.cMatchProvider_FixedList(aSeq = cGenderSelectionPhraseWheel._gender_map.values())
674 mp.setThresholds(1, 1, 3)
675
676 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
677 self.selection_only = True
678 self.matcher = mp
679 self.picklist_delay = 50
680 #------------------------------------------------------------
682
684 query = u"""
685 SELECT DISTINCT ON (list_label)
686 pk AS data,
687 name AS field_label,
688 name || coalesce(' (' || issuer || ')', '') as list_label
689 FROM dem.enum_ext_id_types
690 WHERE name %(fragment_condition)s
691 ORDER BY list_label
692 LIMIT 25
693 """
694 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
695 mp.setThresholds(1, 3, 5)
696 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
697 self.SetToolTipString(_("Enter or select a type for the external ID."))
698 self.matcher = mp
699 #--------------------------------------------------------
704 #------------------------------------------------------------
706
708 query = u"""
709 SELECT distinct issuer, issuer
710 from dem.enum_ext_id_types
711 where issuer %(fragment_condition)s
712 order by issuer limit 25"""
713 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
714 mp.setThresholds(1, 3, 5)
715 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
716 self.SetToolTipString(_("Type or select an ID issuer."))
717 self.capitalisation_mode = gmTools.CAPS_FIRST
718 self.matcher = mp
719 #------------------------------------------------------------
720 # edit areas
721 #------------------------------------------------------------
722 from Gnumed.wxGladeWidgets import wxgExternalIDEditAreaPnl
723
724 -class cExternalIDEditAreaPnl(wxgExternalIDEditAreaPnl.wxgExternalIDEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
725 """An edit area for editing/creating external IDs.
726
727 Does NOT act on/listen to the current patient.
728 """
730
731 try:
732 data = kwargs['external_id']
733 del kwargs['external_id']
734 except:
735 data = None
736
737 wxgExternalIDEditAreaPnl.wxgExternalIDEditAreaPnl.__init__(self, *args, **kwargs)
738 gmEditArea.cGenericEditAreaMixin.__init__(self)
739
740 self.identity = None
741
742 self.mode = 'new'
743 self.data = data
744 if data is not None:
745 self.mode = 'edit'
746
747 self.__init_ui()
748 #--------------------------------------------------------
750 self._PRW_type.add_callback_on_lose_focus(self._on_type_set)
751 #----------------------------------------------------------------
752 # generic Edit Area mixin API
753 #----------------------------------------------------------------
755 validity = True
756
757 # do not test .GetData() because adding external
758 # IDs will create types as necessary
759 #if self._PRW_type.GetData() is None:
760 if self._PRW_type.GetValue().strip() == u'':
761 validity = False
762 self._PRW_type.display_as_valid(False)
763 self._PRW_type.SetFocus()
764 else:
765 self._PRW_type.display_as_valid(True)
766
767 if self._TCTRL_value.GetValue().strip() == u'':
768 validity = False
769 self.display_tctrl_as_valid(tctrl = self._TCTRL_value, valid = False)
770 else:
771 self.display_tctrl_as_valid(tctrl = self._TCTRL_value, valid = True)
772
773 return validity
774 #----------------------------------------------------------------
776 data = {}
777 data['pk_type'] = None
778 data['name'] = self._PRW_type.GetValue().strip()
779 data['value'] = self._TCTRL_value.GetValue().strip()
780 data['issuer'] = gmTools.none_if(self._PRW_issuer.GetValue().strip(), u'')
781 data['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
782
783 self.identity.add_external_id (
784 type_name = data['name'],
785 value = data['value'],
786 issuer = data['issuer'],
787 comment = data['comment']
788 )
789
790 self.data = data
791 return True
792 #----------------------------------------------------------------
794 self.data['name'] = self._PRW_type.GetValue().strip()
795 self.data['value'] = self._TCTRL_value.GetValue().strip()
796 self.data['issuer'] = gmTools.none_if(self._PRW_issuer.GetValue().strip(), u'')
797 self.data['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
798
799 self.identity.update_external_id (
800 pk_id = self.data['pk_id'],
801 type = self.data['name'],
802 value = self.data['value'],
803 issuer = self.data['issuer'],
804 comment = self.data['comment']
805 )
806
807 return True
808 #----------------------------------------------------------------
810 self._PRW_type.SetText(value = u'', data = None)
811 self._TCTRL_value.SetValue(u'')
812 self._PRW_issuer.SetText(value = u'', data = None)
813 self._TCTRL_comment.SetValue(u'')
814 #----------------------------------------------------------------
818 #----------------------------------------------------------------
820 self._PRW_type.SetText(value = self.data['name'], data = self.data['pk_type'])
821 self._TCTRL_value.SetValue(self.data['value'])
822 self._PRW_issuer.SetText(self.data['issuer'])
823 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
824 #----------------------------------------------------------------
825 # internal helpers
826 #----------------------------------------------------------------
828 """Set the issuer according to the selected type.
829
830 Matches are fetched from existing records in backend.
831 """
832 pk_curr_type = self._PRW_type.GetData()
833 if pk_curr_type is None:
834 return True
835 rows, idx = gmPG2.run_ro_queries(queries = [{
836 'cmd': u"SELECT issuer from dem.enum_ext_id_types where pk = %s",
837 'args': [pk_curr_type]
838 }])
839 if len(rows) == 0:
840 return True
841 wx.CallAfter(self._PRW_issuer.SetText, rows[0][0])
842 return True
843
844 #============================================================
845 # identity widgets
846 #------------------------------------------------------------
848 allow_empty_dob = gmGuiHelpers.gm_show_question (
849 _(
850 'Are you sure you want to leave this person\n'
851 'without a valid date of birth ?\n'
852 '\n'
853 'This can be useful for temporary staff members\n'
854 'but will provoke nag screens if this person\n'
855 'becomes a patient.\n'
856 ),
857 _('Validating date of birth')
858 )
859 return allow_empty_dob
860 #------------------------------------------------------------
862
863 # valid timestamp ?
864 if dob_prw.is_valid_timestamp(allow_empty = False): # properly colors the field
865 dob = dob_prw.date
866 # but year also usable ?
867 if (dob.year > 1899) and (dob < gmDateTime.pydt_now_here()):
868 return True
869
870 if dob.year < 1900:
871 msg = _(
872 'DOB: %s\n'
873 '\n'
874 'While this is a valid point in time Python does\n'
875 'not know how to deal with it.\n'
876 '\n'
877 'We suggest using January 1st 1901 instead and adding\n'
878 'the true date of birth to the patient comment.\n'
879 '\n'
880 'Sorry for the inconvenience %s'
881 ) % (dob, gmTools.u_frowning_face)
882 else:
883 msg = _(
884 'DOB: %s\n'
885 '\n'
886 'Date of birth in the future !'
887 ) % dob
888 gmGuiHelpers.gm_show_error (
889 msg,
890 _('Validating date of birth')
891 )
892 dob_prw.display_as_valid(False)
893 dob_prw.SetFocus()
894 return False
895
896 # invalid timestamp but not empty
897 if dob_prw.GetValue().strip() != u'':
898 dob_prw.display_as_valid(False)
899 gmDispatcher.send(signal = u'statustext', msg = _('Invalid date of birth.'))
900 dob_prw.SetFocus()
901 return False
902
903 # empty DOB field
904 dob_prw.display_as_valid(False)
905 return True
906
907 #------------------------------------------------------------
909
910 val = ctrl.GetValue().strip()
911
912 if val == u'':
913 return True
914
915 converted, hours = gmTools.input2int(val[:2], 0, 23)
916 if not converted:
917 return False
918
919 converted, minutes = gmTools.input2int(val[3:5], 0, 59)
920 if not converted:
921 return False
922
923 return True
924
925 #------------------------------------------------------------
926 from Gnumed.wxGladeWidgets import wxgIdentityEAPnl
927
929 """An edit area for editing/creating title/gender/dob/dod etc."""
930
932
933 try:
934 data = kwargs['identity']
935 del kwargs['identity']
936 except KeyError:
937 data = None
938
939 wxgIdentityEAPnl.wxgIdentityEAPnl.__init__(self, *args, **kwargs)
940 gmEditArea.cGenericEditAreaMixin.__init__(self)
941
942 self.mode = 'new'
943 self.data = data
944 if data is not None:
945 self.mode = 'edit'
946
947 # self.__init_ui()
948 #----------------------------------------------------------------
949 # def __init_ui(self):
950 # # adjust phrasewheels etc
951 #----------------------------------------------------------------
952 # generic Edit Area mixin API
953 #----------------------------------------------------------------
955
956 has_error = False
957
958 if self._PRW_gender.GetData() is None:
959 self._PRW_gender.SetFocus()
960 has_error = True
961
962 if self.data is not None:
963 if not _validate_dob_field(self._PRW_dob):
964 has_error = True
965
966 # TOB validation
967 if _validate_tob_field(self._TCTRL_tob):
968 self.display_ctrl_as_valid(ctrl = self._TCTRL_tob, valid = True)
969 else:
970 has_error = True
971 self.display_ctrl_as_valid(ctrl = self._TCTRL_tob, valid = False)
972
973 if not self._PRW_dod.is_valid_timestamp(allow_empty = True):
974 gmDispatcher.send(signal = u'statustext', msg = _('Invalid date of death.'))
975 self._PRW_dod.SetFocus()
976 has_error = True
977
978 return (has_error is False)
979 #----------------------------------------------------------------
983 #----------------------------------------------------------------
985
986 if self._PRW_dob.GetValue().strip() == u'':
987 if not _empty_dob_allowed():
988 return False
989 self.data['dob'] = None
990 else:
991 self.data['dob'] = self._PRW_dob.GetData()
992 self.data['dob_is_estimated'] = self._CHBOX_estimated_dob.GetValue()
993 val = self._TCTRL_tob.GetValue().strip()
994 if val == u'':
995 self.data['tob'] = None
996 else:
997 self.data['tob'] = pydt.time(int(val[:2]), int(val[3:5]))
998 self.data['gender'] = self._PRW_gender.GetData()
999 self.data['title'] = gmTools.none_if(self._PRW_title.GetValue().strip(), u'')
1000 self.data['deceased'] = self._PRW_dod.GetData()
1001 self.data['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
1002
1003 self.data.save()
1004 return True
1005 #----------------------------------------------------------------
1008 #----------------------------------------------------------------
1010
1011 self._LBL_info.SetLabel(u'ID: #%s' % (
1012 self.data.ID
1013 # FIXME: add 'deleted' status
1014 ))
1015 if self.data['dob'] is None:
1016 val = u''
1017 else:
1018 val = gmDateTime.pydt_strftime (
1019 self.data['dob'],
1020 format = '%Y-%m-%d',
1021 accuracy = gmDateTime.acc_minutes
1022 )
1023 self._PRW_dob.SetText(value = val, data = self.data['dob'])
1024 self._CHBOX_estimated_dob.SetValue(self.data['dob_is_estimated'])
1025 if self.data['tob'] is None:
1026 self._TCTRL_tob.SetValue(u'')
1027 else:
1028 self._TCTRL_tob.SetValue(self.data['tob'].strftime('%H:%M'))
1029 if self.data['deceased'] is None:
1030 val = u''
1031 else:
1032 val = gmDateTime.pydt_strftime (
1033 self.data['deceased'],
1034 format = '%Y-%m-%d %H:%M',
1035 accuracy = gmDateTime.acc_minutes
1036 )
1037 self._PRW_dod.SetText(value = val, data = self.data['deceased'])
1038 self._PRW_gender.SetData(self.data['gender'])
1039 #self._PRW_ethnicity.SetValue()
1040 self._PRW_title.SetText(gmTools.coalesce(self.data['title'], u''))
1041 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
1042 #----------------------------------------------------------------
1045 #------------------------------------------------------------
1046 from Gnumed.wxGladeWidgets import wxgPersonNameEAPnl
1047
1048 -class cPersonNameEAPnl(wxgPersonNameEAPnl.wxgPersonNameEAPnl, gmEditArea.cGenericEditAreaMixin):
1049 """An edit area for editing/creating names of people.
1050
1051 Does NOT act on/listen to the current patient.
1052 """
1054
1055 try:
1056 data = kwargs['name']
1057 identity = gmPerson.cIdentity(aPK_obj = data['pk_identity'])
1058 del kwargs['name']
1059 except KeyError:
1060 data = None
1061 identity = kwargs['identity']
1062 del kwargs['identity']
1063
1064 wxgPersonNameEAPnl.wxgPersonNameEAPnl.__init__(self, *args, **kwargs)
1065 gmEditArea.cGenericEditAreaMixin.__init__(self)
1066
1067 self.__identity = identity
1068
1069 self.mode = 'new'
1070 self.data = data
1071 if data is not None:
1072 self.mode = 'edit'
1073
1074 #self.__init_ui()
1075 #----------------------------------------------------------------
1076 # def __init_ui(self):
1077 # # adjust phrasewheels etc
1078 #----------------------------------------------------------------
1079 # generic Edit Area mixin API
1080 #----------------------------------------------------------------
1082 validity = True
1083
1084 if self._PRW_lastname.GetValue().strip() == u'':
1085 validity = False
1086 self._PRW_lastname.display_as_valid(False)
1087 self._PRW_lastname.SetFocus()
1088 else:
1089 self._PRW_lastname.display_as_valid(True)
1090
1091 if self._PRW_firstname.GetValue().strip() == u'':
1092 validity = False
1093 self._PRW_firstname.display_as_valid(False)
1094 self._PRW_firstname.SetFocus()
1095 else:
1096 self._PRW_firstname.display_as_valid(True)
1097
1098 return validity
1099 #----------------------------------------------------------------
1101
1102 first = self._PRW_firstname.GetValue().strip()
1103 last = self._PRW_lastname.GetValue().strip()
1104 active = self._CHBOX_active.GetValue()
1105
1106 try:
1107 data = self.__identity.add_name(first, last, active)
1108 except gmPG2.dbapi.IntegrityError as exc:
1109 _log.exception('cannot save new name')
1110 gmGuiHelpers.gm_show_error (
1111 aTitle = _('Adding name'),
1112 aMessage = _(
1113 'Cannot add this name to the patient !\n'
1114 '\n'
1115 ' %s'
1116 ) % str(exc)
1117 )
1118 return False
1119
1120 old_nick = self.__identity['active_name']['preferred']
1121 new_nick = gmTools.none_if(self._PRW_nick.GetValue().strip(), u'')
1122 if active:
1123 data['preferred'] = gmTools.coalesce(new_nick, old_nick)
1124 else:
1125 data['preferred'] = new_nick
1126 data['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
1127 data.save()
1128
1129 self.data = data
1130 return True
1131 #----------------------------------------------------------------
1133 """The knack here is that we can only update a few fields.
1134
1135 Otherwise we need to clone the name and update that.
1136 """
1137 first = self._PRW_firstname.GetValue().strip()
1138 last = self._PRW_lastname.GetValue().strip()
1139 active = self._CHBOX_active.GetValue()
1140
1141 current_name = self.data['firstnames'].strip() + self.data['lastnames'].strip()
1142 new_name = first + last
1143
1144 # editable fields only ?
1145 if new_name == current_name:
1146 self.data['active_name'] = self._CHBOX_active.GetValue()
1147 self.data['preferred'] = gmTools.none_if(self._PRW_nick.GetValue().strip(), u'')
1148 self.data['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
1149 self.data.save()
1150 # else clone name and update that
1151 else:
1152 try:
1153 name = self.__identity.add_name(first, last, active)
1154 except gmPG2.dbapi.IntegrityError as exc:
1155 _log.exception('cannot clone name when editing existing name')
1156 gmGuiHelpers.gm_show_error (
1157 aTitle = _('Editing name'),
1158 aMessage = _(
1159 'Cannot clone a copy of this name !\n'
1160 '\n'
1161 ' %s'
1162 ) % str(exc)
1163 )
1164 return False
1165 name['preferred'] = gmTools.none_if(self._PRW_nick.GetValue().strip(), u'')
1166 name['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
1167 name.save()
1168 self.data = name
1169
1170 return True
1171 #----------------------------------------------------------------
1173 self._PRW_firstname.SetText(value = u'', data = None)
1174 self._PRW_lastname.SetText(value = u'', data = None)
1175 self._PRW_nick.SetText(value = u'', data = None)
1176 self._TCTRL_comment.SetValue(u'')
1177 self._CHBOX_active.SetValue(False)
1178
1179 self._PRW_firstname.SetFocus()
1180 #----------------------------------------------------------------
1182 self._refresh_as_new()
1183 self._PRW_firstname.SetText(value = u'', data = None)
1184 self._PRW_nick.SetText(gmTools.coalesce(self.data['preferred'], u''))
1185
1186 self._PRW_lastname.SetFocus()
1187 #----------------------------------------------------------------
1189 self._PRW_firstname.SetText(self.data['firstnames'])
1190 self._PRW_lastname.SetText(self.data['lastnames'])
1191 self._PRW_nick.SetText(gmTools.coalesce(self.data['preferred'], u''))
1192 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
1193 self._CHBOX_active.SetValue(self.data['active_name'])
1194
1195 self._TCTRL_comment.SetFocus()
1196 #------------------------------------------------------------
1197 # list manager
1198 #------------------------------------------------------------
1200 """A list for managing a person's names.
1201
1202 Does NOT act on/listen to the current patient.
1203 """
1205
1206 try:
1207 self.__identity = kwargs['identity']
1208 del kwargs['identity']
1209 except KeyError:
1210 self.__identity = None
1211
1212 gmListWidgets.cGenericListManagerPnl.__init__(self, *args, **kwargs)
1213
1214 self.new_callback = self._add_name
1215 self.edit_callback = self._edit_name
1216 self.delete_callback = self._del_name
1217 self.refresh_callback = self.refresh
1218
1219 self.__init_ui()
1220 self.refresh()
1221 #--------------------------------------------------------
1222 # external API
1223 #--------------------------------------------------------
1225 if self.__identity is None:
1226 self._LCTRL_items.set_string_items()
1227 return
1228
1229 names = self.__identity.get_names()
1230 self._LCTRL_items.set_string_items (
1231 items = [ [
1232 gmTools.bool2str(n['active_name'], 'X', ''),
1233 n['lastnames'],
1234 n['firstnames'],
1235 gmTools.coalesce(n['preferred'], u''),
1236 gmTools.coalesce(n['comment'], u'')
1237 ] for n in names ]
1238 )
1239 self._LCTRL_items.set_column_widths()
1240 self._LCTRL_items.set_data(data = names)
1241 #--------------------------------------------------------
1242 # internal helpers
1243 #--------------------------------------------------------
1245 self._LCTRL_items.set_columns(columns = [
1246 _('Active'),
1247 _('Lastname'),
1248 _('Firstname(s)'),
1249 _('Preferred Name'),
1250 _('Comment')
1251 ])
1252 #--------------------------------------------------------
1254 #ea = cPersonNameEAPnl(self, -1, name = self.__identity.get_active_name())
1255 ea = cPersonNameEAPnl(self, -1, identity = self.__identity)
1256 dlg = gmEditArea.cGenericEditAreaDlg2(self, -1, edit_area = ea, single_entry = True)
1257 dlg.SetTitle(_('Adding new name'))
1258 if dlg.ShowModal() == wx.ID_OK:
1259 dlg.Destroy()
1260 return True
1261 dlg.Destroy()
1262 return False
1263 #--------------------------------------------------------
1265 ea = cPersonNameEAPnl(self, -1, name = name)
1266 dlg = gmEditArea.cGenericEditAreaDlg2(self, -1, edit_area = ea, single_entry = True)
1267 dlg.SetTitle(_('Editing name'))
1268 if dlg.ShowModal() == wx.ID_OK:
1269 dlg.Destroy()
1270 return True
1271 dlg.Destroy()
1272 return False
1273 #--------------------------------------------------------
1275
1276 if len(self.__identity.get_names()) == 1:
1277 gmDispatcher.send(signal = u'statustext', msg = _('Cannot delete the only name of a person.'), beep = True)
1278 return False
1279
1280 if name['active_name']:
1281 gmDispatcher.send(signal = u'statustext', msg = _('Cannot delete the active name of a person.'), beep = True)
1282 return False
1283
1284 go_ahead = gmGuiHelpers.gm_show_question (
1285 _( 'It is often advisable to keep old names around and\n'
1286 'just create a new "currently active" name.\n'
1287 '\n'
1288 'This allows finding the patient by both the old\n'
1289 'and the new name (think before/after marriage).\n'
1290 '\n'
1291 'Do you still want to really delete\n'
1292 "this name from the patient ?"
1293 ),
1294 _('Deleting name')
1295 )
1296 if not go_ahead:
1297 return False
1298
1299 self.__identity.delete_name(name = name)
1300 return True
1301 #--------------------------------------------------------
1302 # properties
1303 #--------------------------------------------------------
1306
1310
1311 identity = property(_get_identity, _set_identity)
1312 #------------------------------------------------------------
1314 """A list for managing a person's external IDs.
1315
1316 Does NOT act on/listen to the current patient.
1317 """
1319
1320 try:
1321 self.__identity = kwargs['identity']
1322 del kwargs['identity']
1323 except KeyError:
1324 self.__identity = None
1325
1326 gmListWidgets.cGenericListManagerPnl.__init__(self, *args, **kwargs)
1327
1328 self.new_callback = self._add_id
1329 self.edit_callback = self._edit_id
1330 self.delete_callback = self._del_id
1331 self.refresh_callback = self.refresh
1332
1333 self.__init_ui()
1334 self.refresh()
1335 #--------------------------------------------------------
1336 # external API
1337 #--------------------------------------------------------
1339 if self.__identity is None:
1340 self._LCTRL_items.set_string_items()
1341 return
1342
1343 ids = self.__identity.get_external_ids()
1344 self._LCTRL_items.set_string_items (
1345 items = [ [
1346 i['name'],
1347 i['value'],
1348 gmTools.coalesce(i['issuer'], u''),
1349 gmTools.coalesce(i['comment'], u'')
1350 ] for i in ids
1351 ]
1352 )
1353 self._LCTRL_items.set_column_widths()
1354 self._LCTRL_items.set_data(data = ids)
1355 #--------------------------------------------------------
1356 # internal helpers
1357 #--------------------------------------------------------
1359 self._LCTRL_items.set_columns(columns = [
1360 _('ID type'),
1361 _('Value'),
1362 _('Issuer'),
1363 _('Comment')
1364 ])
1365 #--------------------------------------------------------
1367 ea = cExternalIDEditAreaPnl(self, -1)
1368 ea.identity = self.__identity
1369 dlg = gmEditArea.cGenericEditAreaDlg2(self, -1, edit_area = ea)
1370 dlg.SetTitle(_('Adding new external ID'))
1371 if dlg.ShowModal() == wx.ID_OK:
1372 dlg.Destroy()
1373 return True
1374 dlg.Destroy()
1375 return False
1376 #--------------------------------------------------------
1378 ea = cExternalIDEditAreaPnl(self, -1, external_id = ext_id)
1379 ea.identity = self.__identity
1380 dlg = gmEditArea.cGenericEditAreaDlg2(self, -1, edit_area = ea, single_entry = True)
1381 dlg.SetTitle(_('Editing external ID'))
1382 if dlg.ShowModal() == wx.ID_OK:
1383 dlg.Destroy()
1384 return True
1385 dlg.Destroy()
1386 return False
1387 #--------------------------------------------------------
1389 go_ahead = gmGuiHelpers.gm_show_question (
1390 _( 'Do you really want to delete this\n'
1391 'external ID from the patient ?'),
1392 _('Deleting external ID')
1393 )
1394 if not go_ahead:
1395 return False
1396 self.__identity.delete_external_id(pk_ext_id = ext_id['pk_id'])
1397 return True
1398 #--------------------------------------------------------
1399 # properties
1400 #--------------------------------------------------------
1403
1407
1408 identity = property(_get_identity, _set_identity)
1409 #------------------------------------------------------------
1410 # integrated panels
1411 #------------------------------------------------------------
1412 from Gnumed.wxGladeWidgets import wxgPersonIdentityManagerPnl
1413
1415 """A panel for editing identity data for a person.
1416
1417 - provides access to:
1418 - identity EA
1419 - name list manager
1420 - external IDs list manager
1421
1422 Does NOT act on/listen to the current patient.
1423 """
1425
1426 wxgPersonIdentityManagerPnl.wxgPersonIdentityManagerPnl.__init__(self, *args, **kwargs)
1427
1428 self.__identity = None
1429 self.refresh()
1430 #--------------------------------------------------------
1431 # external API
1432 #--------------------------------------------------------
1434 self._PNL_names.identity = self.__identity
1435 self._PNL_ids.identity = self.__identity
1436 # this is an Edit Area:
1437 self._PNL_identity.mode = 'new'
1438 self._PNL_identity.data = self.__identity
1439 if self.__identity is not None:
1440 self._PNL_identity.mode = 'edit'
1441 self._PNL_identity._refresh_from_existing()
1442 #--------------------------------------------------------
1443 # properties
1444 #--------------------------------------------------------
1447
1451
1452 identity = property(_get_identity, _set_identity)
1453 #--------------------------------------------------------
1454 # event handlers
1455 #--------------------------------------------------------
1459 #self._PNL_identity.refresh()
1460 #--------------------------------------------------------
1463
1464 #============================================================
1465 from Gnumed.wxGladeWidgets import wxgPersonSocialNetworkManagerPnl
1466
1467 -class cPersonSocialNetworkManagerPnl(wxgPersonSocialNetworkManagerPnl.wxgPersonSocialNetworkManagerPnl):
1469
1470 wxgPersonSocialNetworkManagerPnl.wxgPersonSocialNetworkManagerPnl.__init__(self, *args, **kwargs)
1471
1472 self.__identity = None
1473 self._PRW_provider.selection_only = False
1474 self.refresh()
1475 #--------------------------------------------------------
1476 # external API
1477 #--------------------------------------------------------
1479
1480 tt = _('Link another person in this database as the emergency contact:\n\nEnter person name part or identifier and hit <enter>.')
1481
1482 if self.__identity is None:
1483 self._TCTRL_er_contact.SetValue(u'')
1484 self._TCTRL_person.person = None
1485 self._TCTRL_person.SetToolTipString(tt)
1486
1487 self._PRW_provider.SetText(value = u'', data = None)
1488 return
1489
1490 self._TCTRL_er_contact.SetValue(gmTools.coalesce(self.__identity['emergency_contact'], u''))
1491 if self.__identity['pk_emergency_contact'] is not None:
1492 ident = gmPerson.cIdentity(aPK_obj = self.__identity['pk_emergency_contact'])
1493 self._TCTRL_person.person = ident
1494 tt = u'%s\n\n%s\n\n%s' % (
1495 tt,
1496 ident['description_gender'],
1497 u'\n'.join([
1498 u'%s: %s%s' % (
1499 c['l10n_comm_type'],
1500 c['url'],
1501 gmTools.bool2subst(c['is_confidential'], _(' (confidential !)'), u'', u'')
1502 )
1503 for c in ident.get_comm_channels()
1504 ])
1505 )
1506 else:
1507 self._TCTRL_person.person = None
1508
1509 self._TCTRL_person.SetToolTipString(tt)
1510
1511 if self.__identity['pk_primary_provider'] is None:
1512 self._PRW_provider.SetText(value = u'', data = None)
1513 else:
1514 self._PRW_provider.SetData(data = self.__identity['pk_primary_provider'])
1515 #--------------------------------------------------------
1516 # properties
1517 #--------------------------------------------------------
1520
1524
1525 identity = property(_get_identity, _set_identity)
1526 #--------------------------------------------------------
1527 # event handlers
1528 #--------------------------------------------------------
1543 #--------------------------------------------------------
1546 #--------------------------------------------------------
1557 #--------------------------------------------------------
1565
1566 #============================================================
1567 # patient demographics editing classes
1568 #============================================================
1570 """Notebook displaying demographics editing pages:
1571
1572 - Identity (as per Jim/Rogerio 12/2011)
1573 - Contacts (addresses, phone numbers, etc)
1574 - Social network (significant others, GP, etc)
1575
1576 Does NOT act on/listen to the current patient.
1577 """
1578 #--------------------------------------------------------
1580
1581 wx.Notebook.__init__ (
1582 self,
1583 parent = parent,
1584 id = id,
1585 style = wx.NB_TOP | wx.NB_MULTILINE | wx.NO_BORDER,
1586 name = self.__class__.__name__
1587 )
1588
1589 self.__identity = None
1590 self.__do_layout()
1591 self.SetSelection(0)
1592 #--------------------------------------------------------
1593 # public API
1594 #--------------------------------------------------------
1596 """Populate fields in pages with data from model."""
1597 for page_idx in range(self.GetPageCount()):
1598 page = self.GetPage(page_idx)
1599 page.identity = self.__identity
1600
1601 return True
1602 #--------------------------------------------------------
1603 # internal API
1604 #--------------------------------------------------------
1606 """Build patient edition notebook pages."""
1607
1608 # identity page
1609 new_page = cPersonIdentityManagerPnl(self, -1)
1610 new_page.identity = self.__identity
1611 self.AddPage (
1612 page = new_page,
1613 text = _('Identity'),
1614 select = False
1615 )
1616
1617 # contacts page
1618 new_page = gmPersonContactWidgets.cPersonContactsManagerPnl(self, -1)
1619 new_page.identity = self.__identity
1620 self.AddPage (
1621 page = new_page,
1622 text = _('Contacts'),
1623 select = True
1624 )
1625
1626 # social network page
1627 new_page = cPersonSocialNetworkManagerPnl(self, -1)
1628 new_page.identity = self.__identity
1629 self.AddPage (
1630 page = new_page,
1631 text = _('Social network'),
1632 select = False
1633 )
1634 #--------------------------------------------------------
1635 # properties
1636 #--------------------------------------------------------
1639
1641 self.__identity = identity
1642
1643 identity = property(_get_identity, _set_identity)
1644 #============================================================
1645 # old occupation widgets
1646 #============================================================
1647 # FIXME: support multiple occupations
1648 # FIXME: redo with wxGlade
1649
1651 """Page containing patient occupations edition fields.
1652 """
1654 """
1655 Creates a new instance of BasicPatDetailsPage
1656 @param parent - The parent widget
1657 @type parent - A wx.Window instance
1658 @param id - The widget id
1659 @type id - An integer
1660 """
1661 wx.Panel.__init__(self, parent, id)
1662 self.__ident = ident
1663 self.__do_layout()
1664 #--------------------------------------------------------
1666 PNL_form = wx.Panel(self, -1)
1667 # occupation
1668 STT_occupation = wx.StaticText(PNL_form, -1, _('Occupation'))
1669 self.PRW_occupation = cOccupationPhraseWheel(parent = PNL_form, id = -1)
1670 self.PRW_occupation.SetToolTipString(_("primary occupation of the patient"))
1671 # known since
1672 STT_occupation_updated = wx.StaticText(PNL_form, -1, _('Last updated'))
1673 self.TTC_occupation_updated = wx.TextCtrl(PNL_form, -1, style = wx.TE_READONLY)
1674
1675 # layout input widgets
1676 SZR_input = wx.FlexGridSizer(cols = 2, rows = 5, vgap = 4, hgap = 4)
1677 SZR_input.AddGrowableCol(1)
1678 SZR_input.Add(STT_occupation, 0, wx.SHAPED)
1679 SZR_input.Add(self.PRW_occupation, 1, wx.EXPAND)
1680 SZR_input.Add(STT_occupation_updated, 0, wx.SHAPED)
1681 SZR_input.Add(self.TTC_occupation_updated, 1, wx.EXPAND)
1682 PNL_form.SetSizerAndFit(SZR_input)
1683
1684 # layout page
1685 SZR_main = wx.BoxSizer(wx.VERTICAL)
1686 SZR_main.Add(PNL_form, 1, wx.EXPAND)
1687 self.SetSizer(SZR_main)
1688 #--------------------------------------------------------
1691 #--------------------------------------------------------
1693 if identity is not None:
1694 self.__ident = identity
1695 jobs = self.__ident.get_occupations()
1696 if len(jobs) > 0:
1697 self.PRW_occupation.SetText(jobs[0]['l10n_occupation'])
1698 self.TTC_occupation_updated.SetValue(jobs[0]['modified_when'].strftime('%m/%Y'))
1699 return True
1700 #--------------------------------------------------------
1702 if self.PRW_occupation.IsModified():
1703 new_job = self.PRW_occupation.GetValue().strip()
1704 jobs = self.__ident.get_occupations()
1705 for job in jobs:
1706 if job['l10n_occupation'] == new_job:
1707 continue
1708 self.__ident.unlink_occupation(occupation = job['l10n_occupation'])
1709 self.__ident.link_occupation(occupation = new_job)
1710 return True
1711 #============================================================
1713 """Patient demographics plugin for main notebook.
1714
1715 Hosts another notebook with pages for Identity, Contacts, etc.
1716
1717 Acts on/listens to the currently active patient.
1718 """
1719 #--------------------------------------------------------
1721 wx.Panel.__init__ (self, parent = parent, id = id, style = wx.NO_BORDER)
1722 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
1723 self.__do_layout()
1724 self.__register_interests()
1725 #--------------------------------------------------------
1726 # public API
1727 #--------------------------------------------------------
1728 #--------------------------------------------------------
1729 # internal helpers
1730 #--------------------------------------------------------
1732 """Arrange widgets."""
1733 self.__patient_notebook = cPersonDemographicsEditorNb(self, -1)
1734
1735 szr_main = wx.BoxSizer(wx.VERTICAL)
1736 szr_main.Add(self.__patient_notebook, 1, wx.EXPAND)
1737 self.SetSizerAndFit(szr_main)
1738 #--------------------------------------------------------
1739 # event handling
1740 #--------------------------------------------------------
1742 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
1743 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
1744 #--------------------------------------------------------
1747 #--------------------------------------------------------
1750 # reget mixin API
1751 #--------------------------------------------------------
1761 #============================================================
1762 #============================================================
1763 if __name__ == "__main__":
1764
1765 #--------------------------------------------------------
1767 app = wx.PyWidgetTester(size = (600, 400))
1768 app.SetWidget(cKOrganizerSchedulePnl)
1769 app.MainLoop()
1770 #--------------------------------------------------------
1772 app = wx.PyWidgetTester(size = (600, 400))
1773 widget = cPersonNamesManagerPnl(app.frame, -1)
1774 widget.identity = activate_patient()
1775 app.frame.Show(True)
1776 app.MainLoop()
1777 #--------------------------------------------------------
1779 app = wx.PyWidgetTester(size = (600, 400))
1780 widget = cPersonIDsManagerPnl(app.frame, -1)
1781 widget.identity = activate_patient()
1782 app.frame.Show(True)
1783 app.MainLoop()
1784 #--------------------------------------------------------
1786 app = wx.PyWidgetTester(size = (600, 400))
1787 widget = cPersonIdentityManagerPnl(app.frame, -1)
1788 widget.identity = activate_patient()
1789 app.frame.Show(True)
1790 app.MainLoop()
1791 #--------------------------------------------------------
1793 app = wx.PyWidgetTester(size = (600, 400))
1794 app.SetWidget(cPersonNameEAPnl, name = activate_patient().get_active_name())
1795 app.MainLoop()
1796 #--------------------------------------------------------
1798 app = wx.PyWidgetTester(size = (600, 400))
1799 widget = cPersonDemographicsEditorNb(app.frame, -1)
1800 widget.identity = activate_patient()
1801 widget.refresh()
1802 app.frame.Show(True)
1803 app.MainLoop()
1804 #--------------------------------------------------------
1806 patient = gmPersonSearch.ask_for_patient()
1807 if patient is None:
1808 print "No patient. Exiting gracefully..."
1809 sys.exit(0)
1810 from Gnumed.wxpython import gmPatSearchWidgets
1811 gmPatSearchWidgets.set_active_patient(patient=patient)
1812 return patient
1813 #--------------------------------------------------------
1814 if len(sys.argv) > 1 and sys.argv[1] == 'test':
1815
1816 gmI18N.activate_locale()
1817 gmI18N.install_domain(domain='gnumed')
1818 gmPG2.get_connection()
1819
1820 # app = wx.PyWidgetTester(size = (400, 300))
1821 # app.SetWidget(cNotebookedPatEditionPanel, -1)
1822 # app.frame.Show(True)
1823 # app.MainLoop()
1824
1825 # phrasewheels
1826 # test_organizer_pnl()
1827
1828 # identity related widgets
1829 #test_person_names_pnl()
1830 test_person_ids_pnl()
1831 #test_pat_ids_pnl()
1832 #test_name_ea_pnl()
1833
1834 #test_cPersonDemographicsEditorNb()
1835
1836 #============================================================
1837
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Sat Oct 5 03:56:37 2013 | http://epydoc.sourceforge.net |