| Home | Trees | Indices | Help |
|
|---|
|
|
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 """
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 #--------------------------------------------------------
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 #--------------------------------------------------------
121
122 #--------------------------------------------------------
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 #--------------------------------------------------------
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 #--------------------------------------------------------
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 #--------------------------------------------------------
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 #--------------------------------------------------------
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 #--------------------------------------------------------
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 #--------------------------------------------------------
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 #--------------------------------------------------------
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 #--------------------------------------------------------
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 #----------------------------------------
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
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Fri Jan 25 02:55:27 2019 | http://epydoc.sourceforge.net |