Index: cprs/branches/tmg-cprs/CPRS-Chart/TMG_Extra/fPtDemoEdit.pas
===================================================================
--- cprs/branches/tmg-cprs/CPRS-Chart/TMG_Extra/fPtDemoEdit.pas	(revision 498)
+++ cprs/branches/tmg-cprs/CPRS-Chart/TMG_Extra/fPtDemoEdit.pas	(revision 541)
@@ -6,9 +6,32 @@
 uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
-  Dialogs, ComCtrls, StdCtrls, ExtCtrls, DKLang;
+  Dialogs, ComCtrls, StdCtrls, ExtCtrls, DKLang, Grids;
 
 type
   BoolUC = (bucFalse, bucTrue, bucUnchanged);
-  
+
+  tFileEntry = record
+    Field     : string;
+    FileNum   : string;
+    FieldName : String;
+    IENS      : string;
+    oldValue,newValue : string;
+  end;
+
+  TGridInfo = class;  //forward declaration
+  TGridDataLoader = procedure (GridInfo: TGridInfo) of object;
+  TGridInfo = class (TObject)
+  public
+    Grid      : TStringGrid;  //doesn't own object
+    FileNum   : string;
+    IENS      : string;
+    BasicMode : Boolean;
+    Data      : TStringList;  //doesn't own object
+    Message   : string;  //optional text.
+    DataLoadProc : TGridDataLoader;
+    ApplyBtn  : TButton;
+    RevertBtn : TButton;
+  end;
+
   TPatientInfo = class(TObject)
   public
@@ -58,5 +81,5 @@
 
     Modified : boolean;
-      
+
     constructor Create;
     destructor Destroy; override;
@@ -126,4 +149,6 @@
     DKLanguageController1: TDKLanguageController;
     EMailEdit: TEdit;
+    Advanced: TTabSheet;
+    gridPatientDemo: TStringGrid;
     procedure AliasComboBoxChange(Sender: TObject);
     procedure FormCreate(Sender: TObject);
@@ -162,4 +187,11 @@
     procedure DOBEditChange(Sender: TObject);
     procedure SSNumEditChange(Sender: TObject);
+    procedure PageControlChange(Sender: TObject);
+    procedure gridPatientDemoSelectCell(Sender: TObject; ACol,
+      ARow: Integer; var CanSelect: Boolean);
+    procedure gridPatientDemoSetEditText(Sender: TObject; ACol,
+      ARow: Integer; const Value: String);
+    procedure PageControlChanging(Sender: TObject;
+      var AllowChange: Boolean);
   private
     { Private declarations }
@@ -167,20 +199,52 @@
     FServerPatientInfo : TPatientInfo;
     FCurAliasEdit : integer;
+    CurrentAnyFileData : TStringList;
     ProgAliasChangeOccuring : boolean;
+    CurrentPatientData : TStringList;
     ProgNameChangeOccuring : boolean;
     ProgPhoneChangeOccuring : boolean;
+    FLastSelectedRow,FLastSelectedCol : integer;
     ProgAddressChangeOccuring : boolean;
+    DataForGrid : TStringList;
     MaxAliasIEN : integer;
+    Data : TStringList;
     ChangesMade : boolean;
+    BasicTemplate : TStringList;
+    FLoadingGrid: boolean;
+    CachedWPField : TStringList;
     procedure GetPtInfo(PatientInfo : TPatientInfo);
     procedure PostChangedInfo(PatientInfo : TPatientInfo);
     procedure ShowAliasInfo(Patient : TPatientInfo);
+    procedure GetPatientInfo(GridInfo: TGridInfo);
     procedure ShowPtInfo(Patient : TPatientInfo);
     function CombinedName : string;
+    procedure AddGridInfo(Grid: TStringGrid;
+                                  Data : TStringList;
+                                  BasicMode : boolean;
+                                  DataLoader : TGridDataLoader;
+                                  FileNum : string);
     procedure NameParts(CombinedName: string; var LName, FName, MName : string);
+    function ExtractNum (S : String; StartPos : integer) : string;
     procedure SetModified(value : boolean);
     procedure SetAliasEnabled(value : boolean);
+    function PostChanges(Grid : TStringGrid) : TModalResult;
+    procedure CompileChanges(Grid : TStringGrid; CurrentUserData,Changes : TStringList);
+    procedure RegisterGridInfo(GridInfo : TGridInfo);
   public
     { Public declarations }
