Hi Boki

I have been playing with SearchNext() some more and there are still problems in the way it's been implemented.

For example:

When the SearchNext() function reaches the last row a grid, it automatically "rolls over" to the first row of the grid and continues the search.

The following code will always cause an endless loop:

CODE

while SearcNext() do

....

because even if there is only one row in the grid that matches the search criteria, it will keep finding the same row over and over again.

Take a look at these changes:

CODE

TSearchOptions = set of (soCaseInsensitive, soPartialKey);

CODE

function Roll(FromRow, ToRow: Integer; SearchOptions: TSearchOptions): Boolean;

var

i: Integer;

begin

Result := False;

for i := FromRow to ToRow do

begin

if soCaseInsensitive in SearchOptions then

begin

if soPartialKey in SearchOptions then

Result := WideCompareText(LeftStr(Cells[ColumnIndex, i], Length(Value)) , Value) = 0

else

Result := WideCompareText(Cells[ColumnIndex, i], Value) = 0;

end

else

begin

if soPartialKey in SearchOptions then

Result := WideCompareStr(LeftStr(Cells[ColumnIndex, i], Length(Value)) , Value) = 0

else

Result := WideCompareStr(Cells[ColumnIndex, i], Value) = 0;

end;

if Result then

begin

SelectedRow := i;

if not IsUpdating then ScrollToRow(i);

Break;

end;

end;

end;

I can now choose whether or not I want partial matches, and I can specify whether or not the search should be case-sensitive.

CODE

function TNxCustomGrid.SearchFirst(ColumnIndex: Integer; Value: WideString;

SearchOptions: TSearchOptions = []): Boolean;

begin

Result := False;

if RowCount = 0 then Exit;

Result := Roll(0, Pred(RowCount), SearchOptions);

end;

SearchFirst always starts from the first row, and then searches for the first match (if any).

CODE

function TNxCustomGrid.SearchNext(ColumnIndex: Integer; Value: WideString;

SearchOptions: TSearchOptions = []): Boolean;

begin

Result := False;

if RowCount = 0 then Exit;

Result := Roll(Succ(SelectedRow), Pred(RowCount), SearchOptions);

end;

SearcNext always starts at Succ(SelectedRow) and then searches

**only to the end of the grid**. We want to find the next match, but exclude any matches we have already found.

Now we can use these functions recursively, and we know that we won't find the same row twice.

CODE

Matches := 0;

if SearchFirst(ACol, Value, []) then

begin

Inc(Matches);

while SearchNext(ACol, Value, []) do

Inc(Matches);

end;

I also added a Locate function:

CODE

function TNxCustomGrid.Locate(ColumnIndex: Integer; Value: WideString;

SearchOptions: TSearchOptions = []): Boolean;

begin

Result := False;

if RowCount = 0 then Exit;

Result := Roll(SelectedRow, Pred(RowCount), SearchOptions) or Roll(0,SelectedRow, SearchOptions);

end;

Locate is very similar to SearchFirst, but it starts searching on the SelectedRow. If the row we are looking for is already selected, the function returns immediately without searching the whole grid, so it is good if we simply want to know if a match exists, but we don't care if it's the first match or about the position of row.

I think using the SearchFirst --> SearchNext setup makes the functions more usefull, and SearchOptions makes it a lot more flexible. What do you think?

Regards,

Deon