# GNUmed #=========================================================== __author__ = "R.Terry , I.Haywood , K.Hilbert " __license__ = "GPL v2 or later" import sys import os.path import datetime as pyDT import logging import wx from Gnumed.pycommon import gmGuiBroker from Gnumed.pycommon import gmDispatcher from Gnumed.pycommon import gmTools from Gnumed.pycommon import gmCfg2 from Gnumed.pycommon import gmDateTime from Gnumed.pycommon import gmI18N from Gnumed.business import gmPerson from Gnumed.business import gmEMRStructItems from Gnumed.business import gmAllergy from Gnumed.wxpython import gmGuiHelpers from Gnumed.wxpython import gmDemographicsWidgets from Gnumed.wxpython import gmAllergyWidgets from Gnumed.wxpython import gmPatSearchWidgets from Gnumed.wxpython import gmEMRStructWidgets from Gnumed.wxpython import gmPatPicWidgets _log = logging.getLogger('gm.ui') #=========================================================== from Gnumed.wxGladeWidgets import wxgTopPnl class cTopPnl(wxgTopPnl.wxgTopPnl): def __init__(self, *args, **kwargs): wxgTopPnl.wxgTopPnl.__init__(self, *args, **kwargs) self.__gb = gmGuiBroker.GuiBroker() self.curr_pat = gmPerson.gmCurrentPatient() self.__init_ui() self.__register_interests() #------------------------------------------------------- def __init_ui(self): cfg = gmCfg2.gmCfgData() if cfg.get(option = 'slave'): self._TCTRL_patient_selector.SetEditable(0) self._TCTRL_patient_selector.SetToolTip(None) if sys.platform == u'darwin': _log.debug('adjusting font size on Mac for top panel parts') for ctrl in [self._TCTRL_patient_selector, self._LBL_age, self._LBL_allergies, self._TCTRL_allergies]: curr_font = ctrl.GetFont() mac_font = wx.FontFromNativeInfo(curr_font.NativeFontInfo) mac_font.SetPointSize(pointSize = int(curr_font.GetPointSize() / 0.8)) ctrl.SetFont(mac_font) #------------------------------------------------------- def __register_interests(self): # events wx.EVT_LEFT_DCLICK(self._TCTRL_allergies, self._on_allergies_dclicked) # client internal signals gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection) gmDispatcher.connect(signal = u'focus_patient_search', receiver = self._on_focus_patient_search) gmDispatcher.connect(signal = u'gm_table_mod', receiver = self._on_database_signal) #---------------------------------------------- # event handling #---------------------------------------------- def _on_allergies_dclicked(self, evt): if not self.curr_pat.connected: gmDispatcher.send('statustext', msg = _('Cannot activate Allergy Manager. No active patient.')) return dlg = gmAllergyWidgets.cAllergyManagerDlg(parent=self, id=-1) dlg.ShowModal() return #---------------------------------------------- def _on_database_signal(self, **kwds): if kwds['table'] not in [u'dem.identity', u'dem.names', u'dem.identity_tag', u'clin.allergy', u'clin.allergy_state']: return True if self.curr_pat.connected: # signal is not about our patient: ignore signal if int(kwds['pk_identity']) != self.curr_pat.ID: return True if kwds['table'] == u'dem.identity': # we don't care about newly INSERTed or DELETEd patients if kwds['operation'] != 'UPDATE': return True self.__update_age_label() return True if kwds['table'] == u'dem.names': self.__update_age_label() return True if kwds['table'] == u'dem.identity_tag': self.__update_tags() return True if kwds['table'] == u'clin.allergy': self.__update_allergies() return True if kwds['table'] == u'clin.allergy_state': self.__update_allergies() return True return True #---------------------------------------------- def _on_post_patient_selection(self, **kwargs): self.__update_age_label() self.__update_allergies() self.__update_tags() #------------------------------------------------------- def _on_focus_patient_search(self, **kwargs): wx.CallAfter(self._TCTRL_patient_selector.SetFocus) #------------------------------------------------------- # internal API #------------------------------------------------------- def __update_tags(self): self._PNL_tags.refresh(patient = self.curr_pat) #------------------------------------------------------- def __update_age_label(self): # no patient if not self.curr_pat.connected: self._LBL_age.SetLabel(_('')) self._LBL_age.SetToolTipString(_('no patient selected')) return # gender is always known tt = _(u'Gender: %s (%s) - %s\n') % ( self.curr_pat.gender_symbol, gmTools.coalesce(self.curr_pat[u'gender'], u'?'), self.curr_pat.gender_string ) # dob is not known if self.curr_pat['dob'] is None: age = u'%s %s' % ( self.curr_pat.gender_symbol, self.curr_pat.get_formatted_dob() ) self._LBL_age.SetLabel(age) self._LBL_age.SetToolTipString(tt) return tt += _('Born: %s\n') % self.curr_pat.get_formatted_dob(format = '%d %b %Y', encoding = gmI18N.get_encoding()) # patient is dead if self.curr_pat['deceased'] is not None: tt += _('Died: %s\n') % gmDateTime.pydt_strftime(self.curr_pat['deceased'], '%d %b %Y') tt += _('At age: %s\n') % self.curr_pat['medical_age'] age = u'%s %s - %s (%s)' % ( self.curr_pat.gender_symbol, self.curr_pat.get_formatted_dob(format = '%d %b %Y', encoding = gmI18N.get_encoding()), gmDateTime.pydt_strftime(self.curr_pat['deceased'], '%d %b %Y'), self.curr_pat['medical_age'] ) if self.curr_pat['dob_is_estimated']: tt += _(' (date of birth and age are estimated)\n') self._LBL_age.SetLabel(age) self._LBL_age.SetToolTipString(tt) return # patient alive now = gmDateTime.pydt_now_here() # patient birthday ? if self.curr_pat.get_formatted_dob(format = '%m-%d') == now.strftime('%m-%d'): template = _('%(sex)s %(dob)s (%(age)s today !)') tt += _("\nToday is the patient's birthday !\n\n") else: if self.curr_pat.current_birthday_passed(): template = u'%(sex)s %(dob)s%(l_arr)s (%(age)s)' tt += _(u'Birthday: %s ago\n') % gmDateTime.format_apparent_age_medically ( age = gmDateTime.calculate_apparent_age(start = self.curr_pat.birthday_this_year, end = now) ) else: template = u'%(sex)s %(r_arr)s%(dob)s (%(age)s)' tt += _(u'Birthday: in %s\n') % gmDateTime.format_apparent_age_medically ( age = gmDateTime.calculate_apparent_age(start = now, end = self.curr_pat.birthday_this_year) ) tt += _('Age: %s\n') % self.curr_pat['medical_age'] # FIXME: if the age is below, say, 2 hours we should fire # a timer here that updates the age in increments of 1 minute ... :-) age = template % { u'sex': self.curr_pat.gender_symbol, u'dob': self.curr_pat.get_formatted_dob(format = '%d %b %Y', encoding = gmI18N.get_encoding()), u'age': self.curr_pat['medical_age'], u'r_arr': gmTools.u_right_arrow, u'l_arr': gmTools.u_left_arrow } # Easter Egg ;-) if self.curr_pat['lastnames'] == u'Leibner': if self.curr_pat['firstnames'] == u'Steffi': if self.curr_pat['preferred'] == u'Wildfang': age = u'%s %s' % (gmTools.u_black_heart, age) if self.curr_pat['dob_is_estimated']: tt += _(' (date of birth and age are estimated)\n') self._LBL_age.SetLabel(age) self._LBL_age.SetToolTipString(tt) #------------------------------------------------------- def __update_allergies(self, **kwargs): if not self.curr_pat.connected: self._LBL_allergies.SetForegroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT)) self._TCTRL_allergies.SetForegroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT)) self._TCTRL_allergies.SetValue(u'') self._TCTRL_allergies.SetToolTipString(u'') return show_red = True emr = self.curr_pat.get_emr() state = emr.allergy_state # state in tooltip if state['last_confirmed'] is None: confirmed = _('never') else: confirmed = gmDateTime.pydt_strftime(state['last_confirmed'], '%Y %b %d') tt = (state.state_string + (90 * u' '))[:90] + u'\n' tt += _('last confirmed %s\n') % confirmed tt += gmTools.coalesce(state['comment'], u'', _('Comment (%s): %%s') % state['modified_by']) tt += u'\n' # allergies display = [] for allergy in emr.get_allergies(): # in field: "true" allergies only, not intolerances if allergy['type'] == u'allergy': display.append(allergy['descriptor'][:10].strip() + gmTools.u_ellipsis) # in tooltip if allergy['definite']: certainty = _('definite') else: certainty = _('suspected') reaction = gmTools.coalesce(allergy['reaction'], _('reaction not recorded')) if len(reaction) > 50: reaction = reaction[:50] + gmTools.u_ellipsis tt += u'%s (%s, %s): %s\n' % ( allergy['descriptor'], allergy['l10n_type'], certainty, reaction ) if len(display) == 0: display = state.state_symbol if display == gmTools.u_diameter: show_red = False else: display = ','.join(display) if state['last_confirmed'] is not None: display += gmDateTime.pydt_strftime(state['last_confirmed'], ' (%Y %b)') if show_red: self._LBL_allergies.SetForegroundColour('red') self._TCTRL_allergies.SetForegroundColour('red') else: self._LBL_allergies.SetForegroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT)) self._TCTRL_allergies.SetForegroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT)) self._TCTRL_allergies.SetValue(display) self._TCTRL_allergies.SetToolTipString(tt) #=========================================================== if __name__ == "__main__": app = wxPyWidgetTester(size = (400, 200)) app.SetWidget(cMainTopPanel, -1) app.SetWidget(cTopPanel, -1) app.MainLoop() #===========================================================