unit Sequenceu;{ ULObjUsr descendant for holding sequence related data }
{
  (C) 2000 - 2001 Jindrich Jindrich, Pavel Pisa, PiKRON Ltd.

  Originators of the CHROMuLAN project:

  Jindrich Jindrich - http://www.jindrich.com
                      http://orgchem.natur.cuni.cz/Chromulan/
                      software developer, project coordinator
  Pavel Pisa        - http://cmp.felk.cvut.cz/~pisa
                      embeded software developer
  PiKRON Ltd.       - http://www.pikron.com
                      project initiator, sponsor, instrument developer

  The CHROMuLAN project is distributed under the GNU General Public Licence.
  See file COPYING for details.

  Originators reserve the right to use and publish sources
  under different conditions too. If third party contributors
  do not accept this condition, they can delete this statement
  and only GNU license will apply.
}


interface
{$I define.pas}
uses
  SysUtils, Messages, Classes, Controls, Forms, ActnList, Menus,
  {$IFDEF DELPHI4} FileCtrl, {$ENDIF}
  XStringGrid,
  WinUtl, Timer, Timersu, Fileu, Compareu, ExeLogu,
  {$IFNDEF CONSOLE}
  Msgu, Language, XGridFrm,
  {$ENDIF}

  ULRecTyp, ULRecUtl, ULObju, ULFObju, ULObjUsru, ULObjDes,

  ULAType,
  ULADType, ULADObju, Modulu,
  ULIType, ULIObju, Instrumentu,
  ULMType, ULMObju, Methodu,
  AAPGType, AAPGObju, AAPLType, AAPLObju, AAPrgu,
  USPType, USPObju, Prgu, SeqPrgu,

  ULSQType, ULSQObju, ULSRType, ULSRObju, ULPRType, ULPRObju,

  UlanType, Spectrum, AcqInfou, ModuUtl, UlanGlob,
  {$IFNDEF CONSOLE}
  SpecForm, ULStringGrid, AnalSetupFrm, ULEdutl,
  {$ENDIF}
  FileDlg, CalibrationFrm, CompCalu
  ;

{urXXXX}
{urSeqXXXX}
const
  urOK = 0;
  urSeq = 9000;
  urSeqMethodExists = urSeq + 1;
  urSeqInstrumentExists = urSeq + 2;
  urSeqPrgExists = urSeq + 3;
  {v0.41}
  urSetSequenceStateInvalid = urSeq + 4;

  urInvalidProgramNoEquil = urSeq + 5;
  urNoSamples = urSeq + 6;
  {/v0.41}
  {v0.51}
  urInvalidProgramFormat = urSeq + 7;
  {/v0.51}
{/urSeqXXXX}
type
  TSequenceResult = integer;

