Package Gnumed :: Package wxpython :: Module gmProgressNotesEAWidgets
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gmProgressNotesEAWidgets

  1  # -*- coding: utf-8 -*- 
  2  """GNUmed expando based textual progress notes handling widgets.""" 
  3  #================================================================ 
  4  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>" 
  5  __license__ = "GPL v2 or later (details at http://www.gnu.org)" 
  6   
  7  import sys 
  8  import logging 
  9   
 10   
 11  import wx 
 12   
 13   
 14  if __name__ == '__main__': 
 15          sys.path.insert(0, '../../') 
 16   
 17  from Gnumed.pycommon import gmI18N 
 18   
 19  if __name__ == '__main__': 
 20          gmI18N.activate_locale() 
 21          gmI18N.install_domain() 
 22   
 23  from Gnumed.pycommon import gmDispatcher 
 24  from Gnumed.pycommon import gmDateTime 
 25  from Gnumed.pycommon import gmCfg 
 26   
 27  from Gnumed.business import gmPerson 
 28  from Gnumed.business import gmPraxis 
 29  from Gnumed.business import gmEMRStructItems 
 30  from Gnumed.business import gmClinNarrative 
 31   
 32  from Gnumed.wxpython import gmGuiHelpers 
 33  from Gnumed.wxpython import gmTextCtrl 
 34  from Gnumed.wxpython import gmVisualProgressNoteWidgets 
 35  from Gnumed.wxpython import gmEMRStructWidgets 
 36   
 37  _log = logging.getLogger('gm.ui') 
 38   
 39  #============================================================ 
 40  from Gnumed.wxGladeWidgets import wxgProgressNotesEAPnl 
 41   
