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 parent = self, 276 message = msg, 277 caption = _('Creating problem (episode) to save notelet under ...'), 278 defaultValue = epi_name, 279 style = wx.OK | wx.CANCEL | wx.CENTRE 280 ) 281 decision = dlg.ShowModal() 282 if decision != wx.ID_OK: 283 return None 284 285 epi_name = dlg.GetValue().strip() 286 if epi_name == '': 287 gmGuiHelpers.gm_show_error(_('Cannot save a new problem without a name.'), _('saving progress note')) 288 return None 289 290 # create episode 291 new_episode = emr.add_episode ( 292 episode_name = epi_name[:45], 293 pk_health_issue = None, 294 is_open = True, 295 allow_dupes = True # this ensures we get a new episode even if a same-name one already exists 296 ) 297 new_episode['summary'] = self._TCTRL_episode_summary.GetValue().strip() 298 new_episode.save() 299 300 if self.problem is not None: 301 issue = emr.problem2issue(self.problem) 302 if not gmEMRStructWidgets.move_episode_to_issue(episode = new_episode, target_issue = issue, save_to_backend = True): 303 gmGuiHelpers.gm_show_warning ( 304 _( 305 'The new episode:\n' 306 '\n' 307 ' "%s"\n' 308 '\n' 309 'will remain unassociated despite the editor\n' 310 'having been invoked from the health issue:\n' 311 '\n' 312 ' "%s"' 313 ) % ( 314 new_episode['description'], 315 issue['description'] 316 ), 317 _('saving progress note') 318 ) 319 320 return new_episode
321 322 #-------------------------------------------------------- 323 # event handling 324 #--------------------------------------------------------
325 - def __register_interests(self):
326 if self.__use_soap_fields: 327 for field in self.__soap_fields: 328 self.bind_expando_layout_event(field) 329 self.bind_expando_layout_event(self._TCTRL_episode_summary) 330 gmDispatcher.connect(signal = 'blobs.doc_obj_mod_db', receiver = self.refresh_visual_soap)
331 332 #-------------------------------------------------------- 333 # properties 334 #--------------------------------------------------------
335 - def _get_soap(self):
336 if not self.__use_soap_fields: 337 return self._STC_soap.soap 338 339 soap = {} 340 tmp = self._TCTRL_Soap.GetValue().strip() 341 if tmp != '': 342 soap['s'] = [tmp] 343 tmp = self._TCTRL_sOap.GetValue().strip() 344 if tmp != '': 345 soap['o'] = [tmp] 346 tmp = self._TCTRL_soAp.GetValue().strip() 347 if tmp != '': 348 soap['a'] = [tmp] 349 tmp = self._TCTRL_soaP.GetValue().strip() 350 if tmp != '': 351 soap['p'] = [tmp] 352 return soap
353 354 soap = property(_get_soap, lambda x:x) 355 #--------------------------------------------------------
356 - def _get_empty(self):
357 if self.__use_soap_fields: 358 for field in self.__soap_fields: 359 if field.GetValue().strip() != '': 360 return False 361 else: 362 if not self._STC_soap.empty: 363 return False 364 365 # summary 366 summary = self._TCTRL_episode_summary.GetValue().strip() 367 if self.problem is None: 368 if summary != '': 369 return False 370 elif self.problem['type'] == 'issue': 371 if summary != '': 372 return False 373 else: 374 if self.problem['summary'] is None: 375 if summary != '': 376 return False 377 else: 378 if summary != self.problem['summary'].strip(): 379 return False 380 381 # codes 382 new_codes = self._PRW_episode_codes.GetData() 383 if self.problem is None: 384 if len(new_codes) > 0: 385 return False 386 elif self.problem['type'] == 'issue': 387 if len(new_codes) > 0: 388 return False 389 else: 390 old_code_pks = self.problem.generic_codes 391 if len(old_code_pks) != len(new_codes): 392 return False 393 for code in new_codes: 394 if code['data'] not in old_code_pks: 395 return False 396 397 return True
398 399 empty = property(_get_empty, lambda x:x)
400 401 #============================================================ 402 # main 403 #--------------------------------------------------- 404 if __name__ == '__main__': 405 406 if len(sys.argv) < 2: 407 sys.exit() 408 409 if sys.argv[1] != 'test': 410 sys.exit() 411 412 #----------------------------------------
413 - def test_cProgressNotesEAPnl():
414 pat = gmPersonSearch.ask_for_patient() 415 application = wx.PyWidgetTester(size=(800,500)) 416 soap_input = cProgressNotesEAPnl(application.frame, -1) 417 application.frame.Show(True) 418 application.MainLoop()
419 #---------------------------------------- 420 421 test_cProgressNotesEAPnl() 422