unit ULRecTyp;
{ Generic streamable data records - persistent objects definition:  ulanrecs.lst

    - Every T[UL]xxRec record type has its unique ID (RecID)
    - record can by of any length (RecLen)
    - RecID and RecLen are specified in Head field, that is
      present in every record at its beggining
    - Head field is immediately followed by TULRecInfo structure
    - any data bytes can follow - count = Head.RecLen - sizeof(TULRecHead) -
        sizeof(TULRecInfo)
    - record itself can be a header for data that follow after the record
      (mostly other TULxRec records), in that case TULRecInfo.DataLen is
      non zero, if TULRecInfo.Flags have rfNoULRecChild set, then the
      data are not TULxRec records (e.g. acquisition data) and the TULxRec
      usually defines own methods to handle them

  Top owner of all TULxxRec records/objects/forms is ULFObju .TULFObj }

{see *Sample TULRec record }

interface
{ see UlanDef\ULREC.LST for Chromulan objects definitions }
{mytype}
const
  ULRecMaxDataSize = 256*256*256;
    { Arbitrarily chosen maximal size of the ULxxRec record }
  ULMaxChildRecIDCount = 100;
    { Arbitrarily chosen maximal allowed number of different RecIDs
      allowed for child records }
  ULMaxFldCount = 128;
  ULFExt = '.ULF';
    { Default extension for files }
  {v0.24}
  ULMaxFieldColorCount = 16;
  {/v0.24}

