home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 December
/
Chip_2001-12_cd1.bin
/
zkuste
/
delphi
/
kolekce
/
d56
/
DM2KVCL.ZIP
/
WORKGRID.PAS
< prev
Wrap
Pascal/Delphi Source File
|
2000-12-31
|
23KB
|
516 lines
{****************************************************************************}
{ Data Master 2000 }
{****************************************************************************}
unit WorkGrid;
{$B-,X+}
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Grids, ClipBrd, Common, Data, Math;
type
TWorksheet=class(TDrawGrid)
private
FContainer: TContainer;
FBlockColorF, FBlockColorB: TColor;
FAlignRight: boolean; {align number by right of cell}
FDrawHeaders: boolean; {draw or not column headers & line numbers}
FHeader: TStringList; {keeps column headers}
procedure SetContainer(C: TContainer); {also updates grid size!}
procedure SetBlockColorF(C: TColor); {refresh cells}
procedure SetBlockColorB(C: TColor); {-#-}
procedure SetAlignRight(B: boolean); {-#-}
procedure SetDrawHeaders(B: boolean); {-#-}
function GetHeader: TStrings;
procedure SetHeader(const Value: TStrings);
procedure StringsChanged(Sender: TObject);
protected
procedure DrawCell(ACol, ARow: Longint; ARect: TRect;
AState: TGridDrawState); override;
procedure MouseDown(Btn: TMouseButton; {added selection}
Shift: TShiftState; X,Y: Integer); override;
function SelectCell(ACol, ARow: Longint): Boolean; override;
function GetEditText(ACol, ARow: Longint): string; override;
procedure SetEditText(ACol, ARow: Longint; const Value: string); override;
procedure KeyDown(var Key: Word; Shift: TShiftState); override; {edit}
public
constructor Create(AOwner: TComponent); override;
procedure UpdateSize; {update col/row numbers after setcontainer}
procedure CopyToClipBoard(UseTabs: boolean); {copy selection as text}
procedure PasteFromClipBoard(InsertLines,Overwrite: boolean);
procedure Delete; {delete selected cells}
procedure AlignTextOut(ARect: TRect; ss: string); {useful in OnDrawCell}
destructor Destroy; override; {disposes off headers}
procedure SelectAll;
published
property Container: TContainer read FContainer write SetContainer;
property BlockColorF: TColor read FBlockColorF write SetBlockColorF;
property BlockColorB: TColor read FBlockColorB write SetBlockColorB;
property AlignRight: boolean read FAlignRight write SetAlignRight;
property DrawHeaders: boolean read FDrawHeaders write SetDrawHeaders;
property Header: TStrings read GetHeader write SetHeader;
end;
procedure Register; {note that this component requires TDataContainer!}
implementation
procedure TWorksheet.DrawCell(ACol, ARow: Longint; ARect: TRect;
AState: TGridDrawState);
var S: string; D: TData;
begin
if (ACol<FixedCols) or (ARow<FixedRows) then {draw fixed area}
if FDrawHeaders then {if fixed cells used, draw headers}
begin
if (ARow=0) and (ACol>=FixedCols) {draw column headers}
and (ACol-FixedCols<FHeader.Count) then
AlignTextOut(ARect, FHeader[ACol-FixedCols]);
if (Acol=0) and (Arow=0) then {draw "select all button"}
begin
Canvas.Brush.Color:=FBlockColorB;
ARect.Left:=ARect.Left+2; ARect.Right:=ARect.Right-2;
ARect.Top:=ARect.Top+2; ARect.Bottom:=ARect.Bottom-2;
Canvas.FillRect(ARect); Exit;
end;
if (ACol=0) and (ARow>=FixedRows) then {draw line number}
AlignTextOut(ARect,IntToStr(ARow-FixedRows));
if (ACol>0) and (ARow>0) then {draw OTHER fixed cells!}
inherited DrawCell(ACol, ARow, ARect, AState);
end
else inherited DrawCell(ACol, ARow, ARect, AState) else
begin {draw other (non-fixed) cells}
if (not Assigned(FContainer)) or (ARow>=FixedRows+FContainer.Items.Count)
then begin inherited DrawCell(ACol, ARow, ARect, AState); Exit; end;
D:=FContainer.Items[ARow-FixedRows]; {get data}
ACol:=ACol-FixedCols; {correct to data area}
if gdSelected in AState then {correct colors}
begin
Canvas.Brush.Color:=FBlockColorB; Canvas.FillRect(ARect);
Canvas.Font.Color:=FBlockColorF;
end;
if (D is TFunction) and (ACol<2) then {function or derivatives:}
begin
if ACol=0 then S:=FloatToStr((D as TFunction).X)
else S:=FloatToStr((D as TFunction).Y);
end;
if (D is TRealData) and (ACol<MaxCols) then
S:=(D as TRealData).GetItemText(ACol+1); {realdata: ACol m.b. > NumCol!}
if not ((D is TRealData) or (D is TFunction))
then S:=WordStr(D.Data, ACol+1); {other: try to display as words}
AlignTextOut(ARect,S);
end;
end;
procedure TWorksheet.UpdateSize; {updates row/column numbers}
begin
if Assigned(FContainer) then
begin
if FContainer.DataType=dtFunction then ColCount:=FixedCols+2;
if FContainer.DataType=dtRealData then ColCount:=FixedCols+MaxCols;
RowCount:=FContainer.Items.Count+1+FixedRows; {one extra line for edit}
end;
Invalidate;
end;
constructor TWorksheet.Create(AOwner: TComponent); {init new fields}
begin
inherited Create(AOwner);
Options:=[goFixedVertLine,goFixedHorzLine,goVertLine,goHorzLine,
goThumbTracking,goColSizing{,goRowSelect,goEditing},goRangeSelect];
FBlockColorF:=clYellow; FBlockColorB:=Color;
DefaultDrawing:=true; FAlignRight:=false; DrawHeaders:=false;
FHeader:=TStringList.Create; FHeader.OnChange:=StringsChanged;
end;
destructor TWorksheet.Destroy;
begin if Assigned(FHeader) then FHeader.Free; inherited; end;
procedure TWorksheet.SetDrawHeaders(B: boolean);
begin if B<>FDrawHeaders then begin FDrawHeaders:=B; Invalidate; end; end;
function TWorksheet.GetHeader: TStrings;
begin Result:=FHeader; end;
procedure TWorksheet.SetHeader(const Value: TStrings);
begin if Assigned(FHeader) then FHeader.Assign(Value); end;
procedure TWorksheet.StringsChanged(Sender: TObject);
begin if Sender=FHeader then Invalidate; end;
procedure TWorksheet.CopyToClipBoard(UseTabs: boolean);
var
D: TData; S,Ss: string; SL: TStringList; LC,CC,Btm: integer;
Data: pointer; HData: THandle; MS: TMemoryStream; L,R,N,I: integer; X:TReal;
begin
if not Assigned(FContainer) or (FContainer.Items.Count<1) then Exit;
Btm:=Selection.Bottom; if Btm=RowCount-1 then Btm:=RowCount-2; {correct}
Screen.Cursor:=crHourGlass;
SL:=TStringList.Create; {allocate and clear buffer}
MS:=TMemoryStream.Create; {create buffer for RealDataFormat}
try
LC:=0; MS.Write(LC, SizeOf(LC)); {write line counter}
for LC:=Selection.Top to Btm do {row cycle}
begin
S:='';
if Btm>Selection.Top then {may be one cell!}
FContainer.ShowProgress(Round((LC-Selection.Top)*100
/(Btm-Selection.Top))); {show progress of copy}
D:=FContainer.Items[LC-FixedRows];
if D is TRealData then {add realdata to buffer stream}
begin
L:=Selection.Left-FixedCols+1; R:=Selection.Right-FixedCols+1;
if (D as TRealData).Size>R then N:=R else N:=(D as TRealData).Size;
I:=N-L+1; MS.Write(I, SizeOf(I));
for CC:=L to N do
begin X:=(D as TRealData).RData[CC]; MS.Write(X, SizeOf(X)); end;
integer(MS.Memory^):=integer(MS.Memory^)+1; {increment line counter}
end;
for CC:=Selection.Left to Selection.Right do {column cycle}
begin
if D is TRealData then
SS:=(D as TRealData).GetItemText(CC-FixedCols+1);
if D is TFunction then if CC=FixedCols
then SS:=FloatToStr((D as TFunction).X)
else SS:=FloatToStr((D as TFunction).Y);
if not ((D is TRealData) or (D is TFunction)) then
begin S:=D.Data; Break; end; {no columns!!!}
if SS<>'' then if S<>'' then {Tabs for Origin, spaces for Grapher}
if UseTabs then S:=S+#9+Ss else S:=S+' '+Ss else S:=SS;
end; {now in S-data string!}
SL.Add(S); {add to buffer}
end;
ClipBoard.Open; {copy to clipboard}
try
ClipBoard.AsText:=SL.Text;
if integer(MS.Memory^)>0 then
begin
HData:=GlobalAlloc(GMEM_MOVEABLE+GMEM_DDESHARE, MS.Size);
try
Data:=GlobalLock(HData);
try
Move(MS.Memory^, Data^, MS.Size);
SetClipboardData(TRealData.GetClipboardFormat, HData);
finally
GlobalUnlock(HData);
end;
except
GlobalFree(HData); raise;
end;
end;
finally
ClipBoard.Close;
end;
finally
MS.Free; SL.Free;
Screen.Cursor:=crDefault;
end;
end;
procedure TWorksheet.PasteFromClipBoard(InsertLines,Overwrite: boolean);
var H: THandle; Buf: PChar; S: TStringList; I,J,N,N1,SL: integer; D: TData;
s1,s2,s3: string; R,R1: TRealArray;
{$ifndef PasteRowCol}Row,Col: integer;{$endif}
MS: TMemoryStream; NN,Mn: integer;
begin
{$ifndef PasteRowCol}Row:=Selection.Top; Col:=Selection.Left;{$endif}
if Clipboard.HasFormat(TRealData.GetClipboardFormat)
and (Container.DataType=dtRealData) then
begin{first try "native" RealDataFormat-only for appropriate container type}
Clipboard.Open;
try
H:=GetClipboardData(TRealData.GetClipboardFormat);
if H=0 then Exit; Buf:=GlobalLock(H); if Buf=nil then Exit;
try
MS:=TMemoryStream.Create;
try
MS.WriteBuffer(Buf^, GlobalSize(H));
MS.Position:=0; MS.Read(NN, SizeOf(NN));
if NN>0 then
begin
Screen.Cursor:=crHourGlass;
try
for I:=0 to NN-1 do
begin
if NN>1 then Container.ShowProgress(Round(I/(NN-1)*100));
MS.Read(N, SizeOf(N));
for J:=1 to N do MS.Read(R[J], SizeOf(R[J]));
if InsertLines then
begin
D:=Container.InitItem; (D as TRealData).SetRData(N,R);
if Row-FixedRows<Container.Items.Count then
Container.Items.Insert(Row+I-FixedRows, D)
else Container.Items.Add(D);
RowCount:=RowCount+1;
end else
if (Row-FixedRows<Container.Items.Count) and
(I<Container.Items.Count-Row+FixedRows) then
begin
D:=FContainer.Items[Row-FixedRows+I]; SL:=Col-FixedCols;
N1:=(D as TRealData).GetRData(R1);
if Overwrite then
begin
Mn:=Min(N,MaxCols-SL);
for J:=1 to Mn do R1[J+SL]:=R[J];
(D as TRealData).SetRData(Max(Mn+SL,N1),R1);
end else
begin
for J:=Min(N1, MaxCols-N-SL) downto SL+1 do
R1[J+N]:=R1[J];
for J:=1 to Min(N, MaxCols-SL) do R1[J+SL]:=R[J];
(D as TRealData).SetRData(Min(N+N1,MaxCols),R1);
end
end else
begin {the end of container reached or last cell selected}
D:=FContainer.InitItem; (D as TRealData).SetRData(N,R);
FContainer.Items.Add(D); RowCount:=RowCount+1;
end;
end;
finally
Screen.Cursor:=crDefault; ReFresh; Container.Modified:=true;
end;
end;
finally
MS.Free;
end;
finally
GlobalUnlock(H);
end;
finally
Clipboard.Close;
end;
Exit;
end;
if not Clipboard.HasFormat(CF_TEXT) then Exit; {no text in clipboard!}
Clipboard.Open; H:=GetClipboardData(CF_TEXT); {get clp data handler}
Buf:=GlobalLock(H); {must be locked}
S:=TStringList.Create; Screen.Cursor:=crHourGlass;
try
S.SetText(Buf); {copy to stringlist (divide into lines!)}
for I:=0 to S.Count-1 do
begin
if S.Count>1 then FContainer.ShowProgress(Round(I/(S.Count-1)*100));
if InsertLines then {insert all lines into container}
begin
D:=FContainer.InitItem; D.Data:=S[I];
if Row-FixedRows<FContainer.Items.Count then
FContainer.Items.Insert(Row+I-FixedRows, D)
else FContainer.Items.Add(D);
RowCount:=RowCount+1;
end else
if (Row-FixedRows<FContainer.Items.Count) and
(I<FContainer.Items.Count-Row+FixedRows) then
begin
D:=FContainer.Items[Row-FixedRows+I]; SL:=Col-FixedCols; {SL: 0..n!}
if D is TRealData then {avoid precision loss due to string conversion}
begin
N:=Str2Real(S[I], R1);
if ((not Overwrite) and ((D as TRealData).Size+N>MaxCols)) or
(Overwrite and (SL+N>MaxCols)) then
raise ERealDataError.Create(errInsItem); {check for number count!}
N1:=(D as TRealData).GetRData(R);
for J:=1 to N do R[SL+J]:=R1[J];
if not Overwrite then
for J:=SL+1 to N1 do R[J+N]:=(D as TRealData).RData[J];
if Overwrite then (D as TRealData).SetRData(Max(SL+N,N1),R)
else (D as TRealData).SetRData((D as TRealData).Size+N,R);
end else
begin {convert data to string and insert S[I]}
s1:=D.Data; s2:=''; s3:='';
for J:=1 to SL do s2:=s2+' '+WordStr(s1, J);
for J:=SL+1 to NumWords(s1) do s3:=s3+' '+WordStr(s1, J);
if Overwrite then
begin
s2:=s2+' '+S[I];
for J:=NumWords(s2)+1 to NumWords(s1) do s2:=s2+' '+WordStr(s1,J);
D.Data:=s2;
end else D.Data:=s2+' '+S[I]+' '+s3;
end;
end else
begin {the end of container reached or last cell selected}
D:=FContainer.InitItem; D.Data:=S[I];
FContainer.Items.Add(D); RowCount:=RowCount+1; {=> we should add data}
end; {parasitic scroll^ may be here if lines inserted!}
end;{for I:=...}
finally
GlobalUnlock(H); S.Free; Clipboard.Close; {free resources}
Screen.Cursor:=crDefault; ReFresh; FContainer.Modified:=true;
end;
end;
procedure TWorksheet.SetContainer(C: TContainer);
begin FContainer:=C; UpdateSize; end;
procedure TWorksheet.SetBlockColorF(C: TColor);
begin FBlockColorF:=C; Invalidate; end;
procedure TWorksheet.SetBlockColorB(C: TColor);
begin FBlockColorB:=C; Invalidate; end;
procedure TWorksheet.SetAlignRight(B: boolean);
begin FAlignRight:=B; Invalidate; end;
function TWorksheet.SelectCell(ACol, ARow: Longint): Boolean;
var D: TData;
begin
Result:=true; if not Assigned(FContainer) then {no data}
begin Result:=inherited SelectCell(ACol, ARow); Exit; end;
ACol:=ACol-FixedCols; ARow:=ARow-FixedRows; {data area coords}
if ARow>FContainer.Items.Count-1
then Result:=ACol<1 else {last row (for insert)}
begin
D:=FContainer.Items[ARow];
if D is TFunction then Result:=ACol<2;
if D is TRealData then Result:=ACol<=(D as TRealData).Size;
end;
end;
function TWorksheet.GetEditText(ACol, ARow: Longint): string;
var D: TData;
begin {NOTE: support events!}
if not Assigned(FContainer) or (ARow-FixedRows>FContainer.Items.Count-1)
then Result:=inherited GetEditText(ACol, ARow) else
begin
D:=FContainer.Items[ARow-FixedRows];
if not ((D is TRealData) or (D is TFunction)) then
Result:=inherited GetEditText(ACol, ARow);
ACol:=ACol-FixedCols; {if D - func or arrray...}
if D is TFunction then
if ACol=0 then Result:=FloatToStr((D as TFunction).X)
else Result:=FloatToStr((D as TFunction).Y);
if D is TRealData then Result:=(D as TRealData).GetItemText(ACol+1);
end;
end;
procedure TWorksheet.SetEditText(ACol, ARow: Longint; const Value: string);
var R: TReal; Flag: integer; D: TData;
begin {NOTE: support events!}
if not Assigned(FContainer) or (ARow-FixedRows>FContainer.Items.Count-1)
then inherited SetEditText(ACol, ARow, Value) else
begin
Val(Value, R, Flag); if Flag<>0 then Exit; {unable digitize text!}
D:=FContainer.Items[ARow-FixedRows];
if not ((D is TRealData) or (D is TFunction)) then
inherited SetEditText(ACol, ARow, Value);
ACol:=ACol-FixedCols; {Note: ACol points data area}
try {WARNING: may be errors!}
if D is TFunction then
if ACol=0 then (D as TFunction).X:=R else (D as TFunction).Y:=R;
if D is TRealData then with (D as TRealData) do
if ACol<Size then SetItem(ACol+1, R) else InsItem(R);
finally
FContainer.Modified:=true; {NOTE: editing CHANGES data!}
end;{try}
end;
end;
procedure TWorksheet.KeyDown(var Key: Word; Shift: TShiftState);
var D: TRealData; // this method extends functions of built-in inplace editor
begin
if not (Assigned(FContainer) and (goEditing in Options)) then
begin inherited KeyDown(Key, Shift); Exit; end; {no edition if no container}
case Key of
vk_Delete: if (Row<FContainer.Items.Count+FixedRows) {not last cell!}
then if ssShift in Shift then {Shift+DEL-delete row}
begin
if FContainer.Items.Count=0 then Exit; {list is empty!}
D:=FContainer.Items[Row-FixedRows];
D.Free; FContainer.Items.Remove(D);
RowCount:=RowCount-1;
end else {Alt+DEL delete item}
begin
D:=FContainer.Items[Row-FixedRows];
if not (D is TRealData) then Exit; {only TRealData!}
try
if (ssAlt in Shift) then D.DelItem(Col+1-FixedCols);
except
raise; Exit;
end;
end
else Exit;
vk_Insert: if ssShift in Shift then begin {Shift+INS - insert row}
if Row-FixedRows<FContainer.Items.Count then
FContainer.Items.Insert(Row-FixedRows, FContainer.InitItem)
else FContainer.Items.Add(FContainer.InitItem);
RowCount:=RowCount+1;
end else Exit;
else begin inherited KeyDown(Key, Shift); Exit; end; {allow inherited}
end;{case} {note: Exit-no modification!}
Invalidate; FContainer.Modified:=true;
end;
procedure TWorksheet.MouseDown(Btn: TMouseButton; Shift: TShiftState;
X,Y: Integer);
var Col, Row: longint;
begin
inherited MouseDown(Btn,Shift,X,Y); {allow inherited behavior}
if (not FDrawHeaders) or (not Assigned(FContainer)) or (FixedCols=0)
or (FixedRows=0) then Exit; {unable or nothing to select!}
MouseToCell(X,Y,Col,Row); {what cell clicked?}
if (Col=0) and (Row=0) then SelectAll;
end;
procedure TWorksheet.AlignTextOut(ARect: TRect; ss: string);
var X,Y,L: integer; {makes textout using AlignRight}
begin
if ss='' then Exit; {nothing to output!}
X:=ARect.Left+GridLineWidth-Font.Height div 2; {calc position}
Y:=ARect.Top+(RowHeights[Row]+Font.Height) div 2;
if AlignRight then
begin
L:=Canvas.TextWidth(Ss);
if ARect.Right-X-L>0 then X:=ARect.Right-X-L+ARect.Left;
end;
Canvas.TextOut(X, Y, Ss);
end;
procedure TWorksheet.Delete;
var BegItem,EndItem,Item,N,J,SL,SR,SR1: integer; s1,s2,s3: string; D: TData;
begin
if not Assigned(FContainer) or (FContainer.Items.Count<1) then Exit;
Screen.Cursor:=crHourGlass;
try
BegItem:=Selection.Top-FixedRows; EndItem:=Selection.Bottom-FixedRows;
SL:=Selection.Left-FixedCols+1; SR:=Selection.Right-FixedCols+1; {1..N!}
Item:=BegItem; if EndItem>FContainer.Items.Count-1
then EndItem:=FContainer.Items.Count-1; {correct}
while Item<=EndItem do
begin
D:=Container.Items[Item];
if D is TRealData then N:=(D as TRealData).Size else N:=NumWords(D.Data);
if (SL=1) and (SR>=N) then {all item data selected => delete whole item}
begin Container.Items.Delete(Item); Dec(EndItem); end else
begin
if D is TRealData then
begin {real data:}
if SR>N then SR1:=N else SR1:=SR;
for J:=1 to SR1-SL+1 do (D as TRealData).DelItem(SL);
end else
begin {string:}
s1:=D.Data; s2:=''; s3:='';
for J:=1 to SL-1 do s2:=s2+' '+WordStr(s1, J);
for J:=SR+1 to N do s3:=s3+' '+WordStr(s1, J);
D.Data:=s2+' '+s3;
end;
Inc(Item);
end;
end;
UpdateSize; LeftCol:=FixedCols; {here - clear selection?}
finally
Screen.Cursor:=crDefault; FContainer.Modified:=true;
end;
end;
procedure TWorksheet.SelectAll;
var R: TGridRect; // select all container items like in spreadsheets
begin
R.Left:=FixedCols; R.Right:=ColCount-1; R.Top:=FixedRows;
R.Bottom:=FContainer.Items.Count+FixedRows-1;
if Assigned(FContainer) and (FContainer.Items.Count>0) then Selection:=R;{!}
end;
{component registration - this unit may be used separately from dm2000}
procedure Register;
begin RegisterComponents('DM2000', [TWorksheet]); end;
end.