1 """GNUmed medication/substances handling widgets.
2 """
3
4
5
6 __version__ = "$Revision: 1.32 $"
7 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
8
9 import logging, sys, os.path
10
11
12 import wx, wx.grid
13
14
15 if __name__ == '__main__':
16 sys.path.insert(0, '../../')
17 from Gnumed.pycommon import gmDispatcher, gmCfg, gmShellAPI, gmTools, gmDateTime
18 from Gnumed.pycommon import gmMatchProvider, gmI18N, gmPrinting, gmCfg2
19 from Gnumed.business import gmPerson, gmATC, gmSurgery, gmMedication, gmForms
20 from Gnumed.wxpython import gmGuiHelpers, gmRegetMixin, gmAuthWidgets, gmEditArea, gmMacro
21 from Gnumed.wxpython import gmCfgWidgets, gmListWidgets, gmPhraseWheel, gmFormWidgets
22
23
24 _log = logging.getLogger('gm.ui')
25 _log.info(__version__)
26
28
29 if parent is None:
30 parent = wx.GetApp().GetTopWindow()
31
32
33 def delete(component):
34 gmMedication.delete_component_from_branded_drug (
35 brand = component['pk_brand'],
36 component = component['pk_substance_in_brand']
37 )
38 return True
39
40 def refresh(lctrl):
41 substs = gmMedication.get_substances_in_brands()
42 items = [ [
43 u'%s%s' % (s['brand'], gmTools.coalesce(s['atc_brand'], u'', u' (%s)')),
44 s['substance'],
45 gmTools.coalesce(s['atc_substance'], u''),
46 s['preparation'],
47 gmTools.coalesce(s['external_code_brand'], u''),
48 s['pk_substance_in_brand']
49 ] for s in substs ]
50 lctrl.set_string_items(items)
51 lctrl.set_data(substs)
52
53 msg = _('\nThese are the substances in the drug brands known to GNUmed.\n')
54
55 gmListWidgets.get_choices_from_list (
56 parent = parent,
57 msg = msg,
58 caption = _('Showing drug brand components (substances).'),
59 columns = [_('Brand'), _('Substance'), u'ATC', _('Preparation'), _('Code'), u'#'],
60 single_selection = True,
61
62
63 delete_callback = delete,
64 refresh_callback = refresh
65 )
66
68
69 if parent is None:
70 parent = wx.GetApp().GetTopWindow()
71
72 def delete(brand):
73 gmMedication.delete_branded_drug(brand = brand['pk'])
74 return True
75
76 def new():
77 drug_db = get_drug_database(parent = parent)
78
79 if drug_db is None:
80 return False
81
82 drug_db.import_drugs()
83
84 return True
85
86 def refresh(lctrl):
87 drugs = gmMedication.get_branded_drugs()
88 items = [ [
89 d['description'],
90 d['preparation'],
91 gmTools.coalesce(d['atc_code'], u''),
92 gmTools.coalesce(d['external_code'], u''),
93 d['pk']
94 ] for d in drugs ]
95 lctrl.set_string_items(items)
96 lctrl.set_data(drugs)
97
98 msg = _('\nThese are the drug brands known to GNUmed.\n')
99
100 gmListWidgets.get_choices_from_list (
101 parent = parent,
102 msg = msg,
103 caption = _('Showing branded drugs.'),
104 columns = [_('Name'), _('Preparation'), _('ATC'), _('Code'), u'#'],
105 single_selection = True,
106 refresh_callback = refresh,
107 new_callback = new,
108
109 delete_callback = delete
110 )
111
113
114 if parent is None:
115 parent = wx.GetApp().GetTopWindow()
116
117 def delete(substance):
118 gmMedication.delete_used_substance(substance = substance['pk'])
119 return True
120
121 def new():
122 drug_db = get_drug_database(parent = parent)
123
124 if drug_db is None:
125 return False
126
127 drug_db.import_drugs()
128
129 return True
130
131 def refresh(lctrl):
132 substs = gmMedication.get_substances_in_use()
133 items = [ [
134 s['description'],
135 gmTools.coalesce(s['atc_code'], u''),
136 s['pk']
137 ] for s in substs ]
138 lctrl.set_string_items(items)
139 lctrl.set_data(substs)
140
141 msg = _('\nThese are the substances currently or previously\nconsumed across all patients.\n')
142
143 gmListWidgets.get_choices_from_list (
144 parent = parent,
145 msg = msg,
146 caption = _('Showing consumed substances.'),
147 columns = [_('Name'), _('ATC'), u'#'],
148 single_selection = True,
149 refresh_callback = refresh,
150 new_callback = new,
151
152 delete_callback = delete
153 )
154
155
156
174
204
211
213
214 dbcfg = gmCfg.cCfgSQL()
215
216 ifap_cmd = dbcfg.get2 (
217 option = 'external.ifap-win.shell_command',
218 workplace = gmSurgery.gmCurrentPractice().active_workplace,
219 bias = 'workplace',
220 default = 'wine "C:\Ifapwin\WIAMDB.EXE"'
221 )
222 found, binary = gmShellAPI.detect_external_binary(ifap_cmd)
223 if not found:
224 gmDispatcher.send('statustext', msg = _('Cannot call IFAP via [%s].') % ifap_cmd)
225 return False
226 ifap_cmd = binary
227
228 if import_drugs:
229 transfer_file = os.path.expanduser(dbcfg.get2 (
230 option = 'external.ifap-win.transfer_file',
231 workplace = gmSurgery.gmCurrentPractice().active_workplace,
232 bias = 'workplace',
233 default = '~/.wine/drive_c/Ifapwin/ifap2gnumed.csv'
234 ))
235
236 try:
237 f = open(transfer_file, 'w+b').close()
238 except IOError:
239 _log.exception('Cannot create IFAP <-> GNUmed transfer file [%s]', transfer_file)
240 gmDispatcher.send('statustext', msg = _('Cannot create IFAP <-> GNUmed transfer file [%s].') % transfer_file)
241 return False
242
243 wx.BeginBusyCursor()
244 gmShellAPI.run_command_in_shell(command = ifap_cmd, blocking = import_drugs)
245 wx.EndBusyCursor()
246
247 if import_drugs:
248
249
250 try:
251 csv_file = open(transfer_file, 'rb')
252 except:
253 _log.exception('cannot access [%s]', fname)
254 csv_file = None
255
256 if csv_file is not None:
257 import csv
258 csv_lines = csv.DictReader (
259 csv_file,
260 fieldnames = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split(),
261 delimiter = ';'
262 )
263 pat = gmPerson.gmCurrentPatient()
264 emr = pat.get_emr()
265
266 epi = emr.add_episode(episode_name = _('Current medication'))
267 for line in csv_lines:
268 narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % (
269 line['Packungszahl'].strip(),
270 line['Handelsname'].strip(),
271 line['Form'].strip(),
272 line[u'Packungsgr\xf6\xdfe'].strip(),
273 line['Abpackungsmenge'].strip(),
274 line['Einheit'].strip(),
275 line['Hersteller'].strip(),
276 line['PZN'].strip()
277 )
278 emr.add_clin_narrative(note = narr, soap_cat = 's', episode = epi)
279 csv_file.close()
280
281 return True
282
284
285 dlg = wx.FileDialog (
286 parent = None,
287 message = _('Choose an ATC import config file'),
288 defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')),
289 defaultFile = '',
290 wildcard = "%s (*.conf)|*.conf|%s (*)|*" % (_('config files'), _('all files')),
291 style = wx.OPEN | wx.HIDE_READONLY | wx.FILE_MUST_EXIST
292 )
293
294 result = dlg.ShowModal()
295 if result == wx.ID_CANCEL:
296 return
297
298 cfg_file = dlg.GetPath()
299 dlg.Destroy()
300
301 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('importing ATC reference data'))
302 if conn is None:
303 return False
304
305 wx.BeginBusyCursor()
306
307 if gmATC.atc_import(cfg_fname = cfg_file, conn = conn):
308 gmDispatcher.send(signal = 'statustext', msg = _('Successfully imported ATC reference data.'))
309 else:
310 gmDispatcher.send(signal = 'statustext', msg = _('Importing ATC reference data failed.'), beep = True)
311
312 wx.EndBusyCursor()
313 return True
314
315
316
317
319
321
322 query = u"""
323 SELECT schedule as sched, schedule
324 FROM clin.substance_intake
325 where schedule %(fragment_condition)s
326 ORDER BY sched
327 LIMIT 50"""
328
329 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
330 mp.setThresholds(1, 2, 4)
331 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
332 self.SetToolTipString(_('The schedule for taking this substance.'))
333 self.matcher = mp
334 self.selection_only = False
335
337
339
340 query = u"""
341 (
342 SELECT preparation as prep, preparation
343 FROM ref.branded_drug
344 where preparation %(fragment_condition)s
345 ) union (
346 SELECT preparation as prep, preparation
347 FROM clin.substance_intake
348 where preparation %(fragment_condition)s
349 )
350 order by prep
351 limit 30"""
352
353 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
354 mp.setThresholds(1, 2, 4)
355 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
356 self.SetToolTipString(_('The preparation (form) of the substance the patient is taking.'))
357 self.matcher = mp
358 self.selection_only = False
359
361
363
364 query = u"""
365 (
366 SELECT pk, (coalesce(atc_code || ': ', '') || description) as subst
367 FROM clin.consumed_substance
368 WHERE description %(fragment_condition)s
369 ) union (
370 SELECT NULL, (coalesce(atc_code || ': ', '') || description) as subst
371 FROM ref.substance_in_brand
372 WHERE description %(fragment_condition)s
373 )
374 order by subst
375 limit 50"""
376
377 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
378 mp.setThresholds(1, 2, 4)
379 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
380 self.SetToolTipString(_('The INN / substance the patient is taking.'))
381 self.matcher = mp
382 self.selection_only = False
383
385
387
388 query = u"""
389 SELECT pk, (coalesce(atc_code || ': ', '') || description || ' (' || preparation || ')') as brand
390 FROM ref.branded_drug
391 WHERE description %(fragment_condition)s
392 ORDER BY brand
393 LIMIT 50"""
394
395 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
396 mp.setThresholds(2, 3, 4)
397 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
398 self.SetToolTipString(_('The brand name of the drug the patient is taking.'))
399 self.matcher = mp
400 self.selection_only = False
401
402
403 from Gnumed.wxGladeWidgets import wxgCurrentMedicationEAPnl
404
405 -class cCurrentMedicationEAPnl(wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl, gmEditArea.cGenericEditAreaMixin):
406
423
429
430
431
432
472
546
585
605
607
608 self._PRW_substance.SetText(self.data['substance'], self.data['pk_substance'])
609 self._PRW_strength.SetText(gmTools.coalesce(self.data['strength'], u''), self.data['strength'])
610 self._PRW_preparation.SetText(gmTools.coalesce(self.data['preparation'], u''), self.data['preparation'])
611 if self.data['is_long_term']:
612 self._CHBOX_long_term.SetValue(True)
613 self._PRW_duration.Enable(False)
614 self._PRW_duration.SetText(gmTools.u_infinity, None)
615 else:
616 self._CHBOX_long_term.SetValue(False)
617 self._PRW_duration.Enable(True)
618 if self.data['duration'] is None:
619 self._PRW_duration.SetText(u'', None)
620 else:
621 self._PRW_duration.SetText(gmDateTime.format_interval(self.data['duration'], gmDateTime.acc_days), self.data['duration'])
622 self._PRW_aim.SetText(gmTools.coalesce(self.data['aim'], u''), self.data['aim'])
623 self._PRW_notes.SetText(gmTools.coalesce(self.data['notes'], u''), self.data['notes'])
624 self._PRW_episode.SetData(self.data['pk_episode'])
625 self._PRW_schedule.SetText(gmTools.coalesce(self.data['schedule'], u''), self.data['schedule'])
626
627 self._CHBOX_approved.SetValue(self.data['intake_is_approved_of'])
628
629 self._DP_started.SetValue(gmDateTime.py_dt2wxDate(py_dt = self.data['started'], wx = wx))
630
631 self._PRW_brand.SetText(u'', None)
632 self._TCTRL_brand_ingredients.SetValue(u'')
633 if self.data['pk_brand'] is not None:
634 brand = gmMedication.cBrandedDrug(aPK_obj = self.data['pk_brand'])
635 self._PRW_brand.SetText(brand['description'], self.data['pk_brand'])
636 comps = brand.components
637 if comps is not None:
638 comps = u' / '.join([ u'%s%s' % (c['description'], gmTools.coalesce(c['atc_code'], u'', u' (%s)')) for c in comps ])
639 self._TCTRL_brand_ingredients.SetValue(comps)
640
641 self._PRW_substance.SetFocus()
642
644 self._refresh_as_new()
645
646 self._PRW_substance.SetText(u'', None)
647 self._PRW_strength.SetText(u'', None)
648 self._PRW_notes.SetText(u'', None)
649
650 self._PRW_substance.SetFocus()
651
652
653
655 self._TCTRL_brand_ingredients.SetValue(u'')
656
657 pk_brand = self._PRW_brand.GetData()
658 if pk_brand is None:
659 return
660
661 brand = gmMedication.cBrandedDrug(aPK_obj = pk_brand)
662 self._PRW_preparation.SetText(brand['preparation'], None)
663
664 comps = brand.components
665 if comps is None:
666 return
667 comps = u' / '.join([ u'%s%s' % (c['description'], gmTools.coalesce(c['atc_code'], u'', u' (%s)')) for c in comps ])
668 self._TCTRL_brand_ingredients.SetValue(comps)
669
685
701
703 if self._CHBOX_long_term.IsChecked() is True:
704 self._PRW_duration.Enable(False)
705 else:
706 self._PRW_duration.Enable(True)
707
709 delete_it = gmGuiHelpers.gm_show_question (
710 aMessage = _(
711 'Do you really want to remove this substance intake ?\n'
712 '\n'
713 'It may be prudent to edit the details first so as to\n'
714 'leave behind some indication of why it was deleted.\n'
715 ),
716 aTitle = _('Deleting medication / substance intake')
717 )
718 if not delete_it:
719 return
720
721 gmMedication.delete_substance_intake(substance = substance)
722
732
733
734
755
757
758 if parent is None:
759 parent = wx.GetApp().GetTopWindow()
760
761
762 dbcfg = gmCfg.cCfgSQL()
763 option = u'form_templates.medication_list'
764
765 template = dbcfg.get2 (
766 option = option,
767 workplace = gmSurgery.gmCurrentPractice().active_workplace,
768 bias = 'user'
769 )
770
771 if template is None:
772 template = configure_medication_list_template(parent = parent)
773 if template is None:
774 gmGuiHelpers.gm_show_error (
775 aMessage = _('There is no medication list template configured.'),
776 aTitle = _('Printing medication list')
777 )
778 return False
779 else:
780 try:
781 name, ver = template.split(u' - ')
782 except:
783 _log.exception('problem splitting medication list template name [%s]', template)
784 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading medication list template.'), beep = True)
785 return False
786 template = gmForms.get_form_template(name_long = name, external_version = ver)
787 if template is None:
788 gmGuiHelpers.gm_show_error (
789 aMessage = _('Cannot load medication list template [%s - %s]') % (name, ver),
790 aTitle = _('Printing medication list')
791 )
792 return False
793
794
795 meds_list = template.instantiate()
796 ph = gmMacro.gmPlaceholderHandler()
797
798 meds_list.substitute_placeholders(data_source = ph)
799 pdf_name = meds_list.generate_output(cleanup = cleanup)
800 if cleanup:
801 meds_list.cleanup()
802 if pdf_name is None:
803 gmGuiHelpers.gm_show_error (
804 aMessage = _('Error generating the medication list.'),
805 aTitle = _('Printing medication list')
806 )
807 return False
808
809
810 printed = gmPrinting.print_file_by_shellscript(filename = pdf_name, jobtype = 'medication_list')
811 if not printed:
812 gmGuiHelpers.gm_show_error (
813 aMessage = _('Error printing the medication list.'),
814 aTitle = _('Printing medication list')
815 )
816 return False
817
818 pat = gmPerson.gmCurrentPatient()
819 emr = pat.get_emr()
820 epi = emr.add_episode(episode_name = 'administration', is_open = False)
821 emr.add_clin_narrative (
822 soap_cat = None,
823 note = _('medication list printed from template [%s - %s]') % (template['name_long'], template['external_version']),
824 episode = epi
825 )
826
827 return True
828
830 """A grid class for displaying current substance intake.
831
832 - does NOT listen to the currently active patient
833 - thereby it can display any patient at any time
834 """
836
837 wx.grid.Grid.__init__(self, *args, **kwargs)
838
839 self.__patient = None
840 self.__row_data = {}
841 self.__row_tooltips = {}
842 self.__prev_row = None
843 self.__prev_tooltip_row = None
844 self.__prev_cell_0 = None
845 self.__grouping_mode = u'episode'
846 self.__filter_show_unapproved = False
847 self.__filter_show_inactive = False
848
849 self.__grouping2col_labels = {
850 u'episode': [
851 _('Episode'),
852 _('Substance'),
853 _('Dose'),
854 _('Schedule'),
855 _('Started'),
856 _('Duration'),
857 _('Brand')
858 ],
859 u'brand': [
860 _('Brand'),
861 _('Schedule'),
862 _('Substance'),
863 _('Dose'),
864 _('Started'),
865 _('Duration'),
866 _('Episode')
867 ]
868 }
869
870 self.__grouping2order_by_clauses = {
871 u'episode': u'pk_health_issue nulls first, episode, substance, started',
872 u'brand': u'brand nulls last, substance, started'
873 }
874
875 self.__init_ui()
876 self.__register_events()
877
878
879
881
882 sel_block_top_left = self.GetSelectionBlockTopLeft()
883 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
884 sel_cols = self.GetSelectedCols()
885 sel_rows = self.GetSelectedRows()
886
887 selected_cells = []
888
889
890 selected_cells += self.GetSelectedCells()
891
892
893 selected_cells += list (
894 (row, col)
895 for row in sel_rows
896 for col in xrange(self.GetNumberCols())
897 )
898
899
900 selected_cells += list (
901 (row, col)
902 for row in xrange(self.GetNumberRows())
903 for col in sel_cols
904 )
905
906
907 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
908 selected_cells += [
909 (row, col)
910 for row in xrange(top_left[0], bottom_right[0] + 1)
911 for col in xrange(top_left[1], bottom_right[1] + 1)
912 ]
913
914 return set(selected_cells)
915
917 rows = {}
918
919 for row, col in self.get_selected_cells():
920 rows[row] = True
921
922 return rows.keys()
923
926
928
929 self.empty_grid()
930
931 if self.__patient is None:
932 return
933
934 emr = self.__patient.get_emr()
935 meds = emr.get_current_substance_intake (
936 order_by = self.__grouping2order_by_clauses[self.__grouping_mode],
937 include_unapproved = self.__filter_show_unapproved,
938 include_inactive = self.__filter_show_inactive
939 )
940 if not meds:
941 return
942
943 self.BeginBatch()
944
945
946 labels = self.__grouping2col_labels[self.__grouping_mode]
947 if self.__filter_show_unapproved:
948 self.AppendCols(numCols = len(labels) + 1)
949 else:
950 self.AppendCols(numCols = len(labels))
951 for col_idx in range(len(labels)):
952 self.SetColLabelValue(col_idx, labels[col_idx])
953 if self.__filter_show_unapproved:
954 self.SetColLabelValue(len(labels), u'OK?')
955 self.SetColSize(len(labels), 40)
956
957 self.AppendRows(numRows = len(meds))
958
959
960 for row_idx in range(len(meds)):
961 med = meds[row_idx]
962 self.__row_data[row_idx] = med
963
964 if med['is_currently_active'] is not True:
965 attr = self.GetOrCreateCellAttr(row_idx, 0)
966 attr.SetTextColour('grey')
967 self.SetRowAttr(row_idx, attr)
968
969 if self.__grouping_mode == u'episode':
970 if med['pk_episode'] is None:
971 self.__prev_cell_0 = None
972 self.SetCellValue(row_idx, 0, gmTools.u_diameter)
973 else:
974 if self.__prev_cell_0 != med['episode']:
975 self.__prev_cell_0 = med['episode']
976 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['episode'], u''))
977
978 self.SetCellValue(row_idx, 1, med['substance'])
979 self.SetCellValue(row_idx, 2, gmTools.coalesce(med['strength'], u''))
980 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['schedule'], u''))
981 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
982
983 if med['is_long_term']:
984 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
985 else:
986 if med['duration'] is None:
987 self.SetCellValue(row_idx, 5, u'')
988 else:
989 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
990
991 if med['pk_brand'] is None:
992 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u''))
993 else:
994 if med['fake_brand']:
995 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u'', _('%s (fake)')))
996 else:
997 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u''))
998
999 elif self.__grouping_mode == u'brand':
1000
1001 if med['pk_brand'] is None:
1002 self.__prev_cell_0 = None
1003 self.SetCellValue(row_idx, 0, gmTools.u_diameter)
1004 else:
1005 if self.__prev_cell_0 != med['brand']:
1006 self.__prev_cell_0 = med['brand']
1007 if med['fake_brand']:
1008 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['brand'], u'', _('%s (fake)')))
1009 else:
1010 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['brand'], u''))
1011
1012 self.SetCellValue(row_idx, 1, gmTools.coalesce(med['schedule'], u''))
1013 self.SetCellValue(row_idx, 2, med['substance'])
1014 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['strength'], u''))
1015 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1016
1017 if med['is_long_term']:
1018 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1019 else:
1020 if med['duration'] is None:
1021 self.SetCellValue(row_idx, 5, u'')
1022 else:
1023 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1024
1025 if med['pk_episode'] is None:
1026 self.SetCellValue(row_idx, 6, u'')
1027 else:
1028 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['episode'], u''))
1029
1030 else:
1031 raise ValueError('unknown grouping mode [%s]' % self.__grouping_mode)
1032
1033 if self.__filter_show_unapproved:
1034 self.SetCellValue (
1035 row_idx,
1036 len(labels),
1037 gmTools.bool2subst(med['intake_is_approved_of'], gmTools.u_checkmark_thin, u'', u'?')
1038 )
1039
1040
1041
1042 self.EndBatch()
1043
1045 self.BeginBatch()
1046 self.ClearGrid()
1047
1048
1049 if self.GetNumberRows() > 0:
1050 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
1051 if self.GetNumberCols() > 0:
1052 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
1053 self.EndBatch()
1054 self.__row_data = {}
1055 self.__prev_cell_0 = None
1056
1058
1059 if len(self.__row_data) == 0:
1060 return
1061
1062 sel_rows = self.get_selected_rows()
1063 if len(sel_rows) != 1:
1064 return
1065
1066 drug_db = get_drug_database()
1067 if drug_db is None:
1068 return
1069
1070 drug_db.show_info_on_substance(substance = self.get_selected_data()[0])
1071
1085
1088
1102
1104
1105 rows = self.get_selected_rows()
1106
1107 if len(rows) == 0:
1108 return
1109
1110 if len(rows) > 1:
1111 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete more than one substance at once.'), beep = True)
1112 return
1113
1114 subst = self.get_selected_data()[0]
1115 delete_substance_intake(parent = self, substance = subst['pk_substance_intake'])
1116
1121
1180
1181
1182
1184 self.CreateGrid(0, 1)
1185 self.EnableEditing(0)
1186 self.EnableDragGridSize(1)
1187 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
1188
1189 self.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTER)
1190
1191 self.SetRowLabelSize(0)
1192 self.SetRowLabelAlignment(horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
1193
1194
1195
1197 return self.__patient
1198
1202
1203 patient = property(_get_patient, _set_patient)
1204
1206 return self.__grouping_mode
1207
1211
1212 grouping_mode = property(_get_grouping_mode, _set_grouping_mode)
1213
1215 return self.__filter_show_unapproved
1216
1220
1221 filter_show_unapproved = property(_get_filter_show_unapproved, _set_filter_show_unapproved)
1222
1224 return self.__filter_show_inactive
1225
1229
1230 filter_show_inactive = property(_get_filter_show_inactive, _set_filter_show_inactive)
1231
1232
1233
1235
1236 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
1237
1238
1239
1240
1241 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
1242
1244 """Calculate where the mouse is and set the tooltip dynamically."""
1245
1246
1247
1248 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262 row, col = self.XYToCell(x, y)
1263
1264 if row == self.__prev_tooltip_row:
1265 return
1266
1267 self.__prev_tooltip_row = row
1268
1269 try:
1270 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
1271 except KeyError:
1272 pass
1273
1278
1279 from Gnumed.wxGladeWidgets import wxgCurrentSubstancesPnl
1280
1281 -class cCurrentSubstancesPnl(wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl, gmRegetMixin.cRegetOnPaintMixin):
1282
1283 """Panel holding a grid with current substances. Used as notebook page."""
1284
1291
1292
1293
1302
1303
1304
1306 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
1307 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._schedule_data_reget)
1308 gmDispatcher.connect(signal = u'substance_intake_mod_db', receiver = self._schedule_data_reget)
1309
1310
1311
1313 wx.CallAfter(self.__on_pre_patient_selection)
1314
1316 self._grid_substances.patient = None
1317
1320
1323
1326
1329
1332
1335
1338
1341
1344
1347
1348
1349
1350 if __name__ == '__main__':
1351
1352 from Gnumed.pycommon import gmI18N
1353
1354 gmI18N.activate_locale()
1355 gmI18N.install_domain(domain = 'gnumed')
1356
1357
1358
1359 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
1360
1361 pass
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482