type
  TULRecID = longint;
    { Unique record ID - every data type record has it's own ID }
  TULRecIDStr = shortstring;

  TULRecLen = longint;
    { Length of the record data, including sizeof(TULRecHead), i.e. = sizeof(TULxRec) }
  TULDataLen = longint;
    { Length of the additional data that are not part of the record itself,
      the data are stored in streams immediately after the record,
      it can be array of another records (loaded into Components array)
      or data of any structure }
  TULRecFlags = longint;
    { Field that has every ULxRec data record in Info field,
      meaning of bits depends on RecID, for common ones see rfXXXX  }
  TULRecOptions = longint;
    { For user defined flags, not used by the system. }
  TULRecCount = longint;
    { Number of owned TULxxRec records. }
  TULRecName = shortstring;
    { Name used for discrimination of more records of the same type stored
      in the same file. If the record.Info.Flags has rfHasRecName set,
      then the first field after Info field is shortstring that holds
      name of the record. (see TULFileName) }

  TULRecHead = packed record
    RecID: TULRecID;
    RecLen: TULRecLen;
  end;
    { Every TULxRec starts with this structure and is followed by TULRecInfo
      structure }

  TULRecInfo = packed record
    Flags: TULRecFlags; { see rfXXXX }
    CreateTime: TDateTime;
      { date/time of creation of this record }
    ChangeTime: TDateTime;
      { date/time of last modification (last common published property,
        see ULRecLastCommonProp ) }
    DataLen: TULDataLen;
      { sum of sizes of child records, that follow in the source stream }
    FieldsLen: integer;
      { Equals mostly = sizeof(TULxxRec), only if the record contains longstring
        fields, then it includes also lenghts of the strings. Whole record
        including its fields and data needs FieldsLen+DataLen bytes in the stream. }
    Options: TULRecOptions;
      { Flags reserved just for user convenience, not used in any way }
  end;
    { Every TULxRec contains this structure immediately after TULRecHead
      structure, that is at the beginning of the TULxRec }

  TULRec = packed record
    Head: TULRecHead;
    Info: TULRecInfo;
    Fields: record end;
  end;

  PULRec = ^TULRec;
  TULRecMax = packed record
    Head: TULRecHead;
    Info: TULRecInfo;
    case integer of
      0: (Fields: array[0..ULRecMaxDataSize - 1]of byte);
      1: (RecName: TULRecName);
      2: (Data: array[0..ULRecMaxDataSize - 1]of byte);
  end;
    { just for typecasting }
  PULRecMax = ^TULRecMax;

(*Sample TULRec with all possible field types and descriptions

  TXXXXRec = packed record
    {<
       Caption="caption of the record"
       RootChild=1
       ChildRecIDs=ULADID,ULAFID,ULIID,ULMID
       HasRecName=1
       Uses=ULADType,ULAFType,ULIType,ULMType
       Enabled=1
       Visible=1
       HasPointer=1
    >}
    { Description of the record, might be used for generation of online
      help }


    Head: TULRecHead;{ mandatory field }
    Info: TULRecInfo;{ mandatory field }

    Field1: TULRecName;
     { If Rec.HasRecName=1, then this field (first field after Info) must be
       some shortstring (string[x], x=1..255) and can be used for locating
       the record using ulobj.findobj function }

    Field2: xxx;
      {<
        Enabled=1
        Caption="title = short description of the field1"
        Hint="text that will appear on status line if this field input is active"
        Type=Enum
      >}
      { Description of the field=property, can be used for generating of online help }


      {
        Type=Enum
               TComboBox, use for enumerated types
             ULEnum
               TComboBox (assigning value from the field of the
               same name of one of the child records of
               ValuesSource ULObject assigned runtime to FieldDesc
               accorging to ValuesSourceRecID (= RecID of the owner of
               the childs with the fields of the same name (can be 0 for any))
             FileName
               TEdit (for now; assigns RelativeFileName))
             FileDateTime
               TEdit (converting to human readable value)
             (for boolean TCheckBox used automatically)
      }
  end;
*)

{v0.09}
type
  TUserCoef = single;
{/v0.09}
  {v0.24}
  TULFieldColor = array[0..1] of integer;{pen/brush colors}
  TULFieldColors = array [0..ULMaxFieldColorCount - 1] of TULFieldColor;{TColor;}
  PULFieldColors = ^TULFieldColors;
  {/v0.24}

  TULFldDesc = record { keep in sync with ULOFType }
    Caption: string;
      { Name of the field that should be appear in edit and browse window }
    Hint: string;
      { Short description of the field purpose. }
    EditWidth: integer;
      { Width of the field value in editwindow. If = 0, default used. }
    BrowseWidth: integer;
      { Width of the field value in browsewindow. If = 0, default used. }
    Flags: longint;
      { See ffXXXX }
    {v0.09}
    UserCoef: TUserCoef;
      { Coeficient by which the value of the field will be divided
        if UserValue will be requested (taken in account if <> 0) }
    NumDec: integer;
      { number of decimal points if converting number to string,
        number of digits taken from BrowseWidth }
    {/v0.09}
    {v0.14}
    ValuesSourceRecID: TULRecID;
    {/v0.14}
    {v0.24}
    FieldColorCount: integer;
    FieldColors: PULFieldColors;
    Filter: string;
    Left, Top, Width, Height: integer;
      { default position/size in record edit window }
    DefDir: string;
      { Default directory where to look for files for this field
        (if is filename) }
    StripPrefix: string;
    {/v0.24}
    {v0.26}
    EditMask: string;
    {/v0.26}
    {v0.45}
    MaxID: integer;
      { used if AutoInc field }
    DispPropName: string;
      { for ULEnum field, name of the field in related ULObj, that should be
        shown }
    {/v0.45}
  end;
  PULFldDesc = ^TULFldDesc;

  TULFldDescs = array[0..ULMaxFldCount-1] of TULFldDesc;
  PULFldDescs = ^TULFldDescs;

  TULChildRecIDs = array [0..ULMaxChildRecIDCount - 1] of TULRecID;
  PULChildRecIDs = ^TULChildRecIDs;
  TULRecDesc = record { these fields must be also in ULORType }
    { Info common for all instances of given TULxxRec record. }
    Caption: string;
      { Name of the record that is shown to the user }
    ChildRecIDsStr: string;
      { List of child RecIDs, in ASCII, comma separated. Used in MAKECOMP.  }
    ChildRecIDs: PULChildRecIDs;
      { pointer to array containing list of RecIDs that are allowed
        for TULxxObj childs. }
    ChildRecIDCount: integer;
      { How many RecIDs are in the ChildRecIDs^ array. }
    FldCount: integer;
      { Number of ULxxRec fields (exluded Head and Info fields) }
    Flds: PULFldDescs;
      { Description of fields (common info for all instances of the record) }
    Flags: TULRecFlags;
    SortExp: string;
      { Pascal expression that returns sort value of the record; of rfSortedByNumber
        is set, than the result should be number otherwise string. }
    EditFieldList: string;
      { List of names of the fields (comma separated, no spaces) that should
        appear in the edit window (in the given order). If not specified,
        all fields in normal order will be used. }
    BrowseFieldList: string;
      { List of names of the fields (comma separated, no spaces) that should
        appear in browser (in the given order). If not specified all fields
        will be used. }
    {v0.22}
    MenuFieldList: string;
      { List of names of the method fields (comma separated, no spaces)
        that should appear in local menu (e.gi in browser), in the given order.
        If not specified all method fields will be used. }
    {/v0.22}
    {v0.23}
    BrowseChildRecIDs: string;
      { List of ULRecIDs (strings) of childs that should appear in browser that
        shows childs of this object (comma separated, no spaces). If empty, than
        all childs will be shown, if set to 0 browsing of childs will be disabled;
        see rfIsBrowseChild (in UserMode=umSysOp browsing shows all childs) }
    NameProp: string;
      { Name of the record's property, that is used as default for creating/searching
        ULObjPath; if = '', then first ULObj indexed field used if rfHasRecName set,
        otherwise TComponent.Name is used. Use TULObjDesc.EfNameProp to get the default
        name }
    {/v0.23}
    {v0.24}
    MainProp: string;
      { Name of the main record's property. Calling it's Set method will cause
        sending cmULObjMainPropUpdated message. }
    DefDir: string;
      { Default directory where to look for files with this object
        or where create new file containing this object. Can be changed
        runtime. }
    {/v0.24}
    {v0.25}
    OpenFilter: string;
      { filter for OpenDialog }
    SaveFilter: string;
      { filter for SaveDialog }
    {/v0.25}
  end;
  PULRecDesc = ^TULRecDesc;

  TULFileName = shortstring;
    { Name of the files used for storing ulan data, records. If
      the name contains "#" (= ULFNDelim) then before "#" is the usual filename
      part, after "#" follows name of the record stored in that file - used for
      reading just that record from the file. }
  TULRecFn = function(AObj: pointer):integer;
    { Exported function that are looked up before calling standard TULObj
      methods have this type }

const
  ULFNDelim = '#';
    { See TULFileName. }
  ULFID =  ord('U') + 256*ord('L') + 256*256*ord('F');
    { ID of master record that holds all records read from file. }
  {v0.24}
  ULRID = ord('U') + 256*ord('L') + 256*256*ord('R');
    { ID of ULObjRW object - runtime object(structure) creator }
  {/v0.24}

  NoULRecID = 0;
    { Means no data assigned }
  UlxID = ord('U') + 256*ord('L') + 256*256*ord('X');
    { generic ULxRec record with default behavior - just read/write data of
      any size - not supported now. }
  ULRecHeadSize = sizeof(TULRecHead);
    { lenght of header of ULxRec data record(s) (files)
      (includes record type unique ID (TRecID = longint) and (TRecLen = longint)
      length of the record }
  ULRecInfoSize = sizeof(TULRecInfo);
  ULRecSize = sizeof(TULRec);
  ULRecMaxSize = ULRecSize + ULRecMaxDataSize;
  ULRecLastCommonProp = 'ChangeTime';
    { Name of the last published property that is present in every ULObj
      object descendant }

{rfXXXX common ULxRecFlags bits}
const
  {v0.25}
  rfAskForSave = $00000002;
    { If set, then if the object is browsed, upon closing the window
      user will be asked if modified data should be saved to file,
      if answer is yes, the data in the memory will be replaced by
      the data from the file. }
  {/v0.25}
  {v0.24}
  rfUsingColors = $00000004;
    { set true automatically if at least one field of the record is using colors
      in browser, or must be specified in ULRec declaration if color used
      just for the whole record }
  {/v0.24}
  {v0.23}
  rfBrowseModal = $00000008;
    { should the browser window for obj childs be opened modal }
  rfIsBrowseChild = $00000010;
    { not really set to TULObj.Flags field, just used in IsFlagSet method to
      query childs that should appear in browser: returns true if
        (Owner.BrowseChildRecIDs = '') and rfVisible is set,
      or if the Obj.RecID is listed in the non empty owner's BrowseChildRecID list }
  {/v0.23}
  {v0.22}
  rfHasPointer = $00000020;
    { If set, then the record has some field(s), that holds pointers to
      some other objects - they must be assigned runtime, i.e. during
      load the fields (name of the pointer fields must end with _Ptr suffix)
      a cleared, must be set to usable values later by the program).
      Also set if some field is using ValuesSource.

      This flag is used for speeding up the load operation (so that not
      all records field names must be scanned for _Ptr suffix);
      also messages from destroyed objects will be handled (clearing the pointers) }
  {/v0.22}
  {v0.21}
  rfEditModal = $00000040;
    { If set, then Edit method will cause editing the objects properties
      in modal dialog }
  {/v0.21}
  {v0.15}
  rfWriteLocked = $00000080;
    { Records is currently locked for writing, i.e. can not be changed by user
      (in edit form or browser). Can be changed runtime (see rfEnabled, rfVisible) }
  {/v0.15}
  {v0.24 moved to osXXXXX}{/v0.24 rfJustCreated = $00000100;}
    { if set, then the object was created in browser and is beeing edited,
      should be destroyed if editing canceled (by pressing Cancel btn) }
  {v0.44}
  rfOwnMessageOnSelect = $00000400;
    { Selecting Obj (toggling rfSelected) will genereate cmULObjUpdatedSelect
      instead of cmULObjUpdated }
  {/v0.44}
  rfCantAddChild   = $00000800;
    { Child can not be added from browser (by user) }
  rfSelected = $00001000;
    { The objects is currently selected (highligthed) }
  rfSortedByNumber = $00002000;
    { If set, then if rfChildSorted set, then Sort method uses childs'
      GetSortNum method insted of GetSortStr (must be set to owner and childs) }
  rfBrowseOnEdit   = $00004000;
    { If set, then if Edit is called from browse window, then TULObj.Browse
      method is called insted of TULObj.Edit (used for objects, that are
      just no info having headers for array of records, e.g. peaks or baseline) }
  rfCantDelete     = $00008000;
    { The object can not be deleted by user during browsing if flag set.
      Especially useful, if pointer to some childs used, prevents dereferencing
      already invalid pointer (i.e. the child won't get destroyed by calling
      ChildsDelete method)  }
  rfFileDataStream = $00010000;
    { FData field in TULObj is implemented as FileStream; rfHasRecName must
      be also on and the RecName property is used for FileStream's name. }
  rfVisible        = $00020000;
    { Record visible during manual/user editing - in browser, menu, ..
      (permanent flag, i.e. should not be changed runtime) }
  rfEnabled        = $00040000;
    { Record enabled for user manual editing (permanent flag, i.e.
      should not be changed runtime) }
  rfTemporary      = $00080000;
    { The record/object is created just at runtime, not stored to file
      (SaveToStream methods of given object does nothing) }
  rfRootChild      = $00100000;
    { The record/object can be direct child of root TULFObj object
      (used to offer this record as possible new record if New Record requested) }
  rfHasRecName     = $00200000;
    { If set, then the record contains field, that holds name of the record -
      it is ALWAYS the first field after standard Head and Info fields;
      used for discrimination if more records of the same type included
      in the same file. (see TULFileName) }
  rfChildSorted    = $00400000;
    { If set, child records are sorted, i.e. child objects must implement
      (override) method GetSortStr. }
  rfChildAllowed   = $00800000;
    { if set, the record can have child data - if rfNoULRecChild set, then
      just generic data, otherwise childs are ULxRec records in Components array}
  rfDefault        = $01000000;
    { if set, then the record contains program compile time default values }
  rfFromTemplate   = $02000000;
    { if set, then the record contains data retrieved from ini or template file }
  rfManual         = $04000000;
    { if set, then the record contains data that were set by the user manually
      during the program session }
  rfAcquired       = $08000000;
    { if set, then the record contains data received from some device }
  rfIsTemplate     = $10000000;
    { if set, then the record is serving as a template record (read only) }
  rfEncrypted      = $20000000;
    { if set, then all record fields after Head and Info fields are encrypted }
  rfDataChild   = $40000000;
    { if set, then data that follow after the record are not TULxRec records
      and will be loaded to Data memory stream associated with TULObj,
      instead into TULObj.Components array }
{/rfXXXX}

{ffXXXX ULRec fields/properties flags }
const
  ffEnabled = 1;
    { Field can be modified by user }
  {v0.22}
  ffNonVisible = 2; {used if EditFieldList or BrowseFieldList are not defined}
  {/v0.22}
  {v0.13}
  ffFileName = 4;
    { The field value is name of a file }
  ffFileDateTime = 8;
    { The field value (integer) is File-date/time value }
  {/v0.13}
  {v0.14}
  ffULEnum = $10;
    { The field is of type ULEnum (i.e. values can be assigned only
      from childs of ValuesSource ULObj (its ID can be specified in ValuesSourceRecID) }
  ffReadOnly = $20;
    { The field (must be edited in TEdit) is readonly, i.e. if Enabled,
      user can put cursor in it but can not modify it }
  {/v0.14}
  {v0.22}
  ffMemo = $40;
    { For strings that should be editited in Memo (more lines, 3 by default) }
  ffMethod = $80;
    { The field is method. Some reasonable value must be assigned to the field
      at runtime if should be used somehow. Local (e.g. in browser) menu
      can be updated by adding published methods of the window root object. }
  {/v0.22}
  {v0.23}
  ffCommand = $100;
    { The field is command. If any value written to it, the command will be
      executed. It also means, that no value can be read from the property
      (i.e. is write-only).
      Will be set automatically if type of the property in XXXXType
      file will be specified as TCommand.  }
  ffWriteAlways = $200;
    { Should be every value assignet to the property, even if it has the
      same value? }
  {/v0.23}
  {v0.24}
  ffDir = $400;
    { The field holds directory name (Type=Dir) }
  {/v0.24}
  {v0.25}
  ffIsSortField = $800;
    { The field is part of SortExp }
  {/v0.25}
  {v0.31}
  ffToPrint = $1000;
    { should the field be printed? }
  ffToPrintFoot = $2000;
     { should the field be printed in detailfoot band? }
  {/v0.31}
  {v0.45}
  ffTime = $4000;
    { the field holds time value (TDateTime, using only fractional part) }
  ffDate = $8000;
    { the field holds date value (TDateTime, using only interger part) }
  ffDateTime = ffTime or ffDate;

  ffAutoInc = $10000;
    { is autoincrement field? }
  {/v0.45}
{/ffXXXX}

{ULRecFindOptions}
type
  TULRecFindOptions = longint;
    { options for TULObj.FindObj(ARecID:TULRecID; fo:TULRecFindOptions;
      var AObj:TULObj) method }
{foXXXX}
const
  foDefault = 0;
    { starts looking from self, then childs, recursively }
  foNotSelf = 1;
    { look only to childs (not self), recursively }
  foNotRecursive = 2;
    { don't look in childs' childs }
  foFromRoot = 4;
    { start looking from top owner }
  foNext = 8;
    { look for next matching AObj (i.e. AObj start value is last found value) }
  foFromOwner = $10;
    { start looking from self.owner }

  {v0.30}
  foChilds = foNotSelf + foNotRecursive;
  {/v0.30}
{/foXXXX}

{/FindULRecOptions}
type
  TStreamOptions = record
    Flags: longint;
    IndentLevel: shortstring;
    Line: longint;
    Head: shortstring;
    IsInData: boolean;
    {v0.22}
    MemoLevel: shortstring;
    LastPropName: shortstring;
    {/v0.22}
  end;
{sfXXXX}
const
  sfAscii = 1;
    { TULRec.SaveToStream, LoadFromStream, LoadRecFromStream will deal with
      ascii file/conversion. This flag set if FileName has .ASC extension
      instead of .ULF }
  sfOnlySelectedChilds = 2;
    { SaveToStream will save only selected childs }
{/sfXXXX}

type
  TULRecFnID = integer;
{ufXXXX supported ULRec exported functions; parameter to  ULFObju
  .TULFObj.ULFindObjFN method }
const
  ufEdit = 0;
    { function called when Obj.Edit method called }

{/ufXXXX}

const
  AscBeginTag = ' begin';
    { When exporting TULObj to .ASC file, every record begining is marked
      with line: "ULxx begin" (eventuall indent spaces at the beginning) }
  AscEndTag = 'end';
    { When exporting TULObj to .ASC file, every record end with line: "end"
      (eventuall indent spaces at the beginning) }
  AscValDelimiter = '=';
    { When exporting TULObj to .ASC file, value of each published property
      of the record is written on the separate line prepended with property
      name - separated with "=", e.g. "Name=Neco" record end with line: "end"


{ULRecChildType}
type
  TULRecChildType = byte;
{ctXXXX}
const
  ctNone = 0;
    { no childs allowed for the ULxRec record }
  ctData = 1;
    { generic data (non ULxRec) childs allowed (= rfChildAllowed and rfNoULRecChild) }
  ctULRec = 2;
    { childs are ULxRec record (= rfChildAllowed and (not rfNoULRecChild) }
{/ctXXXX}

{/ULRecChildType}

{pnXXXX record/fields attribute/property names (specify in ULxxType.PAS files,
  used by makecomp.exe to generate source files), see ulobju }
const
  {common ULRec properties}
  pnRecID = 'RecID';
  pnRecLen = 'RecLen';
  pnFlags = 'Flags';
  pnCreateTime = 'CreateTime';
  pnChangeTime = 'ChangeTime';
  pnRecSize = 'RecSize';
  {pnFileName = 'FileName';}
  pnDataLen = 'DataLen';
  pnChildType = 'ChildType';
  {/common ULRec properties}

  {ULxxType.PAS properties used to define additional properties of TULxxRec
    specified in TULRecDesc }
  pnType = 'Type';
    { Property of fields - type of the field for Form creation:
      for pvEnum - TComboBox
      for pvULEnum - TComboBox (assigning value from the field of the
        same name of on of the child records of ValuesSource ULObject assigned
        runtime to FieldDesc accorging to ValuesSourceRecID (= RecID of
        the owner of the childs with the fields of the same name (can be 0 for any))
      for pvFileName - TEdit (for now; assigns RelativeFileName))
      for pvFileDateTime - TEdit (converting to human readable value)
      for pvSet - buttonedit invoking CheckedListBox
      else TEdit (for boolean TCheckBox) }
  pnCaption = 'Caption';
    { Property for: record - name of the record type shown to the user;
                    field - name of the field shown to the user }
  pnChildRecIDs = 'ChildRecIDs';
    { Property for record. Holds comma separated list of ULyyID constants,
      that are allowed for the childs of this record (i.e. what kind of records
      are allowed in TULxxObj.Childs array) }
  pnChildSorted = 'ChildSorted';
    { Property for record. If = '1', then child records will be sorted.
      Makes sense only if ChildRecIDs defined. (= rfChildSorted) }
  pnDataChild = 'DataChild';
    { Property of record. If = '1', then the record has just generic data stream,
      not TULxxRec childs (= rfDataChild) }
  pnUses = 'Uses';
    { Property of record. List of units (comma separated, no spaces) that
      should be in uses clause of units created by MAKECOMP }
  pnRootChild = 'RootChild';
    { Property of record. If specified (e.g. RootChild=1), than the record is
      direct child of TULFObj }
  pnHasRecName = 'HasRecName';
    { Property of record (= rfHasRecName). }
  {v0.22}
  pnHasPointer = 'HasPointer';
    { Property of record (= rfHasPointer). }
  {/v0.22}
  pnSortExp = 'SortExp';
    { Property of record - pascal expression that is returned by GetSortStr
      method }
  pnTemporary = 'Temporary';
    { Property of record (= rfTemporary) }
  pnEnabled = 'Enabled';
    { Property of record (= rfEnabled), or field (ffEnabled) }
  pnReadOnly = 'ReadOnly';
    { property if field (= ffReadOnly) }
  pnVisible = 'Visible';
    { Property of record (= rfVisible) }
  pnNonVisible= 'NonVisible';
    { property of field = ffNonVisible }
  pnFileDataStream = 'FileDataStream';
    { Property of record (= rfFileDataStream) }
  pnBrowseOnEdit = 'BrowseOnEdit';
    { Property of record (= rfBrowseOnEdit) }
  pnSortedByNumber = 'SortedByNumber';
    { Property of record (owner and child) = (rfSortedByNumber) }
  pnEditFieldList = 'EditFieldList';
    { Property of record, list of fields (comma separated, no spaces)
      that should be included in edit window. }
  pnBrowseFieldList = 'BrowseFieldList';
    { Property of record, list of fields (comma separated, no spaces) that
      should be included in browser (in less details mode). }
  {v0.22}
  pnMenuFieldList = 'MenuFieldList';
    { Property of record, list of method fields (comma seperated, no spaces) that
      should be included in local menu (if assigned). }
  {/v0.22}
  {/v0.23}
  pnBrowseChildRecIDs = 'BrowseChildRecIDs';
    { Property of record, list of RecIDStr of those childs, that should appear
      in child browser; if not specified, childs with rfVisible will appear in
      the list (childs are asked IsFlagSet(rfIsBrowseChild) (see this flag).
      !!! Specify the attribute after ChildRecIDs !!! }
  pnNameProp = 'NameProp';
    { property of record; if specified, holds name of the field that is
      used for creating/searching default ULObjPath. If not specified,
      then first ULObj index field used if rfHasRecName set, otherwise
      TComponent.Name field used (use TULObjDesc.EfNameProp to get the default
      name) }
  {/v0.23}
  pnHint = 'Hint';
    { Property of fields. }
  pnEditWidth = 'EditWidth';
    { Property of fields }
  pnBrowseWidth = 'BrowseWidth';
    { Property of fields. }
  {v0.09}
  pnUserCoef = 'UserCoef';
  pnNumDec = 'NumDec';
  {/0.09}
  {v0.14}
  pnValuesSourceRecID = 'ValuesSourceRecID';
    { Property of fields, is specified only if pnType=ULEnum, then it's value
      is RecID of the ULObject (e.g. 'ULDID'), which childs have the field with
      the same name, and only one of the values specified in the childs can
      be assigned to the field that has this property defined. What is the
      source object must be specified runtime by assigning FieldDesc.ValuesSource := ..,
      before invoking edit dialog. }
  {/ULxxType.PAS properties ...}
  {v0.21}
  pnEditModal = 'EditModal';
  {/v0.21}
  {v0.44}
  pnOwnMessageOnSelect = 'OwnMessageOnSelect';{makecmp2 ulobjrwu}{usrsu}
  {/v0.44}
  {v0.23}
  pnBrowseModal = 'BrowseModal';
  {v0.23}
  {v0.24}
  pnUsingColors = 'UsingColors';
    { flag property of record }
  pnColors = 'Colors';
    { Property of field. Can be specified if field's type is Enum, then
      defines comma separated list of color pairs
      (e.g: penColor1,brushColor1,penColor2,brushColor2,..) that
      correspond to (ordinal) field values. }
  pnDefVal = 'DefVal';
    { Property of field, default value of the field, used in ULObj constructor.
      Must be specified in internal units (i.e. ignores any eventual UserCoef
      attribute) }
  pnMainProp = 'MainProp';{uldptype}
    { Property of record, specifies name of the property, that should generate
      cmULObjMainPropUpdated message }
  pnFilter = 'Filter';
    { Property of field. For Type=FileName specifies the OpenDialog.Filter
      (i.e. string in format e.g.: 'Text files (*.txt)|*.TXT|Pascal files (*.pas)|*.PAS' }
  pnDefDir = 'DefDir';
    { Property of record and field. Specifies eventual default directory
      (where OpenDialog should start) with files of either files holding
      the object (if record property), or files which names should appear
      as the field value (if field property, for FileName type fields) ulobju}
  pnStripPrefix = 'StripPrefix';
    { Property of fields of Type=Enum. If specified, than this string will be
      stripped off from the beggining of enum value string before showing to
      users (expecting that by the same prefix start ALL enum values names) }
  {pnDefDirRecID = 'DefDirRecID';
    { Property of field of type FileName. xxxxID of ULObj its' ObjDesc.DefDir
      should be copied to the field's DefDir upon the creation of the field
      (or if not found then, tries to locate it upon request of FldDesc.DefDir) }
  {/v0.24}
  {v0.25}
  pnOpenFilter = 'OpenFilter';
   { Property of record, filter for OpenDialog }
  pnSaveFilter = 'SaveFilter';
   { Property of record, filter for SaveDialog }
  pnAskForSave = 'AskForSave';
    { see rfAskForSave }
  pnIsSortField = 'IsSortField';
    { Property of field. Set 1 if the field is used in SortExp. Used
      during Field.SetValue to call Obj.Owner.Sort method automatically }
  {/v0.25}
  {v0.26}
  pnEditMask = 'EditMask';
    { Property of field. Used in browser for inplace editor (see TMaskEdit) }
  {/v0.26}
  {v0.45}
  pnAutoInc = 'AutoInc';
  pnMaxID = 'MaxID';
  pnDispPropname = 'DispPropName';
  {/v0.45}

{/pnXXXX}

{pvXXXX record/fields attribute/property values }
  pvEnum = 'Enum';
  {v0.44}
  pvSet = 'Set';
  {/v0.44}
  {v0.13}
  pvFileName = 'FileName';
  pvFileDateTime = 'FileDateTime';
  {v0.45}
  pvDate = 'Date';
  pvTime = 'Time';
  pvDateTime = 'DateTime';
    { fields of this type should hold datetime info in std local time
      (i.e. ignoring DST status). Used GPTimeZone StdToUsrDateTime/UsrToStrDateTime;
      or StdDateTimeToUsrStr, UsrStrToStdDateTime methods to show users the date/time. }
  {/v0.45}
  {v0.24}
  pvDir = 'Dir';
  {/v0.24}
  {/v0.13}
  {v0.14}
  pvULEnum = 'ULEnum';
  {/v0.14}
  {v0.22}
  pvMemo = 'Memo';
  pvMethod = 'Method';
  {/v0.22}
  {v0.23}
  pvWriteAlways = 'WriteAlways';
  {/v0.23}
{/pvXXXX}

type
  TULObjResult = integer;
{orXXXX ULObject result codes}

  (* were exceptions:
        EEmptyFileName = class(Exception);
        { Trying to save to file, but no file name specified. }
      EEmptyRec = class(Exception);
        { Trying to access data in empty record. }
      EInvalidRecID = class(Exception);
        { Invalid RecID encountered. Raised from ULFObju CreateObj }
      EInvalidRecSize = class(Exception);
        { Trying to access field which offset is beyond allocated memory. }
      ENegativeRecSize = class(Exception);
        { Trying to set negative size for the record. }
      ENoChildAllowed = class(Exception);
        { Trying to create child in ULObj for which it is not allowed. }
      EInvalidChildType = class(Exception);
        { Trying to access Data field for in non ctData childtype ULObj. }
      {EOnlyULFCanLoadFromFile = class(Exception);
        { Trying to call LoadFromFile method by object with other RecID then
          ULFID. }
      EULFCantLoadRecFromStream = class(Exception);
        { LoadRecFromStream method can not be called by ULFID object to load itself
          (ULF object is never stored in the stream). }
      EInvalidULRecDataLen = class(Exception);
        { There was not enough data in the stream as was specified by DataLen field }
      EULFTopOwnerNotFound = class(Exception);
        { Every ULObj should have as the top owner ULFID record, but it was
          not found for this one. }
      ENonULObjOwner = class(Exception);
        { Every non ULFID TULxxObj descendants must have always Owner of type
          TULxxObj }
      EAbstractCreateObj = class(Exception);
        { Abstract method TULObj.CreateObj was called. }
      EMustHaveOwner = class(Exception);
        { Every object with other ID than ULFID must have Owner. }
      EAbstractBrowseObj = class(Exception);
      EAbstractEditObj = class(Exception);
      EFileDataStreamMustHasRecName = class(Exception);
        { Object has rfFileDataStream set, but not rfHasRecName }
      EInvalidAscFormat = class(Exception);
        { While reading from .ASC file something went wrong. }
      EUnregisteredUser = class(Exception);
        { Trying to unregister unregistered user of TULObj }
   *)

const
  orOK = 0;
  or0 = 4000;
  orEmptyFileName = or0 + 1;
    { Trying to save to file, but no file name specified. }
  orEmptyRec = or0 + 2;
    { Trying to access data in empty record. }
  orInvalidRecID = or0 + 3;
    { Invalid RecID encountered. Raised from ULFObju CreateObj }
  orInvalidRecSize = or0 + 4;
    { Trying to access field which offset is beyond allocated memory. }
  orNegativeRecSize = or0 + 5;
    { Trying to set negative size for the record. }
  orNoChildAllowed = or0 + 6;
    { Trying to create child in ULObj for which it is not allowed. }
  orInvalidChildType = or0 + 7;
    { Trying to access Data field for in non ctData childtype ULObj. }
  {EOnlyULFCanLoadFromFile = class(Exception);
    { Trying to call LoadFromFile method by object with other RecID then
      ULFID. }
  orULFCantLoadRecFromStream = or0 + 8;
    { LoadRecFromStream method can not be called by ULFID object to load itself
      (ULF object is never stored in the stream). }
  orInvalidULRecDataLen = or0 + 9;
    { There was not enough data in the stream as was specified by DataLen field }
  orULFTopOwnerNotFound = or0 + 10;
    { Every ULObj should have as the top owner ULFID record, but it was
      not found for this one. }
  orNonULObjOwner = or0 + 11;
    { Every non ULFID TULxxObj descendants must have always Owner of type
      TULxxObj }
  orAbstractCreateObj = or0 + 11;
    { Abstract method TULObj.CreateObj was called. }
  orMustHaveOwner = or0 + 12;
    { Every object with other ID than ULFID must have Owner. }
  orEmptyCurULObj = or0 + 13;
    { CurULObj variable was not set to valid ULObj e.g. before calling
      TBrowseForm.Create. }
  orAbstractBrowseObj = or0 + 14;
  orAbstractEditObj = or0 + 15;
  orFileDataStreamMustHasRecName = or0 + 16;
    { Object has rfFileDataStream set, but not rfHasRecName }
  orInvalidAscFormat = or0 + 17;
    { While reading from .ASC file something went wrong. }
  orUnregisteredUser = or0 + 18;
    { Trying to unregister unregistered user of TULObj }
  orFieldNotFound = or0 + 19;
    { Property with specified name was not found in RTTI of the object }
  orEmptyPropInfo = or0 + 20;
    { Parameter APropInfo in some method (ULObjDes) was nil }
  orUpdateUnlockFailed = or0 + 21;
    { UpdateUnlock was called more times than UpdateLock }
  {v0.14}
  orNotULObject = or0 + 22;
    { Assigning value to field that should be pointer to ULObj, that is
      not pointer to such object  }
  orInvalidValuesSourceRecID = or0 + 23;
    { Setting ValuesSource value to pointer to other ULObj then
      specified in field definition }
  orNotULEnumField = or0 + 24;
  orValuesSourceNil = or0 + 25;
  {/v0.14}
  {v0.22}
  orGetPropStrFailed = or0 + 26;
  orSetPropStrFailed = or0 + 27;
  orInvalidChildFieldIndex = or0 + 28;
  orNilOwner = or0 + 29;
    { expected non nil owner }
  orUnregisteredUsers = or0 + 30;
    { some users of ULObj did not unregistered itself during cmULObjDestroyed
      message sent by ULObj to be destroyed }
  orInvalidFieldType = or0 + 31;
  {/v0.22}
  {v0.23}
  orMisplacedQuoteInFindByULPath = or0 + 32;
  orDotMissingInULPath = or0 + 33;  
  {/v0.23}
  {v0.25}
  orOnlyULFCanDoFileOpen = or0 + 34;
  {/v0.25}
  {v0.31}
  orCanNotCreateRepFrmDir = or0 + 35;
  {/v0.31}
{/orXXXX}

{bmXXXX browse modes for ULBrowu browsers, specified in ULObjDes . TULObjDesc }
type
  TULBrowseMode = (
    bmShort,
    bmFull
  );
{/bmXXXX}

const
  MaxULBrowseCols = 40;

type
  TULBrowseColWidths = array[0..MaxULBrowseCols-1] of integer;

{v0.09}
type
  TULObjStateFlag = integer;

{osXXXX ULObj State flags, accessible only through corresponding methods}
const
  osModified = 1;
    { set if some property of the object modified since load or save }
  osReadOnly = 2;
    { object is opened readonly, changes won't be saved (useful for ULF object) }
  {v0.24 replacing rfJustCreated }
  osJustCreated =  4;
    { set if child created in browser by user action, will be set false if
      new child saved from edit window}
  osInsertNextChild = 8;
    { if set, then next call of Add method will cause inserting the new Child
      before the active one }
  osJustLoadedFromFile = $10;
    { Set true just in ULObjUsr.Create constructor, flag for Load constructor
      not to load again the same file (Load calls Create) }
  {/v0.24}
  {v0.31}
  osBrowserAutoClose = $20;
    { Close the file (destroy ULObjUsr) that contains the ULObj object when
      the browse window (ULGrid) is closed? ulobju}
  osEditorAutoClose = $40;
    { Close the file (destroy ULObjUsr) that contains the ULObj object when
      the edit window is closed? }
  {/v0.31}
{/v0.09}
{v0.22}
const
  AscExt = '.ASC';
  TmpExt = '.TMP';

{cmXXXX commands for ULObj descendants, moved from UlanType, used with UtlType.WM_APPMESSAGE }
const
  cm0 = 7000;

  cmULObjUserRegister = cm0 + 300;
    { WM_APPMESSAGE sent by (usually visual) object that instantiated
      pointer to ULObject, so that it is included to ULObjects' Users
      list (i.e. it will get messages from the ULObject), lParam = ULObjUser }
  cmULObjUserUnregister = cm0 + 301;
    { see above, removing from ULObjects' Users list }
  cmULObjCanDestroy = cm0 + 302;
    { WM_APPMESSAGE sent by ULObject to all objects in its Users list,
      if some of these objects will set result to 1 (does ULEdFrm and ULBrowu),
      the ULObject will know, that it should not destroy itself yet
      (but ULObj.Free ignores it,  so call ULObj.CanDestroy before calling Free). }
  cmULObjUpdated = cm0 + 303;
    { WM_APPMESSAGE sent by ULObject to all objects in its Users list,
      to inform them, that it has changed some of its property value
      or child counts/values. Beware infinite recursions - see also
      cmULObjAfterEdit, cmULObjAfterBrowseEdit - sent only upon changes
      of values from Edit and  Browse forms.}
  cmULObjDestroyed = cm0 + 304;
    { WM_APPMESSAGE sent by ULObject to all objects in its Users list,
      to inform them, that they should not use pointer to it anymore. }
  cmULObjBeforeEdit = cm0 + 305;
    { WM_APPMESSAGE sent by ULObject to Application.MainForm before an ULEditForm
      is invoked. If Result set to <> 0, editing won't appear. lParam = ULObject;
      UsersNotify called with message cmULObjEditFormBringToFront }
  cmULEditFormCloseQuery = cm0 + 306;
    { WM_APPMESSAGE sent by ULEditForm to Application.MainForm when it is
      going to be closed with mrOK result (lParam = ULEditForm). If result
      set to <> 0, the from won't be closed }
  cmULObjAfterEdit = cm0 + 307;
    { WM_APPMESSAGE sent by ULObject to Application.MainForm after its ULEditForm
      executed (seea also cmULObjAfterBrowseEdit). lParam = ULObject.
      Better to respond to this message (in other windows then edit) then
      to cmULObjUpdated, that is generated upon EVERY change of ULObj value,
      i.e. even if made inside the receiver window
      (infinite recursion must be watched in such cases);
      Also UsersNotify. }

  cmULObjEditFormBringToFront = cm0 + 308;
    { WM_APPMESSAGE sent by ULObject to its Users, if there is a editform
      for the objects, it will return 1 and bring itself to front
      (if not, the ULObject will call open new edit form) }
  cmULObjBrowseFormBringToFront = cm0 + 309;
    { WM_APPMESSAGE sent by ULObject to its Users, if there is a browseform
      for the objects, it will return 1 and bring itself to front
      (if not, the ULObject will call open new browse form) }

  cmULObjAfterBrowseEdit = cm0 + 311;
    { WM_APPMESSAGE sent by ULObject to Application.MainForm after its
      value in browser row changed (see also cmULObjAfterEdit).
      lParam = ULObject.  Better to respond to this message
      (in other windows then browse) then to cmULObjUpdated, that is generated
      upon EVERY change of ULObj value,  i.e. even if made inside the receiver
      window (infinite recursion must be watched in such cases) }
  cmULObjValuesSourceNeeded = cm0 + 312;
    { WM_APPMESSAGE sent to all ULObj Users (using UsersNotify), in
      TULObj.MessageInfo is ULIndex of the field, that needs to fill
      FldDesc.ValuesSource (or corresponging xxx_Src_Ptr field, if present)  }
  {v0.24}
  cmULObjUpdateNow = cm0 + 313;
    { Generated by TULObjField.UpdateNow method, sent to all ULObjUsrs }
  cmULObjMainPropUpdated = cm0 + 314;
    { Generated when Set method for MainProp ULObj property (its name
      specified in MainProp record attribute in XXXXType file) is called.
      Called even if the new value of the property is the same as the old value.
      If MainProp not specified, this command is never sent. If the value changed,
      cmULObjUpdated message was already sent (but it could be generated also by
      change of other ULObj property). }
  cmULObjFieldDirChanged = cm0 + 315;
    { WM_APPMESSAGE sent if the value of field of Type=Dir was changed
      (new directory was selected using FolderDialog) }
  cmULObjFieldFileNameChanged = cm0 + 316;
    { WM_APPMESSAGE sent if the value of field of Type=FileName was changed
      (new file was selected using OpenDialog) }
  {/v0.24}
  {v0.30}
  cmULObjUserActionNeeded = cm0 + 317;
    { WM_APPMESSAGE sent by ulobj to all its users. If the ULObjUser wants to
      add some actions to local menu, is should call ULObj.MenuActionAdd
      method to add TAction object(s) (owned by the ULObjUser).
      The user must be TComponent descendant }
  {/v0.30}
  {v0.31}
  cmULObjULGridDestroyed = cm0 + 318;
    { WM_APPMESSAGE sent from the first line of ULStringGrid.Destroy
      (used by ULObjUsr to free itself if BrowserAutoClose set) }
  cmULObjFileNameChanged = cm0 + 319;
  {/v0.31}
  {v0.36}
  cmULObjULGridCreated = cm0 + 320;
  {/v0.36}
  {v0.38}
  cmULObjFileDiscarded = cm0 + 321;
    { User clicked on Yes to "Discard the file?" question which appeared
      during canceling NONAME file window (ULObjUsr can e.g. restore
      the previous file used) }
  cmULObjCloseViews = cm0 + 322;
    { Request to users to close themselves if they are some kind of graphical
      views on the Obj ULStringGrid}
  {/v0.38}
  {v0.41}
  cmULObjUserFirstActionNeeded = cm0 + 323;
    { WM_APPMESSAGE sent by ulobj to all its users. If the ULObjUser wants to
      add some actions at the beggining of local menu, is should call
      ULObj.MenuActionAdd method to add TAction object(s) (owned by the ULObjUser).
      The user must be TComponent descendant }
  {/v0.41}
  {v0.44}
  cmULObjULGridFormActivated = cm0 + 324;
  cmULObjULGridFormDeactivated = cm0 + 325;{ulstringgrid}
  cmULObjChildsResorted = cm0 + 326;
    { Sent to Users after child list Sort call finished }
  cmULObjBeginUpdate = cm0 + 327;
    { UsersNotify from first DoChangeLock call; TWinControls can disable redraw
      and enable it again in cmULObjEndUpdate }
  cmULObjEndUpdate = cm0 + 328;
    { UsersNotify from last DoChangeUnlock }
  cmULObjActiveChildChanged = cm0 + 329;
  cmULObjUpdatedSelect = cm0 + 330;
    { UsersNotify if Obj or its childs have rfOwnMessageOnSelect set and their
      selection state changed }
  {v0.46}
  cmULObjBeforeDelete = cm0 + 331;
    { UsersNotify, sent before deleting the object by user from the file }
  {/v0.46
  cmULObjBeforeBrowseChildDelete = cm0 + 331;}
    { UsersNotify, sent before calling CurChild.Free, from ULStringGrid.DelRec }
  cmULObjAfterBrowseChildDelete = cm0 + 332;
    { UsersNotify, sent from ULStringGrid after CurChild.Delete and setting
      new CurChild, from ULStringGrid.DelRec (see cmULObjAfterBrowseChildDelete) }
  cmULObjBeforeBrowseChildInsert = cm0 + 333;
  cmULObjAfterBrowseChildInsert = cm0 + 334;

  cmULObjFieldChangedInBrowser = cm0 + 335;
    { FieldUsersNotify, sent when its value changed in browser (by user);
      (Param - TULObjField) }
  {/v0.44}
  {v0.46}
  cmULObjAfterChildsDelete = cm0 + 336;
    { UsersNotify from last line of TULObj.ChildsDelete, if at least one
      child was deleted (see cmULObjAfterBrowseChildDelete for one child delete) }
  {/v0.46}

{/cmXXXX cm0=7000}

const
  SortStrPrecision = 7;
    { Used as parameter for FloatToStrF function in GetSortStr methods }
  SortStrDigits = 0;
    { Used as parameter for FloatToStrF function in GetSortStr methods }

{umXXXX UserMode (moved from ulantype)}
  { Global variable UserMode specifies how the program
    should behave }
type
  TUserMode = (
    umSysOp,
      { ULObj browsers allow access to all properties,
        user dialogs replaced by ULEdit dialogs with
        all properties enabled }
    umUser
  );
{/umXXXX}

{/v0.22}
{v0.23}
type
  TULObjPath = string;
    { used to assign unique name of the object (to TComponent.Name property),
      used in ULObjCtrl component }
  TULObjPropName = string;
    { used in ULObjCtrl }
  TCommand = integer;
    { the property is command, i.e. if anything written to it, a command will
      be triggered }
{/v0.23}
{v0.24}
type
  TColorType = (ctPen, ctBrush);

const
  ULObjFormat = 'ULObjFormat';
    { ULObj clipboard format name ; use var f:UINT
      f := RegisterClipboardFormat(ULObjFormat)
      to obtain clipboard format code }

{urXXXX result codes of TULObjBasicUsr, TULObjUsr }
const
  ur0 = 8000;
  urInvalidCreateParams = ur0 + 1;
    { generates ULObjUsr }
  urUnknownChildRecID = ur0 + 2;
    { should be used by descendants in ChildCreate method, if unsupported RecID
      submitted }
  urFileNotFound = ur0 + 3;
    { File submited to Load method not found ( raised if <> '' and <> ULRecDefFileName) }
  urTooManyRecords = ur0 + 4;
    { If AutoInc specified in some field and also specified MaxID > 0 for that field,
      then if new ID is larger then MaxID this error is shown }
  urChildCreateNotOverriden = ur0 + 5;
{/urXXXX}
{/v0.24}
{v0.31}
type
  TULObjFieldName = shortstring;
    { Used in ULOFType }
{/v0.31}
{v0.40}
{cfXXXX ULObjDesc.ClassFlags}
const
  cfFldNamesCaseNonSensitive = 1;
{/cfXXXX}
{/v0.40}
{v0.41 move from ulantype}
type
  TOpenMode = (omCreate, omRead, omReadOnly, omCreateTemplate);
    { Modes for opening ulobjusr/analysis file:
      omCreate - data will be acquired (submitted filename is a template filename if non empty)
      omRead - acquired data will be viewed/worked with (can be modified and saved)
      omReadOnly - acquired data will be viewed, any changes will not be possible
                   to save
      omCreateTemplate - only used for creating template files }
{/v0.41}
{v0.44}
  TULObjGridOption = ( {ulstringgrid ulobjdes}
    ogEditDisabled,
    ogAlwaysShowEditor,
    ogInternalValuesEnabled,
    ogAllDetails,
    ogAutoSizeBrowseCols,
    ogColumnSortEnabled,
    ogFocusSelectedEnabled
    {ogAutoSizeForm}
  );
  TULObjGridOptions = set of TULObjGridOption;

  { common menu items in ulobj browser }
  TULObjMenuItem = (
    omHeader,  { edit Obj }
    omFocused, { submenu for Obj.ActiveChild's actions }
    omGridOptions, { submenu for browser options }
    omCopy,    { Edit | Copy command }
    omPaste,   { Edit | Paste command }
    omCopySelected,
    omDeleteSelected,
    omDeleteAll,
    omSort,
    omChildAdd,
    omChildInsert,
    omChildDelete,
    omChildFileSelect,
    omPrintOptions,
    omPrint,
    omSaveAs
  );
  TULObjMenuItems = set of TULObjMenuItem;

{/v0.44}
implementation

end.
