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 4648256 257 #============================================================ 258 from Gnumed.wxGladeWidgets import wxgExportAreaPluginPnl 25950 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()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."""870 871 #============================================================ 872 from Gnumed.wxGladeWidgets import wxgPrintMgrPluginPnl 873267 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_file757 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_pwd815 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 True874 -class cPrintMgrPluginPnl(wxgPrintMgrPluginPnl.wxgPrintMgrPluginPnl, gmRegetMixin.cRegetOnPaintMixin):875 """Panel holding print jobs. 876 877 Used as notebook page.""" 8781025880 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
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Wed Dec 19 02:55:28 2018 | http://epydoc.sourceforge.net |