docs: def on_upload_file(self, event):
          """
          Write all data to appropriate er_* and pmag_* files.
          Then use those files to create a MagIC upload format file.
          Validate the upload file.
          """
          # coherence validations
          wait = wx.BusyInfo('Validating data, please wait...')
          wx.SafeYield()
          spec_warnings, samp_warnings, site_warnings, loc_warnings = self.er_magic.validate_data()
          result_warnings = self.er_magic.validate_results(self.er_magic.results)
          meas_warnings = self.er_magic.validate_measurements(self.er_magic.measurements)
          self.warn_dict = {'specimen': spec_warnings, 'sample': samp_warnings,
                            'site': site_warnings, 'location': loc_warnings,
                            'result': result_warnings, 'age': {}, 'measurement': meas_warnings}
          # done coherence validations
          del wait
          # write upload file and perform data validations
          wait = wx.BusyInfo('Making upload file, please wait...')
          wx.SafeYield()
          self.er_magic.write_files()
          upfile, error_message, errors = ipmag.upload_magic(dir_path=self.WD,
                                                             data_model=self.data_model)
          del wait
          if upfile:
              text = "You are ready to upload.\nYour file:\n{}\nwas generated in directory: \n{}\nDrag and drop this file in the MagIC database.".format(os.path.split(upfile)[1], self.WD)
              dlg = wx.MessageDialog(self, caption="Saved", message=text, style=wx.OK)
          else:
              text = "There were some problems with the creation of your upload file.\nError message: {}\nSee Terminal/Command Prompt for details".format(error_message)
              dlg = wx.MessageDialog(self, caption="Error", message=text, style=wx.OK)
          result = dlg.ShowModal()
          if result == wx.ID_OK:
              dlg.Destroy()
          self.edited = False
          ## add together data & coherence errors into one dictionary
          if errors:
              for item_type in errors:
                  for item_name in errors[item_type]:
                      if item_name in self.warn_dict[item_type]:
                          self.warn_dict[item_type][item_name].update(errors[item_type][item_name])
                      else:
                          self.warn_dict[item_type][item_name] = errors[item_type][item_name]
  
          has_problems = []
          for item_type, warnings in list(self.warn_dict.items()):
              if warnings:
                  has_problems.append(item_type)
          # for any dtypes with validation problems (data or coherence),
          # highlight the button to the corresponding grid
          # skip this step for Windows
          if sys.platform in ['win32', 'win62']:
              pass
          else:
              for dtype in self.warn_dict:
                  wind = self.FindWindowByName(dtype + '_btn')
                  if wind:
                      if dtype in has_problems:
                          wind.Bind(wx.EVT_PAINT, self.highlight_button)
                      else:
                          wind.Unbind(wx.EVT_PAINT, handler=self.highlight_button)
              self.Refresh()
          if has_problems:
              self.validation_mode = set(has_problems)
              if sys.platform in ['win32', 'win62']:
                  self.message.SetLabel('The following grid(s) have incorrect or incomplete data:\n{}'.format(', '.join(self.validation_mode)))
              else:
                  self.message.SetLabel('Highlighted grids have incorrect or incomplete data')
              self.bSizer_msg.ShowItems(True)
              self.hbox.Fit(self)
          if not has_problems:
              self.validation_mode = set()
              self.message.SetLabel('')
              self.bSizer_msg.ShowItems(False)
              self.hbox.Fit(self)