git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.DevExpressVCL@63 05c56307-c608-d34a-929d-697000501d7a
4363 lines
121 KiB
ObjectPascal
4363 lines
121 KiB
ObjectPascal
{********************************************************************}
|
|
{ }
|
|
{ Developer Express Visual Component Library }
|
|
{ ExpressVerticalGrid }
|
|
{ }
|
|
{ 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 }
|
|
{ }
|
|
{ THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES }
|
|
{ (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE }
|
|
{ SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS }
|
|
{ LICENSED TO DISTRIBUTE THE EXPRESSVERTICALGRID AND ALL }
|
|
{ ACCOMPANYING VCL CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY. }
|
|
{ }
|
|
{ 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 cxOI;
|
|
|
|
{$I cxVer.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, TypInfo,
|
|
{$IFDEF DELPHI6}
|
|
RTLConsts,
|
|
{$ENDIF}
|
|
dxCore, cxGraphics, cxClasses, cxControls, cxEdit, cxInplaceContainer, cxVGrid;
|
|
|
|
const
|
|
CN_PropertyChanged = WM_DX + 25;
|
|
|
|
type
|
|
TcxPropertyEditor = class;
|
|
TcxRTTIInspectorController = class;
|
|
TcxCustomRTTIInspector = class;
|
|
|
|
{ TcxComponentList }
|
|
|
|
TcxComponentList = class(TObject)
|
|
private
|
|
FList: TList;
|
|
function GetItem(Index: Integer): TPersistent;
|
|
function GetCount: Integer;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
function Add(Item: TPersistent): Integer;
|
|
function Equals(List: TcxComponentList): Boolean;{$IFDEF DELPHI12}reintroduce;{$ENDIF}
|
|
|
|
property Count: Integer read GetCount;
|
|
property Items[Index: Integer]: TPersistent read GetItem; default;
|
|
end;
|
|
|
|
TcxPropertyAttribute =
|
|
(ipaValueList, ipaSubProperties, ipaDialog, ipaMultiSelect, ipaAutoUpdate,
|
|
ipaSortList, ipaReadOnly, ipaRevertable);
|
|
TcxPropertyAttributes = set of TcxPropertyAttribute;
|
|
|
|
TcxInstProp = record
|
|
Instance: TPersistent;
|
|
PropInfo: PPropInfo;
|
|
end;
|
|
|
|
PcxInstPropList = ^TcxInstPropList;
|
|
TcxInstPropList = array[0..1023] of TcxInstProp;
|
|
|
|
TcxGetPropEditProc = procedure(APropertyEditor: TcxPropertyEditor) of object;
|
|
|
|
{ TcxPropertyEditor }
|
|
|
|
TcxPropertyEditor = class
|
|
private
|
|
FInspector: TcxCustomRTTIInspector;
|
|
FAncestorList: TList;
|
|
FPropCount: Integer;
|
|
FPropList: PcxInstPropList;
|
|
FOwner: TComponent;
|
|
FRoot: TComponent;
|
|
FAncestor: TPersistent;
|
|
FRootAncestor: TComponent;
|
|
FLookingFor: TComponent;
|
|
FDoneLooking: Boolean;
|
|
procedure AddAncestor(Component: TComponent);
|
|
procedure GetLookupInfo(var Ancestor: TPersistent;
|
|
var Root, LookupRoot, RootAncestor: TComponent);
|
|
procedure SetPropEntry(Index: Integer; AInstance: TPersistent;
|
|
APropInfo: PPropInfo);
|
|
procedure WriteComponentSimulation(Component: TComponent);
|
|
protected
|
|
procedure AdjustInnerEditProperties(AProperties: TcxCustomEditProperties); virtual;
|
|
function GetFloatValue: Extended;
|
|
function GetFloatValueAt(Index: Integer): Extended;
|
|
function GetInt64Value: Int64;
|
|
function GetInt64ValueAt(Index: Integer): Int64;
|
|
function GetOrdValue: Longint;
|
|
function GetOrdValueAt(Index: Integer): Longint;
|
|
function GetPropInfo: PPropInfo;
|
|
function GetStrValue: string;
|
|
function GetStrValueAt(Index: Integer): string;
|
|
function GetVarValue: Variant;
|
|
function GetVarValueAt(Index: Integer): Variant;
|
|
function FindRoot: TComponent;
|
|
procedure PostChangedNotification;
|
|
procedure SetFloatValue(Value: Extended);
|
|
procedure SetInt64Value(Value: Int64);
|
|
procedure SetOrdValue(Value: Longint);
|
|
procedure SetStrValue(const Value: string);
|
|
procedure SetVarValue(const Value: Variant);
|
|
|
|
property Inspector: TcxCustomRTTIInspector read FInspector;
|
|
public
|
|
constructor Create(AOwner: TComponent; AInspector: TcxCustomRTTIInspector;
|
|
APropCount: Integer);
|
|
destructor Destroy; override;
|
|
|
|
function AllEqual: Boolean; virtual;
|
|
procedure Edit; virtual;
|
|
function GetAttributes: TcxPropertyAttributes; virtual;
|
|
function GetComponent(Index: Integer): TPersistent;
|
|
function GetEditLimit: Integer; virtual;
|
|
function GetName: string; virtual;
|
|
procedure GetProperties(AOwner: TComponent; Proc: TcxGetPropEditProc); virtual;
|
|
function GetPropType: PTypeInfo;
|
|
function GetValue: string; virtual;
|
|
procedure GetValues(Proc: TGetStrProc); virtual;
|
|
procedure SetValue(const Value: string); virtual;
|
|
function IsDefaultValue: Boolean; virtual;
|
|
function ValueAvailable: Boolean;
|
|
|
|
property PropCount: Integer read FPropCount;
|
|
property Value: string read GetValue write SetValue;
|
|
end;
|
|
|
|
TcxPropertyEditorClass = class of TcxPropertyEditor;
|
|
|
|
{ TcxOrdinalProperty }
|
|
|
|
TcxOrdinalProperty = class(TcxPropertyEditor)
|
|
function AllEqual: Boolean; override;
|
|
function GetEditLimit: Integer; override;
|
|
end;
|
|
|
|
{ TcxIntegerProperty }
|
|
|
|
TcxIntegerProperty = class(TcxOrdinalProperty)
|
|
public
|
|
function GetValue: string; override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxCharProperty }
|
|
|
|
TcxCharProperty = class(TcxOrdinalProperty)
|
|
public
|
|
function GetValue: string; override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxEnumProperty }
|
|
|
|
TcxEnumProperty = class(TcxOrdinalProperty)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetValue: string; override;
|
|
procedure GetValues(Proc: TGetStrProc); override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxBoolProperty }
|
|
|
|
TcxBoolProperty = class(TcxEnumProperty)
|
|
public
|
|
function GetValue: string; override;
|
|
procedure GetValues(Proc: TGetStrProc); override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxFloatProperty }
|
|
|
|
TcxFloatProperty = class(TcxPropertyEditor)
|
|
public
|
|
function AllEqual: Boolean; override;
|
|
function GetValue: string; override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TInt64Property }
|
|
|
|
TcxInt64Property = class(TcxPropertyEditor)
|
|
public
|
|
function AllEqual: Boolean; override;
|
|
function GetEditLimit: Integer; override;
|
|
function GetValue: string; override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxStringProperty}
|
|
|
|
TcxStringProperty = class(TcxPropertyEditor)
|
|
public
|
|
function AllEqual: Boolean; override;
|
|
function GetEditLimit: Integer; override;
|
|
function GetValue: string; override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxSetElementProperty }
|
|
|
|
TcxSetElementProperty = class(TcxPropertyEditor)
|
|
private
|
|
FElement: Integer;
|
|
constructor Create(APropList: PcxInstPropList; APropCount: Integer; AElement: Integer);
|
|
public
|
|
destructor Destroy; override;
|
|
function AllEqual: Boolean; override;
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetName: string; override;
|
|
function GetValue: string; override;
|
|
procedure GetValues(Proc: TGetStrProc); override;
|
|
procedure SetValue(const Value: string); override;
|
|
function IsDefaultValue: Boolean; override;
|
|
end;
|
|
|
|
{ TcxSetProperty }
|
|
|
|
TcxSetProperty = class(TcxOrdinalProperty)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
procedure GetProperties(AOwner: TComponent; Proc: TcxGetPropEditProc); override;
|
|
function GetValue: string; override;
|
|
end;
|
|
|
|
{ TcxClassProperty }
|
|
|
|
TcxClassProperty = class(TcxPropertyEditor)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
procedure GetProperties(AOwner: TComponent; Proc: TcxGetPropEditProc); override;
|
|
function GetValue: string; override;
|
|
end;
|
|
|
|
{ TcxComponentProperty }
|
|
|
|
TcxComponentProperty = class(TcxPropertyEditor)
|
|
private
|
|
function GetFullName(AComponent: TComponent): string;
|
|
protected
|
|
function IsValidComponent(AComponent: TComponent): Boolean; virtual;
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetEditLimit: Integer; override;
|
|
function GetValue: string; override;
|
|
procedure GetValues(Proc: TGetStrProc); override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxComponentNameProperty }
|
|
|
|
TcxComponentNameProperty = class(TcxStringProperty)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetEditLimit: Integer; override;
|
|
end;
|
|
|
|
{ TcxFontNameProperty }
|
|
|
|
TcxFontNameProperty = class(TcxStringProperty)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
procedure GetValues(Proc: TGetStrProc); override;
|
|
end;
|
|
|
|
{ TcxFontCharsetProperty }
|
|
|
|
TcxFontCharsetProperty = class(TcxIntegerProperty)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetValue: string; override;
|
|
procedure GetValues(Proc: TGetStrProc); override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxImeNameProperty }
|
|
|
|
TcxImeNameProperty = class(TcxStringProperty)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
procedure GetValues(Proc: TGetStrProc); override;
|
|
end;
|
|
|
|
{ TColorProperty }
|
|
|
|
TcxColorProperty = class(TcxIntegerProperty)
|
|
public
|
|
procedure Edit; override;
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetValue: string; override;
|
|
procedure GetValues(Proc: TGetStrProc); override;
|
|
end;
|
|
|
|
{ TcxCursorProperty }
|
|
|
|
TcxCursorProperty = class(TcxIntegerProperty)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetValue: string; override;
|
|
procedure GetValues(Proc: TGetStrProc); override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxFontProperty }
|
|
|
|
TcxFontProperty = class(TcxClassProperty)
|
|
public
|
|
procedure Edit; override;
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
end;
|
|
|
|
{ TcxStringsProperty }
|
|
|
|
TcxStringsProperty = class(TcxClassProperty)
|
|
public
|
|
procedure Edit; override;
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
end;
|
|
|
|
{ TcxGraphicProperty }
|
|
|
|
TcxGraphicProperty = class(TcxClassProperty)
|
|
private
|
|
function HasGraphic: Boolean;
|
|
protected
|
|
function GetGraphic: TGraphic; virtual;
|
|
procedure SetGraphic(Value: TGraphic); virtual;
|
|
|
|
function GetClipboardFormat: Word; virtual;
|
|
function GetGraphicFilter: string; virtual;
|
|
function GraphicClass: TGraphicClass;
|
|
public
|
|
procedure Edit; override;
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetValue: string; override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxPictureProperty }
|
|
|
|
TcxPictureProperty = class(TcxGraphicProperty)
|
|
protected
|
|
function GetGraphic: TGraphic; override;
|
|
procedure SetGraphic(Value: TGraphic); override;
|
|
end;
|
|
|
|
{ TcxModalResultProperty }
|
|
|
|
TcxModalResultProperty = class(TcxIntegerProperty)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetValue: string; override;
|
|
procedure GetValues(Proc: TGetStrProc); override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxShortCutProperty }
|
|
|
|
TcxShortCutProperty = class(TcxOrdinalProperty)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetValue: string; override;
|
|
procedure GetValues(Proc: TGetStrProc); override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxMPFilenameProperty }
|
|
|
|
TcxMPFilenameProperty = class(TcxStringProperty)
|
|
public
|
|
procedure Edit; override;
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
end;
|
|
|
|
{ TcxTabOrderProperty }
|
|
|
|
TcxTabOrderProperty = class(TcxIntegerProperty)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
end;
|
|
|
|
{ TCaptionProperty }
|
|
|
|
TcxCaptionProperty = class(TcxStringProperty)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
end;
|
|
|
|
{ TcxDateProperty }
|
|
|
|
TcxDateProperty = class(TcxPropertyEditor)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetValue: string; override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxTimeProperty }
|
|
|
|
TcxTimeProperty = class(TcxPropertyEditor)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetValue: string; override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxDateTimeProperty }
|
|
|
|
TcxDateTimeProperty = class(TcxPropertyEditor)
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetValue: string; override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
{ TcxVariantProperty }
|
|
|
|
TcxVariantProperty = class(TcxPropertyEditor)
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
procedure GetProperties(AOwner: TComponent; Proc: TcxGetPropEditProc); override;
|
|
function GetValue: string; override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
// the support DevExpress editor's properties
|
|
|
|
{ TcxEditPropertiesProperty }
|
|
|
|
TcxEditPropertiesProperty = class(TcxClassProperty)
|
|
protected
|
|
function HasSubProperties: Boolean;
|
|
public
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetValue: string; override;
|
|
procedure GetValues(Proc: TGetStrProc); override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
EcxPropertyError = class(EdxException);
|
|
|
|
{ TcxPropertyRow }
|
|
|
|
TcxPropertyRow = class(TcxEditorRow)
|
|
private
|
|
FIsDefaultValue: Boolean;
|
|
FPropertyEditor: TcxPropertyEditor;
|
|
public
|
|
property IsDefaultValue: Boolean read FIsDefaultValue;
|
|
property PropertyEditor: TcxPropertyEditor read FPropertyEditor;
|
|
end;
|
|
|
|
{ TcxRTTIInspectorEditingController }
|
|
|
|
TcxRTTIInspectorEditingController = class(TcxEditingController)
|
|
private
|
|
FDeactivating: Boolean;
|
|
function GetController: TcxRTTIInspectorController;
|
|
function GetInspector: TcxCustomRTTIInspector;
|
|
protected
|
|
property Controller: TcxRTTIInspectorController read GetController;
|
|
property Deactivating: Boolean read FDeactivating;
|
|
property Inspector: TcxCustomRTTIInspector read GetInspector;
|
|
public
|
|
procedure HideEdit(Accept: Boolean); override;
|
|
end;
|
|
|
|
{ TcxRTTIInspectorController }
|
|
|
|
TcxRTTIInspectorController = class(TcxvgController)
|
|
private
|
|
FFocusChanging: Boolean;
|
|
FNeedCorrect: Boolean;
|
|
function GetEditingController: TcxRTTIInspectorEditingController;
|
|
function GetFocusedRowIndex: Integer;
|
|
function GetInspector: TcxCustomRTTIInspector;
|
|
function GetRowIndexFromCellEdit(Value: TcxCustomInplaceEditContainer): Integer;
|
|
procedure SetFocusedRowIndex(AIndex: Integer);
|
|
protected
|
|
procedure BeforeEditKeyDown(var Key: Word; var Shift: TShiftState); override;
|
|
procedure DoEditDblClick(Sender: TObject); override;
|
|
procedure DoUpdateRowAndCell(ANewRow: TcxCustomRow; ANewCellIndex: Integer); override;
|
|
procedure FocusChanged; override;
|
|
function IsKeyForController(AKey: Word; AShift: TShiftState): Boolean; override;
|
|
procedure SetFocusedItem(Value: TcxCustomInplaceEditContainer); override;
|
|
procedure SetFocusedRowAndCell(Value: TcxCustomRow; ACellIndex: Integer); override;
|
|
public
|
|
procedure SetFocusedRecordItem(ARecordIndex: Integer;
|
|
AItem: TcxCustomInplaceEditContainer); override;
|
|
property EditingController: TcxRTTIInspectorEditingController read GetEditingController;
|
|
property Inspector: TcxCustomRTTIInspector read GetInspector;
|
|
end;
|
|
|
|
{ TcxRTTIInspectorOptionsView }
|
|
|
|
TcxRTTIInspectorOptionsView = class(TcxvgOptionsView)
|
|
public
|
|
constructor Create(AOwner: TPersistent); override;
|
|
published
|
|
property PaintStyle default psDelphi;
|
|
property ShowEditButtons default ecsbFocused;
|
|
end;
|
|
|
|
{ TcxRTTIInspectorOptionsBehavior }
|
|
|
|
TcxRTTIInspectorOptionsBehavior = class(TcxvgOptionsBehavior)
|
|
public
|
|
constructor Create(AOwner: TPersistent); override;
|
|
published
|
|
property AlwaysShowEditor default True;
|
|
end;
|
|
|
|
{ TcxCustomRTTIInspector }
|
|
IcxRTTIInspectorHelper = interface
|
|
['{EA7182FA-139D-4525-9C5F-4D8BBAB5FEEE}']
|
|
procedure CloseNonModal(AInspector: TcxCustomRTTIInspector);
|
|
procedure PropertyChanged(AInspector: TcxCustomRTTIInspector);
|
|
end;
|
|
|
|
TcxFilterPropertyEvent = procedure(Sender: TObject; const PropertyName: string;
|
|
var Accept: Boolean) of object;
|
|
|
|
TcxCustomRTTIInspector = class(TcxUnboundVerticalGrid)
|
|
private
|
|
FBoldFont: TFont;
|
|
FCurrentRow: TcxPropertyRow;
|
|
FListeners: TList;
|
|
FLockRefresh: Boolean;
|
|
FInspectedObject: TPersistent;
|
|
FParentRow: TcxCustomRow;
|
|
FReloaded: Boolean;
|
|
FSaveTopRowIndex: Integer;
|
|
FSettingValue: Boolean;
|
|
FOnFilterProperty: TcxFilterPropertyEvent;
|
|
FOnFilterPropertyEx: TcxFilterPropertyEvent;
|
|
FOnPropertyChanged: TNotifyEvent;
|
|
function CanInvokePropertyEditorDlg: Boolean;
|
|
procedure CNPropertyChanged(var AMessage: TMsg); message CN_PropertyChanged;
|
|
procedure CreatePropertyRows(AOldInspectedObject: TPersistent);
|
|
procedure CreateRows(APropertyEditor: TcxPropertyEditor);
|
|
procedure GetComponentsProperties(const AInstances: array of TPersistent);
|
|
function GetController: TcxRTTIInspectorController;
|
|
function GetPropertyEditor: TcxPropertyEditor;
|
|
procedure GetStrProc(const S: string);
|
|
procedure ReleaseComponentProperties;
|
|
procedure RowButtonClick(Sender: TObject; AbsoluteIndex: Integer);
|
|
procedure SetInspectedObject(Value: TPersistent);
|
|
procedure TryInvokePropertyEditorDlg;
|
|
function TrySetValue(AEdit: TcxCustomEdit; AUseText: Boolean): Boolean;
|
|
protected
|
|
//override VCL
|
|
function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
|
|
MousePos: TPoint): Boolean; override;
|
|
procedure FontChanged; override;
|
|
procedure Loaded; override;
|
|
procedure Notification(AComponent: TComponent; AOperation: TOperation); override;
|
|
procedure DataChanged; override;
|
|
procedure DoPropertyChanged;
|
|
procedure EditChange(Sender: TObject);
|
|
procedure EditValueChanged(Sender: TObject);
|
|
function GetControllerClass: TcxCustomControlControllerClass; override;
|
|
procedure GetDefaultViewParams(Index: Integer; AData: TObject; out AParams: TcxViewParams); override;
|
|
function GetEditingControllerClass: TcxEditingControllerClass; override;
|
|
function GetOptionsBehaviorClass: TcxControlOptionsBehaviorClass; override;
|
|
function GetOptionsViewClass: TcxControlOptionsViewClass; override;
|
|
|
|
function FilterProperty(const APropertyName: string): Boolean; virtual;
|
|
function FilterPropertyEx(const AFullPropertyName: string): Boolean; virtual;
|
|
function FindRowByPropertyName(const APropertyName: string): TcxPropertyRow;
|
|
procedure FocusRowByPropertyName(const APropertyName: string);
|
|
function GetEditPropertiesClass(APropertyEditor: TcxPropertyEditor): TcxCustomEditPropertiesClass; virtual;
|
|
procedure PostChangedNotification;
|
|
procedure PrepareEditProperties(AProperties: TcxCustomEditProperties; APropertyEditor: TcxPropertyEditor); virtual;
|
|
|
|
property Controller: TcxRTTIInspectorController read GetController;
|
|
property PropertyEditor: TcxPropertyEditor read GetPropertyEditor;
|
|
property Reloaded: Boolean read FReloaded;
|
|
property LockRefresh: Boolean read FLockRefresh;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure AddListener(AListener: TPersistent);
|
|
procedure CloseNonModalEditors;
|
|
procedure RefreshInspectedProperties;
|
|
procedure RemoveListener(AListener: TPersistent);
|
|
property InspectedObject: TPersistent read FInspectedObject write SetInspectedObject;
|
|
property OnFilterProperty: TcxFilterPropertyEvent read FOnFilterProperty write FOnFilterProperty;
|
|
property OnFilterPropertyEx: TcxFilterPropertyEvent read FOnFilterPropertyEx write FOnFilterPropertyEx;
|
|
property OnPropertyChanged: TNotifyEvent read FOnPropertyChanged write FOnPropertyChanged;
|
|
end;
|
|
|
|
{ TcxRTTIInspector }
|
|
|
|
TcxRTTIInspector = class(TcxCustomRTTIInspector)
|
|
published
|
|
property Align;
|
|
property Anchors;
|
|
property Constraints;
|
|
property DragCursor;
|
|
property DragKind;
|
|
property DragMode;
|
|
property Enabled;
|
|
property Font;
|
|
property Images;
|
|
property InspectedObject;
|
|
property LayoutStyle;
|
|
property LookAndFeel;
|
|
property OptionsView; //before OptionsBehavior
|
|
property OptionsBehavior;
|
|
property OptionsData;
|
|
property ParentFont;
|
|
property PopupMenu;
|
|
property Styles;
|
|
property TabOrder;
|
|
property TabStop;
|
|
property Visible;
|
|
|
|
property OnClick;
|
|
{$IFDEF DELPHI5}
|
|
property OnContextPopup;
|
|
{$ENDIF}
|
|
property OnDblClick;
|
|
property OnDragDrop;
|
|
property OnDragOver;
|
|
property OnDrawBackground;
|
|
property OnDrawRowHeader;
|
|
property OnDrawValue;
|
|
property OnEdited;
|
|
property OnEditing;
|
|
property OnEditValueChanged;
|
|
property OnEndDock;
|
|
property OnEndDrag;
|
|
property OnEnter;
|
|
property OnExit;
|
|
property OnFilterProperty;
|
|
property OnFilterPropertyEx;
|
|
property OnItemChanged;
|
|
property OnKeyDown;
|
|
property OnKeyPress;
|
|
property OnKeyUp;
|
|
property OnLayoutChanged;
|
|
property OnLeftVisibleBandIndexChanged;
|
|
property OnMouseDown;
|
|
property OnMouseEnter;
|
|
property OnMouseLeave;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
property OnMouseWheel;
|
|
property OnMouseWheelDown;
|
|
property OnMouseWheelUp;
|
|
property OnPropertyChanged;
|
|
property OnResize;
|
|
property OnStartDock;
|
|
property OnStartDrag;
|
|
property OnTopRowIndexChanged;
|
|
end;
|
|
|
|
procedure cxRegisterPropertyEditor(APropertyType: PTypeInfo; AComponentClass: TClass;
|
|
const APropertyName: string; AEditorClass: TcxPropertyEditorClass);
|
|
|
|
type
|
|
TcxPropertyMapperFunc = function(Obj: TPersistent; PropInfo: PPropInfo): TcxPropertyEditorClass;
|
|
|
|
procedure cxRegisterPropertyMapper(AMapper: TcxPropertyMapperFunc);
|
|
procedure cxGetComponentProperties(AOwner: TComponent;
|
|
AInspector: TcxCustomRTTIInspector; AComponents: TcxComponentList;
|
|
AFilter: TTypeKinds; AProc: TcxGetPropEditProc);
|
|
|
|
function cxGetPropertiesClassByEditor(APropertyEditor: TcxPropertyEditor): TcxCustomEditPropertiesClass;
|
|
procedure cxRegisterEditPropertiesClass(AEditorClass: TcxPropertyEditorClass; AEditPropertiesClass: TcxCustomEditPropertiesClass);
|
|
function HasProperty(AClass: TClass; const APropertyName: string): Boolean;
|
|
function IsUniquePropertyRelativeTo(AClass, ARelativeClass: TClass; const APropertyName: string): Boolean;
|
|
function IsUniquePropertyRelativeParent(AClass: TClass; const APropertyName: string): Boolean;
|
|
|
|
function IsValidInspectedObject(AObject: TPersistent; AInspector: TcxCustomRTTIInspector): Boolean;
|
|
|
|
procedure cxDotNetInspectObject(AObject: TPersistent; AInspector: TcxRTTIInspector);
|
|
|
|
implementation
|
|
|
|
uses
|
|
Menus, Clipbrd, Dialogs, Consts, Registry, MPlayer,
|
|
cxOIStringsEd, cxOIPictureEd, cxOICollectionEd, cxColorComboBox,
|
|
{$IFDEF DELPHI6}
|
|
Variants,
|
|
{$ELSE}
|
|
cxVariants,
|
|
{$ENDIF}
|
|
cxTextEdit, cxDropDownEdit, cxCalendar, cxSpinEdit, cxTimeEdit, cxButtonEdit,
|
|
cxCustomData, cxGeometry, cxVGridConsts, cxDateUtils;
|
|
|
|
const
|
|
cxSString = 'String';
|
|
cxSNull = '(Null)';
|
|
cxSUnassigned = '(Unassigned)';
|
|
|
|
type
|
|
TcxCustomRowAccess = class(TcxCustomRow);
|
|
TcxCustomEditPropertiesAccess = class(TcxCustomEditProperties);
|
|
TcxEditCellViewInfoAccess = class(TcxEditCellViewInfo);
|
|
TcxColorComboBoxPropertiesAccess = class(TcxColorComboBoxProperties);
|
|
{$IFNDEF DELPHI6}
|
|
IInterface = IUnknown;
|
|
{$ENDIF}
|
|
|
|
TcxIntegerSet = set of 0..SizeOf(Integer) * 8 - 1;
|
|
|
|
TcxPropertyClassRec = class
|
|
Group: Integer;
|
|
PropertyType: PTypeInfo;
|
|
PropertyName: string;
|
|
ComponentClass: TClass;
|
|
EditorClass: TcxPropertyEditorClass;
|
|
end;
|
|
|
|
TcxPropertyMapperRec = class
|
|
Group: Integer;
|
|
Mapper: TcxPropertyMapperFunc;
|
|
end;
|
|
|
|
TcxEditPropertiesMapperRec = class
|
|
EditorClass: TcxPropertyEditorClass;
|
|
EditPropertiesClass: TcxCustomEditPropertiesClass;
|
|
end;
|
|
|
|
TcxInspectedObjectPropertyEditor = class(TcxComponentProperty)
|
|
protected
|
|
function IsValidComponent(AComponent: TComponent): Boolean; override;
|
|
end;
|
|
|
|
const
|
|
cxPropClassMap: array[TTypeKind] of TcxPropertyEditorClass = (
|
|
nil, TcxIntegerProperty, TcxCharProperty, TcxEnumProperty,
|
|
TcxFloatProperty, TcxStringProperty, TcxSetProperty, TcxClassProperty,
|
|
nil, TcxPropertyEditor, TcxStringProperty, TcxStringProperty,
|
|
TcxPropertyEditor, nil, nil, nil, TcxInt64Property, nil{$IFDEF DELPHI12}, TcxStringProperty{$ENDIF});
|
|
|
|
var
|
|
FPropertyClasses: TList = nil;
|
|
FPropertyMappers: TList = nil;
|
|
FEditPropertiesClasses: TList = nil;
|
|
|
|
{$IFNDEF DELPHI5}
|
|
function SameText(const S1, S2: string): Boolean; assembler;
|
|
asm
|
|
CMP EAX,EDX
|
|
JZ @1
|
|
OR EAX,EAX
|
|
JZ @2
|
|
OR EDX,EDX
|
|
JZ @3
|
|
MOV ECX,[EAX-4]
|
|
CMP ECX,[EDX-4]
|
|
JNE @3
|
|
CALL CompareText
|
|
TEST EAX,EAX
|
|
JNZ @3
|
|
@1: MOV AL,1
|
|
@2: RET
|
|
@3: XOR EAX,EAX
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function HasProperty(AClass: TClass; const APropertyName: string): Boolean;
|
|
var
|
|
TypeKinds: TTypeKinds;
|
|
PropCount: Integer;
|
|
PropList: PPropList;
|
|
I: Integer;
|
|
begin
|
|
TypeKinds := tkProperties;
|
|
PropCount := GetPropList(AClass.ClassInfo, TypeKinds, nil);
|
|
if PropCount > 0 then
|
|
begin
|
|
PropList := AllocMem(PropCount * SizeOf(PPropInfo));
|
|
try
|
|
PropCount := GetPropList(AClass.ClassInfo, TypeKinds, PropList);
|
|
I := 0;
|
|
while (I < PropCount) and (CompareText(dxShortStringToString(PropList^[I].Name), APropertyName) <> 0) do
|
|
Inc(I);
|
|
Result := I < PropCount;
|
|
finally
|
|
FreeMem(PropList, PropCount * SizeOf(PPropInfo));
|
|
end;
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function IsUniquePropertyRelativeTo(AClass, ARelativeClass: TClass; const APropertyName: string): Boolean;
|
|
begin
|
|
Result := HasProperty(AClass, APropertyName) and
|
|
((ARelativeClass = nil) or not HasProperty(ARelativeClass, APropertyName));
|
|
end;
|
|
|
|
function IsUniquePropertyRelativeParent(AClass: TClass; const APropertyName: string): Boolean;
|
|
begin
|
|
Result := IsUniquePropertyRelativeTo(AClass, AClass.ClassParent, APropertyName);
|
|
end;
|
|
|
|
function IsValidInspectedObject(AObject: TPersistent; AInspector: TcxCustomRTTIInspector): Boolean;
|
|
begin
|
|
Result := AObject <> AInspector;
|
|
if Result and (AObject is TcxCustomRTTIInspector) then
|
|
Result := IsValidInspectedObject(TcxCustomRTTIInspector(AObject).InspectedObject, AInspector);
|
|
end;
|
|
|
|
{ TComponentList }
|
|
|
|
constructor TcxComponentList.Create;
|
|
begin
|
|
inherited Create;
|
|
FList := TList.Create;
|
|
end;
|
|
|
|
destructor TcxComponentList.Destroy;
|
|
begin
|
|
FList.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TcxComponentList.GetItem(Index: Integer): TPersistent;
|
|
begin
|
|
Result := FList[Index];
|
|
end;
|
|
|
|
function TcxComponentList.GetCount: Integer;
|
|
begin
|
|
Result := FList.Count;
|
|
end;
|
|
|
|
function TcxComponentList.Add(Item: TPersistent): Integer;
|
|
begin
|
|
Result := FList.Add(Item);
|
|
end;
|
|
|
|
function TcxComponentList.Equals(List: TcxComponentList): Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := False;
|
|
if List.Count <> FList.Count then Exit;
|
|
for I := 0 to List.Count - 1 do
|
|
if List[I] <> FList[I] then Exit;
|
|
Result := True;
|
|
end;
|
|
|
|
function cxGetPropertiesClassByEditor(APropertyEditor: TcxPropertyEditor): TcxCustomEditPropertiesClass;
|
|
var
|
|
I: Integer;
|
|
Item: TcxEditPropertiesMapperRec;
|
|
begin
|
|
Result := nil;
|
|
if FEditPropertiesClasses <> nil then
|
|
for I := 0 to FEditPropertiesClasses.Count - 1 do
|
|
begin
|
|
Item := TcxEditPropertiesMapperRec(FEditPropertiesClasses[I]);
|
|
if Item.EditorClass.InheritsFrom(APropertyEditor.ClassType) then
|
|
Result := Item.EditPropertiesClass;
|
|
if Item.EditorClass = APropertyEditor.ClassType then
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
procedure cxRegisterEditPropertiesClass(
|
|
AEditorClass: TcxPropertyEditorClass;
|
|
AEditPropertiesClass: TcxCustomEditPropertiesClass);
|
|
var
|
|
Item: TcxEditPropertiesMapperRec;
|
|
begin
|
|
if FEditPropertiesClasses = nil then FEditPropertiesClasses := TList.Create;
|
|
Item := TcxEditPropertiesMapperRec.Create;
|
|
Item.EditorClass := AEditorClass;
|
|
Item.EditPropertiesClass := AEditPropertiesClass;
|
|
FEditPropertiesClasses.Insert(0, Item);
|
|
end;
|
|
|
|
procedure ListFreeAndNil(var List: TList);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if List <> nil then
|
|
begin
|
|
for I := 0 to List.Count - 1 do
|
|
TObject(List[I]).Free;
|
|
List.Free;
|
|
List := nil;
|
|
end;
|
|
end;
|
|
|
|
{ TcxPropertyEditor }
|
|
|
|
constructor TcxPropertyEditor.Create(AOwner: TComponent;
|
|
AInspector: TcxCustomRTTIInspector; APropCount: Integer);
|
|
begin
|
|
GetMem(FPropList, APropCount * SizeOf(TcxInstProp));
|
|
FInspector := AInspector;
|
|
FPropCount := APropCount;
|
|
FOwner := AOwner;
|
|
end;
|
|
|
|
destructor TcxPropertyEditor.Destroy;
|
|
begin
|
|
if FPropList <> nil then
|
|
FreeMem(FPropList, FPropCount * SizeOf(TcxInstProp));
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TcxPropertyEditor.AllEqual: Boolean;
|
|
begin
|
|
Result := FPropCount = 1;
|
|
end;
|
|
|
|
procedure TcxPropertyEditor.Edit;
|
|
type
|
|
TcxGetStrFunc = function(const Value: string): Integer of object;
|
|
var
|
|
I: Integer;
|
|
Values: TStringList;
|
|
AddValue: TcxGetStrFunc;
|
|
begin
|
|
Values := TStringList.Create;
|
|
Values.Sorted := ipaSortList in GetAttributes;
|
|
try
|
|
AddValue := Values.Add;
|
|
GetValues(TGetStrProc(AddValue));
|
|
if Values.Count > 0 then
|
|
begin
|
|
I := Values.IndexOf(Value) + 1;
|
|
if I = Values.Count then I := 0;
|
|
Value := Values[I];
|
|
end;
|
|
finally
|
|
Values.Free;
|
|
end;
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaRevertable];
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetComponent(Index: Integer): TPersistent;
|
|
begin
|
|
Result := FPropList^[Index].Instance;
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetFloatValue: Extended;
|
|
begin
|
|
Result := GetFloatValueAt(0);
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetFloatValueAt(Index: Integer): Extended;
|
|
begin
|
|
with FPropList^[Index] do
|
|
Result := GetFloatProp(Instance, PropInfo);
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetInt64Value: Int64;
|
|
begin
|
|
Result := GetInt64ValueAt(0);
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetInt64ValueAt(Index: Integer): Int64;
|
|
begin
|
|
with FPropList^[Index] do
|
|
Result := GetInt64Prop(Instance, PropInfo);
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetEditLimit: Integer;
|
|
begin
|
|
Result := 255;
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetName: string;
|
|
begin
|
|
Result := dxShortStringToString(FPropList^[0].PropInfo^.Name);
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetOrdValue: Longint;
|
|
begin
|
|
Result := GetOrdValueAt(0);
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetOrdValueAt(Index: Integer): Longint;
|
|
begin
|
|
with FPropList^[Index] do
|
|
Result := GetOrdProp(Instance, PropInfo);
|
|
end;
|
|
|
|
procedure TcxPropertyEditor.GetProperties(AOwner: TComponent; Proc: TcxGetPropEditProc);
|
|
begin
|
|
end;
|
|
|
|
procedure TcxPropertyEditor.AdjustInnerEditProperties(
|
|
AProperties: TcxCustomEditProperties);
|
|
begin
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetPropInfo: PPropInfo;
|
|
begin
|
|
Result := FPropList^[0].PropInfo;
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetPropType: PTypeInfo;
|
|
begin
|
|
Result := FPropList^[0].PropInfo^.PropType^;
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetStrValue: string;
|
|
begin
|
|
Result := GetStrValueAt(0);
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetStrValueAt(Index: Integer): string;
|
|
begin
|
|
with FPropList^[Index] do
|
|
Result := GetStrProp(Instance, PropInfo);
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetVarValue: Variant;
|
|
begin
|
|
Result := GetVarValueAt(0);
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetVarValueAt(Index: Integer): Variant;
|
|
begin
|
|
with FPropList^[Index] do
|
|
Result := GetVariantProp(Instance, PropInfo);
|
|
end;
|
|
|
|
function TcxPropertyEditor.GetValue: string;
|
|
begin
|
|
Result := srUnknown;
|
|
end;
|
|
|
|
procedure TcxPropertyEditor.GetValues(Proc: TGetStrProc);
|
|
begin
|
|
end;
|
|
|
|
function TcxPropertyEditor.FindRoot: TComponent;
|
|
begin
|
|
Result := FOwner;
|
|
end;
|
|
|
|
procedure TcxPropertyEditor.PostChangedNotification;
|
|
begin
|
|
Inspector.PostChangedNotification;
|
|
end;
|
|
|
|
procedure TcxPropertyEditor.SetFloatValue(Value: Extended);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to FPropCount - 1 do
|
|
with FPropList^[I] do
|
|
SetFloatProp(Instance, PropInfo, Value);
|
|
end;
|
|
|
|
procedure TcxPropertyEditor.SetInt64Value(Value: Int64);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to FPropCount - 1 do
|
|
with FPropList^[I] do
|
|
SetInt64Prop(Instance, PropInfo, Value);
|
|
end;
|
|
|
|
procedure TcxPropertyEditor.SetOrdValue(Value: Longint);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to FPropCount - 1 do
|
|
with FPropList^[I] do
|
|
SetOrdProp(Instance, PropInfo, Value);
|
|
end;
|
|
|
|
procedure TcxPropertyEditor.SetStrValue(const Value: string);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to FPropCount - 1 do
|
|
with FPropList^[I] do
|
|
SetStrProp(Instance, PropInfo, Value);
|
|
end;
|
|
|
|
procedure TcxPropertyEditor.SetVarValue(const Value: Variant);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to FPropCount - 1 do
|
|
with FPropList^[I] do
|
|
SetVariantProp(Instance, PropInfo, Value);
|
|
end;
|
|
|
|
procedure TcxPropertyEditor.SetValue(const Value: string);
|
|
begin
|
|
end;
|
|
|
|
function AncestorIsValid(Ancestor: TPersistent; Root, RootAncestor: TComponent): Boolean;
|
|
begin
|
|
Result := (Ancestor <> nil) and (RootAncestor <> nil) and
|
|
Root.InheritsFrom(RootAncestor.ClassType);
|
|
end;
|
|
|
|
{$IFNDEF DELPHI6}
|
|
type
|
|
IInterfaceComponentReference = interface
|
|
['{E28B1858-EC86-4559-8FCD-6B4F824151ED}']
|
|
function GetComponent: TComponent;
|
|
end;
|
|
|
|
function VarSameValue(const A, B: Variant): Boolean;
|
|
var
|
|
LA, LB: TVarData;
|
|
begin
|
|
LA := FindVarData(A)^;
|
|
LB := FindVarData(B)^;
|
|
if LA.VType = varEmpty then
|
|
Result := LB.VType = varEmpty
|
|
else if LA.VType = varNull then
|
|
Result := LB.VType = varNull
|
|
else if LB.VType in [varEmpty, varNull] then
|
|
Result := False
|
|
else
|
|
Result := A = B;
|
|
end;
|
|
|
|
function VarIsClear(const V: Variant): Boolean;
|
|
var
|
|
LVarData: TVarData;
|
|
begin
|
|
LVarData := FindVarData(V)^;
|
|
with LVarData do
|
|
Result := (VType = varEmpty) or
|
|
(((VType = varDispatch) or (VType = varUnknown)) and (VDispatch = nil));
|
|
end;
|
|
|
|
function GetInterfaceProp(Instance: TObject; PropInfo: PPropInfo): IInterface;
|
|
type
|
|
TInterfaceGetProc = function :IInterface of object;
|
|
TInterfaceIndexedGetProc = function (Index: Integer): IInterface of object;
|
|
var
|
|
P: ^IInterface;
|
|
M: TMethod;
|
|
Getter: Longint;
|
|
begin
|
|
Getter := Longint(PropInfo^.GetProc);
|
|
if (Getter and $FF000000) = $FF000000 then
|
|
begin // field - Getter is the field's offset in the instance data
|
|
P := Pointer(Integer(Instance) + (Getter and $00FFFFFF));
|
|
Result := P^; // auto ref count
|
|
end
|
|
else
|
|
begin
|
|
if (Getter and $FF000000) = $FE000000 then
|
|
// virtual method - Getter is a signed 2 byte integer VMT offset
|
|
M.Code := Pointer(PInteger(PInteger(Instance)^ + SmallInt(Getter))^)
|
|
else
|
|
// static method - Getter is the actual address
|
|
M.Code := Pointer(Getter);
|
|
|
|
M.Data := Instance;
|
|
if PropInfo^.Index = Integer($80000000) then // no index
|
|
Result := TInterfaceGetProc(M)()
|
|
else
|
|
Result := TInterfaceIndexedGetProc(M)(PropInfo^.Index);
|
|
end;
|
|
end;
|
|
|
|
function GetObjectProp(Instance: TObject; PropInfo: PPropInfo): TObject;
|
|
begin
|
|
Result := TObject(GetOrdProp(Instance, PropInfo));
|
|
end;
|
|
|
|
function GetWideStrProp(Instance: TObject; PropInfo: PPropInfo): WideString;
|
|
type
|
|
TWideStringGetProc = function :WideString of object;
|
|
TWideStringIndexedGetProc = function (Index: Integer): WideString of object;
|
|
var
|
|
P: PWideString;
|
|
M: TMethod;
|
|
Getter: Longint;
|
|
begin
|
|
case PropInfo^.PropType^.Kind of
|
|
tkString,
|
|
tkLString: Result := GetStrProp(Instance, PropInfo);
|
|
tkWString:
|
|
begin
|
|
Getter := Longint(PropInfo^.GetProc);
|
|
if (Getter and $FF000000) = $FF000000 then
|
|
begin // field - Getter is the field's offset in the instance data
|
|
P := Pointer(Integer(Instance) + (Getter and $00FFFFFF));
|
|
Result := P^; // auto ref count
|
|
end
|
|
else
|
|
begin
|
|
if (Getter and $FF000000) = $FE000000 then
|
|
// virtual method - Getter is a signed 2 byte integer VMT offset
|
|
M.Code := Pointer(PInteger(PInteger(Instance)^ + SmallInt(Getter))^)
|
|
else
|
|
// static method - Getter is the actual address
|
|
M.Code := Pointer(Getter);
|
|
|
|
M.Data := Instance;
|
|
if PropInfo^.Index = Integer($80000000) then // no index
|
|
Result := TWideStringGetProc(M)()
|
|
else
|
|
Result := TWideStringIndexedGetProc(M)(PropInfo^.Index);
|
|
end;
|
|
end;
|
|
else
|
|
Result := '';
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFNDEF DELPHI7}
|
|
type
|
|
TGetLookupInfoEvent = procedure(var Ancestor: TPersistent;
|
|
var Root, LookupRoot, RootAncestor: TComponent) of object;
|
|
|
|
function IsDefaultPropertyValue(Instance: TObject; PropInfo: PPropInfo;
|
|
OnGetLookupInfo: TGetLookupInfoEvent): Boolean;
|
|
var
|
|
PropType: PTypeInfo;
|
|
Ancestor: TPersistent;
|
|
LookupRoot: TComponent;
|
|
RootAncestor: TComponent;
|
|
Root: TComponent;
|
|
AncestorValid: Boolean;
|
|
|
|
function IsDefaultOrdProp: Boolean;
|
|
var
|
|
Value: Longint;
|
|
Default: LongInt;
|
|
begin
|
|
Value := GetOrdProp(Instance, PropInfo);
|
|
if AncestorValid then
|
|
Result := Value = GetOrdProp(Ancestor, PropInfo)
|
|
else
|
|
begin
|
|
Default := PPropInfo(PropInfo)^.Default;
|
|
Result := (Default <> LongInt($80000000)) and (Value = Default);
|
|
end;
|
|
end;
|
|
|
|
function IsDefaultFloatProp: Boolean;
|
|
var
|
|
Value: Extended;
|
|
begin
|
|
Value := GetFloatProp(Instance, PropInfo);
|
|
if AncestorValid then
|
|
Result := Value = GetFloatProp(Ancestor, PropInfo)
|
|
else
|
|
Result := Value = 0;;
|
|
end;
|
|
|
|
function IsDefaultInt64Prop: Boolean;
|
|
var
|
|
Value: Int64;
|
|
begin
|
|
Value := GetInt64Prop(Instance, PropInfo);
|
|
if AncestorValid then
|
|
Result := Value = GetInt64Prop(Ancestor, PropInfo)
|
|
else
|
|
Result := Value = 0;
|
|
end;
|
|
|
|
function IsDefaultStrProp: Boolean;
|
|
var
|
|
Value: WideString;
|
|
begin
|
|
Value := GetWideStrProp(Instance, PropInfo);
|
|
if AncestorValid then
|
|
Result := Value = GetWideStrProp(Ancestor, PropInfo)
|
|
else
|
|
Result := Value = '';
|
|
end;
|
|
|
|
function ObjectAncestorMatch(AncestorValue, Value: TComponent): Boolean;
|
|
begin
|
|
Result := (AncestorValue <> nil) and (AncestorValue.Owner = RootAncestor) and
|
|
(Value <> nil) and (Value.Owner = Root) and
|
|
SameText(AncestorValue.Name, Value.Name);
|
|
end;
|
|
|
|
function IsDefaultObjectProp: Boolean;
|
|
var
|
|
Value: TObject;
|
|
|
|
function IsDefault: Boolean;
|
|
var
|
|
AncestorValue: TObject;
|
|
begin
|
|
AncestorValue := nil;
|
|
if AncestorValid then
|
|
begin
|
|
AncestorValue := TObject(GetOrdProp(Ancestor, PropInfo));
|
|
if ObjectAncestorMatch(TComponent(AncestorValue), TComponent(Value)) then
|
|
AncestorValue := Value;
|
|
end;
|
|
Result := Value = AncestorValue;
|
|
end;
|
|
|
|
begin
|
|
Result := True;
|
|
Value := TObject(GetOrdProp(Instance, PropInfo));
|
|
if (Value = nil) and not IsDefault then
|
|
begin
|
|
Result := False; // nil wasn't the "default" value
|
|
end
|
|
else if Value is TPersistent then
|
|
begin
|
|
{$IFDEF DELPHI6}
|
|
if (Value is TComponent) and
|
|
not (csSubComponent in TComponent(Value).ComponentStyle) then
|
|
begin
|
|
if not IsDefault then
|
|
begin
|
|
// A non sub-component TComponent is only non-default if
|
|
// it actually has a name (that way, it can be streamed out -
|
|
// it can't be streamed without a name).
|
|
if TComponent(Value).Name <> '' then
|
|
Result := False;
|
|
end
|
|
end
|
|
else
|
|
{$ENDIF}
|
|
Result := False; // The TPersistent should be checked for default's by the caller
|
|
end;
|
|
end;
|
|
|
|
function IsDefaultInterfaceProp: Boolean;
|
|
var
|
|
Intf: IInterface;
|
|
Value: TComponent;
|
|
|
|
function IsDefaultValue: Boolean;
|
|
var
|
|
AncestorIntf: IInterface;
|
|
ASR: IInterfaceComponentReference;
|
|
begin
|
|
Result := Intf = nil;
|
|
if AncestorValid then
|
|
begin
|
|
AncestorIntf := GetInterfaceProp(Ancestor, PropInfo);
|
|
Result := Intf = AncestorIntf;
|
|
if not Result then
|
|
begin
|
|
if Supports(AncestorIntf, IInterfaceComponentReference, ASR) then
|
|
Result := ObjectAncestorMatch(ASR.GetComponent, Value);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
SR: IInterfaceComponentReference;
|
|
begin
|
|
Result := True;
|
|
Intf := GetInterfaceProp(Instance, PropInfo);
|
|
if (Intf = nil) or (not Supports(Intf, IInterfaceComponentReference, SR)) then
|
|
begin
|
|
if AncestorValid and (GetInterfaceProp(Ancestor, PropInfo) <> nil) then
|
|
Result := False;
|
|
end
|
|
else
|
|
begin
|
|
Value := SR.GetComponent;
|
|
if not IsDefaultValue then
|
|
begin
|
|
// We can only stream out components (ie: non-default ones)
|
|
// if they actually have a name
|
|
if Value.Name <> '' then
|
|
Result := False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function IsDefaultMethodProp: Boolean;
|
|
var
|
|
Value: TMethod;
|
|
DefaultCode: Pointer;
|
|
begin
|
|
Value := GetMethodProp(Instance, PropInfo);
|
|
DefaultCode := nil;
|
|
if AncestorValid then
|
|
DefaultCode := GetMethodProp(Ancestor, PropInfo).Code;
|
|
Result := (Value.Code = DefaultCode) or
|
|
((Value.Code <> nil) and (LookupRoot.MethodName(Value.Code) = ''));
|
|
end;
|
|
|
|
function IsDefaultVariantProp: Boolean;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := GetVariantProp(Instance, PropInfo);
|
|
if AncestorValid then
|
|
Result := VarSameValue(Value, GetVariantProp(Ancestor, PropInfo))
|
|
else
|
|
Result := VarIsClear(Value);
|
|
end;
|
|
|
|
begin
|
|
Ancestor := nil;
|
|
Root := nil;
|
|
LookupRoot := nil;
|
|
RootAncestor := nil;
|
|
|
|
if Assigned(OnGetLookupInfo) then
|
|
OnGetLookupInfo(Ancestor, Root, LookupRoot, RootAncestor);
|
|
|
|
AncestorValid := AncestorIsValid(Ancestor, Root, RootAncestor);
|
|
|
|
Result := True;
|
|
if (PropInfo^.GetProc <> nil) and
|
|
((PropInfo^.SetProc <> nil) {$IFDEF DELPHI6} or
|
|
((PropInfo^.PropType^.Kind = tkClass) and
|
|
(TObject(GetOrdProp(Instance, PropInfo)) is TComponent) and
|
|
(csSubComponent in TComponent(GetOrdProp(Instance, PropInfo)).ComponentStyle)) {$ENDIF}) then
|
|
begin
|
|
PropType := PropInfo^.PropType^;
|
|
case PropType^.Kind of
|
|
tkInteger, tkChar, tkEnumeration, tkSet:
|
|
Result := IsDefaultOrdProp;
|
|
tkFloat:
|
|
Result := IsDefaultFloatProp;
|
|
tkString, tkLString, tkWString:
|
|
Result := IsDefaultStrProp;
|
|
tkClass:
|
|
Result := IsDefaultObjectProp;
|
|
tkMethod:
|
|
Result := IsDefaultMethodProp;
|
|
tkVariant:
|
|
Result := IsDefaultVariantProp;
|
|
tkInt64:
|
|
Result := IsDefaultInt64Prop;
|
|
tkInterface:
|
|
Result := IsDefaultInterfaceProp;
|
|
end;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function TcxPropertyEditor.IsDefaultValue: Boolean;
|
|
function CheckProperties(AnObject: TObject): Boolean;
|
|
var
|
|
PropList: PPropList;
|
|
PropInfo: PPropInfo;
|
|
I, Count: Integer;
|
|
begin
|
|
Result := True;
|
|
// Go through each of the properties on the object
|
|
Count := GetTypeData(AnObject.ClassInfo)^.PropCount;
|
|
if Count > 0 then
|
|
begin
|
|
GetMem(PropList, Count * SizeOf(Pointer));
|
|
try
|
|
GetPropInfos(AnObject.ClassInfo, PropList);
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
PropInfo := PropList^[I];
|
|
if PropInfo = nil then
|
|
Break;
|
|
if not IsDefaultPropertyValue(AnObject, PropInfo, GetLookupInfo) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
end;
|
|
finally
|
|
FreeMem(PropList, Count * SizeOf(Pointer));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
FirstInstance: TObject;
|
|
FirstPropInfo: PPropInfo;
|
|
|
|
SubObject: TObject;
|
|
OldAncestor: TPersistent;
|
|
|
|
begin
|
|
Result := True;
|
|
if PropCount > 0 then
|
|
begin
|
|
// if they are not all equal, then they aren't all the default (at least one..)
|
|
if not AllEqual then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
|
|
FirstInstance := FPropList^[0].Instance;
|
|
FirstPropInfo := FPropList^[0].PropInfo;
|
|
if IsStoredProp(FirstInstance, FirstPropInfo) then
|
|
begin
|
|
// TWriter.WriteDescendent simulation
|
|
FRootAncestor := nil;
|
|
FAncestor := nil;
|
|
FRoot := FindRoot;
|
|
if FirstInstance is TComponent then
|
|
begin
|
|
FLookingFor := TComponent(FirstInstance);
|
|
// Only lookup the component if it was introduced in an ancestor form/frame
|
|
if csAncestor in FLookingFor.ComponentState then
|
|
begin
|
|
FDoneLooking := False;
|
|
WriteComponentSimulation(FRoot);
|
|
end
|
|
else
|
|
begin
|
|
FRootAncestor := nil;
|
|
FAncestor := nil;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
// In this case, we will not look up the ancestor (there really
|
|
// isn't one - take columns on tlistview as an example)
|
|
FRootAncestor := nil;
|
|
FAncestor := nil;
|
|
end;
|
|
|
|
Result := IsDefaultPropertyValue(FirstInstance, FirstPropInfo, GetLookupInfo);
|
|
if not Result then
|
|
begin
|
|
if FirstPropInfo^.PropType^.Kind = tkClass then
|
|
begin
|
|
// If it was a class/object then we need to recursivly check that
|
|
// object to see if it has all default properties.
|
|
SubObject := GetObjectProp(FirstInstance, FirstPropInfo);
|
|
|
|
OldAncestor := FAncestor;
|
|
try
|
|
if AncestorIsValid(FAncestor, FRoot, FRootAncestor) then
|
|
FAncestor := TPersistent(GetOrdProp(FAncestor, FirstPropInfo));
|
|
Result := CheckProperties(SubObject);
|
|
finally
|
|
FAncestor := OldAncestor;
|
|
end;
|
|
|
|
if SubObject is TCollection then
|
|
begin
|
|
if not AncestorIsValid(FAncestor, FRoot, FRootAncestor) or
|
|
not CollectionsEqual(TCollection(SubObject),
|
|
TCollection(GetOrdProp(FAncestor, FirstPropInfo))
|
|
{$IFDEF DELPHI6}, FRoot, FRootAncestor{$ENDIF}) then
|
|
Result := False;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TcxPropertyEditor.ValueAvailable: Boolean;
|
|
var
|
|
I: Integer;
|
|
S: string;
|
|
begin
|
|
Result := True;
|
|
for I := 0 to FPropCount - 1 do
|
|
if (FPropList^[I].Instance is TComponent) and
|
|
(csCheckPropAvail in TComponent(FPropList^[I].Instance).ComponentStyle) then
|
|
begin
|
|
try
|
|
S := GetValue;
|
|
AllEqual;
|
|
except
|
|
Result := False;
|
|
end;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxPropertyEditor.AddAncestor(Component: TComponent);
|
|
begin
|
|
FAncestorList.Add(Component);
|
|
end;
|
|
|
|
procedure TcxPropertyEditor.GetLookupInfo(var Ancestor: TPersistent;
|
|
var Root, LookupRoot, RootAncestor: TComponent);
|
|
begin
|
|
Ancestor := FAncestor;
|
|
Root := FRoot;
|
|
LookupRoot := FRoot; // Same in this case
|
|
RootAncestor := FRootAncestor;
|
|
end;
|
|
|
|
procedure TcxPropertyEditor.SetPropEntry(Index: Integer;
|
|
AInstance: TPersistent; APropInfo: PPropInfo);
|
|
begin
|
|
with FPropList^[Index] do
|
|
begin
|
|
Instance := AInstance;
|
|
PropInfo := APropInfo;
|
|
end;
|
|
end;
|
|
|
|
type
|
|
TComponentHack = class(TComponent);
|
|
|
|
procedure TcxPropertyEditor.WriteComponentSimulation(Component: TComponent);
|
|
function FindAncestor(const Name: string): TComponent;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to FAncestorList.Count - 1 do
|
|
begin
|
|
Result := FAncestorList[I];
|
|
if SameText(Result.Name, Name) then Exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
var
|
|
OldAncestor: TPersistent;
|
|
OldRoot, OldRootAncestor: TComponent;
|
|
OldAncestorList: TList;
|
|
TempAncestor: TPersistent;
|
|
begin
|
|
if FDoneLooking then
|
|
Exit;
|
|
|
|
OldAncestor := FAncestor;
|
|
OldRootAncestor := FRootAncestor;
|
|
try
|
|
if Assigned(FAncestorList) then
|
|
FAncestor := FindAncestor(Component.Name);
|
|
|
|
// If we are at the component we were looking for, then we
|
|
// can stop at this point
|
|
if FLookingFor = Component then
|
|
FDoneLooking := True
|
|
else if SameText(FLookingFor.Name, Component.Name) then
|
|
FDoneLooking := True
|
|
else
|
|
begin
|
|
if (FAncestor = nil) and (Component <> FRoot) then
|
|
begin
|
|
TempAncestor := FRoot;
|
|
if TempAncestor <> nil then
|
|
begin
|
|
FAncestor := TempAncestor;
|
|
FRootAncestor := TComponent(FAncestor);
|
|
end;
|
|
end;
|
|
// Component.WriteState(Self); // This is simulated below, inline
|
|
OldAncestorList := FAncestorList;
|
|
OldRoot := FRoot;
|
|
OldRootAncestor := FRootAncestor;
|
|
try
|
|
FAncestorList := nil;
|
|
try
|
|
if (FAncestor <> nil) and (FAncestor is TComponent) then
|
|
begin
|
|
{$IFDEF DELPHI5}
|
|
if csInline in TComponent(FAncestor).ComponentState then
|
|
FRootAncestor := TComponent(FAncestor);
|
|
{$ENDIF}
|
|
FAncestorList := TList.Create;
|
|
TComponentHack(FAncestor).GetChildren(AddAncestor, FRootAncestor);
|
|
end;
|
|
{$IFDEF DELPHI5}
|
|
if csInline in Component.ComponentState then
|
|
FRoot := Component;
|
|
{$ENDIF}
|
|
TComponentHack(Component).GetChildren(WriteComponentSimulation, FRoot);
|
|
finally
|
|
FAncestorList.Free;
|
|
end;
|
|
finally
|
|
FAncestorList := OldAncestorList;
|
|
if not FDoneLooking then
|
|
begin
|
|
FRoot := OldRoot;
|
|
FRootAncestor := OldRootAncestor;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
if not FDoneLooking then
|
|
begin
|
|
// Only restore the ancestor if we were not done looking.
|
|
// This way, we can continue up the chaing looking for the
|
|
// component
|
|
FAncestor := OldAncestor;
|
|
FRootAncestor := OldRootAncestor;
|
|
end
|
|
end;
|
|
end;
|
|
|
|
{ TcxOrdinalProperty }
|
|
|
|
function TcxOrdinalProperty.AllEqual: Boolean;
|
|
var
|
|
I: Integer;
|
|
V: Longint;
|
|
begin
|
|
Result := False;
|
|
if PropCount > 1 then
|
|
begin
|
|
V := GetOrdValue;
|
|
for I := 1 to PropCount - 1 do
|
|
if GetOrdValueAt(I) <> V then Exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function TcxOrdinalProperty.GetEditLimit: Integer;
|
|
begin
|
|
Result := 63;
|
|
end;
|
|
|
|
{ TcxIntegerProperty }
|
|
|
|
function TcxIntegerProperty.GetValue: string;
|
|
begin
|
|
Result := IntToStr(GetOrdValue);
|
|
end;
|
|
|
|
procedure TcxIntegerProperty.SetValue(const Value: string);
|
|
|
|
procedure Error(const Args: array of const);
|
|
begin
|
|
raise EcxPropertyError.CreateFmt(SOutOfRange, Args);
|
|
end;
|
|
|
|
var
|
|
L: Int64;
|
|
begin
|
|
L := StrToInt64(Value);
|
|
with GetTypeData(GetPropType)^ do
|
|
{$IFDEF DELPHI5}
|
|
if OrdType = otULong then
|
|
begin
|
|
if (L < Cardinal(MinValue)) or (L > Cardinal(MaxValue)) then
|
|
Error([Int64(Cardinal(MinValue)), Int64(Cardinal(MaxValue))]);
|
|
end
|
|
else
|
|
{$ENDIF}if (L < MinValue) or (L > MaxValue) then
|
|
Error([MinValue, MaxValue]);
|
|
SetOrdValue(L);
|
|
end;
|
|
|
|
{ TCharProperty }
|
|
|
|
function TcxCharProperty.GetValue: string;
|
|
var
|
|
Ch: Char;
|
|
begin
|
|
Ch := Chr(GetOrdValue);
|
|
if dxCharInSet(Ch, [#33..#127]) then
|
|
Result := Ch
|
|
else
|
|
FmtStr(Result, '#%d', [Ord(Ch)]);
|
|
end;
|
|
|
|
procedure TcxCharProperty.SetValue(const Value: string);
|
|
var
|
|
L: Longint;
|
|
begin
|
|
if Length(Value) = 0 then
|
|
L := 0
|
|
else
|
|
if Length(Value) = 1 then
|
|
L := Ord(Value[1])
|
|
else
|
|
if Value[1] = '#' then
|
|
L := StrToInt(Copy(Value, 2, Maxint))
|
|
else
|
|
raise EcxPropertyError.Create(SInvalidPropertyValue);
|
|
|
|
with GetTypeData(GetPropType)^ do
|
|
if (L < MinValue) or (L > MaxValue) then
|
|
raise EcxPropertyError.CreateFmt(SOutOfRange, [MinValue, MaxValue]);
|
|
SetOrdValue(L);
|
|
end;
|
|
|
|
{ TcxEnumProperty }
|
|
|
|
function TcxEnumProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaValueList, ipaSortList, ipaRevertable];
|
|
end;
|
|
|
|
function TcxEnumProperty.GetValue: string;
|
|
var
|
|
L: Longint;
|
|
begin
|
|
L := GetOrdValue;
|
|
with GetTypeData(GetPropType)^ do
|
|
if (L < MinValue) or (L > MaxValue) then L := MaxValue;
|
|
Result := GetEnumName(GetPropType, L);
|
|
end;
|
|
|
|
procedure TcxEnumProperty.GetValues(Proc: TGetStrProc);
|
|
var
|
|
I: Integer;
|
|
EnumType: PTypeInfo;
|
|
begin
|
|
EnumType := GetPropType;
|
|
with GetTypeData(EnumType)^ do
|
|
for I := MinValue to MaxValue do
|
|
Proc(GetEnumName(EnumType, I));
|
|
end;
|
|
|
|
procedure TcxEnumProperty.SetValue(const Value: string);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I := GetEnumValue(GetPropType, Value);
|
|
if I < 0 then raise EcxPropertyError.Create(SInvalidPropertyValue);
|
|
SetOrdValue(I);
|
|
end;
|
|
|
|
{ TcxBoolProperty }
|
|
|
|
function TcxBoolProperty.GetValue: string;
|
|
begin
|
|
if GetOrdValue = 0 then
|
|
Result := 'False'
|
|
else
|
|
Result := 'True';
|
|
end;
|
|
|
|
procedure TcxBoolProperty.GetValues(Proc: TGetStrProc);
|
|
begin
|
|
Proc('False');
|
|
Proc('True');
|
|
end;
|
|
|
|
procedure TcxBoolProperty.SetValue(const Value: string);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if CompareText(Value, 'False') = 0 then
|
|
I := 0
|
|
else
|
|
if CompareText(Value, 'True') = 0 then
|
|
I := 1
|
|
else
|
|
I := StrToInt(Value);
|
|
SetOrdValue(I);
|
|
end;
|
|
|
|
{ TInt64Property }
|
|
|
|
function TcxInt64Property.AllEqual: Boolean;
|
|
var
|
|
I: Integer;
|
|
V: Int64;
|
|
begin
|
|
Result := False;
|
|
if PropCount > 1 then
|
|
begin
|
|
V := GetInt64Value;
|
|
for I := 1 to PropCount - 1 do
|
|
if GetInt64ValueAt(I) <> V then Exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function TcxInt64Property.GetEditLimit: Integer;
|
|
begin
|
|
Result := 63;
|
|
end;
|
|
|
|
function TcxInt64Property.GetValue: string;
|
|
begin
|
|
Result := IntToStr(GetInt64Value);
|
|
end;
|
|
|
|
procedure TcxInt64Property.SetValue(const Value: string);
|
|
begin
|
|
SetInt64Value(StrToInt64(Value));
|
|
end;
|
|
|
|
{ TcxFloatProperty }
|
|
|
|
function TcxFloatProperty.AllEqual: Boolean;
|
|
var
|
|
I: Integer;
|
|
V: Extended;
|
|
begin
|
|
Result := False;
|
|
if PropCount > 1 then
|
|
begin
|
|
V := GetFloatValue;
|
|
for I := 1 to PropCount - 1 do
|
|
if GetFloatValueAt(I) <> V then Exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function TcxFloatProperty.GetValue: string;
|
|
const
|
|
Precisions: array[TFloatType] of Integer = (7, 15, 18, 18, 18);
|
|
begin
|
|
Result := FloatToStrF(GetFloatValue, ffGeneral,
|
|
Precisions[GetTypeData(GetPropType)^.FloatType], 0);
|
|
end;
|
|
|
|
procedure TcxFloatProperty.SetValue(const Value: string);
|
|
begin
|
|
SetFloatValue(StrToFloat(Value));
|
|
end;
|
|
|
|
{ TcxStringProperty }
|
|
|
|
function TcxStringProperty.AllEqual: Boolean;
|
|
var
|
|
I: Integer;
|
|
V: string;
|
|
begin
|
|
Result := False;
|
|
if PropCount > 1 then
|
|
begin
|
|
V := GetStrValue;
|
|
for I := 1 to PropCount - 1 do
|
|
if GetStrValueAt(I) <> V then Exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function TcxStringProperty.GetEditLimit: Integer;
|
|
begin
|
|
if GetPropType^.Kind = tkString then
|
|
Result := GetTypeData(GetPropType)^.MaxLength
|
|
else
|
|
Result := 255;
|
|
end;
|
|
|
|
function TcxStringProperty.GetValue: string;
|
|
begin
|
|
Result := GetStrValue;
|
|
end;
|
|
|
|
procedure TcxStringProperty.SetValue(const Value: string);
|
|
begin
|
|
SetStrValue(Value);
|
|
end;
|
|
|
|
{ TcxComponentNameProperty }
|
|
|
|
function TcxComponentNameProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [];
|
|
end;
|
|
|
|
function TcxComponentNameProperty.GetEditLimit: Integer;
|
|
begin
|
|
Result := 63;
|
|
end;
|
|
|
|
{ TcxSetElementProperty }
|
|
|
|
constructor TcxSetElementProperty.Create(APropList: PcxInstPropList;
|
|
APropCount: Integer; AElement: Integer);
|
|
begin
|
|
FPropList := APropList;
|
|
FPropCount := APropCount;
|
|
FElement := AElement;
|
|
end;
|
|
|
|
destructor TcxSetElementProperty.Destroy;
|
|
begin
|
|
end;
|
|
|
|
function TcxSetElementProperty.AllEqual: Boolean;
|
|
var
|
|
I: Integer;
|
|
S: TcxIntegerSet;
|
|
V: Boolean;
|
|
begin
|
|
Result := False;
|
|
if PropCount > 1 then
|
|
begin
|
|
Integer(S) := GetOrdValue;
|
|
V := FElement in S;
|
|
for I := 1 to PropCount - 1 do
|
|
begin
|
|
Integer(S) := GetOrdValueAt(I);
|
|
if (FElement in S) <> V then Exit;
|
|
end;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function TcxSetElementProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaValueList, ipaSortList, ipaRevertable];
|
|
end;
|
|
|
|
function TcxSetElementProperty.GetName: string;
|
|
begin
|
|
Result := GetEnumName(GetTypeData(GetPropType)^.CompType^, FElement);
|
|
end;
|
|
|
|
function TcxSetElementProperty.GetValue: string;
|
|
var
|
|
S: TcxIntegerSet;
|
|
begin
|
|
Integer(S) := GetOrdValue;
|
|
if FElement in S then
|
|
Result := 'True'
|
|
else
|
|
Result := 'False';
|
|
end;
|
|
|
|
procedure TcxSetElementProperty.GetValues(Proc: TGetStrProc);
|
|
begin
|
|
Proc('False');
|
|
Proc('True');
|
|
end;
|
|
|
|
procedure TcxSetElementProperty.SetValue(const Value: string);
|
|
var
|
|
S: TcxIntegerSet;
|
|
begin
|
|
Integer(S) := GetOrdValue;
|
|
if CompareText(Value, 'True') = 0 then
|
|
Include(S, FElement)
|
|
else
|
|
Exclude(S, FElement);
|
|
SetOrdValue(Integer(S));
|
|
end;
|
|
|
|
function TcxSetElementProperty.IsDefaultValue: Boolean;
|
|
var
|
|
S1, S2: TcxIntegerSet;
|
|
HasStoredProc: Integer;
|
|
ProcAsInt: Integer;
|
|
begin
|
|
Result := inherited IsDefaultValue;
|
|
if not Result then
|
|
begin
|
|
ProcAsInt := Integer(PPropInfo(GetPropInfo)^.StoredProc);
|
|
HasStoredProc := ProcAsInt and $FFFFFF00;
|
|
if HasStoredProc = 0 then
|
|
begin
|
|
Integer(S1) := PPropInfo(GetPropInfo)^.Default;
|
|
Integer(S2) := GetOrdValue;
|
|
Result := not ((FElement in S1) xor (FElement in S2));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TcxSetProperty }
|
|
|
|
function TcxSetProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaSubProperties, ipaReadOnly, ipaRevertable];
|
|
end;
|
|
|
|
procedure TcxSetProperty.GetProperties(AOwner: TComponent; Proc: TcxGetPropEditProc);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with GetTypeData(GetTypeData(GetPropType)^.CompType^)^ do
|
|
for I := MinValue to MaxValue do
|
|
Proc(TcxSetElementProperty.Create(FPropList, FPropCount, I));
|
|
end;
|
|
|
|
function TcxSetProperty.GetValue: string;
|
|
var
|
|
S: TcxIntegerSet;
|
|
TypeInfo: PTypeInfo;
|
|
I: Integer;
|
|
begin
|
|
Integer(S) := GetOrdValue;
|
|
TypeInfo := GetTypeData(GetPropType)^.CompType^;
|
|
Result := '[';
|
|
for I := 0 to SizeOf(Integer) * 8 - 1 do
|
|
if I in S then
|
|
begin
|
|
if Length(Result) <> 1 then Result := Result + ',';
|
|
Result := Result + GetEnumName(TypeInfo, I);
|
|
end;
|
|
Result := Result + ']';
|
|
end;
|
|
|
|
{ TcxClassProperty }
|
|
|
|
function TcxClassProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaSubProperties, ipaReadOnly];
|
|
end;
|
|
|
|
procedure TcxClassProperty.GetProperties(AOwner: TComponent; Proc: TcxGetPropEditProc);
|
|
var
|
|
Components: TcxComponentList;
|
|
I: Integer;
|
|
begin
|
|
Components := TcxComponentList.Create;
|
|
try
|
|
for I := 0 to PropCount - 1 do
|
|
if TComponent(GetOrdValueAt(I)) <> nil then
|
|
Components.Add(TComponent(GetOrdValueAt(I)));
|
|
cxGetComponentProperties(AOwner, FInspector, Components, tkProperties, Proc);
|
|
finally
|
|
Components.Free;
|
|
end;
|
|
end;
|
|
|
|
function TcxClassProperty.GetValue: string;
|
|
begin
|
|
FmtStr(Result, '(%s)', [GetPropType^.Name]);
|
|
end;
|
|
|
|
{ TcxComponentProperty }
|
|
|
|
function TcxComponentProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaValueList, ipaSortList, ipaRevertable];
|
|
end;
|
|
|
|
function TcxComponentProperty.GetEditLimit: Integer;
|
|
begin
|
|
Result := 127;
|
|
end;
|
|
|
|
function TcxComponentProperty.GetValue: string;
|
|
begin
|
|
if TComponent(GetOrdValue) <> nil then
|
|
Result := GetFullName(TComponent(GetOrdValue))
|
|
else
|
|
Result := '';
|
|
end;
|
|
|
|
procedure TcxComponentProperty.GetValues(Proc: TGetStrProc);
|
|
|
|
procedure AddProc(AComponent: TComponent);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to AComponent.ComponentCount - 1 do
|
|
begin
|
|
if IsValidComponent(AComponent.Components[i]) then
|
|
Proc(GetFullName(AComponent.Components[i]));
|
|
AddProc(AComponent.Components[i]);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
AOwner: TComponent;
|
|
begin
|
|
if FOwner <> nil then
|
|
begin
|
|
AOwner := FOwner;
|
|
while AOwner.Owner <> nil do
|
|
AOwner := AOwner.Owner;
|
|
AddProc(AOwner);
|
|
end
|
|
else
|
|
AddProc(Application);
|
|
end;
|
|
|
|
procedure TcxComponentProperty.SetValue(const Value: string);
|
|
var
|
|
Component: TComponent;
|
|
|
|
function GetComponentByName(const AName: string): TComponent;
|
|
|
|
procedure CheckOwner(AOwner: TComponent);
|
|
var
|
|
I: Integer;
|
|
AComponent: TComponent;
|
|
begin
|
|
if Result <> nil then Exit;
|
|
for I := 0 to AOwner.ComponentCount - 1 do
|
|
begin
|
|
AComponent := AOwner.Components[I];
|
|
if SameText(GetFullName(AComponent), AName) then
|
|
begin
|
|
Result := AComponent;
|
|
break;
|
|
end
|
|
else
|
|
CheckOwner(AComponent);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
AOwner: TComponent;
|
|
begin
|
|
Result := nil;
|
|
AOwner := FOwner;
|
|
while AOwner.Owner <> nil do
|
|
AOwner := AOwner.Owner;
|
|
CheckOwner(AOwner);
|
|
end;
|
|
|
|
begin
|
|
if Value = '' then
|
|
Component := nil
|
|
else
|
|
begin
|
|
Component := GetComponentByName(Value);
|
|
if not (Component is GetTypeData(GetPropType)^.ClassType) then
|
|
raise EcxPropertyError.Create(SInvalidPropertyValue);
|
|
end;
|
|
SetOrdValue(Longint(Component));
|
|
end;
|
|
|
|
function TcxComponentProperty.IsValidComponent(AComponent: TComponent): Boolean;
|
|
begin
|
|
Result := (AComponent.Name <> '') and (AComponent is GetTypeData(GetPropType)^.ClassType);
|
|
end;
|
|
|
|
function TcxComponentProperty.GetFullName(AComponent: TComponent): string;
|
|
begin
|
|
Result := cxGetFullComponentName(AComponent);
|
|
end;
|
|
|
|
{ TcxFontNameProperty }
|
|
|
|
function TcxFontNameProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaValueList, ipaSortList, ipaRevertable];
|
|
end;
|
|
|
|
procedure TcxFontNameProperty.GetValues(Proc: TGetStrProc);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Screen.Fonts.Count - 1 do
|
|
Proc(Screen.Fonts[I]);
|
|
end;
|
|
|
|
{ TcxFontCharsetProperty }
|
|
|
|
function TcxFontCharsetProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaSortList, ipaValueList];
|
|
end;
|
|
|
|
function TcxFontCharsetProperty.GetValue: string;
|
|
begin
|
|
if not CharsetToIdent(TFontCharset(GetOrdValue), Result) then
|
|
FmtStr(Result, '%d', [GetOrdValue]);
|
|
end;
|
|
|
|
procedure TcxFontCharsetProperty.GetValues(Proc: TGetStrProc);
|
|
begin
|
|
GetCharsetValues(Proc);
|
|
end;
|
|
|
|
procedure TcxFontCharsetProperty.SetValue(const Value: string);
|
|
var
|
|
NewValue: Longint;
|
|
begin
|
|
if IdentToCharset(Value, NewValue) then
|
|
SetOrdValue(NewValue)
|
|
else
|
|
inherited SetValue(Value);
|
|
end;
|
|
|
|
{ TcxImeNameProperty }
|
|
|
|
function TcxImeNameProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaValueList, ipaSortList, ipaMultiSelect];
|
|
end;
|
|
|
|
procedure TcxImeNameProperty.GetValues(Proc: TGetStrProc);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Screen.Imes.Count - 1 do
|
|
Proc(Screen.Imes[I]);
|
|
end;
|
|
|
|
{ TcxMPFilenameProperty }
|
|
|
|
procedure TcxMPFilenameProperty.Edit;
|
|
var
|
|
OpenDialog: TOpenDialog;
|
|
begin
|
|
OpenDialog := TOpenDialog.Create(Application);
|
|
with OpenDialog do
|
|
try
|
|
Filename := GetValue;
|
|
Filter := SMPOpenFilter;
|
|
Options := Options + [ofPathMustExist, ofFileMustExist];
|
|
if Execute then
|
|
begin
|
|
SetValue(FileName);
|
|
PostChangedNotification;
|
|
end;
|
|
finally
|
|
Free;
|
|
end;
|
|
end;
|
|
|
|
function TcxMPFilenameProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaDialog, ipaRevertable];
|
|
end;
|
|
|
|
{ TcxColorProperty }
|
|
|
|
procedure TcxColorProperty.Edit;
|
|
var
|
|
ColorDialog: TColorDialog;
|
|
IniFile: TRegIniFile;
|
|
|
|
procedure GetCustomColors;
|
|
begin
|
|
IniFile := TRegIniFile.Create('\Software\Borland\Delphi\7.0');
|
|
try
|
|
IniFile.ReadSectionValues(SCustomColors,
|
|
ColorDialog.CustomColors);
|
|
except
|
|
{ Ignore errors reading values }
|
|
end;
|
|
end;
|
|
|
|
procedure SaveCustomColors;
|
|
var
|
|
I, P: Integer;
|
|
S: string;
|
|
begin
|
|
if IniFile <> nil then
|
|
with ColorDialog do
|
|
for I := 0 to CustomColors.Count - 1 do
|
|
begin
|
|
S := CustomColors.Strings[I];
|
|
P := Pos('=', S);
|
|
if P <> 0 then
|
|
begin
|
|
S := Copy(S, 1, P - 1);
|
|
IniFile.WriteString(SCustomColors, S,
|
|
CustomColors.Values[S]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
IniFile := nil;
|
|
ColorDialog := TColorDialog.Create(Application);
|
|
with ColorDialog do
|
|
try
|
|
GetCustomColors;
|
|
Color := GetOrdValue;
|
|
if Execute then
|
|
begin
|
|
SetOrdValue(Color);
|
|
PostChangedNotification;
|
|
end;
|
|
SaveCustomColors;
|
|
finally
|
|
if IniFile <> nil then IniFile.Free;
|
|
Free;
|
|
end;
|
|
end;
|
|
|
|
function TcxColorProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaDialog];
|
|
end;
|
|
|
|
function TcxColorProperty.GetValue: string;
|
|
begin
|
|
Result := IntToStr(GetOrdValue);
|
|
end;
|
|
|
|
procedure TcxColorProperty.GetValues(Proc: TGetStrProc);
|
|
begin
|
|
end;
|
|
|
|
{ TcxCursorProperty }
|
|
|
|
function TcxCursorProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaValueList, ipaSortList, ipaRevertable];
|
|
end;
|
|
|
|
function TcxCursorProperty.GetValue: string;
|
|
begin
|
|
Result := CursorToString(TCursor(GetOrdValue));
|
|
end;
|
|
|
|
procedure TcxCursorProperty.GetValues(Proc: TGetStrProc);
|
|
begin
|
|
GetCursorValues(Proc);
|
|
end;
|
|
|
|
procedure TcxCursorProperty.SetValue(const Value: string);
|
|
var
|
|
NewValue: Longint;
|
|
begin
|
|
if IdentToCursor(Value, NewValue) then
|
|
SetOrdValue(NewValue)
|
|
else
|
|
inherited SetValue(Value);
|
|
end;
|
|
|
|
{ TcxFontProperty }
|
|
|
|
procedure TcxFontProperty.Edit;
|
|
var
|
|
FontDialog: TFontDialog;
|
|
begin
|
|
FontDialog := TFontDialog.Create(Application);
|
|
try
|
|
FontDialog.Font := TFont(GetOrdValue);
|
|
FontDialog.Options := FontDialog.Options + [fdForceFontExist];
|
|
if FontDialog.Execute then
|
|
begin
|
|
SetOrdValue(Longint(FontDialog.Font));
|
|
PostChangedNotification;
|
|
end;
|
|
finally
|
|
FontDialog.Free;
|
|
end;
|
|
end;
|
|
|
|
function TcxFontProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaSubProperties, ipaDialog, ipaReadOnly];
|
|
end;
|
|
|
|
{TcxStringsProperty}
|
|
|
|
procedure TcxStringsProperty.Edit;
|
|
var
|
|
Data: TcxStringsEditorDlgData;
|
|
begin
|
|
if Inspector <> nil then
|
|
Data.LookAndFeel := TcxCustomRTTIInspector(Inspector).LookAndFeel
|
|
else
|
|
Data.LookAndFeel := nil;
|
|
Data.Caption := GetComponent(0).GetNamePath + '.' + GetName;
|
|
Data.Text := TStrings(GetOrdValue).Text;
|
|
if cxShowStringsEditor(@Data) then
|
|
begin
|
|
TStrings(GetOrdValue).Text := Data.Text;
|
|
PostChangedNotification;
|
|
end;
|
|
end;
|
|
|
|
function TcxStringsProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaDialog, ipaReadOnly];
|
|
end;
|
|
|
|
{ TcxGraphicProperty }
|
|
|
|
procedure TcxGraphicProperty.Edit;
|
|
var
|
|
Data: TcxPictureEditorDlgData;
|
|
P: TPicture;
|
|
begin
|
|
P := TPicture.Create;
|
|
try
|
|
P.Assign(GetGraphic);
|
|
with Data do
|
|
begin
|
|
if Inspector <> nil then
|
|
LookAndFeel := TcxCustomRTTIInspector(Inspector).LookAndFeel
|
|
else
|
|
LookAndFeel := nil;
|
|
Caption := GetComponent(0).GetNamePath + '.' + GetName;
|
|
ClipboardFormat := GetClipboardFormat;
|
|
GraphicFilter := GetGraphicFilter;
|
|
Picture := P;
|
|
end;
|
|
if cxShowPictureEditor(@Data) then
|
|
begin
|
|
SetGraphic(P.Graphic);
|
|
PostChangedNotification;
|
|
end;
|
|
finally
|
|
P.Free;
|
|
end;
|
|
end;
|
|
|
|
function TcxGraphicProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaDialog];
|
|
end;
|
|
|
|
function TcxGraphicProperty.HasGraphic: Boolean;
|
|
begin
|
|
Result := (GetGraphic <> nil) and not GetGraphic.Empty;
|
|
end;
|
|
|
|
function TcxGraphicProperty.GraphicClass: TGraphicClass;
|
|
begin
|
|
if GetGraphic = nil then
|
|
Result := nil
|
|
else
|
|
Result := TGraphicClass(GetGraphic.ClassType);
|
|
end;
|
|
|
|
function TcxGraphicProperty.GetGraphicFilter: string;
|
|
begin
|
|
Result := GraphicFilter(TGraphic)
|
|
end;
|
|
|
|
function TcxGraphicProperty.GetClipboardFormat: Word;
|
|
begin
|
|
Result := CF_PICTURE;
|
|
if GraphicClass <> nil then
|
|
if GraphicClass.InheritsFrom(TBitmap) then
|
|
Result := CF_BITMAP
|
|
else
|
|
if GraphicClass.InheritsFrom(TMetafile) then
|
|
Result := CF_METAFILEPICT;
|
|
end;
|
|
|
|
function TcxGraphicProperty.GetGraphic: TGraphic;
|
|
begin
|
|
Result := TGraphic(GetOrdValue);
|
|
end;
|
|
|
|
procedure TcxGraphicProperty.SetGraphic(Value: TGraphic);
|
|
begin
|
|
GetGraphic.Assign(Value);
|
|
end;
|
|
|
|
function TcxGraphicProperty.GetValue: string;
|
|
begin
|
|
if HasGraphic then
|
|
Result := '(' + GetGraphic.ClassName + ')'
|
|
else
|
|
Result := '(None)';
|
|
end;
|
|
|
|
procedure TcxGraphicProperty.SetValue(const Value: string);
|
|
begin
|
|
if Value = '' then SetGraphic(nil);
|
|
end;
|
|
|
|
{TcxPictureProperty}
|
|
|
|
function TcxPictureProperty.GetGraphic: TGraphic;
|
|
begin
|
|
if GetOrdValue = 0 then
|
|
Result := nil
|
|
else
|
|
Result := TPicture(GetOrdValue).Graphic;
|
|
end;
|
|
|
|
procedure TcxPictureProperty.SetGraphic(Value: TGraphic);
|
|
begin
|
|
TPicture(GetOrdValue).Assign(Value);
|
|
end;
|
|
|
|
{ TcxModalResultProperty }
|
|
|
|
const
|
|
dxModalResults: array[mrNone..mrYesToAll] of string = (
|
|
'mrNone',
|
|
'mrOk',
|
|
'mrCancel',
|
|
'mrAbort',
|
|
'mrRetry',
|
|
'mrIgnore',
|
|
'mrYes',
|
|
'mrNo',
|
|
'mrAll',
|
|
'mrNoToAll',
|
|
'mrYesToAll');
|
|
|
|
function TcxModalResultProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaValueList, ipaRevertable];
|
|
end;
|
|
|
|
function TcxModalResultProperty.GetValue: string;
|
|
var
|
|
CurValue: Longint;
|
|
begin
|
|
CurValue := GetOrdValue;
|
|
case CurValue of
|
|
Low(dxModalResults)..High(dxModalResults):
|
|
Result := dxModalResults[CurValue];
|
|
else
|
|
Result := IntToStr(CurValue);
|
|
end;
|
|
end;
|
|
|
|
procedure TcxModalResultProperty.GetValues(Proc: TGetStrProc);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := Low(dxModalResults) to High(dxModalResults) do
|
|
Proc(dxModalResults[I]);
|
|
end;
|
|
|
|
procedure TcxModalResultProperty.SetValue(const Value: string);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if Value = '' then
|
|
begin
|
|
SetOrdValue(0);
|
|
Exit;
|
|
end;
|
|
for I := Low(dxModalResults) to High(dxModalResults) do
|
|
if CompareText(dxModalResults[I], Value) = 0 then
|
|
begin
|
|
SetOrdValue(I);
|
|
Exit;
|
|
end;
|
|
inherited SetValue(Value);
|
|
end;
|
|
|
|
{ TcxShortCutProperty }
|
|
|
|
const
|
|
cxShortCuts: array[0..82] of TShortCut = (
|
|
scNone,
|
|
Byte('A') or scCtrl,
|
|
Byte('B') or scCtrl,
|
|
Byte('C') or scCtrl,
|
|
Byte('D') or scCtrl,
|
|
Byte('E') or scCtrl,
|
|
Byte('F') or scCtrl,
|
|
Byte('G') or scCtrl,
|
|
Byte('H') or scCtrl,
|
|
Byte('I') or scCtrl,
|
|
Byte('J') or scCtrl,
|
|
Byte('K') or scCtrl,
|
|
Byte('L') or scCtrl,
|
|
Byte('M') or scCtrl,
|
|
Byte('N') or scCtrl,
|
|
Byte('O') or scCtrl,
|
|
Byte('P') or scCtrl,
|
|
Byte('Q') or scCtrl,
|
|
Byte('R') or scCtrl,
|
|
Byte('S') or scCtrl,
|
|
Byte('T') or scCtrl,
|
|
Byte('U') or scCtrl,
|
|
Byte('V') or scCtrl,
|
|
Byte('W') or scCtrl,
|
|
Byte('X') or scCtrl,
|
|
Byte('Y') or scCtrl,
|
|
Byte('Z') or scCtrl,
|
|
VK_F1,
|
|
VK_F2,
|
|
VK_F3,
|
|
VK_F4,
|
|
VK_F5,
|
|
VK_F6,
|
|
VK_F7,
|
|
VK_F8,
|
|
VK_F9,
|
|
VK_F10,
|
|
VK_F11,
|
|
VK_F12,
|
|
VK_F1 or scCtrl,
|
|
VK_F2 or scCtrl,
|
|
VK_F3 or scCtrl,
|
|
VK_F4 or scCtrl,
|
|
VK_F5 or scCtrl,
|
|
VK_F6 or scCtrl,
|
|
VK_F7 or scCtrl,
|
|
VK_F8 or scCtrl,
|
|
VK_F9 or scCtrl,
|
|
VK_F10 or scCtrl,
|
|
VK_F11 or scCtrl,
|
|
VK_F12 or scCtrl,
|
|
VK_F1 or scShift,
|
|
VK_F2 or scShift,
|
|
VK_F3 or scShift,
|
|
VK_F4 or scShift,
|
|
VK_F5 or scShift,
|
|
VK_F6 or scShift,
|
|
VK_F7 or scShift,
|
|
VK_F8 or scShift,
|
|
VK_F9 or scShift,
|
|
VK_F10 or scShift,
|
|
VK_F11 or scShift,
|
|
VK_F12 or scShift,
|
|
VK_F1 or scShift or scCtrl,
|
|
VK_F2 or scShift or scCtrl,
|
|
VK_F3 or scShift or scCtrl,
|
|
VK_F4 or scShift or scCtrl,
|
|
VK_F5 or scShift or scCtrl,
|
|
VK_F6 or scShift or scCtrl,
|
|
VK_F7 or scShift or scCtrl,
|
|
VK_F8 or scShift or scCtrl,
|
|
VK_F9 or scShift or scCtrl,
|
|
VK_F10 or scShift or scCtrl,
|
|
VK_F11 or scShift or scCtrl,
|
|
VK_F12 or scShift or scCtrl,
|
|
VK_INSERT,
|
|
VK_INSERT or scShift,
|
|
VK_INSERT or scCtrl,
|
|
VK_DELETE,
|
|
VK_DELETE or scShift,
|
|
VK_DELETE or scCtrl,
|
|
VK_BACK or scAlt,
|
|
VK_BACK or scShift or scAlt);
|
|
|
|
function TcxShortCutProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaValueList, ipaRevertable];
|
|
end;
|
|
|
|
function TcxShortCutProperty.GetValue: string;
|
|
var
|
|
CurValue: TShortCut;
|
|
begin
|
|
CurValue := GetOrdValue;
|
|
if CurValue = scNone then
|
|
Result := srNone
|
|
else
|
|
Result := ShortCutToText(CurValue);
|
|
end;
|
|
|
|
procedure TcxShortCutProperty.GetValues(Proc: TGetStrProc);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Proc(srNone);
|
|
for I := 1 to High(cxShortCuts) do
|
|
Proc(ShortCutToText(cxShortCuts[I]));
|
|
end;
|
|
|
|
procedure TcxShortCutProperty.SetValue(const Value: string);
|
|
var
|
|
NewValue: TShortCut;
|
|
begin
|
|
NewValue := 0;
|
|
if (Value <> '') and (AnsiCompareText(Value, srNone) <> 0) then
|
|
begin
|
|
NewValue := TextToShortCut(Value);
|
|
if NewValue = 0 then
|
|
raise EcxPropertyError.Create(SInvalidPropertyValue);
|
|
end;
|
|
SetOrdValue(NewValue);
|
|
end;
|
|
|
|
{ TcxTabOrderProperty }
|
|
|
|
function TcxTabOrderProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [];
|
|
end;
|
|
|
|
{ TcxCaptionProperty }
|
|
|
|
function TcxCaptionProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaAutoUpdate, ipaRevertable];
|
|
end;
|
|
|
|
{ TcxDateProperty }
|
|
|
|
function TcxDateProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaRevertable];
|
|
end;
|
|
|
|
function TcxDateProperty.GetValue: string;
|
|
var
|
|
DT: TDateTime;
|
|
begin
|
|
DT := GetFloatValue;
|
|
if DT = 0.0 then
|
|
Result := ''
|
|
else
|
|
Result := DateToStr(DT);
|
|
end;
|
|
|
|
procedure TcxDateProperty.SetValue(const Value: string);
|
|
var
|
|
DT: TDateTime;
|
|
begin
|
|
if Value = '' then
|
|
DT := 0.0
|
|
else
|
|
DT := StrToDate(Value);
|
|
SetFloatValue(DT);
|
|
end;
|
|
|
|
{ TcxTimeProperty }
|
|
|
|
function TcxTimeProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaRevertable];
|
|
end;
|
|
|
|
function TcxTimeProperty.GetValue: string;
|
|
var
|
|
DT: TDateTime;
|
|
begin
|
|
DT := GetFloatValue;
|
|
Result := TimeToStr(TimeOf(DT));
|
|
end;
|
|
|
|
procedure TcxTimeProperty.SetValue(const Value: string);
|
|
var
|
|
DT: TDateTime;
|
|
begin
|
|
if Value = '' then
|
|
DT := 0.0
|
|
else
|
|
DT := StrToTime(Value);
|
|
SetFloatValue(DT);
|
|
end;
|
|
|
|
{ TcxDateTimeProperty }
|
|
|
|
function TcxDateTimeProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaRevertable];
|
|
end;
|
|
|
|
function TcxDateTimeProperty.GetValue: string;
|
|
var
|
|
DT: TDateTime;
|
|
begin
|
|
DT := GetFloatValue;
|
|
if DT = 0.0 then
|
|
Result := ''
|
|
else
|
|
Result := DateTimeToStr(DT);
|
|
end;
|
|
|
|
procedure TcxDateTimeProperty.SetValue(const Value: string);
|
|
var
|
|
DT: TDateTime;
|
|
begin
|
|
if Value = '' then
|
|
DT := 0.0
|
|
else
|
|
DT := StrToDateTime(Value);
|
|
SetFloatValue(DT);
|
|
end;
|
|
|
|
{ TVariantTypeProperty }
|
|
|
|
{$IFNDEF DELPHI6}
|
|
const
|
|
varInt64 = $14;
|
|
{$ENDIF}
|
|
|
|
var
|
|
VarTypeNames: array[varEmpty..varInt64] of string = (
|
|
'Unassigned', // varEmpty
|
|
'Null', // varNull
|
|
'Smallint', // varSmallint
|
|
'Integer', // varInteger
|
|
'Single', // varSingle
|
|
'Double', // varDouble
|
|
'Currency', // varCurrency
|
|
'Date', // varDate
|
|
'OleStr', // varOleStr
|
|
'', // varDispatch
|
|
'', // varError
|
|
'Boolean', // varBoolean
|
|
'', // varVariant
|
|
'', // varUnknown
|
|
'', // [varDecimal]
|
|
'', // [undefined]
|
|
'Shortint', // varShortInt
|
|
'Byte', // varByte
|
|
'Word', // varWord
|
|
'LongWord', // varLongWord
|
|
'Int64'); // varInt64
|
|
|
|
type
|
|
TcxVariantTypeProperty = class(TcxPropertyEditor)
|
|
public
|
|
constructor Create(APropList: PcxInstPropList; APropCount: Integer);
|
|
destructor Destroy; override;
|
|
function AllEqual: Boolean; override;
|
|
function GetAttributes: TcxPropertyAttributes; override;
|
|
function GetName: string; override;
|
|
function GetValue: string; override;
|
|
procedure GetValues(Proc: TGetStrProc); override;
|
|
procedure SetValue(const Value: string); override;
|
|
end;
|
|
|
|
constructor TcxVariantTypeProperty.Create(APropList: PcxInstPropList;
|
|
APropCount: Integer);
|
|
begin
|
|
FPropList := APropList;
|
|
FPropCount := APropCount;
|
|
end;
|
|
|
|
destructor TcxVariantTypeProperty.Destroy;
|
|
begin
|
|
end;
|
|
|
|
function TcxVariantTypeProperty.AllEqual: Boolean;
|
|
var
|
|
i: Integer;
|
|
V1, V2: Variant;
|
|
begin
|
|
Result := False;
|
|
if PropCount > 1 then
|
|
begin
|
|
V1 := GetVarValue;
|
|
for i := 1 to PropCount - 1 do
|
|
begin
|
|
V2 := GetVarValueAt(i);
|
|
if VarType(V1) <> VarType(V2) then Exit;
|
|
end;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function TcxVariantTypeProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaValueList, ipaSortList];
|
|
end;
|
|
|
|
function TcxVariantTypeProperty.GetName: string;
|
|
begin
|
|
Result := 'Type';
|
|
end;
|
|
|
|
function TcxVariantTypeProperty.GetValue: string;
|
|
begin
|
|
if VarIsStr(GetVarValue) then
|
|
Result := cxSString
|
|
else
|
|
case VarType(GetVarValue) and varTypeMask of
|
|
Low(VarTypeNames)..High(VarTypeNames):
|
|
Result := VarTypeNames[VarType(GetVarValue)];
|
|
else
|
|
Result := cxGetResourceString(@cxSvgUnknown);
|
|
end;
|
|
end;
|
|
|
|
procedure TcxVariantTypeProperty.GetValues(Proc: TGetStrProc);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to High(VarTypeNames) do
|
|
if VarTypeNames[i] <> '' then
|
|
Proc(VarTypeNames[i]);
|
|
Proc(cxSString);
|
|
end;
|
|
|
|
procedure TcxVariantTypeProperty.SetValue(const Value: string);
|
|
|
|
function GetSelectedType: Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := -1;
|
|
for i := 0 to High(VarTypeNames) do
|
|
if VarTypeNames[i] = Value then
|
|
begin
|
|
Result := i;
|
|
break;
|
|
end;
|
|
if (Result = -1) and (Value = cxSString) then
|
|
Result := varString;
|
|
end;
|
|
|
|
var
|
|
NewType: Integer;
|
|
V: Variant;
|
|
begin
|
|
V := GetVarValue;
|
|
NewType := GetSelectedType;
|
|
case NewType of
|
|
varEmpty: VarClear(V);
|
|
varNull: V := NULL;
|
|
-1: raise EdxException.Create('UnknownType'); //todo resource
|
|
else
|
|
try
|
|
VarCast(V, V, NewType);
|
|
except
|
|
// If it cannot cast, clear it and then cast again.
|
|
VarClear(V);
|
|
VarCast(V, V, NewType);
|
|
end;
|
|
end;
|
|
SetVarValue(V);
|
|
end;
|
|
|
|
{ TcxVariantProperty }
|
|
|
|
{$IFNDEF DELPHI6}
|
|
|
|
function VarToStrDef(const V: Variant; const ADefault: string): string;
|
|
begin
|
|
if not VarIsNull(V) then
|
|
Result := V
|
|
else
|
|
Result := ADefault;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function TcxVariantProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := [ipaMultiSelect, ipaSubProperties];
|
|
end;
|
|
|
|
procedure TcxVariantProperty.GetProperties(AOwner: TComponent;
|
|
Proc: TcxGetPropEditProc);
|
|
begin
|
|
Proc(TcxVariantTypeProperty.Create(FPropList, FPropCount));
|
|
end;
|
|
|
|
function TcxVariantProperty.GetValue: string;
|
|
|
|
function GetVariantStr(const Value: Variant): string;
|
|
begin
|
|
case VarType(Value) of
|
|
varBoolean:
|
|
Result := BooleanIdents[Value = True];
|
|
varCurrency:
|
|
Result := CurrToStr(Value);
|
|
else
|
|
Result := VarToStrDef(Value, cxSNull);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := GetVarValue;
|
|
if VarType(Value) <> varDispatch then
|
|
Result := GetVariantStr(Value)
|
|
else
|
|
Result := 'ERROR';
|
|
end;
|
|
|
|
procedure TcxVariantProperty.SetValue(const Value: string);
|
|
|
|
function Cast(var Value: Variant; NewType: Integer): Boolean;
|
|
var
|
|
V2: Variant;
|
|
begin
|
|
Result := True;
|
|
if NewType = varCurrency then
|
|
Result := AnsiPos(CurrencyString, Value) > 0;
|
|
if Result then
|
|
try
|
|
VarCast(V2, Value, NewType);
|
|
Result := (NewType = varDate) or (VarToStr(V2) = VarToStr(Value));
|
|
if Result then Value := V2;
|
|
except
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
V: Variant;
|
|
OldType: Integer;
|
|
begin
|
|
OldType := VarType(GetVarValue);
|
|
V := Value;
|
|
if Value = '' then
|
|
VarClear(V) else
|
|
if (CompareText(Value, cxSNull) = 0) then
|
|
V := NULL else
|
|
if not Cast(V, OldType) then
|
|
V := Value;
|
|
SetVarValue(V);
|
|
end;
|
|
|
|
{ TcxEditPropertiesProperty }
|
|
|
|
function TcxEditPropertiesProperty.HasSubProperties: Boolean;
|
|
var
|
|
I: Integer;
|
|
AIntf: IcxEditorPropertiesContainer;
|
|
begin
|
|
for I := 0 to PropCount - 1 do
|
|
begin
|
|
Result := Supports(GetComponent(I), IcxEditorPropertiesContainer, AIntf) and
|
|
(AIntf.GetProperties <> nil);
|
|
if not Result then Exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function TcxEditPropertiesProperty.GetAttributes: TcxPropertyAttributes;
|
|
begin
|
|
Result := inherited GetAttributes;
|
|
if not HasSubProperties then
|
|
Exclude(Result, ipaSubProperties);
|
|
Result := Result - [ipaReadOnly] + [ipaValueList, ipaSortList, ipaRevertable];
|
|
end;
|
|
|
|
function TcxEditPropertiesProperty.GetValue: string;
|
|
begin
|
|
if HasSubProperties then
|
|
Result := GetRegisteredEditProperties.GetDescriptionByClass(
|
|
TcxCustomEditProperties(GetOrdValue).ClassType)
|
|
else
|
|
Result := '';
|
|
end;
|
|
|
|
procedure TcxEditPropertiesProperty.GetValues(Proc: TGetStrProc);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to GetRegisteredEditProperties.Count - 1 do
|
|
Proc(GetRegisteredEditProperties.Descriptions[I]);
|
|
end;
|
|
|
|
procedure TcxEditPropertiesProperty.SetValue(const Value: string);
|
|
var
|
|
APropertiesClass: TcxCustomEditPropertiesClass;
|
|
I: Integer;
|
|
AIntf: IcxEditorPropertiesContainer;
|
|
begin
|
|
APropertiesClass := TcxCustomEditPropertiesClass(
|
|
GetRegisteredEditProperties.FindByClassName(Value));
|
|
if APropertiesClass = nil then
|
|
APropertiesClass := TcxCustomEditPropertiesClass(
|
|
GetRegisteredEditProperties.FindByDescription(Value));
|
|
for I := 0 to PropCount - 1 do
|
|
if Supports(GetComponent(I), IcxEditorPropertiesContainer, AIntf) then
|
|
AIntf.SetPropertiesClass(APropertiesClass);
|
|
inherited;
|
|
end;
|
|
|
|
{ TcxPropInfoList }
|
|
|
|
type
|
|
TcxPropInfoList = class
|
|
private
|
|
FList: PPropList;
|
|
FCount: Integer;
|
|
FSize: Integer;
|
|
function Get(Index: Integer): PPropInfo;
|
|
public
|
|
constructor Create(Instance: TPersistent; Filter: TTypeKinds);
|
|
destructor Destroy; override;
|
|
|
|
function Contains(P: PPropInfo): Boolean;
|
|
procedure Delete(Index: Integer);
|
|
procedure Intersect(List: TcxPropInfoList);
|
|
|
|
property Count: Integer read FCount;
|
|
property Items[Index: Integer]: PPropInfo read Get; default;
|
|
end;
|
|
|
|
constructor TcxPropInfoList.Create(Instance: TPersistent; Filter: TTypeKinds);
|
|
begin
|
|
if Instance.ClassInfo <> nil then
|
|
begin
|
|
FCount := GetPropList(Instance.ClassInfo, Filter, nil);
|
|
FSize := FCount * SizeOf(Pointer);
|
|
GetMem(FList, FSize);
|
|
GetPropList(Instance.ClassInfo, Filter, FList);
|
|
end;
|
|
end;
|
|
|
|
destructor TcxPropInfoList.Destroy;
|
|
begin
|
|
if FList <> nil then FreeMem(FList, FSize);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TcxPropInfoList.Contains(P: PPropInfo): Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to FCount - 1 do
|
|
with FList^[I]^ do
|
|
if (PropType^ = P^.PropType^) and
|
|
(CompareText(dxShortStringToString(Name), dxShortStringToString(P^.Name)) = 0) then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TcxPropInfoList.Delete(Index: Integer);
|
|
begin
|
|
Dec(FCount);
|
|
if Index < FCount then
|
|
Move(FList^[Index + 1], FList^[Index], (FCount - Index) * SizeOf(Pointer));
|
|
end;
|
|
|
|
function TcxPropInfoList.Get(Index: Integer): PPropInfo;
|
|
begin
|
|
Result := FList^[Index];
|
|
end;
|
|
|
|
procedure TcxPropInfoList.Intersect(List: TcxPropInfoList);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := FCount - 1 downto 0 do
|
|
if not List.Contains(FList^[I]) then Delete(I);
|
|
end;
|
|
|
|
{ GetComponentProperties }
|
|
|
|
procedure cxRegisterPropertyEditor(APropertyType: PTypeInfo; AComponentClass: TClass;
|
|
const APropertyName: string; AEditorClass: TcxPropertyEditorClass);
|
|
var
|
|
Item: TcxPropertyClassRec;
|
|
begin
|
|
if FPropertyClasses = nil then FPropertyClasses := TList.Create;
|
|
Item := TcxPropertyClassRec.Create;
|
|
with Item do
|
|
begin
|
|
Group := CurrentGroup;
|
|
PropertyType := APropertyType;
|
|
ComponentClass := AComponentClass;
|
|
PropertyName := '';
|
|
if ComponentClass <> nil then PropertyName := APropertyName;
|
|
EditorClass := AEditorClass;
|
|
end;
|
|
FPropertyClasses.Insert(0, Item);
|
|
end;
|
|
|
|
procedure cxRegisterPropertyMapper(AMapper: TcxPropertyMapperFunc);
|
|
var
|
|
Item: TcxPropertyMapperRec;
|
|
begin
|
|
if FPropertyMappers = nil then
|
|
FPropertyMappers := TList.Create;
|
|
Item := TcxPropertyMapperRec.Create;
|
|
Item.Group := CurrentGroup;
|
|
Item.Mapper := AMapper;
|
|
FPropertyMappers.Insert(0, Item);
|
|
end;
|
|
|
|
function cxGetEditorClass(APropInfo: PPropInfo; Obj: TPersistent): TcxPropertyEditorClass;
|
|
var
|
|
PropType: PTypeInfo;
|
|
P, C: TcxPropertyClassRec;
|
|
I: Integer;
|
|
begin
|
|
if FPropertyMappers <> nil then
|
|
for I := 0 to FPropertyMappers.Count - 1 do
|
|
with TcxPropertyMapperRec(FPropertyMappers[I]) do
|
|
begin
|
|
Result := Mapper(Obj, APropInfo);
|
|
if Result <> nil then Exit;
|
|
end;
|
|
|
|
PropType := APropInfo^.PropType^;
|
|
I := 0;
|
|
C := nil;
|
|
|
|
if FPropertyClasses <> nil then
|
|
while I < FPropertyClasses.Count do
|
|
begin
|
|
P := FPropertyClasses[I];
|
|
if ((P.PropertyType = PropType) or ((PropType^.Kind = tkClass) and
|
|
(P.PropertyType^.Kind = tkClass) and
|
|
GetTypeData(PropType)^.ClassType.InheritsFrom(GetTypeData(P.PropertyType)^.ClassType))) and
|
|
((P.ComponentClass = nil) or (Obj.InheritsFrom(P.ComponentClass))) and
|
|
((P.PropertyName = '') or (CompareText(dxShortStringToString(APropInfo^.Name), P.PropertyName) = 0)) then
|
|
if (C = nil) or ((C.ComponentClass = nil) and (P.ComponentClass <> nil))
|
|
or ((C.PropertyName = '') and (P.PropertyName <> '')) then
|
|
C := P;
|
|
Inc(I);
|
|
end;
|
|
|
|
if C <> nil then
|
|
Result := C.EditorClass
|
|
else
|
|
Result := cxPropClassMap[PropType^.Kind];
|
|
end;
|
|
|
|
procedure cxGetComponentProperties(AOwner: TComponent;
|
|
AInspector: TcxCustomRTTIInspector; AComponents: TcxComponentList;
|
|
AFilter: TTypeKinds; AProc: TcxGetPropEditProc);
|
|
var
|
|
I, J, CompCount: Integer;
|
|
CompType: TClass;
|
|
Candidates: TcxPropInfoList;
|
|
PropLists: TList;
|
|
Editor: TcxPropertyEditor;
|
|
EdClass: TcxPropertyEditorClass;
|
|
PropInfo: PPropInfo;
|
|
AddEditor: Boolean;
|
|
Obj: TPersistent;
|
|
begin
|
|
if (AComponents = nil) or (AComponents.Count = 0) then Exit;
|
|
CompCount := AComponents.Count;
|
|
Obj := AComponents[0];
|
|
CompType := AComponents[0].ClassType;
|
|
Candidates := TcxPropInfoList.Create(AComponents[0], AFilter);
|
|
try
|
|
for I := Candidates.Count - 1 downto 0 do
|
|
begin
|
|
PropInfo := Candidates[I];
|
|
EdClass := cxGetEditorClass(PropInfo, Obj);
|
|
if EdClass = nil then
|
|
Candidates.Delete(I)
|
|
else
|
|
begin
|
|
Editor := EdClass.Create(AOwner, AInspector, 1);
|
|
try
|
|
Editor.SetPropEntry(0, Obj, PropInfo);
|
|
with PropInfo^ do
|
|
if (GetProc = nil) or
|
|
((PropType^.Kind <> tkClass) and (SetProc = nil)) or
|
|
((CompCount > 1) and
|
|
not (ipaMultiSelect in Editor.GetAttributes)) or
|
|
not Editor.ValueAvailable then
|
|
Candidates.Delete(I);
|
|
finally
|
|
Editor.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
PropLists := TList.Create;
|
|
try
|
|
PropLists.Capacity := CompCount;
|
|
for I := 0 to CompCount - 1 do
|
|
PropLists.Add(TcxPropInfoList.Create(AComponents[I], AFilter));
|
|
for I := 0 to CompCount - 1 do
|
|
Candidates.Intersect(TcxPropInfoList(PropLists[I]));
|
|
for I := 0 to CompCount - 1 do
|
|
TcxPropInfoList(PropLists[I]).Intersect(Candidates);
|
|
for I := 0 to Candidates.Count - 1 do
|
|
begin
|
|
EdClass := cxGetEditorClass(Candidates[I], Obj);
|
|
if EdClass = nil then Continue;
|
|
Editor := EdClass.Create(AOwner, AInspector, CompCount);
|
|
try
|
|
AddEditor := True;
|
|
for J := 0 to CompCount - 1 do
|
|
begin
|
|
if (AComponents[J].ClassType <> CompType) and
|
|
(cxGetEditorClass(TcxPropInfoList(PropLists[J])[I],
|
|
AComponents[J]) <> EdClass) then
|
|
begin
|
|
AddEditor := False;
|
|
Break;
|
|
end;
|
|
Editor.SetPropEntry(J, AComponents[J], TcxPropInfoList(PropLists[J])[I]);
|
|
end;
|
|
except
|
|
Editor.Free;
|
|
raise;
|
|
end;
|
|
if AddEditor and Editor.ValueAvailable and Assigned(AProc) then
|
|
AProc(Editor)
|
|
else
|
|
Editor.Free;
|
|
end;
|
|
finally
|
|
for I := 0 to PropLists.Count - 1 do TcxPropInfoList(PropLists[I]).Free;
|
|
PropLists.Free;
|
|
end;
|
|
finally
|
|
Candidates.Free;
|
|
end;
|
|
end;
|
|
|
|
{ TcxRTTIInspectorEditingController }
|
|
|
|
procedure TcxRTTIInspectorEditingController.HideEdit(Accept: Boolean);
|
|
|
|
procedure RemoveEditing;
|
|
begin
|
|
EditingItem := nil;
|
|
HideInplaceEditor;
|
|
end;
|
|
|
|
var
|
|
AEditViewInfo: TcxEditCellViewInfo;
|
|
AItem: TcxCustomInplaceEditContainer;
|
|
ASaveIndex: Integer;
|
|
begin
|
|
if FDeactivating then Exit;
|
|
Controller.CancelCheckEditPost;
|
|
CancelEditUpdatePost;
|
|
StopEditShowingTimer;
|
|
if EditHiding or not IsEditing then Exit;
|
|
EditHiding := True;
|
|
try
|
|
if Accept then
|
|
begin
|
|
FDeactivating := True;
|
|
if Inspector.FocusedRow <> nil then
|
|
ASaveIndex := Inspector.FocusedRow.AbsoluteIndex
|
|
else
|
|
ASaveIndex := -1;
|
|
try
|
|
try
|
|
if not Edit.Deactivate then raise EAbort.Create('');
|
|
Controller.DataController.PostEditingData;
|
|
except
|
|
RemoveEditing;
|
|
with Inspector do
|
|
if CanFocusEx then SetFocus;
|
|
raise;
|
|
end;
|
|
finally
|
|
with Inspector do
|
|
if Reloaded then
|
|
begin
|
|
RemoveEditing;
|
|
if (ASaveIndex >= 0) and (ASaveIndex < Rows.Count) then
|
|
begin
|
|
Controller.InternalSetRowAndCell(TcxPropertyRow(Rows[ASaveIndex]), 0);
|
|
Controller.InternalSetFocusedItem(TcxPropertyRow(Rows[ASaveIndex]).EditContainer)
|
|
end
|
|
else
|
|
begin
|
|
Controller.InternalSetRowAndCell(nil, 0);
|
|
Controller.InternalSetFocusedItem(nil);
|
|
end;
|
|
Controller.RefreshFocusedRow;
|
|
Controller.FNeedCorrect := True;
|
|
end;
|
|
FDeactivating := False;
|
|
end;
|
|
IsErrorOnEditExit := False;
|
|
if EditingItem = nil then Exit;
|
|
AEditViewInfo := Controller.GetFocusedCellViewInfo(EditingItem);
|
|
if AEditViewInfo <> nil then
|
|
Edit.ActiveProperties.Update(
|
|
TcxEditCellViewInfoAccess(AEditViewInfo).Properties);
|
|
end;
|
|
AItem := EditingItem;
|
|
TcxCustomRTTIInspector(EditingControl).DoEdited(AItem);
|
|
EditingItem := nil;
|
|
Controller.RefreshFocusedCellViewInfo(AItem);
|
|
HideInplaceEditor;
|
|
IsErrorOnEditExit := False;
|
|
finally
|
|
EditHiding := False;
|
|
end;
|
|
end;
|
|
|
|
function TcxRTTIInspectorEditingController.GetController: TcxRTTIInspectorController;
|
|
begin
|
|
Result := TcxRTTIInspectorController(inherited Controller);
|
|
end;
|
|
|
|
function TcxRTTIInspectorEditingController.GetInspector: TcxCustomRTTIInspector;
|
|
begin
|
|
Result := TcxCustomRTTIInspector(EditingControl);
|
|
end;
|
|
|
|
{ TcxRTTIInspectorController }
|
|
|
|
procedure TcxRTTIInspectorController.SetFocusedRecordItem(
|
|
ARecordIndex: Integer; AItem: TcxCustomInplaceEditContainer);
|
|
var
|
|
AIndex: Integer;
|
|
begin
|
|
AIndex := GetRowIndexFromCellEdit(AItem);
|
|
EditingController.HideEdit(True);
|
|
if FNeedCorrect then
|
|
begin
|
|
if (AIndex >= 0) and (AIndex < Inspector.Rows.Count) and
|
|
(Inspector.Rows[AIndex] is TcxPropertyRow) then
|
|
AItem := TcxPropertyRow(Inspector.Rows[AIndex]).EditContainer
|
|
else
|
|
AItem := nil;
|
|
FNeedCorrect := False;
|
|
end;
|
|
AllowCheckEdit := False;
|
|
try
|
|
DisableCellsRefresh := (FocusedRecordIndex = ARecordIndex);
|
|
FocusedRecordIndex := ARecordIndex;
|
|
DisableCellsRefresh := DisableCellsRefresh and (FocusedItem = AItem);
|
|
FocusedItem := AItem;
|
|
finally
|
|
AllowCheckEdit := True;
|
|
CheckEdit;
|
|
DisableCellsRefresh := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxRTTIInspectorController.BeforeEditKeyDown(var Key: Word;
|
|
var Shift: TShiftState);
|
|
begin
|
|
if (Key = VK_RETURN) and (ssCtrl in Shift) then
|
|
begin
|
|
Key := 0;
|
|
Inspector.TryInvokePropertyEditorDlg;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxRTTIInspectorController.DoEditDblClick(Sender: TObject);
|
|
begin
|
|
with Inspector do
|
|
if (PropertyEditor <> nil) and not (ipaRevertable in PropertyEditor.GetAttributes) then
|
|
TryInvokePropertyEditorDlg;
|
|
end;
|
|
|
|
procedure TcxRTTIInspectorController.DoUpdateRowAndCell(ANewRow: TcxCustomRow;
|
|
ANewCellIndex: Integer);
|
|
begin
|
|
if Inspector.LockRefresh then Exit;
|
|
inherited DoUpdateRowAndCell(ANewRow, ANewCellIndex);
|
|
end;
|
|
|
|
procedure TcxRTTIInspectorController.FocusChanged;
|
|
begin
|
|
if FFocusChanging or Inspector.LockRefresh then Exit;
|
|
FFocusChanging := True;
|
|
try
|
|
inherited FocusChanged;
|
|
finally
|
|
FFocusChanging := False;
|
|
end;
|
|
end;
|
|
|
|
function TcxRTTIInspectorController.IsKeyForController(AKey: Word;
|
|
AShift: TShiftState): Boolean;
|
|
begin
|
|
Result := inherited IsKeyForController(AKey, AShift) or
|
|
((AKey = VK_RETURN) and (ssCtrl in AShift));
|
|
end;
|
|
|
|
procedure TcxRTTIInspectorController.SetFocusedItem(
|
|
Value: TcxCustomInplaceEditContainer);
|
|
var
|
|
AIndex: Integer;
|
|
begin
|
|
if Inspector.LockRefresh then Exit;
|
|
try
|
|
AIndex := GetRowIndexFromCellEdit(Value);
|
|
if IsEditing then EditingController.HideEdit(True);
|
|
if FNeedCorrect then
|
|
begin
|
|
if (AIndex >= 0) and (AIndex < Inspector.Rows.Count) and
|
|
(Inspector.Rows[AIndex] is TcxPropertyRow) then
|
|
Value := TcxPropertyRow(Inspector.Rows[AIndex]).EditContainer
|
|
else
|
|
Value := nil;
|
|
FNeedCorrect := False;
|
|
end;
|
|
inherited SetFocusedItem(Value);
|
|
finally
|
|
Inspector.FReloaded := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxRTTIInspectorController.SetFocusedRowAndCell(Value: TcxCustomRow;
|
|
ACellIndex: Integer);
|
|
var
|
|
AEditContainer: TcxCustomInplaceEditContainer;
|
|
begin
|
|
if EditingController.Deactivating or Inspector.IsDesigning or
|
|
Assigned(Value) and not TcxCustomRowAccess(Value).CanFocus then Exit;
|
|
FLockUpdate := True;
|
|
try
|
|
if (Value <> nil) and (Value is TcxPropertyRow) then
|
|
AEditContainer := TcxPropertyRow(Value).GetEditContainer(ACellIndex)
|
|
else
|
|
AEditContainer := nil;
|
|
FNeedCorrect := False;
|
|
if FocusedItem <> AEditContainer then
|
|
FocusedItem := AEditContainer;
|
|
if FocusedItem <> nil then
|
|
Value := TcxCellEdit(FocusedItem).Row
|
|
else
|
|
Value := nil;
|
|
finally
|
|
FLockUpdate := False;
|
|
AllowCheckEdit := True;
|
|
end;
|
|
inherited DoUpdateRowAndCell(Value, ACellIndex);
|
|
end;
|
|
|
|
function TcxRTTIInspectorController.GetEditingController: TcxRTTIInspectorEditingController;
|
|
begin
|
|
Result := TcxRTTIInspectorEditingController(inherited EditingController);
|
|
end;
|
|
|
|
function TcxRTTIInspectorController.GetFocusedRowIndex: Integer;
|
|
begin
|
|
if FocusedRow = nil then
|
|
Result := -1
|
|
else
|
|
Result := FocusedRow.AbsoluteIndex;
|
|
end;
|
|
|
|
function TcxRTTIInspectorController.GetInspector: TcxCustomRTTIInspector;
|
|
begin
|
|
Result := TcxCustomRTTIInspector(EditingControl);
|
|
end;
|
|
|
|
function TcxRTTIInspectorController.GetRowIndexFromCellEdit(
|
|
Value: TcxCustomInplaceEditContainer): Integer;
|
|
begin
|
|
if Value <> nil then
|
|
Result := TcxCellEdit(Value).Row.AbsoluteIndex
|
|
else
|
|
Result := -1;
|
|
end;
|
|
|
|
procedure TcxRTTIInspectorController.SetFocusedRowIndex(AIndex: Integer);
|
|
var
|
|
ARow: TcxCustomRow;
|
|
AItem: TcxCustomInplaceEditContainer;
|
|
begin
|
|
AItem := nil;
|
|
if (AIndex >= 0) and (AIndex < Inspector.Rows.Count) then
|
|
begin
|
|
ARow := Inspector.Rows[AIndex];
|
|
if ARow is TcxPropertyRow then
|
|
AItem := TcxPropertyRow(ARow).EditContainer;
|
|
end
|
|
else
|
|
ARow := nil;
|
|
InternalSetRowAndCell(ARow, 0);
|
|
InternalSetFocusedItem(AItem);
|
|
end;
|
|
|
|
{ TcxRTTIInspectorOptionsView }
|
|
|
|
constructor TcxRTTIInspectorOptionsView.Create(AOwner: TPersistent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
PaintStyle := psDelphi;
|
|
ShowEditButtons := ecsbFocused;
|
|
end;
|
|
|
|
{ TcxRTTIInspectorOptionsBehavior }
|
|
|
|
constructor TcxRTTIInspectorOptionsBehavior.Create(AOwner: TPersistent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
AlwaysShowEditor := True;
|
|
end;
|
|
|
|
{ TcxCustomRTTIInspector }
|
|
|
|
constructor TcxCustomRTTIInspector.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
OptionsBehavior.CellHints := True;
|
|
OptionsBehavior.AlwaysShowEditor := True;
|
|
FBoldFont := TFont.Create;
|
|
FBoldFont.Assign(Font);
|
|
FBoldFont.Style := FBoldFont.Style + [fsBold];
|
|
end;
|
|
|
|
destructor TcxCustomRTTIInspector.Destroy;
|
|
begin
|
|
if FListeners <> nil then
|
|
begin
|
|
CloseNonModalEditors;
|
|
FListeners.Free;
|
|
end;
|
|
ReleaseComponentProperties;
|
|
FBoldFont.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.AddListener(AListener: TPersistent);
|
|
begin
|
|
if FListeners = nil then FListeners := TList.Create;
|
|
if (AListener <> nil) and (FListeners.IndexOf(AListener) < 0) then
|
|
FListeners.Add(AListener)
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.CloseNonModalEditors;
|
|
var
|
|
I: Integer;
|
|
AIntf: IcxRTTIInspectorHelper;
|
|
begin
|
|
if FListeners <> nil then
|
|
for I := 0 to FListeners.Count - 1 do
|
|
if Supports(TObject(FListeners[I]), IcxRTTIInspectorHelper, AIntf) then
|
|
begin
|
|
AIntf.CloseNonModal(Self);
|
|
AIntf := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.RefreshInspectedProperties;
|
|
|
|
function GetFullName(ARow: TcxCustomRow): string;
|
|
begin
|
|
Result := '';
|
|
repeat
|
|
if ARow is TcxPropertyRow then
|
|
Result := UpperCase(TcxPropertyRow(ARow).Properties.Caption) + ' ' + Result;
|
|
ARow := ARow.Parent;
|
|
until ARow = nil;
|
|
end;
|
|
|
|
var
|
|
ALayout: TStringList;
|
|
AIndex, I, J: Integer;
|
|
AObject: TPersistent;
|
|
ARow: TcxCustomRow;
|
|
AFullName: string;
|
|
begin
|
|
BeginUpdate;
|
|
FLockRefresh := True;
|
|
try
|
|
FSaveTopRowIndex := TopVisibleRowIndex;
|
|
ALayout := TStringList.Create;
|
|
try
|
|
for I := 0 to Rows.Count - 1 do
|
|
begin
|
|
ARow := Rows[I];
|
|
if ARow.Expanded then
|
|
ALayout.Add(GetFullName(ARow));
|
|
end;
|
|
AObject := InspectedObject;
|
|
AIndex := Controller.GetFocusedRowIndex;
|
|
InspectedObject := nil;
|
|
InspectedObject := AObject;
|
|
if ALayout.Count > 0 then
|
|
for I := 0 to Rows.Count - 1 do
|
|
begin
|
|
ARow := Rows[I];
|
|
AFullName := GetFullName(ARow);
|
|
for J := 0 to ALayout.Count - 1 do
|
|
if ALayout[J] = AFullName then
|
|
ARow.Expanded := True;
|
|
end;
|
|
TopVisibleRowIndex := FSaveTopRowIndex;
|
|
FLockRefresh := False;
|
|
if not Controller.EditingController.FDeactivating then
|
|
Controller.SetFocusedRowIndex(AIndex);
|
|
finally
|
|
ALayout.Free;
|
|
end;
|
|
finally
|
|
EndUpdate;
|
|
FReloaded := True;
|
|
FLockRefresh := False;
|
|
if not Controller.EditingController.FDeactivating then
|
|
Controller.CheckEdit
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.RemoveListener(AListener: TPersistent);
|
|
begin
|
|
if (FListeners <> nil) and (FListeners.IndexOf(AListener) >= 0) then
|
|
FListeners.Remove(AListener);
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.Notification(AComponent: TComponent; AOperation: TOperation);
|
|
begin
|
|
inherited Notification(AComponent, AOperation);
|
|
if (AOperation = opRemove) and (AComponent = InspectedObject) then
|
|
InspectedObject := nil;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.DataChanged;
|
|
begin
|
|
end;
|
|
|
|
function TcxCustomRTTIInspector.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
|
|
MousePos: TPoint): Boolean;
|
|
var
|
|
ARow: TcxCustomRow;
|
|
begin
|
|
if ([ssShift] = Shift) and not IsScrollingContent then
|
|
begin
|
|
if WheelDelta > 0 then
|
|
ARow := PrevVisibleRow(FocusedRow)
|
|
else
|
|
ARow := NextVisibleRow(FocusedRow);
|
|
if ARow <> nil then FocusedRow := ARow;
|
|
Result := ARow <> nil;
|
|
end
|
|
else
|
|
Result := inherited DoMouseWheel(Shift, WheelDelta, MousePos);
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.FontChanged;
|
|
begin
|
|
FBoldFont.Assign(Font);
|
|
FBoldFont.Style := FBoldFont.Style + [fsBold];
|
|
inherited FontChanged;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.Loaded;
|
|
begin
|
|
inherited Loaded;
|
|
if not IsDesigning and Assigned(InspectedObject) then
|
|
begin
|
|
HandleNeeded;
|
|
CreatePropertyRows(nil);
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomRTTIInspector.FilterProperty(const APropertyName: string): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnFilterProperty) then FOnFilterProperty(Self, APropertyName, Result);
|
|
end;
|
|
|
|
function TcxCustomRTTIInspector.FilterPropertyEx(const AFullPropertyName: string): Boolean;
|
|
begin
|
|
Result := True;
|
|
if Assigned(FOnFilterPropertyEx) then FOnFilterPropertyEx(Self, AFullPropertyName, Result);
|
|
end;
|
|
|
|
function TcxCustomRTTIInspector.FindRowByPropertyName(const APropertyName: string): TcxPropertyRow;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if APropertyName <> '' then
|
|
for I := 0 to Rows.Count - 1 do
|
|
if Rows[I] is TcxPropertyRow then
|
|
begin
|
|
Result := TcxPropertyRow(Rows[I]);
|
|
if CompareText(APropertyName, Result.PropertyEditor.GetName) = 0 then
|
|
Exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.FocusRowByPropertyName(const APropertyName: string);
|
|
var
|
|
ARow: TcxCustomRow;
|
|
begin
|
|
ARow := FindRowByPropertyName(APropertyName);
|
|
if ARow = nil then ARow := FirstVisibleRow;
|
|
FocusedRow := ARow;
|
|
end;
|
|
|
|
function TcxCustomRTTIInspector.GetEditPropertiesClass(APropertyEditor: TcxPropertyEditor): TcxCustomEditPropertiesClass;
|
|
var
|
|
AFullPropertyName: string;
|
|
ARow: TcxPropertyRow;
|
|
begin
|
|
AFullPropertyName := APropertyEditor.GetName;
|
|
ARow := TcxPropertyRow(FParentRow);
|
|
while ARow <> nil do
|
|
begin
|
|
if ARow.PropertyEditor <> nil then
|
|
begin
|
|
if AFullPropertyName <> '' then
|
|
AFullPropertyName := '.' + AFullPropertyName;
|
|
AFullPropertyName := ARow.PropertyEditor.GetName + AFullPropertyName;
|
|
end;
|
|
ARow := TcxPropertyRow(ARow.Parent);
|
|
end;
|
|
if FilterProperty(APropertyEditor.GetName) and FilterPropertyEx(AFullPropertyName) then
|
|
begin
|
|
Result := cxGetPropertiesClassByEditor(APropertyEditor);
|
|
if Result = TcxColorComboBoxProperties then Exit;
|
|
if ipaDialog in APropertyEditor.GetAttributes then
|
|
Result := TcxButtonEditProperties;
|
|
if ipaValueList in APropertyEditor.GetAttributes then
|
|
Result := TcxComboBoxProperties;
|
|
if Result = nil then
|
|
Result := TcxTextEditProperties
|
|
end
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.PostChangedNotification;
|
|
begin
|
|
PostMessage(Handle, CN_PropertyChanged, 0, 0);
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.PrepareEditProperties(
|
|
AProperties: TcxCustomEditProperties; APropertyEditor: TcxPropertyEditor);
|
|
begin
|
|
with TcxCustomEditPropertiesAccess(AProperties) do
|
|
begin
|
|
//todo: need cxEditors fix
|
|
ClickKey := 0;
|
|
//remove ipaSubProperties for TcxVariantProperty
|
|
ReadOnly := ([ipaReadOnly] * APropertyEditor.GetAttributes <> []);
|
|
UseMouseWheel := False;
|
|
ValidateOnEnter := True;
|
|
OnChange := EditChange;
|
|
OnEditValueChanged := EditValueChanged;
|
|
end;
|
|
if AProperties is TcxCustomTextEditProperties then
|
|
TcxCustomTextEditProperties(AProperties).MaxLength := APropertyEditor.GetEditLimit;
|
|
if AProperties is TcxComboBoxProperties then
|
|
begin
|
|
APropertyEditor.GetValues(GetStrProc);
|
|
with TcxComboBoxProperties(AProperties) do
|
|
begin
|
|
DropDownAutoWidth := True;
|
|
ImmediateDropDown := False;
|
|
Revertable := ipaRevertable in APropertyEditor.GetAttributes;
|
|
end;
|
|
end;
|
|
if AProperties is TcxColorComboBoxProperties then
|
|
with TcxColorComboBoxPropertiesAccess(AProperties) do
|
|
begin
|
|
//todo exteditors bug
|
|
//DropDownListStyle := lsEditFixedList;
|
|
ColorValueFormat := cxcvHexadecimal;
|
|
DropDownListStyle := lsEditList;
|
|
MaxMRUColors := 0;
|
|
ColorBoxWidth := 16;
|
|
PrepareDelphiColorList(False, False);
|
|
end;
|
|
if AProperties is TcxButtonEditProperties then
|
|
with TcxButtonEditProperties(AProperties) do
|
|
OnButtonClick := RowButtonClick;
|
|
if AProperties is TcxSpinEditProperties then
|
|
TcxSpinEditProperties(AProperties).UseCtrlIncrement := True;
|
|
APropertyEditor.AdjustInnerEditProperties(AProperties);
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.DoPropertyChanged;
|
|
var
|
|
I: Integer;
|
|
AIntf: IcxRTTIInspectorHelper;
|
|
begin
|
|
if FListeners <> nil then
|
|
for I := 0 to FListeners.Count - 1 do
|
|
if Supports(TObject(FListeners[I]), IcxRTTIInspectorHelper, AIntf) then
|
|
begin
|
|
AIntf.PropertyChanged(Self);
|
|
AIntf := nil;
|
|
end;
|
|
if Assigned(FOnPropertyChanged) then FOnPropertyChanged(Self);
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.EditChange(Sender: TObject);
|
|
begin
|
|
if (PropertyEditor <> nil) and (ipaAutoUpdate in PropertyEditor.GetAttributes) then
|
|
begin
|
|
if Sender is TcxCustomTextEdit then
|
|
begin
|
|
try
|
|
PropertyEditor.Value := TcxCustomTextEdit(Sender).Text;
|
|
DoPropertyChanged;
|
|
except
|
|
TcxCustomTextEdit(Sender).Text := PropertyEditor.GetValue;
|
|
raise
|
|
end;
|
|
end
|
|
else
|
|
TrySetValue(TcxCustomEdit(Sender), True);
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.EditValueChanged(Sender: TObject);
|
|
begin
|
|
if not ((PropertyEditor <> nil) and (ipaAutoUpdate in PropertyEditor.GetAttributes)) then
|
|
TrySetValue(TcxCustomEdit(Sender), False);
|
|
Controller.CheckPostData;
|
|
end;
|
|
|
|
function TcxCustomRTTIInspector.GetControllerClass: TcxCustomControlControllerClass;
|
|
begin
|
|
Result := TcxRTTIInspectorController;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.GetDefaultViewParams(Index: Integer;
|
|
AData: TObject; out AParams: TcxViewParams);
|
|
var
|
|
AIsUnfocusedColor: Boolean;
|
|
ARow: TcxPropertyRow;
|
|
AFocused: Boolean;
|
|
|
|
function IsRootParentComponent: Boolean;
|
|
var
|
|
AParent: TcxCustomRow;
|
|
begin
|
|
Result := True;
|
|
AParent := ARow.Parent;
|
|
while (AParent <> nil) and not AParent.IsRootLevel do
|
|
begin
|
|
if (AParent is TcxPropertyRow) and
|
|
(TcxPropertyRow(AParent).PropertyEditor is TcxComponentProperty) and
|
|
(TcxPropertyRow(AParent).PropertyEditor.GetComponent(0) <> InspectedObject) then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
AParent := AParent.Parent;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
with AParams do
|
|
case Index of
|
|
vgs_Content:
|
|
begin
|
|
Bitmap := nil;
|
|
with PcxvgContentParamsData(AData)^ do
|
|
begin
|
|
ARow := TcxPropertyRow(Row);
|
|
AFocused := Focused;
|
|
end;
|
|
AIsUnfocusedColor := not AFocused or ARow.Properties.EditProperties.ReadOnly;
|
|
Color := ViewInfo.CalcHelper.GetContentColor(not AIsUnfocusedColor);
|
|
if not (AFocused or ARow.IsDefaultValue) then
|
|
Font := FBoldFont
|
|
else
|
|
Font := Self.Font;
|
|
TextColor := ViewInfo.CalcHelper.GetContentTextColor;
|
|
end;
|
|
vgs_Header:
|
|
if TcxCustomRow(AData) is TcxPropertyRow then
|
|
begin
|
|
Bitmap := nil;
|
|
ARow := TcxPropertyRow(AData);
|
|
Color := ViewInfo.CalcHelper.GetHeaderColor;
|
|
Font := Self.Font;
|
|
if ARow.PropertyEditor is TcxComponentProperty then
|
|
TextColor := clMaroon
|
|
else
|
|
if IsRootParentComponent then
|
|
TextColor := ViewInfo.CalcHelper.GetHeaderTextColor
|
|
else
|
|
TextColor := clGreen;
|
|
end
|
|
else
|
|
inherited GetDefaultViewParams(Index, AData, AParams);
|
|
else
|
|
inherited GetDefaultViewParams(Index, AData, AParams);
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomRTTIInspector.GetEditingControllerClass: TcxEditingControllerClass;
|
|
begin
|
|
Result := TcxRTTIInspectorEditingController;
|
|
end;
|
|
|
|
function TcxCustomRTTIInspector.GetOptionsBehaviorClass: TcxControlOptionsBehaviorClass;
|
|
begin
|
|
Result := TcxRTTIInspectorOptionsBehavior;
|
|
end;
|
|
|
|
function TcxCustomRTTIInspector.GetOptionsViewClass: TcxControlOptionsViewClass;
|
|
begin
|
|
Result := TcxRTTIInspectorOptionsView;
|
|
end;
|
|
|
|
function TcxCustomRTTIInspector.CanInvokePropertyEditorDlg: Boolean;
|
|
begin
|
|
Result := (PropertyEditor <> nil) and
|
|
((ipaDialog in PropertyEditor.GetAttributes) or (ipaValueList in PropertyEditor.GetAttributes));
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.CNPropertyChanged(var AMessage: TMsg);
|
|
begin
|
|
DoPropertyChanged;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.CreatePropertyRows(AOldInspectedObject: TPersistent);
|
|
var
|
|
APropName: string;
|
|
begin
|
|
APropName := '';
|
|
BeginUpdate;
|
|
try
|
|
if AOldInspectedObject <> nil then
|
|
begin
|
|
if PropertyEditor <> nil then APropName := PropertyEditor.GetName;
|
|
ReleaseComponentProperties;
|
|
end;
|
|
if FInspectedObject <> nil then
|
|
GetComponentsProperties([FInspectedObject]);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
//todo: move before EndUpdate;
|
|
if not LockRefresh then
|
|
FocusRowByPropertyName(APropName);
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.CreateRows(APropertyEditor: TcxPropertyEditor);
|
|
var
|
|
AEditPropertiesClass: TcxCustomEditPropertiesClass;
|
|
begin
|
|
AEditPropertiesClass := GetEditPropertiesClass(APropertyEditor);
|
|
if AEditPropertiesClass = nil then
|
|
begin
|
|
APropertyEditor.Free;
|
|
Exit;
|
|
end;
|
|
FCurrentRow := TcxPropertyRow(AddChild(FParentRow, TcxPropertyRow));
|
|
with FCurrentRow.Properties do
|
|
begin
|
|
Caption := APropertyEditor.GetName;
|
|
FCurrentRow.FIsDefaultValue := APropertyEditor.IsDefaultValue;
|
|
EditPropertiesClass := AEditPropertiesClass;
|
|
PrepareEditProperties(EditProperties, APropertyEditor);
|
|
end;
|
|
FCurrentRow.FPropertyEditor := APropertyEditor;
|
|
FCurrentRow.Properties.Value := APropertyEditor.Value;
|
|
if ipaSubProperties in APropertyEditor.GetAttributes then
|
|
begin
|
|
FParentRow := FCurrentRow;
|
|
APropertyEditor.GetProperties(APropertyEditor.FOwner, CreateRows);
|
|
FParentRow := FParentRow.Parent; //check for nil
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.GetComponentsProperties(
|
|
const AInstances: array of TPersistent);
|
|
|
|
function FindRootOwner(APersistent: TPersistent): TComponent;
|
|
begin
|
|
if (APersistent is TComponent) then
|
|
Result := TComponent(APersistent).Owner
|
|
else Result := nil;
|
|
if Result <> nil then
|
|
while (Result.Owner <> nil) and not (Result is TDataModule) and
|
|
not (Result is TCustomForm) {$IFDEF DELPHI5} and not (Result is TCustomFrame) {$ENDIF} do
|
|
Result := Result.Owner;
|
|
end;
|
|
|
|
var
|
|
ComponentList: TcxComponentList;
|
|
I: Integer;
|
|
AOwner: TComponent;
|
|
begin
|
|
ComponentList := TcxComponentList.Create;
|
|
try
|
|
AOwner := FindRootOwner(AInstances[Low(AInstances)]);
|
|
for I := Low(AInstances) to High(AInstances) do
|
|
begin
|
|
ComponentList.Add(TPersistent(AInstances[I]));
|
|
if (AOwner <> nil) then
|
|
begin
|
|
if FindRootOwner(AInstances[I]) <> AOwner then
|
|
AOwner := nil;
|
|
end else AOwner := nil;
|
|
end;
|
|
if AOwner = nil then
|
|
AOwner := self;
|
|
cxGetComponentProperties(AOwner, Self, ComponentList, tkProperties, CreateRows);
|
|
FullCollapse;
|
|
FParentRow := nil;
|
|
FCurrentRow := nil;
|
|
finally
|
|
ComponentList.Free;
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomRTTIInspector.GetController: TcxRTTIInspectorController;
|
|
begin
|
|
Result := TcxRTTIInspectorController(FController);
|
|
end;
|
|
|
|
function TcxCustomRTTIInspector.GetPropertyEditor: TcxPropertyEditor;
|
|
begin
|
|
if FocusedRow <> nil then
|
|
Result := TcxPropertyRow(FocusedRow).PropertyEditor
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.GetStrProc(const S: string);
|
|
begin
|
|
TcxComboBoxProperties(TcxPropertyRow(FCurrentRow).Properties.EditProperties).Items.Add(S);
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.ReleaseComponentProperties;
|
|
var
|
|
I: Integer;
|
|
ARow: TcxCustomRow;
|
|
begin
|
|
for I := 0 to Rows.Count - 1 do
|
|
begin
|
|
ARow := Rows[I];
|
|
if ARow is TcxPropertyRow then
|
|
with TcxPropertyRow(ARow) do
|
|
begin
|
|
if PropertyEditor is TcxPropertyEditor then
|
|
begin
|
|
PropertyEditor.Free;
|
|
FPropertyEditor := nil;
|
|
end;
|
|
end;
|
|
end;
|
|
if not (csDestroying in ComponentState) then
|
|
ClearRows;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.RowButtonClick(Sender: TObject; AbsoluteIndex: Integer);
|
|
begin
|
|
TryInvokePropertyEditorDlg;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.SetInspectedObject(Value: TPersistent);
|
|
var
|
|
OldInspectedObject: TPersistent;
|
|
begin
|
|
if (FInspectedObject <> Value) and IsValidInspectedObject(Value, Self) then
|
|
begin
|
|
if not (csDestroying in ComponentState) then
|
|
OldInspectedObject := FInspectedObject
|
|
else
|
|
OldInspectedObject := nil;
|
|
if not FLockRefresh and (OldInspectedObject <> nil) and
|
|
not OptionsData.CancelOnExit and Controller.IsEditing then
|
|
begin
|
|
TrySetValue(Controller.EditingController.Edit, True);
|
|
end;
|
|
FInspectedObject := Value;
|
|
if (FInspectedObject <> nil) and (FInspectedObject is TComponent) then
|
|
TComponent(Value).FreeNotification(Self);
|
|
if ([csDesigning, csLoading, csDestroying] * ComponentState) = [] then
|
|
CreatePropertyRows(OldInspectedObject);
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomRTTIInspector.TryInvokePropertyEditorDlg;
|
|
begin
|
|
if CanInvokePropertyEditorDlg then
|
|
begin
|
|
PropertyEditor.Edit;
|
|
RefreshInspectedProperties;
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomRTTIInspector.TrySetValue(
|
|
AEdit: TcxCustomEdit; AUseText: Boolean): Boolean;
|
|
var
|
|
V: Variant;
|
|
begin
|
|
Result := False;
|
|
if FSettingValue or (PropertyEditor = nil) then Exit;
|
|
FSettingValue := True;
|
|
try
|
|
V := PropertyEditor.Value;
|
|
try
|
|
if AUseText and (AEdit is TcxCustomTextEdit) then
|
|
PropertyEditor.Value := TcxCustomTextEdit(AEdit).Text
|
|
else
|
|
PropertyEditor.Value := AEdit.EditValue;
|
|
Result := True;
|
|
except
|
|
PropertyEditor.Value := V;
|
|
AEdit.EditValue := V;
|
|
raise;
|
|
end;
|
|
DoPropertyChanged;
|
|
RefreshInspectedProperties;
|
|
finally
|
|
FSettingValue := False;
|
|
end;
|
|
end;
|
|
|
|
procedure cxDotNetInspectObject(AObject: TPersistent; AInspector: TcxRTTIInspector);
|
|
var
|
|
I: Integer;
|
|
C: TcxCategoryRow;
|
|
begin
|
|
if AObject <> nil then
|
|
with AInspector do
|
|
begin
|
|
InspectedObject := nil;
|
|
BeginUpdate;
|
|
try
|
|
InspectedObject := AObject;
|
|
OptionsBehavior.AlwaysShowEditor := False;
|
|
OptionsView.GridLineColor := clBtnFace;
|
|
OptionsView.PaintStyle := psdotNet;
|
|
C := TcxCategoryRow(Add(TcxCategoryRow));
|
|
with C do
|
|
begin
|
|
if (AObject is TComponent) and (TComponent(AObject).Name <> '') then
|
|
Properties.Caption := TComponent(AObject).Name + ': ' + AObject.ClassName
|
|
else
|
|
Properties.Caption := AObject.ClassName;
|
|
Properties.HeaderAlignmentVert := vaCenter;
|
|
Index := 0;
|
|
end;
|
|
for I := 1 to Rows.Count - 1 do
|
|
if Rows[I].Level = 0 then
|
|
Rows[I].Parent := C;
|
|
finally
|
|
FocusedRow := FirstVisibleRow;
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TcxInspectedObjectPropertyEditor }
|
|
|
|
function TcxInspectedObjectPropertyEditor.IsValidComponent(AComponent: TComponent): Boolean;
|
|
begin
|
|
Result := inherited IsValidComponent(AComponent) and
|
|
IsValidInspectedObject(AComponent, Inspector);
|
|
end;
|
|
|
|
initialization
|
|
cxRegisterPropertyEditor(TypeInfo(TColor), nil, '', TcxColorProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TFont), nil, '', TcxFontProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TFontCharset), nil, '', TcxFontCharsetProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TFontName), nil, '', TcxFontNameProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TCursor), nil, '', TcxCursorProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(string), TMediaPlayer, 'FileName', TcxMPFilenameProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TCaption), nil, '', TcxCaptionProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TComponent), nil, '', TcxComponentProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TComponentName), nil, '', TcxComponentNameProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TImeName), nil, '', TcxImeNameProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TModalResult), nil, '', TcxModalResultProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TShortCut), nil, '', TcxShortCutProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TTabOrder), nil, '', TcxTabOrderProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TDate), nil, '', TcxDateProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TTime), nil, '', TcxTimeProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TDateTime), nil, '', TcxDateTimeProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(Boolean), nil, '', TcxBoolProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TStrings), nil, '', TcxStringsProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TPicture), nil, '', TcxPictureProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(TBitmap), nil, '', TcxGraphicProperty);
|
|
cxRegisterPropertyEditor(TypeInfo(Variant), nil, '', TcxVariantProperty);
|
|
|
|
cxRegisterPropertyEditor(TypeInfo(TPersistent),
|
|
TcxCustomRTTIInspector, 'InspectedObject', TcxInspectedObjectPropertyEditor);
|
|
|
|
cxRegisterEditPropertiesClass(TcxCaptionProperty, TcxTextEditProperties);
|
|
cxRegisterEditPropertiesClass(TcxColorProperty, TcxColorComboBoxProperties);
|
|
cxRegisterEditPropertiesClass(TcxComponentNameProperty, TcxTextEditProperties);
|
|
cxRegisterEditPropertiesClass(TcxComponentProperty, TcxComboBoxProperties);
|
|
cxRegisterEditPropertiesClass(TcxCursorProperty, TcxComboBoxProperties);
|
|
cxRegisterEditPropertiesClass(TcxDateProperty, TcxDateEditProperties);
|
|
cxRegisterEditPropertiesClass(TcxDateTimeProperty, TcxTextEditProperties);
|
|
cxRegisterEditPropertiesClass(TcxFontCharsetProperty, TcxComboBoxProperties);
|
|
cxRegisterEditPropertiesClass(TcxFontNameProperty, TcxComboBoxProperties);
|
|
cxRegisterEditPropertiesClass(TcxFontProperty, TcxTextEditProperties);
|
|
cxRegisterEditPropertiesClass(TcxIntegerProperty, TcxSpinEditProperties);
|
|
cxRegisterEditPropertiesClass(TcxImeNameProperty, TcxTextEditProperties);
|
|
cxRegisterEditPropertiesClass(TcxModalResultProperty, TcxComboBoxProperties);
|
|
cxRegisterEditPropertiesClass(TcxMPFilenameProperty, TcxTextEditProperties);
|
|
cxRegisterEditPropertiesClass(TcxPictureProperty, TcxButtonEditProperties);
|
|
cxRegisterEditPropertiesClass(TcxShortCutProperty, TcxComboBoxProperties);
|
|
cxRegisterEditPropertiesClass(TcxStringsProperty, TcxButtonEditProperties);
|
|
cxRegisterEditPropertiesClass(TcxTabOrderProperty, TcxSpinEditProperties);
|
|
cxRegisterEditPropertiesClass(TcxTimeProperty, TcxTimeEditProperties);
|
|
//
|
|
cxRegisterPropertyEditor(TypeInfo(string), TcxCustomEditorRowProperties, 'EditPropertiesClassName', nil);
|
|
cxRegisterPropertyEditor(TypeInfo(TcxCustomEditProperties), TcxCustomEditorRowProperties, 'EditProperties', TcxEditPropertiesProperty);
|
|
|
|
finalization
|
|
ListFreeAndNil(FEditPropertiesClasses);
|
|
ListFreeAndNil(FPropertyClasses);
|
|
ListFreeAndNil(FPropertyMappers);
|
|
|
|
end.
|
|
|