Package Gnumed :: Package wxpython :: Module gmExportAreaWidgets
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gmExportAreaWidgets

   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   
47 -class cCreatePatientMediaDlg(wxgCreatePatientMediaDlg.wxgCreatePatientMediaDlg):
48
49 - def __init__(self, *args, **kwargs):
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 #--------------------------------------------------------
71 - def _on_select_directory_button_pressed(self, event):
72 event.Skip() 73 if self.__burn2cd: 74 msg = _('Select a directory for inclusion into the patient CD / DVD.') 75 else: 76 msg = _('Select a directory in which to create the patient media.') 77 def_path = self._LBL_directory.Label 78 dlg = wx.DirDialog ( 79 self, 80 message = msg, 81 defaultPath = def_path 82 ) 83 choice = dlg.ShowModal() 84 path = dlg.GetPath() 85 dlg.Destroy() 86 if choice != wx.ID_OK: 87 return 88 self._LBL_directory.Label = path 89 self.__refresh_dir_is_empty() 90 self.__refresh_include_or_remove_existing_data()
91 92 #--------------------------------------------------------
93 - def _on_use_subdirectory_changed(self, event):
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 #--------------------------------------------------------
108 - def _on_save_button_pressed(self, event):
109 event.Skip() 110 111 if self.__burn2cd: 112 self.EndModal(wx.ID_SAVE) 113 return 114 115 if self._CHBOX_use_subdirectory.IsChecked() is True: 116 self.EndModal(wx.ID_SAVE) 117 return 118 119 path = self._LBL_directory.Label 120 121 if gmTools.dir_is_empty(path) is True: 122 self.EndModal(wx.ID_SAVE) 123 return 124 125 if self._RBTN_remove_data.Value is True: 126 really_remove_existing_data = gmGuiHelpers.gm_show_question ( 127 title = _('Creating patient media'), 128 question = _( 129 'Really delete any existing data under\n' 130 '\n' 131 ' [%s]\n' 132 '\n' 133 'from disk ?\n' 134 '\n' 135 '(this operation is generally not reversible)' 136 ) % path 137 ) 138 if really_remove_existing_data is False: 139 return 140 141 self.EndModal(wx.ID_SAVE)
142 143 #--------------------------------------------------------
144 - def _on_browse_directory_button_pressed(self, event):
145 event.Skip() 146 path = self._LBL_directory.Label.strip() 147 if path == '': 148 return 149 gmMimeLib.call_viewer_on_file(path, block = False)
150 151 #-------------------------------------------------------- 152 # internal API 153 #--------------------------------------------------------
154 - def __init_ui(self):
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 #--------------------------------------------------------
197 - def __refresh_dir_is_empty(self):
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."""
266 - def __init__(self, *args, **kwargs):
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 #--------------------------------------------------------
275 - def __register_interests(self):
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 #--------------------------------------------------------
285 - def _on_table_mod(self, *args, **kwargs):
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 #--------------------------------------------------------
296 - def _on_list_item_selected(self, event):
297 event.Skip()
298 299 #--------------------------------------------------------
300 - def _on_show_item_button_pressed(self, event):
301 event.Skip() 302 item = self._LCTRL_items.get_selected_item_data(only_one = True) 303 if item is None: 304 return 305 item.display_via_mime(block = False)
306 307 #--------------------------------------------------------
308 - def _on_add_items_button_pressed(self, event):
309 event.Skip() 310 dlg = wx.FileDialog ( 311 parent = self, 312 message = _("Select files to add to the export area"), 313 defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')), 314 style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE | wx.FD_PREVIEW 315 ) 316 choice = dlg.ShowModal() 317 fnames = dlg.GetPaths() 318 dlg.Destroy() 319 if choice != wx.ID_OK: 320 return 321 if not gmPerson.gmCurrentPatient().export_area.add_files(fnames): 322 gmGuiHelpers.gm_show_error ( 323 title = _('Adding files to export area'), 324 error = _('Cannot add (some of) the following files to the export area:\n%s ') % '\n '.join(fnames) 325 )
326 327 #--------------------------------------------------------
328 - def _on_add_from_archive_button_pressed(self, event):
329 event.Skip() 330 selected_docs = gmDocumentWidgets.manage_documents ( 331 parent = self, 332 msg = _('Select the documents to be put into the export area:'), 333 single_selection = False 334 ) 335 if selected_docs is None: 336 return 337 gmPerson.gmCurrentPatient().export_area.add_documents(documents = selected_docs)
338 339 #--------------------------------------------------------
340 - def _on_clipboard_items_button_pressed(self, event):
341 event.Skip() 342 clip = gmGuiHelpers.clipboard2file(check_for_filename = True) 343 if clip is None: 344 return 345 if clip is False: 346 return 347 if not gmPerson.gmCurrentPatient().export_area.add_file(filename = clip, hint = _('clipboard')): 348 gmGuiHelpers.gm_show_error ( 349 title = _('Loading clipboard item (saved to file) into export area'), 350 error = _('Cannot add the following clip to the export area:\n%s ') % clip 351 )
352 353 #--------------------------------------------------------
354 - def _on_scan_items_button_pressed(self, event):
355 event.Skip() 356 scans = gmDocumentWidgets.acquire_images_from_capture_device(calling_window = self) 357 if scans is None: 358 return 359 360 if not gmPerson.gmCurrentPatient().export_area.add_files(scans, _('scan')): 361 gmGuiHelpers.gm_show_error ( 362 title = _('Scanning files into export area'), 363 error = _('Cannot add (some of) the following scans to the export area:\n%s ') % '\n '.join(fnames) 364 )
365 366 #--------------------------------------------------------
367 - def _on_remove_items_button_pressed(self, event):
368 event.Skip() 369 items = self._LCTRL_items.get_selected_item_data(only_one = False) 370 if len(items) == 0: 371 return 372 really_delete = gmGuiHelpers.gm_show_question ( 373 title = _('Deleting document from export area.'), 374 question = _('Really remove %s selected document(s)\nfrom the patient export area ?') % len(items) 375 ) 376 if not really_delete: 377 return 378 for item in items: 379 gmExportArea.delete_export_item(pk_export_item = item['pk_export_item'])
380 381 #--------------------------------------------------------
382 - def _on_print_items_button_pressed(self, event):
383 event.Skip() 384 items = self._LCTRL_items.get_selected_item_data(only_one = False) 385 if len(items) == 0: 386 return 387 388 files2print = [] 389 for item in items: 390 files2print.append(item.save_to_file()) 391 392 if len(files2print) == 0: 393 return 394 395 jobtype = 'export_area' 396 printed = gmPrinting.print_files(filenames = files2print, jobtype = jobtype, verbose = _cfg.get(option = 'debug')) 397 if not printed: 398 gmGuiHelpers.gm_show_error ( 399 aMessage = _('Error printing documents.'), 400 aTitle = _('Printing [%s]') % jobtype 401 ) 402 return False 403 404 self.__save_soap_note(soap = _('Printed:\n - %s') % '\n - '.join([ i['description'] for i in items ])) 405 return True
406 407 #--------------------------------------------------------
408 - def _on_remote_print_button_pressed(self, event):
409 event.Skip() 410 items = self._LCTRL_items.get_selected_item_data(only_one = False) 411 for item in items: 412 item.is_print_job = True
413 414 #--------------------------------------------------------
415 - def _on_save_items_button_pressed(self, event):
416 event.Skip() 417 418 items = self._LCTRL_items.get_selected_item_data(only_one = False) 419 if len(items) == 0: 420 items = self._LCTRL_items.get_item_data() 421 422 if len(items) == 0: 423 return 424 425 pat = gmPerson.gmCurrentPatient() 426 dlg = cCreatePatientMediaDlg (self, -1, burn2cd = False, patient = pat, item_count = len(items)) 427 _log.debug("calling dlg.ShowModal()") 428 choice = dlg.ShowModal() 429 _log.debug("after returning from dlg.ShowModal()") 430 if choice != wx.ID_SAVE: 431 dlg.Destroy() 432 return 433 434 use_subdir = dlg._CHBOX_use_subdirectory.IsChecked() 435 path = dlg._LBL_directory.Label.strip() 436 remove_existing_data = dlg._RBTN_remove_data.Value is True 437 generate_metadata = dlg._CHBOX_generate_metadata.IsChecked() 438 dlg.Destroy() 439 if use_subdir: 440 path = gmTools.mk_sandbox_dir ( 441 prefix = '%s-' % pat.subdir_name, 442 base_dir = path 443 ) 444 else: 445 if remove_existing_data is True: 446 if gmTools.rm_dir_content(path) is False: 447 gmGuiHelpers.gm_show_error ( 448 title = _('Creating patient media'), 449 error = _('Cannot remove content from\n [%s]') % path 450 ) 451 return False 452 453 exp_area = pat.export_area 454 if generate_metadata: 455 export_dir = exp_area.export(base_dir = path, items = items) 456 else: 457 export_dir = exp_area.dump_items_to_disk(base_dir = path, items = items) 458 459 self.__save_soap_note(soap = _('Saved to [%s]:\n - %s') % ( 460 export_dir, 461 '\n - '.join([ i['description'] for i in items ]) 462 )) 463 464 msg = _('Saved documents into directory:\n\n %s') % export_dir 465 browse_index = gmGuiHelpers.gm_show_question ( 466 title = _('Creating patient media'), 467 question = msg + '\n\n' + _('Browse patient data pack ?'), 468 cancel_button = False 469 ) 470 if browse_index: 471 if generate_metadata: 472 gmNetworkTools.open_url_in_browser(url = 'file://%s' % os.path.join(export_dir, 'index.html')) 473 else: 474 gmMimeLib.call_viewer_on_file(export_dir, block = False) 475 476 return True
477 478 #--------------------------------------------------------
479 - def _on_burn_items_button_pressed(self, event):
480 event.Skip() 481 482 # anything to do ? 483 found, external_cmd = gmShellAPI.detect_external_binary('gm-burn_doc') 484 if not found: 485 return 486 items = self._LCTRL_items.get_selected_item_data(only_one = False) 487 if len(items) == 0: 488 items = self._LCTRL_items.get_item_data() 489 if len(items) == 0: 490 return 491 492 pat = gmPerson.gmCurrentPatient() 493 dlg = cCreatePatientMediaDlg(self, -1, burn2cd = True, patient = pat, item_count = len(items)) 494 choice = dlg.ShowModal() 495 if choice != wx.ID_SAVE: 496 return 497 path2include = dlg._LBL_directory.Label.strip() 498 include_selected_dir = dlg._CHBOX_include_directory.IsChecked() 499 dlg.Destroy() 500 501 # do the export 502 base_dir = None 503 if include_selected_dir: 504 if gmTools.dir_is_empty(path2include) is False: 505 base_dir = gmTools.get_unique_filename(suffix = '.iso') 506 try: 507 shutil.copytree(path2include, base_dir) 508 except shutil.Error: 509 _log.exception('cannot copy include directory [%s] -> [%s]', path2include, base_dir) 510 return 511 512 export_dir = gmPerson.gmCurrentPatient().export_area.export(base_dir = base_dir, items = items) 513 if export_dir is None: 514 return 515 516 # burn onto media 517 cmd = '%s %s' % (external_cmd, export_dir) 518 if os.name == 'nt': 519 blocking = True 520 else: 521 blocking = False 522 success = gmShellAPI.run_command_in_shell ( 523 command = cmd, 524 blocking = blocking 525 ) 526 if not success: 527 gmGuiHelpers.gm_show_error ( 528 aMessage = _('Error burning documents to CD/DVD.'), 529 aTitle = _('Burning documents') 530 ) 531 return 532 533 self.__save_soap_note(soap = _('Burned onto CD/DVD:\n - %s') % '\n - '.join([ i['description'] for i in items ])) 534 535 browse_index = gmGuiHelpers.gm_show_question ( 536 title = _('Creating patient media'), 537 question = _('Browse patient data pack ?'), 538 cancel_button = False 539 ) 540 if browse_index: 541 gmNetworkTools.open_url_in_browser(url = 'file://%s' % os.path.join(export_dir, 'index.html')) 542 543 return True
544 545 #--------------------------------------------------------
546 - def _on_zip_items_button_pressed(self, event):
547 event.Skip() 548 # anything to do ? 549 items = self._LCTRL_items.get_selected_item_data(only_one = False) 550 if len(items) == 0: 551 items = self._LCTRL_items.get_item_data() 552 if len(items) == 0: 553 return None 554 # ask, might be a lot 555 process_all = gmGuiHelpers.gm_show_question ( 556 title = _('Creating zip archive'), 557 question = _('You have not selected any entries.\n\nCreate archive from all %s entries ?') % len(items), 558 cancel_button = False 559 ) 560 if not process_all: 561 return None 562 563 exp_area = gmPerson.gmCurrentPatient().export_area 564 # get passphrase from user 565 zip_file = exp_area.export_as_zip(passphrase = None) 566 if zip_file is None: 567 gmGuiHelpers.gm_show_error ( 568 aMessage = _('Error creating zip file.'), 569 aTitle = _('Creating zip archive') 570 ) 571 return False 572 573 # cleanup - ask ! 574 # - files corresponding to DIR/DIR CONTENT entries 575 # - entries in export area 576 remove_items = gmGuiHelpers.gm_show_question ( 577 title = _('Creating zip archive'), 578 question = _( 579 'Zip archive created as:\n' 580 '\n' 581 ' [%s]\n' 582 '\n' 583 'Remove archived entries from export area ?' 584 ) % zip_file, 585 cancel_button = False 586 ) 587 if remove_items: 588 exp_area.remove_items(items = items) 589 return True
590 591 #--------------------------------------------------------
592 - def _on_archive_items_button_pressed(self, event):
593 print("Event handler '_on_archive_items_button_pressed' not implemented!") 594 event.Skip()
595 596 #--------------------------------------------------------
597 - def _on_mail_items_button_pressed(self, event):
598 event.Skip() 599 600 found, external_cmd = gmShellAPI.detect_external_binary('gm-mail_doc') 601 if not found: 602 return False 603 604 zip_file = self.__export_as_zip ( 605 _('Mailing documents as zip archive'), 606 encrypt = True 607 ) 608 if zip_file is None: 609 gmGuiHelpers.gm_show_error ( 610 aMessage = _('Error creating zip file.'), 611 aTitle = title 612 ) 613 return False 614 615 prax = gmPraxis.gmCurrentPraxisBranch() 616 args = [external_cmd, prax.vcf, zip_file] 617 success, ret_code, stdout = gmShellAPI.run_process(cmd_line = args,verbose = _cfg.get(option = 'debug')) 618 if not success: 619 gmGuiHelpers.gm_show_error ( 620 aMessage = _('Error mailing documents.'), 621 aTitle = title 622 ) 623 return False 624 625 self.__save_soap_note(soap = _('Mailed:\n - %s') % '\n - '.join([ i['description'] for i in items ])) 626 return True
627 628 #--------------------------------------------------------
629 - def _on_fax_items_button_pressed(self, event):
630 event.Skip() 631 632 items = self._LCTRL_items.get_selected_item_data(only_one = False) 633 if len(items) == 0: 634 return 635 636 found, external_cmd = gmShellAPI.detect_external_binary('gm-fax_doc') 637 if not found: 638 return False 639 640 files2fax = [] 641 for item in items: 642 files2fax.append(item.save_to_file()) 643 644 fax_number = wx.GetTextFromUser ( 645 _('Please enter the fax number here !\n\n' 646 'It can be left empty if the external\n' 647 'fax software knows how to get the number.'), 648 caption = _('Faxing documents'), 649 parent = self, 650 centre = True 651 ) 652 653 cmd = '%s "%s" %s' % (external_cmd, fax_number, ' '.join(files2fax)) 654 if os.name == 'nt': 655 blocking = True 656 else: 657 blocking = False 658 success = gmShellAPI.run_command_in_shell ( 659 command = cmd, 660 blocking = blocking 661 ) 662 if not success: 663 gmGuiHelpers.gm_show_error ( 664 aMessage = _('Error faxing documents to\n\n %s') % fax_number, 665 aTitle = _('Faxing documents') 666 ) 667 return False 668 669 self.__save_soap_note(soap = _('Faxed to [%s]:\n - %s') % ( 670 fax_number, 671 '\n - '.join([ i['description'] for i in items ]) 672 )) 673 return True
674 675 #--------------------------------------------------------
676 - def repopulate_ui(self):
677 self._populate_with_data()
678 679 #-------------------------------------------------------- 680 # internal API 681 #--------------------------------------------------------
682 - def __init_ui(self):
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 #--------------------------------------------------------
713 - def __save_soap_note(self, soap=None):
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 #--------------------------------------------------------
725 - def __export_as_zip(self, msg_title, encrypt=True):
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 #--------------------------------------------------------
759 - def __get_archive_password(self, msg_title):
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 #--------------------------------------------------------
819 - def _drop_target_consume_filenames(self, filenames):
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 #--------------------------------------------------------
852 - def _populate_with_data(self):
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
879 - def __init__(self, *args, **kwargs):
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 #--------------------------------------------------------
887 - def __register_interests(self):
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 #--------------------------------------------------------
897 - def _on_post_patient_selection(self):
898 self._RBTN_active_patient_only.Enable(True) 899 self._BTN_export_printouts.Enable(True)
900 #--------------------------------------------------------
901 - def _on_table_mod(self, *args, **kwargs):
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 #--------------------------------------------------------
914 - def _on_all_patients_selected(self, event):
915 event.Skip() 916 self._schedule_data_reget()
917 #--------------------------------------------------------
918 - def _on_active_patient_only_selected(self, event):
919 event.Skip() 920 self._schedule_data_reget()
921 #--------------------------------------------------------
922 - def _on_view_button_pressed(self, event):
923 event.Skip() 924 printout = self._LCTRL_printouts.get_selected_item_data(only_one = True) 925 if printout is None: 926 return 927 printout.display_via_mime(block = False)
928 #--------------------------------------------------------
929 - def _on_print_button_pressed(self, event):
930 event.Skip() 931 printouts = self._LCTRL_printouts.get_selected_item_data(only_one = False) 932 if len(printouts) == 0: 933 return 934 935 files2print = [] 936 for printout in printouts: 937 files2print.append(printout.save_to_file()) 938 939 if len(files2print) == 0: 940 return 941 942 jobtype = 'print_manager' 943 printed = gmPrinting.print_files(filenames = files2print, jobtype = jobtype, verbose = _cfg.get(option = 'debug')) 944 if not printed: 945 gmGuiHelpers.gm_show_error ( 946 aMessage = _('Error printing documents.'), 947 aTitle = _('Printing [%s]') % jobtype 948 ) 949 return False 950 951 return True
952 #--------------------------------------------------------
953 - def _on_export_button_pressed(self, event):
954 event.Skip() 955 pat = gmPerson.gmCurrentPatient() 956 if not pat.connected: 957 return 958 printouts = self._LCTRL_printouts.get_selected_item_data(only_one = False) 959 for printout in printouts: 960 printout.is_print_job = False
961 #--------------------------------------------------------
962 - def _on_delete_button_pressed(self, event):
963 event.Skip() 964 printouts = self._LCTRL_printouts.get_selected_item_data(only_one = False) 965 if len(printouts) == 0: 966 return 967 if len(printouts) > 1: 968 really_delete = gmGuiHelpers.gm_show_question ( 969 title = _('Deleting document from export area.'), 970 question = _('Really remove %s selected document(s)\nfrom the patient export area ?') % len(printouts) 971 ) 972 if not really_delete: 973 return 974 for printout in printouts: 975 gmExportArea.delete_export_item(pk_export_item = printout['pk_export_item'])
976 #-------------------------------------------------------- 977 # internal API 978 #--------------------------------------------------------
979 - def __init_ui(self):
980 self._BTN_export_printouts.Enable(False)
981 #-------------------------------------------------------- 982 # reget mixin API 983 #--------------------------------------------------------
984 - def _populate_with_data(self):
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