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 -def _add_file_to_export_area(**kwargs):
45 try: 46 del kwargs['signal'] 47 del kwargs['sender'] 48 except KeyError: 49 pass 50 wx.CallAfter(add_file_to_export_area, **kwargs)
51
52 -def _add_files_to_export_area(**kwargs):
53 try: 54 del kwargs['signal'] 55 del kwargs['sender'] 56 except KeyError: 57 pass 58 wx.CallAfter(add_files_to_export_area, **kwargs)
59 60 #----------------------
61 -def add_file_to_export_area(parent=None, filename=None, hint=None, unlock_patient=False):
62 return add_files_to_export_area ( 63 parent = parent, 64 filenames = [filename], 65 hint = hint, 66 unlock_patient = unlock_patient 67 )
68 69 #----------------------
70 -def add_files_to_export_area(parent=None, filenames=None, hint=None, unlock_patient=False):
71 pat = gmPerson.gmCurrentPatient() 72 if not pat.connected: 73 gmDispatcher.send(signal = 'statustext', msg = _('Cannot add files to export area. No patient.'), beep = True) 74 return False 75 76 wx.BeginBusyCursor() 77 if parent is None: 78 parent = wx.GetApp().GetTopWindow() 79 if not pat.export_area.add_files(filenames = filenames, hint = hint): 80 wx.EndBusyCursor() 81 gmGuiHelpers.gm_show_error ( 82 aMessage = _('Cannot import files into export area.'), 83 aTitle = _('Export area') 84 ) 85 return False 86 87 wx.EndBusyCursor() 88 # remove non-temp files 89 tmp_dir = gmTools.gmPaths().tmp_dir 90 files2remove = [ f for f in filenames if not f.startswith(tmp_dir) ] 91 if len(files2remove) > 0: 92 do_delete = gmGuiHelpers.gm_show_question ( 93 _( 'Successfully imported files into export area.\n' 94 '\n' 95 'Do you want to delete imported files from the filesystem ?\n' 96 '\n' 97 ' %s' 98 ) % '\n '.join(files2remove), 99 _('Removing files') 100 ) 101 if do_delete: 102 for fname in files2remove: 103 gmTools.remove_file(fname) 104 else: 105 gmDispatcher.send(signal = 'statustext', msg = _('Imported files into export area.'), beep = True) 106 return True
107 108 #if unlock_patient: 109 # pat.locked = False 110 111 #---------------------- 112 gmDispatcher.connect(signal = 'add_file_to_export_area', receiver = _add_file_to_export_area) 113 gmDispatcher.connect(signal = 'add_files_to_export_area', receiver = _add_files_to_export_area) 114 115 #============================================================ 116 from Gnumed.wxGladeWidgets import wxgExportAreaExportToMediaDlg 117
118 -class cExportAreaExportToMediaDlg(wxgExportAreaExportToMediaDlg.wxgExportAreaExportToMediaDlg):
119
120 - def __init__(self, *args, **kwargs):
121 self.__patient = kwargs['patient'] 122 del kwargs['patient'] 123 self.__item_count = kwargs['item_count'] 124 del kwargs['item_count'] 125 super().__init__(*args, **kwargs) 126 127 self.__init_ui()
128 129 #-------------------------------------------------------- 130 # event handling 131 #--------------------------------------------------------
132 - def _on_reload_media_list_button_pressed(self, event):
133 event.Skip() 134 wx.BeginBusyCursor() 135 try: 136 self.__update_media_list() 137 finally: 138 wx.EndBusyCursor()
139 140 #--------------------------------------------------------
141 - def _on_media_selected(self, event):
142 self.__update_ui_state()
143 144 #--------------------------------------------------------
145 - def _on_media_deselected(self, event):
146 self.__update_ui_state()
147 148 #--------------------------------------------------------
149 - def _on_use_subdirectory_toggled(self, event):
150 event.Skip() 151 self.__update_ui_state()
152 153 #--------------------------------------------------------
154 - def _on_open_directory_button_pressed(self, event):
155 event.Skip() 156 path = self.__calc_path() 157 if not os.path.isdir(path): 158 return 159 gmMimeLib.call_viewer_on_file(path, block = False)
160 161 #--------------------------------------------------------
162 - def _on_clear_directory_button_pressed(self, event):
163 event.Skip() 164 path = self.__calc_path() 165 if not os.path.isdir(path): 166 return 167 168 delete_data = gmGuiHelpers.gm_show_question ( 169 title = _('Clearing out a directory'), 170 question = _( 171 'Do you really want to delete all existing data\n' 172 'from the following directory ?\n' 173 '\n' 174 ' %s\n' 175 '\n' 176 'Note, this can NOT be reversed without backups.' 177 ) % path, 178 cancel_button = False 179 ) 180 if delete_data: 181 gmTools.rm_dir_content(path) 182 self.__update_ui_state()
183 184 #--------------------------------------------------------
185 - def _on_save2media_button_pressed(self, event):
186 event.Skip() 187 188 path = self.__calc_path() 189 if path is None: 190 return # no media selected, should not happen 191 if path == -2: # not mounted, should not happen 192 return 193 if path == -1: # optical drive 194 if self.__burn_script is None: 195 return # no burn script, should not happen 196 197 self.EndModal(wx.ID_SAVE)
198 199 #-------------------------------------------------------- 200 # internal API 201 #--------------------------------------------------------
202 - def __init_ui(self):
203 msg = _( 204 '\n' 205 'Number of entries to export: %s\n' 206 '\n' 207 'Patient: %s\n' 208 '\n' 209 'Select the media to export onto below.\n' 210 ) % ( 211 self.__item_count, 212 self.__patient['description_gender'] 213 ) 214 self._LBL_header.Label = msg 215 self._LCTRL_removable_media.set_columns([_('Type'), _('Medium'), _('Details')]) 216 self._LCTRL_removable_media.set_column_widths([wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE]) 217 self._LCTRL_removable_media.set_resize_column() 218 self._LCTRL_removable_media.select_callback = self._on_media_selected 219 self._LCTRL_removable_media.deselect_callback = self._on_media_deselected 220 221 self.__update_media_list() 222 self.__update_ui_state()
223 224 #--------------------------------------------------------
225 - def __calc_path(self):
226 media = self._LCTRL_removable_media.get_selected_item_data(only_one = True) 227 if media is None: 228 return None 229 230 if media['type'] == 'cd': 231 return -1 232 233 if media['is_mounted'] is False: 234 return -2 235 236 mnt_path = media['mountpoint'] 237 if self._CHBOX_use_subdirectory.IsChecked(): 238 return os.path.join(mnt_path, self.__patient.subdir_name) 239 240 return mnt_path
241 242 #--------------------------------------------------------
243 - def __update_media_list(self):
244 245 self._LCTRL_removable_media.remove_items_safely() 246 items = [] 247 data = [] 248 249 found, self.__burn_script = gmShellAPI.detect_external_binary('gm-burn_doc') 250 251 # USB / MMC drives 252 removable_partitions = gmTools.enumerate_removable_partitions() 253 for key in removable_partitions: 254 part = removable_partitions[key] 255 if part['is_mounted'] is False: 256 continue 257 items.append ([ 258 part['bus'].upper(), 259 _('%s (%s %s) - %s free') % ( 260 part['fs_label'], 261 part['vendor'], 262 part['model'], 263 gmTools.size2str(part['bytes_free']) 264 ), 265 _('%s (%s): %s in %s on %s') % ( 266 part['mountpoint'], 267 gmTools.size2str(part['size_in_bytes']), 268 part['fs_type'], 269 part['partition'], 270 part['device'] 271 ) 272 ]) 273 data.append(part) 274 for key in removable_partitions: 275 part = removable_partitions[key] 276 if part['is_mounted'] is True: 277 continue 278 items.append ([ 279 part['bus'].upper(), 280 '%s (%s %s)' % ( 281 part['fs_label'], 282 part['vendor'], 283 part['model'] 284 ), 285 _('%s on %s, not mounted') % ( 286 part['partition'], 287 part['device'] 288 ) 289 ]) 290 data.append(part) 291 292 # optical drives: CD/DVD/BD 293 optical_writers = gmTools.enumerate_optical_writers() 294 for cdrw in optical_writers: 295 items.append ([ 296 cdrw['type'].upper(), 297 cdrw['model'], 298 cdrw['device'] 299 ]) 300 data.append(cdrw) 301 302 self._LCTRL_removable_media.set_string_items(items) 303 self._LCTRL_removable_media.set_data(data) 304 self._LCTRL_removable_media.set_column_widths() 305 306 self._BTN_save2media.Disable()
307 308 #--------------------------------------------------------
309 - def __update_ui_state(self):
310 311 media = self._LCTRL_removable_media.get_selected_item_data(only_one = True) 312 if media is None: 313 self._BTN_save2media.Disable() 314 self._BTN_open_directory.Disable() 315 self._BTN_clear_directory.Disable() 316 self._CHBOX_encrypt.Disable() 317 self._CHBOX_use_subdirectory.Disable() 318 self._LBL_directory.Label = '' 319 self._LBL_dir_is_empty.Label = '' 320 return 321 322 if media['type'] == 'cd': 323 self._BTN_open_directory.Disable() 324 self._BTN_clear_directory.Disable() 325 self._LBL_directory.Label = '' 326 if self.__burn_script is None: 327 self._BTN_save2media.Disable() 328 self._CHBOX_use_subdirectory.Disable() 329 self._CHBOX_encrypt.Disable() 330 self._LBL_dir_is_empty.Label = _('helper <gm-burn_doc(.bat)> not found') 331 else: 332 self._BTN_save2media.Enable() 333 self._CHBOX_use_subdirectory.Enable() 334 self._CHBOX_encrypt.Enable() 335 self._LBL_dir_is_empty.Label = '' 336 return 337 338 if media['is_mounted'] is False: 339 self._BTN_save2media.Disable() 340 self._BTN_open_directory.Disable() 341 self._BTN_clear_directory.Disable() 342 self._CHBOX_use_subdirectory.Disable() 343 self._CHBOX_encrypt.Disable() 344 self._LBL_directory.Label = '' 345 self._LBL_dir_is_empty.Label = _('media not mounted') 346 return 347 348 self._BTN_save2media.Enable() 349 self._CHBOX_use_subdirectory.Enable() 350 self._CHBOX_encrypt.Enable() 351 352 path = self.__calc_path() 353 self._LBL_directory.Label = path + os.sep 354 is_empty = gmTools.dir_is_empty(directory = path) 355 if is_empty is True: 356 self._LBL_dir_is_empty.Label = '' 357 self._BTN_open_directory.Enable() 358 self._BTN_clear_directory.Disable() 359 elif is_empty is False: 360 self._LBL_dir_is_empty.Label = _('directory contains data') 361 self._BTN_open_directory.Enable() 362 self._BTN_clear_directory.Enable() 363 else: # we don't know, say, use_subdir and subdir does not yet exist 364 self._LBL_dir_is_empty.Label = '' 365 self._BTN_open_directory.Disable() 366 self._BTN_clear_directory.Disable()
367 368 #============================================================ 369 from Gnumed.wxGladeWidgets import wxgExportAreaSaveAsDlg 370
371 -class cExportAreaSaveAsDlg(wxgExportAreaSaveAsDlg.wxgExportAreaSaveAsDlg):
372
373 - def __init__(self, *args, **kwargs):
374 self.__patient = kwargs['patient'] 375 del kwargs['patient'] 376 self.__item_count = kwargs['item_count'] 377 del kwargs['item_count'] 378 super().__init__(*args, **kwargs) 379 380 self.__init_ui()
381 382 #-------------------------------------------------------- 383 # event handlers 384 #--------------------------------------------------------
385 - def _on_use_subdirectory_toggled(self, event):
386 event.Skip() 387 self.__update_ui_state()
388 389 #--------------------------------------------------------
390 - def _on_select_directory_button_pressed(self, event):
391 event.Skip() 392 curr_path = self._LBL_directory.Label.rstrip(os.sep).rstrip('/') 393 if not os.path.isdir(curr_path): 394 curr_path = os.path.join(gmTools.gmPaths().home_dir, 'gnumed') 395 msg = _('Select directory where to save the archive or files.') 396 dlg = wx.DirDialog(self, message = msg, defaultPath = curr_path, style = wx.DD_DEFAULT_STYLE)# | wx.DD_DIR_MUST_EXIST) 397 choice = dlg.ShowModal() 398 selected_path = dlg.GetPath().rstrip(os.sep).rstrip('/') 399 dlg.DestroyLater() 400 if choice != wx.ID_OK: 401 return 402 403 self._LBL_directory.Label = selected_path + os.sep 404 self.__update_ui_state()
405 406 #--------------------------------------------------------
407 - def _on_open_directory_button_pressed(self, event):
408 event.Skip() 409 path = self._LBL_directory.Label.strip().rstrip(os.sep).rstrip('/') 410 if not os.path.isdir(path): 411 return 412 gmMimeLib.call_viewer_on_file(path, block = False)
413 414 #--------------------------------------------------------
415 - def _on_clear_directory_button_pressed(self, event):
416 event.Skip() 417 path = self._LBL_directory.Label.strip().rstrip(os.sep).rstrip('/') 418 if not os.path.isdir(path): 419 return 420 delete_data = gmGuiHelpers.gm_show_question ( 421 title = _('Clearing out a directory'), 422 question = _( 423 'Do you really want to delete all existing data\n' 424 'from the following directory ?\n' 425 '\n' 426 ' %s\n' 427 '\n' 428 'Note, this can NOT be reversed without backups.' 429 ) % path, 430 cancel_button = False 431 ) 432 if delete_data: 433 gmTools.rm_dir_content(path) 434 self.__update_ui_state()
435 436 #--------------------------------------------------------
437 - def _on_save_archive_button_pressed(self, event):
438 event.Skip() 439 self.EndModal(wx.ID_SAVE)
440 441 #-------------------------------------------------------- 442 # internal API 443 #--------------------------------------------------------
444 - def __init_ui(self):
445 msg = ('\n' + _('Number of entries to save: %s') + '\n\n' + _('Patient: %s') + '\n') % ( 446 self.__item_count, 447 self.__patient['description_gender'] 448 ) 449 self._LBL_header.Label = msg 450 self._LBL_directory.Label = os.path.join(gmTools.gmPaths().home_dir, 'gnumed', self.__patient.subdir_name) + os.sep 451 self.__update_ui_state()
452 453 #--------------------------------------------------------
454 - def __update_ui_state(self):
455 subdir_name = self.__patient.subdir_name 456 path = self._LBL_directory.Label.strip().rstrip(os.sep).rstrip('/') 457 if self._CHBOX_use_subdirectory.IsChecked(): 458 # add subdir if needed 459 if not path.endswith(subdir_name): 460 path = os.path.join(path, subdir_name) 461 self._LBL_directory.Label = path + os.sep 462 else: 463 # remove subdir if there 464 if path.endswith(subdir_name): 465 path = path[:-len(subdir_name)].rstrip(os.sep).rstrip('/') 466 self._LBL_directory.Label = path + os.sep 467 468 is_empty = gmTools.dir_is_empty(directory = path) 469 if is_empty is True: 470 self._LBL_dir_is_empty.Label = '' 471 self._BTN_open_directory.Disable() 472 self._BTN_clear_directory.Disable() 473 self._BTN_save_files.Enable() 474 self._BTN_save_archive.Enable() 475 elif is_empty is False: 476 self._LBL_dir_is_empty.Label = _('directory contains data') 477 self._BTN_open_directory.Enable() 478 self._BTN_clear_directory.Enable() 479 self._BTN_save_files.Disable() 480 self._BTN_save_archive.Disable() 481 else: # we don't know, say, use_subdir and subdir does not yet exist 482 self._LBL_dir_is_empty.Label = '' 483 self._BTN_open_directory.Disable() 484 self._BTN_clear_directory.Disable() 485 self._BTN_save_files.Enable() 486 self._BTN_save_archive.Enable() 487 488 self.Layout()
489 490 #============================================================ 491 from Gnumed.wxGladeWidgets import wxgExportAreaPluginPnl 492
493 -class cExportAreaPluginPnl(wxgExportAreaPluginPnl.wxgExportAreaPluginPnl, gmRegetMixin.cRegetOnPaintMixin):
494 """Panel holding a number of items for further processing. 495 496 Acts on the current patient. 497 498 Used as notebook page."""
499 - def __init__(self, *args, **kwargs):
500 wxgExportAreaPluginPnl.wxgExportAreaPluginPnl.__init__(self, *args, **kwargs) 501 gmRegetMixin.cRegetOnPaintMixin.__init__(self) 502 self.__init_ui() 503 self.__register_interests()
504 505 #-------------------------------------------------------- 506 # event handling 507 #--------------------------------------------------------
508 - def __register_interests(self):
509 gmDispatcher.connect(signal = 'pre_patient_unselection', receiver = self._on_pre_patient_unselection) 510 # gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._schedule_data_reget) 511 gmDispatcher.connect(signal = 'gm_table_mod', receiver = self._on_table_mod)
512 513 #--------------------------------------------------------
515 self._LCTRL_items.set_string_items([])
516 517 #--------------------------------------------------------
518 - def _on_table_mod(self, *args, **kwargs):
519 if kwargs['table'] != 'clin.export_item': 520 return 521 pat = gmPerson.gmCurrentPatient() 522 if not pat.connected: 523 return 524 if kwargs['pk_identity'] != pat.ID: 525 return 526 self._schedule_data_reget()
527 528 #--------------------------------------------------------
529 - def _on_list_item_selected(self, event):
530 event.Skip()
531 532 #--------------------------------------------------------
533 - def _on_show_item_button_pressed(self, event):
534 event.Skip() 535 item = self._LCTRL_items.get_selected_item_data(only_one = True) 536 if item is None: 537 return 538 item.display_via_mime(block = False)
539 540 #--------------------------------------------------------
541 - def _on_add_items_button_pressed(self, event):
542 event.Skip() 543 dlg = wx.FileDialog ( 544 parent = self, 545 message = _("Select files to add to the export area"), 546 defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')), 547 style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE | wx.FD_PREVIEW 548 ) 549 choice = dlg.ShowModal() 550 fnames = dlg.GetPaths() 551 dlg.DestroyLater() 552 if choice != wx.ID_OK: 553 return 554 if not gmPerson.gmCurrentPatient().export_area.add_files(fnames): 555 gmGuiHelpers.gm_show_error ( 556 title = _('Adding files to export area'), 557 error = _('Cannot add (some of) the following files to the export area:\n%s ') % '\n '.join(fnames) 558 )
559 560 #--------------------------------------------------------
561 - def _on_add_directory_button_pressed(self, event):
562 event.Skip() 563 dlg = wx.DirDialog ( 564 parent = self, 565 message = _("Select directory to add to the export area"), 566 defaultPath = os.path.expanduser(os.path.join('~', 'gnumed')), 567 style = wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST 568 ) 569 choice = dlg.ShowModal() 570 path = dlg.GetPath() 571 dlg.DestroyLater() 572 if choice != wx.ID_OK: 573 return 574 if not gmPerson.gmCurrentPatient().export_area.add_path(path): 575 gmGuiHelpers.gm_show_error ( 576 title = _('Adding path to export area'), 577 error = _('Cannot add the following path to the export area:\n%s ') % path 578 )
579 580 #--------------------------------------------------------
581 - def _on_add_from_archive_button_pressed(self, event):
582 event.Skip() 583 selected_docs = gmDocumentWidgets.manage_documents ( 584 parent = self, 585 msg = _('Select the documents to be put into the export area:'), 586 single_selection = False 587 ) 588 if selected_docs is None: 589 return 590 gmPerson.gmCurrentPatient().export_area.add_documents(documents = selected_docs)
591 592 #--------------------------------------------------------
593 - def _on_clipboard_items_button_pressed(self, event):
594 event.Skip() 595 clip = gmGuiHelpers.clipboard2file(check_for_filename = True) 596 if clip is None: 597 return 598 if clip is False: 599 return 600 if not gmPerson.gmCurrentPatient().export_area.add_file(filename = clip, hint = _('clipboard')): 601 gmGuiHelpers.gm_show_error ( 602 title = _('Loading clipboard item (saved to file) into export area'), 603 error = _('Cannot add the following clip to the export area:\n%s ') % clip 604 )
605 606 #--------------------------------------------------------
607 - def _on_scan_items_button_pressed(self, event):
608 event.Skip() 609 scans = gmDocumentWidgets.acquire_images_from_capture_device(calling_window = self) 610 if scans is None: 611 return 612 613 if not gmPerson.gmCurrentPatient().export_area.add_files(scans, _('scan')): 614 gmGuiHelpers.gm_show_error ( 615 title = _('Scanning files into export area'), 616 error = _('Cannot add (some of) the following scans to the export area:\n%s ') % '\n '.join(fnames) 617 )
618 619 #--------------------------------------------------------
620 - def _on_remove_items_button_pressed(self, event):
621 event.Skip() 622 items = self._LCTRL_items.get_selected_item_data(only_one = False) 623 if len(items) == 0: 624 return 625 really_delete = gmGuiHelpers.gm_show_question ( 626 title = _('Deleting document from export area.'), 627 question = _('Really remove %s selected document(s)\nfrom the patient export area ?') % len(items) 628 ) 629 if not really_delete: 630 return 631 for item in items: 632 gmPerson.gmCurrentPatient().export_area.remove_item(item)
633 634 #--------------------------------------------------------
635 - def _on_print_items_button_pressed(self, event):
636 event.Skip() 637 items = self._LCTRL_items.get_selected_item_data(only_one = False) 638 if len(items) == 0: 639 return 640 641 files2print = [] 642 for item in items: 643 files2print.append(item.save_to_file()) 644 645 if len(files2print) == 0: 646 return 647 648 jobtype = 'export_area' 649 printed = gmPrinting.print_files(filenames = files2print, jobtype = jobtype, verbose = _cfg.get(option = 'debug')) 650 if not printed: 651 gmGuiHelpers.gm_show_error ( 652 aMessage = _('Error printing documents.'), 653 aTitle = _('Printing [%s]') % jobtype 654 ) 655 return False 656 657 self.__save_soap_note(soap = _('Printed:\n - %s') % '\n - '.join([ i['description'] for i in items ])) 658 return True
659 660 #--------------------------------------------------------
661 - def _on_remote_print_button_pressed(self, event):
662 event.Skip() 663 items = self._LCTRL_items.get_selected_item_data(only_one = False) 664 if len(items) == 0: 665 return 666 for item in items: 667 item.is_print_job = True 668 gmDispatcher.send(signal = 'statustext', msg = _('Item(s) moved to Print Center.'))
669 670 #--------------------------------------------------------
671 - def _on_save_items_button_pressed(self, event):
672 event.Skip() 673 674 items = self.__get_items_to_work_on(_('Saving entries')) 675 if items is None: 676 return 677 678 pat = gmPerson.gmCurrentPatient() 679 dlg = cExportAreaSaveAsDlg(self, -1, patient = pat, item_count = len(items)) 680 choice = dlg.ShowModal() 681 path = dlg._LBL_directory.Label 682 generate_metadata = dlg._CHBOX_generate_metadata.IsChecked() 683 use_subdir = dlg._CHBOX_use_subdirectory.IsChecked() 684 encrypt = dlg._CHBOX_encrypt.IsChecked() 685 dlg.DestroyLater() 686 if choice == wx.ID_CANCEL: 687 return 688 689 if choice == wx.ID_SAVE: 690 create_archive = True 691 elif choice == wx.ID_OK: 692 create_archive = False 693 else: 694 raise Exception('invalid return') 695 696 if create_archive: 697 export_dir = path 698 zip_file = self.__export_as_zip ( 699 gmTools.coalesce(encrypt, _('Saving entries as encrypted ZIP archive'), _('Saving entries as unencrypted ZIP archive')), 700 items = items, 701 encrypt = encrypt 702 ) 703 if zip_file is None: 704 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save: aborted or error.')) 705 return 706 gmTools.mkdir(export_dir) 707 final_zip_file = shutil.move(zip_file, export_dir) 708 gmDispatcher.send(signal = 'statustext', msg = _('Saved entries into [%s]') % final_zip_file) 709 target = final_zip_file 710 else: 711 export_dir = self.__export_as_files ( 712 gmTools.coalesce(encrypt, _('Saving entries as encrypted files'), _('Saving entries as unencrypted files')), 713 base_dir = path, 714 items = items, 715 encrypt = encrypt, 716 with_metadata = generate_metadata 717 ) 718 if export_dir is None: 719 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save: aborted or error.')) 720 return 721 gmDispatcher.send(signal = 'statustext', msg = _('Saved entries into [%s]') % export_dir) 722 target = export_dir 723 724 self.__save_soap_note(soap = _('Saved from export area to [%s]:\n - %s') % ( 725 target, 726 '\n - '.join([ i['description'] for i in items ]) 727 )) 728 self.__browse_patient_data(export_dir) 729 730 # remove_entries ? 731 732 return True
733 734 # cleanup - ask ! 735 # - files corresponding to DIR/DIR CONTENT entries 736 # - entries in export area 737 # remove_items = gmGuiHelpers.gm_show_question ( 738 # title = _('Creating zip archive'), 739 # question = _( 740 # 'Zip archive created as:\n' 741 # '\n' 742 # ' [%s]\n' 743 # '\n' 744 # 'Remove archived entries from export area ?' 745 # ) % zip_file, 746 # cancel_button = False 747 # ) 748 # if remove_items: 749 # exp_area.remove_items(items = items) 750 # return True 751 752 #--------------------------------------------------------
753 - def _on_export_items_button_pressed(self, event):
754 event.Skip() 755 756 items = self.__get_items_to_work_on(_('Exporting entries')) 757 if items is None: 758 return 759 760 # export dialog 761 pat = gmPerson.gmCurrentPatient() 762 dlg = cExportAreaExportToMediaDlg(self, -1, patient = pat, item_count = len(items)) 763 choice = dlg.ShowModal() 764 media = dlg._LCTRL_removable_media.get_selected_item_data(only_one = True) 765 use_subdir = dlg._CHBOX_use_subdirectory.IsChecked() 766 encrypt = dlg._CHBOX_encrypt.IsChecked() 767 dlg.DestroyLater() 768 if choice == wx.ID_CANCEL: 769 return 770 771 # export the files 772 if media['type'] == 'cd': 773 base_dir = gmTools.mk_sandbox_dir(prefix = 'iso-') 774 else: 775 base_dir = media['mountpoint'] 776 if use_subdir: 777 dir2save2 = os.path.join(base_dir, pat.subdir_name) 778 else: 779 dir2save2 = base_dir 780 export_dir = self.__export_as_files ( 781 gmTools.coalesce(encrypt, _('Exporting encrypted entries'), _('Exporting entries')), 782 base_dir = dir2save2, 783 items = items, 784 encrypt = encrypt, 785 with_metadata = True 786 ) 787 if export_dir is None: 788 gmDispatcher.send(signal = 'statustext', msg = _('Cannot export: aborted or error.')) 789 return 790 791 if media['type'] == 'cd': 792 if not self.__burn_dir_to_disk(base_dir = base_dir): 793 return 794 gmDispatcher.send(signal = 'statustext', msg = _('Entries successfully burned to disk.')) 795 self.__save_soap_note(soap = _('Burned onto CD/DVD:\n - %s') % '\n - '.join([ i['description'] for i in items ])) 796 else: 797 gmDispatcher.send(signal = 'statustext', msg = _('Exported entries into [%s]') % export_dir) 798 self.__save_soap_note(soap = _('Exported onto removable media:\n - %s') % '\n - '.join([ i['description'] for i in items ])) 799 800 self.__browse_patient_data(dir2save2, encrypted = encrypt, archive = False, has_metadata = True) 801 802 # remove_entries ? 803 804 return True
805 806 #--------------------------------------------------------
807 - def _on_archive_items_button_pressed(self, event):
808 print("Event handler '_on_archive_items_button_pressed' not implemented!") 809 event.Skip()
810 811 #--------------------------------------------------------
812 - def _on_mail_items_button_pressed(self, event):
813 event.Skip() 814 815 _log.debug('gm-mail_doc(.bat) API: "MAIL-PROGRAM PRAXIS-VCF ZIP-ARCHIVE"') 816 817 found, external_cmd = gmShellAPI.detect_external_binary('gm-mail_doc') 818 if not found: 819 gmDispatcher.send(signal = 'statustext', msg = _('Cannot send e-mail: <gm-mail_doc(.bat)> not found')) 820 return False 821 822 zip_file = self.__export_as_zip ( 823 _('Mailing documents as zip archive'), 824 encrypt = True 825 ) 826 if zip_file is None: 827 gmDispatcher.send(signal = 'statustext', msg = _('Cannot send e-mail: no archive created.')) 828 return False 829 830 prax = gmPraxis.gmCurrentPraxisBranch() 831 args = [external_cmd, prax.vcf, zip_file] 832 success, ret_code, stdout = gmShellAPI.run_process(cmd_line = args, verbose = _cfg.get(option = 'debug')) 833 if not success: 834 gmGuiHelpers.gm_show_error ( 835 aMessage = _('Error mailing documents.'), 836 aTitle = _('Mailing documents') 837 ) 838 return False 839 840 #self.__save_soap_note(soap = _('Mailed:\n - %s') % '\n - '.join([ i['description'] for i in items ])) 841 self.__save_soap_note(soap = _('Mailed export area content.')) 842 return True
843 844 #--------------------------------------------------------
845 - def _on_fax_items_button_pressed(self, event):
846 event.Skip() 847 848 _log.debug('gm-fax_doc(.bat) API: "FAX-PROGRAM FAXNUMBER-OR-<EMPTY> LIST-OF-FILES-TO-FAX" (any file type !)') 849 850 found, external_cmd = gmShellAPI.detect_external_binary('gm-fax_doc') 851 if not found: 852 gmDispatcher.send(signal = 'statustext', msg = _('Cannot send fax: <gm-fax_doc(.bat)> not found')) 853 return False 854 855 items = self._LCTRL_items.get_selected_item_data(only_one = False) 856 if len(items) == 0: 857 items = self._LCTRL_items.get_item_data() 858 if len(items) == 0: 859 gmDispatcher.send(signal = 'statustext', msg = _('Cannot send fax: no items')) 860 return None 861 if len(items) > 1: 862 # ask, might be a lot 863 process_all = gmGuiHelpers.gm_show_question ( 864 title = _('Faxing documents'), 865 question = _('You have not selected any entries.\n\nSend fax with all %s entries ?') % len(items), 866 cancel_button = False 867 ) 868 if not process_all: 869 return None 870 871 return False 872 873 files2fax = [] 874 for item in items: 875 files2fax.append(item.save_to_file()) 876 fax_number = wx.GetTextFromUser ( 877 _('Please enter the fax number here !\n\n' 878 'It can be left empty if the external\n' 879 'fax software knows how to get the number.'), 880 caption = _('Faxing documents'), 881 parent = self, 882 centre = True 883 ) 884 if fax_number == '': 885 fax_number = 'EMPTY' 886 args = [external_cmd, fax_number, ' '.join(files2fax)] 887 success, ret_code, stdout = gmShellAPI.run_process(cmd_line = args, verbose = _cfg.get(option = 'debug')) 888 if not success: 889 gmGuiHelpers.gm_show_error ( 890 aMessage = _('Error faxing documents to\n\n %s') % fax_number, 891 aTitle = _('Faxing documents') 892 ) 893 return False 894 895 self.__save_soap_note(soap = _('Faxed to [%s]:\n - %s') % (fax_number, '\n - '.join([ i['description'] for i in items ]))) 896 return True
897 898 #--------------------------------------------------------
899 - def repopulate_ui(self):
900 self._populate_with_data()
901 902 #-------------------------------------------------------- 903 # internal API 904 #--------------------------------------------------------
905 - def __init_ui(self):
906 self._LCTRL_items.set_columns([_('By'), _('When'), _('Description')]) 907 908 self._BTN_archive_items.Disable() 909 910 # there's no GetToolTipText() in wx2.8 911 self.__mail_script_exists, path = gmShellAPI.detect_external_binary(binary = r'gm-mail_doc') 912 if not self.__mail_script_exists: 913 self._BTN_mail_items.Disable() 914 tt = self._BTN_mail_items.GetToolTipText() + '\n\n' + _('<gm-mail_doc(.bat) not found>') 915 self._BTN_mail_items.SetToolTip(tt) 916 917 self.__fax_script_exists, path = gmShellAPI.detect_external_binary(binary = r'gm-fax_doc') 918 if not self.__fax_script_exists: 919 self._BTN_fax_items.Disable() 920 tt = self._BTN_fax_items.GetToolTipText() + '\n\n' + _('<gm-fax_doc(.bat) not found>') 921 self._BTN_fax_items.SetToolTip(tt) 922 923 self.__burn_script_exists, path = gmShellAPI.detect_external_binary(binary = r'gm-burn_doc') 924 if not self.__burn_script_exists: 925 self._BTN_burn_items.Disable() 926 tt = self._BTN_burn_items.GetToolTipText() + '\n\n' + _('<gm-burn_doc(.bat) not found>') 927 self._BTN_burn_items.SetToolTip(tt) 928 929 # make me and listctrl file drop targets 930 dt = gmGuiHelpers.cFileDropTarget(target = self) 931 self.SetDropTarget(dt) 932 dt = gmGuiHelpers.cFileDropTarget(on_drop_callback = self._drop_target_consume_filenames) 933 self._LCTRL_items.SetDropTarget(dt)
934 935 #--------------------------------------------------------
936 - def __save_soap_note(self, soap=None):
937 if soap.strip() == '': 938 return 939 emr = gmPerson.gmCurrentPatient().emr 940 epi = emr.add_episode(episode_name = 'administrative', is_open = False) 941 emr.add_clin_narrative ( 942 soap_cat = None, 943 note = soap, 944 episode = epi 945 )
946 947 #--------------------------------------------------------
948 - def __export_as_files(self, msg_title, base_dir=None, encrypt=False, with_metadata=False, items=None):
949 # get password 950 data_pwd = None 951 if encrypt: 952 data_pwd = self.__get_password(msg_title) 953 if data_pwd is None: 954 _log.debug('user aborted by not providing the same password twice') 955 gmDispatcher.send(signal = 'statustext', msg = _('Password not provided twice. Aborting.')) 956 return None 957 # save 958 wx.BeginBusyCursor() 959 try: 960 exp_area = gmPerson.gmCurrentPatient().export_area 961 if with_metadata: 962 export_dir = exp_area.export(base_dir = base_dir, items = items, passphrase = data_pwd) 963 else: 964 export_dir = exp_area.dump_items_to_disk(base_dir = base_dir, items = items, passphrase = data_pwd) 965 finally: 966 wx.EndBusyCursor() 967 if export_dir is None: 968 gmGuiHelpers.gm_show_error ( 969 aMessage = _('Error exporting entries.'), 970 aTitle = msg_title 971 ) 972 return None 973 974 return export_dir
975 976 #--------------------------------------------------------
977 - def __export_as_zip(self, msg_title, encrypt=True, items=None):
978 # get password 979 zip_pwd = None 980 if encrypt: 981 zip_pwd = self.__get_password(msg_title) 982 if zip_pwd is None: 983 _log.debug('user aborted by not providing the same password twice') 984 gmDispatcher.send(signal = 'statustext', msg = _('Password not provided twice. Aborting.')) 985 return None 986 # create archive 987 wx.BeginBusyCursor() 988 zip_file = None 989 try: 990 exp_area = gmPerson.gmCurrentPatient().export_area 991 zip_file = exp_area.export_as_zip(passphrase = zip_pwd, items = items) 992 except Exception: 993 _log.exception('cannot create zip file') 994 wx.EndBusyCursor() 995 if zip_file is None: 996 gmGuiHelpers.gm_show_error ( 997 aMessage = _('Error creating zip file.'), 998 aTitle = msg_title 999 ) 1000 return zip_file
1001 1002 #--------------------------------------------------------
1003 - def __get_password(self, msg_title):
1004 while True: 1005 data_pwd = wx.GetPasswordFromUser ( 1006 message = _( 1007 'Enter passphrase to protect the data with.\n' 1008 '\n' 1009 '(minimum length: 5, trailing blanks will be stripped)' 1010 ), 1011 caption = msg_title 1012 ) 1013 # minimal weakness check 1014 data_pwd = data_pwd.rstrip() 1015 if len(data_pwd) > 4: 1016 break 1017 retry = gmGuiHelpers.gm_show_question ( 1018 title = msg_title, 1019 question = _( 1020 'Insufficient passphrase.\n' 1021 '\n' 1022 '(minimum length: 5, trailing blanks will be stripped)\n' 1023 '\n' 1024 'Enter another passphrase ?' 1025 ) 1026 ) 1027 if not retry: 1028 # user changed her mind 1029 return None 1030 # confidentiality 1031 gmLog2.add_word2hide(data_pwd) 1032 # reget password 1033 while True: 1034 data_pwd4comparison = wx.GetPasswordFromUser ( 1035 message = _( 1036 'Once more enter passphrase to protect the data with.\n' 1037 '\n' 1038 '(this will protect you from typos)\n' 1039 '\n' 1040 'Abort by leaving empty.' 1041 ), 1042 caption = msg_title 1043 ) 1044 data_pwd4comparison = data_pwd4comparison.rstrip() 1045 if data_pwd4comparison == '': 1046 # user changed her mind ... 1047 return None 1048 if data_pwd == data_pwd4comparison: 1049 break 1050 gmGuiHelpers.gm_show_error ( 1051 error = _( 1052 'Passphrases do not match.\n' 1053 '\n' 1054 'Retry, or abort with an empty passphrase.' 1055 ), 1056 title = msg_title 1057 ) 1058 return data_pwd
1059 1060 #--------------------------------------------------------
1061 - def __get_items_to_work_on(self, msg_title):
1062 1063 items = self._LCTRL_items.get_selected_item_data(only_one = False) 1064 if len(items) > 0: 1065 return items 1066 1067 items = self._LCTRL_items.get_item_data() 1068 if len(items) == 0: 1069 gmDispatcher.send(signal = 'statustext', msg = _('Export area empty. Nothing to do.')) 1070 return None 1071 1072 if len(items) == 1: 1073 return items 1074 1075 process_all = gmGuiHelpers.gm_show_question ( 1076 title = msg_title, 1077 question = _('You have not selected any entries.\n\nReally use all %s entries ?') % len(items), 1078 cancel_button = False 1079 ) 1080 if process_all: 1081 return items 1082 1083 return None
1084 1085 #--------------------------------------------------------
1086 - def __burn_dir_to_disk(self, base_dir):
1087 1088 _log.debug('gm-burn_doc(.bat) API: "DIRECTORY-TO-BURN-FROM"') 1089 1090 found, burn_cmd = gmShellAPI.detect_external_binary('gm-burn_doc') 1091 if not found: 1092 gmDispatcher.send(signal = 'statustext', msg = _('Cannot burn to disk: Helper not found.')) # should not happen 1093 return False 1094 1095 args = [burn_cmd, base_dir] 1096 wx.BeginBusyCursor() 1097 try: 1098 success, ret_code, stdout = gmShellAPI.run_process(cmd_line = args, verbose = _cfg.get(option = 'debug')) 1099 finally: 1100 wx.EndBusyCursor() 1101 if success: 1102 return True 1103 1104 gmGuiHelpers.gm_show_error ( 1105 aMessage = _('Error burning documents to CD/DVD.'), 1106 aTitle = _('Burning documents') 1107 ) 1108 return False
1109 1110 #--------------------------------------------------------
1111 - def __browse_patient_data(self, base_dir):
1112 1113 msg = _('Documents saved into:\n\n %s') % base_dir 1114 browse_index = gmGuiHelpers.gm_show_question ( 1115 title = _('Browsing patient data excerpt'), 1116 question = msg + '\n\n' + _('Browse saved entries ?'), 1117 cancel_button = False 1118 ) 1119 if not browse_index: 1120 return 1121 1122 if os.path.isfile(os.path.join(base_dir, 'index.html')): 1123 gmNetworkTools.open_url_in_browser(url = 'file://%s' % os.path.join(base_dir, 'index.html')) 1124 return 1125 1126 gmMimeLib.call_viewer_on_file(base_dir, block = False)
1127 1128 #-------------------------------------------------------- 1129 # file drop target API 1130 #--------------------------------------------------------
1131 - def _drop_target_consume_filenames(self, filenames):
1132 pat = gmPerson.gmCurrentPatient() 1133 if not pat.connected: 1134 gmDispatcher.send(signal = 'statustext', msg = _('Cannot accept new documents. No active patient.')) 1135 return 1136 1137 # dive into folders dropped onto us and extract files (one level deep only) 1138 real_filenames = [] 1139 for pathname in filenames: 1140 try: 1141 files = os.listdir(pathname) 1142 gmDispatcher.send(signal='statustext', msg=_('Extracting files from folder [%s] ...') % pathname) 1143 for file in files: 1144 fullname = os.path.join(pathname, file) 1145 if not os.path.isfile(fullname): 1146 continue 1147 real_filenames.append(fullname) 1148 except OSError: 1149 real_filenames.append(pathname) 1150 1151 if not pat.export_area.add_files(real_filenames, hint = _('Drag&Drop')): 1152 gmGuiHelpers.gm_show_error ( 1153 title = _('Adding files to export area'), 1154 error = _('Cannot add (some of) the following files to the export area:\n%s ') % '\n '.join(real_filenames) 1155 )
1156 #-------------------------------------------------------- 1157 # reget mixin API 1158 # 1159 # remember to call 1160 # self._schedule_data_reget() 1161 # whenever you learn of data changes from database 1162 # listener threads, dispatcher signals etc. 1163 #--------------------------------------------------------
1164 - def _populate_with_data(self):
1165 pat = gmPerson.gmCurrentPatient() 1166 if not pat.connected: 1167 return True 1168 1169 items = pat.export_area.items 1170 self._LCTRL_items.set_string_items ([ 1171 [ i['created_by'], 1172 gmDateTime.pydt_strftime(i['created_when'], '%Y %b %d %H:%M'), 1173 i['description'] 1174 ] for i in items 1175 ]) 1176 self._LCTRL_items.set_column_widths([wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE]) 1177 self._LCTRL_items.set_data(items) 1178 1179 self._LCTRL_items.SetFocus() 1180 1181 return True
1182 1183 #============================================================ 1184 from Gnumed.wxGladeWidgets import wxgPrintMgrPluginPnl 1185
1186 -class cPrintMgrPluginPnl(wxgPrintMgrPluginPnl.wxgPrintMgrPluginPnl, gmRegetMixin.cRegetOnPaintMixin):
1187 """Panel holding print jobs. 1188 1189 Used as notebook page.""" 1190
1191 - def __init__(self, *args, **kwargs):
1192 wxgPrintMgrPluginPnl.wxgPrintMgrPluginPnl.__init__(self, *args, **kwargs) 1193 gmRegetMixin.cRegetOnPaintMixin.__init__(self) 1194 self.__init_ui() 1195 self.__register_interests()
1196 #-------------------------------------------------------- 1197 # event handling 1198 #--------------------------------------------------------
1199 - def __register_interests(self):
1200 gmDispatcher.connect(signal = 'pre_patient_unselection', receiver = self._on_pre_patient_unselection) 1201 gmDispatcher.connect(signal = 'post_patient_selection', receiver = self._on_post_patient_selection) 1202 gmDispatcher.connect(signal = 'gm_table_mod', receiver = self._on_table_mod)
1203 #--------------------------------------------------------
1205 self._RBTN_active_patient_only.Enable(False) 1206 self._RBTN_all_patients.Value = True 1207 self._BTN_export_printouts.Enable(False)
1208 #--------------------------------------------------------
1209 - def _on_post_patient_selection(self):
1210 self._RBTN_active_patient_only.Enable(True) 1211 self._BTN_export_printouts.Enable(True)
1212 #--------------------------------------------------------
1213 - def _on_table_mod(self, *args, **kwargs):
1214 if kwargs['table'] != 'clin.export_item': 1215 return 1216 if self._RBTN_all_patients.Value is True: 1217 self._schedule_data_reget() 1218 return 1219 pat = gmPerson.gmCurrentPatient() 1220 if not pat.connected: 1221 return 1222 if kwargs['pk_identity'] != pat.ID: 1223 return 1224 self._schedule_data_reget()
1225 #--------------------------------------------------------
1226 - def _on_all_patients_selected(self, event):
1227 event.Skip() 1228 self._schedule_data_reget()
1229 #--------------------------------------------------------
1230 - def _on_active_patient_only_selected(self, event):
1231 event.Skip() 1232 self._schedule_data_reget()
1233 #--------------------------------------------------------
1234 - def _on_view_button_pressed(self, event):
1235 event.Skip() 1236 printout = self._LCTRL_printouts.get_selected_item_data(only_one = True) 1237 if printout is None: 1238 return 1239 printout.display_via_mime(block = False)
1240 #--------------------------------------------------------
1241 - def _on_print_button_pressed(self, event):
1242 event.Skip() 1243 printouts = self._LCTRL_printouts.get_selected_item_data(only_one = False) 1244 if len(printouts) == 0: 1245 return 1246 1247 files2print = [] 1248 for printout in printouts: 1249 files2print.append(printout.save_to_file()) 1250 1251 if len(files2print) == 0: 1252 return 1253 1254 jobtype = 'print_manager' 1255 printed = gmPrinting.print_files(filenames = files2print, jobtype = jobtype, verbose = _cfg.get(option = 'debug')) 1256 if not printed: 1257 gmGuiHelpers.gm_show_error ( 1258 aMessage = _('Error printing documents.'), 1259 aTitle = _('Printing [%s]') % jobtype 1260 ) 1261 return False 1262 1263 return True
1264 #--------------------------------------------------------
1265 - def _on_export_button_pressed(self, event):
1266 event.Skip() 1267 pat = gmPerson.gmCurrentPatient() 1268 if not pat.connected: 1269 return 1270 printouts = self._LCTRL_printouts.get_selected_item_data(only_one = False) 1271 for printout in printouts: 1272 printout.is_print_job = False
1273 #--------------------------------------------------------
1274 - def _on_delete_button_pressed(self, event):
1275 event.Skip() 1276 printouts = self._LCTRL_printouts.get_selected_item_data(only_one = False) 1277 if len(printouts) == 0: 1278 return 1279 if len(printouts) > 1: 1280 really_delete = gmGuiHelpers.gm_show_question ( 1281 title = _('Deleting document from export area.'), 1282 question = _('Really remove %s selected document(s)\nfrom the patient export area ?') % len(printouts) 1283 ) 1284 if not really_delete: 1285 return 1286 for printout in printouts: 1287 gmExportArea.delete_export_item(pk_export_item = printout['pk_export_item'])
1288 1289 #-------------------------------------------------------- 1290 # internal API 1291 #--------------------------------------------------------
1292 - def __init_ui(self):
1293 self._BTN_export_printouts.Enable(False)
1294 #-------------------------------------------------------- 1295 # reget mixin API 1296 #--------------------------------------------------------
1297 - def _populate_with_data(self):
1298 if self._RBTN_all_patients.Value is True: 1299 columns = [_('Patient'), _('Provider'), _('Description')] 1300 printouts = gmExportArea.get_print_jobs(order_by = 'pk_identity, description') 1301 items = [[ 1302 '%s, %s (%s)' % ( 1303 p['lastnames'], 1304 p['firstnames'], 1305 p['gender'] 1306 ), 1307 p['created_by'], 1308 p['description'] 1309 ] for p in printouts ] 1310 else: 1311 pat = gmPerson.gmCurrentPatient() 1312 if pat.connected: 1313 columns = [_('Provider'), _('Created'), _('Description')] 1314 printouts = pat.export_area.get_printouts(order_by = 'created_when, description') 1315 items = [[ 1316 p['created_by'], 1317 gmDateTime.pydt_strftime(p['created_when'], '%Y %b %d %H:%M'), 1318 p['description'] 1319 ] for p in printouts ] 1320 else: 1321 columns = [_('Patient'), _('Provider'), _('Description')] 1322 printouts = gmExportArea.get_print_jobs(order_by = 'pk_identity, description') 1323 items = [[ 1324 '%s, %s (%s)' % ( 1325 p['lastnames'], 1326 p['firstnames'], 1327 p['gender'] 1328 ), 1329 p['created_by'], 1330 p['description'] 1331 ] for p in printouts ] 1332 self._LCTRL_printouts.set_columns(columns) 1333 self._LCTRL_printouts.set_string_items(items) 1334 self._LCTRL_printouts.set_column_widths([wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE]) 1335 self._LCTRL_printouts.set_data(printouts) 1336 self._LCTRL_printouts.SetFocus() 1337 return True
1338