+    function GetInfoForGrid(Grid : TStringGrid) : TGridInfo;
+    procedure LoadAnyGrid(Grid : TStringGrid; BasicMode: boolean; FileNum : string;
+                                  IENS : string;
+                                  CurrentData : TStringList);
+    procedure LoadAnyGridFromInfo(GridInfo : TGridInfo);
+    function IsWPField(FileNum,FieldNum : string) : boolean;
+    function IsSubFile(FieldDef: string ; var SubFileNum : string) : boolean;
+    function GetInfoIndexForGrid(Grid : TStringGrid) : integer;
+    function PostVisibleGrid: TModalResult;
+    function GetLineInfo(Grid : TStringGrid; CurrentUserData : TStringList; ARow: integer) : tFileEntry;
+    procedure GetOneRecord(FileNum, IENS : string; Data, BlankFileInfo: TStringList);
+    //procedure GridSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean);
+    function GetUserLine(CurrentUserData : TStringList; Grid : TStringGrid; ARow: integer) : integer;
+    function FindInStrings(fieldNum : string; Strings : TStringList; var fileNum : string) : integer;
   end;
 
@@ -188,4 +252,11 @@
   frmPtDemoEdit: TfrmPtDemoEdit;
 
+Const
+  DEF_GRID_ROW_HEIGHT = 17;  
+  CLICK_FOR_SUBS = '<CLICK for Sub-Entries>';
+  COMPUTED_FIELD = '<Computed Field --> CAN''T EDIT>';
+  CLICK_TO_EDIT = '<CLICK to Edit Text>';
+  HIDDEN_FIELD = '<Hidden>';
+
 implementation
 
@@ -193,5 +264,6 @@
 
 uses
-  IniFiles,Trpcb,ORNet,uCore, mfunstr, strutils;
+  IniFiles,Trpcb,ORNet,uCore, mfunstr, subfilesU, strutils, LookupU, SetSelU,
+  SelDateTimeU, PostU, EditTextU, FMErrorU;
 
 const
@@ -218,4 +290,5 @@
 begin
   AliasInfo := TStringList.Create;
+  
   Clear;
 end;
@@ -250,4 +323,5 @@
   DOB:= '';
   SSNum:= '';
+  EMail:= '';
   ClearAliasInfo;  
   AddressLine1:= '';
@@ -300,4 +374,5 @@
   DOB:=Source.DOB;
   SSNum:=Source.SSNum;
+  EMail:=Source.EMail;
   
   ClearAliasInfo;
@@ -424,4 +499,5 @@
   CompStrs(DOB, OldInfo.DOB);
   CompStrs(SSNum, OldInfo.SSNum);
+  CompStrs(EMail, OldInfo.EMail);
   
   CompStrs(AddressLine1, OldInfo.AddressLine1);
@@ -554,4 +630,5 @@
     Sex:= tempINI.ReadString('DATA','SEX','');
     SSNum:= tempINI.ReadString('DATA','SS_NUM','');
+    EMail:= tempINI.ReadString('DATA','EMAIL','');
     AddressLine1:= tempINI.ReadString('DATA','ADDRESS_LINE_1','');
     AddressLine2:= tempINI.ReadString('DATA','ADDRESS_LINE_2','');
@@ -621,4 +698,5 @@
     CheckPost('SEX',Sex);
     CheckPost('SS_NUM',SSNum);
+    CheckPost('EMAIL',EMail);
     CheckPost('ADDRESS_LINE_1',AddressLine1);
     CheckPost('ADDRESS_LINE_2',AddressLine2);
@@ -690,4 +768,5 @@
     DOBEdit.Text := DOB;
     SSNumEdit.Text := SSNum;
+    EMailEdit.Text := EMail;
     if Sex='MALE' then SexComboBox.ItemIndex := 0 else SexComboBox.ItemIndex := 1;
     AliasComboBox.Items.Clear;
@@ -748,5 +827,5 @@
     end;  
     ShowAliasInfo(FCurPatientInfo);
-  end;  
+  end;
 end;
 
@@ -756,4 +835,5 @@
   FCurPatientInfo := TPatientInfo.Create;
   FServerPatientInfo := TPatientInfo.Create;
+  DataForGrid := TStringList.Create;  //will own GridInfo objects.
   ProgAliasChangeOccuring  := false;
   ProgNameChangeOccuring := false;
@@ -762,10 +842,15 @@
   MaxAliasIEN := 0;
   ChangesMade := false;
+  CurrentPatientData := TStringList.Create;
+  AddGridInfo(GridPatientDemo,CurrentPatientData,false,GetPatientInfo,'2');
+
 end;
 
 procedure TfrmPtDemoEdit.FormDestroy(Sender: TObject);
 begin
+  DataForGrid.Free;
   FCurPatientInfo.Destroy;
   FServerPatientInfo.Destroy;
+  CurrentPatientData.Free;
 end;
 
@@ -887,7 +972,8 @@
 procedure TfrmPtDemoEdit.FormShow(Sender: TObject);
 begin
