📄 frxpreviewpages.pas
字号:
{******************************************}
{ }
{ FastReport v4.0 }
{ Preview Pages }
{ }
{ Copyright (c) 1998-2008 }
{ by Alexander Tzyganenko, }
{ Fast Reports Inc. }
{ }
{******************************************}
unit frxPreviewPages;
interface
{$I frx.inc}
uses
Windows, SysUtils, Messages, Classes, Graphics, Controls, Forms, Dialogs,
frxClass, frxXML, frxPictureCache
{$IFDEF Delphi6}
, Variants
{$ENDIF};
type
TfrxOutline = class(TfrxCustomOutline)
private
protected
function GetCount: Integer; override;
public
function Root: TfrxXMLItem;
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
FAllowPartialLoading: Boolean;
FCopyNo: Integer;
FDictionary: TfrxDictionary; { list of all objects }
FFirstObjectIndex: Integer; { used in the ClearFirstPassPages }
FFirstPageIndex: Integer; { used in the ClearFirstPassPages }
FLogicalPageN: Integer;
FPageCache: TStringList; { last 20 TfrxPreviewPage }
FPagesItem: TfrxXMLItem; { shortcut to XMLDoc.Root.FindName('previewpages') }
FPictureCache: TfrxPictureCache;
FPrintScale: Extended;
FSourcePages: TList; { list of source pages }
FTempStream: TStream;
FXMLDoc: TfrxXMLDocument; { parsed FP3 document }
FXMLSize: Integer;
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 AddPicture(Picture: TfrxPictureView); 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 IncLogicalPageNumber; override;
procedure ResetLogicalPageNumber; override;
procedure PasteObjects(X, Y: Extended); override;
procedure ShiftAnchors(From, NewTop: Integer); override;
procedure UpdatePageDimensions(Page: TfrxReportPage; Width, Height: Extended);
function BandExists(Band: TfrxBand): Boolean; override;
function FindAnchor(const Text: String): TfrxXMLItem;
function GetAnchorPage(const Text: String): Integer;
function GetAnchorCurPosition: Integer; override;
function GetCurPosition: Integer; override;
function GetLastY: Extended; override;
function GetLogicalPageNo: Integer; override;
function GetLogicalTotalPages: Integer; 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; DBClick: Boolean = False); override;
property SourcePages: TList read FSourcePages;
end;
implementation
uses
frxPreview, Printers, frxPrinter, frxPrintDialog, frxXMLSerializer, frxUtils,
ShellApi, frxDMPClass, frxRes;
type
THackComponent = class(TfrxComponent);
THackMemoView = class(TfrxCustomMemoView);
THackThread = class(TThread);
{ 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 := String(Item.Prop['page']);
if s <> '' then
Page := StrToInt(s);
s := String(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
if CurItem = nil then
Result := 0
else
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
if From = nil then Exit;
i := From.Parent.IndexOf(From);
if i + 1 >= From.Parent.Count then Exit;
From := From.Parent[i + 1];
TopY := StrToInt(String(From.Prop['top']));
CorrY := NewTop - TopY;
EnumItems(From);
end;
function TfrxOutline.GetCurPosition: TfrxXMLItem;
begin
if Count = 0 then
Result := nil 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;
{$IFDEF Delphi12}
var
TempStr: String;
{$ENDIF}
begin
{$IFDEF Delphi12}
TempStr := CreateUniqueName(Base);
Add(TempStr, SourceName, Obj);
Result := TempStr;
{$ELSE}
Result := CreateUniqueName(Base);
Add(Result, SourceName, Obj);
{$ENDIF}
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;
FPictureCache := TfrxPictureCache.Create;
end;
destructor TfrxPreviewPages.Destroy;
begin
ClearPageCache;
FPageCache.Free;
FDictionary.Free;
ClearSourcePages;
FPictureCache.Free;
FSourcePages.Free;
FXMLDoc.Free;
inherited;
end;
procedure TfrxPreviewPages.Clear;
begin
ClearPageCache;
ClearSourcePages;
FXMLDoc.Clear;
FDictionary.Clear;
FPictureCache.Clear;
CurPage := -1;
FXMLSize := 0;
end;
procedure TfrxPreviewPages.Initialize;
begin
FPictureCache.UseFileCache := Report.PreviewOptions.PictureCacheInFile;
FPictureCache.TempDir := Report.EngineOptions.TempDir;
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;
ResetLogicalPageNumber;
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
{$IFDEF Delphi12}
{ if (AnsiStrIComp(PAnsiChar(FXMLDoc.Root[i].Name), PAnsiChar(AnsiString('anchors'))) <> 0) and
(AnsiStrIComp(PAnsiChar(FXMLDoc.Root[i].Name), PAnsiChar(AnsiString('logicalpagenumbers'))) <> 0) then}
if (CompareText(FXMLDoc.Root[i].Name, 'anchors') <> 0) and
(CompareText(FXMLDoc.Root[i].Name, 'logicalpagenumbers') <> 0) then
{$ELSE}
if (CompareText(FXMLDoc.Root[i].Name, 'anchors') <> 0) and
(CompareText(FXMLDoc.Root[i].Name, 'logicalpagenumbers') <> 0) then
{$ENDIF}
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;
ResetLogicalPageNumber;
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];
{$IFDEF Delphi12}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -