You've already forked lazarus-ccr
158 lines
4.5 KiB
ObjectPascal
158 lines
4.5 KiB
ObjectPascal
![]() |
unit GridProcs;
|
||
|
|
||
|
{$mode objfpc}{$H+}
|
||
|
|
||
|
interface
|
||
|
|
||
|
uses
|
||
|
Classes, SysUtils, Grids,
|
||
|
Globals, DictionaryUnit;
|
||
|
|
||
|
function CollectValues(AGrid: TStringGrid; AColIndex: Integer;
|
||
|
AColCheck: IntDyneVec): DblDyneVec;
|
||
|
|
||
|
procedure GetMinMax(AGrid: TStringGrid; AColIndex: Integer;
|
||
|
const AColCheck: IntDyneVec; out AMin, AMax: Double);
|
||
|
|
||
|
function GoodRecord(AGrid: TStringGrid; ARow: integer;
|
||
|
const AColCheck: IntDyneVec): boolean;
|
||
|
|
||
|
function IsEmptyNumericValue(AGrid: TStringGrid; ARow, ACol: Integer): Boolean;
|
||
|
|
||
|
function IsFiltered(AGrid: TStringGrid; ARow: integer): boolean;
|
||
|
|
||
|
function IsMissingValueCode(AGrid: TStringGrid; ARow, ACol: Integer): Boolean;
|
||
|
|
||
|
function ValidValue(AGrid: TStringGrid; ARow, ACol: integer): boolean;
|
||
|
|
||
|
|
||
|
implementation
|
||
|
|
||
|
uses
|
||
|
Math;
|
||
|
|
||
|
{ Extracts the values in the given column from the grid and returns them as an
|
||
|
array.
|
||
|
Cells which are filtered or empty are not considered. This check is extended
|
||
|
over all columns specified by the column indices in AColCheck; AColCheck
|
||
|
should be empty to consider only the current column.
|
||
|
Non-numeric values in the considered cell will raise an exception.
|
||
|
|
||
|
NOTE: AColCheck must not be overdimensioned! }
|
||
|
function CollectValues(AGrid: TStringGrid; AColIndex: Integer; AColCheck: IntDyneVec): DblDyneVec;
|
||
|
var
|
||
|
row, n: Integer;
|
||
|
begin
|
||
|
SetLength(Result, AGrid.RowCount);
|
||
|
n := 0;
|
||
|
for row := 1 to AGrid.RowCount-1 do
|
||
|
begin
|
||
|
if Length(AColCheck) = 0 then
|
||
|
begin
|
||
|
if not ValidValue(AGrid, row, AColIndex) then continue;
|
||
|
end else
|
||
|
begin
|
||
|
if not GoodRecord(AGrid, row, AColCheck) then continue;
|
||
|
end;
|
||
|
Result[n] := StrToFloat(trim(AGrid.Cells[AColIndex, row]));
|
||
|
inc(n);
|
||
|
end;
|
||
|
SetLength(Result, n);
|
||
|
end;
|
||
|
|
||
|
|
||
|
{ Determines the minimum and maximum of the values in the specified column of
|
||
|
the grid. Rows with "invalid" data are ignored. If AColCheck contains other
|
||
|
column indices these cells must be "valid", too. }
|
||
|
procedure GetMinMax(AGrid: TStringGrid; AColIndex: Integer;
|
||
|
const AColCheck: IntDyneVec; out AMin, AMax: Double);
|
||
|
var
|
||
|
row: Integer;
|
||
|
value: Double;
|
||
|
begin
|
||
|
AMin := Infinity;
|
||
|
AMax := -Infinity;
|
||
|
for row := 1 to AGrid.RowCount-1 do
|
||
|
begin
|
||
|
if Length(AColCheck) = 0 then
|
||
|
begin
|
||
|
if not ValidValue(AGrid, row, AColIndex) then continue;
|
||
|
end else
|
||
|
begin
|
||
|
if not GoodRecord(AGrid, row, AColCheck) then continue;
|
||
|
end;
|
||
|
value := StrToFloat(trim(AGrid.Cells[AColIndex, row]));
|
||
|
if value < AMin then AMin := value;
|
||
|
if value > AMax then AMax := value;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
|
||
|
{ Checks whether all cells specified for the given row in the columns listed in
|
||
|
the GridPos array are "valid": not filtered and not empty }
|
||
|
function GoodRecord(AGrid: TStringGrid; ARow: integer;
|
||
|
const AColCheck: IntDyneVec): boolean;
|
||
|
var
|
||
|
i, j: integer;
|
||
|
begin
|
||
|
Result := true;
|
||
|
for i := 0 to High(AColCheck) do
|
||
|
begin
|
||
|
j := AColCheck[i];
|
||
|
if not ValidValue(AGrid, ARow, j) then
|
||
|
Result := false;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
|
||
|
{ Checks whether the cell in the given row in the given numeric column is empty. }
|
||
|
function IsEmptyNumericValue(AGrid: TStringGrid; ARow, ACol: Integer): Boolean;
|
||
|
var
|
||
|
value: String;
|
||
|
isStringField: Boolean;
|
||
|
begin
|
||
|
value := Trim(AGrid.Cells[ACol, ARow]);
|
||
|
isStringField := DictionaryFrm.DictGrid.Cells[4, ACol] = 'S';
|
||
|
Result := not IsStringField and (value = '');
|
||
|
end;
|
||
|
|
||
|
|
||
|
{ Checks whether the specified row is "filtered". Two criteria are needed for
|
||
|
a row to be filtered:
|
||
|
- The cell in column FilterCol (global value) must contain the text 'NO'.
|
||
|
- The global variable "FilterOn" must be TRUE. }
|
||
|
function IsFiltered(AGrid: TStringGrid; ARow: integer): boolean;
|
||
|
begin
|
||
|
Result := FilterOn and (Trim(AGrid.Cells[FilterCol, ARow]) = 'NO');
|
||
|
end;
|
||
|
|
||
|
|
||
|
{ Checks whether specified cell contains the "missing value code" defined by
|
||
|
the Dictionary }
|
||
|
function IsMissingValueCode(AGrid: TStringGrid; ARow, ACol: Integer): Boolean;
|
||
|
var
|
||
|
missingCode: String;
|
||
|
value: String;
|
||
|
begin
|
||
|
missingCode := Trim(DictionaryFrm.DictGrid.Cells[6, ACol]);
|
||
|
value := Trim(AGrid.Cells[ACol, ARow]);
|
||
|
Result := (value = missingCode);
|
||
|
end;
|
||
|
|
||
|
|
||
|
{ Checks wheter the value in cell at the given column and row is a not-filtered,
|
||
|
non-empty number.
|
||
|
NOTE: non-numeric characters in a numeric field are not taken into account! }
|
||
|
function ValidValue(AGrid: TStringGrid; ARow, ACol: integer): boolean;
|
||
|
begin
|
||
|
Result := not (
|
||
|
IsFiltered(AGrid, ARow) or // filtering is active and row is marked to be excluded
|
||
|
IsEmptyNumericValue(AGrid, ARow, aCol) or // column is numeric, but cell is empty
|
||
|
IsMissingValueCode(AGrid, ARow, ACol) // cell contains the "missing value code"
|
||
|
);
|
||
|
end;
|
||
|
|
||
|
|
||
|
end.
|
||
|
|