+  PageControl.ActivePageIndex := 0;
   GetPtInfo(FServerPatientInfo);
   FCurPatientInfo.Assign(FServerPatientInfo);
-  ShowPtInfo(FCurPatientInfo);  
+  ShowPtInfo(FCurPatientInfo);
 end;
 
@@ -1178,4 +1264,5 @@
 var TempPatientInfo : tPatientInfo;
 begin
+if pagecontrol.ActivePageIndex = 0 then begin
   TempPatientInfo := tPatientInfo.Create;
   TempPatientInfo.Assign(FCurPatientInfo);
@@ -1184,5 +1271,90 @@
   TempPatientInfo.Destroy;
   SetModified(false);
-end;
+end else begin
+  PostVisibleGrid;
+  SetModified(false);
+end;
+end;
+function TfrmPtDemoEdit.PostVisibleGrid: TModalResult;
+  begin
+    result := PostChanges(gridPatientDemo);
+  end;
+
+function TfrmPtDemoEdit.PostChanges(Grid : TStringGrid) : TModalResult;
+  //Results:  mrNone -- no post done (not needed)
+  //          mrCancel -- user pressed cancel on confirmation screen.
+  //          mrNo -- signals posting error.
+  var Changes : TStringList;
+      PostResult : TModalResult;
+      CurrentData : TStringList;
+      GridInfo : TGridInfo;
+      IENS : string;  
+  begin
+    Result := mrNone;  //default to No changes
+    GridInfo := GetInfoForGrid(Grid);
+    if GridInfo=nil then exit;
+    CurrentData := GridInfo.Data;
+    if CurrentData=nil then exit;
+    if CurrentData.Count = 0 then exit;
+    IENS := Patient.DFN;
+    if IENS='' then exit;
+    Changes := TStringList.Create;
+    CompileChanges(Grid,CurrentData,Changes);
+    if Changes.Count>0 then begin
+      PostForm.PrepForm(Changes);
+      PostResult := PostForm.ShowModal;
+      if PostResult = mrOK then begin
+        //if DisuserChanged(Changes) then begin  //looks for change in file 200, field 4
+        //  InitializeUsersTreeView;
+        //end else begin
+          if Pos('+',IENS)>0 then begin
+            GridInfo.IENS := PostForm.GetNewIENS(IENS);
+          end;
+          if assigned(GridInfo.DataLoadProc) then begin
+            GridInfo.DataLoadProc(GridInfo);
+          end;
+          {
+          if CurrentData = CurrentUserData then begin
+            LoadUserData(IENS,CurrentData);  //reload record from server.
+          end else if CurrentData = CurrentSettingsData then begin
+            GetSettingsInfo(GridInfo.FileNum, GridInfo.IENS, CurrentData);
+          end else if CurrentData = CurrentPatientData then begin
+            GetPatientInfo(GridInfo.IENS, CurrentData);            
+          end else if CurrentData = CurrentAnyFileData then begin
+            GetAnyFileInfo(GridInfo.FileNum, GridInfo.IENS, CurrentData);
+          end;  
+          }
+        //end;  
+      end else if PostResult = mrNo then begin  //mrNo is signal of post Error
+        // show error...
+      end;
+      Result := PostResult;
+    end else begin
+      Result := mrNone;  
+    end;
+    Changes.Free;
+  end;
+
+  procedure TfrmPtDemoEdit.CompileChanges(Grid : TStringGrid; CurrentUserData,Changes : TStringList);
+  //Output format:
+  // FileNum^IENS^FieldNum^FieldName^newValue^oldValue
+
+  var row : integer;
+      Entry : tFileEntry;
+      oneEntry : string;
+  begin
+    for row := 1 to Grid.RowCount-1 do begin
+      Entry := GetLineInfo(Grid,CurrentUserData, row);
+      if Entry.oldValue <> Entry.newValue then begin
+        if (Entry.newValue <> CLICK_FOR_SUBS) and
+          (Entry.newValue <> COMPUTED_FIELD) and
+          (Entry.newValue <> CLICK_TO_EDIT) then begin   
+          oneEntry := Entry.FileNum + '^' + Entry.IENS + '^' + Entry.Field + '^' + Entry.FieldName;
+          oneEntry := oneEntry + '^' + Entry.newValue + '^' + Entry.oldValue;
+          Changes.Add(oneEntry);
+        end;  
+      end;
+    end;
+  end;
 
 procedure TfrmPtDemoEdit.SetModified(value : boolean);
@@ -1219,6 +1391,6 @@
     case MessageDlg('Apply Changes?',mtConfirmation,mbYesNoCancel,0) of
       mrYes : begin
