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, decimal
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
26
27
28
46
82
89
90
92
93 dbcfg = gmCfg.cCfgSQL()
94
95 ifap_cmd = dbcfg.get2 (
96 option = 'external.ifap-win.shell_command',
97 workplace = gmSurgery.gmCurrentPractice().active_workplace,
98 bias = 'workplace',
99 default = 'wine "C:\Ifapwin\WIAMDB.EXE"'
100 )
101 found, binary = gmShellAPI.detect_external_binary(ifap_cmd)
102 if not found:
103 gmDispatcher.send('statustext', msg = _('Cannot call IFAP via [%s].') % ifap_cmd)
104 return False
105 ifap_cmd = binary
106
107 if import_drugs:
108 transfer_file = os.path.expanduser(dbcfg.get2 (
109 option = 'external.ifap-win.transfer_file',
110 workplace = gmSurgery.gmCurrentPractice().active_workplace,
111 bias = 'workplace',
112 default = '~/.wine/drive_c/Ifapwin/ifap2gnumed.csv'
113 ))
114
115 try:
116 f = open(transfer_file, 'w+b').close()
117 except IOError:
118 _log.exception('Cannot create IFAP <-> GNUmed transfer file [%s]', transfer_file)
119 gmDispatcher.send('statustext', msg = _('Cannot create IFAP <-> GNUmed transfer file [%s].') % transfer_file)
120 return False
121
122 wx.BeginBusyCursor()
123 gmShellAPI.run_command_in_shell(command = ifap_cmd, blocking = import_drugs)
124 wx.EndBusyCursor()
125
126 if import_drugs:
127
128
129 try:
130 csv_file = open(transfer_file, 'rb')
131 except:
132 _log.exception('cannot access [%s]', fname)
133 csv_file = None
134
135 if csv_file is not None:
136 import csv
137 csv_lines = csv.DictReader (
138 csv_file,
139 fieldnames = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split(),
140 delimiter = ';'
141 )
142 pat = gmPerson.gmCurrentPatient()
143 emr = pat.get_emr()
144
145 epi = emr.add_episode(episode_name = _('Current medication'))
146 for line in csv_lines:
147 narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % (
148 line['Packungszahl'].strip(),
149 line['Handelsname'].strip(),
150 line['Form'].strip(),
151 line[u'Packungsgr\xf6\xdfe'].strip(),
152 line['Abpackungsmenge'].strip(),
153 line['Einheit'].strip(),
154 line['Hersteller'].strip(),
155 line['PZN'].strip()
156 )
157 emr.add_clin_narrative(note = narr, soap_cat = 's', episode = epi)
158 csv_file.close()
159
160 return True
161
162
163
164
165
167
168 if parent is None:
169 parent = wx.GetApp().GetTopWindow()
170
171 def refresh(lctrl):
172 atcs = gmATC.get_reference_atcs()
173
174 items = [ [
175 a['atc'],
176 a['term'],
177 u'%s' % gmTools.coalesce(a['ddd'], u''),
178 gmTools.coalesce(a['unit'], u''),
179 gmTools.coalesce(a['administrative_route'], u''),
180 gmTools.coalesce(a['comment'], u''),
181 a['version'],
182 a['lang']
183 ] for a in atcs ]
184 lctrl.set_string_items(items)
185 lctrl.set_data(atcs)
186
187 gmListWidgets.get_choices_from_list (
188 parent = parent,
189 msg = _('\nThe ATC codes as known to GNUmed.\n'),
190 caption = _('Showing ATC codes.'),
191 columns = [ u'ATC', _('Term'), u'DDD', _('Unit'), _(u'Route'), _('Comment'), _('Version'), _('Language') ],
192 single_selection = True,
193 refresh_callback = refresh
194 )
195
196
197
199
200 dlg = wx.FileDialog (
201 parent = None,
202 message = _('Choose an ATC import config file'),
203 defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')),
204 defaultFile = '',
205 wildcard = "%s (*.conf)|*.conf|%s (*)|*" % (_('config files'), _('all files')),
206 style = wx.OPEN | wx.HIDE_READONLY | wx.FILE_MUST_EXIST
207 )
208
209 result = dlg.ShowModal()
210 if result == wx.ID_CANCEL:
211 return
212
213 cfg_file = dlg.GetPath()
214 dlg.Destroy()
215
216 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('importing ATC reference data'))
217 if conn is None:
218 return False
219
220 wx.BeginBusyCursor()
221
222 if gmATC.atc_import(cfg_fname = cfg_file, conn = conn):
223 gmDispatcher.send(signal = 'statustext', msg = _('Successfully imported ATC reference data.'))
224 else:
225 gmDispatcher.send(signal = 'statustext', msg = _('Importing ATC reference data failed.'), beep = True)
226
227 wx.EndBusyCursor()
228 return True
229
230
231
233
235
236 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
237
238 query = u"""
239
240 SELECT DISTINCT ON (label)
241 atc_code,
242 label
243 FROM (
244
245 SELECT
246 code as atc_code,
247 (code || ': ' || term || coalesce(' (' || ddd || unit || ')', ''))
248 AS label
249 FROM ref.atc
250 WHERE
251 term %(fragment_condition)s
252 OR
253 code %(fragment_condition)s
254
255 UNION ALL
256
257 SELECT
258 atc_code,
259 (atc_code || ': ' || description)
260 AS label
261 FROM ref.consumable_substance
262 WHERE
263 description %(fragment_condition)s
264 OR
265 atc_code %(fragment_condition)s
266
267 UNION ALL
268
269 SELECT
270 atc_code,
271 (atc_code || ': ' || description || ' (' || preparation || ')')
272 AS label
273 FROM ref.branded_drug
274 WHERE
275 description %(fragment_condition)s
276 OR
277 atc_code %(fragment_condition)s
278
279 -- it would be nice to be able to include clin.vacc_indication but that's hard to do in SQL
280
281 ) AS candidates
282
283 ORDER BY label
284 LIMIT 50"""
285
286 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
287 mp.setThresholds(1, 2, 4)
288
289 self.SetToolTipString(_('Select an ATC (Anatomical-Therapeutic-Chemical) code.'))
290 self.matcher = mp
291 self.selection_only = True
292
293
294
295
297
298 if parent is None:
299 parent = wx.GetApp().GetTopWindow()
300
301 def add_from_db(substance):
302 drug_db = get_drug_database(parent = parent)
303 if drug_db is None:
304 return False
305 drug_db.import_drugs()
306 return True
307
308 def edit(substance=None):
309 return edit_consumable_substance(parent = parent, substance = substance, single_entry = (substance is not None))
310
311 def delete(substance):
312 return gmMedication.delete_consumable_substance(substance = substance['pk'])
313
314 def refresh(lctrl):
315 substs = gmMedication.get_consumable_substances(order_by = 'description')
316 items = [ [
317 s['description'],
318 gmTools.coalesce(s['atc_code'], u''),
319 s['pk']
320 ] for s in substs ]
321 lctrl.set_string_items(items)
322 lctrl.set_data(substs)
323
324 msg = _('\nThese are the consumable substances registered with GNUmed.\n')
325
326 gmListWidgets.get_choices_from_list (
327 parent = parent,
328 msg = msg,
329 caption = _('Showing consumable substances.'),
330 columns = [_('Substance'), 'ATC', u'#'],
331 single_selection = True,
332 new_callback = edit,
333 edit_callback = edit,
334 delete_callback = delete,
335 refresh_callback = refresh,
336 left_extra_button = (_('Import'), _('Import consumable substances from a drug database.'), add_from_db)
337 )
338
339
351
352
353 from Gnumed.wxGladeWidgets import wxgConsumableSubstanceEAPnl
354
356
374
375
376
377
378
379
380
381
383
384 validity = True
385
386 if self._TCTRL_substance.GetValue().strip() == u'':
387 validity = False
388 self.display_tctrl_as_valid(tctrl = self._TCTRL_substance, valid = False)
389 else:
390 self.display_tctrl_as_valid(tctrl = self._TCTRL_substance, valid = True)
391
392 if validity is False:
393 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save consumable substance. Must enter substance name.'))
394
395 return validity
396
412
414 self.data['description'] = self._TCTRL_substance.GetValue().strip()
415 self.data['atc_code'] = self._PRW_atc.GetData()
416 success, data = self.data.save()
417
418 if not success:
419 err, msg = data
420 _log.error(err)
421 _log.error(msg)
422 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save consumable substance. %s') % msg, beep = True)
423 return False
424
425 return True
426
428 self._TCTRL_substance.SetValue(u'')
429 self._PRW_atc.SetText(u'', None)
430
431 self._TCTRL_substance.SetFocus()
432
438
440 self._refresh_as_new()
441
442
443
444
446
447 if parent is None:
448 parent = wx.GetApp().GetTopWindow()
449
450
451 def edit(component=None):
452 return edit_drug_component(parent = parent, drug_component = component, single_entry = (component is not None))
453
454 def delete(component):
455 return component.containing_drug.remove_component(substance = component['pk_component'])
456
457 def refresh(lctrl):
458 comps = gmMedication.get_drug_components()
459 items = [ [
460 u'%s%s' % (c['brand'], gmTools.coalesce(c['atc_brand'], u'', u' [%s]')),
461 u'%s%s' % (c['substance'], gmTools.coalesce(c['atc_substance'], u'', u' [%s]')),
462 u'%s%s' % (c['amount'], c['unit']),
463 c['preparation'],
464 gmTools.coalesce(c['external_code_brand'], u'', u'%%s [%s]' % c['external_code_type_brand']),
465 c['pk_component']
466 ] for c in comps ]
467 lctrl.set_string_items(items)
468 lctrl.set_data(comps)
469
470 msg = _('\nThese are the components in the drug brands known to GNUmed.\n')
471
472 gmListWidgets.get_choices_from_list (
473 parent = parent,
474 msg = msg,
475 caption = _('Showing drug brand components.'),
476 columns = [_('Brand'), _('Substance'), _('Strength'), _('Preparation'), _('Code'), u'#'],
477 single_selection = True,
478
479 edit_callback = edit,
480 delete_callback = delete,
481 refresh_callback = refresh
482 )
483
484
496
497
498 from Gnumed.wxGladeWidgets import wxgDrugComponentEAPnl
499
500 -class cDrugComponentEAPnl(wxgDrugComponentEAPnl.wxgDrugComponentEAPnl, gmEditArea.cGenericEditAreaMixin):
501
519
520
521
522
523
524
525
526
528 if self.data is not None:
529 if self.data['is_in_use']:
530 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit drug component. It is in use.'), beep = True)
531 return False
532
533 validity = True
534
535 if self._PRW_substance.GetData() is None:
536 validity = False
537 self._PRW_substance.display_as_valid(False)
538 else:
539 self._PRW_substance.display_as_valid(True)
540
541 val = self._TCTRL_amount.GetValue().strip().replace(',', u'.', 1)
542 try:
543 decimal.Decimal(val)
544 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True)
545 except:
546 validity = False
547 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False)
548
549 if self._PRW_unit.GetValue().strip() == u'':
550 validity = False
551 self._PRW_unit.display_as_valid(False)
552 else:
553 self._PRW_unit.display_as_valid(True)
554
555 if validity is False:
556 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save drug component. Invalid or missing essential input.'))
557
558 return validity
559
561
562 data = 1
563 data[''] = 1
564 data[''] = 1
565
566
567
568
569
570
571 return False
572 return True
573
575 self.data['pk_consumable_substance'] = self._PRW_substance.GetData(can_create = True)
576 self.data['amount'] = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', u'.', 1))
577 self.data['unit'] = self._PRW_unit.GetValue().strip()
578 return self.data.save()
579
589
591 self._TCTRL_brand.SetValue(u'%s (%s)' % (self.data['brand'], self.data['preparation']))
592 self._TCTRL_components.SetValue(u' / '.join(self.data.containing_drug['components']))
593 details = []
594 if self.data['atc_brand'] is not None:
595 details.append(u'ATC: %s' % self.data['atc_brand'])
596 if self.data['external_code_brand'] is not None:
597 details.append(u'%s: %s' % (self.data['external_code_type_brand'], self.data['external_code_brand']))
598 self._TCTRL_codes.SetValue(u'; '.join(details))
599
600 self._PRW_substance.SetText(self.data['substance'], self.data['pk_consumable_substance'])
601 self._TCTRL_amount.SetValue(u'%s' % self.data['amount'])
602 self._PRW_unit.SetText(self.data['unit'], self.data['unit'])
603
604 self._PRW_substance.SetFocus()
605
607
608
609
610 self._PRW_substance.SetText(u'', None)
611 self._TCTRL_amount.SetValue(u'')
612 self._PRW_unit.SetText(u'', None)
613
614 self._PRW_substance.SetFocus()
615
616
618
620
621 query = u"""
622 (
623 SELECT DISTINCT ON (preparation)
624 preparation as prep, preparation
625 FROM ref.branded_drug
626 WHERE preparation %(fragment_condition)s
627 ) UNION (
628 SELECT DISTINCT ON (preparation)
629 preparation as prep, preparation
630 FROM clin.substance_intake
631 WHERE preparation %(fragment_condition)s
632 )
633 ORDER BY prep
634 limit 30"""
635
636 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
637 mp.setThresholds(1, 2, 4)
638 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
639 self.SetToolTipString(_('The preparation (form) of the substance or brand.'))
640 self.matcher = mp
641 self.selection_only = False
642
644
646
647 query = u"""
648 (
649 SELECT
650 pk::text,
651 description as subst
652 --(description || coalesce(' [' || atc_code || ']', '')) as subst
653 FROM ref.consumable_substance
654 WHERE description %(fragment_condition)s
655
656 ) UNION (
657
658 SELECT
659 term,
660 term as subst
661 --NULL,
662 --(term || ' [' || atc || ']') as subst
663 FROM ref.v_atc
664 WHERE
665 is_group_code IS FALSE
666 AND
667 term %(fragment_condition)s
668 )
669 ORDER BY subst
670 LIMIT 50"""
671
672 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
673 mp.setThresholds(1, 2, 4)
674 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
675 self.SetToolTipString(_('The preparation (form) of the substance or brand in question.'))
676 self.matcher = mp
677 self.selection_only = False
678
679 - def GetData(self, can_create=False, as_instance=False):
680
681 if self.data is not None:
682 try:
683 int(self.data)
684 except ValueError:
685 self.data = None
686
687 return super(cSubstancePhraseWheel, self).GetData(can_create = can_create, as_instance = as_instance)
688
689
690
691
693
694 if parent is None:
695 parent = wx.GetApp().GetTopWindow()
696
697 def add_from_db(brand):
698 drug_db = get_drug_database(parent = parent)
699 if drug_db is None:
700 return False
701 drug_db.import_drugs()
702 return True
703
704 def edit(brand=None):
705 if brand is None:
706 return edit_branded_drug(parent = parent, branded_drug = brand, single_entry = False)
707
708 if brand.is_vaccine:
709 gmGuiHelpers.gm_show_info (
710 aTitle = _('Editing medication'),
711 aMessage = _(
712 'Cannot edit the medication\n'
713 '\n'
714 ' "%s" (%s)\n'
715 '\n'
716 'because it is a vaccine. Please edit it\n'
717 'from the vaccine management section !\n'
718 ) % (brand['brand'], brand['preparation'])
719 )
720 return False
721
722 return edit_branded_drug(parent = parent, branded_drug = brand, single_entry = True)
723
724 def delete(brand):
725 if brand.is_vaccine:
726 gmGuiHelpers.gm_show_info (
727 aTitle = _('Deleting medication'),
728 aMessage = _(
729 'Cannot delete the medication\n'
730 '\n'
731 ' "%s" (%s)\n'
732 '\n'
733 'because it is a vaccine. Please delete it\n'
734 'from the vaccine management section !\n'
735 ) % (brand['brand'], brand['preparation'])
736 )
737 return False
738 gmMedication.delete_branded_drug(brand = brand['pk_brand'])
739 return True
740
741 def new():
742
743
744 drug_db = get_drug_database(parent = parent)
745 if drug_db is None:
746 return False
747 drug_db.import_drugs()
748 return True
749
750 def refresh(lctrl):
751 drugs = gmMedication.get_branded_drugs()
752 items = [ [
753 u'%s%s' % (
754 d['brand'],
755 gmTools.bool2subst(d['is_fake_brand'], ' (%s)' % _('fake'), u'')
756 ),
757 d['preparation'],
758 gmTools.coalesce(d['atc'], u''),
759 gmTools.coalesce(d['components'], u''),
760 gmTools.coalesce(d['external_code'], u'', u'%%s [%s]' % d['external_code_type']),
761 d['pk_brand']
762 ] for d in drugs ]
763 lctrl.set_string_items(items)
764 lctrl.set_data(drugs)
765
766 msg = _('\nThese are the drug brands known to GNUmed.\n')
767
768 gmListWidgets.get_choices_from_list (
769 parent = parent,
770 msg = msg,
771 caption = _('Showing branded drugs.'),
772 columns = [_('Name'), _('Preparation'), _('ATC'), _('Components'), _('Code'), u'#'],
773 single_selection = True,
774 refresh_callback = refresh,
775 new_callback = edit,
776 edit_callback = edit,
777 delete_callback = delete,
778 left_extra_button = (_('Import'), _('Import consumable substances from a drug database.'), add_from_db)
779 )
780
781
793
794
795 from Gnumed.wxGladeWidgets import wxgBrandedDrugEAPnl
796
797 -class cBrandedDrugEAPnl(wxgBrandedDrugEAPnl.wxgBrandedDrugEAPnl, gmEditArea.cGenericEditAreaMixin):
798
816
817
818
819
820
821
822
823
824
826
827 if self.data is not None:
828 if self.data['is_in_use']:
829 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit drug brand. It is in use.'), beep = True)
830 return False
831
832 validity = True
833
834 if self._PRW_brand.GetData() is None:
835 validity = False
836 self._PRW_brand.display_as_valid(False)
837 else:
838 self._PRW_brand.display_as_valid(True)
839
840
841 if self._PRW_preparation.GetValue().strip() == u'':
842 validity = False
843 self._PRW_preparation.display_as_valid(False)
844 else:
845 self._PRW_preparation.display_as_valid(True)
846
847 if validity is False:
848 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save branded drug. Invalid or missing essential input.'))
849
850 return validity
851
853
854 data = 1
855
856 data[''] = 1
857 data[''] = 1
858
859 data.save()
860
861
862
863
864 self.data = data
865 return False
866 return True
867
869
870 self.data[''] = 1
871 self.data[''] = 1
872 self.data[''] = 1
873 self.data.save()
874 return True
875
877 self._PRW_brand.SetText(u'', None)
878 self._PRW_preparation.SetText(u'', None)
879 self._CHBOX_is_fake.SetValue(False)
880 self._TCTRL_components.SetValue(u'')
881 self._PRW_atc.SetText(u'', None)
882 self._TCTRL_external_code.SetValue(u'')
883 self._PRW_external_code_type.SetText(u'', None)
884
885 self._PRW_brand.SetFocus()
886
888 self._refresh_as_new()
889
902
903
904
906
908
909 query = u"""
910 SELECT
911 pk,
912 (description || ' (' || preparation || ')' || coalesce(' [' || atc_code || ']', ''))
913 AS brand
914 FROM ref.branded_drug
915 WHERE description %(fragment_condition)s
916 ORDER BY brand
917 LIMIT 50"""
918
919 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
920 mp.setThresholds(2, 3, 4)
921 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
922 self.SetToolTipString(_('The brand name of the drug.'))
923 self.matcher = mp
924 self.selection_only = False
925
926
927
928
930
932
933 query = u"""
934 SELECT DISTINCT ON (sched)
935 schedule as sched,
936 schedule
937 FROM clin.substance_intake
938 WHERE schedule %(fragment_condition)s
939 ORDER BY sched
940 LIMIT 50"""
941
942 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
943 mp.setThresholds(1, 2, 4)
944 mp.word_separators = '[ \t=+&:@]+'
945 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
946 self.SetToolTipString(_('The schedule for taking this substance.'))
947 self.matcher = mp
948 self.selection_only = False
949
950
951 from Gnumed.wxGladeWidgets import wxgCurrentMedicationEAPnl
952
953 -class cCurrentMedicationEAPnl(wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl, gmEditArea.cGenericEditAreaMixin):
954
971
976
978 emr = gmPerson.gmCurrentPatient().get_emr()
979
980 state = emr.allergy_state
981 if state['last_confirmed'] is None:
982 confirmed = _('never')
983 else:
984 confirmed = state['last_confirmed'].strftime('%Y %B %d').decode(gmI18N.get_encoding())
985 msg = _(u'%s, last confirmed %s\n') % (state.state_string, confirmed)
986 msg += gmTools.coalesce(state['comment'], u'', _('Comment (%s): %%s\n') % state['modified_by'])
987 msg += u'\n'
988
989 for allergy in emr.get_allergies():
990 msg += u'%s (%s, %s): %s\n' % (
991 allergy['descriptor'],
992 allergy['l10n_type'],
993 gmTools.bool2subst(allergy['definite'], _('definite'), _('suspected'), u'?'),
994 gmTools.coalesce(allergy['reaction'], _('reaction not recorded'))
995 )
996
997 self._LBL_allergies.SetLabel(msg)
998
1000
1001 if self._PRW_brand.GetData() is None:
1002 self._TCTRL_brand_ingredients.SetValue(u'')
1003 if self.data is None:
1004 return
1005 if self.data['pk_brand'] is None:
1006 return
1007 self._PRW_brand.SetText(self.data['brand'], self.data['pk_brand'])
1008
1009 brand = gmMedication.cBrandedDrug(aPK_obj = self._PRW_brand.GetData())
1010
1011 if self.data is None:
1012 self._PRW_preparation.SetText(brand['preparation'], None)
1013 else:
1014 self._PRW_preparation.SetText (
1015 gmTools.coalesce(self.data['preparation'], brand['preparation']),
1016 self.data['preparation']
1017 )
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029 if brand['components'] is None:
1030 self._TCTRL_brand_ingredients.SetValue(u'')
1031 else:
1032 self._TCTRL_brand_ingredients.SetValue(u' / '.join(brand['components']))
1033
1034
1035
1104
1106
1107 pk_brand = self._PRW_brand.GetData()
1108 brand = None
1109
1110 if pk_brand is None:
1111 prep = self._PRW_preparation.GetValue()
1112 if self._PRW_substance.GetData() is None:
1113 subst = self._PRW_substance.GetValue().strip()
1114 else:
1115
1116 subst = gmMedication.cConsumableSubstance(aPK_obj = self._PRW_substance.GetData())['description']
1117 substances = [
1118 [subst['description'], self._PRW_strength.GetValue()]
1119 ]
1120 else:
1121 brand = gmMedication.cBrandedDrug(aPK_obj = pk_brand)
1122 prep = brand['preparation']
1123 comps = brand.components
1124 if len(comps) == 1:
1125 substances = [
1126 [comps[0], self._PRW_strength.GetValue()]
1127 ]
1128 else:
1129
1130 print "missing"
1131
1132 emr = gmPerson.gmCurrentPatient().get_emr()
1133 epi = self._PRW_episode.GetData(can_create = True)
1134
1135
1136 last_intake = None
1137 for subst, strength in substances:
1138 intake = emr.add_substance_intake (
1139 substance = subst,
1140 episode = epi,
1141 preparation = prep
1142 )
1143 intake['strength'] = strength
1144 intake['started'] = self._DP_started.GetValue(as_pydt = True, invalid_as_none = True)
1145 intake['discontinued'] = self._DP_discontinued.GetValue(as_pydt = True, invalid_as_none = True)
1146 if intake['discontinued'] is None:
1147 intake['discontinue_reason'] = None
1148 else:
1149 intake['discontinue_reason'] = self._PRW_discontinue_reason().GetValue().strip()
1150 intake['schedule'] = self._PRW_schedule.GetValue()
1151 intake['aim'] = self._PRW_aim.GetValue()
1152 intake['notes'] = self._PRW_notes.GetValue()
1153 intake['is_long_term'] = self._CHBOX_long_term.IsChecked()
1154 intake['intake_is_approved_of'] = self._CHBOX_approved.IsChecked()
1155 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
1156 intake['duration'] = None
1157 else:
1158 intake['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue())
1159 intake['pk_brand'] = pk_brand
1160 intake.save()
1161 last_intake = intake
1162
1163 self.data = last_intake
1164
1165 if self._CHBOX_is_allergy.IsChecked():
1166 if brand is None:
1167 allg = self.data.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
1168 else:
1169 allg = brand.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
1170
1171 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = self, id = -1)
1172 dlg.ShowModal()
1173
1174 return True
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1211
1212 if self._PRW_substance.GetData() is None:
1213 self.data['pk_substance'] = gmMedication.create_consumable_substance (
1214 substance = self._PRW_substance.GetValue().strip()
1215 )['pk']
1216 else:
1217 self.data['pk_substance'] = self._PRW_substance.GetData()
1218
1219 self.data['started'] = self._DP_started.GetValue(as_pydt = True, invalid_as_none = True)
1220 self.data['discontinued'] = self._DP_discontinued.GetValue(as_pydt = True, invalid_as_none = True)
1221 if self.data['discontinued'] is None:
1222 self.data['discontinue_reason'] = None
1223 else:
1224 self.data['discontinue_reason'] = self._PRW_discontinue_reason.GetValue().strip()
1225 self.data['preparation'] = self._PRW_preparation.GetValue()
1226 self.data['strength'] = self._PRW_strength.GetValue()
1227 self.data['schedule'] = self._PRW_schedule.GetValue()
1228 self.data['aim'] = self._PRW_aim.GetValue()
1229 self.data['notes'] = self._PRW_notes.GetValue()
1230 self.data['is_long_term'] = self._CHBOX_long_term.IsChecked()
1231 self.data['intake_is_approved_of'] = self._CHBOX_approved.IsChecked()
1232 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True)
1233
1234 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
1235 self.data['duration'] = None
1236 else:
1237 self.data['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue())
1238
1239 if self._PRW_brand.GetData() is None:
1240 desc = self._PRW_brand.GetValue().strip()
1241 if desc != u'':
1242
1243 self.data['pk_brand'] = gmMedication.create_branded_drug (
1244 brand_name = desc,
1245 preparation = self._PRW_preparation.GetValue().strip(),
1246 return_existing = True
1247 )['pk']
1248 else:
1249 self.data['pk_brand'] = self._PRW_brand.GetData()
1250
1251 self.data.save()
1252
1253 if self._CHBOX_is_allergy.IsChecked():
1254 allg = self.data.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
1255
1256 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = self, id = -1)
1257 dlg.ShowModal()
1258
1259 return True
1260
1262 self._PRW_brand.SetText(u'', None)
1263 self._TCTRL_brand_ingredients.SetValue(u'')
1264
1265 self._PRW_substance.SetText(u'', None)
1266 self._PRW_substance.Enable(True)
1267
1268 self._PRW_strength.SetText(u'', None)
1269 self._PRW_strength.Enable(True)
1270
1271 self._PRW_preparation.SetText(u'', None)
1272 self._PRW_preparation.Enable(True)
1273
1274 self._PRW_schedule.SetText(u'', None)
1275 self._PRW_duration.SetText(u'', None)
1276 self._PRW_aim.SetText(u'', None)
1277 self._PRW_notes.SetText(u'', None)
1278 self._PRW_episode.SetText(u'', None)
1279
1280 self._CHBOX_long_term.SetValue(False)
1281 self._CHBOX_approved.SetValue(True)
1282
1283 self._DP_started.SetValue(gmDateTime.pydt_now_here())
1284 self._DP_discontinued.SetValue(None)
1285 self._PRW_discontinue_reason.SetValue(u'')
1286
1287
1288 self.__refresh_allergies()
1289
1290 self._PRW_brand.SetFocus()
1291
1293
1294 self._PRW_substance.SetText(self.data['substance'], self.data['pk_substance'])
1295 self._PRW_strength.SetText(gmTools.coalesce(self.data['strength'], u''), self.data['strength'])
1296 self._PRW_preparation.SetText(self.data['preparation'], self.data['preparation'])
1297
1298 if self.data['is_long_term']:
1299 self._CHBOX_long_term.SetValue(True)
1300 self._PRW_duration.Enable(False)
1301 self._PRW_duration.SetText(gmTools.u_infinity, None)
1302 self._BTN_discontinued_as_planned.Enable(False)
1303 else:
1304 self._CHBOX_long_term.SetValue(False)
1305 self._PRW_duration.Enable(True)
1306 self._BTN_discontinued_as_planned.Enable(True)
1307 if self.data['duration'] is None:
1308 self._PRW_duration.SetText(u'', None)
1309 else:
1310 self._PRW_duration.SetText(gmDateTime.format_interval(self.data['duration'], gmDateTime.acc_days), self.data['duration'])
1311 self._PRW_aim.SetText(gmTools.coalesce(self.data['aim'], u''), self.data['aim'])
1312 self._PRW_notes.SetText(gmTools.coalesce(self.data['notes'], u''), self.data['notes'])
1313 self._PRW_episode.SetData(self.data['pk_episode'])
1314 self._PRW_schedule.SetText(gmTools.coalesce(self.data['schedule'], u''), self.data['schedule'])
1315
1316 self._CHBOX_approved.SetValue(self.data['intake_is_approved_of'])
1317
1318 self._DP_started.SetValue(self.data['started'])
1319 self._DP_discontinued.SetValue(self.data['discontinued'])
1320 self._PRW_discontinue_reason.SetValue(gmTools.coalesce(self.data['discontinue_reason'], u''))
1321
1322 self.__refresh_brand_and_components()
1323 self.__refresh_allergies()
1324
1325 self._PRW_substance.SetFocus()
1326
1328 self._refresh_as_new()
1329
1330
1331
1333 if self._PRW_brand.GetData() is None:
1334 self._PRW_brand.SetText(u'', None)
1335 self._LBL_substance.Enable(True)
1336 self._PRW_substance.Enable(True)
1337 self._BTN_database_substance.Enable(True)
1338 self._LBL_strength.Enable(True)
1339 self._PRW_strength.Enable(True)
1340 self._LBL_preparation.Enable(True)
1341 self._PRW_preparation.Enable(True)
1342 self._PRW_preparation.SetText(u'', None)
1343 self._TCTRL_brand_ingredients.SetValue(u'')
1344 else:
1345 brand = gmMedication.cBrandedDrug(aPK_obj = self._PRW_brand.GetData())
1346 comps = brand.components
1347
1348 self._LBL_substance.Enable(False)
1349 self._PRW_substance.Enable(False)
1350 self._BTN_database_substance.Enable(False)
1351 if len(comps) == 1:
1352 self._LBL_strength.Enable(True)
1353 self._PRW_strength.Enable(True)
1354 else:
1355 self._LBL_strength.Enable(False)
1356 self._PRW_strength.Enable(False)
1357 self._LBL_preparation.Enable(False)
1358 self._PRW_preparation.Enable(False)
1359 self._PRW_preparation.SetText(brand['preparation'], None)
1360 self._TCTRL_brand_ingredients.SetValue(u' / '.join ([
1361 u'%s%s' % (
1362 c['description'],
1363 gmTools.coalesce(c['atc_code'], u'', u' (%s)')
1364 ) for c in comps
1365 ]))
1366
1368 if self._PRW_substance.GetValue().strip() == u'':
1369 self._PRW_brand.Enable(True)
1370 self._BTN_database_brand.Enable(True)
1371
1372 self._LBL_preparation.Enable(False)
1373 self._PRW_preparation.Enable(False)
1374 else:
1375 self._PRW_brand.SetText(u'', None)
1376 self._PRW_brand.Enable(False)
1377 self._BTN_database_brand.Enable(False)
1378 self._TCTRL_brand_ingredients.SetValue(u'')
1379
1380 self._LBL_strength.Enable(True)
1381 self._PRW_strength.Enable(True)
1382 self._LBL_preparation.Enable(True)
1383 self._PRW_preparation.Enable(True)
1384 self._PRW_preparation.SetText(u'', None)
1385
1387 if self._DP_discontinued.GetValue() is None:
1388 self._PRW_discontinue_reason.Enable(False)
1389 self._CHBOX_is_allergy.Enable(False)
1390
1391 else:
1392 self._PRW_discontinue_reason.Enable(True)
1393 self._CHBOX_is_allergy.Enable(True)
1394
1395
1414
1436
1465
1467 if self._CHBOX_long_term.IsChecked() is True:
1468 self._PRW_duration.Enable(False)
1469 self._BTN_discontinued_as_planned.Enable(False)
1470 self._PRW_discontinue_reason.Enable(False)
1471 self._CHBOX_is_allergy.Enable(False)
1472 else:
1473 self._PRW_duration.Enable(True)
1474 self._BTN_discontinued_as_planned.Enable(True)
1475 self._PRW_discontinue_reason.Enable(True)
1476 self._CHBOX_is_allergy.Enable(True)
1477
1478 self.__refresh_allergies()
1479
1481 if self._CHBOX_is_allergy.IsChecked() is True:
1482 val = self._PRW_discontinue_reason.GetValue().strip()
1483 if not val.startswith(_('not tolerated:')):
1484 self._PRW_discontinue_reason.SetValue(u'%s %s' % (_('not tolerated:'), val))
1485
1486 self.__refresh_allergies()
1487
1489
1490 subst = gmMedication.cSubstanceIntakeEntry(aPK_obj = substance)
1491 msg = _(
1492 '\n'
1493 '[%s]\n'
1494 '\n'
1495 'It may be prudent to edit (before deletion) the details\n'
1496 'of this substance intake entry so as to leave behind\n'
1497 'some indication of why it was deleted.\n'
1498 ) % subst.format()
1499
1500 dlg = gmGuiHelpers.c3ButtonQuestionDlg (
1501 parent,
1502 -1,
1503 caption = _('Deleting medication / substance intake'),
1504 question = msg,
1505 button_defs = [
1506 {'label': _('&Edit'), 'tooltip': _('Allow editing of substance intake entry before deletion.'), 'default': True},
1507 {'label': _('&Delete'), 'tooltip': _('Delete immediately without editing first.')},
1508 {'label': _('&Cancel'), 'tooltip': _('Abort. Do not delete or edit substance intake entry.')}
1509 ]
1510 )
1511
1512 edit_first = dlg.ShowModal()
1513 dlg.Destroy()
1514
1515 if edit_first == wx.ID_CANCEL:
1516 return
1517
1518 if edit_first == wx.ID_YES:
1519 edit_intake_of_substance(parent = parent, substance = subst)
1520 delete_it = gmGuiHelpers.gm_show_question (
1521 aMessage = _('Now delete substance intake entry ?'),
1522 aTitle = _('Deleting medication / substance intake')
1523 )
1524 else:
1525 delete_it = True
1526
1527 if not delete_it:
1528 return
1529
1530 gmMedication.delete_substance_intake(substance = substance)
1531
1533 ea = cCurrentMedicationEAPnl(parent = parent, id = -1, substance = substance)
1534 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = (substance is not None))
1535 dlg.SetTitle(gmTools.coalesce(substance, _('Adding substance intake'), _('Editing substance intake')))
1536 if dlg.ShowModal() == wx.ID_OK:
1537 dlg.Destroy()
1538 return True
1539 dlg.Destroy()
1540 return False
1541
1542
1543
1544
1572
1574
1575 if parent is None:
1576 parent = wx.GetApp().GetTopWindow()
1577
1578
1579 dbcfg = gmCfg.cCfgSQL()
1580 option = u'form_templates.medication_list'
1581
1582 template = dbcfg.get2 (
1583 option = option,
1584 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1585 bias = 'user'
1586 )
1587
1588 if template is None:
1589 template = configure_medication_list_template(parent = parent)
1590 if template is None:
1591 gmGuiHelpers.gm_show_error (
1592 aMessage = _('There is no medication list template configured.'),
1593 aTitle = _('Printing medication list')
1594 )
1595 return False
1596 else:
1597 try:
1598 name, ver = template.split(u' - ')
1599 except:
1600 _log.exception('problem splitting medication list template name [%s]', template)
1601 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading medication list template.'), beep = True)
1602 return False
1603 template = gmForms.get_form_template(name_long = name, external_version = ver)
1604 if template is None:
1605 gmGuiHelpers.gm_show_error (
1606 aMessage = _('Cannot load medication list template [%s - %s]') % (name, ver),
1607 aTitle = _('Printing medication list')
1608 )
1609 return False
1610
1611
1612 try:
1613 meds_list = template.instantiate()
1614 except KeyError:
1615 _log.exception('cannot instantiate medication list template [%s]', template)
1616 gmGuiHelpers.gm_show_error (
1617 aMessage = _('Invalid medication list template [%s - %s (%s)]') % (name, ver, template['engine']),
1618 aTitle = _('Printing medication list')
1619 )
1620 return False
1621
1622 ph = gmMacro.gmPlaceholderHandler()
1623
1624 meds_list.substitute_placeholders(data_source = ph)
1625 pdf_name = meds_list.generate_output(cleanup = cleanup)
1626 if cleanup:
1627 meds_list.cleanup()
1628 if pdf_name is None:
1629 gmGuiHelpers.gm_show_error (
1630 aMessage = _('Error generating the medication list.'),
1631 aTitle = _('Printing medication list')
1632 )
1633 return False
1634
1635
1636 printed = gmPrinting.print_file_by_shellscript(filename = pdf_name, jobtype = 'medication_list')
1637 if not printed:
1638 gmGuiHelpers.gm_show_error (
1639 aMessage = _('Error printing the medication list.'),
1640 aTitle = _('Printing medication list')
1641 )
1642 return False
1643
1644 pat = gmPerson.gmCurrentPatient()
1645 emr = pat.get_emr()
1646 epi = emr.add_episode(episode_name = 'administration', is_open = False)
1647 emr.add_clin_narrative (
1648 soap_cat = None,
1649 note = _('medication list printed from template [%s - %s]') % (template['name_long'], template['external_version']),
1650 episode = epi
1651 )
1652
1653 return True
1654
1656 """A grid class for displaying current substance intake.
1657
1658 - does NOT listen to the currently active patient
1659 - thereby it can display any patient at any time
1660 """
1662
1663 wx.grid.Grid.__init__(self, *args, **kwargs)
1664
1665 self.__patient = None
1666 self.__row_data = {}
1667 self.__prev_row = None
1668 self.__prev_tooltip_row = None
1669 self.__prev_cell_0 = None
1670 self.__grouping_mode = u'episode'
1671 self.__filter_show_unapproved = False
1672 self.__filter_show_inactive = False
1673
1674 self.__grouping2col_labels = {
1675 u'episode': [
1676 _('Episode'),
1677 _('Substance'),
1678 _('Dose'),
1679 _('Schedule'),
1680 _('Started'),
1681 _('Duration'),
1682 _('Brand')
1683 ],
1684 u'brand': [
1685 _('Brand'),
1686 _('Schedule'),
1687 _('Substance'),
1688 _('Dose'),
1689 _('Started'),
1690 _('Duration'),
1691 _('Episode')
1692 ]
1693 }
1694
1695 self.__grouping2order_by_clauses = {
1696 u'episode': u'pk_health_issue nulls first, episode, substance, started',
1697 u'brand': u'brand nulls last, substance, started'
1698 }
1699
1700 self.__init_ui()
1701 self.__register_events()
1702
1703
1704
1706
1707 sel_block_top_left = self.GetSelectionBlockTopLeft()
1708 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
1709 sel_cols = self.GetSelectedCols()
1710 sel_rows = self.GetSelectedRows()
1711
1712 selected_cells = []
1713
1714
1715 selected_cells += self.GetSelectedCells()
1716
1717
1718 selected_cells += list (
1719 (row, col)
1720 for row in sel_rows
1721 for col in xrange(self.GetNumberCols())
1722 )
1723
1724
1725 selected_cells += list (
1726 (row, col)
1727 for row in xrange(self.GetNumberRows())
1728 for col in sel_cols
1729 )
1730
1731
1732 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
1733 selected_cells += [
1734 (row, col)
1735 for row in xrange(top_left[0], bottom_right[0] + 1)
1736 for col in xrange(top_left[1], bottom_right[1] + 1)
1737 ]
1738
1739 return set(selected_cells)
1740
1742 rows = {}
1743
1744 for row, col in self.get_selected_cells():
1745 rows[row] = True
1746
1747 return rows.keys()
1748
1751
1753
1754 self.empty_grid()
1755
1756 if self.__patient is None:
1757 return
1758
1759 emr = self.__patient.get_emr()
1760 meds = emr.get_current_substance_intake (
1761 order_by = self.__grouping2order_by_clauses[self.__grouping_mode],
1762 include_unapproved = self.__filter_show_unapproved,
1763 include_inactive = self.__filter_show_inactive
1764 )
1765 if not meds:
1766 return
1767
1768 self.BeginBatch()
1769
1770
1771 labels = self.__grouping2col_labels[self.__grouping_mode]
1772 if self.__filter_show_unapproved:
1773 self.AppendCols(numCols = len(labels) + 1)
1774 else:
1775 self.AppendCols(numCols = len(labels))
1776 for col_idx in range(len(labels)):
1777 self.SetColLabelValue(col_idx, labels[col_idx])
1778 if self.__filter_show_unapproved:
1779 self.SetColLabelValue(len(labels), u'OK?')
1780 self.SetColSize(len(labels), 40)
1781
1782 self.AppendRows(numRows = len(meds))
1783
1784
1785 for row_idx in range(len(meds)):
1786 med = meds[row_idx]
1787 self.__row_data[row_idx] = med
1788
1789 if med['is_currently_active'] is True:
1790 atcs = []
1791 if med['atc_substance'] is not None:
1792 atcs.append(med['atc_substance'])
1793
1794
1795
1796 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (med['substance'],))
1797 if allg not in [None, False]:
1798 attr = self.GetOrCreateCellAttr(row_idx, 0)
1799 if allg['type'] == u'allergy':
1800 attr.SetTextColour('red')
1801 else:
1802 attr.SetTextColour('yellow')
1803 self.SetRowAttr(row_idx, attr)
1804 else:
1805 attr = self.GetOrCreateCellAttr(row_idx, 0)
1806 attr.SetTextColour('grey')
1807 self.SetRowAttr(row_idx, attr)
1808
1809 if self.__grouping_mode == u'episode':
1810 if med['pk_episode'] is None:
1811 self.__prev_cell_0 = None
1812 self.SetCellValue(row_idx, 0, gmTools.u_diameter)
1813 else:
1814 if self.__prev_cell_0 != med['episode']:
1815 self.__prev_cell_0 = med['episode']
1816 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['episode'], u''))
1817
1818 self.SetCellValue(row_idx, 1, med['substance'])
1819 self.SetCellValue(row_idx, 2, u'%s%s' % (med['amount'], med['unit']))
1820 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['schedule'], u''))
1821 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1822
1823 if med['is_long_term']:
1824 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1825 else:
1826 if med['duration'] is None:
1827 self.SetCellValue(row_idx, 5, u'')
1828 else:
1829 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1830
1831 if med['pk_brand'] is None:
1832 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u''))
1833 else:
1834 if med['fake_brand']:
1835 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u'', _('%s (fake)')))
1836 else:
1837 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u''))
1838
1839 elif self.__grouping_mode == u'brand':
1840
1841 if med['pk_brand'] is None:
1842 self.__prev_cell_0 = None
1843 self.SetCellValue(row_idx, 0, gmTools.u_diameter)
1844 else:
1845 if self.__prev_cell_0 != med['brand']:
1846 self.__prev_cell_0 = med['brand']
1847 if med['fake_brand']:
1848 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['brand'], u'', _('%s (fake)')))
1849 else:
1850 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['brand'], u''))
1851
1852 self.SetCellValue(row_idx, 1, gmTools.coalesce(med['schedule'], u''))
1853 self.SetCellValue(row_idx, 2, med['substance'])
1854 self.SetCellValue(row_idx, 3, u'%s%s' % (med['amount'], med['unit']))
1855 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1856
1857 if med['is_long_term']:
1858 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1859 else:
1860 if med['duration'] is None:
1861 self.SetCellValue(row_idx, 5, u'')
1862 else:
1863 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1864
1865 if med['pk_episode'] is None:
1866 self.SetCellValue(row_idx, 6, u'')
1867 else:
1868 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['episode'], u''))
1869
1870 else:
1871 raise ValueError('unknown grouping mode [%s]' % self.__grouping_mode)
1872
1873 if self.__filter_show_unapproved:
1874 self.SetCellValue (
1875 row_idx,
1876 len(labels),
1877 gmTools.bool2subst(med['intake_is_approved_of'], gmTools.u_checkmark_thin, u'', u'?')
1878 )
1879
1880
1881
1882 self.EndBatch()
1883
1885 self.BeginBatch()
1886 self.ClearGrid()
1887
1888
1889 if self.GetNumberRows() > 0:
1890 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
1891 if self.GetNumberCols() > 0:
1892 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
1893 self.EndBatch()
1894 self.__row_data = {}
1895 self.__prev_cell_0 = None
1896
1898
1899 if len(self.__row_data) == 0:
1900 return
1901
1902 sel_rows = self.get_selected_rows()
1903 if len(sel_rows) != 1:
1904 return
1905
1906 drug_db = get_drug_database()
1907 if drug_db is None:
1908 return
1909
1910 drug_db.show_info_on_substance(substance = self.get_selected_data()[0])
1911
1927
1940
1954
1957
1971
1973
1974 rows = self.get_selected_rows()
1975
1976 if len(rows) == 0:
1977 return
1978
1979 if len(rows) > 1:
1980 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete more than one substance at once.'), beep = True)
1981 return
1982
1983 subst = self.get_selected_data()[0]
1984 delete_substance_intake(parent = self, substance = subst['pk_substance_intake'])
1985
2007
2012
2116
2117
2118
2120 self.CreateGrid(0, 1)
2121 self.EnableEditing(0)
2122 self.EnableDragGridSize(1)
2123 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
2124
2125 self.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTER)
2126
2127 self.SetRowLabelSize(0)
2128 self.SetRowLabelAlignment(horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
2129
2130
2131
2133 return self.__patient
2134
2138
2139 patient = property(_get_patient, _set_patient)
2140
2142 return self.__grouping_mode
2143
2147
2148 grouping_mode = property(_get_grouping_mode, _set_grouping_mode)
2149
2151 return self.__filter_show_unapproved
2152
2156
2157 filter_show_unapproved = property(_get_filter_show_unapproved, _set_filter_show_unapproved)
2158
2160 return self.__filter_show_inactive
2161
2165
2166 filter_show_inactive = property(_get_filter_show_inactive, _set_filter_show_inactive)
2167
2168
2169
2171
2172 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
2173
2174
2175
2176
2177 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
2178
2180 """Calculate where the mouse is and set the tooltip dynamically."""
2181
2182
2183
2184 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198 row, col = self.XYToCell(x, y)
2199
2200 if row == self.__prev_tooltip_row:
2201 return
2202
2203 self.__prev_tooltip_row = row
2204
2205 try:
2206 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
2207 except KeyError:
2208 pass
2209
2214
2215 from Gnumed.wxGladeWidgets import wxgCurrentSubstancesPnl
2216
2217 -class cCurrentSubstancesPnl(wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl, gmRegetMixin.cRegetOnPaintMixin):
2218
2219 """Panel holding a grid with current substances. Used as notebook page."""
2220
2227
2228
2229
2238
2239
2240
2242 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
2243 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._schedule_data_reget)
2244 gmDispatcher.connect(signal = u'substance_intake_mod_db', receiver = self._schedule_data_reget)
2245
2246
2247
2249 wx.CallAfter(self.__on_pre_patient_selection)
2250
2252 self._grid_substances.patient = None
2253
2256
2259
2262
2265
2268
2271
2274
2277
2280
2283
2286
2289
2292
2293
2294
2295 if __name__ == '__main__':
2296
2297 if len(sys.argv) < 2:
2298 sys.exit()
2299
2300 if sys.argv[1] != 'test':
2301 sys.exit()
2302
2303 from Gnumed.pycommon import gmI18N
2304
2305 gmI18N.activate_locale()
2306 gmI18N.install_domain(domain = 'gnumed')
2307
2308
2309 app = wx.PyWidgetTester(size = (600, 600))
2310 app.SetWidget(cATCPhraseWheel, -1)
2311 app.MainLoop()
2312
2313
2314