//Advanced Delphi Systems Code: ads_SelfDocument
{{Copyright(c)2016 Advanced Delphi Systems

 Richard Maley
  Advanced Delphi Systems
  12613 Maidens Bower Drive
  Potomac, MD 20854 USA
  phone 301-840-1554
  dickmaley@advdelphisys.com

  The code herein can be used or modified by anyone.  Please retain references
  to Richard Maley at Advanced Delphi Systems.  If you make improvements to the
  code please send your improvements to dickmaley@advdelphisys.com so that the
  entire Delphi community can benefit.  All comments are welcome.
}
unit ads_SelfDocument;

(*
UnitIndex Master Index Implementation Section Download Units
Description: ads_SelfDocument.pas
This unit contains the following routines.

CorrectAllPriorAndNext  CorrectPriorAndNext   GlobalGetHelp   GlobalInitForHelp   GlobalInitForHistory   MakeHelpIndex   MakeHistoryIndex   MakeIndexDetail   RecordHelpScreen   RecordScreenHistory   ScreenShot   ScreenShotDetail   SelfDocFinal   SelfDocInit   THelpForm.FormChanged   THelpForm.FormKeyDown   THelpForm.TimerTimer  

*)
interface
{Copyright(c)2016 Advanced Delphi Systems

 Richard Maley
 Advanced Delphi Systems
 12613 Maidens Bower Drive
 Potomac, MD 20854 USA
 phone 301-840-1554
 dickmaley@advdelphisys.com

 The code herein can be used or modified by anyone.  Please retain references
 to Richard Maley at Advanced Delphi Systems.  If you make improvements to the
 code please send your improvements to dickmaley@advdelphisys.com so that the
 entire Delphi community can benefit.  All comments are welcome.
}
{

Description: Add this unit to an application to create a starting point for
application help or to log user actions.  The unit defaults to doing nothing
and when so configured has zero impact on performance.

The application needs to be run after this unit is added.  This produces a
directory under
C:\Documents and Settings\rmaley\Local Settings\Application Data.
The new directory name is the same as the executable name with no file
extension.  In this new directory is an ini file ending in *.SelfDocumenting.ini.
This file needs to be modified to turn on help generation or screen logging.

example ini file:
Active=TRUE
ShouldOverWriteHelpScreen=FALSE
ShouldRecordHelpScreen=TRUE
ShouldRecordScreenHistory=TRUE
GlobalHistoryMax=50

Meaning:
Active: Do not modify this.  The application does not read this.  The
  application only writes this to inform you that either
  ShouldRecordHelpScreen or ShouldRecordScreenHistory was true and
  consequently Active was set to true.  This means that SelfDocumenting
  was activated with this application.
ShouldOverWriteHelpScreen: If a help file already exists with the same
  name, it will be overwritten if this value is set to TRUE.
ShouldRecordHelpScreen: If TRUE Help screen generation is enabled.  TRUE
  is case sensitive. Results are written to a directory named Help
  in C:\Documents and Settings\rmaley\Local Settings\Application Data\
ShouldRecordScreenHistory: If TRUE screen logging is enabled.  TRUE
  is case sensitive.  Results are written to a directory named History
  in C:\Documents and Settings\rmaley\Local Settings\Application Data\
GlobalHistoryMax: Sets the maximum limit of screen history files maintained.
  default is 50.

Includes:
Previously prepared text for each help screen can be integrated into the
final html page by putting include files in the ..\Help\Include directory.
The include file should be same name as the page in the ..\Help directory
except that the file extension is .txt rather than .html.

A special include feature exists if you are using ads_DlgLU Lookup dialogs.
Includes can be automatically generated by adding an application level
compiler define called LOOKUPINCLUDE.  To do this in the Delphi IDE go to
Project->Options->Directories/Conditionals->Conditionals and add LOOKUPINCLUDE
to the Conditionals edit box.

Generating Help:
-Modify ini by setting ShouldRecordHelpScreen=TRUE
-Run application.
-Bring up every screen including dialogs.  For every screen viewed there will
 be a help file in the help directory mentioned above.
-Include files can be written and put in the include directory.
-Go through the application again viewing all screens and dialogs.  All
 include files are now integrated with the help pages.
-Iterate through this process as many times as need to get help looking the
 way you want it.
-Once done modify ini by setting ShouldRecordHelpScreen=FALSE

Screen Logging:
-Modify ini
-set ShouldRecordScreenHistory=TRUE
-set GlobalHistoryMax=50 or whatever number of user actions you want to
 capture.  If GlobalHistoryMax=50 then the user's last 50 screens will
 be logged at all times.  This can be very valuable in resolving user
 problems.
}


implementation

Uses
  ads_Exception,
  ads_File,
  ads_Strg,
  Classes,
  Controls,
  ExtCtrls,
  Forms,
  Graphics,
  Jpeg,
  SysUtils
  ;
Type
  THelpForm = class(TScrollingWinControl)
  public
    procedure FormChanged(Sender: TObject);
    procedure FormKeyDown(Sender: TObject;var Key: Word;Shift: TShiftState);
    procedure TimerTimer(Sender: TObject);
  End;

Var
  Active                     : Boolean=False;
  DataIni                    : TStringlist;
  DirLocalApp                : String='';
  DirLocalThisApp            : String='';
  ExeName                    : String='';
  ExePath                    : String='';
  FileFormList               : String='';
  FileIni                    : String='';
  FormList                   : TStringlist;
  GlobalCaptionAp            : String='';
  GlobalHelpDir              : String='';
  GlobalHistoryDir           : String='';
  GlobalHistoryMax           : Integer=50;
  GlobalImageDir             : String='';
  GlobalIncludeDir           : String='';
  HelpForm                   : THelpForm;
  lst                        : TStringlist;
  ShouldOverWriteHelpScreen  : Boolean = False;
  ShouldRecordHelpScreen     : Boolean = False;
  ShouldRecordScreenHistory  : Boolean = False;
  Timer                      : TTimer;
  UnitName                   : String = 'ads_SelfDocument';

//
Unit Description UnitIndex Master Index
procedure GlobalGetHelp(Title : String);
Var
  DefaultDir  : String;
  FileName    : String;
  ParamString : String;
  ProcName    : String;
begin
  ProcName    := 'GlobalGetHelp'; Try
  FileName    := ExePath+'Help_ads.exe';
  ParamString := '"'+Title+'"';
  DefaultDir  := GlobalHelpDir;
  ExecuteExeParams(
    FileName    , //FileName    : String;
    ParamString , //ParamString : String;
    DefaultDir  );//DefaultDir  : String): Boolean;
  Except On E : Exception Do RaiseError(UnitName,ProcName,E); End;
end;

//
Unit Description UnitIndex Master Index
procedure THelpForm.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
Var
  ProcName  : String;
  sgCaption : String;
begin
  ProcName := 'THelpForm.FormKeyDown'; Try
  If Key = 112 Then
  Begin
    If Sender is TForm Then
    Begin
      sgCaption := TForm(Sender).Caption;
    End
    Else
    Begin
      If Sender is TComponent Then
      Begin
        sgCaption := TForm(TComponent(Sender).Owner).Caption;
      End
      Else
      Begin
        sgCaption := '';
      End;
    End;
    GlobalGetHelp(sgCaption);
  End;
  Except On E : Exception Do RaiseError(UnitName,ProcName,E); End;
end;

//
Unit Description UnitIndex Master Index
procedure GlobalInitForHelp(Sender:TObject);
Var
  Form     : TForm;
  ProcName : String;
  sgImage  : String;
begin
  ProcName := 'GlobalInitForHelp'; Try
  If Not ShouldRecordHelpScreen Then Exit;
  If Sender is TForm Then
  Begin
    Form            := TForm(Sender);
    Form.KeyPreview := True;
    Form.OnKeyDown  := HelpForm.FormKeyDown;
  End;
  If Not DirectoryExists(GlobalHelpDir)  Then ForceDirectories(GlobalHelpDir);
  sgImage := 'helpq.jpg';
  If Not FileExists(GlobalHelpDir+sgImage) Then
  Begin
    If FileExists(GlobalImageDir+sgImage) Then
    Begin
      CopyFile(GlobalImageDir+sgImage,GlobalHelpDir+sgImage);
    End;
  End;
  sgImage := 'helpyellow.jpg';
  If Not FileExists(GlobalHelpDir+sgImage) Then
  Begin
    If FileExists(GlobalImageDir+sgImage) Then
    Begin
      CopyFile(GlobalImageDir+sgImage,GlobalHelpDir+sgImage);
    End;
  End;
  sgImage := 'open.jpg';
  If Not FileExists(GlobalHelpDir+sgImage) Then
  Begin
    If FileExists(GlobalImageDir+sgImage) Then
    Begin
      CopyFile(GlobalImageDir+sgImage,GlobalHelpDir+sgImage);
    End;
  End;
  sgImage := 'closed.jpg';
  If Not FileExists(GlobalHelpDir+sgImage) Then
  Begin
    If FileExists(GlobalImageDir+sgImage) Then
    Begin
      CopyFile(GlobalImageDir+sgImage,GlobalHelpDir+sgImage);
    End;
  End;
  If Not DirectoryExists(GlobalIncludeDir) Then ForceDirectories(GlobalIncludeDir);
  Except On E : Exception Do RaiseError(UnitName,ProcName,E); End;
end;

//
Unit Description UnitIndex Master Index
procedure  MakeIndexDetail(
  Directory: String;
  Title    : String;
  Prefix   : String);
Var
  DirList  : TStringList;
  inCounter: Integer;
  inIndex  : Integer;
  inPos    : Integer;
  lstPage  : TStringList;
  ModDirLst: TStringList;
  ProcName : String;
  sgList   : String;
  sgItem   : String;
  sgTemp   : String;
  sgUpPref : String;
Begin
  ProcName := 'MakeIndexDetail'; Try
  DirList  := TStringList.Create();
  ModDirLst:= TStringList.Create();
  lstPage  := TStringList.Create();
  Try
    DirList  .Clear;
    ModDirLst.Clear;
    lstPage  .Clear;
    FilesInDirDetail(
      DirList    ,      //FileList    : TStrings;
      Directory,        //Directory   : String;
      '*.html',         //Mask        : String;
      False,            //Intersection: Boolean;
      False,            //IsReadOnly  : Boolean;
      False,            //IsHidden    : Boolean;
      False,            //IsSystem    : Boolean;
      False,            //IsVolumeID  : Boolean;
      False,            //IsDirectory : Boolean;
      False,            //IsArchive   : Boolean;
      True,             //IsNormal    : Boolean;
      False);           //InclDotFiles: Boolean): Boolean;
    inIndex := DirList.IndexOf('00000000.html');
    If inIndex <> -1 Then DirList.Delete(inIndex);
    inIndex := DirList.IndexOf('index.html');
    If inIndex <> -1 Then DirList.Delete(inIndex);
    inIndex := DirList.IndexOf('help.html');
    If inIndex <> -1 Then DirList.Delete(inIndex);
    ModDirLst.SetText(PChar(DirList.Text));
    sgUpPref := UpperCase(Prefix);
    For inCounter := 0 To ModDirLst.Count - 1 Do
    Begin
      sgTemp := ModDirLst[inCounter];
      inPos  := Pos(sgUpPref,UpperCase(sgTemp));
      If inPos = 1 Then
      Begin
        sgTemp := Copy(sgTemp,Length(sgUpPref)+1,Length(sgTemp)-Length(sgUpPref)+1);
      End;
      sgTemp := Copy(sgTemp,1,Length(sgTemp)-5);
      ModDirLst[inCounter] := sgTemp;
    End;
    With lstPage Do
    Begin
      Clear;
      Add('');
      Add('');
      Add(''+Title+'');
      Add('');
      Add('');
      Add('');
      Add('');
      Add('');
      Add('');
      Add('');
      Add('');
      Add('');
      Add('');
      Add('');
      Add('');
      Add('');
      Add('
'); Add(''); Add(''); Add(' '); Add(''); Add(''); Add(' '); Add(' '); Add(' '); Add('
'); Add(' '); Add(' '); Add(' '); Add(' '); Add('
'); Add('

'); Add(' '); Add('

'+Title+'

'); Add(' '); Add('

'); Add('
'); Add('
'); Add(' '); Add('
'); Add(' '); Add(' '); Add(' '; sgList:=sgList+sgItem+#13+#10; End; Add(sgList); Add(' '); Add(' '); Add(' '); Add(' '); Add('
'); Add(' '); Add('
'); sgList := ''; For inCounter:=0 To DirList.Count-1 Do Begin sgItem:='
'+Copy(DirList[inCounter],1,Length(DirList[inCounter])-5)+'
'); Add('
'); Add(' '); Add(''); Add(''); Add('
'); Add(''); Add(''); SaveToFile(Directory+'help.html'); SaveToFile(Directory+'index.html'); End; Finally DirList .Free; ModDirLst.Free; lstPage .Free; End; Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; End; //
Unit Description UnitIndex Master Index
procedure  MakeHelpIndex(Prefix: String);
Var
  Directory: String;
  ProcName : String;
  Title    : String;
Begin
  ProcName := 'MakeHelpIndex'; Try
  Directory:= GlobalHelpDir;
  Title    := GlobalCaptionAp+' Contents';
  GlobalInitForHelp(nil);
  MakeIndexDetail(
    Directory, //Directory: String;
    Title    , //Title    : String;
    Prefix   );//Prefix   : String);
  Except On E : Exception Do RaiseError(UnitName,ProcName,E); End;
End;

//
Unit Description UnitIndex Master Index
procedure CorrectPriorAndNext(FileName : String);
Var
  Directory : String;
  inIndex   : Integer;
  inMax     : Integer;
  inPos     : Integer;
  lst       : TStringList;
  ProcName  : String;
  sgAfter   : String;
  sgBefore  : String;
  sgEnd     : String;
  sgFileName: String;
  sgNext    : String;
  sgPrior   : String;
  sgStart   : String;
  sgTemp    : String;
Begin
  ProcName := 'ChangePagePrior'; Try
  lst := TStringList.Create();
  Try
    If Not FileExists(FileName) Then Exit;
    Directory := ExtractFileDir(FileName);
    FilesInDirDetail(
      lst        ,      //FileList    : TStrings;
      Directory,        //Directory   : String;
      '*.html',         //Mask        : String;
      False,            //Intersection: Boolean;
      False,            //IsReadOnly  : Boolean;
      False,            //IsHidden    : Boolean;
      False,            //IsSystem    : Boolean;
      False,            //IsVolumeID  : Boolean;
      False,            //IsDirectory : Boolean;
      False,            //IsArchive   : Boolean;
      True,             //IsNormal    : Boolean;
      False);           //InclDotFiles: Boolean): Boolean;
    inIndex := lst.IndexOf('00000000.html');
    If inIndex <> -1 Then lst.Delete(inIndex);
    inIndex := lst.IndexOf('index.html');
    If inIndex <> -1 Then lst.Delete(inIndex);
    inIndex := lst.IndexOf('help.html');
    If inIndex <> -1 Then lst.Delete(inIndex);
    sgFileName:= ExtractFileName(FileName);
    lst.Sorted := True;
    lst.Sorted := False;
    inIndex := lst.IndexOf(sgFileName);
    If inIndex = -1 Then Exit;
    sgPrior   := '';
    sgNext    := '';
    inMax     := lst.Count-1;
    If inMax < 1 Then Exit;
    If inIndex = inMax Then
    Begin
      sgPrior   := lst[inMax-1];
      sgNext    := lst[0];
    End
    Else
    Begin
      If inIndex = 0 Then
      Begin
        sgPrior   := lst[inMax];
        sgNext    := lst[1];
      End
      Else
      Begin
        sgPrior   := lst[inIndex-1];
        sgNext    := lst[inIndex+1];
      End;
    End;
    lst.Clear;
    lst.LoadFromFile(FileName);
    sgTemp   := lst.Text;
    sgBefore := '';
    sgAfter  := '';
    inPos    := Pos('',sgTemp);
    If inPos > 0 Then
    Begin
      sgBefore := Copy(sgTemp,1,inPos-1);
      inPos    := Pos('',sgTemp);
      If inPos > 0 Then
      Begin
        sgAfter := Copy(sgTemp,inPos,Length(sgTemp)-inPos+1);
        lst.Clear;
        lst.SetText(PChar(sgBefore+''));
        lst.Add('          ');
        lst.SetText(PChar(lst.Text+'          '+sgAfter));
      End;
    End;
    sgTemp   := lst.Text;
    sgBefore := '';
    sgAfter  := '';
    sgStart  := 'function GoToNextPage(){document.location=';
    sgEnd    := ';}';
    inPos    := Pos(sgStart,sgTemp);
    If inPos > 0 Then
    Begin
      sgBefore := Copy(sgTemp,1,inPos-1)+sgStart;
      sgTemp   := Copy(sgTemp,Length(sgBefore)+1,Length(sgTemp)-(Length(sgBefore)+1));
      inPos    := Pos(sgEnd,sgTemp);
      If inPos > 0 Then
      Begin
        sgAfter := Copy(sgTemp,inPos,Length(sgTemp)-inPos+1);
        lst.Clear;
        lst.SetText(PChar(sgBefore+#39+sgNext+#39+sgAfter));
      End;
    End;
    lst.SaveToFile(FileName);
  Finally
    lst.Free;
  End;
  Except On E : Exception Do RaiseError(UnitName,ProcName,E); End;
end;


//
Unit Description UnitIndex Master Index
procedure CorrectAllPriorAndNext(Directory : String);
Var
  inCounter : Integer;
  inIndex   : Integer;
  lst       : TStringList;
  ProcName  : String;
Begin
  ProcName := 'CorrectAllPriorAndNext'; Try
  lst := TStringList.Create();
  Try
    If Not DirectoryExists(Directory) Then Exit;
    FilesInDirDetail(
      lst        ,      //FileList    : TStrings;
      Directory,        //Directory   : String;
      '*.html',         //Mask        : String;
      False,            //Intersection: Boolean;
      False,            //IsReadOnly  : Boolean;
      False,            //IsHidden    : Boolean;
      False,            //IsSystem    : Boolean;
      False,            //IsVolumeID  : Boolean;
      False,            //IsDirectory : Boolean;
      False,            //IsArchive   : Boolean;
      True,             //IsNormal    : Boolean;
      False);           //InclDotFiles: Boolean): Boolean;
    inIndex := lst.IndexOf('00000000.html');
    If inIndex <> -1 Then lst.Delete(inIndex);
    inIndex := lst.IndexOf('index.html');
    If inIndex <> -1 Then lst.Delete(inIndex);
    inIndex := lst.IndexOf('help.html');
    If inIndex <> -1 Then lst.Delete(inIndex);
    If Copy(Directory,Length(Directory),1) <> '\' Then Directory := Directory + '\';
    For inCounter := 0 To lst.Count - 1 Do
    Begin
      CorrectPriorAndNext(Directory+lst[inCounter]);
    End;
  Finally
    lst.Free;
  End;
  Except On E : Exception Do RaiseError(UnitName,ProcName,E); End;
end;

//
Unit Description UnitIndex Master Index
procedure RecordHelpScreen(ShouldShoot: Boolean;Title,SubTitle,Description,HelpDir: String;Sender:TWinControl;OverWrite:Boolean);
Var
  Bitmap       : TBitmap;
  BitmapFile   : String;
  Form         : TForm;
  Jpeg         : TJpegImage;
  lst          : TStringList;
  lstInclude   : TStringList;
  NextPage     : String;
  PriorPage    : String;
  ProcName     : String;
  sgInclude    : String;
  sgIncludeFile: String;
  sgIndex      : String;
  sgPage       : String;
  WebPage      : String;
begin
  ProcName    := 'RecordScreenHistory'; Try
  If Not ShouldShoot Then Exit;
  If Sender = nil Then Exit;
  Bitmap      := TBitmap.Create;
  Jpeg        := TJpegImage.Create();
  lst         := TStringList.Create();
  lstInclude  := TStringList.Create();
  Try
    sgIndex   := 'help.html';
    sgInclude := 'include\';

    If Not DirectoryExists(GlobalHelpDir)  Then
    Begin
      ForceDirectories(GlobalHelpDir);
      If Not FileExists(GlobalHelpDir+'helpq.jpg') Then
      Begin
        If FileExists(GlobalImageDir+'helpq.jpg') Then
        Begin
          CopyFile(GlobalImageDir+'helpq.jpg',GlobalHelpDir+'helpq.jpg');
        End;
      End;
      If Not FileExists(GlobalHelpDir+'helpyellow.jpg') Then
      Begin
        If FileExists(GlobalImageDir+'helpyellow.jpg') Then
        Begin
          CopyFile(GlobalImageDir+'helpyellow.jpg',GlobalHelpDir+'helpyellow.jpg');
        End;
      End;
    End;
    If Not DirectoryExists(GlobalIncludeDir) Then ForceDirectories(GlobalIncludeDir);


    If Sender is TForm Then
    Begin
      Form     := TForm(Sender);
    End
    Else
    Begin
      Form     := TForm(Sender.Owner);
    End;
    If SubTitle = '' Then
    Begin
      SubTitle := Form.Caption;
    End;
    sgPage     := SubTitle;
    WebPage    := sgPage+'.html';
    If Not OverWrite Then If FileExists(GlobalHelpDir+WebPage) Then Exit;
    sgIncludeFile:= sgPage+'.txt';
    BitmapFile := sgPage+'.jpg';
    NextPage   := 'unknownnext'+'.html';
    PriorPage  := 'unknownprior'+'.html';
    Bitmap.Assign(Form.GetFormImage);
    Jpeg  .Assign(Bitmap);
    Try
      Jpeg  .SaveToFile(GlobalHelpDir+BitmapFile);
    Except
    End;
    lst.Clear;
    lst.Add('');
    lst.Add('');
    lst.Add('');
    lst.Add('');
    lst.Add('');
    lst.Add('');
    lst.Add('');
    lst.Add('');
    lst.Add('  ');
    lst.Add('');
    lst.Add('');
    lst.Add('  ');
    lst.Add('');
    lst.Add('');
    lst.Add('  ');
    lst.Add('');
    lst.Add('
'); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add('
'); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' Contents'); lst.Add(' '); lst.Add(' '); lst.Add('
'); lst.Add('
'); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' ‹'); lst.Add(' '); lst.Add(' '); lst.Add('
'); lst.Add('
'); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' ›'); lst.Add(' '); lst.Add(' '); lst.Add('
'); lst.Add('
'); lst.Add('

'); lst.Add(' '); lst.Add('

'); lst.Add(' '+Title+' Help
'); lst.Add(' '+SubTitle); lst.Add('

'); lst.Add(' '); lst.Add('

'); lst.Add('
'); lst.Add('
'); lst.Add('
'); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add('
'); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add('
'); lst.Add(' '); lst.Add(' '); lst.Add(' '+SubTitle+''); lst.Add(' '); lst.Add(' '); lst.Add('
'); lst.Add('
'); lst.Add(' '); lst.Add('
'); lst.Add(' '); If Description = '' Then Begin If FileExists(GlobalIncludeDir+sgIncludeFile) Then Begin lstInclude.Clear; lstInclude.LoadFromFile(GlobalIncludeDir+sgIncludeFile); lst.SetText(PChar(lst.Text+lstInclude.Text)); End Else Begin lst.Add(''); End; End Else Begin lst.Add(Description); End; lst.Add(' '); lst.Add('
'); lst.Add('
'); lst.Add(' '); lst.Add('
'); lst.Add(' '); lst.Add(' Created '+FormatDateTime('dddd, mmmm d, yyyy hh:nn:ss am/pm',now())); lst.Add(' '); lst.Add('
'); lst.Add('
'); lst.Add('
'); lst.Add(''); lst.Add(''); lst.Add(''); lst.SaveToFile(GlobalHelpDir+WebPage); MakeHelpIndex(GlobalCaptionAp+'-'); CorrectAllPriorAndNext(GlobalHelpDir); Finally Bitmap .Free; Jpeg .Free; lst .Free; lstInclude.Free; End; Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; end; //
Unit Description UnitIndex Master Index
procedure GlobalInitForHistory;
Var
  ProcName : String;
  sgImage  : String;
begin
  ProcName := 'GlobalInitForHistory'; Try
  If Not ShouldRecordScreenHistory Then Exit;
  If Not DirectoryExists(GlobalHistoryDir)  Then ForceDirectories(GlobalHistoryDir);
  sgImage := 'helpq.jpg';
  If Not FileExists(GlobalHistoryDir+sgImage) Then
  Begin
    If FileExists(GlobalImageDir+sgImage) Then
    Begin
      CopyFile(GlobalImageDir+sgImage,GlobalHistoryDir+sgImage);
    End;
  End;
  sgImage := 'helpyellow.jpg';
  If Not FileExists(GlobalHistoryDir+sgImage) Then
  Begin
    If FileExists(GlobalImageDir+sgImage) Then
    Begin
      CopyFile(GlobalImageDir+sgImage,GlobalHistoryDir+sgImage);
    End;
  End;
  sgImage := 'open.jpg';
  If Not FileExists(GlobalHistoryDir+sgImage) Then
  Begin
    If FileExists(GlobalImageDir+sgImage) Then
    Begin
      CopyFile(GlobalImageDir+sgImage,GlobalHistoryDir+sgImage);
    End;
  End;
  sgImage := 'closed.jpg';
  If Not FileExists(GlobalHistoryDir+sgImage) Then
  Begin
    If FileExists(GlobalImageDir+sgImage) Then
    Begin
      CopyFile(GlobalImageDir+sgImage,GlobalHistoryDir+sgImage);
    End;
  End;
  Except On E : Exception Do RaiseError(UnitName,ProcName,E); End;
end;

//
Unit Description UnitIndex Master Index
procedure  MakeHistoryIndex(Prefix: String);
Var
  Directory : String;
  inCounter : Integer;
  inDelete  : Integer;
  inIndex   : Integer;
  lst       : TStringList;
  ProcName  : String;
  Title     : String;
Begin
  ProcName := 'MakeHelpIndex'; Try
  Directory:= GlobalHistoryDir;
  Title    := GlobalCaptionAp+' Screen History';
  GlobalInitForHistory;
  lst := TStringList.Create();
  Try
    FilesInDirDetail(
      lst,              //FileList    : TStrings;
      Directory,        //Directory   : String;
      '*.html',         //Mask        : String;
      False,            //Intersection: Boolean;
      False,            //IsReadOnly  : Boolean;
      False,            //IsHidden    : Boolean;
      False,            //IsSystem    : Boolean;
      False,            //IsVolumeID  : Boolean;
      False,            //IsDirectory : Boolean;
      False,            //IsArchive   : Boolean;
      True,             //IsNormal    : Boolean;
      False);           //InclDotFiles: Boolean): Boolean;
    inIndex := lst.IndexOf('00000000.html');
    If inIndex <> -1 Then lst.Delete(inIndex);
    inIndex := lst.IndexOf('index.html');
    If inIndex <> -1 Then lst.Delete(inIndex);
    inIndex := lst.IndexOf('help.html');
    If inIndex <> -1 Then lst.Delete(inIndex);
    lst.Sorted := True;
    lst.Sorted := False;
    If lst.Count > GlobalHistoryMax Then
    Begin
      inDelete  := lst.Count - GlobalHistoryMax;
      For inCounter := 0 To inDelete Do
      Begin
        DeleteFile(Directory+lst[inCounter]);
        lst.Delete(inCounter);
      End;
    End;
  Finally
    lst.Free;
  End;
  MakeIndexDetail(
    Directory, //Directory: String;
    Title    , //Title    : String;
    Prefix   );//Prefix   : String);
  Except On E : Exception Do RaiseError(UnitName,ProcName,E); End;
End;

//
Unit Description UnitIndex Master Index
procedure RecordScreenHistory(ShouldShoot: Boolean;Title,SubTitle,Description,HistoryDir: String;Sender:TWinControl);
Var
  Bitmap      : TBitmap;
  BitmapFile  : String;
  Form        : TForm;
  Jpeg        : TJpegImage;
  lst         : TStringList;
  NextPage    : String;
  PriorPage   : String;
  ProcName    : String;
  sgImgNum    : String;
  sgLastPage  : String;
  WebPage     : String;
begin
  ProcName    := 'RecordScreenHistory'; Try
  If Not ShouldShoot Then Exit;
  If Sender = nil Then Exit;
  Bitmap      := TBitmap.Create;
  Jpeg        := TJpegImage.Create();
  lst         := TStringList.Create();
  Try
    HistoryDir := GlobalHistoryDir;
    GlobalInitForHistory;
    sgImgNum   := FormatDateTime('yyyy_mm_dd_hh-nn_ss',now());
    WebPage    := sgImgNum+'.html';
    BitmapFile := sgImgNum+'.jpg';
    NextPage   := StringPad('Unknown','0',8,False)+'.html';
    PriorPage  := StringPad('Unknown','0',8,False)+'.html';
    sgLastPage := NextPage;

    If Sender is TForm Then
    Begin
      Form     := TForm(Sender);
    End
    Else
    Begin
      Form     := TForm(Sender.Owner);
    End;
    If SubTitle = '' Then
    Begin
      SubTitle := Form.Caption;
    End;
    Bitmap.Assign(Form.GetFormImage);
    //Bitmap.SaveToFile(HistoryDir+BitmapFile);
    Jpeg  .Assign(Bitmap);
    Jpeg  .SaveToFile(HistoryDir+BitmapFile);
    lst.Clear;
    lst.Add('');
    lst.Add('');
    lst.Add('');
    lst.Add('');
    lst.Add('');
    lst.Add('');
    lst.Add('');
    lst.Add('');
    lst.Add('  ');
    lst.Add('');
    lst.Add('');
    lst.Add('  ');
    lst.Add('');
    lst.Add('');
    lst.Add('  ');
    lst.Add('');
    lst.Add('
'); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add('
'); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' Contents'); lst.Add(' '); lst.Add(' '); lst.Add('
'); lst.Add('
'); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' ‹'); lst.Add(' '); lst.Add(' '); lst.Add('
'); lst.Add('
'); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' ›'); lst.Add(' '); lst.Add(' '); lst.Add('
'); lst.Add('
'); lst.Add('

'); lst.Add(' '); lst.Add('

'); lst.Add(' '+Title+' Screen
'); lst.Add(' '+SubTitle); lst.Add('

'); lst.Add(' '); lst.Add('

'); lst.Add('
'); lst.Add('
'); lst.Add('
'); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add('
'); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add(' '); lst.Add('
'); lst.Add(' '); lst.Add(' '); lst.Add(' '+SubTitle+''); lst.Add(' '); lst.Add(' '); lst.Add('
'); lst.Add('
'); lst.Add(' '); lst.Add('

'); lst.Add(' '); lst.Add(' '); lst.Add(' '+Description+''); lst.Add(' '); lst.Add(' '); lst.Add('

'); lst.Add('
'); lst.Add('
'); lst.Add(' '); lst.Add('
'); lst.Add(' '); lst.Add(' Created '+FormatDateTime('dddd, mmmm d, yyyy hh:nn:ss am/pm',now())); lst.Add(' '); lst.Add('
'); lst.Add('
'); lst.Add('
'); lst.Add(''); lst.Add(''); lst.Add(''); lst.SaveToFile(HistoryDir+WebPage); MakeHistoryIndex(''); CorrectAllPriorAndNext(HistoryDir); Finally Bitmap .Free; Jpeg .Free; lst .Free; End; Except On E : Exception Do RaiseError(UnitName,ProcName,E); End; end; //
Unit Description UnitIndex Master Index
procedure ScreenShotDetail(Sender:TObject);
Var
  ProcName    : String;
Begin
  ProcName := 'ScreenShotDetail'; Try
  If Sender = nil Then Exit;
  If Not (Sender is TWinControl) Then Exit;
  If ShouldRecordScreenHistory Then
    RecordScreenHistory(
      ShouldRecordScreenHistory, //ShouldShoot: Boolean;
      GlobalCaptionAp          , //Title,
      ''                       , //SubTitle,
      ''                       , //Description,
      ''                       , //HistoryDir: String;
      TWinControl(Sender)      );//Sender:TWinControl);

  If ShouldRecordHelpScreen Then
    RecordHelpScreen(
      ShouldRecordHelpScreen   , //ShouldShoot: Boolean;
      GlobalCaptionAp          , //Title,
      ''                       , //SubTitle,
      ''                       , //Description,
      ''                       , //HelpDir: String;
      TWinControl(Sender)      , //Sender:TWinControl);
      ShouldOverWriteHelpScreen);//OverWrite: Boolean;

  Except On E : Exception Do RaiseError(UnitName,ProcName,E); End;
end;


//
Unit Description UnitIndex Master Index
procedure ScreenShot(Sender:TObject);
Var
  ProcName: String;
Begin
  ProcName := 'ScreenShot'; Try
  If Not (ShouldRecordHelpScreen Or ShouldRecordScreenHistory) Then Exit;
  ScreenShotDetail(Sender);
  Except On E : Exception Do RaiseError(UnitName,ProcName,E); End;
End;

//
Unit Description UnitIndex Master Index
procedure THelpForm.FormChanged(Sender: TObject);
Var
  ProcName  : String;
Begin
  ProcName := 'THelpForm.FormChanged'; Try
  Timer.Enabled:=True;
  Except On E : Exception Do RaiseError(UnitName,ProcName,E); End;
End;

//
Unit Description UnitIndex Master Index
procedure THelpForm.TimerTimer(Sender: TObject);
Var
  ProcName  : String;
Begin
  ProcName := 'THelpForm.TimerTimer'; Try
  Timer.Enabled:=False;
  If Screen.ActiveForm<>nil Then
    ScreenShot(Screen.ActiveForm);
  Except On E : Exception Do RaiseError(UnitName,ProcName,E); End;
End;

//
Unit Description UnitIndex Master Index
procedure SelfDocInit();
Var
  ProcName  : String;
Begin
  ProcName := 'SelfDocInit'; Try
  Timer               := TTimer.Create(nil);
  Timer.Interval      := 1000;
  Timer.OnTimer       := HelpForm.TimerTimer;
  DataIni             := TStringlist.Create();
  FormList            := TStringlist.Create();
  ExeName             := ExtractFileName(ParamStr(0));
  ExeName             := LowerCase(Copy(ExeName,1,Length(ExeName)-4));
  ExeName             := UpperCase(Copy(ExeName,1,1))+Copy(ExeName,2,Length(ExeName)-1);
  ExePath             := ExtractFilePath(ParamStr(0));
  DirLocalApp         := PathOfAppDataLocal();
  DirLocalThisApp     := DirLocalApp+ExeName+'\';
  GlobalImageDir      := DirLocalThisApp+'Images\';
  GlobalHistoryDir    := DirLocalThisApp+'History\';
  GlobalHelpDir       := DirLocalThisApp+'Help\';
  GlobalIncludeDir    := DirLocalThisApp+'Help\Include\';
  GlobalCaptionAp     := Application.MainForm.Caption;

  If Not DirectoryExists(DirLocalThisApp) Then
  Begin
    Try
      ForceDirectories(DirLocalThisApp);
    Except
    End;
  End;
  If Not DirectoryExists(GlobalImageDir) Then
  Begin
    Try
      ForceDirectories(GlobalImageDir);
    Except
    End;
  End;
  If Not DirectoryExists(GlobalHistoryDir) Then
  Begin
    Try
      ForceDirectories(GlobalHistoryDir);
    Except
    End;
  End;
  If Not DirectoryExists(GlobalHelpDir) Then
  Begin
    Try
      ForceDirectories(GlobalHelpDir);
    Except
    End;
  End;
  If Not DirectoryExists(GlobalIncludeDir) Then
  Begin
    Try
      ForceDirectories(GlobalIncludeDir);
    Except
    End;
  End;
  FileIni             := DirLocalThisApp+ExeName+'.SelfDocumenting.ini';
  FileFormList        := DirLocalThisApp+ExeName+'.SelfDocumenting.Forms.txt';
  If Not FileExists(FileIni) Then
  Begin
    DataIni.Add('Active=FALSE');
    DataIni.Add('GlobalCaptionAp='+GlobalCaptionAp);
    DataIni.Add('ShouldOverWriteHelpScreen=FALSE');
    DataIni.Add('ShouldRecordHelpScreen=FALSE');
    DataIni.Add('ShouldRecordScreenHistory=FALSE');
    DataIni.SaveToFile(FileIni);
  End;
  If Not FileExists(FileFormList) Then StrToFile('',FileFormList);
  If FileExists(FileIni) Then DataIni.LoadFromFile(FileIni);

  If DataIni.Values['GlobalCaptionAp']<>'' Then GlobalCaptionAp:=DataIni.Values['GlobalCaptionAp'];
  DataIni.Values['GlobalCaptionAp']:=GlobalCaptionAp;

  If DataIni.Values['ShouldOverWriteHelpScreen']<>'' Then ShouldOverWriteHelpScreen:=(DataIni.Values['ShouldOverWriteHelpScreen']='TRUE');
  If ShouldOverWriteHelpScreen Then DataIni.Values['ShouldOverWriteHelpScreen']:='TRUE' Else DataIni.Values['ShouldOverWriteHelpScreen']:='FALSE';

  If DataIni.Values['ShouldRecordHelpScreen']<>'' Then ShouldRecordHelpScreen:=(DataIni.Values['ShouldRecordHelpScreen']='TRUE');
  If ShouldRecordHelpScreen Then DataIni.Values['ShouldRecordHelpScreen']:='TRUE' Else DataIni.Values['ShouldRecordHelpScreen']:='FALSE';

  If DataIni.Values['ShouldRecordScreenHistory']<>'' Then ShouldRecordScreenHistory:=(DataIni.Values['ShouldRecordScreenHistory']='TRUE');
  If ShouldRecordScreenHistory Then DataIni.Values['ShouldRecordScreenHistory']:='TRUE' Else DataIni.Values['ShouldRecordScreenHistory']:='FALSE';

  Active:=(ShouldRecordScreenHistory Or ShouldRecordHelpScreen);
  If Active Then DataIni.Values['Active']:='TRUE' Else DataIni.Values['Active']:='FALSE';

  Try If DataIni.Values['GlobalHistoryMax']<>'' Then GlobalHistoryMax:=StrToInt(DataIni.Values['GlobalHistoryMax']);Except End;
  DataIni.Values['GlobalHistoryMax']:=IntToStr(GlobalHistoryMax);

  DataIni.SaveToFile(FileIni);
  If Not Active Then Exit;
  If FileExists(FileFormList) Then DataIni.LoadFromFile(FileFormList);
  Screen.OnActiveFormChange:=HelpForm.FormChanged;
  GlobalInitForHelp(nil);
  GlobalInitForHistory();
  Except On E : Exception Do RaiseError(UnitName,ProcName,E); End;
End;

//
Unit Description UnitIndex Master Index
procedure SelfDocFinal();
Var
  ProcName  : String;
Begin
  ProcName := 'SelfDocFinal'; Try
  FreeAndNil(lst);
  FreeAndNil(DataIni);
  FreeAndNil(FormList);
  FreeAndNil(Timer);
  Except On E : Exception Do RaiseError(UnitName,ProcName,E); End;
End;

Initialization
  SelfDocInit();
Finalization
  SelfDocFinal();
end.
//