Componentes.Terceros.FastRe.../official/3.23/Source/frxPreviewPages.pas
2007-09-10 15:54:09 +00:00

1790 lines
46 KiB
ObjectPascal

{******************************************}
{ }
{ FastReport v3.0 }
{ Preview Pages }
{ }
{ Copyright (c) 1998-2006 }
{ by Alexander Tzyganenko, }
{ Fast Reports Inc. }
{ }
{******************************************}
unit frxPreviewPages;
interface
{$I frx.inc}
uses
Windows, SysUtils, Messages, Classes, Graphics, Controls, Forms, Dialogs,
frxClass, frxXML
{$IFDEF Delphi6}
, Variants
{$ENDIF};
type
TfrxOutline = class(TfrxCustomOutline)
private
function Root: TfrxXMLItem;
protected
function GetCount: Integer; override;
public
procedure AddItem(const Text: String; Top: Integer); override;
procedure LevelDown(Index: Integer); override;
procedure LevelRoot; override;
procedure LevelUp; override;
procedure GetItem(Index: Integer; var Text: String;
var Page, Top: Integer); override;
procedure ShiftItems(From: TfrxXMLItem; NewTop: Integer); override;
function GetCurPosition: TfrxXMLItem; override;
end;
TfrxDictionary = class(TObject)
private
FNames: TStringList;
FSourceNames: TStringList;
public
constructor Create;
destructor Destroy; override;
procedure Add(const Name, SourceName: String; Obj: TObject);
procedure Clear;
function AddUnique(const Base, SourceName: String; Obj: TObject): String;
function CreateUniqueName(const Base: String): String;
function GetSourceName(const Name: String): String;
function GetObject(const Name: String): TObject;
property Names: TStringList read FNames;
property SourceNames: TStringList read FSourceNames;
end;
TfrxPreviewPages = class(TfrxCustomPreviewPages)
private
FDictionary: TfrxDictionary; { list of all objects }
FFirstObjectIndex: Integer; { used in the ClearFirstPassPages }
FFirstPageIndex: Integer; { used in the ClearFirstPassPages }
FPageCache: TStringList; { last 20 TfrxPreviewPage }
FPagesItem: TfrxXMLItem; { shortcut to XMLDoc.Root.FindName('previewpages') }
FSourcePages: TList; { list of source pages }
FXMLDoc: TfrxXMLDocument; { parsed FP3 document }
FXMLSize: Integer;
FTempStream: TStream;
FAllowPartialLoading: Boolean;
procedure AfterLoad;
procedure BeforeSave;
procedure ClearPageCache;
procedure ClearSourcePages;
function CurXMLPage: TfrxXMLItem;
function GetObject(const Name: String): TfrxComponent;
procedure DoLoadFromStream;
procedure DoSaveToStream;
protected
function GetCount: Integer; override;
function GetPage(Index: Integer): TfrxReportPage; override;
function GetPageSize(Index: Integer): TPoint; override;
public
constructor Create(AReport: TfrxReport); override;
destructor Destroy; override;
procedure Clear; override;
procedure Initialize; override;
{ engine commands }
procedure AddAnchor(const Text: String);
procedure AddObject(Obj: TfrxComponent); override;
procedure AddPage(Page: TfrxReportPage); override;
procedure AddSourcePage(Page: TfrxReportPage); override;
procedure AddToSourcePage(Obj: TfrxComponent); override;
procedure BeginPass; override;
procedure ClearFirstPassPages; override;
procedure CutObjects(APosition: Integer); override;
procedure Finish; override;
procedure PasteObjects(X, Y: Extended); override;
function BandExists(Band: TfrxBand): Boolean; override;
function FindAnchor(const Text: String): TfrxXMLItem;
function GetAnchorPage(const Text: String): Integer;
function GetCurPosition: Integer; override;
function GetLastY: Extended; override;
{ preview commands }
procedure DrawPage(Index: Integer; Canvas: TCanvas; ScaleX, ScaleY,
OffsetX, OffsetY: Extended); override;
procedure AddEmptyPage(Index: Integer); override;
procedure DeletePage(Index: Integer); override;
procedure ModifyPage(Index: Integer; Page: TfrxReportPage); override;
procedure AddFrom(Report: TfrxReport); override;
procedure LoadFromStream(Stream: TStream;
AllowPartialLoading: Boolean = False); override;
procedure SaveToStream(Stream: TStream); override;
function LoadFromFile(const FileName: String;
ExceptionIfNotFound: Boolean = False): Boolean; override;
procedure SaveToFile(const FileName: String); override;
function Print: Boolean; override;
function Export(Filter: TfrxCustomExportFilter): Boolean; override;
procedure ObjectOver(Index: Integer; X, Y: Integer; Button: TMouseButton;
Shift: TShiftState; Scale, OffsetX, OffsetY: Extended;
Click: Boolean; var Cursor: TCursor); override;
property SourcePages: TList read FSourcePages;
end;
implementation
uses
frxPreview, Printers, frxPrinter, frxPrintDialog, frxXMLSerializer, frxUtils,
frxFormUtils, ShellApi, frxDMPClass, frxRes;
type
THackComponent = class(TfrxComponent);
THackMemoView = class(TfrxCustomMemoView);
THackThread = class(TThread);
{$IFDEF TRIAL}
const
FR_UNREG = ')segap 5 ylno( noisrev deretsigernU - tropeRtsaF';
{$ENDIF}
{ TfrxOutline }
procedure TfrxOutline.AddItem(const Text: String; Top: Integer);
begin
CurItem := CurItem.Add;
CurItem.Name := 'item';
CurItem.Text := 'text="' + frxStrToXML(Text) +
'" page="' + IntToStr(PreviewPages.CurPage) +
'" top="' + IntToStr(Top) + '"';
end;
procedure TfrxOutline.GetItem(Index: Integer; var Text: String; var Page,
Top: Integer);
var
Item: TfrxXMLItem;
s: String;
begin
Item := CurItem[Index];
Text := Item.Prop['text'];
s := Item.Prop['page'];
if s <> '' then
Page := StrToInt(s);
s := Item.Prop['top'];
if s <> '' then
Top := StrToInt(s);
end;
procedure TfrxOutline.LevelDown(Index: Integer);
begin
CurItem := CurItem[Index];
end;
procedure TfrxOutline.LevelRoot;
begin
CurItem := Root;
end;
procedure TfrxOutline.LevelUp;
begin
if CurItem <> Root then
CurItem := CurItem.Parent;
end;
function TfrxOutline.Root: TfrxXMLItem;
begin
Result := TfrxPreviewPages(PreviewPages).FXMLDoc.Root.FindItem('outline');
end;
function TfrxOutline.GetCount: Integer;
begin
Result := CurItem.Count;
end;
procedure TfrxOutline.ShiftItems(From: TfrxXMLItem; NewTop: Integer);
var
i, TopY, CorrY: Integer;
procedure EnumItems(Item: TfrxXMLItem);
var
i: Integer;
begin
Item.Prop['page'] := IntToStr(StrToInt(Item.Prop['page']) + 1);
Item.Prop['top'] := IntToStr(StrToInt(Item.Prop['top']) + CorrY);
for i := 0 to Item.Count - 1 do
EnumItems(Item[i]);
end;
begin
i := From.Parent.IndexOf(From);
if i + 1 >= From.Parent.Count then Exit;
From := From.Parent[i + 1];
TopY := StrToInt(From.Prop['top']);
CorrY := NewTop - TopY;
EnumItems(From);
end;
function TfrxOutline.GetCurPosition: TfrxXMLItem;
begin
if Count = 0 then
Result := CurItem else
Result := CurItem[Count - 1];
end;
{ TfrxDictionary }
constructor TfrxDictionary.Create;
begin
FNames := TStringList.Create;
FNames.Sorted := True;
FSourceNames := TStringList.Create;
end;
destructor TfrxDictionary.Destroy;
begin
FNames.Free;
FSourceNames.Free;
inherited;
end;
procedure TfrxDictionary.Clear;
begin
FNames.Clear;
FSourceNames.Clear;
end;
procedure TfrxDictionary.Add(const Name, SourceName: String; Obj: TObject);
var
i: Integer;
begin
i := FSourceNames.AddObject(SourceName, Obj);
FNames.AddObject(Name, TObject(i));
end;
function TfrxDictionary.AddUnique(const Base, SourceName: String; Obj: TObject): String;
begin
Result := CreateUniqueName(Base);
Add(Result, SourceName, Obj);
end;
function TfrxDictionary.CreateUniqueName(const Base: String): String;
var
i: Integer;
begin
i := 10000;
while (i > 1) and (FNames.IndexOf(Base + IntToStr(i)) = -1) do
i := i div 2;
while FNames.IndexOf(Base + IntToStr(i)) <> -1 do
Inc(i);
Result := Base + IntToStr(i);
end;
function TfrxDictionary.GetObject(const Name: String): TObject;
var
i: Integer;
begin
Result := nil;
i := FNames.IndexOf(Name);
if i <> -1 then
Result := FSourceNames.Objects[Integer(FNames.Objects[i])];
end;
function TfrxDictionary.GetSourceName(const Name: String): String;
var
i: Integer;
begin
Result := '';
i := FNames.IndexOf(Name);
if i <> -1 then
Result := FSourceNames[Integer(FNames.Objects[i])];
end;
{ TfrxPreviewPages }
constructor TfrxPreviewPages.Create(AReport: TfrxReport);
begin
inherited;
FDictionary := TfrxDictionary.Create;
FSourcePages := TList.Create;
FXMLDoc := TfrxXMLDocument.Create;
FXMLDoc.Root.Name := 'preparedreport';
// FXMLDoc.AutoIndent := True;
FPageCache := TStringList.Create;
end;
destructor TfrxPreviewPages.Destroy;
begin
ClearPageCache;
FPageCache.Free;
FDictionary.Free;
ClearSourcePages;
FSourcePages.Free;
FXMLDoc.Free;
inherited;
end;
procedure TfrxPreviewPages.Clear;
begin
ClearPageCache;
ClearSourcePages;
FXMLDoc.Clear;
FDictionary.Clear;
CurPage := -1;
FXMLSize := 0;
end;
procedure TfrxPreviewPages.Initialize;
begin
FXMLDoc.TempDir := Report.EngineOptions.TempDir;
Report.InternalOnProgressStart(ptRunning);
end;
procedure TfrxPreviewPages.ClearPageCache;
begin
while FPageCache.Count > 0 do
begin
TfrxReportPage(FPageCache.Objects[0]).Free;
FPageCache.Delete(0);
end;
end;
procedure TfrxPreviewPages.ClearSourcePages;
begin
while FSourcePages.Count > 0 do
begin
TfrxReportPage(FSourcePages[0]).Free;
FSourcePages.Delete(0);
end;
end;
procedure TfrxPreviewPages.BeginPass;
begin
FFirstPageIndex := Count - 1;
if FFirstPageIndex <> -1 then
FFirstObjectIndex := FXMLDoc.Root.FindItem('previewpages')[FFirstPageIndex].Count;
end;
procedure TfrxPreviewPages.ClearFirstPassPages;
var
PagesRoot: TfrxXMLItem;
p: TfrxXMLItem;
i: Integer;
begin
if FFirstPageIndex = -1 then
begin
for i := 0 to FXMLDoc.Root.Count - 1 do
if CompareText(FXMLDoc.Root[i].Name, 'anchors') <> 0 then
FXMLDoc.Root[i].Clear;
end
else
begin
PagesRoot := FXMLDoc.Root.FindItem('previewpages');
p := PagesRoot[FFirstPageIndex];
{ clear some objects on first page }
while p.Count > FFirstObjectIndex do
p[FFirstObjectIndex].Free;
{ clear remained pages }
while Count > FFirstPageIndex + 1 do
PagesRoot[FFirstPageIndex + 1].Free;
end;
CurPage := FFirstPageIndex;
FXMLSize := 0;
end;
function TfrxPreviewPages.CurXMLPage: TfrxXMLItem;
begin
Result := FXMLDoc.Root.FindItem('previewpages');
Result := Result[CurPage];
end;
function TfrxPreviewPages.GetCount: Integer;
begin
Result := FXMLDoc.Root.FindItem('previewpages').Count;
end;
function TfrxPreviewPages.GetCurPosition: Integer;
begin
Result := CurXMLPage.Count;
end;
procedure TfrxPreviewPages.AddAnchor(const Text: String);
var
AnchorRoot, Item: TfrxXMLItem;
begin
AnchorRoot := FXMLDoc.Root.FindItem('anchors');
Item := AnchorRoot.Add;
Item.Name := 'item';
Item.Text := 'text="' + frxStrToXML(Text) +
'" page="' + IntToStr(CurPage) +
'" top="' + IntToStr(Round(Engine.CurY)) + '"';
end;
function TfrxPreviewPages.FindAnchor(const Text: String): TfrxXMLItem;
var
AnchorRoot, Item: TfrxXMLItem;
i: Integer;
begin
Result := nil;
AnchorRoot := FXMLDoc.Root.FindItem('anchors');
for i := AnchorRoot.Count - 1 downto 0 do
begin
Item := AnchorRoot[i];
if AnsiCompareText(Item.Prop['text'], Text) = 0 then
begin
Result := Item;
Exit;
end;
end;
end;
function TfrxPreviewPages.GetAnchorPage(const Text: String): Integer;
var
Item: TfrxXMLItem;
begin
Item := FindAnchor(Text);
if Item <> nil then
Result := StrToInt(Item.Prop['page']) + 1 else
Result := 1;
end;
procedure TfrxPreviewPages.AddObject(Obj: TfrxComponent);
procedure DoAdd(c: TfrxComponent; Item: TfrxXMLItem);
var
i: Integer;
begin
if not c.Visible then Exit;
{ do not put out subreports, cross-tabs and dialog components }
if not ((c is TfrxSubReport) or (CompareText(c.ClassName, 'TfrxCrossView') = 0) or
(CompareText(c.ClassName, 'TfrxDBCrossView') = 0) or (c is TfrxDialogComponent)) then
with THackComponent(c) do
begin
Item := Item.Add;
{ the component that was created after report has been started }
if FOriginalComponent = nil then
begin
Item.Name := ClassName;
Item.Text := AllDiff(nil);
end
else
begin
{ the component that exists in the report template }
Item.Name := FAliasName;
if Engine.FinalPass then
begin
if DefaultDiff then
Item.Text := AllDiff(FOriginalComponent) else
Item.Text := Diff(FOriginalComponent);
end
else
{ we don't need to output all info on the first pass, only coordinates }
Item.Text := InternalDiff(FOriginalComponent);
end;
Inc(FXMLSize, Length(Item.Name) + Length(Item.Text) + Item.InstanceSize + 16);
end;
for i := 0 to c.Objects.Count - 1 do
DoAdd(c.Objects[i], Item);
end;
begin
DoAdd(Obj, CurXMLPage);
end;
procedure TfrxPreviewPages.AddPage(Page: TfrxReportPage);
var
xi: TfrxXMLItem;
procedure UnloadPages;
var
i: Integer;
begin
if Report.EngineOptions.UseFileCache then
if FXMLSize > Report.EngineOptions.MaxMemSize * 1024 * 1024 then
begin
for i := xi.Count - 2 downto 0 do
if xi[i].Loaded then
FXMLDoc.UnloadItem(xi[i]) else
break;
FXMLSize := 0;
end;
end;
function GetSourceNo(Page: TfrxReportPage): Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to FSourcePages.Count - 1 do
if THackComponent(FSourcePages[i]).FOriginalComponent = Page then
begin
Result := i;
break;
end;
end;
begin
FPagesItem := FXMLDoc.Root.FindItem('previewpages');
xi := FPagesItem;
UnloadPages;
CurPage := CurPage + 1;
if (CurPage >= Count) or (AddPageAction = apAdd) then
begin
xi := xi.Add;
xi.Name := 'page' + IntToStr(GetSourceNo(Page));
if Count > 2 then
xi.Unloadable := True;
Report.InternalOnProgress(ptRunning, CurPage + 1);
AddPageAction := apWriteOver;
CurPage := Count - 1;
end;
end;
procedure TfrxPreviewPages.AddSourcePage(Page: TfrxReportPage);
var
p: TfrxReportPage;
xs: TfrxXMLSerializer;
i: Integer;
originals, copies: TList;
c1, c2: TfrxComponent;
s: String;
function EnumObjects(Parent, Parent1: TfrxComponent): TfrxComponent;
var
i: Integer;
c: TfrxComponent;
begin
Result := nil;
if (CompareText(Parent.ClassName, 'TfrxCrossView') = 0) or
(CompareText(Parent.ClassName, 'TfrxDBCrossView') = 0) or
(Parent is TfrxDialogComponent) then Exit;
c := TfrxComponent(Parent.NewInstance);
c.Create(Parent1);
c.Assign(Parent);
c.Name := Parent.Name;
originals.Add(Parent);
copies.Add(c);
for i := 0 to Parent.Objects.Count - 1 do
EnumObjects(Parent.Objects[i], c);
Result := c;
end;
begin
xs := TfrxXMLSerializer.Create(nil);
originals := TList.Create;
copies := TList.Create;
try
p := TfrxReportPage(EnumObjects(Page, nil));
THackComponent(p).FOriginalComponent := Page;
FSourcePages.Add(p);
for i := 1 to copies.Count - 1 do
begin
c1 := copies[i];
c2 := originals[i];
THackComponent(c2).FOriginalComponent := c1;
THackComponent(c1).FOriginalComponent := c2;
if c1 is TfrxBand then
s := 'b' else
s := LowerCase(c1.BaseName[1]);
s := FDictionary.AddUnique(s, 'Page' + IntToStr(FSourcePages.Count - 1) +
'.' + c1.Name, c1);
if c1.DefaultDiff then
THackComponent(c1).FBaseName := c1.ClassName else
THackComponent(c1).FBaseName := xs.WriteComponentStr(c1);
THackComponent(c1).FAliasName := s;
THackComponent(c2).FAliasName := s;
end;
finally
originals.Free;
copies.Free;
xs.Free;
end;
end;
procedure TfrxPreviewPages.AddToSourcePage(Obj: TfrxComponent);
var
NewObj: TfrxComponent;
Page: TfrxReportPage;
s: String;
xs: TfrxXMLSerializer;
begin
xs := TfrxXMLSerializer.Create(nil);
Page := FSourcePages[FSourcePages.Count - 1];
NewObj := TfrxComponent(Obj.NewInstance);
NewObj.Create(Page);
NewObj.Assign(Obj);
NewObj.CreateUniqueName;
s := FDictionary.AddUnique(LowerCase(NewObj.BaseName[1]),
'Page' + IntToStr(FSourcePages.Count - 1) + '.' + NewObj.Name, NewObj);
if NewObj.DefaultDiff then
THackComponent(NewObj).FBaseName := NewObj.ClassName else
THackComponent(NewObj).FBaseName := xs.WriteComponentStr(NewObj);
THackComponent(Obj).FOriginalComponent := NewObj;
THackComponent(Obj).FAliasName := s;
THackComponent(NewObj).FAliasName := s;
xs.Free;
end;
procedure TfrxPreviewPages.Finish;
var
i: Integer;
begin
ClearPageCache;
{ avoid bug with multiple PrepareReport(False) }
for i := 0 to FSourcePages.Count - 1 do
THackComponent(FSourcePages[i]).FOriginalComponent := nil;
Report.InternalOnProgressStop(ptRunning);
end;
function TfrxPreviewPages.BandExists(Band: TfrxBand): Boolean;
var
i: Integer;
c: TfrxComponent;
begin
Result := False;
for i := 0 to CurXMLPage.Count - 1 do
begin
c := GetObject(CurXMLPage[i].Name);
if c <> nil then
if (THackComponent(c).FOriginalComponent = Band) or
((Band is TfrxPageFooter) and (c is TfrxPageFooter)) or
((Band is TfrxColumnFooter) and (c is TfrxColumnFooter)) then
begin
Result := True;
break;
end;
end;
end;
function TfrxPreviewPages.GetLastY: Extended;
var
i: Integer;
c: TfrxComponent;
s: String;
y: Extended;
begin
Result := 0;
for i := 0 to CurXMLPage.Count - 1 do
begin
c := GetObject(CurXMLPage[i].Name);
if c is TfrxBand then
if not (c is TfrxPageFooter) and not (c is TfrxOverlay) then
begin
s := CurXMLPage[i].Prop['t'];
if s <> '' then
y := frxStrToFloat(s) else
y := c.Top;
s := CurXMLPage[i].Prop['h'];
if s <> '' then
y := y + frxStrToFloat(s) else
y := y + c.Height;
if y > Result then
Result := y;
end;
end;
end;
procedure TfrxPreviewPages.CutObjects(APosition: Integer);
var
xi: TfrxXMLItem;
begin
xi := FXMLDoc.Root.FindItem('cutted');
while APosition < CurXMLPage.Count do
xi.AddItem(CurXMLPage[APosition]);
end;
procedure TfrxPreviewPages.PasteObjects(X, Y: Extended);
var
xi: TfrxXMLItem;
LeftX, TopY, CorrX, CorrY: Extended;
procedure CorrectX(xi: TfrxXMLItem);
var
X: Extended;
begin
if xi.Prop['l'] <> '' then
X := frxStrToFloat(xi.Prop['l']) else
X := 0;
X := X + CorrX;
xi.Prop['l'] := FloatToStr(X);
end;
procedure CorrectY(xi: TfrxXMLItem);
var
Y: Extended;
begin
if xi.Prop['t'] <> '' then
Y := frxStrToFloat(xi.Prop['t']) else
Y := 0;
Y := Y + CorrY;
xi.Prop['t'] := FloatToStr(Y);
end;
begin
xi := FXMLDoc.Root.FindItem('cutted');
if xi.Count > 0 then
begin
if xi[0].Prop['l'] <> '' then
LeftX := frxStrToFloat(xi[0].Prop['l']) else
LeftX := 0;
CorrX := X - LeftX;
if xi[0].Prop['t'] <> '' then
TopY := frxStrToFloat(xi[0].Prop['t']) else
TopY := 0;
CorrY := Y - TopY;
while xi.Count > 0 do
begin
CorrectX(xi[0]);
CorrectY(xi[0]);
CurXMLPage.AddItem(xi[0]);
end;
end;
xi.Free;
end;
procedure TfrxPreviewPages.DoLoadFromStream;
var
Compressor: TfrxCustomCompressor;
begin
Compressor := nil;
if frxCompressorClass <> nil then
begin
FAllowPartialLoading := False;
Compressor := TfrxCustomCompressor(frxCompressorClass.NewInstance);
Compressor.Create(nil);
Compressor.Report := Report;
Compressor.IsFR3File := False;
try
Compressor.CreateStream;
Compressor.Decompress(FTempStream);
FTempStream := Compressor.Stream;
except
Compressor.Free;
Report.Errors.Add(frxResources.Get('clDecompressError'));
frxCommonErrorHandler(Report, frxResources.Get('clErrors') + #13#10 + Report.Errors.Text);
Exit;
end;
end;
FXMLDoc.LoadFromStream(FTempStream, FAllowPartialLoading);
AfterLoad;
if Compressor <> nil then
Compressor.Free;
end;
procedure TfrxPreviewPages.DoSaveToStream;
var
Compressor: TfrxCustomCompressor;
StreamTo: TStream;
begin
StreamTo := FTempStream;
Compressor := nil;
if Report.ReportOptions.Compressed and (frxCompressorClass <> nil) then
begin
Compressor := TfrxCustomCompressor(frxCompressorClass.NewInstance);
Compressor.Create(nil);
Compressor.Report := Report;
Compressor.IsFR3File := False;
Compressor.CreateStream;
StreamTo := Compressor.Stream;
end;
try
BeforeSave;
FXMLDoc.SaveToStream(StreamTo);
finally
if Compressor <> nil then
begin
try
Compressor.Compress(FTempStream);
finally
Compressor.Free;
end;
end;
end;
end;
procedure TfrxPreviewPages.LoadFromStream(Stream: TStream;
AllowPartialLoading: Boolean = False);
begin
Clear;
FTempStream := Stream;
FAllowPartialLoading := AllowPartialLoading;
{$IFNDEF FR_COM}
// if Report.EngineOptions.ReportThread <> nil then
// THackThread(Report.EngineOptions.ReportThread).Synchronize(DoLoadFromStream)
// else
{$ENDIF}
DoLoadFromStream;
end;
procedure TfrxPreviewPages.SaveToStream(Stream: TStream);
begin
FTempStream := Stream;
{$IFNDEF FR_COM}
// if Report.EngineOptions.ReportThread <> nil then
// THackThread(Report.EngineOptions.ReportThread).Synchronize(DoSaveToStream)
// else
{$ENDIF}
DoSaveToStream;
end;
function TfrxPreviewPages.LoadFromFile(const FileName: String;
ExceptionIfNotFound: Boolean): Boolean;
var
Stream: TFileStream;
begin
Result := FileExists(FileName);
if Result or ExceptionIfNotFound then
begin
Stream := TFileStream.Create(FileName, fmOpenRead + fmShareDenyWrite);
try
LoadFromStream(Stream);
finally
Stream.Free;
end;
{ Clear;
FXMLDoc.LoadFromFile(FileName);
AfterLoad;}
end;
end;
procedure TfrxPreviewPages.SaveToFile(const FileName: String);
var
Stream: TFileStream;
begin
Stream := TFileStream.Create(FileName, fmCreate);
try
SaveToStream(Stream);
finally
Stream.Free;
end;
{ BeforeSave;
FXMLDoc.SaveToFile(FileName);
ClearPageCache;
AfterLoad;}
end;
procedure TfrxPreviewPages.AfterLoad;
var
i: Integer;
xs: TfrxXMLSerializer;
xi: TfrxXMLItem;
p: TfrxReportPage;
{ store source objects' properties in the FBaseName to get it later in the GetPage }
procedure DoProps(p: TfrxReportPage);
var
i: Integer;
l: TList;
c: THackComponent;
begin
l := p.AllObjects;
for i := 0 to l.Count - 1 do
begin
c := l[i];
c.FBaseName := xs.WriteComponentStr(c);
end;
end;
{ fill FDictionary.Objects }
procedure FillDictionary;
var
i: Integer;
Name, PageName, ObjName: String;
PageN: Integer;
begin
xi := FXMLDoc.Root.FindItem('dictionary');
FDictionary.Clear;
for i := 0 to xi.Count - 1 do
begin
Name := Copy(xi[i].Text, 7, Length(xi[i].Text) - 7);
PageName := Copy(Name, 1, Pos('.', Name) - 1);
ObjName := Copy(Name, Pos('.', Name) + 1, 255);
PageN := StrToInt(Copy(PageName, 5, 255));
FDictionary.Add(xi[i].Name, Name,
TfrxReportPage(FSourcePages[PageN]).FindObject(ObjName));
end;
end;
begin
FPagesItem := FXMLDoc.Root.FindItem('previewpages');
xs := TfrxXMLSerializer.Create(nil);
{ load the report settings }
xi := FXMLDoc.Root.FindItem('report');
if xi.Count > 0 then
xs.ReadRootComponent(Report, xi[0]);
{ build sourcepages }
try
xi := FXMLDoc.Root.FindItem('sourcepages');
ClearSourcePages;
for i := 0 to xi.Count - 1 do
begin
if CompareText(xi[i].Name, 'TfrxDMPPage') = 0 then
p := TfrxDMPPage.Create(nil) else
p := TfrxReportPage.Create(nil);
xs.ReadRootComponent(p, xi[i]);
DoProps(p);
FSourcePages.Add(p);
end;
xi.Clear;
finally
xs.Free;
end;
{ build the dictionary }
FillDictionary;
end;
procedure TfrxPreviewPages.BeforeSave;
var
i: Integer;
xs: TfrxXMLSerializer;
xi: TfrxXMLItem;
begin
FPagesItem := FXMLDoc.Root.FindItem('previewpages');
xs := TfrxXMLSerializer.Create(nil);
{ upload the report settings }
xi := FXMLDoc.Root.FindItem('report');
xi.Clear;
xi := xi.Add;
xi.Name := Report.ClassName;
xi.Text := 'DotMatrixReport="' + frxValueToXML(Report.DotMatrixReport) +
'" PreviewOptions.OutlineVisible="' + frxValueToXML(Report.PreviewOptions.OutlineVisible) +
'" PreviewOptions.OutlineWidth="' + frxValueToXML(Report.PreviewOptions.OutlineWidth) + '"';
{ upload the sourcepages }
try
xi := FXMLDoc.Root.FindItem('sourcepages');
xi.Clear;
for i := 0 to FSourcePages.Count - 1 do
xs.WriteRootComponent(FSourcePages[i], True, xi.Add);
finally
xs.Free;
end;
{ upload the dictionary }
xi := FXMLDoc.Root.FindItem('dictionary');
xi.Clear;
for i := 0 to FDictionary.Names.Count - 1 do
with xi.Add do
begin
Name := FDictionary.Names[i];
Text := 'name="' + FDictionary.GetSourceName(Name) + '"';
end;
end;
function TfrxPreviewPages.GetObject(const Name: String): TfrxComponent;
begin
Result := TfrxComponent(FDictionary.GetObject(Name));
end;
function TfrxPreviewPages.GetPage(Index: Integer): TfrxReportPage;
var
xi: TfrxXMLItem;
xs: TfrxXMLSerializer;
i: Integer;
Source: TfrxReportPage;
procedure DoObjects(Item: TfrxXMLItem; Owner: TfrxComponent);
var
i: Integer;
c, c0: TfrxComponent;
begin
for i := 0 to Item.Count - 1 do
begin
c0 := GetObject(Item[i].Name);
{ object not found in the dictionary }
if c0 = nil then
c := xs.ReadComponentStr(Owner, Item[i].Name + ' ' + Item[i].Text)
else
begin
c := xs.ReadComponentStr(Owner, THackComponent(c0).FBaseName + ' ' + Item[i].Text);
c.Name := c0.Name;
end;
c.Parent := Owner;
DoObjects(Item[i], c);
end;
end;
begin
Result := nil;
if Count = 0 then Exit;
{ check pagecache first }
if not Engine.Running then
begin
i := FPageCache.IndexOf(IntToStr(Index));
if i <> -1 then
begin
Result := TfrxReportPage(FPageCache.Objects[i]);
FPageCache.Exchange(i, 0);
Exit;
end;
end;
xs := TfrxXMLSerializer.Create(nil);
try
{ load the page item }
xi := FPagesItem[Index];
FXMLDoc.LoadItem(xi);
if CompareText(xi.Name, 'TfrxReportPage') = 0 then
begin
{ page item do not refer to the originalpages }
Result := TfrxReportPage.Create(nil);
xs.ReadRootComponent(Result, xi);
end
else if CompareText(xi.Name, 'TfrxDMPPage') = 0 then
begin
{ page item do not refer to the originalpages }
Result := TfrxDMPPage.Create(nil);
xs.ReadRootComponent(Result, xi);
end
else
begin
Source := FSourcePages[StrToInt(Copy(xi.Name, 5, 5))];
{ create reportpage and assign properties from original page }
if Source is TfrxDMPPage then
Result := TfrxDMPPage.Create(nil) else
Result := TfrxReportPage.Create(nil);
Result.Assign(Source);
{ create objects }
DoObjects(xi, Result);
end;
finally
xs.Free;
end;
{ update aligned objects }
Result.AlignChildren;
{ add this page to the pagecache }
FPageCache.InsertObject(0, IntToStr(Index), Result);
i := FPageCache.Count;
{ remove the least used item from the pagecache }
if i > 50 then
begin
xi := FPagesItem[StrToInt(FPageCache[i - 1])];
if Report.EngineOptions.UseFileCache and xi.Unloadable then
begin
FXMLDoc.UnloadItem(xi);
xi.Clear;
end;
TfrxReportPage(FPageCache.Objects[i - 1]).Free;
FPageCache.Delete(i - 1);
end;
end;
function TfrxPreviewPages.GetPageSize(Index: Integer): TPoint;
var
xi: TfrxXMLItem;
p: TfrxReportPage;
begin
if (Count = 0) or (Index < 0) or (Index >= Count) then
begin
Result := Point(0, 0);
Exit;
end;
xi := FPagesItem[Index];
if (CompareText(xi.Name, 'TfrxReportPage') = 0) or
(CompareText(xi.Name, 'TfrxDMPPage') = 0) then
p := GetPage(Index) else
p := FSourcePages[StrToInt(Copy(xi.Name, 5, 256))];
Result.X := Round(p.Width);
Result.Y := Round(p.Height);
end;
procedure TfrxPreviewPages.AddEmptyPage(Index: Integer);
var
xi: TfrxXMLItem;
begin
if Count = 0 then Exit;
xi := TfrxXMLItem.Create;
xi.Name := FPagesItem[Index].Name;
FPagesItem.InsertItem(Index, xi);
ClearPageCache;
end;
procedure TfrxPreviewPages.DeletePage(Index: Integer);
begin
if Count < 2 then Exit;
FPagesItem[Index].Free;
ClearPageCache;
end;
procedure TfrxPreviewPages.ModifyPage(Index: Integer; Page: TfrxReportPage);
var
xs: TfrxXMLSerializer;
begin
xs := TfrxXMLSerializer.Create(nil);
try
FPagesItem[Index].Clear;
xs.WriteRootComponent(Page, True, FPagesItem[Index]);
FPagesItem[Index].Unloadable := False;
ClearPageCache;
finally
xs.Free;
end;
end;
procedure TfrxPreviewPages.AddFrom(Report: TfrxReport);
var
i: Integer;
Page: TfrxReportPage;
xi: TfrxXMLItem;
xs: TfrxXMLSerializer;
begin
xs := TfrxXMLSerializer.Create(nil);
for i := 0 to Report.PreviewPages.Count - 1 do
begin
Page := Report.PreviewPages.Page[i];
xi := TfrxXMLItem.Create;
xi.Name := FPagesItem[Count - 1].Name;
xs.WriteRootComponent(Page, True, xi);
xi.Unloadable := False;
FPagesItem.AddItem(xi);
end;
xs.Free;
ClearPageCache;
end;
procedure TfrxPreviewPages.DrawPage(Index: Integer; Canvas: TCanvas;
ScaleX, ScaleY, OffsetX, OffsetY: Extended);
var
i: Integer;
Page: TfrxReportPage;
l: TList;
c: TfrxComponent;
IsPrinting: Boolean;
SaveLeftMargin, SaveRightMargin: Extended;
rgn: HRGN;
function ViewVisible(c: TfrxComponent): Boolean;
var
r: TRect;
begin
with c do
r := Rect(Round(AbsLeft * ScaleX) - 20, Round(AbsTop * ScaleY) - 20,
Round((AbsLeft + Width) * ScaleX + 20),
Round((AbsTop + Height) * ScaleY + 20));
OffsetRect(r, Round(OffsetX), Round(OffsetY));
Result := RectVisible(Canvas.Handle, r) or (Canvas is TMetafileCanvas);
end;
begin
Page := GetPage(Index);
if Page = nil then Exit;
SaveLeftMargin := Page.LeftMargin;
SaveRightMargin := Page.RightMargin;
if Page.MirrorMargins and (Index mod 2 = 1) then
begin
Page.LeftMargin := SaveRightMargin;
Page.RightMargin := SaveLeftMargin;
end;
IsPrinting := Canvas is TfrxPrinterCanvas;
rgn := 0;
if not IsPrinting then
begin
rgn := CreateRectRgn(0, 0, 10000, 10000);
GetClipRgn(Canvas.Handle, rgn);
IntersectClipRect(Canvas.Handle,
Round(OffsetX),
Round(OffsetY),
Round(OffsetX + Page.PaperWidth * fr01cm * ScaleX) - 1,
Round(OffsetY + Page.PaperHeight * fr01cm * ScaleY) - 1);
end;
Page.Draw(Canvas, ScaleX, ScaleY, OffsetX, OffsetY);
OffsetX := OffsetX + Page.LeftMargin * fr01cm * ScaleX;
OffsetY := OffsetY + Page.TopMargin * fr01cm * ScaleY;
l := Page.AllObjects;
for i := 0 to l.Count - 1 do
begin
c := l[i];
if (c is TfrxView) and ViewVisible(c) then
if not IsPrinting or TfrxView(c).Printable then
begin
c.IsPrinting := IsPrinting;
{ needed for TOTALPAGES macro }
if c is TfrxCustomMemoView then
THackMemoView(c).FTotalPages := Count;
{ draw the object }
TfrxView(c).Draw(Canvas, ScaleX, ScaleY, OffsetX, OffsetY);
c.IsPrinting := False;
end;
end;
Page.LeftMargin := SaveLeftMargin;
Page.RightMargin := SaveRightMargin;
if not IsPrinting then
begin
SelectClipRgn(Canvas.Handle, rgn);
DeleteObject(rgn);
end;
end;
function TfrxPreviewPages.Print: Boolean;
var
Copies, PagesPrinted, ACopyNo: Integer;
Collate: Boolean;
PageNumbers: String;
PrintPages: TfrxPrintPages;
Reverse: Boolean;
pgList: TStringList;
LastDuplexMode: TfrxDuplexMode;
LastPaperSize, LastPaperWidth, LastPaperHeight, LastBin: Integer;
LastOrientation: TPrinterOrientation;
procedure DoPrint;
var
i: Integer;
Printer: TfrxCustomPrinter;
PagePrinted: Boolean;
Page: TfrxReportPage;
function PrintPage(Index: Integer): Boolean;
var
Bin, ACopies, cp: Integer;
begin
Result := True;
if Index >= Count then Exit;
if (pgList.Count <> 0) and (pgList.IndexOf(IntToStr(Index + 1)) = -1) then Exit;
if ((PrintPages = ppOdd) and ((Index + 1) mod 2 = 0)) or
((PrintPages = ppEven) and ((Index + 1) mod 2 = 1)) then Exit;
if Report.Terminated then
begin
Printer.Abort;
Result := False;
Exit;
end;
Page := GetPage(Index);
if Collate then
begin
ACopies := 1;
cp := ACopyNo;
end
else
begin
ACopies := Copies;
cp := 1;
end;
if Assigned(Report.OnPrintPage) then
Report.OnPrintPage(Page, cp);
if Index = 0 then
Bin := Page.Bin else
Bin := Page.BinOtherPages;
if (not PagePrinted) or
((LastPaperSize <> Page.PaperSize) or
(LastPaperWidth <> Round(Page.PaperWidth)) or
(LastPaperHeight <> Round(Page.PaperHeight)) or
(LastBin <> Bin) or
(LastOrientation <> Page.Orientation) or
(LastDuplexMode <> Page.Duplex)) then
Printer.SetPrintParams(Page.PaperSize, Page.PaperWidth, Page.PaperHeight,
Page.Orientation, Bin, Integer(Page.Duplex) + 1, ACopies);
if not PagePrinted then
Printer.BeginDoc;
Printer.BeginPage;
DrawPage(Index, Printer.Canvas, Printer.DPI.X / 96, Printer.DPI.Y / 96,
-Printer.LeftMargin * Printer.DPI.X / 25.4,
-Printer.TopMargin * Printer.DPI.Y / 25.4);
Report.InternalOnProgress(ptPrinting, Index + 1);
{$IFDEF TRIAL}
with Printer.Canvas do
begin
Font.Size := 12;
Font.Color := clBlack;
TextOut(0, 0, frxReverseString(FR_UNREG));
end;
{$ENDIF}
Printer.EndPage;
Application.ProcessMessages;
PagePrinted := True;
Inc(PagesPrinted);
LastPaperSize := Page.PaperSize;
LastPaperWidth := Round(Page.PaperWidth);
LastPaperHeight := Round(Page.PaperHeight);
LastBin := Bin;
LastOrientation := Page.Orientation;
LastDuplexMode := Page.Duplex;
ClearPageCache;
end;
procedure PrintPages;
var
i: Integer;
begin
PagesPrinted := 0;
if Reverse then
begin
{$IFNDEF TRIAL}
for i := Count - 1 downto 0 do
{$ELSE}
for i := 4 downto 0 do
{$ENDIF}
if not PrintPage(i) then
break;
end
else
{$IFNDEF TRIAL}
for i := 0 to Count - 1 do
{$ELSE}
for i := 0 to 4 do
{$ENDIF}
if not PrintPage(i) then
break;
end;
begin
Printer := frxPrinters.Printer;
Report.Terminated := False;
Report.InternalOnProgressStart(ptPrinting);
if Report.ReportOptions.Name <> '' then
Printer.Title := Report.ReportOptions.Name else
Printer.Title := Report.FileName;
if Copies <= 0 then
Copies := 1;
PagePrinted := False;
LastDuplexMode := dmNone;
if Collate then
for i := 0 to Copies - 1 do
begin
ACopyNo := i + 1;
PrintPages;
if (LastDuplexMode in [dmVertical, dmHorizontal]) and (PagesPrinted mod 2 <> 0) then
begin
Printer.BeginPage;
Printer.EndPage;
end;
if Report.Terminated then break;
end
else
PrintPages;
if PagePrinted then
Printer.EndDoc;
Report.InternalOnProgressStop(ptPrinting);
end;
begin
Result := True;
if Report.DotMatrixReport and (frxDotMatrixExport <> nil) then
begin
Report.SelectPrinter;
frxDotMatrixExport.ShowDialog := Report.PrintOptions.ShowDialog;
Result := Export(frxDotMatrixExport);
Exit;
end;
Copies := Report.PrintOptions.Copies;
Collate := Report.PrintOptions.Collate;
PageNumbers := Report.PrintOptions.PageNumbers;
PrintPages := Report.PrintOptions.PrintPages;
Reverse := Report.PrintOptions.Reverse;
Report.SelectPrinter;
if Report.PrintOptions.ShowDialog then
with TfrxPrintDialog.Create(Application) do
begin
UpDown1.Position := Copies;
CollateCB.Checked := Collate;
PageNumbersE.Text := PageNumbers;
if PageNumbers <> '' then
PageNumbersRB.Checked := True;
PrintPagesCB.ItemIndex := Integer(PrintPages);
ReverseCB.Checked := Reverse;
ShowModal;
if ModalResult = mrOk then
begin
Copies := StrToInt(CopiesE.Text);
Collate := CollateCB.Checked;
if AllRB.Checked then
PageNumbers := ''
else if CurPageRB.Checked then
PageNumbers := IntToStr(CurPreviewPage) else
PageNumbers := PageNumbersE.Text;
PrintPages := TfrxPrintPages(PrintPagesCB.ItemIndex);
Reverse := ReverseCB.Checked;
Free;
end
else
begin
Free;
Result := False;
Exit;
end;
end;
if Assigned(Report.OnPrintReport) then
Report.OnPrintReport(Report);
if Report.Preview <> nil then
Report.Preview.Lock;
pgList := TStringList.Create;
try
frxParsePageNumbers(PageNumbers, pgList, Count);
DoPrint;
finally
if Assigned(Report.OnAfterPrintReport) then
Report.OnAfterPrintReport(Report);
pgList.Free;
end;
end;
function TfrxPreviewPages.Export(Filter: TfrxCustomExportFilter): Boolean;
var
pgList: TStringList;
tempBMP: TBitmap;
procedure ExportPage(Index: Integer);
var
i, j: Integer;
Page: TfrxReportPage;
c: TfrxComponent;
p: TfrxPictureView;
{$IFDEF TRIAL}
m: TfrxCustomMemoView;
{$ENDIF}
procedure ExportObject(c: TfrxComponent);
begin
if c is TfrxCustomMemoView then
begin
{ set up font if Highlight is active }
if TfrxCustomMemoView(c).Highlight.Active then
TfrxCustomMemoView(c).Font.Assign(TfrxCustomMemoView(c).Highlight.Font);
{ needed for TOTALPAGES macro }
THackMemoView(c).FTotalPages := Count;
THackMemoView(c).ExtractTotalPages;
{ needed if memo has AutoWidth and Align properties }
if THackMemoView(c).AutoWidth then
THackMemoView(c).Draw(tempBMP.Canvas, 1, 1, 0, 0);
end;
Filter.ExportObject(c);
end;
begin
if Index >= Count then Exit;
if (pgList.Count <> 0) and (pgList.IndexOf(IntToStr(Index + 1)) = -1) then Exit;
Page := GetPage(Index);
if Page = nil then Exit;
if Filter.ShowProgress then
Report.InternalOnProgress(ptExporting, Index + 1);
Filter.StartPage(Page, Index);
try
{ set the offset of the page objects }
if Page.MirrorMargins and (Index mod 2 = 1) then
Page.Left := Page.RightMargin * fr01cm else
Page.Left := Page.LeftMargin * fr01cm;
Page.Top := Page.TopMargin * fr01cm;
{ export the page background picture and frame }
p := TfrxPictureView.Create(nil);
p.Name := '_pagebackground';
p.Color := Page.Color;
p.Frame.Assign(Page.Frame);
p.Picture.Assign(Page.BackPicture);
p.Stretched := True;
p.KeepAspectRatio := False;
try
p.SetBounds(Page.Left, Page.Top,
Page.Width - (Page.LeftMargin + Page.RightMargin) * fr01cm,
Page.Height - (Page.TopMargin + Page.BottomMargin) * fr01cm);
Filter.ExportObject(p);
finally
p.Free;
end;
{$IFDEF TRIAL}
m := TfrxCustomMemoView.Create(nil);
try
m.SetBounds(Page.Left, Page.Top - 10,
Page.Width - (Page.LeftMargin + Page.RightMargin) * fr01cm, 10);
m.Text := frxReverseString(FR_UNREG);
m.HAlign := haRight;
m.Font.Size := 7;
m.Font.Color := clGray;
Filter.ExportObject(m);
finally
m.Free;
end;
{$ENDIF}
for i := 0 to Page.Objects.Count - 1 do
begin
c := Page.Objects[i];
if c is TfrxBand then
begin
if c is TfrxPageHeader then
begin
{ suppress a header }
if Filter.SuppressPageHeadersFooters and (Index <> 0) then continue;
end;
if c is TfrxPageFooter then
begin
{ suppress a footer }
if Filter.SuppressPageHeadersFooters and (Index <> Count - 1) then continue;
end;
end;
ExportObject(c);
if c.Objects.Count <> 0 then
for j := 0 to c.Objects.Count - 1 do
ExportObject(c.Objects[j]);
end;
finally
Filter.FinishPage(Page, Index);
end;
if Report.Preview = nil then
ClearPageCache
else
begin
Page.Left := 0;
Page.Top := 0;
end;
end;
procedure DoExport;
var
i: Integer;
begin
if Filter.Start then
try
if Report.Preview <> nil then
begin
Report.Preview.Refresh;
Report.Preview.Lock;
end;
if Filter.ShowProgress then
Report.InternalOnProgressStart(ptExporting);
{$IFNDEF TRIAL}
for i := 0 to Count - 1 do
{$ELSE}
for i := 0 to 4 do
{$ENDIF}
begin
ExportPage(i);
if Report.Terminated then break;
Application.ProcessMessages;
end;
finally
if Report.Preview <> nil then
begin
TfrxPreview(Report.Preview).HideMessage;
Report.Preview.Refresh;
end;
if Filter.ShowProgress then
Report.InternalOnProgressStop(ptExporting);
Filter.Finish;
end;
end;
begin
Result := False;
if Filter = nil then Exit;
Filter.Report := Report;
if (Filter.ShowDialog and (Filter.ShowModal <> mrOk)) then
Exit;
if Filter.CurPage then
begin
if Report.Preview <> nil then
Filter.PageNumbers := IntToStr(CurPreviewPage) else
Filter.PageNumbers := '1';
end
{$IFDEF FR_COM}
else
Filter.PageNumbers := Report.PrintOptions.PageNumbers
{$ENDIF};
Result := True;
Report.Terminated := False;
pgList := TStringList.Create;
tempBMP := TBitmap.Create;
try
frxParsePageNumbers(Filter.PageNumbers, pgList, Count);
if Filter = frxDotMatrixExport then
if Assigned(Report.OnPrintReport) then
Report.OnPrintReport(Report);
try
DoExport;
except
on e: Exception do
begin
Result := False;
Report.Errors.Text := e.Message;
frxCommonErrorHandler(Report, frxResources.Get('clErrors') + #13#10 + Report.Errors.Text);
end;
end;
if Filter = frxDotMatrixExport then
if Assigned(Report.OnAfterPrintReport) then
Report.OnAfterPrintReport(Report);
finally
pgList.Free;
tempBMP.Free;
end;
end;
procedure TfrxPreviewPages.ObjectOver(Index: Integer; X, Y: Integer;
Button: TMouseButton; Shift: TShiftState; Scale, OffsetX, OffsetY: Extended;
Click: Boolean; var Cursor: TCursor);
var
Page: TfrxReportPage;
c: TfrxComponent;
l: TList;
i: Integer;
Flag: Boolean;
v: TfrxView;
function MouseInView(c: TfrxComponent): Boolean;
var
r: TRect;
begin
with c do
r := Rect(Round(AbsLeft * Scale), Round(AbsTop * Scale),
Round((AbsLeft + Width) * Scale),
Round((AbsTop + Height) * Scale));
OffsetRect(r, Round(OffsetX), Round(OffsetY));
Result := PtInRect(r, Point(X, Y));
end;
procedure SetToAnchor(const Text: String);
var
Item: TfrxXMLItem;
PageN, Top: Integer;
begin
Item := FindAnchor(Text);
if Item <> nil then
begin
PageN := StrToInt(Item.Prop['page']);
Top := StrToInt(Item.Prop['top']);
TfrxPreview(Report.Preview).SetPosition(PageN + 1, Top);
end;
end;
begin
if (Index < 0) or (Index >= Count) or Engine.Running then Exit;
Page := GetPage(Index);
if Page = nil then Exit;
if Page.MirrorMargins and (Index mod 2 = 1) then
OffsetX := OffsetX + Page.RightMargin * fr01cm * Scale else
OffsetX := OffsetX + Page.LeftMargin * fr01cm * Scale;
OffsetY := OffsetY + Page.TopMargin * fr01cm * Scale;
// Report.SetProgressMessage('');
Page := GetPage(Index); // get page again to ensure it was not cleared during export
if Page = nil then Exit;
l := Page.AllObjects;
for i := l.Count - 1 downto 0 do
begin
c := l[i];
if (c is TfrxView) and MouseInView(c) then
begin
v := TfrxView(c);
if v.Cursor <> crDefault then
Cursor := v.Cursor;
if v.URL <> '' then
begin
Report.SetProgressMessage(v.URL);
if v.Cursor = crDefault then
Cursor := crHandPoint;
end;
if Click then
begin
if v.URL <> '' then
if Pos('@', v.URL) = 1 then
TfrxPreview(Report.Preview).PageNo := StrToInt(Copy(v.URL, 2, 255))
else if Pos('#', v.URL) = 1 then
SetToAnchor(Copy(v.URL, 2, 255))
else
ShellExecute(GetDesktopWindow, nil, PChar(v.URL), nil, nil, sw_ShowNormal);
Flag := False;
Report.DoPreviewClick(v, Button, Shift, Flag);
if Flag then
begin
ModifyPage(Index, Page);
Report.Preview.Invalidate;
end;
end
else if Assigned(Report.OnMouseOverObject) then
Report.OnMouseOverObject(v);
break;
end;
end;
end;
end.
//<censored>