-                ApplyBtnClick(Sender);    
-                frmPtDemoEdit.ModalResult := mrOK;  //closes form                                        
+                ApplyBtnClick(Sender);
+                frmPtDemoEdit.ModalResult := mrOK;  //closes form
               end;
       mrNo : begin
@@ -1249,4 +1421,518 @@
 
 
-
+procedure TfrmPtDemoEdit.PageControlChange(Sender: TObject);
+var
+   GridInfo : TGridInfo;
+   IEN : longInt;
+   ModalResult : TModalResult;
+
+begin
+    if pagecontrol.ActivePageIndex = 0 then begin
+       GetPtInfo(FServerPatientInfo);
+       FCurPatientInfo.Assign(FServerPatientInfo);
+       ShowPtInfo(FCurPatientInfo);
+    end else begin
+       IEN := strtoint(patient.dfn);  //get info from selected patient
+       if IEN = 0 then exit;
+       GridInfo := GetInfoForGrid(gridPatientDemo);
+       if GridInfo = nil then exit;
+       GridInfo.IENS := IntToStr(IEN)+',';
+       GetPatientInfo(GridInfo);
+    end;
+
+end;
+
+procedure TfrmPtDemoEdit.GetPatientInfo(GridInfo: TGridInfo);
+
+var cmd,RPCResult : string;
+    IENS : String;
+    grid : TStringGrid;
+begin
+//    IENS := Patient.DFN;
+    IENS := GridInfo.IENS;
+//    Data := GridInfo.Data;
+    grid := GridInfo.Grid;
+    grid.Cells[0,1] := '';
+    grid.Cells[1,1] := '';
+    grid.Cells[2,1] := '';
+    grid.RowCount :=2;
+    grid.Cursor := crHourGlass;
+    if IENS <> '0,' then begin
+      RPCBrokerV.remoteprocedure := 'TMG CHANNEL';
+      RPCBrokerV.param[0].ptype := list;
+      cmd := 'GET ONE RECORD^2^' + IENS;
+      RPCBrokerV.Param[0].Mult['"REQUEST"'] := cmd;
+      RPCBrokerV.Call;
+      RPCResult := RPCBrokerV.Results[0];    //returns:  error: -1;  success=1
+      //Results[1]='FileNum^IENS^FieldNum^ExtValue^FieldName^DDInfo...
+      //Results[2]='FileNum^IENS^FieldNum^ExtValue^FieldName^DDInfo...
+      if piece(RPCResult,'^',1)='-1' then begin
+        messagedlg(RPCBrokerV.Results[1],mtError,mbOKCancel,0);
+        //FMErrorForm.Memo.Lines.Assign(RPCBrokerV.Results);
+      end else begin
+        GridInfo.Data.Assign(RPCBrokerV.results);
+        //LoadAnyGrid(grid,false,'2',IENS,Data);
+        LoadAnyGridFromInfo(GridInfo);
+      end;
+    end;
+  gridPatientDemo.Cursor := crDefault;
+end;
+
+procedure TfrmPtDemoEdit.LoadAnyGrid(Grid : TStringGrid;  //the TStringGrid to load
+                                     BasicMode: boolean;
+                                     FileNum : string;
+                                     IENS : string;
+                                     CurrentData : TStringList);
+  var
+    GridInfo : TGridInfo;
+  begin
+    GridInfo := TGridInfo.Create;
+    //This stores load information into a GridInfo
+    GridInfo.Grid := Grid;
+    GridInfo.BasicMode := BasicMode;
+    GridInfo.FileNum := FileNum;
+    GridInfo.IENS := IENS;
+    GridInfo.Data := CurrentData;
+    LoadAnyGridFromInfo(GridInfo);
+    GridInfo.Free;
+  end;
+
+procedure TfrmPtDemoEdit.LoadAnyGridFromInfo(GridInfo : TGridInfo);
+  //This assumes that GridInfo already has loaded info.
+  var
+    Grid : TStringGrid;  //the TStringGrid to load
+    BasicMode: boolean;
+    FileNum : string;
+    IENS : string;
+    CurrentData : TStringList;
+
+    procedure LoadOneLine (Grid : TStringGrid; oneEntry : string; GridRow : integer);
+    var
+      tempFile,IENS : string;
+      fieldNum,fieldName,fieldDef : string;
+      subFileNum : string;
+      value : string;
+    begin
+      tempFile := Piece(oneEntry,'^',1);
+      if tempFile = FileNum then begin //handle subfiles later...
+        IENS := Piece(oneEntry,'^',2);
+        fieldNum := Piece(oneEntry,'^',3);
+        value := Piece(oneEntry,'^',4);
+        fieldName := Piece(oneEntry,'^',5);
+        fieldDef := Piece(oneEntry,'^',6);
+        Grid.RowCount := GridRow + 1;
+        Grid.Cells[0,GridRow] := fieldNum;
+        Grid.Cells[1,GridRow] := fieldName;
+        if Pos('W',fieldDef)>0 then begin
+          Grid.Cells[2,GridRow] := CLICK_TO_EDIT;
+        end else if IsSubFile(fieldDef, subFileNum) then begin
+          if IsWPField(FileNum,fieldNum) then begin
+            Grid.Cells[2,GridRow] := CLICK_TO_EDIT;
+          end else begin
+            Grid.Cells[2,GridRow] := CLICK_FOR_SUBS;
+          end;
+        end else if Pos('C',fieldDef)>0 then begin
+          Grid.Cells[2,GridRow] := COMPUTED_FIELD;
+        end else begin
+          Grid.Cells[2,GridRow] := value;
+        end;
+        Grid.RowHeights[GridRow] := DEF_GRID_ROW_HEIGHT;
+      end;
+    end;
+
+    function getOneLine(CurrentData : TStringList; oneFileNum,oneFieldNum : string) : string;
+    var i : integer;
+        FileNum,FieldNum : string;
+    begin
+      result := '';
+      // FileNum^IENS^FieldNum^FieldName^newValue^oldValue
+      for i := 1 to CurrentData.Count - 1 do begin
+        FileNum := piece(CurrentData.Strings[i],'^',1);
+        if FileNum <> oneFileNum then continue;
+        FieldNum := piece(CurrentData.Strings[i],'^',3);
+        if FieldNum <> oneFieldNum then continue;
+        result := CurrentData.Strings[i];
+        break;
+      end;
+    end;
+
+  var i : integer;
+      oneEntry  : string;
+      oneFileNum,oneFieldNum : string;
+      gridRow : integer;
+
+  begin
+    FLoadingGrid := true;
+    if GridInfo=nil then exit;
+    Grid := GridInfo.Grid;
+    BasicMode := GridInfo.BasicMode;
+    FileNum := GridInfo.FileNum;
+    IENS := GridInfo.IENS;
+    CurrentData := GridInfo.Data;
+
+    Grid.Cells[0,1] := '';
+    Grid.Cells[1,1] := '';
+    Grid.Cells[2,1] := '';
+    Grid.RowCount :=2;
+    Grid.ColWidths[0] := 50;
+    Grid.ColWidths[1] := 200;
+    Grid.ColWidths[2] := 300;
+    Grid.Cells[0,0] := '#';
+    Grid.Cells[1,0] := 'Name';
+    Grid.Cells[2,0] := 'Value';
+
+    if BasicMode=false then begin
+      for i := 1 to CurrentData.Count-1 do begin  //start at 1 because [0] = 1^Success
+        oneEntry := CurrentData.Strings[i];
+        LoadOneLine (Grid,oneEntry,i);
+      end;
+    end else if BasicMode=true then begin
+      gridRow := 1;
+      for i := 0 to BasicTemplate.Count-1 do begin
+        oneFileNum := Piece(BasicTemplate.Strings[i],'^',1);
+        if oneFileNum <> fileNum then continue;
+        oneFieldNum := Piece(BasicTemplate.Strings[i],'^',2);
+        oneEntry := getOneLine(CurrentData,oneFileNum,oneFieldNum);
+        LoadOneLine (Grid,oneEntry,gridRow);
+        Inc(GridRow);
+      end;
+    end;
+    FLoadingGrid := false;
+  end;
+
+  function TfrmPtDemoEdit.GetInfoForGrid(Grid : TStringGrid) : TGridInfo;
+  var i : integer;
+  begin
+    i := GetInfoIndexForGrid(Grid);
+    if i > -1 then begin
+      result := TGridInfo(DataForGrid.Objects[i]);
+    end else begin
+      result := nil;
+    end;
+  end;
+
+
+  function TfrmPtDemoEdit.GetInfoIndexForGrid(Grid : TStringGrid) : integer;
+  var s : string;
+  begin
+    s := IntToStr(integer(Grid));
+    result := Dataforgrid.indexof(s);
+  end;
+
+function TfrmPtDemoEdit.IsSubFile(FieldDef: string ; var SubFileNum : string) : boolean;
+  //SubFileNum is OUT parameter
+  begin
+    SubFileNum := ExtractNum(FieldDef,1);
+    result := (SubFileNum <> '');
+  end;
+    
+  function TfrmPtDemoEdit.IsWPField(FileNum,FieldNum : string) : boolean;
+  var RPCResult : string;
+      SrchStr : string;
+      Idx: integer;
+  begin
+    SrchStr := FileNum + '^' +  FieldNum + '^';
+    //Idx := CachedWPField.IndexOf(SrchStr + 'YES');
+    //if Idx > -1 then begin Result := true; exit; end;
+    //Idx := CachedWPField.IndexOf(SrchStr + 'NO');
+    //if Idx > -1 then begin Result := false; exit; end;
+  
+    result := false;
+    RPCBrokerV.remoteprocedure := 'TMG CHANNEL';
+    RPCBrokerV.param[0].ptype := list;
+    RPCBrokerV.Param[0].Mult['"REQUEST"'] := 'IS WP FIELD^' + FileNum + '^' + FieldNum;
+    RPCBrokerV.Call;
+    RPCResult := RPCBrokerV.Results[0];    //returns:  error: -1;  success=1
+    if piece(RPCResult,'^',1)='-1' then begin
+      //FMErrorForm.Memo.Lines.Assign(RPCBrokerV.Results);
+      //FMErrorForm.PrepMessage;
+      //FMErrorForm.ShowModal;
+    end else begin
+      RPCResult := piece(RPCResult,'^',3);
+      result := (RPCResult = 'YES');
+      //CachedWPField.Add(SrchStr + RPCResult);
+    end;    
+  end;
+
+  function TfrmPtDemoEdit.ExtractNum (S : String; StartPos : integer) : string;
+  var i : integer;
+      ch : char;
+  begin
+    result := '';
+    if (S = '') or (StartPos < 0) then exit;
+    i := StartPos;
+    repeat
+      ch := S[i]; 
+      i := i + 1;
+      if ch in ['0'..'9','.'] then begin
+        Result := Result + ch;
+      end;  
+    until (i > length(S)) or not  (ch in ['0'..'9','.'])
+  end;
+
+  procedure TfrmPtDemoEdit.gridPatientDemoSelectCell(Sender: TObject; ACol,
+  ARow: Integer; var CanSelect: Boolean);
+    (*
+    For Field def, here is the legend
+    character     meaning
+
+    BC 	          The data is Boolean Computed (true or false).
+    C 	          The data is Computed.
+    Cm 	          The data is multiline Computed.
+    DC 	          The data is Date-valued, Computed.
+    D 	          The data is Date-valued.
+    F 	          The data is Free text.
+    I 	          The data is uneditable.
+    Pn 	          The data is a Pointer reference to file "n".
+    S 	          The data is from a discrete Set of codes.
+    
+    N 	          The data is Numeric-valued.
+    
+    Jn 	          To specify a print length of n characters.
+    Jn,d 	        To specify printing n characters with decimals.
+
+    V 	          The data is a Variable pointer.
+    W 	          The data is Word processing.
+    WL 	          The Word processing data is normally printed in Line mode (i.e., without word wrap).
+      *)
+  var oneEntry,FieldDef : string;                                     
+      date,time: string;
+      FileNum,FieldNum,SubFileNum : string;
+      GridFileNum : string;
+      UserLine : integer;
+      Grid : TStringGrid;
+      IEN : int64;
+      IENS : string;
+      CurrentData : TStringList;
+      GridInfo : TGridInfo;
+      SubFileForm : TSubFileForm;
+  begin
+    if FLoadingGrid then exit;  //prevent pseudo-clicks during loading...
+    Grid := (Sender as TStringGrid);
+    GridInfo := GetInfoForGrid(Grid);
+    if GridInfo=nil then exit;
+    GridFileNum := GridInfo.FileNum;
+    CanSelect := false;  //default to NOT selectable.
+    CurrentData := GridInfo.Data;
+    if CurrentData=nil then exit;
+    if CurrentData.Count = 0 then exit;
+    UserLine := GetUserLine(CurrentData,Grid,ARow);
+    if UserLine = -1 then exit;
+    oneEntry := CurrentData.Strings[UserLine];
+    FieldDef := Piece(oneEntry,'^',6);
+    if Pos('F',FieldDef)>0 then begin  //Free text
+      CanSelect := true;
+    end else if IsSubFile(FieldDef,SubFileNum) then begin  //Subfiles.
+      FileNum :=  Piece(oneEntry,'^',1);
+      FieldNum :=  Piece(oneEntry,'^',3);
+      if IsWPField(FileNum,FieldNum) then begin
+        IENS :=  Piece(oneEntry,'^',2);
+        EditTextForm.PrepForm(FileNum,FieldNum,IENS);
+        EditTextForm.ShowModal;
+      end else begin
+        //handle subfiles here
+        IENS := '';
+        if GridInfo.Message = MSG_SUB_FILE then begin  //used message from subfile Grid
+          IENS := GridInfo.IENS;
+        end; // else if LastSelTreeNode <> nil then begin  //this is one of the selction trees.
+          IEN := strtoint(Patient.DFN); //longInt(LastSelTreeNode.Data);
+          if IEN > 0 then IENS := InttoStr(IEN) + ',';
+        if GridInfo.Data = CurrentAnyFileData then begin
+          IEN := strtoint(patient.dfn);  //get info from selected record
+          if IEN > 0 then IENS := InttoStr(IEN) + ',';
+        end;
+        if IENS <> '' then begin
+          SubFileForm := TSubFileForm.Create(self);
+          SubFileForm.PrepForm(SubFileNum,IENS);
+          SubfileForm.ShowModal;  // note: may call this function again recursively for sub-sub-files etc.
+          SubFileForm.Free;
+        end else begin
+          MessageDlg('IENS for File="".  Can''t process.',mtInformation,[MBOK],0);
+        end;
+      end;
+    end else if Pos('C',FieldDef)>0 then begin  //computed fields.
+      CanSelect := false;
+    end else if Pos('D',FieldDef)>0 then begin  //date field
+      date := piece(Grid.Cells[ACol,ARow],'@',1);
+      time := piece(Grid.Cells[ACol,ARow],'@',2);
+      if date <> '' then begin
+        SelDateTimeForm.DateTimePicker.Date := StrToDate(date);
+      end else begin
+        SelDateTimeForm.DateTimePicker.Date := SysUtils.Date;
+      end;
+      if SelDateTimeForm.ShowModal = mrOK then begin
+        date := DateToStr(SelDateTimeForm.DateTimePicker.Date);
+        time := TimeToStr(SelDateTimeForm.DateTimePicker.Time);
+        if time <> '' then date := date; // + '@' + time;    elh 8/15/08
+        Grid.Cells[ACol,ARow] := date;
+      end;
+      CanSelect := true;
+    end else if Pos('S',FieldDef)>0 then begin  //Set of Codes
+      SetSelForm.PrepForm(Piece(oneEntry,'^',7));
+      if SetSelForm.ShowModal = mrOK then begin
+        Grid.Cells[ACol,ARow] := SetSelForm.ComboBox.Text;
+        CanSelect := true;
+      end;
+    end else if Pos('I',FieldDef)>0 then begin  //uneditable
+      ShowMessage('Sorry. Flagged as UNEDITABLE.');
+    end else if Pos('P',FieldDef)>0 then begin  //Pointer to file.
+      FileNum := ExtractNum (FieldDef,Pos('P',FieldDef)+1);
+      //check for validity here...
+      FieldLookupForm.PrepForm(FileNum,Grid.Cells[ACol,ARow]);
+      if FieldLookupForm.ShowModal = mrOK then begin
+        Grid.Cells[ACol,ARow] := FieldLookupForm.ORComboBox.Text;
+        CanSelect := true;
+      end;
+    end;
+    if CanSelect then begin
+      FLastSelectedRow := ARow;
+      FLastSelectedCol := ACol;
+      SetModified(True);
+    end;
+    //GridInfo.ApplyBtn.Enabled := true;
+    //GridInfo.RevertBtn.Enabled := true;
+  end;
+
+  function TfrmPtDemoEdit.GetLineInfo(Grid : TStringGrid; CurrentUserData : TStringList; ARow: integer) : tFileEntry;
+  var fieldNum : string;
+      oneEntry : string;
+      fileNum : string;
+      gridRow : integer;
+  begin
+    fieldNum := Grid.Cells[0,ARow];
+    gridRow := FindInStrings(fieldNum, CurrentUserData, fileNum);
+    if gridRow > -1 then begin
+      oneEntry := CurrentUserData.Strings[gridRow];
+      Result.Field := fieldNum;
+      Result.FieldName := Grid.Cells[1,ARow];
+      Result.FileNum := fileNum;
+      Result.IENS := Piece(oneEntry,'^',2);
+      Result.oldValue := Piece(oneEntry,'^',4);
+      Result.newValue := Grid.Cells[2,ARow];
+    end else begin
+      Result.Field := '';
+      Result.FieldName := '';
+      Result.FileNum := '';
+      Result.IENS := '';
+      Result.oldValue := '';
+      Result.newValue := '';
+    end;
+  end;
+
+procedure TfrmPtDemoEdit.GetOneRecord(FileNum, IENS : string; Data, BlankFileInfo: TStringList);
+  var cmd,RPCResult : string;
+      i : integer;
+      oneEntry : string;
+  begin
+    Data.Clear;
+    if (IENS='') then exit;
+    if Pos('+',IENS)=0 then begin //don't ask server to load +1 records.
+      RPCBrokerV.remoteprocedure := 'TMG CHANNEL';
+      RPCBrokerV.Param[0].Value := '.X';  // not used
+      RPCBrokerV.param[0].ptype := list;
+      cmd := 'GET ONE RECORD^' + FileNum + '^' + IENS;
+      RPCBrokerV.Param[0].Mult['"REQUEST"'] := cmd;
+      RPCBrokerV.Call;
+      RPCResult := RPCBrokerV.Results[0];    //returns:  error: -1;  success=1
+      if piece(RPCResult,'^',1)='-1' then begin
+      FMErrorForm.Memo.Lines.Assign(RPCBrokerV.Results);
+      FMErrorForm.PrepMessage;
+      FMErrorForm.ShowModal;
+      end else begin
+        Data.Assign(RPCBrokerV.Results);
+      end;
+    end else begin
+      Data.Add('1^Success');  //to keep same as call to server
+      if BlankFileInfo.Count = 0 then begin
+        //Format is: FileNum^^FieldNum^^DDInfo...
+        //  elh GetBlankFileInfo(FileNum,BlankFileInfo);
+      end;  
+      for i := 1 to BlankFileInfo.Count-1 do begin  //0 is 1^success
+        oneEntry := BlankFileInfo.Strings[i];
+        //  elh SetPiece(oneEntry,'^',2,IENS);
+        Data.Add(oneEntry);
+      end;
+    end;
+  end;
+
+function TfrmPtDemoEdit.GetUserLine(CurrentUserData : TStringList; Grid : TStringGrid; ARow: integer) : integer;
+  var fieldNum: string;
+      tempFileNum : string;
+  begin
+    fieldNum := Grid.Cells[0,ARow];
+    Result := FindInStrings(fieldNum,CurrentUserData,tempFileNum);
+  end;
+
+  function TfrmPtDemoEdit.FindInStrings(fieldNum : string; Strings : TStringList; var fileNum : string) : integer;
+  //Note: if fileNum is passed blank, then first matching file will be placed in it (i.e. OUT parameter)
+  var tempFieldNum : string;
+      oneEntry,tempFile : string;
+      i : integer;
+  begin
+    result := -1;
+    fileNum := '';
+    for i := 1 to Strings.Count-1 do begin   //0 --> 1^success
+      oneEntry := Strings.Strings[i];
+      tempFile := Piece(oneEntry,'^',1);
+      if fileNum='' then fileNum := tempFile;
+      if tempFile <> fileNum then continue; //ignore subfiles
+      tempFieldNum := Piece(oneEntry,'^',3);
+      if tempFieldNum <> fieldNum then continue;
+      Result := i;
+      break;
+    end;
+  end;
+
+ procedure TfrmPtDemoEdit.AddGridInfo(Grid: TStringGrid;
+                                  Data : TStringList;
+                                  BasicMode : boolean;
+                                  DataLoader : TGridDataLoader;
+                                  FileNum : string);
+  var tempGridInfo : TGridInfo;
+  begin
+    tempGridInfo := TGridInfo.Create;
+    tempGridInfo.Grid := Grid;
+    tempGridInfo.Data := Data;
+    tempGridInfo.BasicMode := BasicMode;
+    tempGridInfo.FileNum := FileNum;
+    tempGridInfo.DataLoadProc := DataLoader;
+    //tempGridInfo.ApplyBtn := ApplyBtn;
+    //tempGridInfo.RevertBtn := RevertBtn;
+    RegisterGridInfo(tempGridInfo);
+  end;
+
+procedure TfrmPtDemoEdit.RegisterGridInfo(GridInfo : TGridInfo);
+  var s : string;
+  begin
+    if GridInfo = nil then exit;
+    s := IntToStr(integer(GridInfo.Grid));
+    DataForGrid.AddObject(s,GridInfo);
+  end;
+
+procedure TfrmPtDemoEdit.gridPatientDemoSetEditText(Sender: TObject; ACol,
+                                            ARow: Integer; const Value: String);
+begin
+  SetModified(True);
+end;
+
+procedure TfrmPtDemoEdit.PageControlChanging(Sender: TObject;
+  var AllowChange: Boolean);
+var
+   intAnswer : Integer;
+begin
+//Before changing the form, find out if changes need to be applied and
+//prompt user.            elh
+    if ApplyBtn.enabled = True then begin
+       intAnswer := messagedlg('Do you want to apply your changes?', mtWarning,mbYesNoCancel,0);
+       if intAnswer = mrYes then begin  //Yes
+          ApplyBtnClick(Sender);
+          //messagedlg('Changes Saved.', mtWarning,[mbOK],0);
+          SetModified(False);
+        end else if intAnswer = mrNo then begin    //No
+          SetModified(False);
+        end else if intAnswer = mrCancel then begin    //Cancel
+          AllowChange := False;
+        end;
+    end;
+end;
 end.
