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