| Home | Trees | Indices | Help |
|
|---|
|
|
1 """GNUmed medication/substances handling widgets.
2 """
3 #================================================================
4 __version__ = "$Revision: 1.33 $"
5 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
6
7 import logging, sys, os.path, webbrowser
8
9
10 import wx, wx.grid
11
12
13 if __name__ == '__main__':
14 sys.path.insert(0, '../../')
15 from Gnumed.pycommon import gmDispatcher, gmCfg, gmShellAPI, gmTools, gmDateTime
16 from Gnumed.pycommon import gmMatchProvider, gmI18N, gmPrinting, gmCfg2
17 from Gnumed.business import gmPerson, gmATC, gmSurgery, gmMedication, gmForms
18 from Gnumed.wxpython import gmGuiHelpers, gmRegetMixin, gmAuthWidgets, gmEditArea, gmMacro
19 from Gnumed.wxpython import gmCfgWidgets, gmListWidgets, gmPhraseWheel, gmFormWidgets
20 from Gnumed.wxpython import gmAllergyWidgets
21
22
23 _log = logging.getLogger('gm.ui')
24 _log.info(__version__)
25 #============================================================
27
28 if parent is None:
29 parent = wx.GetApp().GetTopWindow()
30 #------------------------------------------------------------
31 def refresh(lctrl):
32 atcs = gmATC.get_reference_atcs()
33
34 items = [ [
35 a['atc'],
36 a['term'],
37 u'%s' % gmTools.coalesce(a['ddd'], u''),
38 gmTools.coalesce(a['unit'], u''),
39 gmTools.coalesce(a['administrative_route'], u''),
40 gmTools.coalesce(a['comment'], u''),
41 a['version'],
42 a['lang']
43 ] for a in atcs ]
44 lctrl.set_string_items(items)
45 lctrl.set_data(atcs)
46 #------------------------------------------------------------
47 gmListWidgets.get_choices_from_list (
48 parent = parent,
49 msg = _('\nThe ATC codes as known to GNUmed.\n'),
50 caption = _('Showing ATC codes.'),
51 columns = [ u'ATC', _('Term'), u'DDD', _('Unit'), _(u'Route'), _('Comment'), _('Version'), _('Language') ],
52 single_selection = True,
53 refresh_callback = refresh
54 )
55
56 #============================================================
58
59 if parent is None:
60 parent = wx.GetApp().GetTopWindow()
61
62 #------------------------------------------------------------
63 def delete(component):
64 gmMedication.delete_component_from_branded_drug (
65 brand = component['pk_brand'],
66 component = component['pk_substance_in_brand']
67 )
68 return True
69 #------------------------------------------------------------
70 def refresh(lctrl):
71 substs = gmMedication.get_substances_in_brands()
72 items = [ [
73 u'%s%s' % (s['brand'], gmTools.coalesce(s['atc_brand'], u'', u' (%s)')),
74 s['substance'],
75 gmTools.coalesce(s['atc_substance'], u''),
76 s['preparation'],
77 gmTools.coalesce(s['external_code_brand'], u'', u'%%s [%s]' % s['external_code_type_brand']),
78 s['pk_substance_in_brand']
79 ] for s in substs ]
80 lctrl.set_string_items(items)
81 lctrl.set_data(substs)
82 #------------------------------------------------------------
83 msg = _('\nThese are the substances in the drug brands known to GNUmed.\n')
84
85 gmListWidgets.get_choices_from_list (
86 parent = parent,
87 msg = msg,
88 caption = _('Showing drug brand components (substances).'),
89 columns = [_('Brand'), _('Substance'), u'ATC', _('Preparation'), _('Code'), u'#'],
90 single_selection = True,
91 #new_callback = new,
92 #edit_callback = edit,
93 delete_callback = delete,
94 refresh_callback = refresh
95 )
96 #============================================================
98
99 if parent is None:
100 parent = wx.GetApp().GetTopWindow()
101 #------------------------------------------------------------
102 def delete(brand):
103 gmMedication.delete_branded_drug(brand = brand['pk'])
104 return True
105 #------------------------------------------------------------
106 def new():
107 drug_db = get_drug_database(parent = parent)
108
109 if drug_db is None:
110 return False
111
112 drug_db.import_drugs()
113
114 return True
115 #------------------------------------------------------------
116 def refresh(lctrl):
117 drugs = gmMedication.get_branded_drugs()
118 items = [ [
119 d['description'],
120 d['preparation'],
121 gmTools.coalesce(d['atc_code'], u''),
122 gmTools.coalesce(d['external_code'], u'', u'%%s [%s]' % d['external_code_type']),
123 d['pk']
124 ] for d in drugs ]
125 lctrl.set_string_items(items)
126 lctrl.set_data(drugs)
127 #------------------------------------------------------------
128 msg = _('\nThese are the drug brands known to GNUmed.\n')
129
130 gmListWidgets.get_choices_from_list (
131 parent = parent,
132 msg = msg,
133 caption = _('Showing branded drugs.'),
134 columns = [_('Name'), _('Preparation'), _('ATC'), _('Code'), u'#'],
135 single_selection = True,
136 refresh_callback = refresh,
137 new_callback = new,
138 #edit_callback = edit,
139 delete_callback = delete
140 )
141 #============================================================
143
144 if parent is None:
145 parent = wx.GetApp().GetTopWindow()
146 #------------------------------------------------------------
147 def delete(substance):
148 gmMedication.delete_used_substance(substance = substance['pk'])
149 return True
150 #------------------------------------------------------------
151 def new():
152 drug_db = get_drug_database(parent = parent)
153
154 if drug_db is None:
155 return False
156
157 drug_db.import_drugs()
158
159 return True
160 #------------------------------------------------------------
161 def refresh(lctrl):
162 substs = gmMedication.get_substances_in_use()
163 items = [ [
164 s['description'],
165 gmTools.coalesce(s['atc_code'], u''),
166 s['pk']
167 ] for s in substs ]
168 lctrl.set_string_items(items)
169 lctrl.set_data(substs)
170 #------------------------------------------------------------
171 msg = _('\nThese are the substances currently or previously\nconsumed across all patients.\n')
172
173 gmListWidgets.get_choices_from_list (
174 parent = parent,
175 msg = msg,
176 caption = _('Showing consumed substances.'),
177 columns = [_('Name'), _('ATC'), u'#'],
178 single_selection = True,
179 refresh_callback = refresh,
180 new_callback = new,
181 #edit_callback = edit,
182 delete_callback = delete
183 )
184 #============================================================
185 # generic drug database access
186 #============================================================
188 gmCfgWidgets.configure_string_from_list_option (
189 parent = parent,
190 message = _(
191 '\n'
192 'Please select the default drug data source from the list below.\n'
193 '\n'
194 'Note that to actually use it you need to have the database installed, too.'
195 ),
196 option = 'external.drug_data.default_source',
197 bias = 'user',
198 default_value = None,
199 choices = gmMedication.drug_data_source_interfaces.keys(),
200 columns = [_('Drug data source')],
201 data = gmMedication.drug_data_source_interfaces.keys(),
202 caption = _('Configuring default drug data source')
203 )
204 #============================================================
206 dbcfg = gmCfg.cCfgSQL()
207
208 default_db = dbcfg.get2 (
209 option = 'external.drug_data.default_source',
210 workplace = gmSurgery.gmCurrentPractice().active_workplace,
211 bias = 'workplace'
212 )
213
214 if default_db is None:
215 gmDispatcher.send('statustext', msg = _('No default drug database configured.'), beep = True)
216 configure_drug_data_source(parent = parent)
217 default_db = dbcfg.get2 (
218 option = 'external.drug_data.default_source',
219 workplace = gmSurgery.gmCurrentPractice().active_workplace,
220 bias = 'workplace'
221 )
222 if default_db is None:
223 gmGuiHelpers.gm_show_error (
224 aMessage = _('There is no default drug database configured.'),
225 aTitle = _('Jumping to drug database')
226 )
227 return None
228
229 try:
230 return gmMedication.drug_data_source_interfaces[default_db]()
231 except KeyError:
232 _log.error('faulty default drug data source configuration: %s', default_db)
233 return None
234 #============================================================
236 dbcfg = gmCfg.cCfgSQL()
237 drug_db = get_drug_database()
238 if drug_db is None:
239 return
240 pat = gmPerson.gmCurrentPatient()
241 if pat.connected:
242 drug_db.patient = pat
243 drug_db.switch_to_frontend(blocking = False)
244 #============================================================
246
247 dbcfg = gmCfg.cCfgSQL()
248
249 ifap_cmd = dbcfg.get2 (
250 option = 'external.ifap-win.shell_command',
251 workplace = gmSurgery.gmCurrentPractice().active_workplace,
252 bias = 'workplace',
253 default = 'wine "C:\Ifapwin\WIAMDB.EXE"'
254 )
255 found, binary = gmShellAPI.detect_external_binary(ifap_cmd)
256 if not found:
257 gmDispatcher.send('statustext', msg = _('Cannot call IFAP via [%s].') % ifap_cmd)
258 return False
259 ifap_cmd = binary
260
261 if import_drugs:
262 transfer_file = os.path.expanduser(dbcfg.get2 (
263 option = 'external.ifap-win.transfer_file',
264 workplace = gmSurgery.gmCurrentPractice().active_workplace,
265 bias = 'workplace',
266 default = '~/.wine/drive_c/Ifapwin/ifap2gnumed.csv'
267 ))
268 # file must exist for Ifap to write into it
269 try:
270 f = open(transfer_file, 'w+b').close()
271 except IOError:
272 _log.exception('Cannot create IFAP <-> GNUmed transfer file [%s]', transfer_file)
273 gmDispatcher.send('statustext', msg = _('Cannot create IFAP <-> GNUmed transfer file [%s].') % transfer_file)
274 return False
275
276 wx.BeginBusyCursor()
277 gmShellAPI.run_command_in_shell(command = ifap_cmd, blocking = import_drugs)
278 wx.EndBusyCursor()
279
280 if import_drugs:
281 # COMMENT: this file must exist PRIOR to invoking IFAP
282 # COMMENT: or else IFAP will not write data into it ...
283 try:
284 csv_file = open(transfer_file, 'rb') # FIXME: encoding
285 except:
286 _log.exception('cannot access [%s]', fname)
287 csv_file = None
288
289 if csv_file is not None:
290 import csv
291 csv_lines = csv.DictReader (
292 csv_file,
293 fieldnames = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split(),
294 delimiter = ';'
295 )
296 pat = gmPerson.gmCurrentPatient()
297 emr = pat.get_emr()
298 # dummy episode for now
299 epi = emr.add_episode(episode_name = _('Current medication'))
300 for line in csv_lines:
301 narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % (
302 line['Packungszahl'].strip(),
303 line['Handelsname'].strip(),
304 line['Form'].strip(),
305 line[u'Packungsgr\xf6\xdfe'].strip(),
306 line['Abpackungsmenge'].strip(),
307 line['Einheit'].strip(),
308 line['Hersteller'].strip(),
309 line['PZN'].strip()
310 )
311 emr.add_clin_narrative(note = narr, soap_cat = 's', episode = epi)
312 csv_file.close()
313
314 return True
315 #============================================================
317
318 dlg = wx.FileDialog (
319 parent = None,
320 message = _('Choose an ATC import config file'),
321 defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')),
322 defaultFile = '',
323 wildcard = "%s (*.conf)|*.conf|%s (*)|*" % (_('config files'), _('all files')),
324 style = wx.OPEN | wx.HIDE_READONLY | wx.FILE_MUST_EXIST
325 )
326
327 result = dlg.ShowModal()
328 if result == wx.ID_CANCEL:
329 return
330
331 cfg_file = dlg.GetPath()
332 dlg.Destroy()
333
334 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('importing ATC reference data'))
335 if conn is None:
336 return False
337
338 wx.BeginBusyCursor()
339
340 if gmATC.atc_import(cfg_fname = cfg_file, conn = conn):
341 gmDispatcher.send(signal = 'statustext', msg = _('Successfully imported ATC reference data.'))
342 else:
343 gmDispatcher.send(signal = 'statustext', msg = _('Importing ATC reference data failed.'), beep = True)
344
345 wx.EndBusyCursor()
346 return True
347
348 #============================================================
349 # current substance intake handling
350 #============================================================
352
354
355 query = u"""
356 SELECT schedule as sched, schedule
357 FROM clin.substance_intake
358 where schedule %(fragment_condition)s
359 ORDER BY sched
360 LIMIT 50"""
361
362 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
363 mp.setThresholds(1, 2, 4)
364 mp.word_separators = '[ \t=+&:@]+'
365 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
366 self.SetToolTipString(_('The schedule for taking this substance.'))
367 self.matcher = mp
368 self.selection_only = False
369 #============================================================
371
373
374 query = u"""
375 (
376 SELECT preparation as prep, preparation
377 FROM ref.branded_drug
378 where preparation %(fragment_condition)s
379 ) union (
380 SELECT preparation as prep, preparation
381 FROM clin.substance_intake
382 where preparation %(fragment_condition)s
383 )
384 order by prep
385 limit 30"""
386
387 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
388 mp.setThresholds(1, 2, 4)
389 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
390 self.SetToolTipString(_('The preparation (form) of the substance the patient is taking.'))
391 self.matcher = mp
392 self.selection_only = False
393 #============================================================
395
397
398 query = u"""
399 (
400 SELECT pk, (coalesce(atc_code || ': ', '') || description) as subst
401 FROM clin.consumed_substance
402 WHERE description %(fragment_condition)s
403 ) union (
404 SELECT NULL, (coalesce(atc_code || ': ', '') || description) as subst
405 FROM ref.substance_in_brand
406 WHERE description %(fragment_condition)s
407 ) union (
408 SELECT NULL, (atc || ': ' || term) as subst
409 FROM ref.v_atc
410 WHERE
411 is_group_code IS FALSE
412 AND
413 term %(fragment_condition)s
414 )
415 order by subst
416 limit 50"""
417
418 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
419 mp.setThresholds(1, 2, 4)
420 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
421 self.SetToolTipString(_('The INN / substance the patient is taking.'))
422 self.matcher = mp
423 self.selection_only = False
424 #============================================================
426
428
429 query = u"""
430 SELECT pk, (coalesce(atc_code || ': ', '') || description || ' (' || preparation || ')') as brand
431 FROM ref.branded_drug
432 WHERE description %(fragment_condition)s
433 ORDER BY brand
434 LIMIT 50"""
435
436 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
437 mp.setThresholds(2, 3, 4)
438 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
439 self.SetToolTipString(_('The brand name of the drug the patient is taking.'))
440 self.matcher = mp
441 self.selection_only = False
442
443 #============================================================
444 from Gnumed.wxGladeWidgets import wxgCurrentMedicationEAPnl
445
446 -class cCurrentMedicationEAPnl(wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl, gmEditArea.cGenericEditAreaMixin):
447
449
450 try:
451 data = kwargs['substance']
452 del kwargs['substance']
453 except KeyError:
454 data = None
455
456 wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl.__init__(self, *args, **kwargs)
457 gmEditArea.cGenericEditAreaMixin.__init__(self)
458 self.mode = 'new'
459 self.data = data
460 if data is not None:
461 self.mode = 'edit'
462
463 self.__init_ui()
464 #----------------------------------------------------------------
466
467 # adjust phrasewheels
468
469 self._PRW_brand.add_callback_on_lose_focus(callback = self._on_leave_brand)
470 #----------------------------------------------------------------
472 emr = gmPerson.gmCurrentPatient().get_emr()
473
474 state = emr.allergy_state
475 if state['last_confirmed'] is None:
476 confirmed = _('never')
477 else:
478 confirmed = state['last_confirmed'].strftime('%Y %B %d').decode(gmI18N.get_encoding())
479 msg = _(u'%s, last confirmed %s\n') % (state.state_string, confirmed)
480 msg += gmTools.coalesce(state['comment'], u'', _('Comment (%s): %%s\n') % state['modified_by'])
481 msg += u'\n'
482
483 for allergy in emr.get_allergies():
484 msg += u'%s (%s, %s): %s\n' % (
485 allergy['descriptor'],
486 allergy['l10n_type'],
487 gmTools.bool2subst(allergy['definite'], _('definite'), _('suspected'), u'?'),
488 gmTools.coalesce(allergy['reaction'], _('reaction not recorded'))
489 )
490
491 self._LBL_allergies.SetLabel(msg)
492 #----------------------------------------------------------------
494
495 if self._PRW_brand.GetData() is None:
496 self._TCTRL_brand_ingredients.SetValue(u'')
497 if self.data is None:
498 return
499 if self.data['pk_brand'] is None:
500 return
501 self._PRW_brand.SetText(self.data['brand'], self.data['pk_brand'])
502
503 brand = gmMedication.cBrandedDrug(aPK_obj = self._PRW_brand.GetData())
504
505 if self.data is None:
506 self._PRW_preparation.SetText(brand['preparation'], None)
507 else:
508 self._PRW_preparation.SetText (
509 gmTools.coalesce(self.data['preparation'], brand['preparation']),
510 self.data['preparation']
511 )
512
513 comps = brand.components
514
515 if comps is None:
516 return
517
518 if len(comps) == 0:
519 return
520
521 comps = u' / '.join([ u'%s%s' % (c['description'], gmTools.coalesce(c['atc_code'], u'', u' (%s)')) for c in comps ])
522 self._TCTRL_brand_ingredients.SetValue(comps)
523 #----------------------------------------------------------------
524 # generic Edit Area mixin API
525 #----------------------------------------------------------------
527
528 validity = True
529
530 if self._PRW_substance.GetValue().strip() == u'':
531 self._PRW_substance.display_as_valid(False)
532 validity = False
533 else:
534 self._PRW_substance.display_as_valid(True)
535
536 if self._PRW_preparation.GetValue().strip() == u'':
537 self._PRW_preparation.display_as_valid(False)
538 validity = False
539 else:
540 self._PRW_preparation.display_as_valid(True)
541
542 if self._CHBOX_approved.IsChecked():
543 if self._PRW_episode.GetValue().strip() == u'':
544 self._PRW_episode.display_as_valid(False)
545 validity = False
546 else:
547 self._PRW_episode.display_as_valid(True)
548
549 if self._CHBOX_approved.IsChecked() is True:
550 self._PRW_duration.display_as_valid(True)
551 else:
552 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
553 self._PRW_duration.display_as_valid(True)
554 else:
555 if gmDateTime.str2interval(self._PRW_duration.GetValue()) is None:
556 self._PRW_duration.display_as_valid(False)
557 validity = False
558 else:
559 self._PRW_duration.display_as_valid(True)
560
561 end = self._DP_discontinued.GetValue(as_pydt = True)
562 if end is not None:
563 start = self._DP_started.GetValue(as_pydt = True)
564 if start > end:
565 self._DP_started.display_as_valid(False)
566 self._DP_discontinued.display_as_valid(False)
567 validity = False
568 else:
569 self._DP_started.display_as_valid(True)
570 self._DP_discontinued.display_as_valid(True)
571
572 if validity is False:
573 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save substance intake. Invalid or missing essential input.'))
574
575 return validity
576 #----------------------------------------------------------------
578
579 emr = gmPerson.gmCurrentPatient().get_emr()
580
581 # 1) create substance intake entry
582 if self._PRW_substance.GetData() is None:
583 subst = self._PRW_substance.GetValue().strip()
584 else:
585 # normalize, do not simply re-use name from phrasewheel
586 subst = gmMedication.get_substance_by_pk(pk = self._PRW_substance.GetData())['description']
587
588 intake = emr.add_substance_intake (
589 substance = subst,
590 episode = self._PRW_episode.GetData(can_create = True),
591 preparation = self._PRW_preparation.GetValue()
592 )
593
594 intake['strength'] = self._PRW_strength.GetValue()
595 intake['started'] = self._DP_started.GetValue(as_pydt = True)
596 intake['discontinued'] = self._DP_discontinued.GetValue(as_pydt = True)
597 if intake['discontinued'] is None:
598 intake['discontinue_reason'] = None
599 else:
600 intake['discontinue_reason'] = self._PRW_discontinue_reason().GetValue().strip()
601 intake['schedule'] = self._PRW_schedule.GetValue()
602 intake['aim'] = self._PRW_aim.GetValue()
603 intake['notes'] = self._PRW_notes.GetValue()
604 intake['is_long_term'] = self._CHBOX_long_term.IsChecked()
605 intake['intake_is_approved_of'] = self._CHBOX_approved.IsChecked()
606
607 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
608 intake['duration'] = None
609 else:
610 intake['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue())
611
612 # 2) create or retrieve brand
613 brand = None
614 pk_brand = self._PRW_brand.GetData()
615
616 # brand pre-selected ?
617 if pk_brand is None:
618 # no, so ...
619 desc = self._PRW_brand.GetValue().strip()
620 if desc != u'':
621 # ... create or get it
622 brand = gmMedication.create_branded_drug (
623 brand_name = desc,
624 preparation = self._PRW_preparation.GetValue().strip(),
625 return_existing = True
626 )
627 pk_brand = brand['pk']
628 else:
629 # yes, so get it
630 brand = gmMedication.cBrandedDrug(aPK_obj = pk_brand)
631
632 # 3) link brand, if available
633 intake['pk_brand'] = pk_brand
634 intake.save()
635
636 # brand neither creatable nor pre-selected
637 if brand is None:
638 self.data = intake
639 return True
640
641 # 4) add substance to brand as component (because
642 # that's effectively what we are saying here)
643 # FIXME: we may want to ask the user here
644 # FIXME: or only do it if there are no components yet
645 if self._PRW_substance.GetData() is None:
646 brand.add_component(substance = self._PRW_substance.GetValue().strip())
647 else:
648 # normalize substance name
649 subst = gmMedication.get_substance_by_pk(pk = self._PRW_substance.GetData())
650 if subst is not None:
651 brand.add_component(substance = subst['description'])
652
653 self.data = intake
654
655 if self._CHBOX_is_allergy.IsChecked():
656 allg = self.data.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
657 # open for editing
658 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = self, id = -1)
659 dlg.ShowModal()
660
661 return True
662 #----------------------------------------------------------------
664
665 if self._PRW_substance.GetData() is None:
666 self.data['pk_substance'] = gmMedication.create_used_substance (
667 substance = self._PRW_substance.GetValue().strip()
668 )['pk']
669 else:
670 self.data['pk_substance'] = self._PRW_substance.GetData()
671
672 self.data['started'] = self._DP_started.GetValue(as_pydt=True)
673 self.data['discontinued'] = self._DP_discontinued.GetValue(as_pydt=True)
674 if self.data['discontinued'] is None:
675 self.data['discontinue_reason'] = None
676 else:
677 self.data['discontinue_reason'] = self._PRW_discontinue_reason.GetValue().strip()
678 self.data['preparation'] = self._PRW_preparation.GetValue()
679 self.data['strength'] = self._PRW_strength.GetValue()
680 self.data['schedule'] = self._PRW_schedule.GetValue()
681 self.data['aim'] = self._PRW_aim.GetValue()
682 self.data['notes'] = self._PRW_notes.GetValue()
683 self.data['is_long_term'] = self._CHBOX_long_term.IsChecked()
684 self.data['intake_is_approved_of'] = self._CHBOX_approved.IsChecked()
685 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True)
686
687 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
688 self.data['duration'] = None
689 else:
690 self.data['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue())
691
692 if self._PRW_brand.GetData() is None:
693 desc = self._PRW_brand.GetValue().strip()
694 if desc != u'':
695 # create or get brand
696 self.data['pk_brand'] = gmMedication.create_branded_drug (
697 brand_name = desc,
698 preparation = self._PRW_preparation.GetValue().strip(),
699 return_existing = True
700 )['pk']
701 else:
702 self.data['pk_brand'] = self._PRW_brand.GetData()
703
704 self.data.save()
705
706 if self._CHBOX_is_allergy.IsChecked():
707 allg = self.data.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
708 # open for editing
709 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = self, id = -1)
710 dlg.ShowModal()
711
712 return True
713 #----------------------------------------------------------------
715 self._PRW_substance.SetText(u'', None)
716 self._PRW_strength.SetText(u'', None)
717 # self._PRW_preparation.SetText(u'', None)
718 self._PRW_schedule.SetText(u'', None)
719 self._PRW_duration.SetText(u'', None)
720 self._PRW_aim.SetText(u'', None)
721 self._PRW_notes.SetText(u'', None)
722 self._PRW_episode.SetData(None)
723
724 self._CHBOX_long_term.SetValue(False)
725 self._CHBOX_approved.SetValue(True)
726
727 self._DP_started.SetValue(gmDateTime.pydt_now_here())
728 self._DP_discontinued.SetValue(None)
729 self._PRW_discontinue_reason.SetValue(u'')
730
731 self.__refresh_brand_and_components()
732 self.__refresh_allergies()
733
734 self._PRW_substance.SetFocus()
735 #----------------------------------------------------------------
737
738 self._PRW_substance.SetText(self.data['substance'], self.data['pk_substance'])
739 self._PRW_strength.SetText(gmTools.coalesce(self.data['strength'], u''), self.data['strength'])
740
741 if self.data['is_long_term']:
742 self._CHBOX_long_term.SetValue(True)
743 self._PRW_duration.Enable(False)
744 self._PRW_duration.SetText(gmTools.u_infinity, None)
745 self._BTN_discontinued_as_planned.Enable(False)
746 else:
747 self._CHBOX_long_term.SetValue(False)
748 self._PRW_duration.Enable(True)
749 self._BTN_discontinued_as_planned.Enable(True)
750 if self.data['duration'] is None:
751 self._PRW_duration.SetText(u'', None)
752 else:
753 self._PRW_duration.SetText(gmDateTime.format_interval(self.data['duration'], gmDateTime.acc_days), self.data['duration'])
754 self._PRW_aim.SetText(gmTools.coalesce(self.data['aim'], u''), self.data['aim'])
755 self._PRW_notes.SetText(gmTools.coalesce(self.data['notes'], u''), self.data['notes'])
756 self._PRW_episode.SetData(self.data['pk_episode'])
757 self._PRW_schedule.SetText(gmTools.coalesce(self.data['schedule'], u''), self.data['schedule'])
758
759 self._CHBOX_approved.SetValue(self.data['intake_is_approved_of'])
760
761 self._DP_started.SetValue(self.data['started'])
762 self._DP_discontinued.SetValue(self.data['discontinued'])
763 self._PRW_discontinue_reason.SetValue(gmTools.coalesce(self.data['discontinue_reason'], u''))
764
765 self.__refresh_brand_and_components()
766 self.__refresh_allergies()
767
768 self._PRW_substance.SetFocus()
769 #----------------------------------------------------------------
771 self._refresh_as_new()
772
773 self._PRW_substance.SetText(u'', None)
774 self._PRW_strength.SetText(u'', None)
775 self._PRW_notes.SetText(u'', None)
776
777 self.__refresh_brand_and_components()
778 self.__refresh_allergies()
779
780 self._PRW_substance.SetFocus()
781 #----------------------------------------------------------------
782 # event handlers
783 #----------------------------------------------------------------
786 #----------------------------------------------------------------
788 if self._DP_discontinued.GetValue() is None:
789 self._PRW_discontinue_reason.Enable(False)
790 self._CHBOX_is_allergy.Enable(False)
791 else:
792 self._PRW_discontinue_reason.Enable(True)
793 self._CHBOX_is_allergy.Enable(True)
794 #----------------------------------------------------------------
813 #----------------------------------------------------------------
835 #----------------------------------------------------------------
864 #----------------------------------------------------------------
866 if self._CHBOX_long_term.IsChecked() is True:
867 self._PRW_duration.Enable(False)
868 self._BTN_discontinued_as_planned.Enable(False)
869 self._PRW_discontinue_reason.Enable(False)
870 self._CHBOX_is_allergy.Enable(False)
871 else:
872 self._PRW_duration.Enable(True)
873 self._BTN_discontinued_as_planned.Enable(True)
874 self._PRW_discontinue_reason.Enable(True)
875 self._CHBOX_is_allergy.Enable(True)
876
877 self.__refresh_allergies()
878 #----------------------------------------------------------------
886 #============================================================
888 delete_it = gmGuiHelpers.gm_show_question (
889 aMessage = _(
890 'Do you really want to remove this substance intake ?\n'
891 '\n'
892 'It may be prudent to edit the details first so as to\n'
893 'leave behind some indication of why it was deleted.\n'
894 ),
895 aTitle = _('Deleting medication / substance intake')
896 )
897 if not delete_it:
898 return
899
900 gmMedication.delete_substance_intake(substance = substance)
901 #------------------------------------------------------------
903 ea = cCurrentMedicationEAPnl(parent = parent, id = -1, substance = substance)
904 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = (substance is not None))
905 dlg.SetTitle(gmTools.coalesce(substance, _('Adding substance intake'), _('Editing substance intake')))
906 if dlg.ShowModal() == wx.ID_OK:
907 dlg.Destroy()
908 return True
909 dlg.Destroy()
910 return False
911 #============================================================
912 # current substances grid
913 #------------------------------------------------------------
915
916 if parent is None:
917 parent = wx.GetApp().GetTopWindow()
918
919 template = gmFormWidgets.manage_form_templates(parent = parent)
920 option = u'form_templates.medication_list'
921
922 if template is None:
923 gmDispatcher.send(signal = 'statustext', msg = _('No medication list template configured.'), beep = True)
924 return None
925
926 if template['engine'] != u'L':
927 gmDispatcher.send(signal = 'statustext', msg = _('No medication list template configured.'), beep = True)
928 return None
929
930 dbcfg = gmCfg.cCfgSQL()
931 dbcfg.set (
932 workplace = gmSurgery.gmCurrentPractice().active_workplace,
933 option = option,
934 value = u'%s - %s' % (template['name_long'], template['external_version'])
935 )
936
937 return template
938 #------------------------------------------------------------
940
941 if parent is None:
942 parent = wx.GetApp().GetTopWindow()
943
944 # 1) get template
945 dbcfg = gmCfg.cCfgSQL()
946 option = u'form_templates.medication_list'
947
948 template = dbcfg.get2 (
949 option = option,
950 workplace = gmSurgery.gmCurrentPractice().active_workplace,
951 bias = 'user'
952 )
953
954 if template is None:
955 template = configure_medication_list_template(parent = parent)
956 if template is None:
957 gmGuiHelpers.gm_show_error (
958 aMessage = _('There is no medication list template configured.'),
959 aTitle = _('Printing medication list')
960 )
961 return False
962 else:
963 try:
964 name, ver = template.split(u' - ')
965 except:
966 _log.exception('problem splitting medication list template name [%s]', template)
967 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading medication list template.'), beep = True)
968 return False
969 template = gmForms.get_form_template(name_long = name, external_version = ver)
970 if template is None:
971 gmGuiHelpers.gm_show_error (
972 aMessage = _('Cannot load medication list template [%s - %s]') % (name, ver),
973 aTitle = _('Printing medication list')
974 )
975 return False
976
977 # 2) process template
978 try:
979 meds_list = template.instantiate()
980 except KeyError:
981 _log.exception('cannot instantiate medication list template [%s]', template)
982 gmGuiHelpers.gm_show_error (
983 aMessage = _('Invalid medication list template [%s - %s (%s)]') % (name, ver, template['engine']),
984 aTitle = _('Printing medication list')
985 )
986 return False
987
988 ph = gmMacro.gmPlaceholderHandler()
989 #ph.debug = True
990 meds_list.substitute_placeholders(data_source = ph)
991 pdf_name = meds_list.generate_output(cleanup = cleanup)
992 if cleanup:
993 meds_list.cleanup()
994 if pdf_name is None:
995 gmGuiHelpers.gm_show_error (
996 aMessage = _('Error generating the medication list.'),
997 aTitle = _('Printing medication list')
998 )
999 return False
1000
1001 # 3) print template
1002 printed = gmPrinting.print_file_by_shellscript(filename = pdf_name, jobtype = 'medication_list')
1003 if not printed:
1004 gmGuiHelpers.gm_show_error (
1005 aMessage = _('Error printing the medication list.'),
1006 aTitle = _('Printing medication list')
1007 )
1008 return False
1009
1010 pat = gmPerson.gmCurrentPatient()
1011 emr = pat.get_emr()
1012 epi = emr.add_episode(episode_name = 'administration', is_open = False)
1013 emr.add_clin_narrative (
1014 soap_cat = None,
1015 note = _('medication list printed from template [%s - %s]') % (template['name_long'], template['external_version']),
1016 episode = epi
1017 )
1018
1019 return True
1020 #------------------------------------------------------------
1022 """A grid class for displaying current substance intake.
1023
1024 - does NOT listen to the currently active patient
1025 - thereby it can display any patient at any time
1026 """
1028
1029 wx.grid.Grid.__init__(self, *args, **kwargs)
1030
1031 self.__patient = None
1032 self.__row_data = {}
1033 self.__prev_row = None
1034 self.__prev_tooltip_row = None
1035 self.__prev_cell_0 = None
1036 self.__grouping_mode = u'episode'
1037 self.__filter_show_unapproved = False
1038 self.__filter_show_inactive = False
1039
1040 self.__grouping2col_labels = {
1041 u'episode': [
1042 _('Episode'),
1043 _('Substance'),
1044 _('Dose'),
1045 _('Schedule'),
1046 _('Started'),
1047 _('Duration'),
1048 _('Brand')
1049 ],
1050 u'brand': [
1051 _('Brand'),
1052 _('Schedule'),
1053 _('Substance'),
1054 _('Dose'),
1055 _('Started'),
1056 _('Duration'),
1057 _('Episode')
1058 ]
1059 }
1060
1061 self.__grouping2order_by_clauses = {
1062 u'episode': u'pk_health_issue nulls first, episode, substance, started',
1063 u'brand': u'brand nulls last, substance, started'
1064 }
1065
1066 self.__init_ui()
1067 self.__register_events()
1068 #------------------------------------------------------------
1069 # external API
1070 #------------------------------------------------------------
1072
1073 sel_block_top_left = self.GetSelectionBlockTopLeft()
1074 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
1075 sel_cols = self.GetSelectedCols()
1076 sel_rows = self.GetSelectedRows()
1077
1078 selected_cells = []
1079
1080 # individually selected cells (ctrl-click)
1081 selected_cells += self.GetSelectedCells()
1082
1083 # selected rows
1084 selected_cells += list (
1085 (row, col)
1086 for row in sel_rows
1087 for col in xrange(self.GetNumberCols())
1088 )
1089
1090 # selected columns
1091 selected_cells += list (
1092 (row, col)
1093 for row in xrange(self.GetNumberRows())
1094 for col in sel_cols
1095 )
1096
1097 # selection blocks
1098 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
1099 selected_cells += [
1100 (row, col)
1101 for row in xrange(top_left[0], bottom_right[0] + 1)
1102 for col in xrange(top_left[1], bottom_right[1] + 1)
1103 ]
1104
1105 return set(selected_cells)
1106 #------------------------------------------------------------
1108 rows = {}
1109
1110 for row, col in self.get_selected_cells():
1111 rows[row] = True
1112
1113 return rows.keys()
1114 #------------------------------------------------------------
1116 return [ self.__row_data[row] for row in self.get_selected_rows() ]
1117 #------------------------------------------------------------
1119
1120 self.empty_grid()
1121
1122 if self.__patient is None:
1123 return
1124
1125 emr = self.__patient.get_emr()
1126 meds = emr.get_current_substance_intake (
1127 order_by = self.__grouping2order_by_clauses[self.__grouping_mode],
1128 include_unapproved = self.__filter_show_unapproved,
1129 include_inactive = self.__filter_show_inactive
1130 )
1131 if not meds:
1132 return
1133
1134 self.BeginBatch()
1135
1136 # columns
1137 labels = self.__grouping2col_labels[self.__grouping_mode]
1138 if self.__filter_show_unapproved:
1139 self.AppendCols(numCols = len(labels) + 1)
1140 else:
1141 self.AppendCols(numCols = len(labels))
1142 for col_idx in range(len(labels)):
1143 self.SetColLabelValue(col_idx, labels[col_idx])
1144 if self.__filter_show_unapproved:
1145 self.SetColLabelValue(len(labels), u'OK?')
1146 self.SetColSize(len(labels), 40)
1147
1148 self.AppendRows(numRows = len(meds))
1149
1150 # loop over data
1151 for row_idx in range(len(meds)):
1152 med = meds[row_idx]
1153 self.__row_data[row_idx] = med
1154
1155 if med['is_currently_active'] is True:
1156 atcs = []
1157 if med['atc_substance'] is not None:
1158 atcs.append(med['atc_substance'])
1159 if med['atc_brand'] is not None:
1160 atcs.append(med['atc_brand'])
1161 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (med['substance'],), brand = med['brand'])
1162 if allg not in [None, False]:
1163 attr = self.GetOrCreateCellAttr(row_idx, 0)
1164 if allg['type'] == u'allergy':
1165 attr.SetTextColour('red')
1166 else:
1167 attr.SetTextColour('yellow')
1168 self.SetRowAttr(row_idx, attr)
1169 else:
1170 attr = self.GetOrCreateCellAttr(row_idx, 0)
1171 attr.SetTextColour('grey')
1172 self.SetRowAttr(row_idx, attr)
1173
1174 if self.__grouping_mode == u'episode':
1175 if med['pk_episode'] is None:
1176 self.__prev_cell_0 = None
1177 self.SetCellValue(row_idx, 0, gmTools.u_diameter)
1178 else:
1179 if self.__prev_cell_0 != med['episode']:
1180 self.__prev_cell_0 = med['episode']
1181 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['episode'], u''))
1182
1183 self.SetCellValue(row_idx, 1, med['substance'])
1184 self.SetCellValue(row_idx, 2, gmTools.coalesce(med['strength'], u''))
1185 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['schedule'], u''))
1186 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1187
1188 if med['is_long_term']:
1189 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1190 else:
1191 if med['duration'] is None:
1192 self.SetCellValue(row_idx, 5, u'')
1193 else:
1194 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1195
1196 if med['pk_brand'] is None:
1197 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u''))
1198 else:
1199 if med['fake_brand']:
1200 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u'', _('%s (fake)')))
1201 else:
1202 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u''))
1203
1204 elif self.__grouping_mode == u'brand':
1205
1206 if med['pk_brand'] is None:
1207 self.__prev_cell_0 = None
1208 self.SetCellValue(row_idx, 0, gmTools.u_diameter)
1209 else:
1210 if self.__prev_cell_0 != med['brand']:
1211 self.__prev_cell_0 = med['brand']
1212 if med['fake_brand']:
1213 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['brand'], u'', _('%s (fake)')))
1214 else:
1215 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['brand'], u''))
1216
1217 self.SetCellValue(row_idx, 1, gmTools.coalesce(med['schedule'], u''))
1218 self.SetCellValue(row_idx, 2, med['substance'])
1219 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['strength'], u''))
1220 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1221
1222 if med['is_long_term']:
1223 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1224 else:
1225 if med['duration'] is None:
1226 self.SetCellValue(row_idx, 5, u'')
1227 else:
1228 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1229
1230 if med['pk_episode'] is None:
1231 self.SetCellValue(row_idx, 6, u'')
1232 else:
1233 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['episode'], u''))
1234
1235 else:
1236 raise ValueError('unknown grouping mode [%s]' % self.__grouping_mode)
1237
1238 if self.__filter_show_unapproved:
1239 self.SetCellValue (
1240 row_idx,
1241 len(labels),
1242 gmTools.bool2subst(med['intake_is_approved_of'], gmTools.u_checkmark_thin, u'', u'?')
1243 )
1244
1245 #self.SetCellAlignment(row, col, horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
1246
1247 self.EndBatch()
1248 #------------------------------------------------------------
1250 self.BeginBatch()
1251 self.ClearGrid()
1252 # Windows cannot do "nothing", it rather decides to assert()
1253 # on thinking it is supposed to do nothing
1254 if self.GetNumberRows() > 0:
1255 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
1256 if self.GetNumberCols() > 0:
1257 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
1258 self.EndBatch()
1259 self.__row_data = {}
1260 self.__prev_cell_0 = None
1261 #------------------------------------------------------------
1263
1264 if len(self.__row_data) == 0:
1265 return
1266
1267 sel_rows = self.get_selected_rows()
1268 if len(sel_rows) != 1:
1269 return
1270
1271 drug_db = get_drug_database()
1272 if drug_db is None:
1273 return
1274
1275 drug_db.show_info_on_substance(substance = self.get_selected_data()[0])
1276 #------------------------------------------------------------
1278
1279 if len(self.__row_data) == 0:
1280 return
1281
1282 sel_rows = self.get_selected_rows()
1283
1284 if len(sel_rows) != 1:
1285 return
1286
1287 webbrowser.open (
1288 url = gmMedication.drug2renal_insufficiency_url(search_term = self.get_selected_data()[0]),
1289 new = False,
1290 autoraise = True
1291 )
1292 #------------------------------------------------------------
1294
1295 dbcfg = gmCfg.cCfgSQL()
1296
1297 url = dbcfg.get2 (
1298 option = u'external.urls.report_ADR',
1299 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1300 bias = u'user',
1301 default = u'https://dcgma.org/uaw/meldung.php'
1302 )
1303
1304 webbrowser.open(url = url, new = False, autoraise = True)
1305 #------------------------------------------------------------
1307
1308 if len(self.__row_data) == 0:
1309 return
1310
1311 drug_db = get_drug_database()
1312 if drug_db is None:
1313 return
1314
1315 if len(self.get_selected_rows()) > 1:
1316 drug_db.check_drug_interactions(substances = self.get_selected_data())
1317 else:
1318 drug_db.check_drug_interactions(substances = self.__row_data.values())
1319 #------------------------------------------------------------
1321 edit_intake_of_substance(parent = self, substance = None)
1322 #------------------------------------------------------------
1324
1325 rows = self.get_selected_rows()
1326
1327 if len(rows) == 0:
1328 return
1329
1330 if len(rows) > 1:
1331 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit more than one substance at once.'), beep = True)
1332 return
1333
1334 subst = self.get_selected_data()[0]
1335 edit_intake_of_substance(parent = self, substance = subst)
1336 #------------------------------------------------------------
1338
1339 rows = self.get_selected_rows()
1340
1341 if len(rows) == 0:
1342 return
1343
1344 if len(rows) > 1:
1345 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete more than one substance at once.'), beep = True)
1346 return
1347
1348 subst = self.get_selected_data()[0]
1349 delete_substance_intake(parent = self, substance = subst['pk_substance_intake'])
1350 #------------------------------------------------------------
1352 rows = self.get_selected_rows()
1353
1354 if len(rows) == 0:
1355 return
1356
1357 if len(rows) > 1:
1358 gmDispatcher.send(signal = 'statustext', msg = _('Cannot create allergy from more than one substance at once.'), beep = True)
1359 return
1360
1361 subst = self.get_selected_data()[0]
1362 if subst['is_currently_active']:
1363 subst['discontinued'] = gmDateTime.pydt_now_here()
1364 if subst['discontinue_reason'] is None:
1365 subst['discontinue_reason'] = _('discontinued due to allergy or intolerance')
1366 subst.save()
1367
1368 emr = self.__patient.get_emr()
1369 allg = subst.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
1370 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = self, id = -1)
1371 dlg.ShowModal()
1372 #------------------------------------------------------------
1374 # there could be some filtering/user interaction going on here
1375 _cfg = gmCfg2.gmCfgData()
1376 print_medication_list(parent = self, cleanup = _cfg.get(option = 'debug'))
1377 #------------------------------------------------------------
1379
1380 try:
1381 entry = self.__row_data[row]
1382 except KeyError:
1383 return u' '
1384
1385 emr = self.__patient.get_emr()
1386 atcs = []
1387 if entry['atc_substance'] is not None:
1388 atcs.append(entry['atc_substance'])
1389 if entry['atc_brand'] is not None:
1390 atcs.append(entry['atc_brand'])
1391 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (entry['substance'],), brand = entry['brand'])
1392
1393 tt = _('Substance intake entry (%s, %s) [#%s] \n') % (
1394 gmTools.bool2subst (
1395 boolean = entry['is_currently_active'],
1396 true_return = gmTools.bool2subst (
1397 boolean = entry['seems_inactive'],
1398 true_return = _('active, needs check'),
1399 false_return = _('active'),
1400 none_return = _('assumed active')
1401 ),
1402 false_return = _('inactive')
1403 ),
1404 gmTools.bool2subst (
1405 boolean = entry['intake_is_approved_of'],
1406 true_return = _('approved'),
1407 false_return = _('unapproved')
1408 ),
1409 entry['pk_substance_intake']
1410 )
1411
1412 if allg not in [None, False]:
1413 certainty = gmTools.bool2subst(allg['definite'], _('definite'), _('suspected'))
1414 tt += u'\n'
1415 tt += u' !! ---- Cave ---- !!\n'
1416 tt += u' %s (%s): %s (%s)\n' % (
1417 allg['l10n_type'],
1418 certainty,
1419 allg['descriptor'],
1420 gmTools.coalesce(allg['reaction'], u'')[:40]
1421 )
1422 tt += u'\n'
1423
1424 tt += u' ' + _('Substance: %s [#%s]\n') % (entry['substance'], entry['pk_substance'])
1425 tt += u' ' + _('Preparation: %s\n') % entry['preparation']
1426 if entry['strength'] is not None:
1427 tt += u' ' + _('Amount per dose: %s') % entry['strength']
1428 if entry.ddd is not None:
1429 tt += u' (DDD: %s %s)' % (entry.ddd['ddd'], entry.ddd['unit'])
1430 tt += u'\n'
1431 else:
1432 if entry.ddd is not None:
1433 tt += u' DDD: %s %s' % (entry.ddd['ddd'], entry.ddd['unit'])
1434 tt += u'\n'
1435 tt += gmTools.coalesce(entry['atc_substance'], u'', _(' ATC (substance): %s\n'))
1436
1437 tt += u'\n'
1438
1439 tt += gmTools.coalesce (
1440 entry['brand'],
1441 u'',
1442 _(' Brand name: %%s [#%s]\n') % entry['pk_brand']
1443 )
1444 tt += gmTools.coalesce(entry['atc_brand'], u'', _(' ATC (brand): %s\n'))
1445
1446 tt += u'\n'
1447
1448 tt += gmTools.coalesce(entry['schedule'], u'', _(' Regimen: %s\n'))
1449
1450 if entry['is_long_term']:
1451 duration = u' %s %s' % (gmTools.u_right_arrow, gmTools.u_infinity)
1452 else:
1453 if entry['duration'] is None:
1454 duration = u''
1455 else:
1456 duration = u' %s %s' % (gmTools.u_right_arrow, gmDateTime.format_interval(entry['duration'], gmDateTime.acc_days))
1457
1458 tt += _(' Started %s%s%s\n') % (
1459 entry['started'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
1460 duration,
1461 gmTools.bool2subst(entry['is_long_term'], _(' (long-term)'), _(' (short-term)'), u'')
1462 )
1463
1464 if entry['discontinued'] is not None:
1465 tt += _(' Discontinued %s\n') % (
1466 entry['discontinued'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
1467 )
1468 tt += _(' Reason: %s\n') % entry['discontinue_reason']
1469
1470 tt += u'\n'
1471
1472 tt += gmTools.coalesce(entry['aim'], u'', _(' Aim: %s\n'))
1473 tt += gmTools.coalesce(entry['episode'], u'', _(' Episode: %s\n'))
1474 tt += gmTools.coalesce(entry['notes'], u'', _(' Advice: %s\n'))
1475
1476 tt += u'\n'
1477
1478 tt += _(u'Revision: #%(row_ver)s, %(mod_when)s by %(mod_by)s.') % ({
1479 'row_ver': entry['row_version'],
1480 'mod_when': entry['modified_when'].strftime('%c').decode(gmI18N.get_encoding()),
1481 'mod_by': entry['modified_by']
1482 })
1483
1484 return tt
1485 #------------------------------------------------------------
1486 # internal helpers
1487 #------------------------------------------------------------
1489 self.CreateGrid(0, 1)
1490 self.EnableEditing(0)
1491 self.EnableDragGridSize(1)
1492 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
1493
1494 self.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTER)
1495
1496 self.SetRowLabelSize(0)
1497 self.SetRowLabelAlignment(horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
1498 #------------------------------------------------------------
1499 # properties
1500 #------------------------------------------------------------
1503
1507
1508 patient = property(_get_patient, _set_patient)
1509 #------------------------------------------------------------
1512
1516
1517 grouping_mode = property(_get_grouping_mode, _set_grouping_mode)
1518 #------------------------------------------------------------
1521
1525
1526 filter_show_unapproved = property(_get_filter_show_unapproved, _set_filter_show_unapproved)
1527 #------------------------------------------------------------
1530
1534
1535 filter_show_inactive = property(_get_filter_show_inactive, _set_filter_show_inactive)
1536 #------------------------------------------------------------
1537 # event handling
1538 #------------------------------------------------------------
1540 # dynamic tooltips: GridWindow, GridRowLabelWindow, GridColLabelWindow, GridCornerLabelWindow
1541 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
1542 #self.GetGridRowLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_row_labels)
1543 #self.GetGridColLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_col_labels)
1544
1545 # editing cells
1546 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
1547 #------------------------------------------------------------
1549 """Calculate where the mouse is and set the tooltip dynamically."""
1550
1551 # Use CalcUnscrolledPosition() to get the mouse position within the
1552 # entire grid including what's offscreen
1553 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
1554
1555 # use this logic to prevent tooltips outside the actual cells
1556 # apply to GetRowSize, too
1557 # tot = 0
1558 # for col in xrange(self.NumberCols):
1559 # tot += self.GetColSize(col)
1560 # if xpos <= tot:
1561 # self.tool_tip.Tip = 'Tool tip for Column %s' % (
1562 # self.GetColLabelValue(col))
1563 # break
1564 # else: # mouse is in label area beyond the right-most column
1565 # self.tool_tip.Tip = ''
1566
1567 row, col = self.XYToCell(x, y)
1568
1569 if row == self.__prev_tooltip_row:
1570 return
1571
1572 self.__prev_tooltip_row = row
1573
1574 try:
1575 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
1576 except KeyError:
1577 pass
1578 #------------------------------------------------------------
1580 row = evt.GetRow()
1581 data = self.__row_data[row]
1582 edit_intake_of_substance(parent = self, substance = data)
1583 #============================================================
1584 from Gnumed.wxGladeWidgets import wxgCurrentSubstancesPnl
1585
1586 -class cCurrentSubstancesPnl(wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl, gmRegetMixin.cRegetOnPaintMixin):
1587
1588 """Panel holding a grid with current substances. Used as notebook page."""
1589
1591
1592 wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl.__init__(self, *args, **kwargs)
1593 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
1594
1595 self.__register_interests()
1596 #-----------------------------------------------------
1597 # reget-on-paint mixin API
1598 #-----------------------------------------------------
1600 """Populate cells with data from model."""
1601 pat = gmPerson.gmCurrentPatient()
1602 if pat.connected:
1603 self._grid_substances.patient = pat
1604 else:
1605 self._grid_substances.patient = None
1606 return True
1607 #--------------------------------------------------------
1608 # event handling
1609 #--------------------------------------------------------
1611 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
1612 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._schedule_data_reget)
1613 gmDispatcher.connect(signal = u'substance_intake_mod_db', receiver = self._schedule_data_reget)
1614 # active_substance_mod_db
1615 # substance_brand_mod_db
1616 #--------------------------------------------------------
1619 #--------------------------------------------------------
1621 self._grid_substances.patient = None
1622 #--------------------------------------------------------
1625 #--------------------------------------------------------
1628 #--------------------------------------------------------
1631 #--------------------------------------------------------
1634 #--------------------------------------------------------
1637 #--------------------------------------------------------
1639 self._grid_substances.grouping_mode = 'episode'
1640 #--------------------------------------------------------
1642 self._grid_substances.grouping_mode = 'brand'
1643 #--------------------------------------------------------
1646 #--------------------------------------------------------
1649 #--------------------------------------------------------
1652 #--------------------------------------------------------
1655 #--------------------------------------------------------
1658 #--------------------------------------------------------
1661 #============================================================
1662 # main
1663 #------------------------------------------------------------
1664 if __name__ == '__main__':
1665
1666 if len(sys.argv) < 2:
1667 sys.exit()
1668
1669 if sys.argv[1] != 'test':
1670 sys.exit()
1671
1672 from Gnumed.pycommon import gmI18N
1673
1674 gmI18N.activate_locale()
1675 gmI18N.install_domain(domain = 'gnumed')
1676
1677 #----------------------------------------
1678 # test_*()
1679 pass
1680
1681 #============================================================
1682
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Jun 28 04:12:45 2010 | http://epydoc.sourceforge.net |