| Home | Trees | Indices | Help |
|
|---|
|
|
1 """GNUmed patient export area widgets."""
2 #================================================================
3 __author__ = "Karsten.Hilbert@gmx.net"
4 __license__ = "GPL v2 or later"
5
6 # std lib
7 import sys
8 import logging
9 import os.path
10 import shutil
11
12
13 # 3rd party
14 import wx
15
16
17 # GNUmed libs
18 if __name__ == '__main__':
19 sys.path.insert(0, '../../')
20
21 from Gnumed.pycommon import gmDispatcher
22 from Gnumed.pycommon import gmTools
23 from Gnumed.pycommon import gmMimeLib
24 from Gnumed.pycommon import gmDateTime
25 from Gnumed.pycommon import gmPrinting
26 from Gnumed.pycommon import gmShellAPI
27 from Gnumed.pycommon import gmNetworkTools
28 from Gnumed.pycommon import gmCfg2
29 from Gnumed.pycommon import gmLog2
30
31 from Gnumed.business import gmPerson
32 from Gnumed.business import gmExportArea
33 from Gnumed.business import gmPraxis
34
35 from Gnumed.wxpython import gmRegetMixin
36 from Gnumed.wxpython import gmGuiHelpers
37 from Gnumed.wxpython import gmDocumentWidgets
38
39
40 _log = logging.getLogger('gm.ui')
41 _cfg = gmCfg2.gmCfgData()
42
43
44 #============================================================
45 from Gnumed.wxGladeWidgets import wxgCreatePatientMediaDlg
46
48
50 self.__burn2cd = False
51 try:
52 self.__burn2cd = kwargs['burn2cd']
53 del kwargs['burn2cd']
54 except KeyError:
55 pass
56 if self.__burn2cd:
57 _log.debug('planning to burn export area items to CD/DVD')
58 else:
59 _log.debug('planning to save export area items to disk')
60 self.__patient = kwargs['patient']
61 del kwargs['patient']
62 self.__item_count = kwargs['item_count']
63 del kwargs['item_count']
64 wxgCreatePatientMediaDlg.wxgCreatePatientMediaDlg.__init__(self, *args, **kwargs)
65
66 self.__init_ui()
67
68 #--------------------------------------------------------
69 # event handling
70 #--------------------------------------------------------
91
92 #--------------------------------------------------------
94 event.Skip()
95
96 self.__refresh_include_or_remove_existing_data()
97
98 if self._CHBOX_use_subdirectory.IsChecked():
99 self._LBL_subdirectory.Label = '%s/%s-###' % (
100 self._LBL_directory.Label,
101 self.__patient.subdir_name
102 )
103 return
104
105 self._LBL_subdirectory.Label = ''
106
107 #--------------------------------------------------------
142
143 #--------------------------------------------------------
150
151 #--------------------------------------------------------
152 # internal API
153 #--------------------------------------------------------
155
156 self._LBL_dir_is_empty.Label = ''
157 self._LBL_subdirectory.Label = ''
158
159 if self.__burn2cd:
160 self._LBL_existing_data.Hide()
161 self._BTN_browse_directory.Disable()
162 self._RBTN_include_data.Hide()
163 self._RBTN_remove_data.Hide()
164 self._CHBOX_include_directory.Show()
165 self._CHBOX_use_subdirectory.Hide()
166 self._LBL_subdirectory.Hide()
167 self._CHBOX_generate_metadata.Hide()
168 lines = [
169 _('Preparing patient media for burning onto CD / DVD'),
170 ''
171 ]
172 found, external_cmd = gmShellAPI.detect_external_binary('gm-burn_doc')
173 if not found:
174 lines.append(_('Script <gm-burn_doc(.bat)> not found.'))
175 lines.append('')
176 lines.append(_('Cannot attempt to burn patient media onto CD/DVD.'))
177 self._BTN_save.Disable()
178 else:
179 lines.append(_('Patient: %s') % self.__patient['description_gender'])
180 lines.append('')
181 lines.append(_('Number of items to export onto CD/DVD: %s\n') % self.__item_count)
182 self._LBL_header.Label = '\n'.join(lines)
183 return
184
185 lines = [
186 _('Preparing patient media for saving to disk (USB, harddrive).'),
187 '',
188 _('Patient: %s') % self.__patient['description_gender'],
189 '',
190 _('Number of items to export to disk: %s\n') % self.__item_count
191 ]
192 self._LBL_header.Label = '\n'.join(lines)
193 self._LBL_directory.Label = os.path.join(gmTools.gmPaths().home_dir, 'gnumed')
194 self.__refresh_dir_is_empty()
195
196 #--------------------------------------------------------
198 path = self._LBL_directory.Label.strip()
199 if path == '':
200 self._LBL_dir_is_empty.Label = ''
201 self._BTN_browse_directory.Disable()
202 self._CHBOX_include_directory.Disable()
203 return
204 is_empty = gmTools.dir_is_empty(directory = path)
205 if is_empty is None:
206 self._LBL_dir_is_empty.Label = _('(cannot check directory)')
207 self._BTN_browse_directory.Disable()
208 self._CHBOX_include_directory.Disable()
209 return
210 if is_empty is True:
211 self._LBL_dir_is_empty.Label = _('(directory appears empty)')
212 self._BTN_browse_directory.Disable()
213 self._CHBOX_include_directory.Disable()
214 return
215
216 msg = _('directory already contains data')
217 self._BTN_browse_directory.Enable()
218 self._CHBOX_include_directory.Enable()
219
220 if os.path.isfile(os.path.join(path, 'DICOMDIR')):
221 msg = _('%s\n- DICOM data') % msg
222
223 if os.path.isdir(os.path.join(path, 'documents')):
224 if len(os.listdir(os.path.join(path, 'documents'))) > 0:
225 msg = _('%s\n- additional documents') % msg
226
227 self._LBL_dir_is_empty.Label = msg
228 self.Layout()
229
230 #--------------------------------------------------------
232 if self._CHBOX_use_subdirectory.IsChecked():
233 self._RBTN_include_data.Disable()
234 self._RBTN_remove_data.Disable()
235 return
236
237 path = self._LBL_directory.Label.strip()
238 if path == '':
239 self._RBTN_include_data.Disable()
240 self._RBTN_remove_data.Disable()
241 return
242
243 is_empty = gmTools.dir_is_empty(directory = path)
244 if is_empty is None:
245 self._RBTN_include_data.Disable()
246 self._RBTN_remove_data.Disable()
247 return
248
249 if is_empty is True:
250 self._RBTN_include_data.Disable()
251 self._RBTN_remove_data.Disable()
252 return
253
254 self._RBTN_include_data.Enable()
255 self._RBTN_remove_data.Enable()
256
257 #============================================================
258 from Gnumed.wxGladeWidgets import wxgExportAreaPluginPnl
259
260 -class cExportAreaPluginPnl(wxgExportAreaPluginPnl.wxgExportAreaPluginPnl, gmRegetMixin.cRegetOnPaintMixin):
261 """Panel holding a number of items for further processing.
262
263 Acts on the current patient.
264
265 Used as notebook page."""
267 wxgExportAreaPluginPnl.wxgExportAreaPluginPnl.__init__(self, *args, **kwargs)
268 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
269 self.__init_ui()
270 self.__register_interests()
271
272 #--------------------------------------------------------
273 # event handling
274 #--------------------------------------------------------
276 gmDispatcher.connect(signal = 'pre_patient_unselection', receiver = self._on_pre_patient_unselection)
277 # gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._schedule_data_reget)
278 gmDispatcher.connect(signal = 'gm_table_mod', receiver = self._on_table_mod)
279
280 #--------------------------------------------------------
282 self._LCTRL_items.set_string_items([])
283
284 #--------------------------------------------------------
286 if kwargs['table'] != 'clin.export_item':
287 return
288 pat = gmPerson.gmCurrentPatient()
289 if not pat.connected:
290 return
291 if kwargs['pk_identity'] != pat.ID:
292 return
293 self._schedule_data_reget()
294
295 #--------------------------------------------------------
297 event.Skip()
298
299 #--------------------------------------------------------
306
307 #--------------------------------------------------------
326
327 #--------------------------------------------------------
338
339 #--------------------------------------------------------
352
353 #--------------------------------------------------------
365
366 #--------------------------------------------------------
380
381 #--------------------------------------------------------
406
407 #--------------------------------------------------------
413
414 #--------------------------------------------------------
477
478 #--------------------------------------------------------
544
545 #--------------------------------------------------------
590
591 #--------------------------------------------------------
595
596 #--------------------------------------------------------
627
628 #--------------------------------------------------------
674
675 #--------------------------------------------------------
678
679 #--------------------------------------------------------
680 # internal API
681 #--------------------------------------------------------
683 self._LCTRL_items.set_columns([_('By'), _('When'), _('Description')])
684
685 self._BTN_archive_items.Disable()
686
687 # there's no GetToolTipText() in wx2.8
688 self.__mail_script_exists, path = gmShellAPI.detect_external_binary(binary = r'gm-mail_doc')
689 if not self.__mail_script_exists:
690 self._BTN_mail_items.Disable()
691 tt = self._BTN_mail_items.GetToolTipText() + '\n\n' + _('<gm-mail_doc(.bat) not found>')
692 self._BTN_mail_items.SetToolTip(tt)
693
694 self.__fax_script_exists, path = gmShellAPI.detect_external_binary(binary = r'gm-fax_doc')
695 if not self.__fax_script_exists:
696 self._BTN_fax_items.Disable()
697 tt = self._BTN_fax_items.GetToolTipText() + '\n\n' + _('<gm-fax_doc(.bat) not found>')
698 self._BTN_fax_items.SetToolTip(tt)
699
700 self.__burn_script_exists, path = gmShellAPI.detect_external_binary(binary = r'gm-burn_doc')
701 if not self.__burn_script_exists:
702 self._BTN_burn_items.Disable()
703 tt = self._BTN_burn_items.GetToolTipText() + '\n\n' + _('<gm-burn_doc(.bat) not found>')
704 self._BTN_burn_items.SetToolTip(tt)
705
706 # make me and listctrl file drop targets
707 dt = gmGuiHelpers.cFileDropTarget(target = self)
708 self.SetDropTarget(dt)
709 dt = gmGuiHelpers.cFileDropTarget(on_drop_callback = self._drop_target_consume_filenames)
710 self._LCTRL_items.SetDropTarget(dt)
711
712 #--------------------------------------------------------
714 if soap.strip() == '':
715 return
716 emr = gmPerson.gmCurrentPatient().emr
717 epi = emr.add_episode(episode_name = 'administrative', is_open = False)
718 emr.add_clin_narrative (
719 soap_cat = None,
720 note = soap,
721 episode = epi
722 )
723
724 #--------------------------------------------------------
726 # anything to do ?
727 items = self._LCTRL_items.get_selected_item_data(only_one = False)
728 if len(items) == 0:
729 items = self._LCTRL_items.get_item_data()
730 if len(items) == 0:
731 return None
732 # ask, might be a lot
733 process_all = gmGuiHelpers.gm_show_question (
734 title = msg_title,
735 question = _('You have not selected any entries.\n\nCreate archive from all %s entries ?') % len(items),
736 cancel_button = False
737 )
738 if not process_all:
739 return None
740 # get password ?
741 zip_pwd = None
742 if encrypt:
743 zip_pwd = self.__get_archive_password(msg_title)
744 if zip_pwd is None:
745 _log.debug('user aborted by not providing the same password twice')
746 return None
747 # create archive
748 exp_area = gmPerson.gmCurrentPatient().export_area
749 zip_file = exp_area.export_as_zip(passphrase = zip_pwd)
750 if zip_file is None:
751 gmGuiHelpers.gm_show_error (
752 aMessage = _('Error creating zip file.'),
753 aTitle = title
754 )
755 return None
756 return zip_file
757
758 #--------------------------------------------------------
760 while True:
761 zip_pwd = wx.GetPasswordFromUser (
762 message = _(
763 'Enter passphrase to protect the archive with.\n'
764 '\n'
765 '(minimum length: 5, trailing blanks will be stripped)'
766 ),
767 caption = msg_title
768 )
769 # minimal weakness check
770 zip_pwd = zip_pwd.rstrip()
771 if len(zip_pwd) > 4:
772 break
773 retry = gmGuiHelpers.gm_show_question (
774 title = msg_title,
775 question = _(
776 'Insufficient passphrase.\n'
777 '\n'
778 '(minimum length: 5, trailing blanks will be stripped)\n'
779 '\n'
780 'Enter another passphrase ?'
781 )
782 )
783 if not retry:
784 # user changed her mind
785 return None
786 # confidentiality
787 gmLog2.add_word2hide(zip_pwd)
788 # reget password
789 while True:
790 zip_pwd4comparison = wx.GetPasswordFromUser (
791 message = _(
792 'Once more enter passphrase to protect the archive with.\n'
793 '\n'
794 '(this will protect you from typos)\n'
795 '\n'
796 'Abort by leaving empty.'
797 ),
798 caption = msg_title
799 )
800 zip_pwd4comparison = zip_pwd4comparison.rstrip()
801 if zip_pwd4comparison == '':
802 # user changed her mind ...
803 return None
804 if zip_pwd == zip_pwd4comparison:
805 break
806 gmGuiHelpers.gm_show_error (
807 error = _(
808 'Passphrases do not match.\n'
809 '\n'
810 'Retry, or abort with an empty passphrase.'
811 ),
812 title = msg_title
813 )
814 return zip_pwd
815
816 #--------------------------------------------------------
817 # file drop target API
818 #--------------------------------------------------------
820 pat = gmPerson.gmCurrentPatient()
821 if not pat.connected:
822 gmDispatcher.send(signal = 'statustext', msg = _('Cannot accept new documents. No active patient.'))
823 return
824
825 # dive into folders dropped onto us and extract files (one level deep only)
826 real_filenames = []
827 for pathname in filenames:
828 try:
829 files = os.listdir(pathname)
830 gmDispatcher.send(signal='statustext', msg=_('Extracting files from folder [%s] ...') % pathname)
831 for file in files:
832 fullname = os.path.join(pathname, file)
833 if not os.path.isfile(fullname):
834 continue
835 real_filenames.append(fullname)
836 except OSError:
837 real_filenames.append(pathname)
838
839 if not pat.export_area.add_files(real_filenames, hint = _('Drag&Drop')):
840 gmGuiHelpers.gm_show_error (
841 title = _('Adding files to export area'),
842 error = _('Cannot add (some of) the following files to the export area:\n%s ') % '\n '.join(real_filenames)
843 )
844 #--------------------------------------------------------
845 # reget mixin API
846 #
847 # remember to call
848 # self._schedule_data_reget()
849 # whenever you learn of data changes from database
850 # listener threads, dispatcher signals etc.
851 #--------------------------------------------------------
853 pat = gmPerson.gmCurrentPatient()
854 if not pat.connected:
855 return True
856
857 items = pat.export_area.items
858 self._LCTRL_items.set_string_items ([
859 [ i['created_by'],
860 gmDateTime.pydt_strftime(i['created_when'], '%Y %b %d %H:%M'),
861 i['description']
862 ] for i in items
863 ])
864 self._LCTRL_items.set_column_widths([wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE])
865 self._LCTRL_items.set_data(items)
866
867 self._LCTRL_items.SetFocus()
868
869 return True
870
871 #============================================================
872 from Gnumed.wxGladeWidgets import wxgPrintMgrPluginPnl
873
874 -class cPrintMgrPluginPnl(wxgPrintMgrPluginPnl.wxgPrintMgrPluginPnl, gmRegetMixin.cRegetOnPaintMixin):
875 """Panel holding print jobs.
876
877 Used as notebook page."""
878
880 wxgPrintMgrPluginPnl.wxgPrintMgrPluginPnl.__init__(self, *args, **kwargs)
881 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
882 self.__init_ui()
883 self.__register_interests()
884 #--------------------------------------------------------
885 # event handling
886 #--------------------------------------------------------
888 gmDispatcher.connect(signal = 'pre_patient_unselection', receiver = self._on_pre_patient_unselection)
889 gmDispatcher.connect(signal = 'post_patient_selection', receiver = self._on_post_patient_selection)
890 gmDispatcher.connect(signal = 'gm_table_mod', receiver = self._on_table_mod)
891 #--------------------------------------------------------
893 self._RBTN_active_patient_only.Enable(False)
894 self._RBTN_all_patients.Value = True
895 self._BTN_export_printouts.Enable(False)
896 #--------------------------------------------------------
900 #--------------------------------------------------------
902 if kwargs['table'] != 'clin.export_item':
903 return
904 if self._RBTN_all_patients.Value is True:
905 self._schedule_data_reget()
906 return
907 pat = gmPerson.gmCurrentPatient()
908 if not pat.connected:
909 return
910 if kwargs['pk_identity'] != pat.ID:
911 return
912 self._schedule_data_reget()
913 #--------------------------------------------------------
917 #--------------------------------------------------------
921 #--------------------------------------------------------
928 #--------------------------------------------------------
952 #--------------------------------------------------------
961 #--------------------------------------------------------
976 #--------------------------------------------------------
977 # internal API
978 #--------------------------------------------------------
980 self._BTN_export_printouts.Enable(False)
981 #--------------------------------------------------------
982 # reget mixin API
983 #--------------------------------------------------------
985 if self._RBTN_all_patients.Value is True:
986 columns = [_('Patient'), _('Provider'), _('Description')]
987 printouts = gmExportArea.get_print_jobs(order_by = 'pk_identity, description')
988 items = [[
989 '%s, %s (%s)' % (
990 p['lastnames'],
991 p['firstnames'],
992 p['gender']
993 ),
994 p['created_by'],
995 p['description']
996 ] for p in printouts ]
997 else:
998 pat = gmPerson.gmCurrentPatient()
999 if pat.connected:
1000 columns = [_('Provider'), _('Created'), _('Description')]
1001 printouts = pat.export_area.get_printouts(order_by = 'created_when, description')
1002 items = [[
1003 p['created_by'],
1004 gmDateTime.pydt_strftime(p['created_when'], '%Y %b %d %H:%M'),
1005 p['description']
1006 ] for p in printouts ]
1007 else:
1008 columns = [_('Patient'), _('Provider'), _('Description')]
1009 printouts = gmExportArea.get_print_jobs(order_by = 'pk_identity, description')
1010 items = [[
1011 '%s, %s (%s)' % (
1012 p['lastnames'],
1013 p['firstnames'],
1014 p['gender']
1015 ),
1016 p['created_by'],
1017 p['description']
1018 ] for p in printouts ]
1019 self._LCTRL_printouts.set_columns(columns)
1020 self._LCTRL_printouts.set_string_items(items)
1021 self._LCTRL_printouts.set_column_widths([wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE])
1022 self._LCTRL_printouts.set_data(printouts)
1023 self._LCTRL_printouts.SetFocus()
1024 return True
1025
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Fri Jan 25 02:55:27 2019 | http://epydoc.sourceforge.net |