ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/ibcontrols/IBLookupComboEditBox.pas
Revision: 311
Committed: Mon Aug 24 09:32:58 2020 UTC (4 years, 3 months ago) by tony
Content type: text/x-pascal
File size: 21140 byte(s)
Log Message:
Fixes merged

File Contents

# User Rev Content
1 tony 21 (*
2     * IBX For Lazarus (Firebird Express)
3     *
4     * The contents of this file are subject to the Initial Developer's
5     * Public License Version 1.0 (the "License"); you may not use this
6     * file except in compliance with the License. You may obtain a copy
7     * of the License here:
8     *
9     * http://www.firebirdsql.org/index.php?op=doc&id=idpl
10     *
11     * Software distributed under the License is distributed on an "AS
12     * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
13     * implied. See the License for the specific language governing rights
14     * and limitations under the License.
15     *
16     * The Initial Developer of the Original Code is Tony Whyman.
17     *
18 tony 23 * The Original Code is (C) 2015 Tony Whyman, MWA Software
19 tony 21 * (http://www.mwasoftware.co.uk).
20     *
21     * All Rights Reserved.
22     *
23     * Contributor(s): ______________________________________.
24     *
25     *)
26     unit IBLookupComboEditBox;
27    
28     {$mode objfpc}{$H+}
29    
30     interface
31    
32     uses
33 tony 263 Classes, SysUtils, LCLType, LResources, Forms, Controls, Graphics, Dialogs, DbCtrls,
34     ExtCtrls, IBSQLParser, DB, StdCtrls, IBCustomDataSet, LCLVersion;
35 tony 21
36     type
37    
38     {TIBLookupComboEditBox is a TDBLookupComboBox descendent that implements "autocomplete"
39     of typed in text and "autoinsert" of new entries. Autocomplete uses SQL manipulation
40     to revise the available list and restrict it to items that are prefixed by the
41     typed text (either case sensitive or case insenstive). Autoinsert allows a
42     newly typed entry to be added to the list dataset and included in the available
43     list items. }
44    
45     TAutoInsert = procedure(Sender: TObject; aText: string; var NewKeyValue: variant) of object;
46     TCanAutoInsert = procedure (Sender: TObject; aText: string; var Accept: boolean) of object;
47    
48     TIBLookupComboEditBox = class;
49    
50     { TIBLookupComboDataLink }
51    
52     TIBLookupComboDataLink = class(TDataLink)
53     private
54     FOwner: TIBLookupComboEditBox;
55     protected
56     procedure ActiveChanged; override;
57 tony 278 {$if lcl_fullversion < 2000000}
58 tony 209 procedure DataEvent(Event: TDataEvent; Info: Ptrint); override;
59 tony 272 {$endif}
60 tony 21 procedure RecordChanged(Field: TField); override;
61     procedure UpdateData; override;
62     public
63     constructor Create(AOwner: TIBLookupComboEditBox);
64     end;
65    
66 tony 27 { TIBLookupControlLink }
67 tony 21
68 tony 27 TIBLookupControlLink = class(TIBControlLink)
69     private
70     FOwner: TIBLookupComboEditBox;
71     protected
72     procedure UpdateSQL(Sender: TObject); override;
73     public
74     constructor Create(AOwner: TIBLookupComboEditBox);
75     end;
76    
77    
78 tony 21 { TIBLookupComboEditBox }
79    
80     TIBLookupComboEditBox = class(TDBLookupComboBox)
81     private
82     { Private declarations }
83     FDataLink: TIBLookupComboDataLink;
84 tony 27 FIBLookupControlLink: TIBLookupControlLink;
85 tony 21 FAutoComplete: boolean;
86     FAutoInsert: boolean;
87     FKeyPressInterval: integer;
88     FOnCanAutoInsert: TCanAutoInsert;
89     FRelationName: string;
90     FTimer: TTimer;
91     FFiltered: boolean;
92     FOnAutoInsert: TAutoInsert;
93     FOriginalTextValue: string;
94     FUpdating: boolean;
95     FInserting: boolean;
96     FExiting: boolean;
97 tony 35 FForceAutoComplete: boolean;
98     FInCheckAndInsert: boolean;
99 tony 21 FLastKeyValue: variant;
100 tony 64 FCurText: string;
101 tony 143 FModified: boolean;
102 tony 21 procedure DoActiveChanged(Data: PtrInt);
103     function GetAutoCompleteText: TComboBoxAutoCompleteText;
104     function GetListSource: TDataSource;
105     function GetRelationNameQualifier: string;
106     procedure HandleTimer(Sender: TObject);
107 tony 27 procedure IBControlLinkChanged;
108 tony 21 procedure ResetParser;
109     procedure RecordChanged(Sender: TObject; aField: TField);
110     procedure SetAutoCompleteText(AValue: TComboBoxAutoCompleteText);
111     procedure SetListSource(AValue: TDataSource);
112     procedure UpdateList;
113     procedure UpdateSQL(Sender: TObject; Parser: TSelectSQLParser);
114     procedure HandleEnter(Data: PtrInt);
115     procedure UpdateLinkData(Sender: TObject);
116 tony 291 procedure ValidateListField;
117 tony 21 protected
118     { Protected declarations }
119     procedure ActiveChanged(Sender: TObject);
120     procedure CheckAndInsert;
121     procedure DoEnter; override;
122     procedure DoExit; override;
123 tony 275 {$if lcl_fullversion >= 2000002}
124 tony 263 {Deferred update changes in Lazarus 2.0 stop the combo box working when
125     the datasource is nil. We thus have to reverse out the changes :(}
126     function DoEdit: boolean; override;
127     procedure Change; override;
128     procedure CloseUp; override;
129     procedure Select; override;
130     {$ifend}
131 tony 276 {$if lcl_fullversion = 2000002}
132     procedure UTF8KeyPress(var UTF8Key: TUTF8Char); override;
133     {$ifend}
134 tony 21 procedure KeyUp(var Key: Word; Shift: TShiftState); override;
135 tony 29 procedure Loaded; override;
136 tony 27 procedure Notification(AComponent: TComponent; Operation: TOperation); override;
137 tony 21 procedure SetItemIndex(const Val: integer); override;
138     procedure UpdateShowing; override;
139 tony 143 procedure UpdateData(Sender: TObject); override;
140 tony 21 public
141     { Public declarations }
142     constructor Create(TheComponent: TComponent); override;
143     destructor Destroy; override;
144     procedure EditingDone; override;
145     published
146     { Published declarations }
147     property AutoInsert: boolean read FAutoInsert write FAutoInsert;
148     property AutoComplete: boolean read FAutoComplete write FAutoComplete default true;
149     property AutoCompleteText: TComboBoxAutoCompleteText read GetAutoCompleteText
150     write SetAutoCompleteText;
151     property ItemHeight;
152     property ItemWidth;
153     property ListSource: TDataSource read GetListSource write SetListSource;
154 tony 27 property KeyPressInterval: integer read FKeyPressInterval write FKeyPressInterval default 200;
155 tony 21 property RelationName: string read FRelationName write FRelationName;
156     property OnAutoInsert: TAutoInsert read FOnAutoInsert write FOnAutoInsert;
157     property OnCanAutoInsert: TCanAutoInsert read FOnCanAutoInsert write FOnCanAutoInsert;
158     end;
159    
160    
161     implementation
162    
163 tony 291 uses Variants, LCLProc, LazUTF8, IBUtils, IBMessages;
164 tony 21
165 tony 27 { TIBLookupControlLink }
166 tony 21
167 tony 27 constructor TIBLookupControlLink.Create(AOwner: TIBLookupComboEditBox);
168 tony 21 begin
169 tony 27 inherited Create;
170     FOwner := AOwner;
171 tony 21 end;
172    
173 tony 27 procedure TIBLookupControlLink.UpdateSQL(Sender: TObject);
174 tony 21 begin
175 tony 27 FOwner.UpdateSQL(self,TIBParserDataSet(Sender).Parser)
176     end;
177 tony 21
178 tony 27 { TIBLookupComboDataLink }
179    
180     procedure TIBLookupComboDataLink.ActiveChanged;
181     begin
182     FOwner.ActiveChanged(self)
183 tony 21 end;
184    
185 tony 278 {$if lcl_fullversion < 2000000}
186 tony 209 procedure TIBLookupComboDataLink.DataEvent(Event: TDataEvent; Info: Ptrint);
187     begin
188     inherited DataEvent(Event, Info);
189     if Event = deLayoutChange then
190     FOwner.LookupCache := FOwner.LookupCache; {sneaky way of calling UpdateLookup}
191     end;
192 tony 272 {$endif}
193 tony 209
194 tony 21 procedure TIBLookupComboDataLink.RecordChanged(Field: TField);
195     begin
196     FOwner.RecordChanged(self,Field);
197     end;
198    
199     procedure TIBLookupComboDataLink.UpdateData;
200     begin
201     FOwner.UpdateLinkData(self)
202     end;
203    
204     constructor TIBLookupComboDataLink.Create(AOwner: TIBLookupComboEditBox);
205     begin
206     inherited Create;
207     FOwner := AOwner
208     end;
209    
210     { TIBLookupComboEditBox }
211    
212     procedure TIBLookupComboEditBox.HandleTimer(Sender: TObject);
213     begin
214     FTimer.Interval := 0;
215     FFiltered := Text <> '';
216     UpdateList
217     end;
218    
219 tony 27 procedure TIBLookupComboEditBox.IBControlLinkChanged;
220     begin
221     if (ListSource <> nil) and (ListSource.DataSet <> nil) and (ListSource.DataSet is TIBParserDataSet) then
222     FIBLookupControlLink.IBDataSet := TIBCustomDataSet(ListSource.DataSet)
223     else
224     FIBLookupControlLink.IBDataSet := nil;
225     end;
226    
227 tony 21 function TIBLookupComboEditBox.GetListSource: TDataSource;
228     begin
229     Result := inherited ListSource;
230     end;
231    
232     function TIBLookupComboEditBox.GetRelationNameQualifier: string;
233     begin
234     if FRelationName <> '' then
235     Result := FRelationName + '.'
236     else
237     Result := ''
238     end;
239    
240     procedure TIBLookupComboEditBox.ActiveChanged(Sender: TObject);
241     begin
242     if not FInserting and not FUpdating then
243     Application.QueueAsyncCall(@DoActiveChanged,0);
244 tony 27 IBControlLinkChanged;
245 tony 21 end;
246    
247     procedure TIBLookupComboEditBox.DoActiveChanged(Data: PtrInt);
248     begin
249     if AppDestroying in Application.Flags then Exit;
250    
251     if (DataSource = nil) and assigned(ListSource) and assigned(ListSource.DataSet)
252     and ListSource.DataSet.Active then
253     begin
254     begin
255 tony 291 ValidateListField;
256 tony 21 if varIsNull(FLastKeyValue) and (ItemIndex = -1) then
257     KeyValue := ListSource.DataSet.FieldByName(KeyField).AsVariant
258     else
259     begin
260     KeyValue := FLastKeyValue;
261     UpdateData(self); {Force auto scroll}
262     if varIsNull(KeyValue) then {Value not present}
263     Text := ListSource.DataSet.FieldByName(ListField).AsString
264     end;
265     end;
266     end
267     else
268     if (DataSource <> nil) and assigned(DataSource.DataSet) and
269     (DataSource.DataSet.Active) and (DataField <> '') then
270     begin
271     ResetParser;
272     KeyValue := Field.AsVariant;
273     end
274     else
275     Text := '';
276     FOriginalTextValue := Text;
277     end;
278    
279     function TIBLookupComboEditBox.GetAutoCompleteText: TComboBoxAutoCompleteText;
280     begin
281     Result := inherited AutoCompleteText;
282     if AutoComplete then
283     Result := Result + [cbactEnabled]
284     end;
285    
286     procedure TIBLookupComboEditBox.ResetParser;
287 tony 27 var curKeyValue: variant;
288 tony 21 begin
289     if FFiltered then
290     begin
291     FFiltered := false;
292 tony 27 curKeyValue := KeyValue;
293     Text := ''; {Ensure full list}
294 tony 21 UpdateList;
295 tony 27 KeyValue := curKeyValue;
296 tony 21 UpdateData(self); {Force Scroll}
297     end;
298     end;
299    
300     procedure TIBLookupComboEditBox.RecordChanged(Sender: TObject; aField: TField);
301     begin
302     {Make sure that we are in sync with other data controls}
303     if DataSource = nil then
304     begin
305     KeyValue := ListSource.DataSet.FieldByName(KeyField).AsVariant;
306     if VarIsNull(KeyValue) then {Probable deletion}
307     begin
308     UpdateList;
309     KeyValue := ListSource.DataSet.FieldByName(KeyField).AsVariant;
310     end;
311     end;
312     end;
313    
314     procedure TIBLookupComboEditBox.SetAutoCompleteText(
315     AValue: TComboBoxAutoCompleteText);
316     begin
317     if AValue <> AutoCompleteText then
318     begin
319     FAutoComplete := cbactEnabled in AValue;
320     inherited AutoCompleteText := AValue - [cbactEnabled]
321     end;
322     end;
323    
324     procedure TIBLookupComboEditBox.SetListSource(AValue: TDataSource);
325     begin
326     if AValue <> inherited ListSource then
327     begin
328     FDataLink.DataSource := AValue;
329     inherited ListSource := AValue;
330 tony 27 IBControlLinkChanged;
331 tony 21 end;
332     end;
333    
334     procedure TIBLookupComboEditBox.UpdateList;
335     { Note: Algorithm taken from TCustomComboBox.KeyUp but modified to use the
336     ListSource DataSet as the source for the autocomplete text. It also runs
337     after a delay rather than immediately on keyup
338     }
339     var
340     iSelStart: Integer; // char position
341     sCompleteText, sPrefixText, sResultText: string;
342     begin
343     if assigned(ListSource) and assigned(ListSource.DataSet) and (ListSource.DataSet is TIBCustomDataSet)
344     and ListSource.DataSet.Active then
345     begin
346 tony 64 FCurText := Text;
347 tony 21 FUpdating := true;
348     try
349     iSelStart := SelStart;//Capture original cursor position
350     if ((iSelStart < UTF8Length(Text)) and
351     (cbactEndOfLineComplete in AutoCompleteText)) then
352     Exit;
353     sPrefixText := UTF8Copy(Text, 1, iSelStart);
354     ListSource.DataSet.Active := false;
355     ListSource.DataSet.Active := true;
356 tony 64 Text := FCurText;
357     if not FExiting and (FForceAutoComplete or Focused) and (FCurText <> '')then
358 tony 21 begin
359     if ListSource.DataSet.Active and (ListSource.DataSet.RecordCount > 0) then
360     begin
361     sCompleteText := ListSource.DataSet.FieldByName(ListField).AsString;
362 tony 64 if (sCompleteText <> FCurText) then
363 tony 21 begin
364 tony 225 KeyValue := ListSource.DataSet.FieldByName(KeyField).AsVariant;
365 tony 21 sResultText := sCompleteText;
366     if ((cbactEndOfLineComplete in AutoCompleteText) and
367     (cbactRetainPrefixCase in AutoCompleteText)) then
368     begin//Retain Prefix Character cases
369     UTF8Delete(sResultText, 1, iSelStart);
370     UTF8Insert(sPrefixText, sResultText, 1);
371     end;
372     Text := sResultText;
373     end;
374 tony 311 SelStart := iSelStart;
375     SelLength := UTF8Length(Text) - iSelStart;
376 tony 65 end
377     else
378     begin
379     SelStart := iSelStart;
380     SelLength := 0;
381 tony 21 end;
382     end;
383     finally
384     FUpdating := false
385     end;
386 tony 143 FModified := true;
387 tony 21 end;
388     end;
389    
390     procedure TIBLookupComboEditBox.UpdateSQL(Sender: TObject;
391     Parser: TSelectSQLParser);
392     var FieldPosition: integer;
393 tony 64 FilterText: string;
394 tony 291 SQLDialect: integer;
395 tony 21 begin
396     if FFiltered then
397     begin
398 tony 64 if FUpdating then
399     FilterText := FCurText
400     else
401     FilterText := Text;
402 tony 291
403     if Parser.DataSet <> nil then
404     SQLDialect := (Parser.DataSet as TIBCustomDataSet).Database.SQLDialect
405     else
406     SQLDialect := 1;
407    
408 tony 21 if cbactSearchCaseSensitive in AutoCompleteText then
409 tony 291 Parser.Add2WhereClause(GetRelationNameQualifier + QuoteIdentifierIfNeeded(SQLDialect,ListField) + ' Like ''' +
410 tony 272 SQLSafeString(FilterText) + '%''')
411 tony 21 else
412 tony 291 Parser.Add2WhereClause('Upper(' + GetRelationNameQualifier + QuoteIdentifierIfNeeded(SQLDialect,ListField) + ') Like Upper(''' +
413 tony 272 SQLSafeString(FilterText) + '%'')');
414 tony 21
415 tony 41 if cbactSearchAscending in AutoCompleteText then
416     begin
417     FieldPosition := Parser.GetFieldPosition(ListField);
418     if FieldPosition = 0 then Exit;
419 tony 21
420 tony 41 Parser.OrderByClause := IntToStr(FieldPosition) + ' ascending';
421     end;
422 tony 21 end;
423     end;
424    
425     procedure TIBLookupComboEditBox.HandleEnter(Data: PtrInt);
426     begin
427 tony 31 if AppDestroying in Application.Flags then Exit;
428 tony 27 SelectAll
429 tony 21 end;
430    
431     procedure TIBLookupComboEditBox.UpdateLinkData(Sender: TObject);
432     begin
433     if FInserting then
434     ListSource.DataSet.FieldByName(ListField).AsString := Text
435     end;
436    
437 tony 291 {Check to ensure that ListField exists and convert to upper case if necessary}
438    
439     procedure TIBLookupComboEditBox.ValidateListField;
440     var SQLDialect: integer;
441     FieldNames: TStringList;
442     begin
443 tony 311 if (ListSource = nil) or (ListSource.DataSet = nil) or
444     not (ListSource.DataSet is TIBCustomDataSet) or
445     ((ListSource.DataSet as TIBCustomDataSet).Database = nil) then Exit;
446 tony 291 SQLDialect := (ListSource.DataSet as TIBCustomDataSet).Database.SQLDialect;
447     FieldNames := TStringList.Create;
448     try
449     FieldNames.CaseSensitive := true;
450     FieldNames.Sorted := true;
451     FieldNames.Duplicates := dupError;
452     ListSource.DataSet.GetFieldNames(FieldNames);
453     if FieldNames.IndexOf(ListField) = -1 then {not found}
454     begin
455     if (SQLDialect = 3) and (FieldNames.IndexOf(AnsiUpperCase(ListField)) <> - 1) then {normalise to upper case}
456     ListField := AnsiUpperCase(ListField)
457     else
458     IBError(ibxeListFieldNotFound,[ListField])
459     end;
460     finally
461     FieldNames.Free;
462     end;
463     end;
464    
465 tony 21 procedure TIBLookupComboEditBox.CheckAndInsert;
466     var Accept: boolean;
467     NewKeyValue: variant;
468     begin
469 tony 35 if FInCheckAndInsert then Exit;
470     FInCheckAndInsert := true;
471 tony 21 try
472 tony 35 if AutoInsert and (Text <> '') and assigned(ListSource) and assigned(ListSource.DataSet)
473     and ListSource.DataSet.Active and (ListSource.DataSet.RecordCount = 0) then
474     try
475     {Is it OK to insert a new list member?}
476     Accept := true;
477     if assigned(FOnCanAutoInsert) then
478     OnCanAutoInsert(self,Text,Accept);
479     if not Accept then
480     begin
481     ResetParser;
482     Text := FOriginalTextValue;
483     SelectAll;
484     Exit;
485     end;
486 tony 21
487 tony 35 FInserting := true;
488     try
489     {New Value}
490     FFiltered := false;
491     if assigned(FOnAutoInsert) then
492     begin
493     {In an OnAutoInsert handler, the client is expected to insert the new
494     row into the List DataSet and to set the KeyValue property to the
495     value of the primary key of the new row.}
496     OnAutoInsert(self,Text,NewKeyValue);
497     end
498     else
499     begin
500     ListSource.DataSet.Append;
501     {The new KeyValue should be determined by an external generator or
502     in the "OnInsert" handler. If it is the same as the ListField, then
503     it will be set from the UpdateLinkData method}
504     try
505     ListSource.DataSet.Post;
506     except
507     ListSource.DataSet.Cancel;
508     raise;
509     end;
510     NewKeyValue := ListSource.DataSet.FieldByName(KeyField).AsVariant;
511     end;
512     Text := ''; {Ensure full list}
513     UpdateList;
514     KeyValue := NewKeyValue;
515     UpdateData(nil); {Force sync with DataField}
516     finally
517     FInserting := false
518     end;
519     except
520     Text := FOriginalTextValue;
521     ResetParser;
522     raise;
523     end;
524     finally
525     FInCheckAndInsert := false
526 tony 21 end;
527     end;
528    
529     procedure TIBLookupComboEditBox.DoEnter;
530     begin
531     inherited DoEnter;
532     FOriginalTextValue:= Text;
533     ResetParser;
534     Application.QueueAsyncCall(@HandleEnter,0);
535     end;
536    
537     procedure TIBLookupComboEditBox.DoExit;
538     begin
539 tony 31 if FTimer.Interval <> 0 then
540     HandleTimer(nil);
541 tony 21 FExiting := true;
542     try
543     CheckAndInsert;
544     ResetParser;
545     FTimer.Interval := 0;
546     finally
547     FExiting := false;
548     end;
549     inherited DoExit;
550     end;
551    
552     procedure TIBLookupComboEditBox.KeyUp(var Key: Word; Shift: TShiftState);
553     begin
554     inherited KeyUp(Key, Shift);
555     if Key = VK_ESCAPE then
556     begin
557     SelStart := UTF8Length(Text); {Ensure end of line selection}
558     ResetParser;
559     Text := FOriginalTextValue;
560     SelectAll;
561     end
562     else
563 tony 225 if AutoComplete and (Style <> csDropDownList) then
564 tony 35 begin
565 tony 225 if (Key = VK_BACK) or (Key = VK_DELETE) then
566     begin
567     if SelStart = 0 then
568     begin
569     SelStart := UTF8Length(Text);
570     SelLength := 0;
571     end;
572     FTimer.Interval := 0;
573     end
574     else
575     if IsEditableTextKey(Key) and
576     (not(cbactEndOfLineComplete in AutoCompleteText) or (SelStart = UTF8Length(Text))) then
577     begin
578     FTimer.Interval := 0;
579 tony 35 FTimer.Interval := FKeyPressInterval;
580 tony 225 end;
581 tony 35 end;
582 tony 21 end;
583    
584 tony 29 procedure TIBLookupComboEditBox.Loaded;
585     begin
586     inherited Loaded;
587     IBControlLinkChanged;
588     end;
589    
590 tony 27 procedure TIBLookupComboEditBox.Notification(AComponent: TComponent;
591     Operation: TOperation);
592     begin
593     inherited Notification(AComponent, Operation);
594     if (Operation = opRemove) and (AComponent = DataSource) then
595     ListSource := nil;
596     end;
597    
598 tony 21 procedure TIBLookupComboEditBox.SetItemIndex(const Val: integer);
599     begin
600 tony 225 if Val > 0 then
601     FCurText := '';
602 tony 21 inherited SetItemIndex(Val);
603     FLastKeyValue := KeyValue;
604     end;
605    
606     procedure TIBLookupComboEditBox.UpdateShowing;
607     begin
608     inherited UpdateShowing;
609     if Showing then {Ensure up-to-date as we were ignoring any changes}
610     ActiveChanged(nil);
611     end;
612    
613 tony 143 procedure TIBLookupComboEditBox.UpdateData(Sender: TObject);
614     begin
615     inherited UpdateData(Sender);
616 tony 225 if FCurText <> '' then
617     Text := FCurText + Text;
618 tony 143 FModified := false;
619     end;
620    
621 tony 276
622     {Workarounds due to bugs in various Lazarus 2.0 release candidates}
623 tony 275 {$if lcl_fullversion >= 2000002}
624 tony 263 type
625    
626     { THackedCustomComboBox }
627    
628     THackedCustomComboBox = class(TCustomComboBox)
629     private
630     procedure CallChange;
631 tony 276 procedure CallUTF8KeyPress(var UTF8Key: TUTF8Char);
632 tony 263 end;
633    
634     { THackedCustomComboBox }
635    
636     procedure THackedCustomComboBox.CallChange;
637     begin
638     inherited Change;
639     end;
640    
641 tony 276 procedure THackedCustomComboBox.CallUTF8KeyPress(var UTF8Key: TUTF8Char);
642     begin
643     inherited UTF8KeyPress(UTF8Key);
644     end;
645    
646 tony 263 procedure TIBLookupComboEditBox.Change;
647     begin
648 tony 275 if DataSource = nil then
649 tony 272 THackedCustomComboBox(self).CallChange
650     else
651     inherited Change;
652 tony 263 end;
653    
654     procedure TIBLookupComboEditBox.CloseUp;
655     begin
656 tony 272 inherited DoEdit;
657 tony 263 inherited CloseUp;
658 tony 272 EditingDone;
659 tony 263 end;
660    
661     procedure TIBLookupComboEditBox.Select;
662     begin
663     inherited Select;
664 tony 275 if DataSource = nil then
665 tony 272 inherited DoEdit;
666 tony 263 end;
667    
668     function TIBLookupComboEditBox.DoEdit: boolean;
669     begin
670     {DoEdit will swallow characters if no editable Field. Hence, to enabled
671     writing we must avoid calling the inherited method.}
672 tony 275 if DataSource = nil then
673 tony 263 Result := true
674     else
675     Result := inherited DoEdit;
676     end;
677     {$ifend}
678    
679 tony 276 {$if lcl_fullversion = 2000002}
680 tony 277 procedure TIBLookupComboEditBox.UTF8KeyPress(var UTF8Key: TUTF8Char);
681 tony 276 begin
682     if DataSource = nil then
683 tony 277 THackedCustomComboBox(self).CallUTF8KeyPress(UTF8Key)
684 tony 276 else
685     inherited;
686     end;
687     {$ifend}
688    
689    
690 tony 21 constructor TIBLookupComboEditBox.Create(TheComponent: TComponent);
691     begin
692     inherited Create(TheComponent);
693     FDataLink := TIBLookupComboDataLink.Create(self);
694 tony 27 FIBLookupControlLink := TIBLookupControlLink.Create(self);
695     FKeyPressInterval := 200;
696 tony 21 FAutoComplete := true;
697     FTimer := TTimer.Create(nil);
698     FTimer.Interval := 0;
699     FTimer.OnTimer := @HandleTimer;
700     FLastKeyValue := NULL;
701     end;
702    
703     destructor TIBLookupComboEditBox.Destroy;
704     begin
705     if assigned(FDataLink) then FDataLink.Free;
706 tony 27 if assigned(FIBLookupControlLink) then FIBLookupControlLink.Free;
707 tony 21 if assigned(FTimer) then FTimer.Free;
708 tony 80 Application.RemoveAsyncCalls(self);
709 tony 21 inherited Destroy;
710     end;
711    
712     procedure TIBLookupComboEditBox.EditingDone;
713     begin
714 tony 35 FForceAutoComplete := true;
715     try
716     if FTimer.Interval <> 0 then
717     HandleTimer(nil);
718     finally
719     FForceAutoComplete := false;
720     end;
721 tony 21 CheckAndInsert;
722 tony 225 FCurText := '';
723 tony 143 if FModified then
724     Change; {ensure Update}
725 tony 21 inherited EditingDone;
726     end;
727    
728     end.