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