unit rHTMLTools;
(*This entire unit was created by K. Toppenberg, starting on 5/27/05
It will hold additional functions to support HTML display of notes
and printing of HTML notes. *)
interface
uses Windows, SysUtils, Classes, Printers, ComCtrls,
ShDocVw, {//kt added ShDocVw 5-2-05 for TWebBrowser access}
Dialogs,
Forms,
Registry, {elh 6/19/09}
ORFn; {//kt for RedrawActivate}
var
DesiredHTMLFontSize : byte;
procedure PrintHTMLReport(Lines: TStringList; var ErrMsg: string;
PtName, DOB, VisitDate, Location:string; Application : TApplication); //kt added 5-2-05
function IsHTML(Lines : TStrings): boolean; overload;
function IsHTML(Line : String): boolean; overload;
function HasHTMLTags(Text: string) : boolean;
procedure FixHTML(Lines : TStrings);
function FixHTMLCRLF(Text : String) : string;
procedure SplitToArray (HTMLText: string; Lines : TStrings);
procedure StripBeforeAfterHTML(Lines,OutBefore,OutAfter : TStrings);
function UnwrapHTML(HTMLText : string) : string;
function WrapHTML(HTMLText : string) : string;
// function WaitForBrowserOK(MaxSecDelay: integer; Application : TApplication) : boolean;
function CheckForImageLink(Lines: TStrings; ImageList : TStringList) : boolean;
function ProtectHTMLSpaces(Text : String) : string;
function Text2HTML(Lines : TStrings) : String; overload;
function Text2HTML(text : string) : String; overload;
procedure SetRegHTMLFontSize(Size: byte);
procedure RestoreRegHTMLFontSize;
procedure SetupHTMLPrinting(Name,DOB,VisitDate,Location,Institution : string);
procedure RestoreIEPrinting;
function ExtractDateOfNote(Lines : TStringList) : string;
Procedure ScanForSubs(Lines : TStrings);
implementation
uses fNotes,
fImages,
Messages,
Graphics, //For color constants
fTMGPrintingAnimation,
ExtCtrls,
uTemplateFields,
fTemplateDialog,
StrUtils;
type
TPrinterEvents = class
public
SavedDefaultPrinter : string;
LastChosenPrinterName : string;
RestorePrinterTimer : TTimer;
PrintingNow : boolean;
procedure HandleRestorePrinting (Sender: TObject);
Constructor Create;
Destructor Destroy; override;
end;
var
PrinterEvents : TPrinterEvents;
const CRLF = #$0D#$0A;
function GetCurrentPrinterName : string;
//var ResStr: array[0..255] of Char;
begin
//GetProfileString('Windows', 'device', '', ResStr, 255);
//Result := StrPas(ResStr);
if (Printer.PrinterIndex > 0)then begin
Result := Printer.Printers[Printer.PrinterIndex];
end else begin
Result := '';
end;
end;
procedure SetDefaultPrinter(PrinterName: String) ;
var
j : Integer;
Device, Driver, Port : PChar;
HdeviceMode : THandle;
aPrinter : TPrinter;
begin
Printer.PrinterIndex := -1;
getmem(Device, 255) ;
getmem(Driver, 255) ;
getmem(Port, 255) ;
aPrinter := TPrinter.create;
j := Printer.Printers.IndexOf(PrinterName);
if j >= 0 then begin
aprinter.printerindex := j;
aPrinter.getprinter(device, driver, port, HdeviceMode) ;
StrCat(Device, ',') ;
StrCat(Device, Driver ) ;
StrCat(Device, Port ) ;
WriteProfileString('windows', 'device', Device) ;
StrCopy( Device, 'windows' ) ;
//SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, Longint(@Device)) ;
end;
Freemem(Device, 255) ;
Freemem(Driver, 255) ;
Freemem(Port, 255) ;
aPrinter.Free;
end;
procedure Wait(Sec : byte; Application : TApplication);
var StartTime : TDateTime;
const OneSec = 0.000012;
begin
StartTime := GetTime;
repeat
Application.ProcessMessages;
until (GetTime-StartTime) > (OneSec*Sec);
end;
procedure PrintHTMLReport(Lines: TStringList; var ErrMsg: string;
PtName, DOB, VisitDate, Location:string;
Application : TApplication);
// Web browser printing options:
// OLECMDEXECOPT_DODEFAULT Use the default behavior, whether prompting the user for input or not.
// OLECMDEXECOPT_PROMPTUSER Execute the command after obtaining user input.
// OLECMDEXECOPT_DONTPROMPTUSER Execute the command without prompting the user.
{Notice: When IE is asked to print, it immediately returns from the function,
but the printing has not yet occured. If UI is requested, then the
printing will not start until after the user selects a printer and
presses [OK]. I could not find any reliable way to determine when the
print job had been created. I had to know this event because I need to
restore some IE settings AFTER the printing has finished. I even tried to
get the active windows and see if it was a print dialog. But IE print dlg
apparently is owned by another thread than CPRS, because GetActiveWindow would
not bring back a handle to the printer dialog window. I therefore told IE
to print WITHOUT asking which printer via UI. In that case it prints to the
system wide default printer. So I have to set the default printer to the
user's choice, and then change it back again. This is bit of a kludge,
but I couldn't figure out any other way after hours of trial and error.
NOTE: I tried to query IE to see if it was able to print, thinking that it
would return NO if in the process of currently printing. It didn't work,
and would return OK immediately.
ADDENDUM: I was getting errors and inconsistent behavior with this, so I
have decided to try to let the user click a button when the printer has
been selected. }
var
UseUI : OleVariant;
//NewPrinterName : string;
//dlgWinPrinter : TPrintDialog;
begin
//if PrinterEvents.RestorePrinterTimer.Enabled = false then begin
// PrinterEvents.SavedDefaultPrinter := GetCurrentPrinterName;
//end;
if PrinterEvents.PrintingNow then exit; // prevent double printing (it has happened)
try
rHTMLTools.ScanForSubs(Lines); //Added to correct Printing issue elh
frmNotes.SetDisplayToHTMLvsText([vmView,vmHTML],Lines); //ActivateHtmlViewer(Lines);
if frmNotes.HtmlViewer.WaitForDocComplete = false then begin
ErrMsg := 'The web browser timed out trying to set up document.';
exit;
end;
PrinterEvents.PrintingNow := true;
SetupHTMLPrinting(PtName,DOB,VisitDate,Location,' '); {elh 6/19/09} //kt
frmNotes.HtmlViewer.PrintFinished := false;
UseUI := true;
frmNotes.HtmlViewer.PrintDocument(UseUI); //Returns immediately, not after printing done.
frmTMGPrinting.ShowModal; // Let user show when print job has been launched.
PrinterEvents.RestorePrinterTimer.Enabled := true; //launch a restore event in 30 seconds
//RestoreIEPrinting; //elh - This was omitted from below. Not sure why. 11/10/09
finally
PrinterEvents.PrintingNow := false;
end;
end;
(*
Safe copy of above. Delete later...
procedure PrintHTMLReport(Lines: TStringList; var ErrMsg: string;
PtName, DOB, Location:string;
Application : TApplication);
// Web browser printing options:
// OLECMDEXECOPT_DODEFAULT Use the default behavior, whether prompting the user for input or not.
// OLECMDEXECOPT_PROMPTUSER Execute the command after obtaining user input.
// OLECMDEXECOPT_DONTPROMPTUSER Execute the command without prompting the user.
{Notice: When IE is asked to print, it immediately returns from the function,
but the printing has not yet occured. If UI is requested, then the
printing will not start until after the user selects a printer and
presses [OK]. I could not find any reliable way to determine when the
print job had been created. I had to know this event because I need to
restore some IE settings AFTER the printing has finished. I even tried to
get the active windows and see if it was a print dialog. But IE print dlg
apparently is owned by another thread than CPRS, because GetActiveWindow would
not bring back a handle to the printer dialog window. I therefore told IE
to print WITHOUT asking which printer via UI. In that case it prints to the
system wide default printer. So I have to set the default printer to the
user's choice, and then change it back again. This is bit of a kludge,
but I couldn't figure out any other way after hours of trial and error.
NOTE: I tried to query IE to see if it was able to print, thinking that it
would return NO if in the process of currently printing. It didn't work,
and would return OK immediately. }
var
UseUI : OleVariant;
NewPrinterName : string;
dlgWinPrinter : TPrintDialog;
begin
if PrinterEvents.RestorePrinterTimer.Enabled = false then begin
PrinterEvents.SavedDefaultPrinter := GetCurrentPrinterName;
end;
dlgWinPrinter := TPrintDialog.Create(nil);
frmTMGPrinting.Show;
//FIX: get printer name for the one used last time somehow...
if dlgWinPrinter.Execute then begin //only sets a local printer
NewPrinterName := GetCurrentPrinterName;
SetDefaultPrinter(NewPrinterName); //Set global setting that IE will use.
PrinterEvents.LastChosenPrinterName := NewPrinterName;
try
frmNotes.SetDisplayToHTMLvsText([vmView,vmHTML],Lines); //ActivateHtmlViewer(Lines);
if frmNotes.HtmlViewer.WaitForDocComplete = false then begin
ErrMsg := 'The web browser timed out trying to set up document.';
exit;
end;
SetupHTMLPrinting(PtName,DOB,Location,' '); {elh 6/19/09} //kt
frmNotes.HtmlViewer.PrintFinished := false;
UseUI := false; //UseUI := true;
frmNotes.HtmlViewer.PrintDocument(UseUI); //Returns immediately, not after printing done.
PrinterEvents.RestorePrinterTimer.Enabled := true; //launch a restore event in 30 seconds
Wait(4,Application);
//WaitForBrowserOK(10, Application); //wait up to 10 seconds //Note: this doesn't do what I want. Status is immediately OK.
//RestoreIEPrinting; {elh 6/19/09} //kt
finally //any needed final code goes here.
//SetDefaultPrinter(DefaultPrinter);
//beep;
end;
end;
dlgWinPrinter.Free;
frmTMGPrinting.Hide;
end;
*)
(*
function WaitForBrowserOK(MaxSecDelay: integer; Application : TApplication) : boolean;
//Returns TRUE if can print
var
StartTime : TDateTime;
Status: OLECMDF;
MaxDelay,ElapsedTime : Double;
CanPrint : boolean;
const
OneMin = 0.0007; //note: 0.0007 is about 1 minute
begin
StartTime := GetTime;
MaxDelay := OneMin * MaxSecDelay;
repeat
Status := frmNotes.HtmlViewer.QueryStatusWB(OLECMDID_PRINT); //"can you print?" -- get print command status
CanPrint := (Status and OLECMDF_ENABLED) > 0;
ElapsedTime := GetTime-StartTime;
Application.ProcessMessages;
until (ElapsedTime > MaxDelay) or CanPrint or frmNotes.HtmlViewer.PrintFinished;
Result := CanPrint;
end;
*)
Procedure ScanForSubs(Lines : TStrings);
//Purpose: To scan note for constant $CPRS$ and replace with CPRS's actual directory
var i : integer;
CPRSDir : string;
begin
for i := 0 to Lines.Count-1 do begin
if Pos('$CPRSDIR$',Lines.Strings[i])>0 then begin
CPRSDir := ExcludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)));
Lines.Strings[i] := AnsiReplaceStr(Lines.Strings[i],'$CPRSDIR$',CPRSDir);
//Ensure images are downloaded before passing page to web browser
frmImages.timLoadImagesTimer(nil);
//NOTE: This often doesn't get the job completed before passing to browser
// ?? check for completion?
end;
end;
end;
function IsHTML(Line : String): boolean;
{Purpose: To look at the Text and determine if it is an HTML document.
Test used: if document contains or