Componentes.Terceros.jvcl/official/3.36/run/JvDBSearchComboBox.pas
2009-02-27 12:23:32 +00:00

411 lines
11 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: JvDBSearchComboBox.pas, released on 2004-02-28.
The Initial Developer of the Original Code is Lionel Reynaud
Portions created by Sébastien Buysse are Copyright (C) 2004 Lionel Reynaud.
All Rights Reserved.
Contributor(s):
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.sourceforge.net
Description:
DB Component to find record with ComboBox
Free modified and corrected component TDBViewCombo from ???
Known Issues:
-----------------------------------------------------------------------------}
// $Id: JvDBSearchComboBox.pas 12133 2009-01-07 15:33:53Z ahuser $
unit JvDBSearchComboBox;
{$I jvcl.inc}
interface
uses
{$IFDEF UNITVERSIONING}
JclUnitVersioning,
{$ENDIF UNITVERSIONING}
{$IFDEF SUPPORTS_GENERICS}
Generics.Collections,
{$ENDIF SUPPORTS_GENERICS}
Windows, Classes, Controls, DB,
JvComboBox;
type
TJvDBCustomSearchComboBox = class;
TJvSearchComboBoxLink = class(TDataLink)
private
FJvDBSearchComboBox: TJvDBCustomSearchComboBox;
FDataFieldName: string;
FDataField: TField;
FWasEdited: Boolean;
FReading: Boolean;
procedure SetDataFieldName(const Value: string);
procedure SetDataField;
protected
procedure ActiveChanged; override;
procedure DataSetScrolled(Distance: Integer); override;
procedure DataSetChanged; override;
procedure EditingChanged; override;
public
constructor Create(AJvDBSearchComboBox: TJvDBCustomSearchComboBox);
property DataField: TField read FDataField;
property DataFieldName: string read FDataFieldName write SetDataFieldName;
end;
{$IFDEF SUPPORTS_GENERICS}
TBookmarkList = TList<TBookmark>;
{$ELSE}
TBookmarkList = TList;
{$ENDIF SUPPORTS_GENERICS}
TJvDBCustomSearchComboBox = class(TJvCustomComboBox)
private
FDataLink: TJvSearchComboBoxLink;
FChanging: Boolean;
FDataResult: string;
// Mantis 4622: TBookmark are TBytes in D12+ and if we store them inside a
// simple TList, the compiler will not see the references to the array of
// bytes, hence will finalize each one of them while we keep them in our
// list as simple pointers.
// To avoid this, we could have fiddled with the reference counting
// ourselves, but we used the new more elegant way of using the generics
// which makes the compiler do all the work for us.
FBookmarks: TBookmarkList;
function GetDataField: string;
function GetDataSource: TDataSource;
procedure SetDataField(const Value: string);
procedure SetDataSource(Value: TDataSource);
protected
procedure Scroll(Distance: Integer);
procedure ReadList;
procedure ClearList;
procedure Select; override;
procedure Notification(Component: TComponent; Operation: TOperation); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function GetResult: Variant;
procedure Refresh;
property ItemIndex;
published
property DataField: string read GetDataField write SetDataField;
property DataResult: string read FDataResult write FDataResult;
property DataSource: TDataSource read GetDataSource write SetDataSource;
end;
TJvDBSearchComboBox = class(TJvDBCustomSearchComboBox)
published
property Align;
property Anchors;
property AutoComplete default True;
property AutoSize;
{$IFDEF COMPILER6_UP}
property AutoDropDown default False;
property BevelEdges;
property BevelInner;
property BevelKind default bkNone;
property BevelOuter;
{$ENDIF COMPILER6_UP}
property BiDiMode;
property CharCase;
property Constraints;
property Style;
property Color;
property DragMode;
property DragCursor;
property DropDownCount;
property Enabled;
property Flat;
property ParentFlat;
property Font;
property ItemHeight;
property MaxLength;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property TabOrder;
property TabStop;
property Text;
property Visible;
property OnChange;
property OnClick;
{$IFDEF COMPILER6_UP}
property OnCloseUp;
{$ENDIF COMPILER6_UP}
property OnContextPopup;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnDrawItem;
property OnDropDown;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMeasureItem;
{$IFDEF COMPILER6_UP}
property OnSelect;
{$ENDIF COMPILER6_UP}
property OnMouseEnter;
property OnMouseLeave;
property OnParentColorChange;
end;
{$IFDEF UNITVERSIONING}
const
UnitVersioning: TUnitVersionInfo = (
RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/branches/JVCL3_36_PREPARATION/run/JvDBSearchComboBox.pas $';
Revision: '$Revision: 12133 $';
Date: '$Date: 2009-01-07 16:33:53 +0100 (mer., 07 janv. 2009) $';
LogPath: 'JVCL\run'
);
{$ENDIF UNITVERSIONING}
implementation
uses
{$IFDEF HAS_UNIT_VARIANTS}
Variants,
{$ENDIF HAS_UNIT_VARIANTS}
SysUtils;
//=== { TJvSearchComboBoxLink } ==============================================
constructor TJvSearchComboBoxLink.Create(AJvDBSearchComboBox: TJvDBCustomSearchComboBox);
begin
inherited Create;
FJvDBSearchComboBox := AJvDBSearchComboBox;
FDataFieldName := '';
FDataField := nil;
FWasEdited := False;
FReading := False;
end;
procedure TJvSearchComboBoxLink.SetDataField;
begin
if DataSource = nil then
Exit;
if DataSource.DataSet = nil then
Exit;
if not DataSource.DataSet.Active then
Exit;
if FDataFieldName = '' then
Exit;
FDataField := DataSource.DataSet.FieldByName(FDataFieldName);
if Active then
FJvDBSearchComboBox.ReadList;
end;
procedure TJvSearchComboBoxLink.SetDataFieldName(const Value: string);
begin
if FDataFieldName <> Value then
begin
FDataFieldName := Value;
SetDataField;
end;
end;
procedure TJvSearchComboBoxLink.ActiveChanged;
begin
if Active then
begin
if FDataField = nil then
SetDataField;
end
else
begin
FDataField := nil;
FJvDBSearchComboBox.ClearList;
end
end;
procedure TJvSearchComboBoxLink.DataSetChanged;
begin
if FReading or FJvDBSearchComboBox.FChanging then
Exit;
FReading := True;
try
if not (DataSource.DataSet.State in dsEditModes) then
begin
FJvDBSearchComboBox.ClearList;
FJvDBSearchComboBox.ReadList;
end;
finally
FReading := False;
end;
end;
procedure TJvSearchComboBoxLink.DataSetScrolled(Distance: Integer);
begin
if Distance <> 0 then
FJvDBSearchComboBox.Scroll(Distance);
end;
procedure TJvSearchComboBoxLink.EditingChanged;
begin
if Editing then
FWasEdited := True;
end;
//=== { TJvDBCustomSearchComboBox } ==========================================
constructor TJvDBCustomSearchComboBox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FBookmarks := TBookmarkList.Create;
FDataLink := TJvSearchComboBoxLink.Create(Self);
FChanging := False;
end;
destructor TJvDBCustomSearchComboBox.Destroy;
begin
ClearList;
FDataLink.Free;
FDataLink := nil; // Notification() is called by inherited Destroy
inherited Destroy;
FBookmarks.Free;
end;
procedure TJvDBCustomSearchComboBox.Notification(Component: TComponent; Operation: TOperation);
begin
inherited Notification(Component, Operation);
if (FDataLink <> nil) and (Component = DataSource) and (Operation = opRemove) then
DataSource := nil;
end;
function TJvDBCustomSearchComboBox.GetDataField: string;
begin
Result := FDataLink.DataFieldName;
end;
function TJvDBCustomSearchComboBox.GetDataSource: TDataSource;
begin
Result := FDataLink.DataSource;
end;
procedure TJvDBCustomSearchComboBox.SetDataField(const Value: string);
begin
FDataLink.DataFieldName := Value;
end;
procedure TJvDBCustomSearchComboBox.SetDataSource(Value: TDataSource);
begin
FDataLink.DataSource := Value;
end;
procedure TJvDBCustomSearchComboBox.Select;
begin
if not FChanging and (ItemIndex <> -1) and
(FDataLink.DataSet <> nil) and (FDataLink.DataField <> nil) then
begin
FChanging := True;
try
FDataLink.DataSet.GotoBookmark(Pointer(Items.Objects[ItemIndex]));
finally
FChanging := False;
end;
end;
inherited Select;
end;
procedure TJvDBCustomSearchComboBox.Refresh;
begin
ReadList;
end;
procedure TJvDBCustomSearchComboBox.Scroll(Distance: Integer);
begin
if FChanging then
Exit;
FChanging := True;
try
ItemIndex := ItemIndex + Distance;
finally
FChanging := False;
end;
end;
procedure TJvDBCustomSearchComboBox.ReadList;
var
Bmrk: {$IFDEF RTL200_UP}TBookmark{$ELSE}TBookmarkStr{$ENDIF RTL200_UP};
N, CurIndex: Integer;
begin
if (FDataLink.DataField = nil) or (FDataLink.DataSet = nil) or
(not FDataLink.DataSet.Active) then
Exit;
ClearList;
CurIndex := -1;
with FDataLink.DataSet do
begin
Bmrk := Bookmark;
DisableControls;
N := 0;
try
First;
while not EOF do
begin
FBookmarks.Add(GetBookmark);
Items.AddObject(FieldByName(FDataLink.FDataFieldName).DisplayText, TObject(FBookmarks[N]));
if {$IFDEF RTL200_UP}CompareBookmarks(Bookmark, Bmrk) = 0{$ELSE}Bookmark = Bmrk{$ENDIF RTL200} then
CurIndex := N;
Inc(N);
Next;
end;
Bookmark := Bmrk;
finally
EnableControls;
end;
ItemIndex := CurIndex;
end;
end;
procedure TJvDBCustomSearchComboBox.ClearList;
var
I: Integer;
begin
if Assigned(FDataLink.DataSet) then
for I := 0 to FBookmarks.Count - 1 do
FDataLink.DataSet.FreeBookmark(FBookmarks[I]);
FBookmarks.Clear;
if HandleAllocated and not (csDestroying in ComponentState) then // TCustomComboBox uses SendMessage(Handle, ...) to clear items
Items.Clear;
end;
function TJvDBCustomSearchComboBox.GetResult: Variant;
begin
Result := Null;
if Assigned(FDataLink.DataSet) and (DataResult <> '') then
Result := FDataLink.DataSet.Lookup(DataField, Text, DataResult);
end;
{$IFDEF UNITVERSIONING}
initialization
RegisterUnitVersion(HInstance, UnitVersioning);
finalization
UnregisterUnitVersion(HInstance);
{$ENDIF UNITVERSIONING}
end.