Gnumed.wxpython.gmFormWidgets

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 Exception: 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                  for form in forms:
     235                          files2import = []
     236                          files2import.extend(form.final_output_filenames)
     237                          files2import.extend(form.re_editable_filenames)
     238                          if len(files2import) == 0:
     239                                  continue
     240                          save_files_as_new_document (
     241                                  parent = parent,
     242                                  filenames = files2import,
     243                                  document_type = form.template['instance_type'],
     244                                  unlock_patient = False,
     245                                  episode = epi,
     246                                  review_as_normal = review_copy_as_normal,
     247                                  reference = None,
     248                                  pk_org_unit = gmPraxis.gmCurrentPraxisBranch()['pk_org_unit'],
     249                                  comment = comment,
     250                                  date_generated = gmDateTime.pydt_now_here()
     251                          )
     252                  return True
     253
     254          #-----------------------------
     255          def print_forms():
     256                  # anything to do ?
     257                  files2print = []
     258                  form_names = []
     259                  for form in forms:
     260                          files2print.extend(form.final_output_filenames)
     261                          form_names.append('%s (%s)' % (form.template['name_long'], form.template['external_version']))
     262                  if len(files2print) == 0:
     263                          return True
     264                  # print
     265                  _cfg = gmCfg2.gmCfgData()
     266                  printed = gmPrinting.print_files(filenames = files2print, jobtype = jobtype, verbose = _cfg.get(option = 'debug'))
     267                  if not printed:
     268                          gmGuiHelpers.gm_show_error (
     269                                  aMessage = _('Error printing documents.'),
     270                                  aTitle = _('Printing [%s]') % jobtype
     271                          )
     272                          return False
     273                  soap_lines.append(_('Printed: %s') % ', '.join(form_names))
     274                  return True
     275
     276          #-----------------------------
     277          def export_forms(remote_print=False):
     278                  pat = gmPerson.gmCurrentPatient()
     279                  return pat.export_area.add_forms(forms = forms, designation = gmTools.bool2subst(remote_print, 'print', None, None))
     280
     281          #-----------------------------
     282          if parent is None:
     283                  parent = wx.GetApp().GetTopWindow()
     284
     285          if jobtype is None:
     286                  jobtype = 'generic_document'
     287
     288          dlg = cFormDisposalDlg(parent, -1)
     289          dlg.forms = forms
     290          dlg.progress_note = progress_note
     291          dlg.episode_name = episode_name
     292          action_code = dlg.ShowModal()
     293
     294          if action_code == wx.ID_CANCEL:
     295                  dlg.DestroyLater()
     296                  return True
     297
     298          forms = dlg._LCTRL_forms.get_item_data()
     299          if len(forms) == 0:
     300                  dlg.DestroyLater()
     301                  return True
     302
     303          progress_note = dlg.progress_note
     304          episode_name = dlg._PRW_episode.GetValue().strip()
     305          if episode_name == '':
     306                  episode_name = None
     307          also_export = dlg._CHBOX_export.GetValue()
     308          dlg.DestroyLater()
     309
     310          if action_code == _ID_FORM_DISPOSAL_ARCHIVE_ONLY:
     311                  success = archive_forms(episode_name = episode_name, comment = progress_note)
     312                  if not success:
     313                          return False
     314                  if progress_note != '':
     315                          soap_lines.insert(0, progress_note)
     316                  if len(soap_lines) > 0:
     317                          save_soap(soap = '\n'.join(soap_lines))
     318                  return True
     319
     320          if action_code == _ID_FORM_DISPOSAL_EXPORT_ONLY:
     321                  success = export_forms()
     322                  if not success:
     323                          return False
     324                  if progress_note != '':
     325                          soap_lines.insert(0, progress_note)
     326                  if len(soap_lines) > 0:
     327                          save_soap(soap = '\n'.join(soap_lines))
     328                  return True
     329
     330          success = False
     331          if action_code == _ID_FORM_DISPOSAL_PRINT:
     332                  success = print_forms()
     333                  if episode_name is not None:
     334                          archive_forms(episode_name = episode_name, comment = progress_note)
     335                  if also_export:
     336                          export_forms()
     337
     338          elif action_code == _ID_FORM_DISPOSAL_REMOTE_PRINT:
     339                  success = export_forms(remote_print = True)
     340                  if episode_name is not None:
     341                          archive_forms(episode_name = episode_name, comment = progress_note)
     342
     343          if not success:
     344                  return False
     345
     346          if progress_note != '':
     347                  soap_lines.insert(0, progress_note)
     348          if len(soap_lines) > 0:
     349                  save_soap(soap = '\n'.join(soap_lines))
     350
     351          return True
     352
     353  #============================================================
     354  from Gnumed.wxGladeWidgets import wxgFormDisposalDlg
     355
     356 -class cFormDisposalDlg(wxgFormDisposalDlg.wxgFormDisposalDlg):
     357
     358 -        def __init__(self, *args, **kwargs):
     359
     360                  wxgFormDisposalDlg.wxgFormDisposalDlg.__init__(self, *args, **kwargs)
     361
     362                  self.__init_ui()
     363
     364          #--------------------------------------------------------
     365          # properties
     366          #--------------------------------------------------------
     367 -        def _set_msg(self, msg):
     368                  self._LBL_msg.SetLabel(msg)
     369                  self._LBL_msg.Refresh()
     370
     371          message = property(lambda x:x, _set_msg)
     372
     373          #--------------------------------------------------------
     374 -        def _set_forms(self, forms):
     375                  items = [ f.template['name_long'] for f in forms ]
     376                  self._LCTRL_forms.set_string_items(items)
     377                  self._LCTRL_forms.set_data(forms)
     378
     379          forms = property(lambda x:x, _set_forms)
     380
     381          #--------------------------------------------------------
     382 -        def _get_note(self):
     383                  return self._TCTRL_soap.GetValue().strip()
     384
     385 -        def _set_note(self, note):
     386                  if note is None:
     387                          note = ''
     388                  self._TCTRL_soap.SetValue(note)
     389
     390          progress_note = property(_get_note, _set_note)
     391
     392          #--------------------------------------------------------
     393 -        def _get_episode_name(self):
     394                  return self._PRW_episode.GetValue().strip()
     395
     396 -        def _set_episode_name(self, episode_name):
     397                  if episode_name is None:
     398                          episode_name = ''
     399                  self._PRW_episode.SetValue(episode_name)
     400
     401          episode_name = property(_get_episode_name, _set_episode_name)
     402
     403          #--------------------------------------------------------
     404          # internal helpers
     405          #--------------------------------------------------------
     406 -        def __init_ui(self):
     407                  self._LCTRL_forms.set_columns([_('Form')])
     408                  #self._CHBOX_export.SetValue(False)
     409          #--------------------------------------------------------
     410          # event handlers
     411          #--------------------------------------------------------
     412 -        def _on_print_button_pressed(self, event):
     413                  self.EndModal(_ID_FORM_DISPOSAL_PRINT)
     414          #--------------------------------------------------------
     415 -        def _on_remote_print_button_pressed(self, event):
     416                  self.EndModal(_ID_FORM_DISPOSAL_REMOTE_PRINT)
     417          #--------------------------------------------------------
     418 -        def _on_export_button_pressed(self, event):
     419                  self.EndModal(_ID_FORM_DISPOSAL_EXPORT_ONLY)
     420          #--------------------------------------------------------
     421 -        def _on_archive_button_pressed(self, event):
     422                  self.EndModal(_ID_FORM_DISPOSAL_ARCHIVE_ONLY)
     423          #--------------------------------------------------------
     424 -        def _on_show_forms_button_pressed(self, event):
     425                  event.Skip()
     426                  if self._LCTRL_forms.ItemCount == 0:
     427                          return
     428                  forms2show = self._LCTRL_forms.get_selected_item_data()
     429                  if len(forms2show) == 0:
     430                          data = self._LCTRL_forms.get_item_data(item_idx = 0)
     431                          if data is None:
     432                                  return
     433                          forms2show = [data]
     434                  if len(forms2show) == 0:
     435                          return
     436                  for form in forms2show:
     437                          for filename in form.final_output_filenames:
     438                                  gmMimeLib.call_viewer_on_file(filename, block = True)
     439          #--------------------------------------------------------
     440 -        def _on_delete_forms_button_pressed(self, event):
     441                  print("Event handler '_on_delete_forms_button_pressed' not implemented!")
     442                  event.Skip()
     443
     444  #============================================================
     445  # form template management
     446  #------------------------------------------------------------
     447 -def edit_template(parent=None, template=None, single_entry=False):
     448          ea = cFormTemplateEAPnl(parent, -1)
     449          ea.data = template
     450          ea.mode = gmTools.coalesce(template, 'new', 'edit')
     451          dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry)
     452          dlg.SetTitle(gmTools.coalesce(template, _('Adding new form template'), _('Editing form template')))
     453          if dlg.ShowModal() == wx.ID_OK:
     454                  dlg.DestroyLater()
     455                  return True
     456          dlg.DestroyLater()
     457          return False
     458
     459  #------------------------------------------------------------
     460 -def manage_form_templates(parent=None, template_types=None, active_only=False, excluded_types=None, msg=None):
     461
     462          if parent is None:
     463                  parent = wx.GetApp().GetTopWindow()
     464
     465          #-------------------------
     466          def edit(template=None):
     467                  return edit_template(parent = parent, template = template)
     468          #-------------------------
     469          def delete(template):
     470                  delete = gmGuiHelpers.gm_show_question (
     471                          aTitle = _('Deleting form template.'),
     472                          aMessage = _(
     473                                  'Are you sure you want to delete\n'
     474                                  'the following form template ?\n\n'
     475                                  ' "%s (%s)"\n\n'
     476                                  'You can only delete templates which\n'
     477                                  'have not yet been used to generate\n'
     478                                  'any forms from.'
     479                          ) % (template['name_long'], template['external_version'])
     480                  )
     481                  if delete:
     482                          # FIXME: make this a priviledged operation ?
     483                          gmForms.delete_form_template(template = template)
     484                          return True
     485                  return False
     486          #-------------------------
     487          def refresh(lctrl):
     488                  templates = gmForms.get_form_templates(active_only = active_only, template_types = template_types, excluded_types = excluded_types)
     489                  lctrl.set_string_items(items = [ [t['name_long'], t['external_version'], gmForms.form_engine_names[t['engine']]] for t in templates ])
     490                  lctrl.set_data(data = templates)
     491          #-------------------------
     492          template = gmListWidgets.get_choices_from_list (
     493                  parent = parent,
     494                  msg = msg,
     495                  caption = _('Select letter or form template.'),
     496                  columns = [_('Template'), _('Version'), _('Type')],
     497                  edit_callback = edit,
     498                  new_callback = edit,
     499                  delete_callback = delete,
     500                  refresh_callback = refresh,
     501                  single_selection = True
     502          )
     503
     504          return template
     505
     506  #------------------------------------------------------------
     507  from Gnumed.wxGladeWidgets import wxgFormTemplateEditAreaPnl
     508
     509 -class cFormTemplateEAPnl(wxgFormTemplateEditAreaPnl.wxgFormTemplateEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
     510
     511 -        def __init__(self, *args, **kwargs):
     512
     513                  try:
     514                          data = kwargs['template']
     515                          del kwargs['template']
     516                  except KeyError:
     517                          data = None
     518
     519                  wxgFormTemplateEditAreaPnl.wxgFormTemplateEditAreaPnl.__init__(self, *args, **kwargs)
     520                  gmEditArea.cGenericEditAreaMixin.__init__(self)
     521
     522                  self.full_filename = None
     523
     524                  self.mode = 'new'
     525                  self.data = data
     526                  if data is not None:
     527                          self.mode = 'edit'
     528
     529                  self.__init_ui()
     530          #----------------------------------------------------------------
     531 -        def __init_ui(self):
     532                  self._PRW_name_long.matcher = gmForms.cFormTemplateNameLong_MatchProvider()
     533                  self._PRW_name_short.matcher = gmForms.cFormTemplateNameShort_MatchProvider()
     534                  self._PRW_template_type.matcher = gmForms.cFormTemplateType_MatchProvider()
     535          #----------------------------------------------------------------
     536          # generic Edit Area mixin API
     537          #----------------------------------------------------------------
     538 -        def _valid_for_save(self):
     539
     540                  validity = True
     541
     542                  # self._TCTRL_filename
     543                  self.display_tctrl_as_valid(tctrl = self._TCTRL_filename, valid = True)
     544                  fname = self._TCTRL_filename.GetValue().strip()
     545                  # 1) new template: file must exist
     546                  if self.data is None:
     547                          try:
     548                                  open(fname, 'r').close()
     549                          except Exception:
     550                                  validity = False
     551                                  self.display_tctrl_as_valid(tctrl = self._TCTRL_filename, valid = False)
     552                                  self.StatusText = _('You must select a template file before saving.')
     553                                  self._TCTRL_filename.SetFocus()
     554                  # 2) existing template
     555                  # - empty = no change
     556                  # - does not exist: name change in DB field
     557                  # - does exist: reload from filesystem
     558
     559                  # self._PRW_instance_type
     560                  if self._PRW_instance_type.GetValue().strip() == '':
     561                          validity = False
     562                          self._PRW_instance_type.display_as_valid(False)
     563                          self.StatusText = _('You must enter a type for documents created with this template.')
     564                          self._PRW_instance_type.SetFocus()
     565                  else:
     566                          self._PRW_instance_type.display_as_valid(True)
     567
     568                  # self._PRW_template_type
     569                  if self._PRW_template_type.GetData() is None:
     570                          validity = False
     571                          self._PRW_template_type.display_as_valid(False)
     572                          self.StatusText = _('You must enter a type for this template.')
     573                          self._PRW_template_type.SetFocus()
     574                  else:
     575                          self._PRW_template_type.display_as_valid(True)
     576
     577                  # self._TCTRL_external_version
     578                  if self._TCTRL_external_version.GetValue().strip() == '':
     579                          validity = False
     580                          self.display_tctrl_as_valid(tctrl = self._TCTRL_external_version, valid = False)
     581                          self.StatusText = _('You must enter a version for this template.')
     582                          self._TCTRL_external_version.SetFocus()
     583                  else:
     584                          self.display_tctrl_as_valid(tctrl = self._TCTRL_external_version, valid = True)
     585
     586                  # self._PRW_name_short
     587                  if self._PRW_name_short.GetValue().strip() == '':
     588                          validity = False
     589                          self._PRW_name_short.display_as_valid(False)
     590                          self.StatusText = _('Missing short name for template.')
     591                          self._PRW_name_short.SetFocus()
     592                  else:
     593                          self._PRW_name_short.display_as_valid(True)
     594
     595                  # self._PRW_name_long
     596                  if self._PRW_name_long.GetValue().strip() == '':
     597                          validity = False
     598                          self._PRW_name_long.display_as_valid(False)
     599                          self.StatusText = _('Missing long name for template.')
     600                          self._PRW_name_long.SetFocus()
     601                  else:
     602                          self._PRW_name_long.display_as_valid(True)
     603
     604                  return validity
     605          #----------------------------------------------------------------
     606 -        def _save_as_new(self):
     607                  data = gmForms.create_form_template (
     608                          template_type = self._PRW_template_type.GetData(),
     609                          name_short = self._PRW_name_short.GetValue().strip(),
     610                          name_long = self._PRW_name_long.GetValue().strip()
     611                  )
     612                  data['external_version'] = self._TCTRL_external_version.GetValue()
     613                  data['instance_type'] = self._PRW_instance_type.GetValue().strip()
     614                  data['filename'] = os.path.split(self._TCTRL_filename.GetValue().strip())[1]
     615                  data['in_use'] = self._CHBOX_active.GetValue()
     616                  data['edit_after_substitution'] = self._CHBOX_editable.GetValue()
     617                  data['engine'] = gmForms.form_engine_abbrevs[self._CH_engine.GetSelection()]
     618                  data.save()
     619
     620                  data.update_template_from_file(filename = self._TCTRL_filename.GetValue().strip())
     621
     622                  self.data = data
     623                  return True
     624          #----------------------------------------------------------------
     625 -        def _save_as_update(self):
     626                  self.data['pk_template_type'] = self._PRW_template_type.GetData()
     627                  self.data['name_short'] = self._PRW_name_short.GetValue().strip()
     628                  self.data['name_long'] = self._PRW_name_long.GetValue().strip()
     629                  self.data['external_version'] = self._TCTRL_external_version.GetValue()
     630                  tmp = self._PRW_instance_type.GetValue().strip()
     631                  if tmp not in [self.data['instance_type'], self.data['l10n_instance_type']]:
     632                          self.data['instance_type'] = tmp
     633                  tmp = os.path.split(self._TCTRL_filename.GetValue().strip())[1]
     634                  if tmp != '':
     635                          self.data['filename'] = tmp
     636                  self.data['in_use'] = self._CHBOX_active.GetValue()
     637                  self.data['edit_after_substitution'] = self._CHBOX_editable.GetValue()
     638                  self.data['engine'] = gmForms.form_engine_abbrevs[self._CH_engine.GetSelection()]
     639                  self.data.save()
     640
     641                  fname = self._TCTRL_filename.GetValue().strip()
     642                  try:
     643                          open(fname, 'r').close()
     644                          self.data.update_template_from_file(filename = fname)
     645                  except Exception:
     646                          pass # filename column already updated
     647
     648                  return True
     649          #----------------------------------------------------------------
     650 -        def _refresh_as_new(self):
     651                  self._PRW_name_long.SetText('')
     652                  self._PRW_name_short.SetText('')
     653                  self._TCTRL_external_version.SetValue('')
     654                  self._PRW_template_type.SetText('')
     655                  self._PRW_instance_type.SetText('')
     656                  self._TCTRL_filename.SetValue('')
     657                  self._CH_engine.SetSelection(0)
     658                  self._CHBOX_active.SetValue(True)
     659                  self._CHBOX_editable.SetValue(True)
     660                  self._LBL_status.SetLabel('')
     661                  self._BTN_export.Enable(False)
     662
     663                  self._PRW_name_long.SetFocus()
     664          #----------------------------------------------------------------
     665 -        def _refresh_as_new_from_existing(self):
     666                  self._refresh_as_new()
     667          #----------------------------------------------------------------
     668 -        def _refresh_from_existing(self):
     669                  self._PRW_name_long.SetText(self.data['name_long'])
     670                  self._PRW_name_short.SetText(self.data['name_short'])
     671                  self._TCTRL_external_version.SetValue(self.data['external_version'])
     672                  self._PRW_template_type.SetText(self.data['l10n_template_type'], data = self.data['pk_template_type'])
     673                  self._PRW_instance_type.SetText(self.data['l10n_instance_type'], data = self.data['instance_type'])
     674                  self._TCTRL_filename.SetValue(self.data['filename'])
     675                  self._CH_engine.SetSelection(gmForms.form_engine_abbrevs.index(self.data['engine']))
     676                  self._CHBOX_active.SetValue(self.data['in_use'])
     677                  self._CHBOX_editable.SetValue(self.data['edit_after_substitution'])
     678                  self._LBL_status.SetLabel(_('last modified %s by %s, internal revision [%s]') % (
     679                          gmDateTime.pydt_strftime(self.data['last_modified'], '%Y %B %d'),
     680                          self.data['modified_by'],
     681                          gmTools.coalesce(self.data['gnumed_revision'], '?')
     682                  ))
     683
     684                  self._TCTRL_filename.Enable(True)
     685                  self._BTN_load.Enable(True)
     686                  self._BTN_export.Enable(True)
     687
     688                  self._BTN_load.SetFocus()
     689          #----------------------------------------------------------------
     690          # event handlers
     691          #----------------------------------------------------------------
     692 -        def _on_load_button_pressed(self, event):
     693                  engine_abbrev = gmForms.form_engine_abbrevs[self._CH_engine.GetSelection()]
     694
     695                  wildcards = []
     696                  try:
     697                          wildcards.append('%s (%s)|%s' % (
     698                                  gmForms.form_engine_names[engine_abbrev],
     699                                  gmForms.form_engine_template_wildcards[engine_abbrev],
     700                                  gmForms.form_engine_template_wildcards[engine_abbrev]
     701                          ))
     702                  except KeyError:
     703                          pass
     704                  wildcards.append("%s (*)|*" % _('all files'))
     705                  wildcards.append("%s (*.*)|*.*" % _('all files (Windows)'))
     706
     707                  dlg = wx.FileDialog (
     708                          parent = self,
     709                          message = _('Choose a form template file'),
     710                          defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')),
     711                          defaultFile = '',
     712                          wildcard = '|'.join(wildcards),
     713                          style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST
     714                  )
     715                  result = dlg.ShowModal()
     716                  if result != wx.ID_CANCEL:
     717                          self._TCTRL_filename.SetValue(dlg.GetPath())
     718                  dlg.DestroyLater()
     719
     720                  event.Skip()
     721          #----------------------------------------------------------------
     722 -        def _on_export_button_pressed(self, event):
     723                  if self.data is None:
     724                          return
     725
     726                  engine_abbrev = gmForms.form_engine_abbrevs[self._CH_engine.GetSelection()]
     727
     728                  wildcards = []
     729                  try:
     730                          wildcards.append('%s (%s)|%s' % (
     731                                  gmForms.form_engine_names[engine_abbrev],
     732                                  gmForms.form_engine_template_wildcards[engine_abbrev],
     733                                  gmForms.form_engine_template_wildcards[engine_abbrev]
     734                          ))
     735                  except KeyError:
     736                          pass
     737                  wildcards.append("%s (*)|*" % _('all files'))
     738                  wildcards.append("%s (*.*)|*.*" % _('all files (Windows)'))
     739
     740                  dlg = wx.FileDialog (
     741                          parent = self,
     742                          message = _('Enter a filename to save the template to'),
     743                          defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')),
     744                          defaultFile = '',
     745                          wildcard = '|'.join(wildcards),
     746                          style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT
     747                  )
     748                  result = dlg.ShowModal()
     749                  if result != wx.ID_CANCEL:
     750                          fname = dlg.GetPath()
     751                          self.data.save_to_file(filename = fname)
     752                  dlg.DestroyLater()
     753
     754                  event.Skip()
     755
     756  #============================================================
     757  from Gnumed.wxGladeWidgets import wxgReceiverSelectionDlg
     758
     759 -class cReceiverSelectionDlg(wxgReceiverSelectionDlg.wxgReceiverSelectionDlg):
     760
     761 -        def __init__(self, *args, **kwargs):
     762                  wxgReceiverSelectionDlg.wxgReceiverSelectionDlg.__init__(self, *args, **kwargs)
     763                  self.__patient = None
     764                  self.__init_ui()
     765                  self.__register_interests()
     766
     767          #------------------------------------------------------------
     768 -        def __init_ui(self):
     769                  if self.__patient is None:
     770                          return
     771
     772                  self._LCTRL_candidates.set_columns([_('Receiver'), _('Details')])
     773                  self._LCTRL_candidates.set_resize_column()
     774                  self._LCTRL_candidates.item_tooltip_callback = self._get_candidate_tooltip
     775                  self.__populate_candidates_list()
     776
     777                  self._LCTRL_addresses.set_resize_column()
     778                  self._LCTRL_addresses.item_tooltip_callback = self._get_address_tooltip
     779                  self._LCTRL_addresses.activate_callback = self._on_address_activated_in_list
     780                  adrs = self.__patient.get_addresses()
     781                  self.__populate_address_list(addresses = adrs)
     782
     783                  self._TCTRL_final_name.SetValue(self.__patient['description'].strip())
     784
     785                  self.Layout()
     786
     787          #------------------------------------------------------------
     788 -        def __register_interests(self):
     789                  self._TCTRL_final_name.add_callback_on_modified(callback = self._on_final_name_modified)
     790                  self._PRW_other_address.add_callback_on_selection(self._on_address_selected_in_PRW)
     791                  self._PRW_org_unit.add_callback_on_set_focus(self._on_entering_org_unit_PRW)
     792                  self._PRW_org_unit.add_callback_on_selection(self._on_org_unit_selected_in_PRW)
     793
     794          #------------------------------------------------------------
     795 -        def __populate_candidates_list(self):
     796
     797                  list_items = [[_('Patient'), self.__patient['description_gender'].strip()]]
     798                  list_data = [(self.__patient['description'].strip(), self.__patient.get_addresses(), '', None)]
     799
     800                  candidate_type = _('Emergency contact')
     801                  if self.__patient['emergency_contact'] is not None:
     802                          name = self.__patient['emergency_contact'].strip()
     803                          list_items.append([candidate_type, name])
     804                          list_data.append((name, [], '', None))
     805                  contact = self.__patient.emergency_contact_in_database
     806                  if contact is not None:
     807                          list_items.append([candidate_type, contact['description_gender']])
     808                          list_data.append((contact['description'].strip(), contact.get_addresses(), '', None))
     809
     810                  candidate_type = _('Primary doctor')
     811                  prov = self.__patient.primary_provider
     812                  if prov is not None:
     813                          ident = prov.identity
     814                          list_items.append([candidate_type, '%s: %s' % (prov['short_alias'], ident['description_gender'])])
     815                          list_data.append((ident['description'].strip(), ident.get_addresses(), _('in-praxis primary provider'), None))
     816
     817                  candidate_type = _('This praxis')
     818                  branches = gmPraxis.get_praxis_branches(order_by = 'branch')
     819                  for branch in branches:
     820                          adr = branch.address
     821                          if adr is None:
     822                                  continue
     823                          list_items.append([candidate_type, '%s @ %s' % (branch['branch'], branch['praxis'])])
     824                          list_data.append(('%s @ %s' % (branch['branch'], branch['praxis']), [adr], branch.format(), None))
     825                  del branches
     826
     827                  candidate_type = _('External care')
     828                  cares = gmExternalCare.get_external_care_items(pk_identity = self.__patient.ID)
     829                  for care in cares:
     830                          details = '%s%s@%s (%s)' % (
     831                                  gmTools.coalesce(care['provider'], '', '%s: '),
     832                                  care['unit'],
     833                                  care['organization'],
     834                                  care['issue']
     835                          )
     836                          name = ('%s%s' % (
     837                                  gmTools.coalesce(care['provider'], '', '%s, '),
     838                                  '%s @ %s' % (care['unit'], care['organization'])
     839                          )).strip()
     840                          org_unit = care.org_unit
     841                          adr = org_unit.address
     842                          if adr is None:
     843                                  addresses = []
     844                          else:
     845                                  addresses = [adr]
     846                          list_items.append([candidate_type, details])
     847                          tt = '\n'.join(care.format(with_health_issue = True, with_address = True, with_comms = True))
     848                          list_data.append((name, addresses, tt, org_unit))
     849                  del cares
     850
     851                  emr = self.__patient.emr
     852
     853                  candidate_type = _('Hospital stay')
     854                  depts = emr.get_attended_hospitals_as_org_units()
     855                  for dept in depts:
     856                          adr = dept.address
     857                          if adr is None:
     858                                  continue
     859                          list_items.append([candidate_type, '%s @ %s' % (dept['unit'], dept['organization'])])
     860                          list_data.append(('%s @ %s' % (dept['unit'], dept['organization']), [adr], '\n'.join(dept.format(with_comms = True)), dept))
     861                  del depts
     862
     863                  candidate_type = _('Procedure')
     864                  proc_locs = emr.get_procedure_locations_as_org_units()
     865                  for proc_loc in proc_locs:
     866                          adr = proc_loc.address
     867                          if adr is None:
     868                                  continue
     869                          list_items.append([candidate_type, '%s @ %s' % (proc_loc['unit'], proc_loc['organization'])])
     870                          list_data.append(('%s @ %s' % (proc_loc['unit'], proc_loc['organization']), [adr], '\n'.join(proc_loc.format(with_comms = True)), proc_loc))
     871                  del proc_locs
     872
     873                  candidate_type = _('Lab')
     874                  labs = emr.get_labs_as_org_units()
     875                  for lab in labs:
     876                          adr = lab.address
     877                          if adr is None:
     878                                  continue
     879                          list_items.append([candidate_type, '%s @ %s' % (lab['unit'], lab['organization'])])
     880                          list_data.append(('%s @ %s' % (lab['unit'], lab['organization']), [adr], '\n'.join(lab.format(with_comms = True)), lab))
     881                  del labs
     882
     883                  candidate_type = _('Bill receiver')
     884                  bills = self.__patient.bills
     885                  adrs_seen = []
     886                  for bill in bills:
     887                          if bill['pk_receiver_address'] in adrs_seen:
     888                                  continue
     889                          adr = bill.address
     890                          if adr is None:
     891                                  continue
     892                          adrs_seen.append(bill['pk_receiver_address'])
     893                          details = '%s%s' % (bill['invoice_id'], gmDateTime.pydt_strftime(dt = bill['close_date'], format = ' (%Y %b %d)', none_str = ''))
     894                          list_items.append([candidate_type, details])
     895                          list_data.append(('', [adr], '\n'.join(adr.format()), None))
     896
     897                  candidate_type = _('Document')
     898                  doc_folder = self.__patient.document_folder
     899                  doc_units = doc_folder.all_document_org_units
     900                  for doc_unit in doc_units:
     901                          adr = doc_unit.address
     902                          if adr is None:
     903                                  continue
     904                          list_items.append([candidate_type, '%s @ %s' % (doc_unit['unit'], doc_unit['organization'])])
     905                          list_data.append(('%s @ %s' % (doc_unit['unit'], doc_unit['organization']), [adr], '\n'.join(doc_unit.format(with_comms = True)), doc_unit))
     906                  del doc_units
     907
     908                  self._LCTRL_candidates.set_string_items(list_items)
     909                  self._LCTRL_candidates.set_column_widths()
     910                  self._LCTRL_candidates.set_data(list_data)
     911
     912          #------------------------------------------------------------
     913 -        def _get_candidate_tooltip(self, data):
     914                  if data is None:
     915                          return ''
     916                  name, addresses, tt, unit = data
     917                  return tt
     918
     919          #------------------------------------------------------------
     920 -        def __update_address_info(self, adr):
     921                  if adr is None:
     922                          self._LBL_address_details.SetLabel('')
     923                          self._LBL_final_country.SetLabel('')
     924                          self._LBL_final_region.SetLabel('')
     925                          self._LBL_final_zip.SetLabel('')
     926                          self._LBL_final_location.SetLabel('')
     927                          self._LBL_final_street.SetLabel('')
     928                          self._LBL_final_number.SetLabel('')
     929                          self.Layout()
     930                          return
     931                  self._LBL_address_details.SetLabel('\n'.join(adr.format()))
     932                  self._LBL_final_country.SetLabel(adr['l10n_country'])
     933                  self._LBL_final_region.SetLabel(adr['l10n_region'])
     934                  self._LBL_final_zip.SetLabel(adr['postcode'])
     935                  self._LBL_final_location.SetLabel('%s%s' % (adr['urb'], gmTools.coalesce(adr['suburb'], '', ' - %s')))
     936                  self._LBL_final_street.SetLabel(adr['street'])
     937                  self._LBL_final_number.SetLabel('%s%s' % (adr['number'], gmTools.coalesce(adr['subunit'], '', ' %s')))
     938                  self.Layout()
     939
     940          #------------------------------------------------------------
     941 -        def __populate_address_list(self, addresses=None):
     942                  self._LCTRL_addresses.Enable()
     943                  cols = [_(u'Address')]
     944                  list_items = []
     945                  for a in addresses:
     946                          try:
     947                                  list_items.append([a['l10n_address_type'], a.format(single_line = True, verbose = False, show_type = False)])
     948                                  cols = [_('Type'), _('Address')]
     949                          except KeyError:
     950                                  list_items.append([a.format(single_line = True, verbose = False, show_type = False)])
     951                                  cols = [_('Address')]
     952
     953                  self._LCTRL_addresses.set_columns(cols)
     954                  self._LCTRL_addresses.set_string_items(list_items)
     955                  self._LCTRL_candidates.set_column_widths()
     956                  self._LCTRL_addresses.set_data(addresses)
     957                  self._PRW_other_address.SetText(value = '', data = None)
     958                  self.__update_address_info(None)
     959
     960          #------------------------------------------------------------
     961 -        def _get_address_tooltip(self, adr):
     962                  return '\n'.join(adr.format(show_type = True))
     963
     964          #------------------------------------------------------------
     965          #------------------------------------------------------------
     966 -        def _on_final_name_modified(self):
     967                  self._LBL_final_name.SetLabel(self._TCTRL_final_name.Value)
     968
     969          #------------------------------------------------------------
     970 -        def _on_address_selected_in_PRW(self, address):
     971                  self.__update_address_info(self._PRW_other_address.GetData(as_instance = True))
     972
     973          #------------------------------------------------------------
     974 -        def _on_entering_org_unit_PRW(self):
     975                  self._LCTRL_addresses.Disable()
     976
     977          #------------------------------------------------------------
     978 -        def _on_org_unit_selected_in_PRW(self, unit):
     979                  if unit is None:
     980                          self._LCTRL_addresses.remove_items_safely(max_tries = 3)
     981                          self._PRW_other_address.SetText(value = '', data = None)
     982                          self.__update_address_info(None)
     983                          self._TCTRL_org_unit_details.SetValue('')
     984                          return
     985
     986                  unit = self._PRW_org_unit.GetData(as_instance = True)
     987                  adr = unit.address
     988                  if adr is None:
     989                          self._LCTRL_addresses.remove_items_safely(max_tries = 3)
     990                          self._PRW_other_address.SetText(value = '', data = None)
     991                          self.__update_address_info(None)
     992                  else:
     993                          self.__populate_address_list(addresses = [adr])
     994                          self._PRW_other_address.SetData(data = adr['pk_address'])
     995                          self.__update_address_info(adr)
     996
     997                  name = '%s @ %s' % (unit['unit'], unit['organization'])
     998                  self._TCTRL_final_name.SetValue(name)
     999                  self._TCTRL_org_unit_details.SetValue('\n'.join(unit.format(with_comms = True)))
    1000                  self.Layout()
    1001
    1002          #------------------------------------------------------------
    1003          #------------------------------------------------------------
    1004 -        def _on_candidate_selected(self, event):
    1005                  event.Skip()
    1006                  name, addresses, tt, unit = self._LCTRL_candidates.get_selected_item_data(only_one = True)
    1007                  self.__populate_address_list(addresses = addresses)
    1008                  if unit is None:
    1009                          self._PRW_org_unit.SetText(value = '', data = None)
    1010                          self._TCTRL_org_unit_details.SetValue('')
    1011                  else:
    1012                          self._PRW_org_unit.SetData(data = unit['pk_org_unit'])
    1013                          self._TCTRL_org_unit_details.SetValue('\n'.join(unit.format(with_comms = True)))
    1014                  self._TCTRL_final_name.SetValue(name.strip())
    1015                  self._LBL_final_name.SetLabel(name.strip())
    1016
    1017          #------------------------------------------------------------
    1018 -        def _on_address_activated_in_list(self, evt):
    1019                  evt.Skip()
    1020                  adr = self._LCTRL_addresses.get_selected_item_data(only_one = True)
    1021                  self._PRW_other_address.address = adr
    1022                  self.__update_address_info(adr)
    1023
    1024          #------------------------------------------------------------
    1025          #------------------------------------------------------------
    1026 -        def _on_manage_addresses_button_pressed(self, event):
    1027                  event.Skip()
    1028                  manage_addresses(parent = self)
    1029
    1030          #------------------------------------------------------------
    1031 -        def _on_manage_orgs_button_pressed(self, event):
    1032                  event.Skip()
    1033                  from Gnumed.wxpython.gmOrganizationWidgets import manage_orgs
    1034                  manage_orgs(parent = self, no_parent = False)
    1035
    1036          #------------------------------------------------------------
    1037 -        def _on_ok_button_pressed(self, event):
    1038                  if self._TCTRL_final_name.GetValue().strip() == '':
    1039                          return False
    1040                  if self._PRW_other_address.address is None:
    1041                          return False
    1042                  event.Skip()
    1043                  self.EndModal(wx.ID_OK)
    1044
    1045          #------------------------------------------------------------
    1046 -        def _set_patient(self, patient):
    1047                  self.__patient = patient
    1048                  self.__init_ui()
    1049
    1050          patient = property(lambda x:x, _set_patient)
    1051
    1052          #------------------------------------------------------------
    1053 -        def _get_name(self):
    1054                  return self._TCTRL_final_name.GetValue().strip()
    1055
    1056          name = property(_get_name, lambda x:x)
    1057
    1058          #------------------------------------------------------------
    1059 -        def _get_address(self):
    1060                  return self._PRW_other_address.address
    1061
    1062          address = property(_get_address, lambda x:x)
    1063
    1064  #============================================================
    1065  # main
    1066  #------------------------------------------------------------
    1067  if __name__ == '__main__':
    1068
    1069          gmI18N.activate_locale()
    1070          gmI18N.install_domain(domain = 'gnumed')
    1071
    1072          #----------------------------------------
    1073 -        def test_cFormTemplateEAPnl():
    1074                  app = wx.PyWidgetTester(size = (400, 300))
    1075                  pnl = cFormTemplateEAPnl(app.frame, -1, template = gmForms.cFormTemplate(aPK_obj=4))
    1076                  app.frame.Show(True)
    1077                  app.MainLoop()
    1078                  return
    1079          #----------------------------------------
    1080          if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
    1081                  test_cFormTemplateEAPnl()
    1082
    1083  #============================================================
    1084