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

# Source Code for Module Gnumed.wxpython.gmFormWidgets

       1  """GNUmed form/letter handling widgets."""
       2
       3  #================================================================
       4  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
       5  __license__ = "GPL v2 or later"
       6
       7
       8  import os.path
       9  import sys
      10  import logging
      11  import shutil
      12
      13
      14  import wx
      15
      16
      17  if __name__ == '__main__':
      18          sys.path.insert(0, '../../')
      19  from Gnumed.pycommon import gmI18N
      20  from Gnumed.pycommon import gmTools
      21  from Gnumed.pycommon import gmDispatcher
      22  from Gnumed.pycommon import gmPrinting
      23  from Gnumed.pycommon import gmDateTime
      24  from Gnumed.pycommon import gmShellAPI
      25  from Gnumed.pycommon import gmMimeLib
      26  from Gnumed.pycommon import gmCfg2
      27
      28  from Gnumed.business import gmForms
      29  from Gnumed.business import gmPerson
      30  from Gnumed.business import gmExternalCare
      31  from Gnumed.business import gmPraxis
      32
      33  from Gnumed.wxpython import gmGuiHelpers
      34  from Gnumed.wxpython import gmListWidgets
      35  from Gnumed.wxpython import gmMacro
      36  from Gnumed.wxpython import gmEditArea
      37  from Gnumed.wxpython.gmDocumentWidgets import save_files_as_new_document
      38
      39
      40  _log = logging.getLogger('gm.ui')
      41
      42  _ID_FORM_DISPOSAL_PRINT, \
      43  _ID_FORM_DISPOSAL_REMOTE_PRINT, \
      44  _ID_FORM_DISPOSAL_EXPORT_ONLY, \
      45  _ID_FORM_DISPOSAL_ARCHIVE_ONLY = range(4)
      46
      47  #============================================================
      48  # generic form generation and handling convenience functions
      49  #------------------------------------------------------------
      50 -def print_doc_from_template(parent=None, jobtype=None, episode=None, edit_form=None):
      51
      52          form = generate_form_from_template (
      53                  parent = parent,
      54                  excluded_template_types = [
      55                          'gnuplot script',
      56                          'visual progress note',
      57                          'invoice'
      58                  ],
      59                  edit = edit_form                        # default None = respect template setting
      60          )
      61          if form is None:
      62                  return False
      63
      64          if form in [True, False]:       # returned by special OOo/LO handling
      65                  return form
      66
      67          if episode is None:
      68                  epi_name = 'administrative'
      69          else:
      70                  epi_name = episode['description']
      71          return act_on_generated_forms (
      72                  parent = parent,
      73                  forms = [form],
      74                  jobtype = jobtype,
      75                  episode_name = epi_name,
      76                  review_copy_as_normal = True
      77          )
      78
      79  #------------------------------------------------------------
      80  # eventually this should become superfluous when there's a
      81  # standard engine wrapper around OOo
      82 -def print_doc_from_ooo_template(template=None):
      83
      84          # export template to file
      85          filename = template.save_to_file()
      86          if filename is None:
      87                  gmGuiHelpers.gm_show_error (
      88                          _(      'Error exporting form template\n'
      89                                  '\n'
      90                                  ' "%s" (%s)'
      91                          ) % (template['name_long'], template['external_version']),
      92                          _('Letter template export')
      93                  )
      94                  return False
      95
      96          try:
      97                  doc = gmForms.cOOoLetter(template_file = filename, instance_type = template['instance_type'])
      98          except ImportError:
      99                  gmGuiHelpers.gm_show_error (
     100                          _('Cannot connect to OpenOffice.\n\n'
     101                            'The UNO bridge module for Python\n'
     102                            'is not installed.'
     103                          ),
     104                          _('Letter writer')
     105                  )
     106                  return False
     107
     108          if not doc.open_in_ooo():
     109                  gmGuiHelpers.gm_show_error (
     110                          _('Cannot connect to OpenOffice.\n'
     111                            '\n'
     112                            'You may want to increase the option\n'
     113                            '\n'
     114                            ' <%s>'
     115                          ) % _('OOo startup time'),
     116                          _('Letter writer')
     117                  )
     118                  try: os.remove(filename)
     119                  except: pass
     120                  return False
     121
     122          doc.show(False)
     123          ph_handler = gmMacro.gmPlaceholderHandler()
     124          doc.replace_placeholders(handler = ph_handler)
     125
     126          filename = filename.replace('.ott', '.odt').replace('-FormTemplate-', '-FormInstance-')
     127          doc.save_in_ooo(filename = filename)
     128
     129          doc.show(True)
     130
     131          return True
     132
     133  #------------------------------------------------------------
     134 -def generate_form_from_template(parent=None, template_types=None, edit=None, template=None, excluded_template_types=None):
     135          """If <edit> is None it will honor the template setting."""
     136
     137          if parent is None:
     138                  parent = wx.GetApp().GetTopWindow()
     139
     140          # 1) get template to use
     141          if template is None:
     142                  template = manage_form_templates (
     143                          parent = parent,
     144                          active_only = True,
     145                          template_types = template_types,
     146                          excluded_types = excluded_template_types
     147                  )
     148                  if template is None:
     149                          gmDispatcher.send(signal = 'statustext', msg = _('No document template selected.'), beep = False)
     150                          return None
     151
     152          if template['engine'] == 'O':
     153                  return print_doc_from_ooo_template(template = template)
     154
     155          wx.BeginBusyCursor()
     156
     157          # 2) process template
     158          try:
     159                  form = template.instantiate()
     160          except KeyError:
     161                  _log.exception('cannot instantiate document template [%s]', template)
     162                  gmGuiHelpers.gm_show_error (
     163                          aMessage = _('Invalid document template [%s - %s (%s)]') % (name, ver, template['engine']),
     164                          aTitle = _('Generating document from template')
     165                  )
     166                  wx.EndBusyCursor()
     167                  return None
     168          ph = gmMacro.gmPlaceholderHandler()
     169          #ph.debug = True
     170          form.substitute_placeholders(data_source = ph)
     171          if edit is None:
     172                  if form.template['edit_after_substitution']:
     173                          edit = True
     174                  else:
     175                          edit = False
     176          if edit:
     177                  wx.EndBusyCursor()
     178                  form.edit()
     179                  wx.BeginBusyCursor()
     180
     181          # 3) generate output
     182          pdf_name = form.generate_output()
     183          wx.EndBusyCursor()
     184          if pdf_name is not None:
     185                  return form
     186
     187          gmGuiHelpers.gm_show_error (
     188                  aMessage = _('Error generating document printout.'),
     189                  aTitle = _('Generating document printout')
     190          )
     191          return None
     192
     193  #------------------------------------------------------------
     194 -def act_on_generated_forms(parent=None, forms=None, jobtype=None, episode_name=None, progress_note=None, review_copy_as_normal=False):
     195          """This function assumes that .generate_output() has already been called on each form.
     196
     197          It operates on the active patient.
     198          """
     199          if len(forms) == 0:
     200                  return True
     201
     202          no_of_printables = 0
     203          for form in forms:
     204                  no_of_printables += len(form.final_output_filenames)
     205
     206          if no_of_printables == 0:
     207                  return True
     208
     209          soap_lines = []
     210
     211          #-----------------------------
     212          def save_soap(soap=None):
     213                  if episode_name is None:
     214                          return
     215                  if soap.strip() == '':
     216                          return
     217                  pat = gmPerson.gmCurrentPatient()
     218                  emr = pat.emr
     219                  epi = emr.add_episode(episode_name = episode_name, is_open = False)
     220                  emr.add_clin_narrative (
     221                          soap_cat = None,
     222                          note = soap,
     223                          episode = epi
     224                  )
     225
     226          #-----------------------------
     227          def archive_forms(episode_name=None, comment=None):
     228                  if episode_name is None:
     229                          epi = None                              # will ask for episode further down
     230                  else:
     231                          pat = gmPerson.gmCurrentPatient()
     232                          emr = pat.emr
     233                          epi = emr.add_episode(episode_name = episode_name, is_open = False)
     234
     235                  for form in forms:
     236                          files2import = []
     237                          files2import.extend(form.final_output_filenames)
     238                          files2import.extend(form.re_editable_filenames)
     239                          if len(files2import) == 0:
     240                                  continue
     241                          save_files_as_new_document (
     242                                  parent = parent,
     243                                  filenames = files2import,
     244                                  document_type = form.template['instance_type'],
     245                                  unlock_patient = False,
     246                                  episode = epi,
     247                                  review_as_normal = review_copy_as_normal,
     248                                  reference = None,
     249                                  pk_org_unit = gmPraxis.gmCurrentPraxisBranch()['pk_org_unit'],
     250                                  comment = comment
     251                          )
     252
     253                  return True
     254
     255          #-----------------------------
     256          def print_forms():
     257                  # anything to do ?
     258                  files2print = []
     259                  form_names = []
     260                  for form in forms:
     261                          files2print.extend(form.final_output_filenames)
     262                          form_names.append('%s (%s)' % (form.template['name_long'], form.template['external_version']))
     263                  if len(files2print) == 0:
     264                          return True
     265                  # print
     266                  _cfg = gmCfg2.gmCfgData()
     267                  printed = gmPrinting.print_files(filenames = files2print, jobtype = jobtype, verbose = _cfg.get(option = 'debug'))
     268                  if not printed:
     269                          gmGuiHelpers.gm_show_error (
     270                                  aMessage = _('Error printing documents.'),
     271                                  aTitle = _('Printing [%s]') % jobtype
     272                          )
     273                          return False
     274                  soap_lines.append(_('Printed: %s') % ', '.join(form_names))
     275                  return True
     276
     277          #-----------------------------
     278          def export_forms(remote_print=False):
     279                  pat = gmPerson.gmCurrentPatient()
     280                  return pat.export_area.add_forms(forms = forms, designation = gmTools.bool2subst(remote_print, 'print', None, None))
     281
     282          #-----------------------------
     283          if parent is None:
     284                  parent = wx.GetApp().GetTopWindow()
     285
     286          if jobtype is None:
     287                  jobtype = 'generic_document'
     288
     289          dlg = cFormDisposalDlg(parent, -1)
     290          dlg.forms = forms
     291          dlg.progress_note = progress_note
     292          dlg.episode_name = episode_name
     293          action_code = dlg.ShowModal()
     294
     295          if action_code == wx.ID_CANCEL:
     296                  dlg.DestroyLater()
     297                  return True
     298
     299          forms = dlg._LCTRL_forms.get_item_data()
     300          if len(forms) == 0:
     301                  dlg.DestroyLater()
     302                  return True
     303
     304          progress_note = dlg.progress_note
     305          episode_name = dlg._PRW_episode.GetValue().strip()
     306          if episode_name == '':
     307                  episode_name = None
     308          also_export = dlg._CHBOX_export.GetValue()
     309          dlg.DestroyLater()
     310
     311          if action_code == _ID_FORM_DISPOSAL_ARCHIVE_ONLY:
     312                  success = archive_forms(episode_name = episode_name, comment = progress_note)
     313                  if not success:
     314                          return False
     315                  if progress_note != '':
     316                          soap_lines.insert(0, progress_note)
     317                  if len(soap_lines) > 0:
     318                          save_soap(soap = '\n'.join(soap_lines))
     319                  return True
     320
     321          if action_code == _ID_FORM_DISPOSAL_EXPORT_ONLY:
     322                  success = export_forms()
     323                  if not success:
     324                          return False
     325                  if progress_note != '':
     326                          soap_lines.insert(0, progress_note)
     327                  if len(soap_lines) > 0:
     328                          save_soap(soap = '\n'.join(soap_lines))
     329                  return True
     330
     331          success = False
     332          if action_code == _ID_FORM_DISPOSAL_PRINT:
     333                  success = print_forms()
     334                  if episode_name is not None:
     335                          archive_forms(episode_name = episode_name, comment = progress_note)
     336                  if also_export:
     337                          export_forms()
     338
     339          elif action_code == _ID_FORM_DISPOSAL_REMOTE_PRINT:
     340                  success = export_forms(remote_print = True)
     341                  if episode_name is not None:
     342                          archive_forms(episode_name = episode_name, comment = progress_note)
     343
     344          if not success:
     345                  return False
     346
     347          if progress_note != '':
     348                  soap_lines.insert(0, progress_note)
     349          if len(soap_lines) > 0:
     350                  save_soap(soap = '\n'.join(soap_lines))
     351
     352          return True
     353
     354  #============================================================
     355  from Gnumed.wxGladeWidgets import wxgFormDisposalDlg
     356
     357 -class cFormDisposalDlg(wxgFormDisposalDlg.wxgFormDisposalDlg):
     358
     359 -        def __init__(self, *args, **kwargs):
     360
     361                  wxgFormDisposalDlg.wxgFormDisposalDlg.__init__(self, *args, **kwargs)
     362
     363                  self.__init_ui()
     364
     365          #--------------------------------------------------------
     366          # properties
     367          #--------------------------------------------------------
     368 -        def _set_msg(self, msg):
     369                  self._LBL_msg.SetLabel(msg)
     370                  self._LBL_msg.Refresh()
     371
     372          message = property(lambda x:x, _set_msg)
     373
     374          #--------------------------------------------------------
     375 -        def _set_forms(self, forms):
     376                  items = [ f.template['name_long'] for f in forms ]
     377                  self._LCTRL_forms.set_string_items(items)
     378                  self._LCTRL_forms.set_data(forms)
     379
     380          forms = property(lambda x:x, _set_forms)
     381
     382          #--------------------------------------------------------
     383 -        def _get_note(self):
     384                  return self._TCTRL_soap.GetValue().strip()
     385
     386 -        def _set_note(self, note):
     387                  if note is None:
     388                          note = ''
     389                  self._TCTRL_soap.SetValue(note)
     390
     391          progress_note = property(_get_note, _set_note)
     392
     393          #--------------------------------------------------------
     394 -        def _get_episode_name(self):
     395                  return self._PRW_episode.GetValue().strip()
     396
     397 -        def _set_episode_name(self, episode_name):
     398                  if episode_name is None:
     399                          episode_name = ''
     400                  self._PRW_episode.SetValue(episode_name)
     401
     402          episode_name = property(_get_episode_name, _set_episode_name)
     403
     404          #--------------------------------------------------------
     405          # internal helpers
     406          #--------------------------------------------------------
     407 -        def __init_ui(self):
     408                  self._LCTRL_forms.set_columns([_('Form')])
     409                  #self._CHBOX_export.SetValue(False)
     410          #--------------------------------------------------------
     411          # event handlers
     412          #--------------------------------------------------------
     413 -        def _on_print_button_pressed(self, event):
     414                  self.EndModal(_ID_FORM_DISPOSAL_PRINT)
     415          #--------------------------------------------------------
     416 -        def _on_remote_print_button_pressed(self, event):
     417                  self.EndModal(_ID_FORM_DISPOSAL_REMOTE_PRINT)
     418          #--------------------------------------------------------
     419 -        def _on_export_button_pressed(self, event):
     420                  self.EndModal(_ID_FORM_DISPOSAL_EXPORT_ONLY)
     421          #--------------------------------------------------------
     422 -        def _on_archive_button_pressed(self, event):
     423                  self.EndModal(_ID_FORM_DISPOSAL_ARCHIVE_ONLY)
     424          #--------------------------------------------------------
     425 -        def _on_show_forms_button_pressed(self, event):
     426                  event.Skip()
     427                  if self._LCTRL_forms.ItemCount == 0:
     428                          return
     429                  forms2show = self._LCTRL_forms.get_selected_item_data()
     430                  if len(forms2show) == 0:
     431                          data = self._LCTRL_forms.get_item_data(item_idx = 0)
     432                          if data is None:
     433                                  return
     434                          forms2show = [data]
     435                  if len(forms2show) == 0:
     436                          return
     437                  for form in forms2show:
     438                          for filename in form.final_output_filenames:
     439                                  gmMimeLib.call_viewer_on_file(filename, block = True)
     440          #--------------------------------------------------------
     441 -        def _on_delete_forms_button_pressed(self, event):
     442                  print("Event handler '_on_delete_forms_button_pressed' not implemented!")
     443                  event.Skip()
     444
     445  #============================================================
     446  # form template management
     447  #------------------------------------------------------------
     448 -def edit_template(parent=None, template=None, single_entry=False):
     449          ea = cFormTemplateEAPnl(parent, -1)
     450          ea.data = template
     451          ea.mode = gmTools.coalesce(template, 'new', 'edit')
     452          dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry)
     453          dlg.SetTitle(gmTools.coalesce(template, _('Adding new form template'), _('Editing form template')))
     454          if dlg.ShowModal() == wx.ID_OK:
     455                  dlg.DestroyLater()
     456                  return True
     457          dlg.DestroyLater()
     458          return False
     459
     460  #------------------------------------------------------------
     461 -def manage_form_templates(parent=None, template_types=None, active_only=False, excluded_types=None, msg=None):
     462
     463          if parent is None:
     464                  parent = wx.GetApp().GetTopWindow()
     465
     466          #-------------------------
     467          def edit(template=None):
     468                  return edit_template(parent = parent, template = template)
     469          #-------------------------
     470          def delete(template):
     471                  delete = gmGuiHelpers.gm_show_question (
     472                          aTitle = _('Deleting form template.'),
     473                          aMessage = _(
     474                                  'Are you sure you want to delete\n'
     475                                  'the following form template ?\n\n'
     476                                  ' "%s (%s)"\n\n'
     477                                  'You can only delete templates which\n'
     478                                  'have not yet been used to generate\n'
     479                                  'any forms from.'
     480                          ) % (template['name_long'], template['external_version'])
     481                  )
     482                  if delete:
     483                          # FIXME: make this a priviledged operation ?
     484                          gmForms.delete_form_template(template = template)
     485                          return True
     486                  return False
     487          #-------------------------
     488          def refresh(lctrl):
     489                  templates = gmForms.get_form_templates(active_only = active_only, template_types = template_types, excluded_types = excluded_types)
     490                  lctrl.set_string_items(items = [ [t['name_long'], t['external_version'], gmForms.form_engine_names[t['engine']]] for t in templates ])
     491                  lctrl.set_data(data = templates)
     492          #-------------------------
     493          template = gmListWidgets.get_choices_from_list (
     494                  parent = parent,
     495                  msg = msg,
     496                  caption = _('Select letter or form template.'),
     497                  columns = [_('Template'), _('Version'), _('Type')],
     498                  edit_callback = edit,
     499                  new_callback = edit,
     500                  delete_callback = delete,
     501                  refresh_callback = refresh,
     502                  single_selection = True
     503          )
     504
     505          return template
     506
     507  #------------------------------------------------------------
     508  from Gnumed.wxGladeWidgets import wxgFormTemplateEditAreaPnl
     509
     510 -class cFormTemplateEAPnl(wxgFormTemplateEditAreaPnl.wxgFormTemplateEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
     511
     512 -        def __init__(self, *args, **kwargs):
     513
     514                  try:
     515                          data = kwargs['template']
     516                          del kwargs['template']
     517                  except KeyError:
     518                          data = None
     519
     520                  wxgFormTemplateEditAreaPnl.wxgFormTemplateEditAreaPnl.__init__(self, *args, **kwargs)
     521                  gmEditArea.cGenericEditAreaMixin.__init__(self)
     522
     523                  self.full_filename = None
     524
     525                  self.mode = 'new'
     526                  self.data = data
     527                  if data is not None:
     528                          self.mode = 'edit'
     529
     530                  self.__init_ui()
     531          #----------------------------------------------------------------
     532 -        def __init_ui(self):
     533                  self._PRW_name_long.matcher = gmForms.cFormTemplateNameLong_MatchProvider()
     534                  self._PRW_name_short.matcher = gmForms.cFormTemplateNameShort_MatchProvider()
     535                  self._PRW_template_type.matcher = gmForms.cFormTemplateType_MatchProvider()
     536          #----------------------------------------------------------------
     537          # generic Edit Area mixin API
     538          #----------------------------------------------------------------
     539 -        def _valid_for_save(self):
     540
     541                  validity = True
     542
     543                  # self._TCTRL_filename
     544                  self.display_tctrl_as_valid(tctrl = self._TCTRL_filename, valid = True)
     545                  fname = self._TCTRL_filename.GetValue().strip()
     546                  # 1) new template: file must exist
     547                  if self.data is None:
     548                          try:
     549                                  open(fname, 'r').close()
     550                          except:
     551                                  validity = False
     552                                  self.display_tctrl_as_valid(tctrl = self._TCTRL_filename, valid = False)
     553                                  self.StatusText = _('You must select a template file before saving.')
     554                                  self._TCTRL_filename.SetFocus()
     555                  # 2) existing template
     556                  # - empty = no change
     557                  # - does not exist: name change in DB field
     558                  # - does exist: reload from filesystem
     559
     560                  # self._PRW_instance_type
     561                  if self._PRW_instance_type.GetValue().strip() == '':
     562                          validity = False
     563                          self._PRW_instance_type.display_as_valid(False)
     564                          self.StatusText = _('You must enter a type for documents created with this template.')
     565                          self._PRW_instance_type.SetFocus()
     566                  else:
     567                          self._PRW_instance_type.display_as_valid(True)
     568
     569                  # self._PRW_template_type
     570                  if self._PRW_template_type.GetData() is None:
     571                          validity = False
     572                          self._PRW_template_type.display_as_valid(False)
     573                          self.StatusText = _('You must enter a type for this template.')
     574                          self._PRW_template_type.SetFocus()
     575                  else:
     576                          self._PRW_template_type.display_as_valid(True)
     577
     578                  # self._TCTRL_external_version
     579                  if self._TCTRL_external_version.GetValue().strip() == '':
     580                          validity = False
     581                          self.display_tctrl_as_valid(tctrl = self._TCTRL_external_version, valid = False)
     582                          self.StatusText = _('You must enter a version for this template.')
     583                          self._TCTRL_external_version.SetFocus()
     584                  else:
     585                          self.display_tctrl_as_valid(tctrl = self._TCTRL_external_version, valid = True)
     586
     587                  # self._PRW_name_short
     588                  if self._PRW_name_short.GetValue().strip() == '':
     589                          validity = False
     590                          self._PRW_name_short.display_as_valid(False)
     591                          self.StatusText = _('Missing short name for template.')
     592                          self._PRW_name_short.SetFocus()
     593                  else:
     594                          self._PRW_name_short.display_as_valid(True)
     595
     596                  # self._PRW_name_long
     597                  if self._PRW_name_long.GetValue().strip() == '':
     598                          validity = False
     599                          self._PRW_name_long.display_as_valid(False)
     600                          self.StatusText = _('Missing long name for template.')
     601                          self._PRW_name_long.SetFocus()
     602                  else:
     603                          self._PRW_name_long.display_as_valid(True)
     604
     605                  return validity
     606          #----------------------------------------------------------------
     607 -        def _save_as_new(self):
     608                  data = gmForms.create_form_template (
     609                          template_type = self._PRW_template_type.GetData(),
     610                          name_short = self._PRW_name_short.GetValue().strip(),
     611                          name_long = self._PRW_name_long.GetValue().strip()
     612                  )
     613                  data['external_version'] = self._TCTRL_external_version.GetValue()
     614                  data['instance_type'] = self._PRW_instance_type.GetValue().strip()
     615                  data['filename'] = os.path.split(self._TCTRL_filename.GetValue().strip())[1]
     616                  data['in_use'] = self._CHBOX_active.GetValue()
     617                  data['edit_after_substitution'] = self._CHBOX_editable.GetValue()
     618                  data['engine'] = gmForms.form_engine_abbrevs[self._CH_engine.GetSelection()]
     619                  data.save()
     620
     621                  data.update_template_from_file(filename = self._TCTRL_filename.GetValue().strip())
     622
     623                  self.data = data
     624                  return True
     625          #----------------------------------------------------------------
     626 -        def _save_as_update(self):
     627                  self.data['pk_template_type'] = self._PRW_template_type.GetData()
     628                  self.data['name_short'] = self._PRW_name_short.GetValue().strip()
     629                  self.data['name_long'] = self._PRW_name_long.GetValue().strip()
     630                  self.data['external_version'] = self._TCTRL_external_version.GetValue()
     631                  tmp = self._PRW_instance_type.GetValue().strip()
     632                  if tmp not in [self.data['instance_type'], self.data['l10n_instance_type']]:
     633                          self.data['instance_type'] = tmp
     634                  tmp = os.path.split(self._TCTRL_filename.GetValue().strip())[1]
     635                  if tmp != '':
     636                          self.data['filename'] = tmp
     637                  self.data['in_use'] = self._CHBOX_active.GetValue()
     638                  self.data['edit_after_substitution'] = self._CHBOX_editable.GetValue()
     639                  self.data['engine'] = gmForms.form_engine_abbrevs[self._CH_engine.GetSelection()]
     640                  self.data.save()
     641
     642                  fname = self._TCTRL_filename.GetValue().strip()
     643                  try:
     644                          open(fname, 'r').close()
     645                          self.data.update_template_from_file(filename = fname)
     646                  except:
     647                          pass # filename column already updated
     648
     649                  return True
     650          #----------------------------------------------------------------
     651 -        def _refresh_as_new(self):
     652                  self._PRW_name_long.SetText('')
     653                  self._PRW_name_short.SetText('')
     654                  self._TCTRL_external_version.SetValue('')
     655                  self._PRW_template_type.SetText('')
     656                  self._PRW_instance_type.SetText('')
     657                  self._TCTRL_filename.SetValue('')
     658                  self._CH_engine.SetSelection(0)
     659                  self._CHBOX_active.SetValue(True)
     660                  self._CHBOX_editable.SetValue(True)
     661                  self._LBL_status.SetLabel('')
     662                  self._BTN_export.Enable(False)
     663
     664                  self._PRW_name_long.SetFocus()
     665          #----------------------------------------------------------------
     666 -        def _refresh_as_new_from_existing(self):
     667                  self._refresh_as_new()
     668          #----------------------------------------------------------------
     669 -        def _refresh_from_existing(self):
     670                  self._PRW_name_long.SetText(self.data['name_long'])
     671                  self._PRW_name_short.SetText(self.data['name_short'])
     672                  self._TCTRL_external_version.SetValue(self.data['external_version'])
     673                  self._PRW_template_type.SetText(self.data['l10n_template_type'], data = self.data['pk_template_type'])
     674                  self._PRW_instance_type.SetText(self.data['l10n_instance_type'], data = self.data['instance_type'])
     675                  self._TCTRL_filename.SetValue(self.data['filename'])
     676                  self._CH_engine.SetSelection(gmForms.form_engine_abbrevs.index(self.data['engine']))
     677                  self._CHBOX_active.SetValue(self.data['in_use'])
     678                  self._CHBOX_editable.SetValue(self.data['edit_after_substitution'])
     679                  self._LBL_status.SetLabel(_('last modified %s by %s, internal revision [%s]') % (
     680                          gmDateTime.pydt_strftime(self.data['last_modified'], '%Y %B %d'),
     681                          self.data['modified_by'],
     682                          gmTools.coalesce(self.data['gnumed_revision'], '?')
     683                  ))
     684
     685                  self._TCTRL_filename.Enable(True)
     686                  self._BTN_load.Enable(True)
     687                  self._BTN_export.Enable(True)
     688
     689                  self._BTN_load.SetFocus()
     690          #----------------------------------------------------------------
     691          # event handlers
     692          #----------------------------------------------------------------
     693 -        def _on_load_button_pressed(self, event):
     694                  engine_abbrev = gmForms.form_engine_abbrevs[self._CH_engine.GetSelection()]
     695
     696                  wildcards = []
     697                  try:
     698                          wildcards.append('%s (%s)|%s' % (
     699                                  gmForms.form_engine_names[engine_abbrev],
     700                                  gmForms.form_engine_template_wildcards[engine_abbrev],
     701                                  gmForms.form_engine_template_wildcards[engine_abbrev]
     702                          ))
     703                  except KeyError:
     704                          pass
     705                  wildcards.append("%s (*)|*" % _('all files'))
     706                  wildcards.append("%s (*.*)|*.*" % _('all files (Windows)'))
     707
     708                  dlg = wx.FileDialog (
     709                          parent = self,
     710                          message = _('Choose a form template file'),
     711                          defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')),
     712                          defaultFile = '',
     713                          wildcard = '|'.join(wildcards),
     714                          style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST
     715                  )
     716                  result = dlg.ShowModal()
     717                  if result != wx.ID_CANCEL:
     718                          self._TCTRL_filename.SetValue(dlg.GetPath())
     719                  dlg.DestroyLater()
     720
     721                  event.Skip()
     722          #----------------------------------------------------------------
     723 -        def _on_export_button_pressed(self, event):
     724                  if self.data is None:
     725                          return
     726
     727                  engine_abbrev = gmForms.form_engine_abbrevs[self._CH_engine.GetSelection()]
     728
     729                  wildcards = []
     730                  try:
     731                          wildcards.append('%s (%s)|%s' % (
     732                                  gmForms.form_engine_names[engine_abbrev],
     733                                  gmForms.form_engine_template_wildcards[engine_abbrev],
     734                                  gmForms.form_engine_template_wildcards[engine_abbrev]
     735                          ))
     736                  except KeyError:
     737                          pass
     738                  wildcards.append("%s (*)|*" % _('all files'))
     739                  wildcards.append("%s (*.*)|*.*" % _('all files (Windows)'))
     740
     741                  dlg = wx.FileDialog (
     742                          parent = self,
     743                          message = _('Enter a filename to save the template to'),
     744                          defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')),
     745                          defaultFile = '',
     746                          wildcard = '|'.join(wildcards),
     747                          style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT
     748                  )
     749                  result = dlg.ShowModal()
     750                  if result != wx.ID_CANCEL:
     751                          fname = dlg.GetPath()
     752                          self.data.save_to_file(filename = fname)
     753                  dlg.DestroyLater()
     754
     755                  event.Skip()
     756
     757  #============================================================
     758  from Gnumed.wxGladeWidgets import wxgReceiverSelectionDlg
     759
     760 -class cReceiverSelectionDlg(wxgReceiverSelectionDlg.wxgReceiverSelectionDlg):
     761
     762 -        def __init__(self, *args, **kwargs):
     763                  wxgReceiverSelectionDlg.wxgReceiverSelectionDlg.__init__(self, *args, **kwargs)
     764                  self.__patient = None
     765                  self.__init_ui()
     766                  self.__register_interests()
     767
     768          #------------------------------------------------------------
     769 -        def __init_ui(self):
     770                  if self.__patient is None:
     771                          return
     772
     773                  self._LCTRL_candidates.set_columns([_('Receiver'), _('Details')])
     774                  self._LCTRL_candidates.set_resize_column()
     775                  self._LCTRL_candidates.item_tooltip_callback = self._get_candidate_tooltip
     776                  self.__populate_candidates_list()
     777
     778                  self._LCTRL_addresses.set_resize_column()
     779                  self._LCTRL_addresses.item_tooltip_callback = self._get_address_tooltip
     780                  self._LCTRL_addresses.activate_callback = self._on_address_activated_in_list
     781                  adrs = self.__patient.get_addresses()
     782                  self.__populate_address_list(addresses = adrs)
     783
     784                  self._TCTRL_final_name.SetValue(self.__patient['description'].strip())
     785
     786                  self.Layout()
     787
     788          #------------------------------------------------------------
     789 -        def __register_interests(self):
     790                  self._TCTRL_final_name.add_callback_on_modified(callback = self._on_final_name_modified)
     791                  self._PRW_other_address.add_callback_on_selection(self._on_address_selected_in_PRW)
     792                  self._PRW_org_unit.add_callback_on_set_focus(self._on_entering_org_unit_PRW)
     793                  self._PRW_org_unit.add_callback_on_selection(self._on_org_unit_selected_in_PRW)
     794
     795          #------------------------------------------------------------
     796 -        def __populate_candidates_list(self):
     797
     798                  list_items = [[_('Patient'), self.__patient['description_gender'].strip()]]
     799                  list_data = [(self.__patient['description'].strip(), self.__patient.get_addresses(), '', None)]
     800
     801                  candidate_type = _('Emergency contact')
     802                  if self.__patient['emergency_contact'] is not None:
     803                          name = self.__patient['emergency_contact'].strip()
     804                          list_items.append([candidate_type, name])
     805                          list_data.append((name, [], '', None))
     806                  contact = self.__patient.emergency_contact_in_database
     807                  if contact is not None:
     808                          list_items.append([candidate_type, contact['description_gender']])
     809                          list_data.append((contact['description'].strip(), contact.get_addresses(), '', None))
     810
     811                  candidate_type = _('Primary doctor')
     812                  prov = self.__patient.primary_provider
     813                  if prov is not None:
     814                          ident = prov.identity
     815                          list_items.append([candidate_type, '%s: %s' % (prov['short_alias'], ident['description_gender'])])
     816                          list_data.append((ident['description'].strip(), ident.get_addresses(), _('in-praxis primary provider'), None))
     817
     818                  candidate_type = _('This praxis')
     819                  branches = gmPraxis.get_praxis_branches(order_by = 'branch')
     820                  for branch in branches:
     821                          adr = branch.address
     822                          if adr is None:
     823                                  continue
     824                          list_items.append([candidate_type, '%s @ %s' % (branch['branch'], branch['praxis'])])
     825                          list_data.append(('%s @ %s' % (branch['branch'], branch['praxis']), [adr], branch.format(), None))
     826                  del branches
     827
     828                  candidate_type = _('External care')
     829                  cares = gmExternalCare.get_external_care_items(pk_identity = self.__patient.ID)
     830                  for care in cares:
     831                          details = '%s%s@%s (%s)' % (
     832                                  gmTools.coalesce(care['provider'], '', '%s: '),
     833                                  care['unit'],
     834                                  care['organization'],
     835                                  care['issue']
     836                          )
     837                          name = ('%s%s' % (
     838                                  gmTools.coalesce(care['provider'], '', '%s, '),
     839                                  '%s @ %s' % (care['unit'], care['organization'])
     840                          )).strip()
     841                          org_unit = care.org_unit
     842                          adr = org_unit.address
     843                          if adr is None:
     844                                  addresses = []
     845                          else:
     846                                  addresses = [adr]
     847                          list_items.append([candidate_type, details])
     848                          tt = '\n'.join(care.format(with_health_issue = True, with_address = True, with_comms = True))
     849                          list_data.append((name, addresses, tt, org_unit))
     850                  del cares
     851
     852                  emr = self.__patient.emr
     853
     854                  candidate_type = _('Hospital stay')
     855                  depts = emr.get_attended_hospitals_as_org_units()
     856                  for dept in depts:
     857                          adr = dept.address
     858                          if adr is None:
     859                                  continue
     860                          list_items.append([candidate_type, '%s @ %s' % (dept['unit'], dept['organization'])])
     861                          list_data.append(('%s @ %s' % (dept['unit'], dept['organization']), [adr], '\n'.join(dept.format(with_comms = True)), dept))
     862                  del depts
     863
     864                  candidate_type = _('Procedure')
     865                  proc_locs = emr.get_procedure_locations_as_org_units()
     866                  for proc_loc in proc_locs:
     867                          adr = proc_loc.address
     868                          if adr is None:
     869                                  continue
     870                          list_items.append([candidate_type, '%s @ %s' % (proc_loc['unit'], proc_loc['organization'])])
     871                          list_data.append(('%s @ %s' % (proc_loc['unit'], proc_loc['organization']), [adr], '\n'.join(proc_loc.format(with_comms = True)), proc_loc))
     872                  del proc_locs
     873
     874                  candidate_type = _('Lab')
     875                  labs = emr.get_labs_as_org_units()
     876                  for lab in labs:
     877                          adr = lab.address
     878                          if adr is None:
     879                                  continue
     880                          list_items.append([candidate_type, '%s @ %s' % (lab['unit'], lab['organization'])])
     881                          list_data.append(('%s @ %s' % (lab['unit'], lab['organization']), [adr], '\n'.join(lab.format(with_comms = True)), lab))
     882                  del labs
     883
     884                  candidate_type = _('Bill receiver')
     885                  bills = self.__patient.bills
     886                  adrs_seen = []
     887                  for bill in bills:
     888                          if bill['pk_receiver_address'] in adrs_seen:
     889                                  continue
     890                          adr = bill.address
     891                          if adr is None:
     892                                  continue
     893                          adrs_seen.append(bill['pk_receiver_address'])
     894                          details = '%s%s' % (bill['invoice_id'], gmDateTime.pydt_strftime(dt = bill['close_date'], format = ' (%Y %b %d)', none_str = ''))
     895                          list_items.append([candidate_type, details])
     896                          list_data.append(('', [adr], '\n'.join(adr.format()), None))
     897
     898                  candidate_type = _('Document')
     899                  doc_folder = self.__patient.document_folder
     900                  doc_units = doc_folder.all_document_org_units
     901                  for doc_unit in doc_units:
     902                          adr = doc_unit.address
     903                          if adr is None:
     904                                  continue
     905                          list_items.append([candidate_type, '%s @ %s' % (doc_unit['unit'], doc_unit['organization'])])
     906                          list_data.append(('%s @ %s' % (doc_unit['unit'], doc_unit['organization']), [adr], '\n'.join(doc_unit.format(with_comms = True)), doc_unit))
     907                  del doc_units
     908
     909                  self._LCTRL_candidates.set_string_items(list_items)
     910                  self._LCTRL_candidates.set_column_widths()
     911                  self._LCTRL_candidates.set_data(list_data)
     912
     913          #------------------------------------------------------------
     914 -        def _get_candidate_tooltip(self, data):
     915                  if data is None:
     916                          return ''
     917                  name, addresses, tt, unit = data
     918                  return tt
     919
     920          #------------------------------------------------------------
     921 -        def __update_address_info(self, adr):
     922                  if adr is None:
     923                          self._LBL_address_details.SetLabel('')
     924                          self._LBL_final_country.SetLabel('')
     925                          self._LBL_final_region.SetLabel('')
     926                          self._LBL_final_zip.SetLabel('')
     927                          self._LBL_final_location.SetLabel('')
     928                          self._LBL_final_street.SetLabel('')
     929                          self._LBL_final_number.SetLabel('')
     930                          self.Layout()
     931                          return
     932                  self._LBL_address_details.SetLabel('\n'.join(adr.format()))
     933                  self._LBL_final_country.SetLabel(adr['l10n_country'])
     934                  self._LBL_final_region.SetLabel(adr['l10n_region'])
     935                  self._LBL_final_zip.SetLabel(adr['postcode'])
     936                  self._LBL_final_location.SetLabel('%s%s' % (adr['urb'], gmTools.coalesce(adr['suburb'], '', ' - %s')))
     937                  self._LBL_final_street.SetLabel(adr['street'])
     938                  self._LBL_final_number.SetLabel('%s%s' % (adr['number'], gmTools.coalesce(adr['subunit'], '', ' %s')))
     939                  self.Layout()
     940
     941          #------------------------------------------------------------
     942 -        def __populate_address_list(self, addresses=None):
     943                  self._LCTRL_addresses.Enable()
     944                  cols = [_(u'Address')]
     945                  list_items = []
     946                  for a in addresses:
     947                          try:
     948                                  list_items.append([a['l10n_address_type'], a.format(single_line = True, verbose = False, show_type = False)])
     949                                  cols = [_('Type'), _('Address')]
     950                          except KeyError:
     951                                  list_items.append([a.format(single_line = True, verbose = False, show_type = False)])
     952                                  cols = [_('Address')]
     953
     954                  self._LCTRL_addresses.set_columns(cols)
     955                  self._LCTRL_addresses.set_string_items(list_items)
     956                  self._LCTRL_candidates.set_column_widths()
     957                  self._LCTRL_addresses.set_data(addresses)
     958                  self._PRW_other_address.SetText(value = '', data = None)
     959                  self.__update_address_info(None)
     960
     961          #------------------------------------------------------------
     962 -        def _get_address_tooltip(self, adr):
     963                  return '\n'.join(adr.format(show_type = True))
     964
     965          #------------------------------------------------------------
     966          #------------------------------------------------------------
     967 -        def _on_final_name_modified(self):
     968                  self._LBL_final_name.SetLabel(self._TCTRL_final_name.Value)
     969
     970          #------------------------------------------------------------
     971 -        def _on_address_selected_in_PRW(self, address):
     972                  self.__update_address_info(self._PRW_other_address.GetData(as_instance = True))
     973
     974          #------------------------------------------------------------
     975 -        def _on_entering_org_unit_PRW(self):
     976                  self._LCTRL_addresses.Disable()
     977
     978          #------------------------------------------------------------
     979 -        def _on_org_unit_selected_in_PRW(self, unit):
     980                  if unit is None:
     981                          self._LCTRL_addresses.remove_items_safely(max_tries = 3)
     982                          self._PRW_other_address.SetText(value = '', data = None)
     983                          self.__update_address_info(None)
     984                          self._TCTRL_org_unit_details.SetValue('')
     985                          return
     986
     987                  unit = self._PRW_org_unit.GetData(as_instance = True)
     988                  adr = unit.address
     989                  if adr is None:
     990                          self._LCTRL_addresses.remove_items_safely(max_tries = 3)
     991                          self._PRW_other_address.SetText(value = '', data = None)
     992                          self.__update_address_info(None)
     993                  else:
     994                          self.__populate_address_list(addresses = [adr])
     995                          self._PRW_other_address.SetData(data = adr['pk_address'])
     996                          self.__update_address_info(adr)
     997
     998                  name = '%s @ %s' % (unit['unit'], unit['organization'])
     999                  self._TCTRL_final_name.SetValue(name)
    1000                  self._TCTRL_org_unit_details.SetValue('\n'.join(unit.format(with_comms = True)))
    1001                  self.Layout()
    1002
    1003          #------------------------------------------------------------
    1004          #------------------------------------------------------------
    1005 -        def _on_candidate_selected(self, event):
    1006                  event.Skip()
    1007                  name, addresses, tt, unit = self._LCTRL_candidates.get_selected_item_data(only_one = True)
    1008                  self.__populate_address_list(addresses = addresses)
    1009                  if unit is None:
    1010                          self._PRW_org_unit.SetText(value = '', data = None)
    1011                          self._TCTRL_org_unit_details.SetValue('')
    1012                  else:
    1013                          self._PRW_org_unit.SetData(data = unit['pk_org_unit'])
    1014                          self._TCTRL_org_unit_details.SetValue('\n'.join(unit.format(with_comms = True)))
    1015                  self._TCTRL_final_name.SetValue(name.strip())
    1016                  self._LBL_final_name.SetLabel(name.strip())
    1017
    1018          #------------------------------------------------------------
    1019 -        def _on_address_activated_in_list(self, evt):
    1020                  evt.Skip()
    1021                  adr = self._LCTRL_addresses.get_selected_item_data(only_one = True)
    1022                  self._PRW_other_address.address = adr
    1023                  self.__update_address_info(adr)
    1024
    1025          #------------------------------------------------------------
    1026          #------------------------------------------------------------
    1027 -        def _on_manage_addresses_button_pressed(self, event):
    1028                  event.Skip()
    1029                  manage_addresses(parent = self)
    1030
    1031          #------------------------------------------------------------
    1032 -        def _on_manage_orgs_button_pressed(self, event):
    1033                  event.Skip()
    1034                  from Gnumed.wxpython.gmOrganizationWidgets import manage_orgs
    1035                  manage_orgs(parent = self, no_parent = False)
    1036
    1037          #------------------------------------------------------------
    1038 -        def _on_ok_button_pressed(self, event):
    1039                  if self._TCTRL_final_name.GetValue().strip() == '':
    1040                          return False
    1041                  if self._PRW_other_address.address is None:
    1042                          return False
    1043                  event.Skip()
    1044                  self.EndModal(wx.ID_OK)
    1045
    1046          #------------------------------------------------------------
    1047 -        def _set_patient(self, patient):
    1048                  self.__patient = patient
    1049                  self.__init_ui()
    1050
    1051          patient = property(lambda x:x, _set_patient)
    1052
    1053          #------------------------------------------------------------
    1054 -        def _get_name(self):
    1055                  return self._TCTRL_final_name.GetValue().strip()
    1056
    1057          name = property(_get_name, lambda x:x)
    1058
    1059          #------------------------------------------------------------
    1060 -        def _get_address(self):
    1061                  return self._PRW_other_address.address
    1062
    1063          address = property(_get_address, lambda x:x)
    1064
    1065  #============================================================
    1066  # main
    1067  #------------------------------------------------------------
    1068  if __name__ == '__main__':
    1069
    1070          gmI18N.activate_locale()
    1071          gmI18N.install_domain(domain = 'gnumed')
    1072
    1073          #----------------------------------------
    1074 -        def test_cFormTemplateEAPnl():
    1075                  app = wx.PyWidgetTester(size = (400, 300))
    1076                  pnl = cFormTemplateEAPnl(app.frame, -1, template = gmForms.cFormTemplate(aPK_obj=4))
    1077                  app.frame.Show(True)
    1078                  app.MainLoop()
    1079                  return
    1080          #----------------------------------------
    1081          if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
    1082                  test_cFormTemplateEAPnl()
    1083
    1084  #============================================================
    1085