home *** CD-ROM | disk | FTP | other *** search
- (*////////////////////////////////////////////////////////////////////////////
- // Part of AlexSoft VCL/DLL Library. //
- // All rights reserved. (c) Copyright 1998. //
- // Created by: Alex Rabichooc //
- //**************************************************************************//
- // Users of this unit must accept this disclaimer of warranty: //
- // "This unit is supplied as is. The author disclaims all warranties, //
- // expressed or implied, including, without limitation, the warranties //
- // of merchantability and of fitness for any purpose. //
- // The author assumes no liability for damages, direct or //
- // consequential, which may result from the use of this unit." //
- // //
- // This Unit is donated to the public as public domain. //
- // //
- // This Unit can be freely used and distributed in commercial and //
- // private environments provided this notice is not modified in any way. //
- // //
- // If you do find this Unit handy and you feel guilty for using such a //
- // great product without paying someone - sorry :-) //
- // //
- // Please forward any comments or suggestions to Alex Rabichooc at: //
- // //
- // a_rabichooc@yahoo.com or alex@carmez.mldnet.com //
- /////////////////////////////////////////////////////////////////////////////*)
-
- unit fmSearch;
-
- interface
-
- uses
- Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- ExtCtrls, StdCtrls, ComCtrls, DB, DBTables, Buttons, Mask, DBCtrls, StdUtils;
-
- type
- TSearchForm = class(TForm)
- paBottom: TPanel;
- paMiddle: TPanel;
- paTop: TPanel;
- laTemplate: TLabel;
- btOk: TButton;
- btCancel: TButton;
- cbFields: TComboBox;
- laFields: TLabel;
- lbFindValues: TListBox;
- ckContext: TCheckBox;
- edTemplate: TMaskEdit;
- ckExtendedSearch: TCheckBox;
- procedure FormClose(Sender: TObject; var Action: TCloseAction);
- procedure edTemplateKeyPress(Sender: TObject; var Key: Char);
- procedure cbFieldsChange(Sender: TObject);
- procedure lbFindValuesDrawItem(Control: TWinControl; Index: Integer;
- Rect: TRect; State: TOwnerDrawState);
- procedure edTemplateChange(Sender: TObject);
- procedure ckContextClick(Sender: TObject);
- procedure lbFindValuesDblClick(Sender: TObject);
- procedure FormCreate(Sender: TObject);
- procedure ckExtendedSearchClick(Sender: TObject);
- procedure cbFieldsKeyPress(Sender: TObject; var Key: Char);
- private
- FDataSet: TDataSet;
- FBookMark: TBookMark;
- FRecords: TStringList;
- FValues: TStringList;
- FField: TField;
- procedure CMChildKey(var Message: TCMChildKey); message CM_CHILDKEY;
- procedure CreateFieldList(AFieldList: TList);
- function FindValue(AString: string; var Index: Integer): Boolean;
- procedure SetFilter(const AFilter: String);
- procedure SetDefaultButton;
- function ValidText: boolean;
- public
- { Public declarations }
- constructor CreateWithDataSet(AOwner: TComponent;
- ADataSet: TDataSet; AFieldList: TList;
- AField: TField); virtual;
- destructor Destroy; override;
- end;
-
- implementation
- uses dbConsts, dbTools;
-
- {$R *.DFM}
-
- {TSearchForm}
-
- function TSearchForm.ValidText: boolean;
- var LKeyField: TField;
- LDataSet: TDataSet;
- begin
- Result := True;
- LKeyField := nil;
- Screen.Cursor := crHourGlass;
- try
- if (FField <> nil) and (FField.FieldKind in [fkData, fkLookup]) and
- (not Assigned(FField.OnGetText) or
- (@FField.OnGetText = @TSenderClass.GetFieldText)) then
- begin
- if FField.FieldKind = fkLookUp then
- begin
- LDataSet := FField.LookupDataSet;
- if LDataSet <> nil then
- LKeyField := LDataSet.FindField(FField.LookUpKeyFields);
- end
- else
- begin
- LDataSet := FField.LookupDataSet;
- if LDataSet <> nil then
- LKeyField := LDataSet.FindField(FField.LookUpKeyFields);
- end;
- if (LDataSet <> nil) and (LKeyField <> nil) then
- begin
- Result := LDataSet.Locate(LDataSet.FieldByName(FField.LookupResultField).FieldName, edTemplate.Text, [loCaseInsensitive]);
- if Result then
- Result := FDataSet.Locate(FField.FieldName, LKeyField.Value, [loCaseInsensitive]);
- end
- else
- Result := FDataSet.Locate(FField.FieldName, edTemplate.Text, [loCaseInsensitive]);
- end;
- finally
- Screen.Cursor := crDefault;
- end;
- end;
-
- constructor TSearchForm.CreateWithDataSet(AOwner: TComponent;
- ADataSet: TDataSet; AFieldList: TList;
- AField: TField);
- begin
- Inherited Create(AOwner);
- FDataSet := ADataSet;
- FBookMark := FDataSet.GetBookmark;
- FRecords := TStringList.Create;
- FValues := TStringList.Create;
- FField := AField;
- CreateFieldList(AFieldList);
- end;
-
- destructor TSearchForm.Destroy;
- begin
- if FBookMark <> nil then
- FDataSet.FreeBookmark(FBookMark);
- if FRecords <> nil then
- FRecords.Free;
- if FValues <> nil then
- FValues.Free;
- Inherited Destroy;
- end;
-
- procedure TSearchForm.FormClose(Sender: TObject; var Action: TCloseAction);
- begin
- case ModalResult of
- mrCancel: FDataSet.GotoBookmark(FBookmark);
- mrOk: if not ckExtendedSearch.Checked and not ValidText then
- begin
- Action := caNone;
- MessageBeep(MB_ICONEXCLAMATION);
- MessageDlg(SRecordNotFound, mtError, [mbOk], 0);
- end;
- end;
- end;
-
- procedure TSearchForm.edTemplateKeyPress(Sender: TObject; var Key: Char);
- var
- ValidKey: boolean;
- AField: TField;
- begin
- if ckExtendedSearch.Checked and (lbFindValues.Items.Count = 0) then Exit;
- ValidKey := True;
- if Key in [#32..#255] then
- begin
- AField := nil;
- if FField.LookUpDataSet <> nil then
- AField := FField.LookUpDataSet.FindField(FField.LookUpResultField);
- if AField = nil then
- AField := FField;
- ValidKey := AField.IsValidChar(Key);
- end;
- if not ValidKey then
- begin
- MessageBeep(0);
- Key := #0;
- end;
- end;
-
- procedure TSearchForm.CreateFieldList(AFieldList: TList);
- var
- i: integer;
- begin
- with FDataSet do
- begin
- if (AFieldList <> nil) and (AFieldList.Count > 0) then
- begin
- for i := 0 to AFieldList.Count-1 do
- begin
- cbFields.Items.AddObject(TField(AFieldList[i]).DisplayLabel,
- TField(AFieldList[i]));
- if FField = TField(AFieldList[i]) then
- cbFields.ItemIndex := cbFields.Items.Count-1;
- end;
- end
- else
- for i := 0 To FieldCount - 1 do
- if not Fields[i].IsBlob and
- not (Fields[i] is TBinaryField) and Fields[i].Visible
- {$IFNDEF VER110}
- and (Fields[i].DataType <> ftDataSet)
- {$ENDIF} then
- begin
- cbFields.Items.AddObject(Fields[i].DisplayLabel, Fields[i]);
- if FField = Fields[i] then
- cbFields.ItemIndex := cbFields.Items.Count-1;
- end;
- end;
- if cbFields.Items.Count = 0 then
- begin
- Destroy;
- Exit;
- end;
- if cbFields.ItemIndex < 0 then
- cbFields.ItemIndex := 0;
- cbFieldsChange(Self);
- cbFields.DropDownCount := cbFields.Items.Count;
- end;
-
- function TSearchForm.FindValue(AString: string; var Index: Integer): Boolean;
- var HighIndex, LowIndex, CurIndex, CompResult: Integer;
- TmpStr: String;
- begin
- Result := False;
- if Length(AString) = 0 then Exit;
- HighIndex := lbFindValues.Items.Count - 1;
- LowIndex := 0;
- while LowIndex <= HighIndex do
- begin
- CurIndex := (LowIndex + HighIndex) div 2;
- with lbFindValues do
- if Length(AString) < Length(Items[CurIndex]) then
- TmpStr := Copy(Items[CurIndex], 1, Length(AString))
- else
- TmpStr := Items[CurIndex];
- CompResult := AnsiCompareText(TmpStr, AString);
- if CompResult < 0 then
- LowIndex := CurIndex + 1
- else
- begin
- HighIndex := CurIndex - 1;
- Result := True;
- end;
- end;
- Index := LowIndex;
- end;
-
- procedure TSearchForm.cbFieldsChange(Sender: TObject);
- var AObject: TObject;
- AIndex: Integer;
- begin
- FField := cbFields.Items.Objects[cbFields.ItemIndex] as TField;
- if not (FField.FieldKind in [fkData, fkLookup]) or
- (Assigned(FField.OnGetText) and
- (@FField.OnGetText <> @TSenderClass.GetFieldText)) then
- begin
- ckExtendedSearch.Enabled := False;
- if not ckExtendedSearch.Checked then
- begin
- ckExtendedSearch.Checked := True;
- exit;
- end;
- end
- else
- ckExtendedSearch.Enabled := True;
- edTemplate.EditMask := FField.EditMask;
- if ckExtendedSearch.Checked then
- begin
- FDataSet.DisableControls;
- try
- Screen.Cursor := crHourGlass;
- lbFindValues.Items.BeginUpdate;
- lbFindValues.Clear;
- FRecords.BeginUpdate;
- FRecords.Clear;
- FValues.BeginUpdate;
- FValues.Clear;
- FDataSet.First;
- while not FDataSet.EOF do
- begin
- AObject := TObject(FRecords.Add(FDataSet.Bookmark));
- AIndex := FValues.AddObject(FField.Text, AObject);
- lbFindValues.Items.AddObject(FValues[AIndex], AObject);
- FDataSet.Next;
- end;
- FDataSet.First;
- finally
- FDataSet.EnableControls;
- Screen.Cursor := crDefault;
- lbFindValues.Items.EndUpdate;
- FRecords.EndUpdate;
- FValues.EndUpdate;
- edTemplate.OnChange := nil;
- try
- if ckContext.Checked then
- edTemplate.Text := ''
- else
- if lbFindValues.Items.Count > 0 then
- edTemplate.Text := lbFindValues.Items[0];
- if lbFindValues.Items.Count > 0 then
- lbFindValues.ItemIndex := 0;
- finally
- edTemplate.OnChange := edTemplateChange;
- end;
- end;
- end
- else
- edTemplate.Text := '';
- if Visible and not cbFields.DroppedDown then
- edTemplate.SetFocus;
- SetDefaultButton;
- end;
-
- procedure TSearchForm.lbFindValuesDrawItem(Control: TWinControl;
- Index: Integer; Rect: TRect; State: TOwnerDrawState);
- var ABookmark: TBookmarkStr;
- begin
- if not ckExtendedSearch.Checked then
- exit;
- with Control as TListBox do
- begin
- inc(Rect.Bottom);
- Canvas.FillRect(Rect);
- Canvas.TextOut(Rect.Left+1, Rect.Top+1, Items[Index]);
- if (odFocused in State) or (odSelected in State) then
- begin
- ABookmark := TBookmarkStr(FRecords.Strings[Integer(lbFindValues.
- Items.Objects[Index])]);
- if ABookMark <> FDataSet.BookMark then
- FDataSet.BookMark := ABookMark;
- end;
- if odFocused in State then
- begin
- edTemplate.OnChange := nil;
- try
- if not ckContext.Checked then
- edTemplate.Text := Items[Index];
- edTemplate.SelectAll;
- finally
- edTemplate.OnChange := edTemplateChange;
- end;
- end;
- end;
- SetDefaultButton;
- end;
-
- procedure TSearchForm.edTemplateChange(Sender: TObject);
- var i: Integer;
- begin
- if not ckExtendedSearch.Checked then
- exit;
- if not ckContext.Checked then
- begin
- if FindValue(edTemplate.Text, i) then
- lbFindValues.ItemIndex := i;
- end
- else
- SetFilter(edTemplate.Text);
- SetDefaultButton;
- end;
-
- procedure TSearchForm.CMChildKey(var Message: TCMChildKey);
- begin
- if not ckExtendedSearch.Checked or (ActiveControl = cbFields) then
- exit;
- with Message do
- case CharCode of
- VK_DOWN, VK_UP, VK_NEXT, VK_PRIOR:
- begin
- if [ssCtrl] = GetShiftState then
- begin
- if CharCode = VK_NEXT then
- CharCode := VK_END;
- if CharCode = VK_PRIOR then
- CharCode := VK_HOME;
- end;
- SendMessage(lbFindValues.Handle, WM_KEYDOWN, CharCode, LongInt(Self));
- Result := 1;
- Application.ProcessMessages;
- if not ckContext.Checked then
- begin
- edTemplate.OnChange := nil;
- try
- edTemplate.Text := lbFindValues.Items[lbFindValues.ItemIndex];
- edTemplate.SelectAll;
- finally
- edTemplate.OnChange := edTemplateChange;
- end;
- end;
- end;
- end;
- SetDefaultButton;
- end;
-
- procedure TSearchForm.ckContextClick(Sender: TObject);
- begin
- if Visible then
- edTemplate.SetFocus
- else
- edTemplate.Text := '';
- SetFilter(edTemplate.Text);
- edTemplate.SelectAll;
- SetDefaultButton;
- end;
-
- procedure TSearchForm.SetFilter(const AFilter: String);
- var i: Integer;
- begin
- if not ckExtendedSearch.Checked then
- exit;
- try
- lbFindValues.Items.BeginUpdate;
- lbFindValues.Clear;
- for i := 0 to FValues.Count-1 do
- if not ckContext.Checked or
- (Length(AFilter) = 0) or
- (Pos(AnsiUpperCase(AFilter),
- AnsiUpperCase(FValues[i])) <> 0) then
- lbFindValues.Items.AddObject(FValues[i], FValues.Objects[i]);
- finally
- lbFindValues.Items.EndUpdate;
- if not ckContext.Checked then
- edTemplate.Text := lbFindValues.Items[0];
- end;
- if lbFindValues.Items.Count > 0 then
- lbFindValues.ItemIndex := 0;
- SetDefaultButton;
- end;
-
- procedure TSearchForm.lbFindValuesDblClick(Sender: TObject);
- begin
- btOk.Click;
- end;
-
- procedure TSearchForm.FormCreate(Sender: TObject);
- var ParentForm: TCustomForm;
- TM: TTextMetric;
- begin
- if (Owner is TWinControl) then
- begin
- ParentForm := GetParentForm(Owner as TWinControl);
- if ParentForm <> nil then
- Font := ParentForm.Font;
- end;
- GetTextMetrics(lbFindValues.Canvas.Handle, TM);
- lbFindValues.ItemHeight := TM.tmHeight+2;
- end;
-
- procedure TSearchForm.SetDefaultButton;
- begin
- btOk.Default := not ckExtendedSearch.Checked or
- not ((lbFindValues.ItemIndex < 0) or
- ((edTemplate.Text <>
- lbFindValues.Items[lbFindValues.ItemIndex]) and
- not ckContext.Checked));
- end;
-
- procedure TSearchForm.ckExtendedSearchClick(Sender: TObject);
- begin
- ckContext.Visible := ckExtendedSearch.Checked;
- if not ckExtendedSearch.Checked then
- ClientHeight := paTop.Height + paBottom.Height
- else
- ClientHeight := paTop.Height+paBottom.Height+(lbFindValues.ItemHeight+1)*10+
- paMiddle.BorderWidth*2;
- cbFieldsChange(cbFields);
- end;
-
- procedure TSearchForm.cbFieldsKeyPress(Sender: TObject; var Key: Char);
- begin
- if (Key = char(VK_RETURN)) and Visible then
- edTemplate.SetFocus;
- end;
-
- end.
-