435 lines
12 KiB
ObjectPascal
435 lines
12 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: JvDBFindEdit.pas, released 2004-03-23
|
|
|
|
The Initial Developer of the Original Code is yul
|
|
Portions created by yul are Copyright (C) 2004 yul.
|
|
All Rights Reserved.
|
|
|
|
Contributor(s):
|
|
|
|
Current Version: 0.50
|
|
|
|
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
|
|
located at http://jvcl.sourceforge.net
|
|
|
|
Known Issues:
|
|
-----------------------------------------------------------------------------}
|
|
// $Id: JvDBFindEdit.pas 11187 2007-02-08 18:51:10Z obones $
|
|
|
|
unit JvDBFindEdit;
|
|
|
|
{$I jvcl.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF UNITVERSIONING}
|
|
JclUnitVersioning,
|
|
{$ENDIF UNITVERSIONING}
|
|
Windows, Classes, Controls, ExtCtrls, DB, DBCtrls,
|
|
JvMaskEdit;
|
|
|
|
type
|
|
TJvEditFindStyle = (fsNavigate, fsFilter);
|
|
TJvEditFindMode = (fmFirstPos, fmAnyPos);
|
|
|
|
TJvDBFindEdit = class(TJvMaskEdit)
|
|
private
|
|
FTimer: TTimer;
|
|
FOldFiltered: Boolean;
|
|
FOldFilterRecord: TFilterRecordEvent;
|
|
FDataLink: TFieldDataLink;
|
|
FIgnoreCase: Boolean;
|
|
FFindMode: TJvEditFindMode;
|
|
FFindStyle: TJvEditFindStyle;
|
|
FSearchText: string;
|
|
procedure ActiveChange(Sender: TObject);
|
|
function GetDataField: string;
|
|
function GetDataSource: TDataSource;
|
|
procedure SetDataField(const Value: string);
|
|
procedure SetDataSource(const Value: TDataSource);
|
|
procedure SetFindMode(const Value: TJvEditFindMode);
|
|
procedure SetFindStyle(const Value: TJvEditFindStyle);
|
|
procedure SetIgnoreCase(const Value: Boolean);
|
|
procedure FTimerTimer(Sender: TObject);
|
|
procedure AFilterRecord(DataSet: TDataSet; var Accept: Boolean);
|
|
protected
|
|
procedure Change; override;
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
function DateVal: Boolean;
|
|
function IsDate(S1: string): Boolean;
|
|
function GetDateDelimiter: string;
|
|
function IsNumeric(S1: string): Boolean;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Find(AText: string);
|
|
procedure ResetFilter;
|
|
published
|
|
property DataField: string read GetDataField write SetDataField;
|
|
property DataSource: TDataSource read GetDataSource write SetDataSource;
|
|
property FindStyle: TJvEditFindStyle read FFindStyle write SetFindStyle default fsNavigate;
|
|
property FindMode: TJvEditFindMode read FFindMode write SetFindMode default fmFirstPos;
|
|
property IgnoreCase: Boolean read FIgnoreCase write SetIgnoreCase default True;
|
|
property Anchors;
|
|
property AutoSelect;
|
|
property AutoSize;
|
|
property BorderStyle;
|
|
property CharCase;
|
|
property Color;
|
|
property Constraints;
|
|
property DragCursor;
|
|
property Enabled;
|
|
{$IFDEF VCL}
|
|
{$IFDEF COMPILER6_UP}
|
|
property BevelEdges;
|
|
property BevelInner;
|
|
property BevelKind default bkNone;
|
|
property BevelOuter;
|
|
{$ENDIF COMPILER6_UP}
|
|
property Flat;
|
|
property ParentFlat;
|
|
{$ENDIF VCL}
|
|
property Font;
|
|
property HideSelection;
|
|
property MaxLength;
|
|
Property EditMask;
|
|
property ParentColor;
|
|
property ParentFont;
|
|
property ParentShowHint;
|
|
property PasswordChar;
|
|
property PopupMenu;
|
|
property ReadOnly;
|
|
property ShowHint;
|
|
property TabOrder;
|
|
property TabStop;
|
|
property Visible;
|
|
property OnChange;
|
|
property OnClick;
|
|
property OnDblClick;
|
|
property OnDragDrop;
|
|
property OnDragOver;
|
|
property OnEndDock;
|
|
property OnEndDrag;
|
|
property OnEnter;
|
|
property OnExit;
|
|
property OnKeyDown;
|
|
property OnKeyPress;
|
|
property OnKeyUp;
|
|
property OnMouseDown;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
property OnStartDock;
|
|
property OnStartDrag;
|
|
end;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
const
|
|
UnitVersioning: TUnitVersionInfo = (
|
|
RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_32/run/JvDBFindEdit.pas $';
|
|
Revision: '$Revision: 11187 $';
|
|
Date: '$Date: 2007-02-08 19:51:10 +0100 (jeu., 08 févr. 2007) $';
|
|
LogPath: 'JVCL\run'
|
|
);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
implementation
|
|
|
|
uses
|
|
SysUtils;
|
|
|
|
constructor TJvDBFindEdit.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FFindStyle := fsNavigate;
|
|
FFindMode := fmFirstPos;
|
|
FIgnoreCase := True;
|
|
FTimer := TTimer.Create(Self);
|
|
FTimer.Enabled := False;
|
|
FTimer.Interval := 400;
|
|
FTimer.OnTimer := FTimerTimer;
|
|
FSearchText := '';
|
|
FOldFiltered := False;
|
|
FOldFilterRecord := nil;
|
|
FDataLink := TFieldDataLink.Create;
|
|
FDataLink.Control := Self;
|
|
FDataLink.OnActiveChange := ActiveChange;
|
|
end;
|
|
|
|
destructor TJvDBFindEdit.Destroy;
|
|
begin
|
|
if FDataLink.Active and (FFindStyle = fsFilter) then
|
|
begin
|
|
FDataLink.DataSet.OnFilterRecord := FOldFilterRecord;
|
|
FDataLink.DataSet.Filtered := FOldFiltered;
|
|
end;
|
|
FDataLink.Control := nil;
|
|
DataSource := nil;
|
|
FDataLink.Free;
|
|
FDataLink := nil;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvDBFindEdit.Change;
|
|
begin
|
|
FTimer.Enabled := False;
|
|
if Text = '' then
|
|
FTimer.Interval := 400;
|
|
FTimer.Enabled := True;
|
|
FSearchText := Text;
|
|
inherited Change;
|
|
end;
|
|
|
|
// (ahuser) Compiler gives hint for unused value. This function prevents it
|
|
function ToDoubleVal(const S: string; var Err: Integer): Double;
|
|
begin
|
|
Val(S, Result, Err);
|
|
end;
|
|
|
|
function TJvDBFindEdit.IsNumeric(S1: string): Boolean;
|
|
var
|
|
ier: Integer;
|
|
begin
|
|
Result := True;
|
|
ToDoubleVal(S1, ier);
|
|
if ier > 0 then
|
|
Result := False;
|
|
end;
|
|
|
|
function TJvDBFindEdit.GetDateDelimiter: string;
|
|
var
|
|
S1: string;
|
|
I: Integer;
|
|
begin
|
|
S1 := DateTimeToStr(Now);
|
|
for I := 1 to Length(S1) do
|
|
if not (S1[I] in ['0'..'9']) then
|
|
begin
|
|
Result := S1[I];
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
function TJvDBFindEdit.IsDate(S1: string): Boolean;
|
|
var
|
|
I, k, p1, p2: Integer;
|
|
sm, sd, sj, ss: string;
|
|
begin
|
|
Result := False;
|
|
ss := GetDateDelimiter;
|
|
k := Length(S1);
|
|
if k > 0 then
|
|
begin
|
|
p1 := 0;
|
|
p2 := 0;
|
|
for I := 1 to k do
|
|
begin
|
|
if p1 = 0 then
|
|
begin
|
|
if S1[I] = ss then
|
|
p1 := I;
|
|
end
|
|
else
|
|
begin
|
|
if S1[I] = ss then
|
|
p2 := I;
|
|
end;
|
|
end;
|
|
if (p1 > 0) and (p2 > 0) and (p2 > p1) then
|
|
begin
|
|
sm := Copy(S1, 1, p1 - 1);
|
|
sd := Copy(S1, p1 + 1, p2 - p1 -1);
|
|
sj := Copy(S1, p2 + 1, k - p2);
|
|
if IsNumeric(sm) and IsNumeric(sd) and IsNumeric(sj) then
|
|
begin
|
|
p1 := StrToInt(sd);
|
|
if (p1 > 0) and (p1 < 32) then
|
|
begin
|
|
p1 := StrToInt(sm);
|
|
if (p1 > 0) and (p1 < 13) then
|
|
begin
|
|
p1 := StrToInt(sj);
|
|
if p1 > 1969 then
|
|
Result := True;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJvDBFindEdit.DateVal: Boolean;
|
|
begin
|
|
Result := True;
|
|
if FDataLink.Field is TDateField then
|
|
if not IsDate(FSearchText) then
|
|
Result := False;
|
|
|
|
if IsDate(FSearchText) then
|
|
//begin
|
|
// DateSeparator :='/';
|
|
// ShortDateFormat := 'mm/dd/yyyy';
|
|
FSearchText := (DateToStr(StrToDate(FSearchText)));
|
|
//end;
|
|
end;
|
|
|
|
procedure TJvDBFindEdit.ResetFilter;
|
|
begin
|
|
Text := '';
|
|
// FSearchText := '';
|
|
FDataLink.DataSet.Filtered := False;
|
|
end;
|
|
|
|
procedure TJvDBFindEdit.FTimerTimer(Sender: TObject);
|
|
begin
|
|
FTimer.Enabled := False;
|
|
ActiveChange(Self);
|
|
if FFindStyle = fsFilter then
|
|
FDataLink.DataSet.Filtered := False;
|
|
if FSearchText = '' then
|
|
begin
|
|
if FFindStyle = fsFilter then
|
|
begin
|
|
FDataLink.DataSet.OnFilterRecord := FOldFilterRecord;
|
|
FDataLink.DataSet.Filtered := FOldFiltered;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if not FDataLink.Active or (FDataLink.Field = nil) then
|
|
Exit;
|
|
if DateVal and not(FDataLink.Field is TBlobField) then
|
|
if FFindStyle = fsNavigate then
|
|
begin
|
|
if IgnoreCase then
|
|
FDataLink.DataSet.Locate(DataField, FSearchText, [loCaseInsensitive, loPartialKey])
|
|
else
|
|
FDataLink.DataSet.Locate(DataField, FSearchText, [loPartialKey]);
|
|
end
|
|
else
|
|
FDataLink.DataSet.Filtered := True;
|
|
end;
|
|
FTimer.Interval := 100;
|
|
end;
|
|
|
|
procedure TJvDBFindEdit.Find(AText: string);
|
|
begin
|
|
FSearchText := AText;
|
|
FTimerTimer(FTimer);
|
|
end;
|
|
|
|
procedure TJvDBFindEdit.AFilterRecord(DataSet: TDataSet; var Accept: Boolean);
|
|
begin
|
|
Accept := True;
|
|
if FOldFiltered and Assigned(FOldFilterRecord) then
|
|
FOldFilterRecord(DataSet, Accept);
|
|
if not Accept then
|
|
Exit;
|
|
if FFindMode = fmFirstPos then
|
|
begin
|
|
if IgnoreCase then
|
|
Accept := Pos(AnsiUpperCase(FSearchText),
|
|
AnsiUpperCase(DataSet.FieldByName(DataField).AsString)) = 1
|
|
else
|
|
Accept := Pos(FSearchText, DataSet.FieldByName(DataField).AsString) = 1;
|
|
end
|
|
else
|
|
begin
|
|
if IgnoreCase then
|
|
Accept := Pos(AnsiUpperCase(FSearchText),
|
|
AnsiUpperCase(DataSet.FieldByName(DataField).AsString)) > 0
|
|
else
|
|
Accept := Pos(FSearchText, DataSet.FieldByName(DataField).AsString) > 0;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvDBFindEdit.ActiveChange(Sender: TObject);
|
|
var
|
|
Func1, Func2: TFilterRecordEvent;
|
|
begin
|
|
if (FFindStyle = fsNavigate) or (FDataLink.DataSet = nil) then
|
|
Exit;
|
|
Func1 := FDataLink.DataSet.OnFilterRecord;
|
|
Func2 := AFilterRecord;
|
|
if FDataLink.Active and (@Func1 <> @Func2) and (FSearchText > '') then
|
|
begin
|
|
FOldFilterRecord := FDataLink.DataSet.OnFilterRecord;
|
|
FOldFiltered := FDataLink.DataSet.Filtered;
|
|
FDataLink.DataSet.OnFilterRecord := AFilterRecord;
|
|
end;
|
|
end;
|
|
|
|
function TJvDBFindEdit.GetDataSource: TDataSource;
|
|
begin
|
|
Result := FDataLink.DataSource;
|
|
end;
|
|
|
|
procedure TJvDBFindEdit.SetDataSource(const Value: TDataSource);
|
|
begin
|
|
if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then
|
|
FDataLink.DataSource := Value;
|
|
if Value <> nil then
|
|
Value.FreeNotification(Self);
|
|
end;
|
|
|
|
function TJvDBFindEdit.GetDataField: string;
|
|
begin
|
|
Result := FDataLink.FieldName;
|
|
end;
|
|
|
|
procedure TJvDBFindEdit.SetDataField(const Value: string);
|
|
begin
|
|
if Value > '' then
|
|
FDataLink.FieldName := Value;
|
|
end;
|
|
|
|
procedure TJvDBFindEdit.SetFindMode(const Value: TJvEditFindMode);
|
|
begin
|
|
if FFindStyle = fsNavigate then
|
|
FFindMode := fmFirstPos
|
|
else
|
|
FFindMode := Value;
|
|
end;
|
|
|
|
procedure TJvDBFindEdit.SetFindStyle(const Value: TJvEditFindStyle);
|
|
begin
|
|
FFindStyle := Value;
|
|
if FFindStyle = fsNavigate then
|
|
FFindMode := fmFirstPos;
|
|
ActiveChange(Self);
|
|
end;
|
|
|
|
procedure TJvDBFindEdit.SetIgnoreCase(const Value: Boolean);
|
|
begin
|
|
FIgnoreCase := Value;
|
|
end;
|
|
|
|
procedure TJvDBFindEdit.Notification(AComponent: TComponent;
|
|
Operation: TOperation);
|
|
begin
|
|
inherited Notification(AComponent, Operation);
|
|
if Operation = opRemove then
|
|
if (FDataLink <> nil) and (AComponent = DataSource) then
|
|
DataSource := nil;
|
|
end;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
initialization
|
|
RegisterUnitVersion(HInstance, UnitVersioning);
|
|
|
|
finalization
|
|
UnregisterUnitVersion(HInstance);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
end.
|
|
|