42 -class cProgressNotesEAPnl(gmTextCtrl.cExpandoTextCtrlHandling_PanelMixin, wxgProgressNotesEAPnl.wxgProgressNotesEAPnl):
43 """An Edit Area like panel for entering progress notes. 44 45 ( 46 Subjective: Codes: 47 expando text ctrl 48 Objective: Codes: 49 expando text ctrl 50 Assessment: Codes: 51 expando text ctrl 52 Plan: Codes: 53 expando text ctrl 54 ) 55 OR 56 SOAP editor (StyledTextCtrl) 57 AND 58 visual progress notes (panel with images) 59 AND 60 Episode synopsis: Codes: 61 expando text ctrl 62 63 - knows the problem this edit area is about 64 - can deal with issue or episode type problems 65 """
66 - def __init__(self, *args, **kwargs):
67 68 try: 69 self.problem = kwargs['problem'] 70 del kwargs['problem'] 71 except KeyError: 72 self.problem = None 73 74 wxgProgressNotesEAPnl.wxgProgressNotesEAPnl.__init__(self, *args, **kwargs) 75 76 dbcfg = gmCfg.cCfgSQL() 77 self.__use_soap_fields = bool(dbcfg.get2 ( 78 option = 'horstspace.soap_editor.use_one_field_per_soap_category', 79 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, 80 bias = 'user', 81 default = True 82 )) 83 84 self.__soap_fields = [ 85 self._TCTRL_Soap, 86 self._TCTRL_sOap, 87 self._TCTRL_soAp, 88 self._TCTRL_soaP 89 ] 90 91 self.__init_ui() 92 self.__register_interests() 93 94 return
95 96 #--------------------------------------------------------
97 - def __init_ui(self):
98 if self.__use_soap_fields is False: 99 for field in self.__soap_fields: 100 field.Hide() 101 self._LBL_Soap.Hide() 102 self._PRW_Soap_codes.Hide() 103 self._LBL_sOap.Hide() 104 self._PRW_sOap_codes.Hide() 105 self._LBL_soAp.Hide() 106 self._PRW_soAp_codes.Hide() 107 self._LBL_soaP.Hide() 108 self._PRW_soaP_codes.Hide() 109 self._STC_soap.Show() 110 111 self.refresh_summary() 112 if self.problem is not None: 113 if self.problem['summary'] is None: 114 self._TCTRL_episode_summary.SetValue('') 115 self.refresh_visual_soap()
116 117 #--------------------------------------------------------
118 - def refresh(self):
119 self.refresh_summary() 120 self.refresh_visual_soap()
121 122 #--------------------------------------------------------
123 - def refresh_summary(self):
124 self._TCTRL_episode_summary.SetValue('') 125 self._PRW_episode_codes.SetText('', self._PRW_episode_codes.list2data_dict([])) 126 self._LBL_summary.SetLabel(_('Episode synopsis')) 127 128 # new problem ? 129 if self.problem is None: 130 return 131 132 # issue-level problem ? 133 if self.problem['type'] == 'issue': 134 return 135 136 # episode-level problem 137 caption = _('Synopsis (%s)') % ( 138 gmDateTime.pydt_strftime ( 139 self.problem['modified_when'], 140 format = '%B %Y', 141 accuracy = gmDateTime.acc_days 142 ) 143 ) 144 self._LBL_summary.SetLabel(caption) 145 146 if self.problem['summary'] is not None: 147 self._TCTRL_episode_summary.SetValue(self.problem['summary'].strip()) 148 149 val, data = self._PRW_episode_codes.generic_linked_codes2item_dict(self.problem.generic_codes) 150 self._PRW_episode_codes.SetText(val, data)
151 152 #--------------------------------------------------------
153 - def refresh_visual_soap(self):
154 if self.problem is None: 155 self._PNL_visual_soap.refresh(document_folder = None) 156 return 157 158 if self.problem['type'] == 'issue': 159 self._PNL_visual_soap.refresh(document_folder = None) 160 return 161 162 if self.problem['type'] == 'episode': 163 pat = gmPerson.gmCurrentPatient() 164 doc_folder = pat.get_document_folder() 165 emr = pat.emr 166 self._PNL_visual_soap.refresh ( 167 document_folder = doc_folder, 168 episodes = [self.problem['pk_episode']], 169 encounter = emr.active_encounter['pk_encounter'] 170 ) 171 return
172 173 #--------------------------------------------------------
174 - def clear(self):
175 self._TCTRL_episode_summary.SetValue('') 176 self._LBL_summary.SetLabel(_('Episode synopsis')) 177 self._PRW_episode_codes.SetText('', self._PRW_episode_codes.list2data_dict([])) 178 self._PNL_visual_soap.clear() 179 180 if self.__use_soap_fields: 181 for field in self.__soap_fields: 182 field.SetValue('') 183 else: 184 self._STC_soap.SetText_from_SOAP()
185 186 #--------------------------------------------------------
187 - def add_visual_progress_note(self):
188 fname, discard_unmodified = gmVisualProgressNoteWidgets.select_visual_progress_note_template(parent = self) 189 if fname is None: 190 return False 191 192 if self.problem is None: 193 issue = None 194 episode = None 195 elif self.problem['type'] == 'issue': 196 issue = self.problem['pk_health_issue'] 197 episode = None 198 else: 199 issue = self.problem['pk_health_issue'] 200 episode = gmEMRStructItems.problem2episode(self.problem) 201 202 wx.CallAfter ( 203 gmVisualProgressNoteWidgets.edit_visual_progress_note, 204 filename = fname, 205 episode = episode, 206 discard_unmodified = discard_unmodified, 207 health_issue = issue 208 )
209 210 #--------------------------------------------------------
211 - def save(self, emr=None, episode_name_candidates=None, encounter=None):
212 213 if self.empty: 214 return True 215 216 # new episode (standalone=unassociated or new-in-issue) 217 if (self.problem is None) or (self.problem['type'] == 'issue'): 218 episode = self.__create_new_episode(emr = emr, episode_name_candidates = episode_name_candidates) 219 # user cancelled 220 if episode is None: 221 return False 222 # existing episode 223 else: 224 episode = emr.problem2episode(self.problem) 225 226 if encounter is None: 227 encounter = emr.current_encounter['pk_encounter'] 228 229 # set summary but only if not already set above for a 230 # newly created episode (either standalone or within 231 # a health issue) 232 if self.problem is not None: 233 if self.problem['type'] == 'episode': 234 episode['summary'] = self._TCTRL_episode_summary.GetValue().strip() 235 episode.save() 236 237 # codes for episode 238 episode.generic_codes = [ d['data'] for d in self._PRW_episode_codes.GetData() ] 239 240 gmClinNarrative.create_progress_note ( 241 soap = self.soap, 242 episode_id = episode['pk_episode'], 243 encounter_id = encounter 244 ) 245 246 return True
247 248 #-------------------------------------------------------- 249 # internal helpers 250 #--------------------------------------------------------
251 - def __create_new_episode(self, emr=None, episode_name_candidates=None):
252 253 episode_name_candidates.append(self._TCTRL_episode_summary.GetValue().strip()) 254 for candidate in episode_name_candidates: 255 if candidate is None: 256 continue 257 epi_name = candidate.strip().replace('\r', '//').replace('\n', '//') 258 break 259 260 if self.problem is None: 261 msg = _( 262 'Enter a short working name for this new problem\n' 263 '(which will become a new, unassociated episode):\n' 264 ) 265 else: 266 issue = emr.problem2issue(self.problem) 267 msg = _( 268 'Enter a short working name for this new\n' 269 'episode under the existing health issue\n' 270 '\n' 271 '"%s":\n' 272 ) % issue['description'] 273 274 dlg = wx.TextEntryDialog ( 275 self, msg, 276 caption = _('Creating problem (episode) to save notelet under ...'), 277 value = epi_name, 278 style = wx.OK | wx.CANCEL | wx.CENTRE 279 ) 280 decision = dlg.ShowModal() 281 if decision != wx.ID_OK: 282 return None 283 284 epi_name = dlg.GetValue().strip() 285 if epi_name == '': 286 gmGuiHelpers.gm_show_error(_('Cannot save a new problem without a name.'), _('saving progress note')) 287 return None 288 289 # create episode 290 new_episode = emr.add_episode ( 291 episode_name = epi_name[:45], 292 pk_health_issue = None, 293 is_open = True, 294 allow_dupes = True # this ensures we get a new episode even if a same-name one already exists 295 ) 296 new_episode['summary'] = self._TCTRL_episode_summary.GetValue().strip() 297 new_episode.save() 298 299 if self.problem is not None: 300 issue = emr.problem2issue(self.problem) 301 if not gmEMRStructWidgets.move_episode_to_issue(episode = new_episode, target_issue = issue, save_to_backend = True): 302 gmGuiHelpers.gm_show_warning ( 303 _( 304 'The new episode:\n' 305 '\n' 306 ' "%s"\n' 307 '\n' 308 'will remain unassociated despite the editor\n' 309 'having been invoked from the health issue:\n' 310 '\n' 311 ' "%s"' 312 ) % ( 313 new_episode['description'], 314 issue['description'] 315 ), 316 _('saving progress note') 317 ) 318 319 return new_episode
320 321 #-------------------------------------------------------- 322 # event handling 323 #--------------------------------------------------------
324 - def __register_interests(self):
325 if self.__use_soap_fields: 326 for field in self.__soap_fields: 327 self.bind_expando_layout_event(field) 328 self.bind_expando_layout_event(self._TCTRL_episode_summary) 329 gmDispatcher.connect(signal = 'blobs.doc_obj_mod_db', receiver = self.refresh_visual_soap)
330 331 #-------------------------------------------------------- 332 # properties 333 #--------------------------------------------------------
334 - def _get_soap(self):
335 if not self.__use_soap_fields: 336 return self._STC_soap.soap 337 338 soap = {} 339 tmp = self._TCTRL_Soap.GetValue().strip() 340 if tmp != '': 341 soap['s'] = [tmp] 342 tmp = self._TCTRL_sOap.GetValue().strip() 343 if tmp != '': 344 soap['o'] = [tmp] 345 tmp = self._TCTRL_soAp.GetValue().strip() 346 if tmp != '': 347 soap['a'] = [tmp] 348 tmp = self._TCTRL_soaP.GetValue().strip() 349 if tmp != '': 350 soap['p'] = [tmp] 351 return soap
352 353 soap = property(_get_soap, lambda x:x) 354 #--------------------------------------------------------
355 - def _get_empty(self):
356 if self.__use_soap_fields: 357 for field in self.__soap_fields: 358 if field.GetValue().strip() != '': 359 return False 360 else: 361 if not self._STC_soap.empty: 362 return False 363 364 # summary 365 summary = self._TCTRL_episode_summary.GetValue().strip() 366 if self.problem is None: 367 if summary != '': 368 return False 369 elif self.problem['type'] == 'issue': 370 if summary != '': 371 return False 372 else: 373 if self.problem['summary'] is None: 374 if summary != '': 375 return False 376 else: 377 if summary != self.problem['summary'].strip(): 378 return False 379 380 # codes 381 new_codes = self._PRW_episode_codes.GetData() 382 if self.problem is None: 383 if len(new_codes) > 0: 384 return False 385 elif self.problem['type'] == 'issue': 386 if len(new_codes) > 0: 387 return False 388 else: 389 old_code_pks = self.problem.generic_codes 390 if len(old_code_pks) != len(new_codes): 391 return False 392 for code in new_codes: 393 if code['data'] not in old_code_pks: 394 return False 395 396 return True
397 398 empty = property(_get_empty, lambda x:x)
399 400 #============================================================ 401 # main 402 #--------------------------------------------------- 403 if __name__ == '__main__': 404 405 if len(sys.argv) < 2: 406 sys.exit() 407 408 if sys.argv[1] != 'test': 409 sys.exit() 410 411 #----------------------------------------
412 - def test_cProgressNotesEAPnl():
413 pat = gmPersonSearch.ask_for_patient() 414 application = wx.PyWidgetTester(size=(800,500)) 415 soap_input = cProgressNotesEAPnl(application.frame, -1) 416 application.frame.Show(True) 417 application.MainLoop()
418 #---------------------------------------- 419 420 test_cProgressNotesEAPnl() 421