📄 teestore.pas
字号:
{*********************************************}
{ TeeChart Storage functions }
{ Copyright (c) 1997-2003 by David Berneda }
{ All rights reserved }
{*********************************************}
unit TeeStore;
{$I TeeDefs.inc}
interface
Uses {$IFNDEF LINUX}
Windows,
{$ENDIF}
Classes, TeeProcs, TeEngine, Chart;
{ Read a Chart from a file ( Chart1,'c:\demo.tee' ) }
Procedure LoadChartFromFile(Var AChart:TCustomChart; Const AFileName:String);
{ Write a Chart to a file ( Chart1,'c:\demo.tee' ) }
Procedure SaveChartToFile(AChart:TCustomChart; Const AFileName:String;
IncludeData:Boolean=True;
TextFormat:Boolean=False);
{ The same using TStream components (good for BLOB fields, etc) }
Procedure LoadChartFromStream(Var AChart:TCustomChart; AStream:TStream);
Procedure SaveChartToStream(AChart:TCustomChart; AStream:TStream;
IncludeData:Boolean=True;
TextFormat:Boolean=False);
{ (Advanced) Read charts and check for errors }
{ return True if ok, False to stop loading }
type TProcTeeCheckError=function(const Message: string): Boolean of object;
Procedure LoadChartFromStreamCheck( Var AChart:TCustomChart;
AStream:TStream;
ACheckError:TProcTeeCheckError=nil;
// For compatibility with version 5 saved
// charts.
// Pass FALSE to skip past-reading
TryReadData:Boolean=True // 6.01
);
Procedure LoadChartFromFileCheck( Var AChart:TCustomChart;
Const AName:String;
ACheckError:TProcTeeCheckError
);
// Convert a binary *.tee file to text format
Procedure ConvertTeeFileToText(Const InputFile,OutputFile:String);
// Convert a text *.tee file to binary format
Procedure ConvertTeeFileToBinary(Const InputFile,OutputFile:String);
type
TSeriesData=class(TTeeExportData)
private
FIncludeColors : Boolean;
FIncludeIndex : Boolean;
FIncludeHeader : Boolean;
FIncludeLabels : Boolean;
FChart : TCustomChart;
FSeries : TChartSeries;
IFormat : TeeFormatFlag;
Procedure Prepare;
protected
Function MaxSeriesCount:Integer;
Function PointToString(Index:Integer):String; virtual;
public
Constructor Create(AChart:TCustomChart; ASeries:TChartSeries=nil); virtual;
Function AsString:String; override;
property Chart:TCustomChart read FChart write FChart;
property IncludeColors:Boolean read FIncludeColors write FIncludeColors default False;
property IncludeHeader:Boolean read FIncludeHeader write FIncludeHeader default False;
property IncludeIndex:Boolean read FIncludeIndex write FIncludeIndex default False;
property IncludeLabels:Boolean read FIncludeLabels write FIncludeLabels default True;
property Series:TChartSeries read FSeries write FSeries;
end;
TSeriesDataText=class(TSeriesData)
private
FTextDelimiter : {$IFDEF CLX}WideChar{$ELSE}Char{$ENDIF};
protected
Function PointToString(Index:Integer):String; override;
public
Constructor Create(AChart:TCustomChart;
ASeries:TChartSeries=nil); override;
Function AsString:String; override;
property TextDelimiter:{$IFDEF CLX}WideChar{$ELSE}Char{$ENDIF}
read FTextDelimiter write FTextDelimiter default TeeTabDelimiter;
end;
TSeriesDataXML=class(TSeriesData)
public
Constructor Create(AChart:TCustomChart; ASeries:TChartSeries=nil); override;
Function AsString:String; override;
published
property IncludeHeader default True;
end;
TSeriesDataHTML=class(TSeriesData)
protected
Function PointToString(Index:Integer):String; override;
public
Function AsString:String; override;
end;
TSeriesDataXLS=class(TSeriesData)
public
Procedure SaveToStream(AStream:TStream); override;
end;
Const TeeTextLineSeparator= #13#10;
// Makes sure AFileName contains the ".tee" extension
Function TeeCheckExtension(Const AFileName:String):String;
implementation
Uses {$IFDEF CLX}
QGraphics, QClipbrd,
{$ELSE}
Graphics, Clipbrd,
{$ENDIF}
SysUtils, TeCanvas, TeeConst;
Const MagicTeeFile =$3060;
{$IFDEF D7}
VersionTeeFile=$0157; { Delphi 7 }
{$ELSE}
{$IFDEF CLX}
VersionTeeFile=$0145; { Delphi 6 CLX / Kylix }
{$ELSE}
{$IFDEF D6}
VersionTeeFile=$0150; { Delphi 6 }
{$ELSE}
{$IFDEF C5}
VersionTeeFile=$0140; { C++ Builder 5 }
{$ELSE}
{$IFDEF D5}
VersionTeeFile=$0130; { Delphi 5 }
{$ELSE}
{$IFDEF C4}
VersionTeeFile=$0125; { C++ Builder 4 }
{$ELSE}
{$IFDEF D4}
VersionTeeFile=$0120; { Delphi 4 }
{$ELSE}
{$IFDEF C3}
VersionTeeFile=$0110; { C++ Builder 3 }
{$ELSE}
VersionTeeFile=$0100; { Delphi 3 }
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$ENDIF}
type
TTeeFileHeader=Packed Record
Magic : Word; { secure checking }
Version : Word; { Chart file version }
end;
TSeriesAccess=class(TChartSeries);
// compatibility with previous versions saved *.tee files
Procedure ReadChartData(AStream:TStream; AChart:TCustomChart);
Var t : Integer;
begin { read each Series data }
for t:=0 to AChart.SeriesCount-1 do TSeriesAccess(AChart[t]).ReadData(AStream);
end;
{ Special reader to skip Delphi 3 or 4 new properties when
reading Charts in Delphi 1.0 or 2.0 }
type TChartReader=class(TReader)
protected
function Error(const Message: string): Boolean; override;
public
CheckError:TProcTeeCheckError;
end;
function TChartReader.Error(const Message: string): Boolean;
begin
if Assigned(CheckError) then result:=CheckError(Message)
else result:=True;
end;
function TeeFileIsValid(Stream:TStream):Boolean;
var Pos : Integer;
Header : TTeeFileHeader;
begin
Pos := Stream.Position;
Stream.Read(Header,SizeOf(Header));
{ check is a valid Tee file }
result:=Header.Magic=MagicTeeFile;
if not result then
result:=Char(Header.Magic) in ['o','O'];
Stream.Position := Pos;
end;
function TeeFileIsBinary(Stream:TStream):Boolean;
var Pos : Integer;
Header : TTeeFileHeader;
begin
Pos := Stream.Position;
Stream.Read(Header,SizeOf(Header));
{ check is a valid Tee file }
result:=Header.Magic=MagicTeeFile;
Stream.Position := Pos;
end;
Procedure TeeWriteHeader(AStream:TStream);
var Header : TTeeFileHeader;
begin
{ write file header, with "magic" number and version }
Header.Magic:=MagicTeeFile;
Header.Version:=VersionTeeFile;
AStream.Write(Header,SizeOf(Header));
end;
Procedure ConvertTeeToBinary(SInput,SOutput:TStream);
begin
if TeeFileIsValid(SInput) then
begin
if not TeeFileIsBinary(SInput) then
begin
TeeWriteHeader(SOutput);
ObjectTextToBinary(SInput,SOutput);
end
else
SOutput.CopyFrom(SInput,SInput.Size);
end
else Raise ChartException.Create(TeeMsg_WrongTeeFileFormat); { 5.01 }
end;
Procedure ConvertTeeToText(SInput,SOutput:TStream);
var Header : TTeeFileHeader;
begin
if TeeFileIsValid(SInput) then
begin
if TeeFileIsBinary(SInput) then
begin
SInput.Read(Header,SizeOf(Header));
ObjectBinaryToText(SInput,SOutput);
end
else SOutput.CopyFrom(SInput,SInput.Size);
end
else Raise ChartException.Create(TeeMsg_WrongTeeFileFormat); { 5.01 }
end;
{ Reads Series and Points from a Stream into a Chart }
Procedure LoadChartFromStreamCheck( Var AChart:TCustomChart;
AStream:TStream;
ACheckError:TProcTeeCheckError=nil;
TryReadData:Boolean=True);
var Reader : TChartReader;
tmp : TCustomChart;
tmpName : TComponentName;
DestStream : TStream;
Header : TTeeFileHeader;
begin
{ 5.01 commented: This allows saving more things to the AStream
before calling here.
AStream.Position:=0; <--- commented out
}
if AStream.Size=0 then
raise ChartException.Create(TeeMsg_EmptyTeeFile);
if TeeFileIsValid(AStream) then
begin
{ disable auto-repaint }
AChart.AutoRepaint:=False;
{ remove all child Series and Tools }
AChart.FreeAllSeries;
AChart.Tools.Clear;
DestStream:=AStream;
if not TeeFileIsBinary(AStream) then
begin
AStream:=TMemoryStream.Create;
ConvertTeeToBinary(DestStream,AStream);
AStream.Position:=0;
end;
AStream.Read(Header,SizeOf(Header));
{ read the Chart, Series and Tools properties }
Reader:=TChartReader.Create(AStream, 4096);
try
Reader.CheckError:=ACheckError;
tmp:=AChart;
try
tmpName:=tmp.Name; { 5.01 preserve the Chart Name }
Reader.ReadRootComponent(AChart);
finally
AChart:=tmp;
end;
if tmpName<>'' then
AChart.Name:=tmpName; { 5.01 set back the same Chart Name }
finally
Reader.Free;
end;
if Assigned(AChart) then
begin
// compatibility with previous versions saved *.tee files
// read the Series points
if TryReadData and (AStream.Size>AStream.Position) then
ReadChartData(AStream,AChart);
(*
{ change each Series ownership }
{ 5.01 Doing this breaks TeeFunction objects as DataSource !! }
if AChart.Owner<>nil then
for t:=0 to AChart.SeriesCount-1 do
begin
AChart[t].Owner.RemoveComponent(AChart[t]);
AChart.Owner.InsertComponent(AChart[t]);
end;
*)
{ restore AutoRepaint }
AChart.AutoRepaint:=True;
AChart.Invalidate;
end
else raise ChartException.Create(TeeMsg_InvalidTeeFile);
if DestStream<>AStream then AStream.Free;
end
else { is the Stream.Position maybe not zero ? }
raise ChartException.Create(TeeMsg_WrongTeeFileFormat);
end;
Procedure LoadChartFromStream(Var AChart:TCustomChart; AStream:TStream);
begin
LoadChartFromStreamCheck(AChart,AStream);
end;
Function TeeCheckExtension(Const AFileName:String):String;
begin // Append ".tee" to filename if the extension is missing
if ExtractFileExt(AFileName)='' then
result:=AFileName+'.'+TeeMsg_TeeExtension
else
result:=AFileName;
end;
Procedure LoadChartFromFileCheck( Var AChart:TCustomChart;
Const AName:String;
ACheckError:TProcTeeCheckError );
Var tmp : TFileStream;
begin
tmp:=TFileStream.Create(TeeCheckExtension(AName),fmOpenRead or fmShareDenyWrite);
try
LoadChartFromStreamCheck(AChart,tmp,ACheckError);
finally
tmp.Free;
end;
end;
Procedure LoadChartFromFile(Var AChart:TCustomChart; Const AFileName:String);
begin
LoadChartFromFileCheck(AChart,AFileName,nil);
end;
Procedure ConvertTeeFile(Const InputFile,OutputFile:String; ToText:Boolean);
var SInput : TFileStream;
SOutput : TFileStream;
begin
SInput:=TFileStream.Create(InputFile,fmOpenRead);
try
SOutput:=TFileStream.Create(OutputFile,fmCreate);
try
if ToText then ConvertTeeToText(SInput,SOutput)
else ConvertTeeToBinary(SInput,SOutput);
finally
SOutput.Free;
end;
finally
SInput.Free;
end;
end;
{ Create a text file from a binary *.tee file }
Procedure ConvertTeeFileToText(Const InputFile,OutputFile:String);
begin
ConvertTeeFile(InputFile,OutputFile,True);
end;
{ Create a binary file from a text *.tee file }
Procedure ConvertTeeFileToBinary(Const InputFile,OutputFile:String);
begin
ConvertTeeFile(InputFile,OutputFile,False);
end;
{
Procedure WriteChartData(AStream:TStream; AChart:TCustomChart);
Var t : Integer;
begin
for t:=0 to AChart.SeriesCount-1 do TSeriesAccess(AChart[t]).WriteData(AStream);
end;
}
{$IFDEF D5}
type TWriterAccess=class(TWriter);
{$ENDIF}
Procedure SaveChartToStream(AChart:TCustomChart; AStream:TStream;
IncludeData:Boolean=True;
TextFormat:Boolean=False);
var tmp : TCustomChart;
OldName : TComponentName;
{$IFDEF D5}
Writer : TWriter;
tmpOwner : TComponent;
{$ENDIF}
DestStream : TStream;
t : Integer;
begin
DestStream:=AStream;
if TextFormat then AStream:=TMemoryStream.Create;
TeeWriteHeader(AStream);
{ write the Chart, Series and Tools properties }
tmp:=AChart;
if not (csDesigning in AChart.ComponentState) then
begin
OldName:=AChart.Name;
AChart.Name:='';
end;
for t:=0 to AChart.SeriesCount-1 do
with TSeriesAccess(AChart[t]) do
if IncludeData then ForceSaveData:=True
else DontSaveData:=True;
try
{$IFDEF D5}
Writer := TWriter.Create(AStream, 4096);
try
tmpOwner:=AChart.Owner;
if not Assigned(tmpOwner) then tmpOwner:=AChart;
TWriterAccess(Writer).SetRoot(tmpOwner); { 5.01 }
Writer.WriteSignature;
Writer.WriteComponent(AChart);
finally
Writer.Free;
end;
{$ELSE}
AStream.WriteComponent(AChart);
{$ENDIF}
finally
for t:=0 to AChart.SeriesCount-1 do
with TSeriesAccess(AChart[t]) do
begin
ForceSaveData:=False;
DontSaveData:=False;
end;
end;
AChart:=tmp;
if not (csDesigning in AChart.ComponentState) then
AChart.Name:=OldName;
{ write the Series data points }
//if IncludeData then WriteChartData(AStream,AChart);
if TextFormat then
begin
AStream.Position:=0;
ConvertTeeToText(AStream,DestStream);
AStream.Free;
end;
end;
Procedure SaveChartToFile(AChart:TCustomChart; Const AFileName:String;
IncludeData:Boolean=True;
TextFormat:Boolean=False);
Var tmp : TFileStream;
begin
tmp:=TFileStream.Create(TeeCheckExtension(AFileName),fmCreate);
try
SaveChartToStream(AChart,tmp,IncludeData,TextFormat);
finally
tmp.Free;
end;
end;
Function ColorToHex(Color:TColor):String;
begin
with RGBValue(ColorToRGB(Color)) do
result:=Format('#%.2x%.2x%.2x',[rgbtRed,rgbtGreen,rgbtBlue]);
end;
{ TSeriesData }
Constructor TSeriesData.Create(AChart:TCustomChart; ASeries:TChartSeries=nil);
begin
inherited Create;
FChart:=AChart;
FSeries:=ASeries;
FIncludeLabels:=True;
end;
Procedure TSeriesData.Prepare;
var tmp : TChartSeries;
begin
if Assigned(FSeries) then tmp:=FSeries
else if FChart.SeriesCount>0 then tmp:=Chart[0]
else tmp:=nil;
if Assigned(tmp) then IFormat:=SeriesGuessContents(tmp);
if not IncludeLabels then Exclude(IFormat,tfLabel);
if not IncludeColors then Exclude(IFormat,tfColor);
end;
Function TSeriesData.AsString:String;
Var tmp : Integer;
t : Integer;
begin
Prepare;
result:='';
tmp:=MaxSeriesCount;
for t:=0 to tmp-1 do result:=result+PointToString(t)+TeeTextLineSeparator;
end;
Function TSeriesData.MaxSeriesCount:Integer;
var t : Integer;
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -