Componentes.Terceros.DevExp.../internal/x.42/2/ExpressInspector/Sources/dxDBInsp.pas

1096 lines
32 KiB
ObjectPascal

{*******************************************************************}
{ }
{ Developer Express Visual Component Library }
{ Express data-aware inspector }
{ }
{ Copyright (c) 1998-2009 Developer Express Inc. }
{ ALL RIGHTS RESERVED }
{ }
{ The entire contents of this file is protected by U.S. and }
{ International Copyright Laws. Unauthorized reproduction, }
{ reverse-engineering, and distribution of all or any portion of }
{ the code contained in this file is strictly prohibited and may }
{ result in severe civil and criminal penalties and will be }
{ prosecuted to the maximum extent possible under the law. }
{ }
{ RESTRICTIONS }
{ }
{ THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED }
{ FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE }
{ COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE }
{ AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT }
{ AND PERMISSION FROM DEVELOPER EXPRESS INC. }
{ }
{ CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON }
{ ADDITIONAL RESTRICTIONS. }
{ }
{*******************************************************************}
unit dxDBInsp;
interface
{$I dxInsVer.inc}
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
dxCntner, dxEditor, dxInspct, DB{$IFNDEF DELPHI3}, DBTables{$ENDIF}, dxDBEdtr
{$IFDEF DELPHI6}, Variants{$ENDIF};
type
{ TdxInspectorDBRow }
TdxInspectorDBRow = class(TdxInspectorRow)
private
FField: TField;
FFieldName: string;
function GetField: TField;
protected
function GetActiveDataLink: Boolean;
function GetDataSet: TDataSet;
function GetDisplayText: string; override;
function GetEditText: string; override;
procedure SetEditText(const Value: string); override;
function GetdxInplaceEditClass: TdxInplaceEditClass; override;
function GetEditLimit: Integer; override;
function GetEditMaskRow: string; override;
// link
function GetLinkObject: TObject; override;
procedure SetLinkObject(Value: TObject); override;
function GetLinkObjectName: string; override;
procedure SetLinkObjectName(const Value: string); override;
public
procedure Assign(Source: TPersistent); override;
function DefaultCaption: string; override;
function DefaultMaxLength: Integer; override;
function DefaultReadOnly: Boolean; override;
function IsCanModify: Boolean; override;
function IsValidChar(InputChar: Char): Boolean; override;
property Field: TField read GetField;
published
property CharCase;
property FieldName: string read GetLinkObjectName write SetLinkObjectName;
end;
TdxDBInspector = class;
{ TdxInspectorDataLink }
TdxInspectorDataLink = class(TDataLink)
private
FInspector: TdxDBInspector;
FFieldCount: Integer;
FFieldMapSize: Integer;
FFieldMap: Pointer;
FModified: Boolean;
FDataSetChanged: Boolean;
function GetFields(I: Integer): TField;
protected
// override TDataLink
procedure ActiveChanged; override;
procedure DataSetChanged; override;
procedure FocusControl(Field: TFieldRef); override;
procedure LayoutChanged; override;
procedure RecordChanged(Field: TField); override;
procedure UpdateData; override;
function GetMappedIndex(RowIndex: Integer): Integer;
public
constructor Create(AInspector: TdxDBInspector);
destructor Destroy; override;
function AddMapping(const FieldName: string): Boolean;
procedure ClearMapping;
procedure Modified;
procedure Reset;
property FieldCount: Integer read FFieldCount;
property Fields[I: Integer]: TField read GetFields;
end;
{ TdxDBInspector }
TdxDBInspectorOption = (dioAutoBandCount, dioAutoWidth, dioBandSizing,
dioCancelOnExit, dioColumnSizing, dioDrawEndEllipsis, dioDynamicColumnSizing,
dioEditing, dioEnterThrough, dioNoCancel, dioRowAutoHeight, dioRowSizing,
dioStoreToRegistry, dioTabs, dioTabThrough);
TdxDBInspectorOptions = set of TdxDBInspectorOption;
TdxDBInspector = class(TCustomdxInspectorControl)
private
FDataLink: TdxInspectorDataLink;
FDefaultFields: Boolean;
FInCanEditModify: Boolean;
FOptions: TdxDBInspectorOptions;
// dataset
function GetDataLinkModified: Boolean;
function GetDataSource: TDataSource;
function GetDefaultFields: Boolean;
function GetFocusedField: TField;
function GetOptions: TdxDBInspectorOptions;
procedure SetDataSource(Value: TDataSource);
procedure SetDefaultFields(Value: Boolean);
procedure SetFocusedField(Value: TField);
procedure SetOptions(Value: TdxDBInspectorOptions);
procedure CMExit(var Message: TMessage); message CM_EXIT;
protected
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
function AcquireFocus: Boolean; override;
function CreateNode: TdxInspectorNode; override;
function SaveNodes: Boolean; override;
//Editor
function CanEditAcceptKey(Key: Char): Boolean; override;
function CanEditModify: Boolean; override;
function CanEditShow: Boolean; override;
function AssignEditValue(ANode: TdxInspectorNode; AInplaceEdit: TdxInplaceEdit): Variant; override;
function IsDefaultEqualValues(const AValue: Variant; ARow: TdxInspectorRow): Boolean; override;
// DataSet
procedure DefineFieldMap; virtual;
procedure DoInternalLayout; override;
procedure LinkActive(Value: Boolean); virtual;
procedure RecordChanged(Field: TField; DataSetChanged: Boolean);
procedure UpdateActive;
procedure UpdateData;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure ClearRows; override;
function GetDefaultRowClass: TdxInspectorRowClass; override;
{$IFDEF DELPHI4}
function ExecuteAction(Action: TBasicAction): Boolean; override;
function UpdateAction(Action: TBasicAction): Boolean; override;
{$ENDIF}
property DataLink: TdxInspectorDataLink read FDataLink;
property DragNode;
property FocusedField: TField read GetFocusedField write SetFocusedField;
property IsModified: Boolean read GetDataLinkModified;
property ReadOnly;
published
property Align;
property BorderStyle;
property Color;
property Ctl3D;
property DataSource: TDataSource read GetDataSource write SetDataSource;
property DefaultFields: Boolean read GetDefaultFields write SetDefaultFields default True;
property DragCursor;
property DragMode;
property Enabled;
property Font;
property ParentColor;
property ParentCtl3D;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property TabOrder;
property Visible;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnStartDrag;
property BandWidth;
property ComplexRowSeparator;
property DividerPos;
property Flat;
property GridColor;
property Images;
property MaxRowTextLineCount;
property MinBandWidth;
property MinColumnWidth;
property Options: TdxDBInspectorOptions read GetOptions write SetOptions
default [dioEditing, dioBandSizing, dioColumnSizing, dioAutoWidth, dioCancelOnExit, dioDynamicColumnSizing];
property PaintStyle;
property RegistryPath;
property RowHeight;
property OnChangeNode;
property OnDrawCaption;
property OnDrawValue;
property OnEditing;
property OnEditChange;
property OnEdited;
property OnEditValidate;
property OnGetEditColor;
property OnGetEditFont;
property OnHideCustomizeForm;
property OnShowCustomizeForm;
property ShowRowHint;
{$IFDEF DELPHI4}
property Anchors;
property Constraints;
{$ENDIF}
{$IFDEF DELPHI5}
property OnContextPopup;
{$ENDIF}
end;
TdxDBInspectorRowClassInfo = record
RowClass: TdxInspectorRowClass;
Version: Integer;
end;
TInitDBInspectorRowClassProc = procedure (AFieldType: TFieldType; AFieldKind: TFieldKind;
var Info: TdxDBInspectorRowClassInfo);
const
DefaultDBRowType: array[ftUnknown..ftTypedBinary] of TdxDBInspectorRowClassInfo = (
(RowClass: nil; Version: 0), { ftUnknown }
(RowClass: TdxInspectorDBRow; Version: 0), { ftString }
(RowClass: TdxInspectorDBRow; Version: 0), { ftSmallint }
(RowClass: TdxInspectorDBRow; Version: 0), { ftInteger }
(RowClass: TdxInspectorDBRow; Version: 0), { ftWord }
(RowClass: TdxInspectorDBRow; Version: 0), { ftBoolean }
(RowClass: TdxInspectorDBRow; Version: 0), { ftFloat }
(RowClass: TdxInspectorDBRow; Version: 0), { ftCurrency }
(RowClass: TdxInspectorDBRow; Version: 0), { ftBCD }
(RowClass: TdxInspectorDBRow; Version: 0), { ftDate }
(RowClass: TdxInspectorDBRow; Version: 0), { ftTime }
(RowClass: TdxInspectorDBRow; Version: 0), { ftDateTime }
(RowClass: TdxInspectorDBRow; Version: 0), { ftBytes }
(RowClass: TdxInspectorDBRow; Version: 0), { ftVarBytes }
(RowClass: TdxInspectorDBRow; Version: 0), { ftAutoInc }
(RowClass: TdxInspectorDBRow; Version: 0), { ftBlob }
(RowClass: TdxInspectorDBRow; Version: 0), { ftMemo }
(RowClass: TdxInspectorDBRow; Version: 0), { ftGraphic }
(RowClass: TdxInspectorDBRow; Version: 0), { ftFmtMemo }
(RowClass: TdxInspectorDBRow; Version: 0), { ftParadoxOle }
(RowClass: TdxInspectorDBRow; Version: 0), { ftDBaseOle }
(RowClass: TdxInspectorDBRow; Version: 0)); { ftTypedBinary }
DefaultLookupRowType: TdxDBInspectorRowClassInfo = (
RowClass: TdxInspectorDBRow; Version: 0);
function GetDefaultDBInspectorRowClass(AField: TField): TdxInspectorRowClass;
procedure InitDefaultRowClasses(Proc: TInitDBInspectorRowClassProc);
procedure ResetDefaultRowClasses;
implementation
{ TdxInspectorDBRow }
procedure TdxInspectorDBRow.Assign(Source: TPersistent);
begin
if Source is TdxInspectorDBRow then
begin
if Assigned(Inspector) then Inspector.BeginUpdate;
try
inherited Assign(Source);
FieldName := TdxInspectorDBRow(Source).FieldName;
finally
if Assigned(Inspector) then Inspector.EndUpdate;
end;
end
else
inherited Assign(Source);
end;
function TdxInspectorDBRow.DefaultCaption: string;
begin
if Assigned(Field) then
Result := Field.DisplayName
else Result := FieldName;
end;
function TdxInspectorDBRow.DefaultMaxLength: Integer;
begin
Result := 0;
if Assigned(Field) and (Field.DataType in [ftString{$IFDEF DELPHI4}, ftWideString{$ENDIF}]) then
Result := Field.Size;
end;
function TdxInspectorDBRow.DefaultReadOnly: Boolean;
begin
Result := False;
if Assigned(Field) then Result := FField.ReadOnly;
end;
function TdxInspectorDBRow.IsCanModify: Boolean;
begin
Result := GetActiveDataLink and Assigned(Field) and (Field.CanModify or (Field.Lookup and CanLookupFieldModify(Field))) and
(not {$IFDEF DELHPI3}Field.IsBlob{$ELSE}(Field is TBlobField){$ENDIF} or Assigned(Field.OnSetText));
end;
function TdxInspectorDBRow.IsValidChar(InputChar: Char): Boolean;
begin
Result := GetActiveDataLink and Assigned(Field) and Field.IsValidChar(InputChar);
end;
// protected TdxInspectorDBRow
function TdxInspectorDBRow.GetActiveDataLink: Boolean;
begin
Result := (Inspector <> nil) and (TdxDBInspector(Inspector).Datalink <> nil) and
(TdxDBInspector(Inspector).Datalink.Active);
end;
function TdxInspectorDBRow.GetDataSet: TDataSet;
begin
if (Inspector <> nil) and (TdxDBInspector(Inspector).Datalink <> nil) then
Result := TdxDBInspector(Inspector).Datalink.DataSet
else Result := nil;
end;
function TdxInspectorDBRow.GetDisplayText: String;
begin
if Assigned(Field) and GetActiveDataLink then
Result := Field.DisplayText
else Result := '';
end;
function TdxInspectorDBRow.GetEditText: String;
begin
if Assigned(Field) and GetActiveDataLink then
Result := Field.Text
else Result := '';
end;
procedure TdxInspectorDBRow.SetEditText(const Value: String);
begin
if Assigned(Field) and GetActiveDataLink then
Field.Text := Value;
end;
function TdxInspectorDBRow.GetdxInplaceEditClass: TdxInplaceEditClass;
begin
Result := TdxInplaceTextEdit;
end;
function TdxInspectorDBRow.GetEditLimit: Integer;
begin
Result := 0;
if Assigned(Field) and (Field.DataType in [ftString{$IFDEF DELPHI4}, ftWideString{$ENDIF}]) then
Result := Field.Size;
end;
function TdxInspectorDBRow.GetEditMaskRow: string;
begin
Result := '';
if GetActiveDataLink and Assigned(Field) then
Result := Field.EditMask;
end;
function TdxInspectorDBRow.GetLinkObject: TObject;
begin
Result := Field;
end;
procedure TdxInspectorDBRow.SetLinkObject(Value : TObject);
begin
FField := TField(Value);
end;
function TdxInspectorDBRow.GetLinkObjectName: String;
begin
Result := FFieldName;
end;
procedure TdxInspectorDBRow.SetLinkObjectName(const Value : String);
begin
FField := nil;
if (Inspector <> nil) and (GetDataSet <> nil) and
not (csLoading in Inspector.ComponentState) and
(Length(Value) > 0) then
FField := GetDataSet.FindField(Value); { no exceptions }
FFieldName := Value;
Changed;
end;
// private TdxInspectorDBRow
function TdxInspectorDBRow.GetField: TField;
begin
Result := FField;
end;
{ TdxInspectorDataLink }
const
MaxMapSize = (MaxInt div 2) div SizeOf(Integer);
type
TIntArray = array[0..MaxMapSize] of Integer;
PIntArray = ^TIntArray;
constructor TdxInspectorDataLink.Create(AInspector: TdxDBInspector);
begin
inherited Create;
FInspector := AInspector;
{$IFDEF DELPHI5}
VisualControl := True;
{$ENDIF}
end;
destructor TdxInspectorDataLink.Destroy;
begin
ClearMapping;
inherited Destroy;
end;
function TdxInspectorDataLink.AddMapping(const FieldName: string): Boolean;
var
Field: TField;
NewSize: Integer;
begin
Result := True;
Field := DataSet.FindField(FieldName);
if FFieldCount = FFieldMapSize then
begin
NewSize := FFieldMapSize;
if NewSize = 0 then
NewSize := 8
else
Inc(NewSize, NewSize);
if (NewSize < FFieldCount) then
NewSize := FFieldCount + 1;
if (NewSize > MaxMapSize) then
NewSize := MaxMapSize;
ReallocMem(FFieldMap, NewSize * SizeOf(Integer));
FFieldMapSize := NewSize;
end;
if Assigned(Field) then
begin
PIntArray(FFieldMap)^[FFieldCount] := Field.Index;
Field.FreeNotification(FInspector);
end
else
PIntArray(FFieldMap)^[FFieldCount] := -1;
Inc(FFieldCount);
end;
procedure TdxInspectorDataLink.ClearMapping;
begin
if FFieldMap <> nil then
begin
FreeMem(FFieldMap, FFieldMapSize * SizeOf(Integer));
FFieldMap := nil;
FFieldMapSize := 0;
FFieldCount := 0;
end;
end;
procedure TdxInspectorDataLink.Modified;
begin
FModified := True;
end;
procedure TdxInspectorDataLink.Reset;
begin
if FModified then RecordChanged(nil) else Dataset.Cancel;
end;
// protected TdxInspectorDataLink
procedure TdxInspectorDataLink.ActiveChanged;
begin
FInspector.LinkActive(Active);
end;
procedure TdxInspectorDataLink.DataSetChanged;
begin
FDataSetChanged := True;
try
RecordChanged(nil);
finally
FDataSetChanged := False;
end;
end;
procedure TdxInspectorDataLink.FocusControl(Field: TFieldRef);
begin
if Assigned(Field) and Assigned(Field^) then
begin
FInspector.FocusedField := Field^;
if (FInspector.FocusedField = Field^)
and FInspector.AcquireFocus then
begin
Field^ := nil;
FInspector.ShowEditor;
if FInspector.FInplaceNode <> nil then
begin
FInspector.FInplaceNode.MakeVisible;
UpdateWindow(FInspector.Handle);
end;
end;
end;
end;
procedure TdxInspectorDataLink.LayoutChanged;
begin
FInspector.LayoutChanged;
inherited LayoutChanged;
end;
procedure TdxInspectorDataLink.RecordChanged(Field: TField);
begin
FInspector.RecordChanged(Field, FDataSetChanged);
FModified := False;
end;
procedure TdxInspectorDataLink.UpdateData;
begin
if FModified then FInspector.UpdateData;
FModified := False;
end;
function TdxInspectorDataLink.GetMappedIndex(RowIndex: Integer): Integer;
begin
if (0 <= RowIndex) and (RowIndex < FFieldCount) then
Result := PIntArray(FFieldMap)^[RowIndex]
else Result := -1;
end;
function TdxInspectorDataLink.GetFields(I: Integer): TField;
begin
if (0 <= I) and (I < FFieldCount) and (PIntArray(FFieldMap)^[I] >= 0) then
Result := DataSet.Fields[PIntArray(FFieldMap)^[I]]
else Result := nil;
end;
{ TdxDBInspector }
constructor TdxDBInspector.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FDataLink := TdxInspectorDataLink.Create(Self);
FOptions := [dioEditing, dioBandSizing, dioColumnSizing, dioAutoWidth, dioCancelOnExit, dioDynamicColumnSizing];
inherited Options := [ioEditing, ioBandSizing, ioColumnSizing, ioAutoWidth, ioDynamicColumnSizing];
FDefaultFields := True;
end;
destructor TdxDBInspector.Destroy;
begin
FDataLink.Free;
FDataLink := nil;
inherited Destroy;
end;
procedure TdxDBInspector.ClearRows;
begin
BeginUpdate;
try
DefaultFields := False;
DestroyRows;
finally
EndUpdate;
end;
end;
function TdxDBInspector.GetDefaultRowClass: TdxInspectorRowClass;
begin
Result := TdxInspectorDBRow;
end;
{$IFDEF DELPHI4}
function TdxDBInspector.ExecuteAction(Action: TBasicAction): Boolean;
begin
Result := inherited ExecuteAction(Action) or (DataLink <> nil) and
DataLink.ExecuteAction(Action);
end;
function TdxDBInspector.UpdateAction(Action: TBasicAction): Boolean;
begin
Result := inherited UpdateAction(Action) or (DataLink <> nil) and
DataLink.UpdateAction(Action);
end;
{$ENDIF}
procedure TdxDBInspector.KeyDown(var Key: Word; Shift: TShiftState);
var
KeyDownEvent: TKeyEvent;
begin
KeyDownEvent := OnKeyDown;
OnKeyDown := nil;
try
if Assigned(KeyDownEvent) then KeyDownEvent(Self, Key, Shift);
if FDatalink.Active then
with FDatalink.DataSet do
begin
if (Key = VK_ESCAPE) and
not ((dioNoCancel in Options) and not FDatalink.FModified) then
FDatalink.Reset;
end;
inherited KeyDown(Key, Shift);
finally
OnKeyDown := KeyDownEvent;
end;
end;
procedure TdxDBInspector.Notification(AComponent: TComponent; Operation: TOperation);
var
I: Integer;
NeedLayout: Boolean;
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) then
begin
if (FDataLink <> nil) then
if (AComponent = DataSource) then
DataSource := nil
else
if (AComponent is TField) then
begin
NeedLayout := False;
for I := 0 to TotalRowCount-1 do
with Rows[I] do
if TField(LinkObject) = AComponent then
begin
LinkObject := nil;
NeedLayout := True;
// Break;
end;
if NeedLayout and ( not Assigned(FDatalink.Dataset) or
(Assigned(FDatalink.Dataset) and
(not FDatalink.Dataset.ControlsDisabled))) then
begin
BeginUpdate;
try
for I := 0 to TotalRowCount-1 do
with Rows[I] do
if TField(LinkObject) = AComponent then
LinkObject := nil;
finally
EndUpdate;
end;
end;
end;
end;
end;
function TdxDBInspector.AcquireFocus: Boolean;
begin
Result := True;
if CanFocus and not (csDesigning in ComponentState) then
begin
SetFocus;
Result := Focused or (InplaceEditor <> nil) and InplaceEditor.Focused;
end;
end;
function TdxDBInspector.SaveNodes: Boolean;
begin
Result := not DefaultFields;
end;
function TdxDBInspector.CreateNode: TdxInspectorNode;
begin
if DefaultFields and not FAddFlag then
raise Exception.Create('DefaultFields property should be set to False');
Result := inherited CreateNode;
end;
function TdxDBInspector.CanEditAcceptKey(Key: Char): Boolean;
begin
Result := GetInplaceEditRow(FocusedNode).IsValidChar(Key);
end;
function TdxDBInspector.CanEditModify: Boolean;
begin
Result := False;
if FDatalink.Active and not FDatalink.Readonly and (FocusedNode <> nil) then
with GetInplaceEditRow(FocusedNode) do
if not ReadOnly and IsCanModify then
begin
FInCanEditModify := True;
try
FDatalink.Edit;
finally
FInCanEditModify := False;
end;
Result := FDatalink.Editing;
if Result then FDatalink.Modified;
end;
end;
function TdxDBInspector.CanEditShow: Boolean;
begin
Result := inherited CanEditShow and (FocusedNode <> nil) and FDataLink.Active;
end;
function TdxDBInspector.AssignEditValue(ANode: TdxInspectorNode; AInplaceEdit: TdxInplaceEdit): Variant;
var
AField: TField;
begin
AField := FocusedField;
if FDataLink.FModified then
begin
if Assigned(AField) and Assigned(FDataLink.DataSet) and
(FDataLink.DataSet.State in dsEditModes) then
begin
EditValue := inherited AssignEditValue(ANode, AInplaceEdit);
end;
end;
end;
function TdxDBInspector.IsDefaultEqualValues(const AValue: Variant; ARow: TdxInspectorRow): Boolean;
var
AField: TField;
AFieldValue: Variant;
begin
if TdxInspectorDBRow(ARow).GetLinkObject is TField then
begin
AField := TField(TdxInspectorDBRow(ARow).GetLinkObject);
if Assigned(AField) and not VarIsEmpty(AValue) then
begin
if (VarType(AValue) = varString) then
Result := AField.Text = AValue
else
begin
AFieldValue := AField.Value;
if VarType(AFieldValue) <> VarType(AValue) then
Result := False
else
Result := AFieldValue = AValue;
end;
end
else
Result := False;
end
else
Result := inherited IsDefaultEqualValues(AValue, ARow);
end;
// DataSet
procedure TdxDBInspector.DefineFieldMap;
var
I: Integer;
begin
if not DefaultFields then
for I := 0 to TotalRowCount-1 do
FDataLink.AddMapping(Rows[I].LinkObjectName)
else
with FDatalink.Dataset do
for I := 0 to FieldCount - 1 do
with Fields[I] do if Visible then Datalink.AddMapping(FieldName);
end;
procedure TdxDBInspector.DoInternalLayout;
var
I, J, K: Integer;
Fld: TField;
Row: TdxInspectorRow;
function FieldIsMapped(F: TField): Boolean;
var
I: Integer;
begin
Result := False;
if F = nil then Exit;
for I := 0 to FDatalink.FieldCount-1 do
if FDatalink.Fields[I] = F then
begin
Result := True;
Exit;
end;
end;
begin
FDatalink.ClearMapping;
if FDatalink.Active then DefineFieldMap;
if DefaultFields then
begin
// Destroy rows whose fields have been destroyed or are no longer in field map
if (not FDataLink.Active) then
DestroyRows
else
for J := TotalRowCount - 1 downto 0 do
with Rows[J] do
if (LinkObject = nil) or
not FieldIsMapped(TField(LinkObject)) then Free;
// validate order rows
I := FDataLink.FieldCount;
for J := 0 to I-1 do
begin
Fld := FDatalink.Fields[J];
if Assigned(Fld) then
begin
K := J;
while (K < Count) and
(TField(TdxInspectorRowNode(Items[K]).Row.LinkObject) <> Fld) do Inc(K);
if K < Count then
Row := TdxInspectorRowNode(Items[K]).Row
else
begin
Row := CreateDefaultRow(GetDefaultDBInspectorRowClass(Fld));
Row.LinkObject := Fld;
end;
end
else
Row := CreateDefaultRow(GetDefaultRowClass);
// set index
if (J < Count) and (Row.Node <> nil) then
Row.Node.MoveTo(TdxInspectorRowNode(Items[J]), inaInsert); // insert before
end;
end
else
begin
// Force rows to reaquire fields (in case dataset has changed)
for I := 0 to TotalRowCount - 1 do
Rows[I].LinkObjectName := Rows[I].LinkObjectName;
end;
if FDataLink.Active then FDataLink.BufferCount := 1;
UpdateActive;
inherited DoInternalLayout;
end;
procedure TdxDBInspector.LinkActive(Value: Boolean);
begin
if not Value then HideEditor;
LayoutChanged;
end;
procedure TdxDBInspector.RecordChanged(Field: TField; DataSetChanged: Boolean);
begin
if not HandleAllocated then Exit;
Invalidate; {TODO}
if FocusedNode <> nil then
with TdxInspectorDBRow(GetInplaceEditRow(FocusedNode)) do
if DataSetChanged or ((Field = nil) or (TField(LinkObject) = Field)) and
((InplaceEditor <> nil) and not InplaceEditor.DisableRefresh and
(not IsEqualValues(EditValue){EditText <> FEditValue})) then // TODO Check
begin
if FInCanEditModify and IsEqualValues(EditValue){(EditText = EditValue)]} then Exit;
InvalidateEditor;
if InplaceEditor <> nil then InplaceEditor.Deselect;
end;
end;
procedure TdxDBInspector.UpdateActive;
begin
if FDatalink.Active and HandleAllocated and not (csLoading in ComponentState) and
(State <> isNodeDragging) then
if FDatalink.DataSet.Active then
begin
if (FocusedNode <> nil) and (GetInplaceEditRow(FocusedNode) <> nil) then
with TdxInspectorDBRow(GetInplaceEditRow(FocusedNode)) do
if not IsEqualValues(EditValue) {EditText <> FEditValue} then
InvalidateEditor;
end;
end;
procedure TdxDBInspector.UpdateData;
begin
// PostEditor;
if (FInplaceEdit <> nil) and FInplaceEdit.IsVisible and
(FInplaceNode <> nil) then InplaceEditor.ValidateEdit;
HideEdit(False);
end;
function TdxDBInspector.GetDataLinkModified: Boolean;
begin
Result := FDataLink.FModified;
end;
function TdxDBInspector.GetDataSource: TDataSource;
begin
Result := FDataLink.DataSource;
end;
function TdxDBInspector.GetFocusedField: TField;
begin
if (FocusedNode <> nil) and (GetInplaceEditRow(FocusedNode) <> nil) then
Result := TField(GetInplaceEditRow(FocusedNode).LinkObject)
else
Result := nil;
end;
function TdxDBInspector.GetOptions: TdxDBInspectorOptions;
begin
Result := FOptions;
end;
procedure TdxDBInspector.SetDataSource(Value: TDataSource);
begin
if Value = FDatalink.Datasource then Exit;
FDataLink.DataSource := Value;
if Value <> nil then Value.FreeNotification(Self);
LinkActive(FDataLink.Active);
end;
procedure TdxDBInspector.SetFocusedField(Value: TField);
procedure CheckRow(ARow: TdxInspectorRow);
begin
if (TField(ARow.LinkObject) = Value) and (ARow.Node <> nil) then
ARow.Node.Focused := True;
end;
procedure CheckComplexRow(AComplexRow: TdxInspectorComplexRow);
var
I: Integer;
ARow: TdxInspectorRow;
begin
for I := 0 to AComplexRow.Items.Count - 1 do
begin
ARow := AComplexRow.Items[I].Row;
if TField(ARow.LinkObject) = Value then
begin
AComplexRow.Node.Focused := True;
InplaceComplexRowIndex := I;
end;
end;
end;
var
I: Integer;
ARow: TdxInspectorRow;
begin
if (Value = nil) then Exit;
if (FocusedNode <> nil) and (GetInplaceEditRow(FocusedNode) <> nil) and
(TField(GetInplaceEditRow(FocusedNode).LinkObject) = Value) then
Exit;
for I := 0 to TotalRowCount - 1 do
begin
ARow := Rows[I];
if ARow.Visible then
begin
if ARow is TdxInspectorComplexRow then
CheckComplexRow(ARow as TdxInspectorComplexRow)
else
CheckRow(ARow);
end;
end;
end;
procedure TdxDBInspector.SetOptions(Value: TdxDBInspectorOptions);
var
NewOptions: TdxInspectorOptions;
begin
if FOptions <> Value then
begin
BeginUpdate;
try
NewOptions := [];
if dioAutoBandCount in Value then
Include(NewOptions, ioAutoBandCount);
if dioAutoWidth in Value then
Include(NewOptions, ioAutoWidth);
if dioBandSizing in Value then
Include(NewOptions, ioBandSizing);
if dioColumnSizing in Value then
Include(NewOptions, ioColumnSizing);
if dioDrawEndEllipsis in Value then
Include(NewOptions, ioDrawEndEllipsis);
if dioDynamicColumnSizing in Value then
Include(NewOptions, ioDynamicColumnSizing);
if dioEditing in Value then
Include(NewOptions, ioEditing);
if dioEnterThrough in Value then
Include(NewOptions, ioEnterThrough);
if dioRowAutoHeight in Value then
Include(NewOptions, ioRowAutoHeight);
if dioRowSizing in Value then
Include(NewOptions, ioRowSizing);
if dioStoreToRegistry in Value then
Include(NewOptions, ioStoreToRegistry);
if dioTabs in Value then
Include(NewOptions, ioTabs);
if dioTabThrough in Value then
Include(NewOptions, ioTabThrough);
inherited Options := NewOptions;
FOptions := Value;
finally
EndUpdate;
end;
end;
end;
procedure TdxDBInspector.CMExit(var Message: TMessage);
begin
try
if FDatalink.Active then
with FDatalink.Dataset do
if (dioCancelOnExit in Options) and (State = dsInsert) and
not Modified and not FDatalink.FModified then
Cancel
else FDataLink.UpdateData;
except
SetFocus;
raise;
end;
inherited;
end;
///
function TdxDBInspector.GetDefaultFields: Boolean;
begin
Result := FDefaultFields;
end;
procedure TdxDBInspector.SetDefaultFields(Value: Boolean);
begin
if FDefaultFields <> Value then
begin
FDefaultFields := Value;
begin
BeginUpdate;
try
DestroyRows;
finally
EndUpdate;
end;
end;
end;
end;
// default data-aware row class info
function GetDefaultDBInspectorRowClass(AField: TField): TdxInspectorRowClass;
begin
with AField do
if FieldKind = fkData then
if DataType in [ftUnknown..ftTypedBinary] then
Result := DefaultDBRowType[DataType].RowClass
else Result := TdxInspectorDBRow
else
if FieldKind = fkLookup then
Result := DefaultLookupRowType.RowClass
else Result := TdxInspectorDBRow;
end;
// init procedure
procedure InitDefaultRowClasses(Proc: TInitDBInspectorRowClassProc);
var
I: TFieldType;
Row: TdxDBInspectorRowClassInfo;
begin
for I := ftUnknown to ftTypedBinary do
begin
Row := DefaultDBRowType[I];
Proc(I, fkData, Row);
if Row.Version > DefaultDBRowType[I].Version then
DefaultDBRowType[I] := Row;
end;
Row := DefaultLookupRowType;
Proc(ftUnknown, fkLookup, Row);
if Row.Version > DefaultLookupRowType.Version then
DefaultLookupRowType := Row;
end;
procedure ResetDefaultRowClasses;
var
I: TFieldType;
begin
DefaultDBRowType[ftUnknown].RowClass := nil;
DefaultDBRowType[ftUnknown].Version := 0;
for I := Succ(ftUnknown) to ftTypedBinary do
begin
DefaultDBRowType[I].RowClass := TdxInspectorDBRow;
DefaultDBRowType[I].Version := 0;
end;
DefaultLookupRowType.RowClass := nil;
DefaultLookupRowType.Version := 0;
end;
initialization
Classes.RegisterClasses([TdxInspectorDBRow]);
end.