type
  {v0.30}
  TScanReason = (srResultTable, srCalibrationFile, srOpen{v0.38}, srOpenOverlay{/v0.38}
    {v0.61},srComposeCalibration{/v0.61});
  {/v0.30}

  TSeqSample = class;

  {TSequence}
  TSequence = class(TULObjUsr) {ulobju ulobjusru}
  private
    FLastSample: TSeqSample;
    FCurSample: TSeqSample;

    FDefMethod: TUlanMethod;
      { default method for new sample }
    FDefInstrument: TInstrument;
      { default instrument for new sample }
    FDefPrg: {v0.49}TPrg{/v0.49 TAAPrg};
      { default program for new sample }
      { ulsqtype }
    {$IFNDEF CONSOLE}
    {v0.30}
    FMakeTable: TAction;
    FCalibrationFileAssign: TAction;
    FDataFilesOpen: TAction;
    {v0.38}
    FDataFilesOpenOverlay: TAction;
    {/v0.38}
    {v0.50}
    FProcessorActivate: TAction;
    {/v0.50}

    FCurGrid: TXStringGrid;
    {$ENDIF}

    FGridValueCaption: string;
    FCurScanULSR: TULSRObj;
    FCurScanAcqData: TAcqData;
    FCurCalibFN: string;
    {/v0.30}
    {$IFNDEF CONSOLE}
    {v0.38}{ulobju}
    {FDeleteFiles: boolean;}
      { delete files corresponding to deleting ulsr? }
    FCurSpecForm: TSpectrumForm;
    {/v0.38}
    {v0.44}
    FClearSampleErrorAction: TAction;
    {/v0.44}
    {$ENDIF}
    {v0.50}
    {FDefBaseLine: TBaseLine;}
    {/v0.50}
    {v0.51}
    FProcessor: TObject;
    {/v0.51}
    {v0.49}
    FDataTemplate: TAcqData;
    {/v0.49}
    {v0.61}
    FComposeCalibrationAction: TAction;

    { opened between ComposeCalibrationBegin/End calls, used in ComposeCalibrationAdd}
    FCompCal: TCompCal;
    {/v0.61}

    {/v0.49}
    function GetSequenceKind: TSequenceKind;
    {/v0.49}
    {v0.50}
    procedure SetSequenceKind(AKind: TSequenceKind);
    function GetDefPrgDir: string;
    function GetDefPrgExt: string;
    function GetDefMethodDir: string;
    function GetDefTemplateDir: string;
    function GetSequencesDir: string;
    {/v0.50}
    {v0.56}
    function GetRunning: boolean;
      { return true if processor activated for this sequence and is running }
    {/v0.56}
  protected
    class function GetClassRecID: TULRecID; override;
    function ChildCreate(AChildObj: TULObj): TULObjUsr; override;
    procedure ChildDestroyed(AChild: TULObjUsr); override;
    procedure ClassFieldsCreate; override;

    function GetULSQ: TULSQObj;
    function GetDefMethod: TUlanMethod;
    function GetDefInstrument: TInstrument;
    function GetDefPrg: {v0.49}TPrg{/v0.49 TAAPrg}; {v0.41}virtual;{/v0.41}
    function GetLastSample: TSeqSample;
    function GetCurSample: TSeqSample;
    function GetNextSample: TSeqSample;
    procedure SeqSampleCreated(ss: TSeqSample);
      { update new SeqSample default values }
    function GetDirName: string;{v0.41}virtual;{/v0.41}
    {v0.30}
    procedure MenuActionNeeded;override;
    procedure MakeResultTable(Sender: TObject);
    procedure CalibrationFileAssign(Sender: TObject);
    procedure DataFilesOpen(Sender: TObject);
    {v0.38}
    procedure DataFilesOpenOverlay(Sender: TObject);
    {/v0.38}
    {v0.50}
    procedure ProcessorActivate(Sender: TObject);
    {/v0.50}

    procedure ChildsScan(sr: TScanReason);
      procedure ResultTableAddRow;
      procedure CalibFNAssign;
      procedure DataFileOpen{v0.38}(Aditive:boolean){/v0.38};
    {/v0.30}
    {v0.32}
    procedure FileNameChanged;override;
    {/v0.32}
    {v0.36}{ulobjusru}
    {$IFNDEF CONSOLE}
    procedure ULGridCreated(AGrid: TULStringGrid); override;
    procedure DoOnDblClick(AGrid: TObject);
    {$ENDIF}

    procedure SetCurSample(ASample: TSeqSample);
    {/v0.36}
    {v0.44}
    procedure FirstMenuActionNeeded; override;
    procedure ClearSampleError(Sender: TObject);
    {/v0.44}
    {v0.49}
    function GetPrgRecID: TULRecID; virtual;
    function GetPrgExt: string;
    {procedure DoAfterLoad; override;}{ulobjusru}

    function GetDataTemplateFileName: TFileName;
    procedure SetDataTemplateFileName(const AFileName: TFileName);
    function GetDataTemplate: TAcqData;
    {/v0.49}
    {v0.50}
    procedure FieldDefDirNeeded(AField: TULObjField); override;
    procedure ObjDefDirNeeded;override;
    function GetChannelName: string;
    function GetFixedSequenceName: string;
    {/v0.50}
    {v0.61}
    procedure ComposeCalibration(Sender: TObject);
       procedure ComposeCalibrationBegin;
      { Check FCurScanAcqData file, eventually use it for the creating calibration }
      procedure ComposeCalibrationAdd;
      procedure ComposeCalibrationEnd;

    { Can be called only during ChildsScan, composes file name for CurChild }
    function CurScanChildFileName: string;

    { Invoking simple FileDialog, filters out file not having ULA.CalibrationStandard
      parameter set. }
    function CalibrationFileSelect(var AFileName: string): boolean;

    { OnAddFile handler - set Add to file if AFileName does not have
      ULA.CalibrationStandard set. }
    procedure DoOnAddCalFile(const AFileName: string; var Add: boolean);

    {/v0.61}
  public
    destructor Destroy;override;
    procedure UpdateDefDirs; override;
    function First: boolean;
      { select first sample as current }
    function Next: boolean;
      { select next sample as current }
    {v0.36}
    procedure NoSample;
    {/v0.36}
    {v0.65}
    { Adds to AList full file names of selected sequence samples }
    procedure FillFileList(AList: TStringList);
    {/v0.65}

    {v0.50}
    function GetNewSequenceName: string;
    procedure UpdateFileNameFromSequenceName;
    procedure CheckDir;

    {procedure Run;{called by usr to start the sequence}
    {procedure Stop;{called by usr to stop the sequence}
    {/v0.50}
    property ULSQ: TULSQObj read GetULSQ;
    property CurSample: TSeqSample read GetCurSample{v0.36} write SetCurSample{/v0.36};
    property LastSample: TSeqSample read GetLastSample;
    property NextSample: TSeqSample read GetNextSample;
    property DefMethod: TUlanMethod read GetDefMethod;
    property DefInstrument: TInstrument read GetDefInstrument;
    property DefPrg: {v0.49}TPrg{/v0.49 TAAPrg} read GetDefPrg;
    { Default (full) dir for files of samples = dir of .ULS file + SequenceName }
    property DirName: string read GetDirName;
    {v0.64}
    property DefTemplateDir: string read GetDefTemplateDir;
    {/v0.64}
    {v0.49}
    property SequenceKind: TSequenceKind read GetSequenceKind write SetSequenceKind;
    property PrgRecID: TULRecID read GetPrgRecID;
    property PrgExt: string read GetPrgExt;
    property DataTemplateFileName: TFileName read GetDataTemplateFileName write SetDataTemplateFileName;
    property DataTemplate: TAcqData read GetDataTemplate;
    {/v0.49}
    {v0.50}
    property ChannelName: string read GetChannelName;
    property FixedSequenceName: string read GetFixedSequenceName;
    {/v0.50}
    {v0.51}
    property Processor: TObject read FProcessor write FProcessor;
    {/v0.51}
    {v0.56}
    property Running: boolean read GetRunning;
    {/v0.56}
  end;
  {/TSequence}
  {v0.41}
  TSequenceClass = class of TSequence;
  {/v0.41}

{TSeqSample}
  TSeqSample = class(TULObjUsr)
  private
    FInstrument: TInstrument;
    FMethod: TUlanMethod;
    FPrg: {v0.49}TPrg{/v0.49 TAAPrg};
    {v0.64}
    FPrgSource: string;
    FMethodSource: string;
    {/v0.64}
    {v0.50} {ulobjusru}
    function GetSequence: TSequence;
    {/v0.50}
    {v0.62}
    function GetDataTemplateFileName: TFileName;
    {/v0.62}
    {v0.64}
    {function GetDefDataTemplateFile: TFileName;}
    {procedure SetMethod(AMethod: TUlanMethod);
    procedure SetPrg(APrg: TPrg);}
    function GetPrgFileName: TFileName;
    function GetMethodFileName: TFileName;
    {/v0.64}
  protected
    function GetULSR: TULSRObj;
    procedure ClassFieldsCreate; override;
    function ChildCreate(AChildObj: TULObj): TULObjUsr; override;
    procedure ChildDestroyed(AChild: TULObjUsr); override;
    class function GetClassRecID: TULRecID; override;
    {v0.50}
    procedure FieldDefDirNeeded(AField: TULObjField); override;
    {procedure AfterBrowseChildDelete; override;}
    {/v0.50}
  public
    constructor Create(AOwner: TULObjUsr; AObj: TULObj; ARecID: TULRecID); reintroduce;
    destructor Destroy;override;
    {v0.64}
    { Assign program just before running the sample. If APrgObj = nil, then FPrg
      will be loaded from the file AFileName and AFileName assigned to FPrgSource.
      If APrgObj <>  nil, then it is assigned to FPrg.Obj and the AFileName is
      assigned to FPrgSource property. AFileName must be non empty, either name
      of a program file or of a template file. }
    procedure PrgObjAssign(APrgObj: TULObj; const AFileName: string);
    { As PrgObjAssign but for method. }
    procedure MethodObjAssign(AMethodObj: TULObj; const AFileName: string);

    { Called after selecting the sample as the next one to be processed.
      Loads program and method from files or assigns them from template. }
    procedure PrgAndMethodLoad;
      procedure PrgLoad;
      procedure MethodLoad;
    {/v0.64}
    {ulobjusru}
    property ULSR: TULSRObj read GetULSR;
    property Method: TUlanMethod read FMethod {v0.64}{write SetMethod}{/v0.64};
    property Instrument: TInstrument read FInstrument;
    property Prg: {v0.49}TPrg{/v0.49 TAAPrg} read FPrg {v0.64} {write SetPrg}{/v0.64};
    {v0.50}
    property Sequence: TSequence read GetSequence;
    {/v0.50}
    {v0.62}
    { Returns value of DataTemplateFileName if assigned, otherwise value
      of the same name field of the Sequence (the template the sequence was
      derived from) }
    property DataTemplateFileName: TFileName read GetDataTemplateFileName;
    {/v0.62}
    {v0.64}
    { Used for finding out where the sample took the program from - either
      name of a program file or a template file. }
    property PrgSource: string read FPrgSource write FPrgSource;
    property MethodSource: string read FMethodSource write FMethodSource;
    { Get full path file name of the program file (if any) }
    property PrgFileName: TFileName read GetPrgFileName;
    { Get full path file name of the method file (if any) }
    property MethodFileName: TFileName read GetMethodFileName;
    {/v0.64}
  end;
{/TSeqSample}

{v0.32}
function SequenceBrowserOpen(const AFileName: shortstring; AMode: TOpenMode): boolean;
{/v0.32}

implementation
{v0.50}
uses AAAu{v0.50}, Processoru{/v0.50}{v0.60}, Main{/v0.60};
{/v0.50}
{v0.41}
{v0.49}{/v0.49
uses SeqFrm;}
{/v0.41}
{TSequence}
class function TSequence.GetClassRecID: TULRecID;
begin
  Result := ULSQID;
end;

procedure TSequence.UpdateDefDirs;
var
  c: TULObjUsr;
  i: integer;
begin
  {v0.49}
  if SequenceKind = skStandalone then begin
{    DefPrg.Obj.ObjDesc.DefDir := ulanglob.PrgsDir;}
  end;
  {/v0.49}

  Obj.FindField('PrgFileName').FldDesc.DefDir := DefPrg.Obj.ObjDesc.DefDir;{AO.PrgsDir;}
  Obj.FindField('MethodFileName').FldDesc.DefDir := DefMethod.Obj.ObjDesc.DefDir;{AO.MethodsDir;}
  {v0.41}
  Obj.FindField('DataTemplateFileName').FldDesc.DefDir :=
    {v0.64}DefTemplateDir{/v0.64 ulanglob.TemplateDir};
  {/v0.41}{ulsqtype}
  for i := 0 to ChildCount - 1 do begin
    c := Childs[i];
    if c is TSeqSample then with c as TSeqSample do begin
      ULSR.FindField('PrgFileName').FldDesc.DefDir := DefPrg.Obj.ObjDesc.DefDir;
      ULSR.FindField('MethodFileName').FldDesc.DefDir := DefMethod.Obj.ObjDesc.DefDir;
      break;
    end;
  end;
end;


{v0.50}
function TSequence.GetDefPrgDir: string;
begin
  if (SequenceKind = skAAA) then begin
    Result := AAA.AO.PrgsDir;{aaatype}
  end else begin
    Result := ulanglob.PrgDir;
  end;
end;

function TSequence.GetDefPrgExt: string;
begin
  if (SequenceKind = skAAA) then begin
    Result := AAPGExt;{aapgtype}
  end else begin
    Result := USPExt;{usptype}
  end;
end;

function TSequence.GetDefMethodDir: string;
begin
  if (SequenceKind = skAAA) then begin
    Result := AAA.AO.MethodsDir;{aaatype}
  end else begin
    Result := ulanglob.MethodDir;
  end;
end;


function TSequence.GetDefTemplateDir: string;
begin
  Result := ulanglob .TemplateDir;
end;

function TSequence.GetSequencesDir: string;
begin
  if (SequenceKind = skAAA) then begin
    Result := AAA.AO.SeqsDir;{aaatype}
  end else begin
    Result := ulanglob . SequenceDir;
  end;
end;

procedure TSequence.FieldDefDirNeeded(AField: TULObjField);
var
  fn: string;
  fd: TULObjFldDesc;
begin
  fd := AField.FldDesc;
  fn := fd.Name;
  if fn = 'PrgFileName' then begin
    fd.DefDir := GetDefPrgDir;
    fd.DefExt := GetDefPrgExt;
  end else if fn = 'MethodFileName' then begin
    fd.DefDir := GetDefMethodDir;
  end else if fn = 'DataTemplateFileName' then begin
    fd.DefDir := {v0.64}DefTemplateDir{/v0.64 GetDefTemplateDir};
  end;
end;

procedure TSequence.ObjDefDirNeeded;
begin
  Obj.ObjDesc.DefDir := GetSequencesDir;{ulanglob}
end;
{/v0.50}

procedure TSequence.ClassFieldsCreate;
begin
  inherited;
  {v0.25}
  {v0.36}
  CurSample := nil;
  {/v0.36 FCurSample := nil;}
  FLastSample := nil;
  {/v0.25
  FLastSampleIndex := -1;
  FCurSampleIndex := -1;}
  {FDefMethod := TUlanMethod}
  (ChildFindOrAdd(ULMID, ''));
  {FDefInstrument := TInstrument}
  (ChildFindOrAdd(ULIID, ''));
  {FDefPrg := TAAPrg}
  (ChildFindOrAdd({v0.49}GetPrgRecID{/v0.49 AAPGID}, ''));
  UpdateDefDirs;
end;

function TSequence.GetDefMethod: TUlanMethod;
begin
  if FDefMethod = nil then
    FDefMethod := TUlanMethod(ChildFindOrAdd(ULMID, ''));
  Result := FDefMethod;
end;

function TSequence.GetDefInstrument: TInstrument;
begin
  if FDefInstrument = nil then
    FDefInstrument := TInstrument(ChildFindOrAdd(ULIID, ''));
  Result := FDefInstrument;
end;

function TSequence.GetDefPrg: {v0.49}TPrg{/v0.49 TAAPrg};
begin
  if FDefPrg = nil then begin
    {v0.49}
    FDefPrg := TPrg(ChildFindOrAdd(GetPrgRecID, ''));
    {/v0.49
    FDefPrg := TAAPrg(ChildFindOrAdd(AAPGID, ''));}
    {v0.41}
    FDefPrg.Obj.SetFlag(rfAskForSave, true);
    {/v0.41}
  end;
  Result := FDefPrg;
end;

procedure TSequence.ChildDestroyed(AChild: TULObjUsr);
begin
  if AChild = FDefMethod then
    FDefMethod := nil
  else if AChild = FDefInstrument then
    FDefInstrument := nil
  else if AChild = FDefPrg then
    FDefPrg := nil;
  {v0.25}
  if AChild = FCurSample then begin
    {v0.36}
    CurSample := nil;
    {/v0.36 FCurSample := nil;}
  end else if AChild = FLastSample then
    FLastSample := nil;
  {/v0.25}
  {v0.50}
{  if AChild = FDefBaseLine then
    FDefBaseLine := nil;}
  {/v0.50}
end;

procedure TSequence.SeqSampleCreated(ss: TSeqSample);
var
  sn, vn: integer;
  i: integer;
{  fn: string;}
{  seqn: string;}
  ou: TULObjUsr;
begin
  if ss.ULSR.PrgFileName = '' then begin
    ss.ULSR.PrgFileName := ULSQ.PrgFileName;
    ss.Prg.Obj.Assign(DefPrg.Obj);
  end;

  if ss.ULSR.MethodFileName = '' then begin
    ss.ULSR.MethodFileName := ULSQ.MethodFileName;
    ss.Method.Obj.Assign(DefMethod.Obj);
  end;

  if ss.ULSR.SampleState = sasWaiting then
    ss.Instrument.Obj.Assign(DefInstrument.Obj);{methodu instrumentu}

  if ss.ULSR.VialNr = 0 then begin
    sn := 0;
    vn := 0;
    for i := 0 to ChildCount - 1  do begin
      ou := Childs[i];
      if ou is TSeqSample then with ou as TSeqSample do begin
        if ou <> ss then begin
          {v0.60}
          if ULSR.SampleNr > sn then
            sn := ULSR.SampleNr;
          if ULSR.VialNr > vn then
            vn := ULSR.VialNr;
          {/v0.60
          sn := ULSR.SampleNr;
          vn := ULSR.VialNr;}
        end;
      end;
    end;
    inc(sn);
    inc(vn);

    ss.ULSR.FileName := 'Sample' + {v0.38} LZero(IntToStr(sn), 3){/v0.38 IntToStr(sn)};
    {v0.52}
    if ss.ULSR.SampleName = '' then
      ss.ULSR.SampleName := ss.ULSR.FileName;
    {/v0.52}
    ss.ULSR.VialNr := vn;
    ss.ULSR.SampleNr := sn;
  end;

  ss.ULSR.FindField('MethodFileName').FldDesc.DefDir := DefMethod.Obj.ObjDesc.DefDir;
  ss.ULSR.FindField('PrgFileName').FldDesc.DefDir := DefPrg.Obj.ObjDesc.DefDir;
end;{ulsrobju}


function TSequence.GetDirName: string;
{v0.50}
begin
{/v0.50
var
  n: string;
  i: integer;
begin
  n := ULSQ.SequenceName;
  for i := 1 to length(n) do begin
    if n[i] in [':',',','/','\','?'] then
      n[i] := '_';
  end; }
  Result := AddBackSlash(ULSQ.RootFileDir) + {v0.50}FixedSequenceName{/v0.50 n} + '\';
end;

{v0.50}
function TSequence.GetFixedSequenceName: string;
var
  i: integer;
begin
  Result := ULSQ.SequenceName;
  for i := 1 to length(Result) do begin
    if Result[i] in [':',',','/','\','?'] then
      Result[i] := '_';
  end;
end;

procedure TSequence.UpdateFileNameFromSequenceName;
begin
  FileName := AbsoluteFileName(Obj.ObjDesc.DefDir, FixedSequenceName, ULSExt);
{  FileName := ReplaceExt(DelBackSlash(DirName), ULSExt);}
end;

{v0.49}
{function TSequence.PrgCreate: TPrg;
begin

end;}
{/v0.49}

function TSequence.ChildCreate(AChildObj: TULObj): TULObjUsr;
var
  id:TULRecID;
  ss: TSeqSample;
begin
  Result := nil;
  if AChildObj = nil then begin
    id := ULSRID
  end else begin
    id := AChildObj.RecID;
  end;

  case id of
    ULSRID: begin
      ss := TSeqSample.Create(Self, AChildObj, id);
      Result := ss;
      SeqSampleCreated(ss);
    end;
    ULMID: begin
      Result := TUlanMethod.Create(Self, AChildObj, id);
      if (FDefMethod = nil) then begin
        {SetResult(urSeqMethodExists, '');}
        FDefMethod := TUlanMethod(Result);
      end;
    end;
    ULIID: begin
      Result := TInstrument.Create(Self, AChildObj, id);
      if FDefInstrument = nil then begin
        {SetResult(urSeqInstrumentExists, '');}
        FDefInstrument := TInstrument(Result);
      end;
    end;
    AAPGID: begin
      Result := TAAPrg.Create(Self, AChildObj, id);
      if FDefPrg = nil then begin
        {SetResult(urSeqPrgExists, '');}
        FDefPrg := {v0.49}TPrg{/v0.49 TAAPrg}(Result);
      end;
    end;
    {v0.49}
    USPID: begin
      Result := TSeqPrg.Create(Self, AChildObj, id);
      if FDefPrg =  nil then begin
        FDefPrg := TPrg(Result);
      end;
    end;
    {/v0.49}
    {v0.50}
    {ULBID: begin
      Result := TBaseLine.Create(Self, AChildObj, id);
      if FDefBaseLine = nil then begin
        FDefBaseLine := TBaseLine(Result);
      end;
    end;}
    {/v0.50}
  else
    SetResult(urUnknownChildRecID, ULRecIDToStrStrip(id));{ulrecutl}
  end;
end;

function TSequence.GetULSQ;
begin
  Result := TULSQObj(Obj);
end;

destructor TSequence.Destroy;
begin
  {v0.49}
  FDataTemplate.Free;
  {/v0.49}
  {v0.51}
  if FProcessor <> nil then begin
    TProcessor(FProcessor).Sequence := nil;
    FProcessor := nil;
  end;
  {/v0.51}
  inherited Destroy;
end;

function TSequence.GetCurSample: TSeqSample;
{var c: TULObjUsr;}
begin
  {v0.25}
  Result := FCurSample;
  {/v0.25
  Result := nil;
  if (FCurSampleIndex >= 0) and (FCurSampleIndex < ChildCount) then begin
    c := Childs[FCurSampleIndex];
    if c is TSeqSample then
      Result := TSeqSample(c);
  end;}
end;

function TSequence.GetLastSample: TSeqSample;
{v0.25}{/v0.25 var c: TULObjUsr;}
begin
  {v0.25}
  Result := FLastSample;
  {/v0.25
  Result := nil;
  if (FLastSampleIndex >= 0) and (FLastSampleIndex < ChildCount) then begin
    c := Childs[FLastSampleIndex];
    if c is TSeqSample then
      Result := TSeqSample(c);
  end;}
end;

function TSequence.GetNextSample: TSeqSample;
var
  i: integer;
  s: TSeqSample;
begin
  Result := nil;
  {v0.25}
  i := ChildList.IndexOf(FCurSample) + 1;
  {/v0.25
  i := FCurSampleIndex + 1;}
  if i < 0 then
    exit;
  while i < ChildCount do begin
    if Childs[i] is TSeqSample then begin
      s := TSeqSample(Childs[i]);{ulsrtype}
      if (s.ULSR.SampleState = sasWaiting) or (s.ULSR.SampleState = sasInLoop) then begin
        Result := s;
        exit;
      end;
    end;
    inc(i);
  end;
end;

function TSequence.First: boolean;
  { select first sample as current }
begin
  {v0.25}
  {v0.36}
  CurSample := nil;
  {/v0.36 FCurSample := nil;}
  FLastSample := nil;
  {/v0.25
  FCurSampleIndex := -1;
  FLastSampleIndex := -1;}
  Result := Next;
end;

function TSequence.Next: boolean;
      { select next sample as current }
var s: TSeqSample;
begin
  s := NextSample;
  {v0.25}
  {v0.36}{/v0.36
  if FCurSample <> nil then begin
    FCurSample.Obj.SetFlag(rfCantDelete, false);
  end;}
  FLastSample := FCurSample;
  {/v0.25
  FLastSampleIndex := FCurSampleIndex;}
  if s <> nil then begin
    {v0.25}
    FCurSample := s;
    {v0.36}{/v0.36
    FCurSample.Obj.SetFlag(rfCantDelete, true);}
    {/v0.25
    FCurSampleIndex := ChildList.IndexOf(s);}
    Result := true;
  end else begin
    Result := false;
    {v0.36}
    CurSample := nil;
    {/v0.36}
  end;
end;

{v0.30}
procedure TSequence.MenuActionNeeded;
var
  s: string;
  o: TULObj;
begin
  s := GetTxt({#}'all');
  if Obj.ChildWithFlagCount(rfSelected) > 0 then begin
    s := GetTxt({#}'selected')
  end else begin
    if not Obj.FindObj(ULSRID, foChilds, '', o) then
      exit;
  end;

  if FMakeTable = nil then begin
    FMakeTable := TAction.Create(Self);
    FMakeTable.OnExecute := MakeResultTable;
  end;
  FMakeTable.Caption := GetTxt({#}'Show results for') + ' ' + s;
  Obj.MenuActionAdd(FMakeTable);

  if FCalibrationFileAssign = nil then begin
    FCalibrationFileAssign := TAction.Create(Self);
    FCalibrationFileAssign.OnExecute := CalibrationFileAssign;
  end;
  FCalibrationFileAssign.Caption := GetTxt({#}'Assign calib.file to') + ' ' + s;
  Obj.MenuActionAdd(FCalibrationFileAssign);

  if FDataFilesOpen = nil then begin
    FDataFilesOpen := TAction.Create(Self);
    FDataFilesOpen.OnExecute := DataFilesOpen;
  end;
  FDataFilesOpen.Caption := GetTxt({#}'Open window for') + ' ' + s;
  Obj.MenuActionAdd(FDataFilesOpen);

  {v0.38}
  if FDataFilesOpenOverlay = nil then begin
    FDataFilesOpenOverlay := TAction.Create(Self);
    FDataFilesOpenOverlay.OnExecute := DataFilesOpenOverlay;
  end;
  FDataFilesOpenOverlay.Caption := GetTxt({#}'Open') + ' ' + s + ' ' +
    GetTxt('in one window');
  Obj.MenuActionAdd(FDataFilesOpenOverlay);
  {/v0.38}

  {v0.61}
  ActionUpdate(FComposeCalibrationAction, ComposeCalibration, GetTxt({#}'Compose Calibration'));
  {/v0.61}
end;

procedure TSequence.DataFileOpen{v0.38}(Aditive:boolean);{/v0.38}
begin
  if FileExists(FCurScanAcqData.ULF.FileName) then begin
    {v0.38}
    if Aditive then begin
      if FCurSpecForm = nil then
        FCurSpecForm := CreateSpectrumForm(FCurScanAcqData.ULF.FileName, omRead)
      else
        FCurSpecForm.AddDataFile(FCurScanAcqData.ULF.FileName);
    end else
    {/v0.38}
    begin
      {v0.38} FCurSpecForm := {/v0.38} CreateSpectrumForm(FCurScanAcqData.ULF.FileName, omRead);
    end;
  end;
  {specform}
end;

procedure TSequence.CalibFNAssign;
var ad: TAcqData;
begin
  ad := FCurScanAcqData;
  ad.CalibrationFileSelect(FCurCalibFN);{spectrum}
end;

procedure TSequence.ResultTableAddRow;
var
  r, c, pc, pi: integer;
{  pn: string;}

  ppn: string;
  pv: string;

  p: TULPRObj;

  ad: TAcqData;
  ulsr: TULSRObj;
  xg: TXStringGrid;
  sp: TSpectrum;

  procedure ColFind(const n: string; var col: integer);
  var
    i: integer;
    s: string;
  begin
    for i := 1 to xg.ColCount - 1 do begin
      s := xg.Cells[i, 0];
      if s = '' then begin
        xg.Cells[i, 0] := n;
        col := i;
        exit;
      end else if s = n then begin
        col := i;
        exit;
      end;
    end;
    xg.ColCount := xg.ColCount + 1;
    col := xg.ColCount - 1;
    xg.Cells[col, 0] := n;
  end;

  procedure RowFind(var row: integer);
  var i: integer;
  begin
    row := -1;
    for i := 0 to xg.RowCount - 1 do begin
      if i > 0 then begin
        if xg.Cells[0, i] = '' then begin
          row := i;
          break;
        end;
      end;
    end;
    if row = -1 then begin
      xg.RowCount := xg.RowCount + 1;
      row := xg.RowCount - 1;
    end;
    xg.Cells[0, row] := ChangeFileExt(ulsr.FileName,'');
  end;

begin
  ad := FCurScanAcqData;
  ulsr := FCurScanULSR;
  xg := FCurGrid;

 {ResultTableValueName[ord(ULSQ.ResultTableValue)]}

  if ad.ULA.AutodetectLater then begin
    try
      sp := TSpectrum.Create(ad);
      try
        try
          sp.AutoDetect;
        except
        end;
      finally
        sp.Free;
      end;
    except;
    end;
  end;

  RowFind(r);
  pc := ad.ULP.ChildCount;
  if pc > (xg.ColCount - 1) then
    xg.ColCount := pc + 1;

  ppn := ResultTableValueName[ULSQ.ResultTableValue];
  for pi := 0 to pc - 1 do begin
    p := TULPRObj(ad.ULP.Childs[pi]);
    if p.RecID = ULPRID then begin
      ColFind(p.PeakName, c);            {ulsqobju uledfrm aapltype}
      if FGridValueCaption = '' then begin
        FGridValueCaption := p.FindField(ppn).FldDesc.Caption;
      end;
      pv := p.FindField(ppn).AsUsrString;
      xg.Cells[c, r] := pv;{FloatToStrF(pv, ffGeneral, 7, 4);}
    end;
  end;
end;

{v0.61}
function TSequence.CurScanChildFileName: string;
begin
  Result := ReplaceExt(DirName + FCurScanULSR.FileName, ULFExt, false);
end;
{/v0.61}

procedure TSequence.ChildsScan(sr: TScanReason);
var
  i: integer;
  fl: TULRecFlags;
  o: TULObj;
  ad: TAcqData;
  releaseData: boolean;
  fn: string;
  frm: TForm;
begin
  i := -1;
  {v0.38}
  FCurSpecForm := nil;
  {/v0.38}
  if Obj.ChildWithFlagCount(rfSelected) > 0 then
    fl := rfSelected
  else
    fl := 0;
  while Obj.ChildWithFlagNext(fl, i) do begin
    o := Obj.Childs[i];
    if o.RecID = ULSRID then begin
      FCurScanULSR := TULSRObj(o);
      try
        releaseData:= true;
        {v0.61}
        fn := CurScanChildFileName;
        {/v0.61
        fn := ChangeFileExt(DirName + FCurScanULSR.FileName, ULFExt);}
        {v0.31}
        case sr of
          srResultTable, srOpen {v0.38},srOpenOverlay{/v0.38}
          {v0.61}, srComposeCalibration{/v0.61}:
          begin
            if not FileExists(fn) then
              continue;
          end;
        end;
        {/v0.31}

        {v0.33}
        case sr of
          srOpen{v0.38}, srOpenOverlay{/v0.38}:
          begin
            ad := TAcqData.Create(fn, omRead);
          end;
          {v0.61}
          srComposeCalibration: begin
            ad := TAcqData.Create(fn, omReadOnly);
          end;
          {/v0.61}
        else
          if not FindOpenedData(fn, ad {v0.36}, frm{/v0.36}) then begin
            ad := TAcqData.Create(fn, omRead);
          end else begin
            releaseData := false;
          end;
        end;
        {/v0.33
        ad := TAcqData.Create(fn, omRead);}
        try
          FCurScanAcqData := ad;
          case sr of
            srResultTable: ResultTableAddRow;
            srCalibrationFile: CalibFNAssign;
            srOpen: DataFileOpen{v0.38}(false){/v0.38};
            {v0.38}
            srOpenOverlay: DataFileOpen(true);
            {/v0.38}
            {v0.61}
            srComposeCalibration: ComposeCalibrationAdd;
            {/v0.61}
          end;
        except
          { ignore adddata failure }
        end;
        FCurScanAcqData := nil;
        if releaseData then begin
          ad.Free;
        end;
      except
        { ignore one datafile read failure }
        {if releaseData then begin
          ad.Free;
          ad := nil;
        end;}
      end;
    end;
  end;
end;

procedure TSequence.DataFilesOpen(Sender: TObject);
begin
  ChildsScan(srOpen);
end;

{v0.38}
procedure TSequence.DataFilesOpenOverlay(Sender: TObject);
begin
  ChildsScan(srOpenOverlay);
end;
{/v0.38}

{v0.61}
procedure TSequence.DoOnAddCalFile(const AFileName: string; var Add: boolean);
var d: TAcqData;
begin
  d := TAcqData.Create(AFileName, omRead);
  try
    Add := d.ULA.CalibrationStandard;
  finally
    d.Free;
  end;
end;

function TSequence.CalibrationFileSelect(var AFileName: string): boolean;
var
  fd: TFileDialog;
begin
  Result := false;
  fd := TFileDialog.Create(Application);
  try
    {v0.62}
    {/v0.62}
    fd.FileListView.OnAddFile := DoOnAddCalFile;
    {v0.62}
    fd.Mask := CalibrationFilesMask;
    {/v0.62
    fd.Mask := '*' + UlfExt + ';*' + UlcExt;}

    {ulrectyp, ulantype}
    fd.InitialDir := DirName;
    if fd.ShowModal = mrOK then begin
      AFileName := fd.FileName;
      Result := true;
    end;
  finally
    fd.Free;
  end;
end;
{/v0.61}

procedure TSequence.CalibrationFileAssign(Sender: TObject);
var fn: string;
begin
  {ulobju}
  fn := '';
  {v0.61}
  {filedlg}if CalibrationFileSelect(fn)
  {/v0.61
  if FileNameOpenSelect(fn, GetTxt('Select calibration file'),
    CalibrationFileFilter, DirName)}
  then
  begin
    FCurCalibFN := fn;
    try
      ChildsScan(srCalibrationFile);
    finally
      FCurCalibFN := '';
    end;
    {specform}
  end;
end;

procedure TSequence.MakeResultTable(Sender: TObject);
var
  f: TXGridForm;
{  i: integer;}
  ok: boolean;
begin
  ok := false;
  FGridValueCaption := '';
  f := TXGridForm.Create(Application);
  try
    f.Caption := ChangeFileExt(FileName, '') + ' ' + GetTxt({#}'Results Table');
    FCurGrid := f.Grid;
    try
      ChildsScan(srResultTable);
    finally
      FCurGrid := nil;
    end;
    ok := true;
    if f.Grid.RowCount > 1 then begin
      f.Grid.FixedRows := 1;
    end else begin
      ok := false;
    end;
    if f.Grid.ColCount > 1 then begin
      f.Grid.FixedCols := 1;
    end else begin
      ok := false;
    end;
    f.Grid.RemoveEmptyColsRows;
  finally
    if ok then begin
      f.Grid.Cells[0,0] := FGridValueCaption;
      f.Show
    end else begin
      f.Free;
      (*ShowMessage(GetTxt({#}'No data found'), smError, 0);*)
    end;
  end
end;
{/v0.30}

{v0.32}
procedure TSequence.FileNameChanged;
begin
  if ULSQ <> nil then
    ULSQ.SequenceName := ChangeFileExt(ExtractFileName(FileName), '');
end;
{/v0.32}

{v0.36}{ulobjusru}
procedure TSequence.ULGridCreated(AGrid: TULStringGrid);
begin
  inherited;
  AGrid.OnDblClick := DoOnDblClick;//agrid.controlstyle csCaptureMouse csClickEvents
end;

procedure TSequence.DoOnDblClick(AGrid: TObject);
var
  o: TULObj;
  fn: string;
  d: TAcqData;
  f: TForm;
begin
  if not (AGrid is TULStringGrid) then
    exit;
  {ulstringgrid}
  o := TULStringGrid(AGrid).CurChild;
  if o is TULSRObj then with o as TULSRObj do begin
    fn := AbsoluteFileName(DirName, FileName, ULFExt);
    if FindOpenedData(fn, d, f) then begin
      f.BringToFront;
    end else begin
      if FileExists(fn) then
        CreateSpectrumForm(fn, omRead);
    end;
  end;
end;

procedure TSequence.NoSample;
begin
  CurSample := nil;
  FLastSample := nil;
end;

procedure TSequence.SetCurSample(ASample: TSeqSample);
begin
  if FCurSample = ASample then
    exit;
  if FCurSample <> nil then begin
    FCurSample.Obj.SetFlag(rfWriteLocked, false);
    FCurSample.Obj.SetFlag(rfCantDelete, false);
  end;
  FCurSample := ASample;
  if FCurSample <> nil then begin
    FCurSample.Obj.SetFlag(rfWriteLocked, true);{disable for usr}
    FCurSample.Obj.SetFlag(rfCantDelete, true);
  end;
end;
{/v0.36}

{v0.44}
procedure TSequence.FirstMenuActionNeeded;

  {procedure ActionUpdate(var AAction: TAction; ANotifyEvent: TNotifyEvent; const ACaption: string);
  begin
    if AAction = nil then begin
      AAction := TAction.Create(Self);
      AAction.OnExecute := ANotifyEvent;
    end;
    AAction.Caption := ACaption;
    Obj.MenuActionAdd(AAction);
  end;}

  procedure AddClearError;
  {var sr: TULSRObj;}
  begin
    {sr := TULSRObj(Obj.ActiveChild);}
    ActionUpdate(FClearSampleErrorAction, ClearSampleError, GetTxt({#}'Clear Sample Error'));
  end;

begin
{ulstringgrid  s := GetTxt('all');
  if Obj.ChildWithFlagCount(rfSelected) > 0 then begin
    s := GetTxt('selected')
  end else begin
    if not Obj.FindObj(ULSRID, foChilds, '', o) then
      exit;
  end; }
  if SequenceKind = skStandalone then
    ActionUpdate(FProcessorActivate, ProcessorActivate, GetTxt({#}'Activate processing'));
  AddClearError;
end;

{v0.56}
function TSequence.GetRunning: boolean;
begin
  Result := (FProcessor <> nil) and TProcessor(FProcessor).Running;
end;
{/v0.56}

procedure TSequence.ClearSampleError(Sender: TObject);
begin
  if Obj.ActiveChild is TULSRObj then with Obj.ActiveChild as TULSRObj do begin
    if (SampleState = sasError)
    {v0.56}
      or ((SampleState = sasInLoop) and (not Running))
    {/v0.56}
    then
      SampleState := sasWaiting;
  end;
    {ulsrtype}
end;
{/v0.44}

{v0.49}
function TSequence.GetPrgRecID: TULRecID;
begin
  case SequenceKind of
     skAAA: Result := AAPGID;
  else
    Result := USPID;
  end;
end;

function TSequence.GetPrgExt: string;
begin
  Result := ULRecDefFileExt(GetPrgRecID);
  {ulrecutl}
end;

{v0.49}
procedure TSequence.SetSequenceKind(AKind: TSequenceKind);
var
  ss: TSeqSample;
  i: integer;
begin
  {v0.50}
  if ULSQ.SequenceKind = AKind then
    exit;
  ULSQ.SequenceKind := AKind;

  DefPrg.Obj.Free;
  ClassFieldsCreate;

  for i := 0 to ChildCount - 1 do begin
    if Childs[i] is TSeqSample then begin
       ss := TSeqSample(Childs[i]);
       ss.FPrg.Obj.Free;
       ss.ClassFieldsCreate;{ulobjusru}
    end;
  end;
  {/v0.50
  ULSQ.SequenceKind := AKind;}
end;

function TSequence.GetSequenceKind: TSequenceKind;
begin
  Result := ULSQ.SequenceKind;
end;
{/v0.49}


{v0.50}
function TSequence.GetNewSequenceName: string;
var
  d: string;
  n: string;
  i: integer;
begin
  Obj.DefDirNeeded;
  n := FormatDateTime('yymmdd', Now);
  i := 1;
  repeat {ulsqtype}
    d := n + '-' + IntToStr(i);
    if not DirectoryExists(AddBackSlash(Obj.ObjDesc.DefDir) + d) then begin
      break;
    end;
    inc(i);
  until false;
  Result := d;
end;

function TSequence.GetChannelName: string;
begin
  Result := DataTemplate.ULI.ChannelName;{spectrum}
end;

procedure TSequence.ProcessorActivate(Sender: TObject);
var p: TProcessor;
begin
  p := Processors.ProcessorGet(ChannelName);
  p.Sequence := Self;
  if Processor = p then
    p.FormShow;
end;
{/v0.50}

{v0.65}
procedure TSequence.FillFileList(AList: TStringList);
var
  i: integer;
//  sl: TStringList;
  o: TULObj;
  ulsr: TULSRObj absolute o;
  fn: string;
begin
  for i := 0 to ULSQ.ChildCount - 1 do begin
    o := ULSQ.Childs[i];
    if (o is TULSRObj) and o.IsSelected then begin
      fn := AbsoluteFileName(DirName, ulsr.FileName, ULFExt);
      if FileExists(fn) then
        AList.Add(fn);
    end;
  end;
end;
{/v0.65}

{v0.61}
procedure TSequence.ComposeCalibration(Sender: TObject);
var
  cct: TCalibType;
  fn: string;
  {v0.65}
  sl: TStringList;
  {/v0.65}
begin
  cct := ctAverage;
  fn := '';
  {v0.65}
  sl := TStringList.Create;
  try
    FillFileList(sl);
  {/v0.65}
    if ComposeCalibrationFormExecute({v0.64} DirName, {/v0.64}{v0.65} sl, {/v0.65} fn, cct) then
    {v0.67 not modal anymore}
    ;
    {/v0.67}


    begin
       {v0.65}{/v0.65
       FCurCalibFn := DirName + ChangeFileExt(ExtractFileName(fn), ULCExt);
       ComposeCalibrationBegin;
       try
         ChildsScan(srComposeCalibration);
       finally
         ComposeCalibrationEnd;
       end;
       }
    end;
  {v0.65}
  finally
    sl.Free;
  end;
  {/v0.65}
end;

procedure TSequence.ComposeCalibrationBegin;
begin
  FCompCal := TCompCal.Create(ChangeFileExt(FCurCalibFN, UlcExt));
end;

procedure TSequence.ComposeCalibrationAdd;
{var
  i: integer;
  o: TULObj;
  p, fp: TULPRObj;}
begin
  if (FCompCal = nil) then
    exit;
  FCompCal.DataCalc(FCurScanAcqData);
end;

procedure TSequence.ComposeCalibrationEnd;
var fn: string;
begin
  fn := '';
  if FCompCal <> nil then
    fn := FCompCal.FileName;
  FCompCal.Free;
  if fn <> '' then
    CreateSpectrumForm(fn, omRead);
end;
{/TSequence.}


{TSeqSample}
constructor TSeqSample.Create(AOwner: TULObjUsr; AObj: TULObj; ARecID: TULRecID);
begin
  inherited Create(AOwner, AObj, ARecID);
end;

procedure TSeqSample.ClassFieldsCreate;
{v0.49}
var fd: TULObjFldDesc;
{/v0.49}
begin
  inherited; {ulfobju}
  ChildFindOrAdd(ULMID, '');
  ChildFindOrAdd(ULIID, '');{ulobjusru}
  {v0.49}
  ChildFindOrAdd(Sequence.GetPrgRecID, '');
  fd := Obj.FindField('PrgFileName').FldDesc;{ulsrtype}
  if TSequence(ULObjOwner).GetPrgRecID = USPID then begin
    fd.Filter := USPFilter;
    fd.DefDir := ulanglob.PrgDir;
  end;
  {/v0.49
  ChildFindOrAdd(AAPGID, '');}
end;

class function TSeqSample.GetClassRecID: TULRecID;
begin
  Result := ULSRID;
end;

function TSeqSample.ChildCreate(AChildObj: TULObj): TULObjUsr;
var
  id:TULRecID;
begin
  Result := nil;
  id := 0;
  if AChildObj = nil then begin
    SetResult(urUnknownChildRecID, '');
  end else begin
    id := AChildObj.RecID;
  end;

  case id of
    ULMID: begin
      Result := TUlanMethod.Create(Self, AChildObj, id);
      if (FMethod = nil) then begin
        FMethod := TUlanMethod(Result);
      end;
      Result := FMethod;
    end;
    ULIID: begin
      Result := TInstrument.Create(Self, AChildObj, id);
      if FInstrument = nil then begin
        FInstrument := TInstrument(Result);
      end;
    end;
    AAPGID: begin
      Result := TAAPrg.Create(Self, AChildObj, id);{aaprgu}
      if FPrg = nil then begin
        FPrg := {v0.49}TPrg{/v0.49 TAAPrg}(Result);
      end;
    end;
    {v0.49}
    USPID: begin
      Result := TSeqPrg.Create(Self, AChildObj, id);
      if FPrg = nil then begin
        FPrg := TPrg(Result);
      end;
    end;
    {/v0.49}
  else
    SetResult(urUnknownChildRecID, ULRecIDToStrStrip(id));{ulrecutl}
  end;
end;

procedure TSeqSample.ChildDestroyed(AChild: TULObjUsr);
begin
  if AChild = FMethod then
    FMethod := nil
  else if AChild = FInstrument then
    FInstrument := nil
  else if AChild = FPrg then
    FPrg := nil;
end;

function TSeqSample.GetULSR: TULSRObj;
begin
  Result := TULSRObj(Obj);
end;

destructor TSeqSample.Destroy;
begin
  inherited Destroy;
end;

{v0.49}
function TSequence.GetDataTemplate: TAcqData;
var
  d: TAcqData;
  {v0.61}{/v0.61
  ul: TUserViewLimit;}
begin
  if FDataTemplate = nil then begin
    {v0.61}
    CreateOrOpenDataFile(DataTemplateFileName, d);
    {/v0.61
    d := TAcqData.Create(DataTemplateFileName, omRead);
    try
      if d.ULI.Duration <> 0 then begin
        ul := NewUserViewLimit;
        d.ULVL.MinX := ul.Min.X;
        d.ULVL.MinY := ul.Min.Y;
        d.ULVL.MaxX := d.ULI.Duration / 60; //min
        d.ULVL.MaxY := ul.Max.Y;
      end;
      d.ULF.SaveToFile(d.ULF.FileName);
    except
      d.Free;
    end;
    }
    FDataTemplate := d;
  end;
  Result := FDataTemplate;
end;

procedure TSequence.SetDataTemplateFileName(const AFileName: TFileName);
begin
  if (AFileName = ULSQ.DataTemplateFileName) then
    exit;
  FDataTemplate.Free;
  FDataTemplate := nil;
  ULSQ.DataTemplateFileName := AFileName;
end;

function TSequence.GetDataTemplateFileName: TFileName;
begin
  if ULSQ.DataTemplateFileName = '' then begin
    ULSQ.DataTemplateFileName :=
      AddBackSlash({v0.64}DefTemplateDir{/v0.64 TemplateDir}) +
      {v0.50} pvUlanDefaultTemplate{/v0.50 pvUlanDefaultSeq};
  end;
  {v0.64}
  Result := ULSQ.FindField('DataTemplateFileName').AsFullFileName;
  {/v0.64
  Result := ULSQ.DataTemplateFileName;}
end;
{/v0.49}

procedure TSequence.CheckDir;
begin
  DefMethod.Obj.FindField('CalibrationFileName').FldDesc.DefDir := DirName;
  CreateDir(DirName);
  if not FileExists(FileName) then
    Save;
end;
{/TSSequence.}

{v0.64}
{function TSequence.GetDefDataTemplateFile: TFileName;
begin

end;}
{/v0.64}


{v0.50}
procedure TSeqSample.FieldDefDirNeeded(AField: TULObjField);
var
  fd: TULObjFldDesc;
  fn: string;
begin
  fd := AField.FldDesc;
  fn := fd.Name;
  if fn = 'PrgFileName' then
    fd.DefDir := Sequence.GetDefPrgDir
  else if fn = 'MethodFileName' then
    fd.DefDir := Sequence.GetDefMethodDir
  {v0.52}
  else if fn = 'DataTemplateFileName' then
    fd.DefDir := Sequence.GetDefTemplateDir
  {/v0.52};
end;

function TSeqSample.GetSequence: TSequence;
begin
  Result := TSequence(ULObjOwner);{ulobjusru}
end;
{/v0.50}

{v0.62}
function TSeqSample.GetDataTemplateFileName: TFileName;
begin
  {v0.64}
  if ULSR.DataTemplateFileName <> '' then begin
    Result := ULSR.FindField('DataTemplateFileName').AsFullFileName
  end else begin
    Result := Sequence.DataTemplateFileName;
  end;
  {/v0.64
  if ULSR.DataTemplateFileName <> '' then
    Result := ULSR.DataTemplateFileName
  else
    Result := Sequence.DataTemplateFileName;
  }
end;
{/v0.62}

{v0.64}
{procedure TSeqSample.SetMethod(AMethod: TUlanMethod);
begin
  Method.Assign(AMethod);
end;

procedure TSeqSample.SetPrg(APrg: TPrg);
begin
  Prg.Assign(APrg);
end;}

procedure TSeqSample.PrgObjAssign(APrgObj: TULObj; const AFileName: string);
begin
  if APrgObj <> nil then begin
    Prg.ObjAssign(APrgObj);
  end else begin
    Prg.LoadFromFile(AFileName);
  end;
  PrgSource := AFileName;
end;

procedure TSeqSample.MethodObjAssign(AMethodObj: TULObj; const AFileName: string);
begin
  if AMethodObj <> nil then begin
    Method.ObjAssign(AMethodObj);
    Method.ULM.MethodTemplate := AFileName;
    Method.ULM.MethodFileName := '';
  end else begin
    Method.LoadFromFile(AFileName);
    Method.ULM.MethodTemplate := AFileName;
    Method.ULM.MethodFileName := AFileName;
  end;
  MethodSource := AFileName;
end;

function TSeqSample.GetPrgFileName: TFileName;
begin
  Result := Obj.FindField('PrgFileName').AsFullFileName;
end;

function TSeqSample.GetMethodFileName: TFileName;
begin
  Result := Obj.FindField('MethodFileName').AsFullFileName;
end;

procedure TSeqSample.PrgLoad;
var d: TAcqData;
begin
  if PrgFileName <> '' then begin
    PrgObjAssign(nil, PrgFileName);
    Log('Sequence program (unique for sample) loaded from file: ' + PrgFileName);
  end else begin
    if (DataTemplateFileName <> '') and (DataTemplateFileName <> Sequence.DataTemplateFileName)
    then begin
       d := TAcqData.Create(DataTemplateFileName, omRead);
       try
         PrgObjAssign(d.ULI_USP, DataTemplateFileName);
         Log('Sequence program (unique for sample) loaded from template file: ' + DataTemplateFileName);
       finally
         d.Free;
       end;
    end else begin
      PrgObjAssign(Sequence.DefPrg.Obj, Sequence.DataTemplateFileName);
      Log('Sequence program (default for sequence) assigned.');
    end;
  end;
end;

procedure TSeqSample.MethodLoad;
var d: TAcqData;
begin
  if MethodFileName <> '' then begin
    MethodObjAssign(nil, MethodFileName);
    Log('Sequence method (unique for sample) loaded from file: ' + MethodFileName);
  end else begin
    if (DataTemplateFileName <> '') and (DataTemplateFileName <> Sequence.DataTemplateFileName)
    then begin
       d := TAcqData.Create(DataTemplateFileName, omRead);
       try
         MethodObjAssign(d.ULM, DataTemplateFileName);
         Log('Sequence method (unique for sample) loaded from template file: ' + DataTemplateFileName);
       finally
         d.Free;
       end;
    end else begin
      MethodObjAssign(Sequence.DefMethod.Obj, Sequence.DataTemplateFileName);
      Log('Sequence method (default for sequence) assigned.');
    end;
  end;
end;

procedure TSeqSample.PrgAndMethodLoad;
begin
  PrgLoad;
  MethodLoad;
end;
{/v0.64}

{/TSeqSample.}





{v0.50}
function SequenceNew(var s: TSequence; template: TULFObj): boolean;
var
  c: TULObj;
{v0.64}{/v0.64 uli: TULIObj;
  ulm: TULMObj;
  usp: TUSPObj;
  n: string;}
  frm: TAnalSetupForm;
  r: integer;
begin
  Result := false;
  {v0.51}
  if template = nil then
    exit;
  {/v0.51}
  s := TSequence.Load('');
  try
    c := template.FindOrAdd(ULAID, '');
    {v0.51}
    {v0.64}{/v0.64 uli := TULIObj(c.FindOrAdd(ULIID, ''));
    usp := nil;}
    {/v0.51}

    s.Obj.Assign(c);
    s.ULSQ.DataTemplateFileName := template.FileName;
    s.SequenceKind := TULIObj(s.Obj.FindOrAdd(ULIID,'')).SequenceKind;

    {v0.64 ignore original source file name of the program and method
      if they are copied from template}
    {/v0.64
    if uli.FindObj(USPID, foNotSelf + foNotRecursive, '', TULObj(usp)) then
      s.ULSQ.PrgFileName := usp.PrgName;

    if c.FindObj(ULMID, foNotSelf + foNotRecursive, '', TULObj(ulm)) then begin
      n := ulm.MethodFileName;
      if n = '' then
        n := ulm.MethodTemplate;
      s.ULSQ.MethodFileName := n;
    end;
    }

    s.ULSQ.SequenceName := s.GetNewSequenceName;
    {v0.50}
    s.UpdateFileNameFromSequenceName;
    {/v0.50
    s.FileName := AbsoluteFileName(s.Obj.ObjDesc.DefDir, s.ULSQ.SequenceName, ULSExt);}

    {v0.50}
    CurULObj := s.DataTemplate.ULA;
    frm := TAnalSetupForm.Create(Application.MainForm);
    try
      frm.ULATabSheet.TabVisible := false;
      frm.SequenceTabSheet.Visible := true;
      frm.SequenceTabSheet.TabVisible := true;
      frm.PageControl.ActivePage := frm.SequenceTabSheet;
      {ULObjToForm(s.ULSQ, frm, [], '');}
      frm.SequenceNameEdit.Text := s.ULSQ.SequenceName;
      frm.SequenceDescEdit.Text := s.ULSQ.SequenceDesc;
      frm.SequenceKindEdit.ItemIndex := ord(s.ULSQ.SequenceKind);
      {}
      r := frm.ShowModal;
      if r <> mrOK then begin
        s.Free;
        exit;
      end else begin
        {FormToULObj(frm, s.ULSQ, [], '');}
        s.ULSQ.SequenceName := frm.SequenceNameEdit.Text;
        s.ULSQ.SequenceDesc := frm.SequenceDescEdit.Text;
        s.ULSQ.SequenceKind := TSequenceKind(frm.SequenceKindEdit.ItemIndex);
        {}
        s.UpdateFileNameFromSequenceName;
        {v0.51}
        if (s.ULSQ.SequenceKind = skStandalone) then begin
          {v0.64}
          s.DefPrg.ObjAssign(s.DataTemplate.ULI_USP);
          {/v0.64
          s.DefPrg.Obj.Assign(s.DataTemplate.ULI_USP)};
        end;
        {/v0.51}
      end;
    finally
      frm.Free;
    end;
    {/v0.50
    if s.Obj.EditModal <> mrOK then begin
      s.Free;
      exit;
    end;}
    CreateDir(s.DirName);
    if not FileExists(s.FileName) then
      s.Save;
  except
    s.Free;
    raise;
  end;
  Result := true;
end;
{/v0.50}

{v0.32}
function SequenceBrowserOpen(const AFileName: shortstring; AMode: TOpenMode): boolean;
var
  s: TSequence;
  {v0.50}
  t: TULFObj;
  {/v0.50
  t: TSequence;}
  fn: string;
  ext: string;
  {v0.41}
  sf: TSequenceClass;
  {/v0.41}
begin
  {v0.50}
  Result := false;
  {/v0.50}
  {v0.41}
  {v0.49}
  sf := TSequence;
  {/v0.49
  if AAAActive then begin
    sf := TSequence
  end else begin
    sf := TSSequence;
  end;}
  {/v0.41}
  if ChangeFileExt(ExtractFileName(AFileName), '') = 'Default' then begin
    fn := ''
  end else
    fn := AFileName;
  ext := ExtractFileExt(fn);
  if ext = '' then
    ext := ULSExt;
  if (AMode = omCreate) then begin
    if (fn <> '') then begin
      {v0.60}
      if ExtractFileName(fn) = pvFromFileTemplate then begin
        if MainForm.ParentFileOpenDialog.Execute then begin
          fn := MainForm.ParentFileOpenDialog.FileName;
          ext := ExtractFileExt(fn);
        end else begin
          raise EUserAborted.Create(GetTxt({#}'User Aborted'));
        end;
      end;
      {/v0.60}
      fn := ChangeFileExt(fn, ext); { ulsqtype ulanrecs.lst }
      if FileExists(fn) then begin
        {v0.50}
        t := TULFObj.Load(fn);{ulobju ulfobju}
        {/v0.50
        t := sf.Load(fn);}
        try
          {v0.50}
          if not SequenceNew(s, t) then
            exit;
          {/v0.50
          s := sf.Load('');
          try
            s.Obj.Assign(t.Obj);
            s.ULSQ.DataTemplateFileName := fn;
          except
            s.Free;
            raise;
          end; }
        finally
          t.Free;
        end;

      end else begin
        raise Exception.Create(GetTxt({#}'Sequence template not found') + ' ' + fn);
      end;
      {v0.41}
      if ExtractFileExt(AFileName) = ULTExt then begin
        {v0.50}{/v0.50
        s.SequenceKind := TULIObj(s.Obj.FindOrAdd(ULIID,'')).SequenceKind;}
        {v0.49}
        {v0.50}
        {/v0.50
        if s.SequenceKind <> skAAA then}
        {/v0.49
        if s is TSSequence then
          TSSequence}
        {v0.50}
        {/v0.50

          (s).DataTemplateFileName := AFileName;}
      end;
      {/v0.41}
    end else begin
      s := {v0.41}sf{/v0.41 TSequence}.Load('');
    end;
  end else begin
    s := {v0.41}sf{/v0.41 TSequence}.Load(fn);
    {v0.41}
    {if ExtractFileExt(AFileName) = ULTExt then begin
      if s is TSSequence then
        TSSequence(s).DataTemplateFileName := AFileName;
    end;}
    {/v0.41}
  end;
  s.Obj.BrowserAutoClose := true;
  s.Obj.SetFlag(rfBrowseModal, false);
  s.Browse;
  Result := true;
end;
{/v0.32}

{v0.24}
initialization
  RegisterClasses([TSequence, TSeqSample]);
{/v0.24}
end.

