{------------------------------------------------------------------------------- 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/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: SynDBEdit.pas, released 2000-05-05. The Original Code is based on DBmwEdit.pas by Vladimir Kuznetsov, part of the mwEdit component suite. Portions created by Vladimir Kuznetsov are Copyright (C) 1999 Vladimir Kuznetsov. Unicode translation by Maël Hörz. All Rights Reserved. Contributors to the SynEdit and mwEdit projects are listed in the Contributors.txt file. Alternatively, the contents of this file may be used under the terms of the GNU General Public License Version 2 or later (the "GPL"), in which case the provisions of the GPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the GPL. $Id: SynDBEdit.pas,v 1.11.2.2 2009/06/14 13:33:38 maelh Exp $ You may retrieve the latest version of this file at the SynEdit home page, located at http://SynEdit.SourceForge.net Known Issues: -------------------------------------------------------------------------------} {$IFNDEF QSYNDBEDIT} unit SynDBEdit; {$ENDIF} {$I SynEdit.inc} interface uses {$IFNDEF SYN_COMPILER_3_UP} DbTables, {$ENDIF} Windows, Messages, Controls, DbCtrls, SynEdit, SynEditKeyCmds, SysUtils, Classes, DB; type TCustomDBSynEdit = class(TCustomSynEdit) private FDataLink: TFieldDataLink; FEditing: Boolean; FBeginEdit: Boolean; FLoadData: TNotifyEvent; procedure DataChange(Sender: TObject); procedure EditingChange(Sender: TObject); function GetDataField: string; function GetDataSource: TDataSource; function GetField: TField; procedure SetDataField(const Value: string); procedure SetDataSource(Value: TDataSource); procedure SetEditing(Value: Boolean); procedure UpdateData(Sender: TObject); private procedure CMEnter(var Msg: TCMEnter); message CM_ENTER; procedure CMExit(var Msg: TCMExit); message CM_EXIT; procedure CMGetDataLink(var Msg: TMessage); message CM_GETDATALINK; protected function GetReadOnly: Boolean; override; procedure Loaded; override; procedure DoChange; override; procedure SetReadOnly(Value: Boolean); override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure DragDrop(Source: TObject; X, Y: Integer); override; procedure ExecuteCommand(Command: TSynEditorCommand; AChar: WideChar; Data: Pointer); override; procedure LoadMemo; procedure Notification(AComponent: TComponent; Operation: TOperation); override; protected property DataField: string read GetDataField write SetDataField; property DataSource: TDataSource read GetDataSource write SetDataSource; property Field: TField read GetField; property OnLoadData: TNotifyEvent read FLoadData write FLoadData; end; TDBSynEdit = class(TCustomDBSynEdit) published // TCustomDBSynEdit properties property DataField; property DataSource; property Field; // TCustomDBSynEdit events property OnLoadData; // inherited properties property Align; {$IFDEF SYN_COMPILER_4_UP} property Anchors; property Constraints; {$ENDIF} property Color; property Ctl3D; property Enabled; property Font; property Height; property Name; property ParentColor; property ParentCtl3D; property ParentFont; property ParentShowHint; property PopupMenu; property ShowHint; property TabOrder; property TabStop default True; property Tag; property Visible; property Width; // inherited events property OnClick; property OnDblClick; property OnDragDrop; property OnDragOver; {$IFDEF SYN_COMPILER_4_UP} property OnEndDock; {$ENDIF} property OnEndDrag; property OnEnter; property OnExit; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnMouseDown; property OnMouseMove; property OnMouseUp; {$IFDEF SYN_COMPILER_4_UP} property OnStartDock; {$ENDIF} property OnStartDrag; // TCustomSynEdit properties property BookMarkOptions; property BorderStyle; property ExtraLineSpacing; property Gutter; property HideSelection; property Highlighter; property ImeMode; property ImeName; property InsertCaret; property InsertMode; property Keystrokes; property MaxScrollWidth; property MaxUndo; property Options; property OverwriteCaret; property ReadOnly; property RightEdge; property RightEdgeColor; property ScrollBars; property SearchEngine; property SelectedColor; property SelectionMode; property TabWidth; property WantTabs; // TCustomSynEdit events property OnChange; property OnCommandProcessed; property OnDropFiles; property OnGutterClick; property OnGutterGetText; property OnGutterPaint; property OnPaint; property OnPlaceBookmark; property OnProcessCommand; property OnProcessUserCommand; property OnReplaceText; property OnSpecialLineColors; property OnStatusChange; property OnPaintTransient; end; implementation constructor TCustomDBSynEdit.Create(AOwner: TComponent); begin inherited Create(AOwner); FDataLink := TFieldDataLink.Create; FDataLink.Control := Self; FDataLink.OnDataChange := DataChange; FDataLink.OnEditingChange := EditingChange; FDataLink.OnUpdateData := UpdateData; end; destructor TCustomDBSynEdit.Destroy; begin FDataLink.Free; FDataLink := nil; inherited Destroy; end; procedure TCustomDBSynEdit.CMEnter(var Msg: TCMEnter); begin SetEditing(True); inherited; end; procedure TCustomDBSynEdit.CMExit(var Msg: TCMExit); begin try FDataLink.UpdateRecord; except SetFocus; raise; end; SetEditing(False); inherited; end; procedure TCustomDBSynEdit.CMGetDataLink(var Msg: TMessage); begin Msg.Result := LRESULT(FDataLink); end; procedure TCustomDBSynEdit.DataChange(Sender: TObject); begin if FDataLink.Field <> nil then begin if FBeginEdit then begin FBeginEdit := False; Exit; end; {$IFDEF SYN_COMPILER_3_UP} if FDataLink.Field.IsBlob then LoadMemo else {$ENDIF} Text := FDataLink.Field.Text; if Assigned(FLoadData) then FLoadData(Self); end else begin if csDesigning in ComponentState then Text := Name else Text := ''; end; end; procedure TCustomDBSynEdit.DragDrop(Source: TObject; X, Y: Integer); begin FDataLink.Edit; inherited; end; procedure TCustomDBSynEdit.EditingChange(Sender: TObject); begin if FDataLink.Editing then begin if Assigned(FDataLink.DataSource) and (FDataLink.DataSource.State <> dsInsert) then FBeginEdit := True; end; end; procedure TCustomDBSynEdit.ExecuteCommand(Command: TSynEditorCommand; AChar: WideChar; Data: Pointer); begin // cancel on [ESC] if (Command = ecChar) and (AChar = #27) then FDataLink.Reset // set editing state if editor command else if (Command >= ecEditCommandFirst) and (Command <= ecEditCommandLast) then if not FDataLink.Edit then Exit; inherited; end; function TCustomDBSynEdit.GetDataField: string; begin Result := FDataLink.FieldName; end; function TCustomDBSynEdit.GetDataSource: TDataSource; begin Result := FDataLink.DataSource; end; function TCustomDBSynEdit.GetField: TField; begin Result := FDataLink.Field; end; function TCustomDBSynEdit.GetReadOnly: Boolean; begin Result := FDataLink.ReadOnly; end; procedure TCustomDBSynEdit.Loaded; begin inherited Loaded; if csDesigning in ComponentState then DataChange(Self); end; procedure TCustomDBSynEdit.LoadMemo; {$IFDEF UNICODE} const BlobFieldWideText = [ftWideMemo,ftWideString]; {$ENDIF} {$IFDEF SYN_COMPILER_3_UP} var BlobStream: TStream; {$ELSE} var BlobStream: TBlobStream; BlobField: TBlobField; {$ENDIF} begin try {$IFDEF SYN_COMPILER_3_UP} BlobStream := FDataLink.DataSet.CreateBlobStream(FDataLink.Field, bmRead); {$ELSE} BlobField := FDataLink.Field as TBlobField; BlobStream := TBlobStream.Create(BlobField, bmRead); {$ENDIF} Lines.BeginUpdate; {$IFDEF UNICODE} //03.12.2019 fix for unicode //Tested on UTF8 TEXT Sqlite3 & Zeos Unicode (UTF16) v7.2.6 //For UTF8 use: System.SysUtils.TEncoding.UTF8 if ((FDataLink.Field is TBlobField) and (TBlobField(FDataLink.Field).BlobType in BlobFieldWideText)) then Lines.LoadFromStream(BlobStream, TEncoding.Unicode) else Lines.LoadFromStream(BlobStream, TEncoding.Default); {$ELSE} //Non Unicode Lines.LoadFromStream(BlobStream); {$ENDIF} Lines.EndUpdate; BlobStream.Free; Modified := False; ClearUndo; except // Memo too large on E: EInvalidOperation do Lines.Text := Format('(%s)', [E.Message]); end; EditingChange(Self); end; procedure TCustomDBSynEdit.DoChange; begin FDataLink.Modified; inherited; end; procedure TCustomDBSynEdit.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if (Operation = opRemove) and (FDataLink <> nil) and (AComponent = DataSource) then DataSource := nil; end; procedure TCustomDBSynEdit.SetDataField(const Value: string); begin FDataLink.FieldName := Value; end; procedure TCustomDBSynEdit.SetDataSource(Value: TDataSource); begin if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then FDataLink.DataSource := Value; if Value <> nil then Value.FreeNotification(Self); end; procedure TCustomDBSynEdit.SetEditing(Value: Boolean); begin if FEditing <> Value then begin FEditing := Value; {$IFDEF SYN_COMPILER_3_UP} if not Assigned(FDataLink.Field) or not FDataLink.Field.IsBlob then {$ENDIF} FDataLink.Reset; end; end; procedure TCustomDBSynEdit.SetReadOnly(Value: Boolean); begin FDataLink.ReadOnly := Value; end; procedure TCustomDBSynEdit.UpdateData(Sender: TObject); {$IFDEF SYN_COMPILER_3_UP} var BlobStream: TStream; {$ENDIF} begin {$IFDEF SYN_COMPILER_3_UP} if FDataLink.Field.IsBlob then begin BlobStream := FDataLink.DataSet.CreateBlobStream(FDataLink.Field, bmWrite); Lines.SaveToStream(BlobStream); BlobStream.Free; end else {$ENDIF} FDataLink.Field.AsString := Text; end; end.