lazarus/components/ideintf/propedits.pp

9333 lines
282 KiB
ObjectPascal

{
*****************************************************************************
See the file COPYING.modifiedLGPL.txt, included in this distribution,
for details about the license.
*****************************************************************************
Author: Mattias Gaertner
Abstract:
This units defines the property editors used by the object inspector.
A Property Editor is the interface between a row of the object inspector
and a property in the RTTI.
For more information see the big comment part below.
}
unit PropEdits;
{$mode objfpc}{$H+}
// This unit contains a lot of base type conversions. Disable range checking.
{$R-}
{$ModeSwitch advancedrecords}
{$IF FPC_FULLVERSION>30300}
{$Define HasExtRtti}
{$ENDIF}
interface
uses
// RTL / FCL
Classes, TypInfo, SysUtils, types, RtlConsts, variants, Contnrs, strutils, FGL,
Math, System.UITypes,
// LCL
LCLType, LCLIntf, LCLProc, Forms, Controls, ButtonPanel, Graphics,
StdCtrls, Buttons, Menus, ExtCtrls, ComCtrls, Dialogs, EditBtn, Grids, ValEdit,
FileCtrl, PropertyStorage, Themes,
// LazControls
CheckBoxThemed,
// LazUtils
FileUtil, StringHashList, LazMethodList, LazLoggerBase, LazUtilities,
GraphType, FPCAdds, // for StrToQWord in older fpc versions
// IdeIntf
ObjInspStrConsts, PropEditUtils, TextTools,
// Forms with .lfm files
FrmSelectProps, StringsPropEditDlg, KeyValPropEditDlg, CollectionPropEditForm,
FileFilterPropEditor, PagesPropEditDlg, IDEWindowIntf;
const
MaxIdentLength: Byte = 63;
CheckBoxThemedLeftOffs = 3;
{$IFDEF LCLCarbon}
// LineFeed symbol (UTF8) to maintain linefeeds in multiline text for Carbon TEdit.
// In Carbon, linefeeds get stripped from TEdit text, so we replace it temporary with
// this symbol which displays correctly a LF symbol in the Object Inspector as well.
LineFeedSymbolUTF8 = #226#144#138;
{$ENDIF}
type
TPersistentSelectionList = PropEditUtils.TPersistentSelectionList;
// For backwards compatibility only. Use TGetStrProc directly.
TGetStringProc = Classes.TGetStrProc;
{ TPropertyEditor
Edits a property of a component, or list of components, selected into the
Object Inspector. The property editor is created based on the type of the
property being edited as determined by the types registered by
RegisterPropertyEditor. The Object Inspector uses a TPropertyEditor
for all modification to a property. GetName and GetValue are called to
display the name and value of the property. SetValue is called whenever the
user requests to change the value. Edit is called when the user
double-clicks the property in the Object Inspector. GetValues is called when
the drop-down list of a property is displayed. GetProperties is called when
the property is expanded to show sub-properties. AllEqual is called to decide
whether or not to display the value of the property when more than one
component is selected.
The following are methods that can be overridden to change the behavior of
the property editor:
Activate
Called whenever the property becomes selected in the object inspector.
This is potentially useful to allow certain property attributes to
to only be determined whenever the property is selected in the object
inspector. Only paSubProperties and paMultiSelect,returned from
GetAttributes,need to be accurate before this method is called.
Deactivate
Called whenevr the property becomes unselected in the object inspector.
AllEqual
Called whenever there is more than one component selected. If this
method returns true,GetValue is called,otherwise blank is displayed
in the Object Inspector. This is called only when GetAttributes
returns paMultiSelect.
AutoFill
Called to determine whether the values returned by GetValues can be
selected incrementally in the Object Inspector. This is called only when
GetAttributes returns paValueList.
Edit
Called when the '...' button is pressed or the property is double-clicked.
This can,for example,bring up a dialog to allow the editing the
component in some more meaningful fashion than by text (e.g. the Font
property).
GetAttributes
Returns the information for use in the Object Inspector to be able to
show the appropriate tools. GetAttributes returns a set of type
TPropertyAttributes:
paValueList: The property editor can return an enumerated list of
values for the property. If GetValues calls Proc
with values then this attribute should be set. This
will cause the drop-down button to appear to the right
of the property in the Object Inspector.
paSortList: Object Inspector to sort the list returned by
GetValues.
paPickList: Usable together with paValueList. The text field is
readonly. The user can still select values from drop
list. Unless paReadOnly.
paSubProperties:The property editor has sub-properties that will be
displayed indented and below the current property in
standard outline format. If GetProperties will
generate property objects then this attribute should
be set.
paDynamicSubProps:The sub properties can change. All designer tools
(e.g. property editors, component editors) that change
the list should call UpdateListPropertyEditors, so that
the object inspector will reread the subproperties.
paDialog: Indicates that the Edit method will bring up a
dialog. This will cause the '...' button to be
displayed to the right of the property in the Object
Inspector.
paMultiSelect: Allows the property to be displayed when more than
one component is selected. Some properties are not
appropriate for multi-selection (e.g. the Name
property).
paAutoUpdate: Causes the SetValue method to be called on each
change made to the editor instead of after the change
has been approved (e.g. the Caption property).
paReadOnly: Value is not allowed to change. But if paDialog is set
a Dialog can change the value. This disables only the
edit and combobox in the object inspector.
paRevertable: Allows the property to be reverted to the original
value. Things that shouldn't be reverted are nested
properties (e.g. Fonts) and elements of a composite
property such as set element values.
paFullWidthName:Tells the object inspector that the value does not
need to be rendered and as such the name should be
rendered the full width of the inspector.
paVolatileSubProperties: Any change of property value causes any shown
subproperties to be recollected.
paDisableSubProperties: All subproperties are readonly
(not even via Dialog).
paReference: property contains a reference to something else. When
used in conjunction with paSubProperties the referenced
object should be displayed as sub properties to this
property.
paNotNestable: Indicates that the property is not safe to show when
showing the properties of an expanded reference.
GetComponent
Returns the Index'th component being edited by this property editor. This
is used to retrieve the components. A property editor can only refer to
multiple components when paMultiSelect is returned from GetAttributes.
GetEditLimit
Returns the number of character the user is allowed to enter for the
value. The inplace editor of the object inspector will be have its
text limited set to the return value. By default this limit is 255.
GetName
Returns the name of the property. By default the value is retrieved
from the type information with all underbars replaced by spaces. This
should only be overridden if the name of the property is not the name
that should appear in the Object Inspector.
GetProperties
Should be overridden to call PropertyProc for every sub-property (or
nested property) of the property begin edited and passing a new
TPropertyEditor for each sub-property. By default, PropertyProc is not
called and no sub-properties are assumed. TClassPropertyEditor will pass a
new property editor for each published property in a class.
TSetPropertyEditor passes a new editor for each element in the set.
GetPropType
Returns the type information pointer for the property(s) being edited.
GetValue
Returns the string value of the property. By default this returns
'(unknown)'. This should be overridden to return the appropriate value.
GetValues
Called when paValueList is returned in GetAttributes. Should call Proc
for every value that is acceptable for this property. TEnumPropertyEditor
will pass every element in the enumeration.
Initialize
Called after the property editor has been created but before it is used.
Many times property editors are created and because they are not a common
property across the entire selection they are thrown away. Initialize is
called after it is determined the property editor is going to be used by
the object inspector and not just thrown away.
SetValue(Value)
Called to set the value of the property. The property editor should be
able to translate the string and call one of the SetXxxValue methods. If
the string is not in the correct format or not an allowed value,the
property editor should generate an exception describing the problem. Set
value can ignore all changes and allow all editing of the property be
accomplished through the Edit method (e.g. the Picture property).
ListMeasureWidth(Value,Canvas,AWidth)
This is called during the width calculation phase of the drop down list
preparation.
ListMeasureHeight(Value,Canvas,AHeight)
This is called during the item/value height calculation phase of the drop
down list's render. This is very similar to TListBox's OnMeasureItem,
just slightly different parameters.
ListDrawValue(Value,Canvas,Rect,Selected)
This is called during the item/value render phase of the drop down list's
render. This is very similar to TListBox's OnDrawItem, just slightly
different parameters.
PropMeasureHeight(Value,Canvas,AHeight)
This is called during the item/property height calculation phase of the
object inspectors rows render. This is very similar to TListBox's
OnMeasureItem, just slightly different parameters.
PropDrawName(Canvas,Rect,Selected)
Called during the render of the name column of the property list. Its
functionality is very similar to TListBox's OnDrawItem,but once again
it has slightly different parameters.
PropDrawValue(Canvas,Rect,Selected)
Called during the render of the value column of the property list. Its
functionality is similar to PropDrawName. If multiple items are selected
and their values don't match this procedure will be passed an empty
value.
Properties and methods useful in creating new TPropertyEditor classes:
Name property
Returns the name of the property returned by GetName
PrivateEditory property
This is the configuration directory of lazarus.
If the property editor needs auxiliary or state files (templates,
examples, etc) they should be stored in this editory.
Value property
The current value,as a string,of the property as returned by GetValue.
Modified
Called to indicate the value of the property has been modified. Called
automatically by the SetXxxValue methods. If you call a TProperty
SetXxxValue method directly,you *must* call Modified as well.
GetXxxValue
Gets the value of the first property in the Properties property. Calls
the appropriate TProperty GetXxxValue method to retrieve the value.
SetXxxValue
Sets the value of all the properties in the Properties property. Calls
the approprate TProperty SetXxxxValue methods to set the value.
GetVisualValue
This function will return the displayable value of the property. If
only one item is selected or all the multi-selected items have the same
property value then this function will return the actual property value.
Otherwise this function will return an empty string.}
TPropertyAttribute=(
paValueList,
paPickList,
paSubProperties,
paDynamicSubProps,
paDialog,
paMultiSelect,
paAutoUpdate,
paSortList,
paReadOnly,
paRevertable,
paFullWidthName,
paVolatileSubProperties,
paDisableSubProperties,
paReference,
paNotNestable,
paCustomDrawn
);
TPropertyAttributes = set of TPropertyAttribute;
TPropertyEditor = class;
{ TInstProp }
TInstProp = record
Instance: TPersistent; // can be nil, e.g. record field
PropInfo: PPropInfo; // can be nil, e.g. record field
Field: Pointer; // for record field
FieldName: PShortString;
FieldTypeInfo: PTypeInfo;
// ToDo: add list of parent instances, e.g. Label1.Font.Color: Font needs Label1
function GetTypeInfo: PTypeInfo;
function GetKind: TTypeKind;
function GetOrd: int64;
procedure SetOrd(const Value: int64);
function GetEnum: string;
procedure SetEnum(const Value: string);
function GetSet(Brackets: boolean): string;
procedure SetSet(const Value: string);
function GetString: AnsiString;
procedure SetString(const Value: string);
function GetWideString: WideString;
procedure SetWideString(const Value: WideString);
function GetUnicodeString: UnicodeString;
procedure SetUnicodeString(const Value: UnicodeString);
function GetRawByteString: RawByteString;
procedure SetRawByteString(const Value: RawByteString);
function GetFloat: Extended;
procedure SetFloat(const Value: Extended);
function GetObject(MinClass: TClass = nil): TObject;
procedure SetObject(const Value: TObject);
function GetPointerValue: Pointer;
procedure SetPointerValue(const Value: Pointer);
function GetMethod: TMethod;
procedure SetMethod(const Value: TMethod);
function GetInterface: IInterface;
procedure SetInterface(const Value: IInterface);
function GetVariant: Variant;
procedure SetVariant(const Value: Variant);
end;
PInstProp = ^TInstProp;
TInstPropList = array[0..999999] of TInstProp;
PInstPropList = ^TInstPropList;
TGetPropEditProc = procedure(Prop: TPropertyEditor) of object;
TPropEditDrawStateType = (pedsSelected, pedsFocused, pedsInEdit, pedsInComboList);
TPropEditDrawState = set of TPropEditDrawStateType;
TPropEditHint = (
pehNone,
pehTree,
pehName,
pehValue,
pehEditButton
);
TPropertyEditorHook = class;
{ TPropertyEditor }
TPropertyEditor = class
private
FOnSubPropertiesChanged: TNotifyEvent;
FPropertyHook: TPropertyEditorHook;
FOwnerComponent: TComponent;
FPropCount: Integer;
FPropList: PInstPropList;
protected
// Draw Checkbox for Boolean and Set element editors.
{$IFDEF UseOINormalCheckBox}
function DrawCheckbox(ACanvas: TCanvas; const ARect: TRect; IsTrue: Boolean): TRect;
{$ENDIF}
function DrawCheckValue(ACanvas: TCanvas; const ARect: TRect;
{%H-}AState: TPropEditDrawState; {%H-}IsTrue: Boolean): TRect;
procedure DrawValue(const AValue: string; ACanvas:TCanvas; const ARect:TRect;
{%H-}AState:TPropEditDrawState);
function GetPrivateDirectory: ansistring;
public
constructor Create(Hook:TPropertyEditorHook; APropCount:Integer); virtual;
destructor Destroy; override;
procedure Activate; virtual;
procedure Deactivate; virtual;
function AllEqual: Boolean; virtual;
function AutoFill: Boolean; virtual;
// Called when clicking on OI property button or double clicking on value.
procedure Edit; virtual;
// Needed for method Contraints.OnChange etc.
procedure Edit(AOwnerComponent: TComponent);
procedure ShowValue; virtual; // called when Ctrl-Click on value
function GetAttributes: TPropertyAttributes; virtual;
function IsReadOnly: boolean; virtual;
// For Delphi compatibility it is called GetComponent instead of GetPersistent
function GetComponent(Index: Integer): TPersistent;
function GetUnitName(Index: Integer = 0): string;
function GetPropTypeUnitName(Index: Integer = 0): string;
function GetPropertyPath(Index: integer = 0): string;// e.g. 'TForm1.Color'
function GetEditLimit: Integer; virtual;
function GetName: shortstring; virtual;
procedure GetProperties({%H-}Proc: TGetPropEditProc); virtual;
function GetPropType: PTypeInfo;
function GetPropInfo: PPropInfo;
function GetInstProp: PInstProp;
function GetEnumValueAt(Index: Integer): string;
function GetFloatValue: Extended;
function GetFloatValueAt(Index: Integer): Extended;
function GetInt64Value: Int64;
function GetInt64ValueAt(Index: Integer): Int64;
function GetIntfValue: IInterface;
function GetIntfValueAt(Index: Integer): IInterface;
function GetMethodValue: TMethod;
function GetMethodValueAt(Index: Integer): TMethod;
function GetOrdValue: Longint;
function GetOrdValueAt(Index: Integer): Longint;
function GetObjectValue: TObject;
function GetObjectValue(MinClass: TClass): TObject;
function GetObjectValueAt(Index: Integer): TObject;
function GetObjectValueAt(Index: Integer; MinClass: TClass): TObject;
function GetDefaultOrdValue: Longint;
function GetSetValue(Brackets: boolean): AnsiString;
function GetSetValueAt(Index: Integer; Brackets: boolean): AnsiString;
function GetStrValue: AnsiString;
function GetStrValueAt(Index: Integer): AnsiString;
function GetVarValue: Variant;
function GetVarValueAt(Index: Integer):Variant;
function GetWideStrValue: WideString;
function GetWideStrValueAt(Index: Integer): WideString;
function GetUnicodeStrValue: UnicodeString;
function GetUnicodeStrValueAt(Index: Integer): UnicodeString;
function GetValue: ansistring; virtual;
function GetHint({%H-}HintType: TPropEditHint; {%H-}x, {%H-}y: integer): string; virtual;
function HasDefaultValue: Boolean;
function GetDefaultValue: ansistring; virtual;
function CallStoredFunction: Boolean; virtual;
function GetVisualValue: ansistring; virtual;
procedure GetValues({%H-}Proc: TGetStrProc); virtual;
procedure Initialize; virtual;
procedure Revert; virtual;
procedure RevertToInherited; virtual;
procedure SetValue(const {%H-}NewValue: ansistring); virtual;
procedure SetPropEntry(Index: Integer; AnInstance: TPersistent;
APropInfo: PPropInfo); virtual;
procedure SetRecordFieldEntry(Index: Integer; AnInstance: Pointer;
aName: PShortString; AFieldInfo: PTypeInfo); virtual;
procedure SetFloatValue(const NewValue: Extended);
procedure SetMethodValue(const NewValue: TMethod);
procedure SetInt64Value(const NewValue: Int64);
procedure SetIntfValue(const NewValue: IInterface);
procedure SetOrdValue(const NewValue: Longint);
procedure SetPtrValue(const NewValue: Pointer);
procedure SetStrValue(const NewValue: AnsiString);
procedure SetWideStrValue(const NewValue: WideString);
procedure SetUnicodeStrValue(const NewValue: UnicodeString);
procedure SetVarValue(const NewValue: Variant);
procedure Modified(Index: integer = 0);
function ValueAvailable: Boolean;
procedure ListMeasureWidth(const {%H-}AValue: ansistring; {%H-}Index: Integer;
{%H-}ACanvas: TCanvas; var {%H-}AWidth: Integer); virtual;
procedure ListMeasureHeight(const AValue: ansistring; {%H-}Index: Integer;
ACanvas: TCanvas; var AHeight: Integer); virtual;
procedure ListDrawValue(const AValue: ansistring; {%H-}Index: Integer;
ACanvas: TCanvas; const ARect: TRect;
{%H-}AState: TPropEditDrawState); virtual;
procedure PropMeasureHeight(const {%H-}NewValue: ansistring; {%H-}ACanvas: TCanvas;
var {%H-}AHeight: Integer); virtual;
procedure PropDrawName(ACanvas: TCanvas; const ARect: TRect;
{%H-}AState: TPropEditDrawState); virtual;
procedure PropDrawValue(ACanvas: TCanvas; const ARect: TRect;
{%H-}AState: TPropEditDrawState); virtual;
procedure UpdateSubProperties; virtual;
function SubPropertiesNeedsUpdate: boolean; virtual;
function ValueIsStreamed: boolean; virtual; // if value is stored, usually because it differs from default value
function IsRevertableToInherited: boolean; virtual;
// These are used for the popup menu in OI
function GetVerbCount: Integer; virtual;
function GetVerb(Index: Integer): string; virtual;
procedure PrepareItem({%H-}Index: Integer; const {%H-}AnItem: TMenuItem); virtual;
procedure ExecuteVerb({%H-}Index: Integer); virtual;
public
property PropertyHook: TPropertyEditorHook read FPropertyHook;
property PrivateDirectory: ansistring read GetPrivateDirectory;
property PropCount: Integer read FPropCount;
property FirstValue: ansistring read GetValue write SetValue;
property OnSubPropertiesChanged: TNotifyEvent
read FOnSubPropertiesChanged write FOnSubPropertiesChanged;
end;
TPropertyEditorClass = class of TPropertyEditor;
TPropertyEditorList = specialize TFPGObjectList<TPropertyEditor>;
{ THiddenPropertyEditor
A property editor to hide a published property. If you can't unpublish it, hide it. }
THiddenPropertyEditor = class(TPropertyEditor)
end;
{ TOrdinalPropertyEditor
The base class of all ordinal property editors. It establishes that ordinal
properties are all equal if the GetOrdValue all return the same value and
provide methods to retrieve the default value. }
TOrdinalPropertyEditor = class(TPropertyEditor)
public
function AllEqual: Boolean; override;
function GetEditLimit: Integer; override;
function GetValue: ansistring; override;
function GetDefaultValue: ansistring; override;
function OrdValueToVisualValue(OrdValue: longint): string; virtual;
end;
{ TIntegerPropertyEditor
Default editor for all Longint properties and all subtypes of the Longint
type (i.e. Integer, Word, 1..10, etc.). Restricts the value entered into
the property to the range of the sub-type. }
TIntegerPropertyEditor = class(TOrdinalPropertyEditor)
public
function OrdValueToVisualValue(OrdValue: longint): string; override;
procedure SetValue(const NewValue: ansistring); override;
end;
{ TCharPropertyEditor
Default editor for all Char properties and sub-types of Char (i.e. Char,
'A'..'Z', etc.). }
TCharPropertyEditor = class(TOrdinalPropertyEditor)
public
function OrdValueToVisualValue(OrdValue: longint): string; override;
procedure SetValue(const NewValue: ansistring); override;
end;
{ TEnumPropertyEditor
The default property editor for all enumerated properties (e.g. TShape =
(sCircle, sTriangle, sSquare), etc.). }
TEnumPropertyEditor = class(TOrdinalPropertyEditor)
private
FInvalid: Boolean;
public
function GetAttributes: TPropertyAttributes; override;
function OrdValueToVisualValue(OrdValue: longint): string; override;
function GetVisualValue: ansistring; override;
procedure GetValues(Proc: TGetStrProc); override;
procedure SetValue(const NewValue: ansistring); override;
end;
type
{ TBoolPropertyEditor
Default property editor for all boolean properties }
TBoolPropertyEditor = class(TEnumPropertyEditor)
public
function OrdValueToVisualValue(OrdValue: longint): string; override;
function GetVisualValue: ansistring; override;
procedure GetValues(Proc: TGetStrProc); override;
procedure SetValue(const NewValue: ansistring); override;
procedure PropDrawValue(ACanvas: TCanvas; const ARect: TRect;
AState: TPropEditDrawState); override;
end;
{ TInt64PropertyEditor
Default editor for all Int64 properties and all subtypes of Int64. }
TInt64PropertyEditor = class(TPropertyEditor)
public
function AllEqual: Boolean; override;
function GetEditLimit: Integer; override;
function GetValue: ansistring; override;
procedure SetValue(const NewValue: ansistring); override;
end;
{ TQWordPropertyEditor
Default editor for all QWord properties }
TQWordPropertyEditor = class(TInt64PropertyEditor)
public
function GetValue: ansistring; override;
procedure SetValue(const NewValue: ansistring); override;
end;
{ TFloatPropertyEditor
The default property editor for all floating point types (e.g. Float,
Single, Double, etc.) }
TFloatPropertyEditor = class(TPropertyEditor)
protected
function FloatInRange(AValue: Extended; AType: TFloatType): Boolean;
public
function AllEqual: Boolean; override;
function FormatValue(const AValue: Extended): ansistring;
function GetDefaultValue: ansistring; override;
function GetValue: ansistring; override;
procedure SetValue(const NewValue: ansistring); override;
end;
{ TStringPropertyEditor
The default property editor for all strings and sub types (e.g. string,
string[20], etc.). }
TStringPropertyEditor = class(TPropertyEditor)
public
function AllEqual: Boolean; override;
function GetEditLimit: Integer; override;
function GetValue: ansistring; override;
procedure SetValue(const NewValue: ansistring); override;
end;
{ TPasswordStringPropertyEditor
The default property editor for string passwords}
TPasswordStringPropertyEditor = class(TStringPropertyEditor)
public
function GetPassword: string; virtual;
procedure PropDrawValue(ACanvas: TCanvas; const ARect: TRect;
AState: TPropEditDrawState); override;
end;
{ TWideStringPropertyEditor
The default property editor for widestrings}
TWideStringPropertyEditor = class(TPropertyEditor)
public
function AllEqual: Boolean; override;
function GetValue: ansistring; override;
procedure SetValue(const NewValue: ansistring); override;
end;
{ TPasswordWideStringPropertyEditor
The default property editor for widestring passwords}
TPasswordWideStringPropertyEditor = class(TWideStringPropertyEditor)
public
function GetPassword: WideString; virtual;
procedure PropDrawValue(ACanvas: TCanvas; const ARect: TRect;
AState: TPropEditDrawState); override;
end;
{ TUnicodeStringPropertyEditor
The default property editor for unicodestrings}
TUnicodeStringPropertyEditor = class(TPropertyEditor)
public
function AllEqual: Boolean; override;
function GetValue: ansistring; override;
procedure SetValue(const NewValue: ansistring); override;
end;
{ TNestedPropertyEditor
A property editor that uses the PropertyHook, PropList and PropCount.
The constructor and destructor do not call inherited, but all derived classes
should. This is useful for properties like the TSetElementPropertyEditor. }
TNestedPropertyEditor = class(TPropertyEditor)
private
FParentEditor: TPropertyEditor;
public
constructor Create(Parent: TPropertyEditor); overload;
destructor Destroy; override;
property ParentEditor: TPropertyEditor read FParentEditor;
end;
{ TSetElementPropertyEditor
A property editor that edits an individual set element. GetName is
changed to display the set element name instead of the property name and
Get/SetValue is changed to reflect the individual element state. This
editor is created by the TSetPropertyEditor editor. }
TSetElementPropertyEditor = class(TNestedPropertyEditor)
private
FElement: Integer;
public
constructor Create(Parent: TPropertyEditor; AElement: Integer); overload;
function AllEqual: Boolean; override;
function GetAttributes: TPropertyAttributes; override;
function GetName: shortstring; override;
function GetValue: ansistring; override;
function GetVerbCount: Integer; override;
function GetVisualValue: ansistring; override;
procedure GetValues(Proc: TGetStrProc); override;
procedure SetValue(const NewValue: ansistring); override;
function ValueIsStreamed: boolean; override;
procedure PropDrawValue(ACanvas: TCanvas; const ARect: TRect;
AState: TPropEditDrawState); override;
end;
{ TSetPropertyEditor
Default property editor for all set properties. This editor does not edit
the set directly but will display sub-properties for each element of the
set. GetValue displays the value of the set in standard set syntax. }
TSetPropertyEditor = class(TOrdinalPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
function GetEditLimit: Integer; override;
procedure GetProperties(Proc: TGetPropEditProc); override;
procedure SetValue(const NewValue: ansistring); override;
function OrdValueToVisualValue(OrdValue: longint): string; override;
end;
{ TStructurePropertyEditor }
TStructurePropertyEditor = class(TPropertyEditor)
private
FSubPropsTypeFilter: TTypeKinds;
FSubPropsNameFilter: String;
FSubProps: TObjectList;
protected
function EditorFilter(const AEditor: TPropertyEditor): Boolean; virtual;
procedure ListSubProps(Prop: TPropertyEditor); virtual;
procedure SetSubPropsTypeFilter(const AValue: TTypeKinds); virtual;
public
constructor Create(Hook: TPropertyEditorHook; APropCount: Integer); override;
destructor Destroy; override;
function AllEqual: Boolean; override;
property SubPropsTypeFilter: TTypeKinds
read FSubPropsTypeFilter write SetSubPropsTypeFilter default tkAny;
property SubPropsNameFilter: String
read FSubPropsNameFilter write FSubPropsNameFilter;
end;
{ TClassPropertyEditor
Default property editor for all objects. Does not allow modifying the
property but does display the class name of the object and will allow the
editing of the object's properties as sub-properties of the property. }
TClassPropertyEditor = class(TStructurePropertyEditor)
private
FHideClassName: Boolean;
protected
function GetSelections: TPersistentSelectionList; virtual;
public
function ValueIsStreamed: boolean; override;
function GetAttributes: TPropertyAttributes; override;
procedure GetProperties(Proc: TGetPropEditProc); override;
function GetValue: String; override;
property HideClassName: Boolean read FHideClassName write FHideClassName;
end;
{ TPersistentPropertyEditor
A base editor for TPersistent. It does allow editing of the properties.
It allows the user to set the value of this property to point to a component
in any form or datamodule that is type compatible with the property being
edited (e.g. the DataSource property). }
TPersistentPropertyEditor = class(TClassPropertyEditor)
private
// Used in AllEqual of TComponentOneFormPropertyEditor and TComponentPropertyEditor.
function ComponentsAllEqual: Boolean;
protected
function FilterFunc(const ATestEditor: TPropertyEditor): Boolean;
function GetPersistentReference: TPersistent; virtual;
function GetSelections: TPersistentSelectionList; override;
function CheckNewValue({%H-}APersistent: TPersistent): boolean; virtual;
public
function AllEqual: Boolean; override;
procedure Edit; override;
function GetAttributes: TPropertyAttributes; override;
function GetEditLimit: Integer; override;
function GetValue: AnsiString; override;
procedure GetValues(Proc: TGetStrProc); override;
procedure SetValue(const NewValue: ansistring); override;
end;
{ TComponentOneFormPropertyEditor
An editor for TComponents. It allows the user to set the value of this
property to point to a component in the same form that is type compatible
with the property being edited (e.g. the ActiveControl property). }
TComponentOneFormPropertyEditor = class(TPersistentPropertyEditor)
protected
fIgnoreClass: TControlClass;
public
function AllEqual: Boolean; override;
procedure GetValues(Proc: TGetStrProc); override;
end;
{ TCoolBarControlPropertyEditor -
An editor for TComponents. It allows the user to set the value of this
property to point to a component in the same form that is type compatible
with the property being edited and is not a TCustomCoolBar
(e.g. the TCoolBand.Control property).}
TCoolBarControlPropertyEditor = class(TComponentOneFormPropertyEditor)
public
constructor Create(Hook: TPropertyEditorHook; APropCount: Integer); override;
end;
{ TComponentPropertyEditor
The default editor for TComponents. It allows the user to set the value of
this property to point to a component in any form in the project that is
type compatible with the property being edited. }
TComponentPropertyEditor = class(TPersistentPropertyEditor)
protected
function GetComponentReference: TComponent; virtual;
public
function AllEqual: Boolean; override;
end;
{ TInterfacePropertyEditor
The default editor for interface references. It allows the user to set
the value of this property to refer to an interface implemented by
a component on the form (or via form linking) that is type compatible
with the property being edited. }
TInterfacePropertyEditor = class(TComponentPropertyEditor)
private
protected
function GetComponent(const AInterface: IInterface): TComponent;
function GetComponentReference: TComponent; override;
function GetSelections: TPersistentSelectionList; override;
public
function AllEqual: Boolean; override;
procedure Edit; override;
function GetAttributes: TPropertyAttributes; override;
procedure GetValues(Proc: TGetStrProc); override;
procedure SetValue(const NewValue: string); override;
function GetValue: AnsiString; override;
end;
{ TNoteBookActiveControlPropertyEditor }
TNoteBookActiveControlPropertyEditor = class(TComponentPropertyEditor)
protected
function CheckNewValue(APersistent: TPersistent): boolean; override;
public
function GetAttributes: TPropertyAttributes; override;
procedure GetValues(Proc: TGetStrProc); override;
end;
{ TPagesPropertyEditor
PropertyEditor editor for the TNoteBook.Pages properties.
Brings up a dialog with a Memo for entering pages. }
TPagesPropEditorDlg = class;
TPagesPropertyEditor = class(TClassPropertyEditor)
public
procedure AssignItems(OldItmes, NewItems: TStrings);
procedure Edit; override;
function CreateDlg(s: TStrings): TPagesPropEditorDlg; virtual;
function GetAttributes: TPropertyAttributes; override;
end;
{ TRecordPropertyEditor }
TRecordPropertyEditor = class(TStructurePropertyEditor)
private
FCanReadFields: boolean;
FCanWriteFields: boolean;
FHideRecordName: Boolean;
protected
FRecordData: PByte; // depending on FRecordRead this points to a temp mem or the instance
FReadAccess, FWriteAccess: Byte; // see ptField..ptConst
procedure LoadRecord; virtual;
procedure GetRecordData(const aMethod: TMethod; WithIndex: boolean; Index: Longint); virtual;
public
constructor Create(Hook: TPropertyEditorHook; APropCount: Integer); override;
destructor Destroy; override;
function AllEqual: Boolean; override;
function GetAttributes: TPropertyAttributes; override;
procedure GetProperties(Proc: TGetPropEditProc); override;
function GetValue: string; override;
procedure Initialize; override;
function ValueIsStreamed: boolean; override;
property HideRecordName: Boolean read FHideRecordName write FHideRecordName;
property CanReadFields: boolean read FCanReadFields;
property CanWriteFields: boolean read FCanWriteFields;
end;
{ TMethodPropertyEditor
Property editor for all method properties. }
TMethodPropertyEditor = class(TPropertyEditor)
private
function GetTrimmedEventName: shortstring;
public
function AllEqual: Boolean; override;
procedure Edit; override;
procedure ShowValue; override;
function GetAttributes: TPropertyAttributes; override;
function GetEditLimit: Integer; override;
function GetValue: ansistring; override;
procedure GetValues(Proc: TGetStrProc); override;
procedure SetValue(const NewValue: ansistring); override;
function GetFormMethodName: shortstring;
class function GetDefaultMethodName(Root, Component: TComponent;
const RootClassName, ComponentName, PropName: shortstring): shortstring;
end;
{ TComponentNamePropertyEditor
Property editor for the Name property. It restricts the name property
from being displayed when more than one component is selected. }
TComponentNamePropertyEditor = class(TStringPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
function GetEditLimit: Integer; override;
function GetValue: ansistring; override;
procedure SetValue(const NewValue: ansistring); override;
end;
{ TDatePropertyEditor
Property editor for date portion of TDateTime type. }
TDatePropertyEditor = class(TPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
function GetValue: string; override;
procedure SetValue(const Value: string); override;
end;
{ TTimePropertyEditor
Property editor for time portion of TDateTime type. }
TTimePropertyEditor = class(TPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
function GetValue: string; override;
procedure SetValue(const Value: string); override;
end;
{ TDateTimePropertyEditor
Edits both date and time data simultaneously }
TDateTimePropertyEditor = class(TPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
function GetValue: string; override;
procedure SetValue(const Value: string); override;
end;
{ TVariantPropertyEditor }
TVariantPropertyEditor = class(TPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
function GetValue: string; override;
procedure SetValue(const {%H-}Value: string); override;
procedure GetProperties({%H-}Proc:TGetPropEditProc); override;
end;
{ TModalResultPropertyEditor }
TModalResultPropertyEditor = class(TIntegerPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
function OrdValueToVisualValue(OrdValue: longint): string; override;
procedure GetValues(Proc: TGetStrProc); override;
procedure SetValue(const NewValue:ansistring); override;
end;
{ TShortCutPropertyEditor
Property editor the ShortCut property. Allows both typing in a short
cut value or picking a short-cut value from a list. }
TShortCutPropertyEditor = class(TOrdinalPropertyEditor)
public
procedure Edit; override;
function GetAttributes: TPropertyAttributes; override;
function OrdValueToVisualValue(OrdValue: longint): string; override;
procedure GetValues(Proc: TGetStrProc); override;
procedure SetValue(const Value: string); override;
end;
{ TTabOrderPropertyEditor
Property editor for the TabOrder property. Prevents the property from being
displayed when more than one component is selected. }
TTabOrderPropertyEditor = class(TIntegerPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
end;
{ TCaptionPropertyEditor
Property editor for the Caption and Text properties. Updates the value of
the property for each change instead on when the property is approved. }
TCaptionPropertyEditor = class(TStringPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
end;
{ TMenuItemCaptionEditor
MenuItem's Caption gets its own editor.
It updates the MenuItem's name when it is turned into a separator. }
TMenuItemCaptionEditor = class(TStringPropertyEditor)
public
procedure SetValue(const NewValue: ansistring); override;
end;
{ TStringMultilinePropertyEditor
PropertyEditor editor for a string property when the string can be
multiline (e.g. TLabel.Caption, TControl.Hint).
Brings up the dialog for entering text. }
TStringMultilinePropertyEditor = class(TCaptionPropertyEditor)
public
procedure Edit; override;
function GetAttributes: TPropertyAttributes; override;
end;
{ TStringsPropertyEditor
PropertyEditor editor for the TStrings properties.
Brings up a dialog with a Memo for entering text. }
TStringsPropEditorDlg = class;
TStringsPropertyEditor = class(TClassPropertyEditor)
public
procedure Edit; override;
function CreateDlg(s: TStrings): TStringsPropEditorDlg; virtual;
function GetAttributes: TPropertyAttributes; override;
end;
{ TValueListPropertyEditor
PropertyEditor editor for the TStrings property of TValueListEditor.
Brings up a dialog with a ValueListEditor for entering keys and values. }
TKeyValPropEditorDlg = class;
TValueListPropertyEditor = class(TClassPropertyEditor)
public
procedure Edit; override;
function CreateDlg(s: TStrings): TKeyValPropEditorDlg; virtual;
function GetAttributes: TPropertyAttributes; override;
end;
{ TCursorPropertyEditor
PropertyEditor editor for the TCursor properties.
Displays cursor as constant name if exists, otherwise an integer. }
TCursorPropertyEditor = class(TIntegerPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
function OrdValueToVisualValue(OrdValue: longint): string; override;
procedure GetValues(Proc: TGetStrProc); override;
procedure SetValue(const NewValue: ansistring); override;
end;
{ TFileNamePropertyEditor
PropertyEditor editor for filename properties.
Show an TOpenDialog on Edit. }
TFileNamePropertyEditor = class(TStringPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
procedure Edit; override;
function GetFilter: String; virtual;
function GetDialogOptions: TOpenOptions; virtual;
function GetDialogTitle: string; virtual;
function GetInitialDirectory: string; virtual;
procedure SetFilename(const Filename: string); virtual;
function CreateFileDialog: TOpenDialog; virtual;
end;
{ TDirectoryPropertyEditor
PropertyEditor editor for directory properties.
Show an TSelectDirectoryDialog on Edit. }
TDirectoryPropertyEditor = class(TFileNamePropertyEditor)
public
function CreateFileDialog: TOpenDialog; override;
end;
{ TURLPropertyEditor
PropertyEditor editor for URL properties.
Show an TOpenDialog on Edit. }
TURLPropertyEditor = class(TFileNamePropertyEditor)
public
procedure SetFilename(const Filename: string); override;
end;
{ TURLDirectoryPropertyEditor
PropertyEditor editor for URL properties.
Show an TOpenDialog on Edit. }
TURLDirectoryPropertyEditor = class(TURLPropertyEditor)
public
function CreateFileDialog: TOpenDialog; override;
end;
{ TFileDlgFilterProperty
PropertyEditor editor for TFileDialog filter properties.
Show a dialog on Edit. }
TFileDlgFilterProperty = class(TStringPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
procedure Edit; override;
end;
{ TSessionPropertiesPropertyEditor
PropertyEditor editor for TControl.SessionProperties properties.
Show a dialog on Edit. }
TSessionPropertiesPropertyEditor = class(TStringPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
procedure Edit; override;
end;
{ TConstraintsPropertyEditor
PropertyEditor editor for TControl.Constraints properties.
Lets a user set the current size as constraints. }
TConstraintsPropertyEditor = class(TClassPropertyEditor)
public
// These are used for the popup menu in OI
function GetVerbCount: Integer; override;
function GetVerb(Index: Integer): string; override;
procedure PrepareItem(Index: Integer; const AnItem: TMenuItem); override;
procedure ExecuteVerb(Index: Integer); override;
end;
{ TListElementPropertyEditor
A property editor for a single element of a TListPropertyEditor
This editor simply redirects all methods to the TListPropertyEditor }
TListPropertyEditor = class;
TListElementPropertyEditor = class(TNestedPropertyEditor)
private
FIndex: integer;
FList: TListPropertyEditor;
public
constructor Create(Parent: TListPropertyEditor; AnIndex: integer); overload;
destructor Destroy; override;
function GetAttributes: TPropertyAttributes; override;
function GetName:shortstring; override;
procedure GetProperties(Proc: TGetPropEditProc); override;
function GetValue: ansistring; override;
procedure GetValues(Proc: TGetStrProc); override;
procedure SetValue(const NewValue: ansistring); override;
property List: TListPropertyEditor read FList;
property TheIndex: integer read FIndex;
end;
{ TListPropertyEditor
A property editor with dynamic sub properties representing a list of objects.
The items are shown embedded in the OI and if the user presses the Edit button
as extra window to select items, which are then shown in the OI.
UNDER CONSTRUCTION by Mattias
The problem with all properties is, that we don't get notified, when something
changes. In this case, the list can change, which means the property editors
for the list elements must be deleted or created.
}
TListPropertyEditor = class(TPropertyEditor)
private
FSaveElementLock: integer;
FSubPropertiesChanged: boolean;
protected
procedure BeginSaveElement;
procedure EndSaveElement;
function IsSaving: boolean;
property SaveElementLock: integer read FSaveElementLock;
protected
// methods and variables usable for descendent property editors:
// MWE: hmm... don't like "public" objects
// TODO: change this ?
SavedList: TObject;
SavedElements: TList;
SavedPropertyEditors: TList;
function ReadElementCount: integer; virtual;
function ReadElement(Index: integer): TPersistent; virtual;
function CreateElementPropEditor(
Index: integer): TListElementPropertyEditor; virtual;
procedure DoSaveElements; virtual;
procedure FreeElementPropertyEditors; virtual;
function GetElementAttributes(
{%H-}Element: TListElementPropertyEditor): TPropertyAttributes; virtual;
function GetElementName(
{%H-}Element: TListElementPropertyEditor):shortstring; virtual;
procedure GetElementProperties({%H-}Element: TListElementPropertyEditor;
{%H-}Proc: TGetPropEditProc); virtual;
function GetElementValue(
{%H-}Element: TListElementPropertyEditor): ansistring; virtual;
procedure GetElementValues({%H-}Element: TListElementPropertyEditor;
{%H-}Proc: TGetStrProc); virtual;
procedure SetElementValue({%H-}Element: TListElementPropertyEditor;
{%H-}NewValue: ansistring); virtual;
public
constructor Create(Hook:TPropertyEditorHook; APropCount:Integer); override;
destructor Destroy; override;
function GetAttributes: TPropertyAttributes; override;
function GetElementCount: integer;
function GetElement(Index: integer): TPersistent;
function GetElement(Element: TListElementPropertyEditor): TPersistent;
function GetElementPropEditor(Index: integer): TListElementPropertyEditor;
procedure GetProperties(Proc: TGetPropEditProc); override;
function GetValue: AnsiString; override;
procedure Initialize; override;
procedure SaveElements;
function SubPropertiesNeedsUpdate: boolean; override;
end;
{ TCollectionPropertyEditor
Default property editor for all TCollections, embedded in the OI
UNDER CONSTRUCTION by Mattias}
TCollectionPropertyEditor = class(TListPropertyEditor)
private
protected
function ReadElementCount: integer; override;
function ReadElement(Index: integer): TPersistent; override;
function GetElementAttributes(
{%H-}Element: TListElementPropertyEditor): TPropertyAttributes; override;
function GetElementName(
Element: TListElementPropertyEditor):shortstring; override;
procedure GetElementProperties(Element: TListElementPropertyEditor;
Proc: TGetPropEditProc); override;
function GetElementValue(
Element: TListElementPropertyEditor): ansistring; override;
procedure GetElementValues(Element: TListElementPropertyEditor;
Proc: TGetStrProc); override;
procedure SetElementValue(Element: TListElementPropertyEditor;
NewValue: ansistring); override;
public
function GetAttributes: TPropertyAttributes; override;
procedure Edit; override;
class function ShowCollectionEditor(ACollection: TCollection;
OwnerPersistent: TPersistent; const PropName: String): TCustomForm; virtual;
end;
{ TDisabledCollectionPropertyEditor }
TDisabledCollectionPropertyEditor = class(TCollectionPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
end;
{ TNoAddDeleteCollectionPropertyEditor }
TNoAddDeleteCollectionPropertyEditor = class(TCollectionPropertyEditor)
public
class function ShowCollectionEditor(ACollection: TCollection;
OwnerPersistent: TPersistent; const PropName: String): TCustomForm; override;
end;
//==============================================================================
// Delphi Compatible Property Editor Classnames
type
TOrdinalProperty = TOrdinalPropertyEditor;
TIntegerProperty = TIntegerPropertyEditor;
TCharProperty = TCharPropertyEditor;
TEnumProperty = TEnumPropertyEditor;
TBoolProperty = TBoolPropertyEditor;
TInt64Property = TInt64PropertyEditor;
TFloatProperty = TFloatPropertyEditor;
TStringProperty = TStringPropertyEditor;
TNestedProperty = TNestedPropertyEditor;
TSetElementProperty = TSetElementPropertyEditor;
TSetProperty = TSetPropertyEditor;
TClassProperty = TClassPropertyEditor;
TMethodProperty = TMethodPropertyEditor;
TComponentProperty = TPersistentPropertyEditor;
TComponentNameProperty = TComponentNamePropertyEditor;
// TImeNameProperty = TImeNamePropertyEditor;
TCursorProperty = TCursorPropertyEditor;
TModalResultProperty = TModalResultPropertyEditor;
TShortCutProperty = TShortCutPropertyEditor;
// TMPFilenameProperty = TMPFilenamePropertyEditor;
TTabOrderProperty = TTabOrderPropertyEditor;
TCaptionProperty = TCaptionPropertyEditor;
TDateProperty = TDatePropertyEditor;
TTimeProperty = TTimePropertyEditor;
TDateTimeProperty = TDateTimePropertyEditor;
type
TSelectionEditorAttribute = (
seaFilterProperties
);
TSelectionEditorAttributes = set of TSelectionEditorAttribute;
{ TBaseSelectionEditor }
TBaseSelectionEditor = class
constructor Create({%H-}ADesigner: TIDesigner; {%H-}AHook: TPropertyEditorHook); virtual;
function GetAttributes: TSelectionEditorAttributes; virtual; abstract;
procedure FilterProperties(ASelection: TPersistentSelectionList; AProperties: TPropertyEditorList); virtual; abstract;
end;
TSelectionEditorClass = class of TBaseSelectionEditor;
TSelectionEditorClassList = specialize TFPGList<TSelectionEditorClass>;
{ TSelectionEditor }
TSelectionEditor = class(TBaseSelectionEditor)
private
FDesigner: TIDesigner;
FHook: TPropertyEditorHook;
public
constructor Create(ADesigner: TIDesigner; AHook: TPropertyEditorHook); override;
function GetAttributes: TSelectionEditorAttributes; override;
procedure FilterProperties({%H-}ASelection: TPersistentSelectionList; {%H-}AProperties: TPropertyEditorList); override;
property Designer: TIDesigner read FDesigner;
property Hook: TPropertyEditorHook read FHook;
end;
//==============================================================================
{ RegisterPropertyEditor
Registers a new property editor for the given type.
When a component is selected the Object Inspector will create a property
editor for each of the component's properties. The property editor is created
based on the type of the property. If, for example, the property type is an
Integer, the property editor for Integer will be created (by default
that would be TIntegerPropertyEditor). Most properties do not need specialized
property editors.
For example, if the property is an ordinal type the default property editor
will restrict the range to the ordinal subtype range (e.g. a property of type
TMyRange=1..10 will only allow values between 1 and 10 to be entered into the
property). Enumerated types will display a drop-down list of all the
enumerated values (e.g. TShapes = (sCircle,sSquare,sTriangle) will be edited
by a drop-down list containing only sCircle,sSquare and sTriangle).
A property editor needs only be created if default property editor or none of
the existing property editors are sufficient to edit the property. This is
typically because the property is an object.
The registered types are looked up newest to oldest.
This allows an existing property editor replaced by a custom property editor.
PropertyEditorType
The type information pointer returned by the TypeInfo built-in function
(e.g. TypeInfo(TMyRange) or TypeInfo(TShapes)).
PersistentClass
Type of the persistent object to which to restrict this type editor. This
parameter can be left nil which will mean this type editor applies to all
properties of PropertyEditorType.
PropertyEditorName
The name of the property to which to restrict this type editor. This
parameter is ignored if PersistentClass is nil. This parameter can be
an empty string ('') which will mean that this editor applies to all
properties of PropertyEditorType in PersistentClass.
editorClass
The class of the editor to be created whenever a property of the type
passed in PropertyEditorTypeInfo is displayed in the Object Inspector.
The class will be created by calling EditorClass.Create. }
procedure RegisterPropertyEditor(PropertyType: PTypeInfo;
PersistentClass: TClass; const PropertyName: shortstring;
EditorClass: TPropertyEditorClass);
type
TPropertyEditorMapperFunc=function(Obj: TPersistent;
PropInfo: PPropInfo): TPropertyEditorClass;
const
AllTypeKinds = [tkInteger..High(TTypeKind)];
procedure RegisterPropertyEditorMapper(Mapper:TPropertyEditorMapperFunc);
type
TPropertyEditorFilterFunc =
function(const ATestEditor: TPropertyEditor): Boolean of object;
TPropInfoFilterFunc =
function(const APropInfo: PPropInfo): Boolean of object;
procedure GetPersistentProperties(ASelection: TPersistentSelectionList;
AFilter: TTypeKinds; AHook: TPropertyEditorHook; AProc: TGetPropEditProc;
APropInfoFilterFunc: TPropInfoFilterFunc;
AEditorFilterFunc: TPropertyEditorFilterFunc
{$IFDEF HasExtRtti};ExtVisibility: TVisibilityClasses = []{$ENDIF});
procedure GetPersistentProperties(ASelection: TPersistentSelectionList;
AFilter: TTypeKinds; AHook: TPropertyEditorHook; AProc: TGetPropEditProc;
AEditorFilterFunc: TPropertyEditorFilterFunc);
procedure GetPersistentProperties(AItem: TPersistent;
AFilter: TTypeKinds; AHook: TPropertyEditorHook; AProc: TGetPropEditProc;
AEditorFilterFunc: TPropertyEditorFilterFunc);
function GetEditorClass(PropInfo: PPropInfo; Obj: TPersistent): TPropertyEditorClass;
function GetEditorClass(PropName: shortstring; Info: PTypeInfo; Obj: TPersistent): TPropertyEditorClass;
//==============================================================================
procedure RegisterSelectionEditor(AComponentClass: TComponentClass; AEditorClass: TSelectionEditorClass);
procedure GetSelectionEditorClasses(AComponent: TComponent; AEditorList: TSelectionEditorClassList);
procedure GetSelectionEditorClasses(ASelection: TPersistentSelectionList; AEditorList: TSelectionEditorClassList);
//==============================================================================
procedure RegisterListPropertyEditor(AnEditor: TListPropertyEditor);
procedure UnregisterListPropertyEditor(AnEditor: TListPropertyEditor);
procedure UpdateListPropertyEditors(AnObject: TObject);
type
TSelectableComponentFlag = (
scfWithoutRoot,
scfWithoutInlineChilds
);
TSelectableComponentFlags = set of TSelectableComponentFlag;
procedure GetSelectableComponents(Root: TComponent;
Flags: TSelectableComponentFlags; var ComponentList: TFPList);
//==============================================================================
{
TPropertyEditorHook
This is the interface for methods, components and objects handling of all
property editors. Just create such thing and give it the object inspector.
}
type
// lookup root
TPropHookChangeLookupRoot = procedure of object;
// methods
TPropHookCreateMethod = function(const Name: ShortString; ATypeInfo: PTypeInfo;
APersistent: TPersistent; const APropertyPath: string): TMethod of object;
TPropHookGetMethodName = function(const Method: TMethod; CheckOwner: TObject;
OrigLookupRoot: TPersistent): String of object;
TPropHookGetCompatibleMethods = procedure(InstProp: PInstProp; const Proc: TGetStrProc) of object;
TPropHookGetMethods = procedure(TypeData: PTypeData; Proc: TGetStrProc) of object;
TPropHookCompatibleMethodExists = function(const Name: String; InstProp: PInstProp;
var MethodIsCompatible,MethodIsPublished,IdentIsMethod: boolean
):boolean of object;
TPropHookMethodExists = function(const Name: String; TypeData: PTypeData;
var MethodIsCompatible,MethodIsPublished,IdentIsMethod: boolean
):boolean of object;
TPropHookRenameMethod = procedure(const CurName, NewName: String) of object;
TPropHookShowMethod = procedure(const Name: String) of object;
TPropHookMethodFromAncestor = function(const Method:TMethod):boolean of object;
TPropHookMethodFromLookupRoot = function(const Method:TMethod):boolean of object;
TPropHookChainCall = procedure(const AMethodName, InstanceName,
InstanceMethod:ShortString; TypeData:PTypeData) of object;
// components
TPropHookGetComponent = function(const ComponentPath: String):TComponent of object;
TPropHookGetComponentName = function(AComponent: TComponent):String of object;
TPropHookGetComponentNames = procedure(TypeData: PTypeData;
Proc: TGetStrProc) of object;
TPropHookGetRootClassName = function:ShortString of object;
TPropHookGetAncestorInstProp = function(const InstProp: TInstProp;
out AncestorInstProp: TInstProp): boolean of object;
TPropHookAddClicked = function(ADesigner: TIDesigner;
MouseDownComponent: TComponent; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer;
var AComponentClass: TComponentClass;
var NewParent: TComponent): boolean of object;
TPropHookBeforeAddPersistent = function(Sender: TObject;
APersistentClass: TPersistentClass;
Parent: TPersistent): boolean of object;
TPropHookComponentRenamed = procedure(AComponent: TComponent) of object;
TPropHookPersistentAdded = procedure(APersistent: TPersistent; Select: boolean
) of object;
TPropHookPersistentDel = procedure(APersistent: TPersistent) of object;
TPropHookDeletePersistent = procedure(var APersistent: TPersistent) of object;
TPropHookGetSelection = procedure(const ASelection: TPersistentSelectionList
) of object;
TPropHookSetSelection = procedure(const ASelection: TPersistentSelectionList
) of object;
TPropHookAddDependency = procedure(const AClass: TClass;
const AnUnitName: shortstring) of object;
// persistent objects
TPropHookGetObject = function(const Name:ShortString):TPersistent of object;
TPropHookGetObjectName = function(Instance:TPersistent):ShortString of object;
TPropHookGetObjectNames = procedure(TypeData:PTypeData;
Proc: TGetStrProc) of object;
TPropHookObjectPropertyChanged = procedure(Sender: TObject;
NewObject: TPersistent) of object;
// modifing
TPropHookModified = procedure(Sender: TObject) of object;
TPropHookModifiedWithName = procedure(Sender: TObject; PropName: ShortString) of object;
TPropHookRevert = procedure(Instance:TPersistent; PropInfo:PPropInfo) of object;
TPropHookRefreshPropertyValues = procedure of object;
// other
TPropHookGetCheckboxForBoolean = procedure(var Value: Boolean) of object;
TPropHookType = (
// lookup root
htChangeLookupRoot,
// methods
htCreateMethod,
htGetMethodName,
htGetCompatibleMethods,
htGetMethods,
htCompatibleMethodExists,
htMethodExists,
htRenameMethod,
htShowMethod,
htMethodFromAncestor,
htMethodFromLookupRoot,
htChainCall,
// components
htGetComponent,
htGetComponentName,
htGetComponentNames,
htGetRootClassName,
htGetAncestorInstProp,
htAddClicked, // user selected a component class and clicked on a form to add a component
htComponentRenamed,
// persistent selection
htBeforeAddPersistent,
htPersistentAdded,
htPersistentDeleting,
htPersistentDeleted,
htDeletePersistent,
htGetSelectedPersistents,
htSetSelectedPersistents,
// persistent objects
htGetObject,
htGetObjectName,
htGetObjectNames,
htObjectPropertyChanged,
// modifing
htModified,
htModifiedWithName,
htRevert,
htRefreshPropertyValues,
// dependencies
htAddDependency,
// designer
htDesignerMouseDown,
htDesignerMouseUp,
// other
htGetCheckboxForBoolean
);
{ TPropertyEditorHook }
TPropertyEditorHook = class(TComponent)
private
FComponentPropertyOnlyDesign: boolean;
FHandlers: array[TPropHookType] of TMethodList;
// lookup root
FLookupRoot: TPersistent;
procedure SetLookupRoot(APersistent: TPersistent);
procedure AddHandler(HookType: TPropHookType; const Handler: TMethod);
procedure RemoveHandler(HookType: TPropHookType; const Handler: TMethod);
function GetHandlerCount(HookType: TPropHookType): integer;
function GetNextHandlerIndex(HookType: TPropHookType;
var i: integer): boolean;
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
public
GetPrivateDirectory: AnsiString;
destructor Destroy; override;
// lookup root
property LookupRoot: TPersistent read FLookupRoot write SetLookupRoot;
// methods
function CreateMethod(const aName: ShortString; ATypeInfo:PTypeInfo;
APersistent: TPersistent;
const APropertyPath: string): TMethod;
function GetMethodName(const Method: TMethod; PropOwner: TObject): String;
procedure GetMethods(TypeData: PTypeData; const Proc: TGetStrProc);
procedure GetCompatibleMethods(InstProp: PInstProp; const Proc: TGetStrProc);
function MethodExists(const aName: String; TypeData: PTypeData;
var MethodIsCompatible,MethodIsPublished,IdentIsMethod: boolean):boolean;
function CompatibleMethodExists(const aName: String; InstProp: PInstProp;
out MethodIsCompatible,MethodIsPublished,IdentIsMethod: boolean):boolean;
procedure RenameMethod(const CurName, NewName: String);
procedure ShowMethod(const aName: String);
function MethodFromAncestor(const Method: TMethod): boolean;
function MethodFromLookupRoot(const Method: TMethod): boolean;
procedure ChainCall(const AMethodName, InstanceName,
InstanceMethod: ShortString; TypeData: PTypeData);
// components
function GetComponent(const ComponentPath: string): TComponent;
function GetComponentName(AComponent: TComponent): String;
procedure GetComponentNames(TypeData: PTypeData; const Proc: TGetStrProc);
function GetRootClassName: ShortString;
function GetAncestorInstance(const InstProp: TInstProp;
out AncestorInstProp: TInstProp): boolean;
function AddClicked(ADesigner: TIDesigner;
MouseDownComponent: TComponent; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer;
var AComponentClass: TComponentClass;
var NewParent: TComponent): boolean;
function BeforeAddPersistent(Sender: TObject;
APersistentClass: TPersistentClass;
Parent: TPersistent): boolean;
procedure ComponentRenamed(AComponent: TComponent);
procedure PersistentAdded(APersistent: TPersistent; Select: boolean);
procedure PersistentDeleting(APersistent: TPersistent);
procedure PersistentDeleted(APersistent: TPersistent);
procedure DeletePersistent(var APersistent: TPersistent);
procedure GetSelection(const ASelection: TPersistentSelectionList);
procedure SetSelection(const ASelection: TPersistentSelectionList);
procedure Unselect(const APersistent: TPersistent);
function IsSelected(const APersistent: TPersistent): boolean;
procedure SelectOnlyThis(const APersistent: TPersistent);
procedure DesignerMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure DesignerMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
// persistent objects
function GetObject(const aName: ShortString): TPersistent;
function GetObjectName(Instance: TPersistent; AOwnerComp: TComponent): String;
procedure GetObjectNames(TypeData: PTypeData; const Proc: TGetStrProc);
procedure ObjectReferenceChanged(Sender: TObject; NewObject: TPersistent);
// modifing
procedure Modified(Sender: TObject; PropName: ShortString = '');
procedure Revert(Instance: TPersistent; PropInfo: PPropInfo);
procedure RefreshPropertyValues;
property ComponentPropertyOnlyDesign: boolean read FComponentPropertyOnlyDesign write FComponentPropertyOnlyDesign;
// dependencies
procedure AddDependency(const AClass: TClass; const AnUnitname: shortstring);
// other
function GetCheckboxForBoolean: Boolean;
public
// Handlers
procedure RemoveAllHandlersForObject(const HandlerObject: TObject);
// lookup root
procedure AddHandlerChangeLookupRoot(
const OnChangeLookupRoot: TPropHookChangeLookupRoot);
procedure RemoveHandlerChangeLookupRoot(
const OnChangeLookupRoot: TPropHookChangeLookupRoot);
// method events
procedure AddHandlerCreateMethod(const OnCreateMethod: TPropHookCreateMethod);
procedure RemoveHandlerCreateMethod(const OnCreateMethod: TPropHookCreateMethod);
procedure AddHandlerGetMethodName(const OnGetMethodName: TPropHookGetMethodName);
procedure RemoveHandlerGetMethodName(const OnGetMethodName: TPropHookGetMethodName);
procedure AddHandlerGetCompatibleMethods(
const OnGetMethods: TPropHookGetCompatibleMethods);
procedure RemoveHandlerGetCompatibleMethods(
const OnGetMethods: TPropHookGetCompatibleMethods);
procedure AddHandlerGetMethods(const OnGetMethods: TPropHookGetMethods);
procedure RemoveHandlerGetMethods(const OnGetMethods: TPropHookGetMethods);
procedure AddHandlerCompatibleMethodExists(
const OnMethodExists: TPropHookCompatibleMethodExists);
procedure RemoveHandlerCompatibleMethodExists(
const OnMethodExists: TPropHookCompatibleMethodExists);
procedure AddHandlerMethodExists(const OnMethodExists: TPropHookMethodExists);
procedure RemoveHandlerMethodExists(const OnMethodExists: TPropHookMethodExists);
procedure AddHandlerRenameMethod(const OnRenameMethod: TPropHookRenameMethod);
procedure RemoveHandlerRenameMethod(const OnRenameMethod: TPropHookRenameMethod);
procedure AddHandlerShowMethod(const OnShowMethod: TPropHookShowMethod);
procedure RemoveHandlerShowMethod(const OnShowMethod: TPropHookShowMethod);
procedure AddHandlerMethodFromAncestor(
const OnMethodFromAncestor: TPropHookMethodFromAncestor);
procedure RemoveHandlerMethodFromAncestor(
const OnMethodFromAncestor: TPropHookMethodFromAncestor);
procedure AddHandlerMethodFromLookupRoot(
const OnMethodFromLookupRoot: TPropHookMethodFromLookupRoot);
procedure RemoveHandlerMethodFromLookupRoot(
const OnMethodFromLookupRoot: TPropHookMethodFromLookupRoot);
procedure AddHandlerChainCall(const OnChainCall: TPropHookChainCall);
procedure RemoveHandlerChainCall(const OnChainCall: TPropHookChainCall);
// component event
procedure AddHandlerGetComponent(const OnGetComponent: TPropHookGetComponent);
procedure RemoveHandlerGetComponent(const OnGetComponent: TPropHookGetComponent);
procedure AddHandlerGetComponentName(
const OnGetComponentName: TPropHookGetComponentName);
procedure RemoveHandlerGetComponentName(
const OnGetComponentName: TPropHookGetComponentName);
procedure AddHandlerGetComponentNames(
const OnGetComponentNames: TPropHookGetComponentNames);
procedure RemoveHandlerGetComponentNames(
const OnGetComponentNames: TPropHookGetComponentNames);
procedure AddHandlerAddClicked(const Handler: TPropHookAddClicked);
procedure RemoveHandlerAddClicked(const Handler: TPropHookAddClicked);
procedure AddHandlerGetRootClassName(
const OnGetRootClassName: TPropHookGetRootClassName);
procedure RemoveHandlerGetRootClassName(
const OnGetRootClassName: TPropHookGetRootClassName);
procedure AddHandlerGetAncestorInstProp(
const OnGetAncestorInstProp: TPropHookGetAncestorInstProp);
procedure RemoveHandlerGetAncestorInstProp(
const OnGetAncestorInstProp: TPropHookGetAncestorInstProp);
procedure AddHandlerDesignerMouseDown(const OnMouseDown: TMouseEvent);
procedure RemoveHandlerDesignerMouseDown(const OnMouseDown: TMouseEvent);
procedure AddHandlerDesignerMouseUp(const OnMouseUp: TMouseEvent);
procedure RemoveHandlerDesignerMouseUp(const OnMouseUp: TMouseEvent);
// component create, delete, rename
procedure AddHandlerComponentRenamed(
const OnComponentRenamed: TPropHookComponentRenamed);
procedure RemoveHandlerComponentRenamed(
const OnComponentRenamed: TPropHookComponentRenamed);
procedure AddHandlerBeforeAddPersistent(
const OnBeforeAddPersistent: TPropHookBeforeAddPersistent);
procedure RemoveHandlerBeforeAddPersistent(
const OnBeforeAddPersistent: TPropHookBeforeAddPersistent);
procedure AddHandlerPersistentAdded(
const OnPersistentAdded: TPropHookPersistentAdded);
procedure RemoveHandlerPersistentAdded(
const OnPersistentAdded: TPropHookPersistentAdded);
procedure AddHandlerPersistentDeleting(
const OnPersistentDeleting: TPropHookPersistentDel);
procedure RemoveHandlerPersistentDeleting(
const OnPersistentDeleting: TPropHookPersistentDel);
procedure AddHandlerPersistentDeleted(
const OnPersistentDeleted: TPropHookPersistentDel);
procedure RemoveHandlerPersistentDeleted(
const OnPersistentDeleted: TPropHookPersistentDel);
procedure AddHandlerDeletePersistent(
const OnDeletePersistent: TPropHookDeletePersistent);
procedure RemoveHandlerDeletePersistent(
const OnDeletePersistent: TPropHookDeletePersistent);
// persistent selection
procedure AddHandlerGetSelection(const OnGetSelection: TPropHookGetSelection);
procedure RemoveHandlerGetSelection(const OnGetSelection: TPropHookGetSelection);
procedure AddHandlerSetSelection(const OnSetSelection: TPropHookSetSelection);
procedure RemoveHandlerSetSelection(const OnSetSelection: TPropHookSetSelection);
// persistent object events
procedure AddHandlerGetObject(const OnGetObject: TPropHookGetObject);
procedure RemoveHandlerGetObject(const OnGetObject: TPropHookGetObject);
procedure AddHandlerGetObjectName(const OnGetObjectName: TPropHookGetObjectName);
procedure RemoveHandlerGetObjectName(const OnGetObjectName: TPropHookGetObjectName);
procedure AddHandlerGetObjectNames(const OnGetObjectNames: TPropHookGetObjectNames);
procedure RemoveHandlerGetObjectNames(const OnGetObjectNames: TPropHookGetObjectNames);
procedure AddHandlerObjectPropertyChanged(
const OnObjectPropertyChanged: TPropHookObjectPropertyChanged);
procedure RemoveHandlerObjectPropertyChanged(
const OnObjectPropertyChanged: TPropHookObjectPropertyChanged);
// modifing events
procedure AddHandlerModified(const OnModified: TPropHookModified);
procedure RemoveHandlerModified(const OnModified: TPropHookModified);
procedure AddHandlerModifiedWithName(const OnModified: TPropHookModifiedWithName);
procedure RemoveHandlerModifiedWithName(const OnModified: TPropHookModifiedWithName);
procedure AddHandlerRevert(const OnRevert: TPropHookRevert);
procedure RemoveHandlerRevert(const OnRevert: TPropHookRevert);
procedure AddHandlerRefreshPropertyValues(
const OnRefreshPropertyValues: TPropHookRefreshPropertyValues);
procedure RemoveHandlerRefreshPropertyValues(
const OnRefreshPropertyValues: TPropHookRefreshPropertyValues);
procedure AddHandlerAddDependency(const OnAddDependency: TPropHookAddDependency);
procedure RemoveHandlerAddDependency(const OnAddDependency: TPropHookAddDependency);
procedure AddHandlerGetCheckboxForBoolean(
const OnGetCheckboxForBoolean: TPropHookGetCheckboxForBoolean);
end;
//==============================================================================
{ TPropInfoList }
type
TPropInfoList = class
private
FList: PPropList;
FCount: Integer;
{$IFDEF HasExtRtti}
FExtVisibility: TVisibilityClasses;
FListExt: PPropListEx;
function GetExt(Index: Integer): PPropInfoEx;
{$ENDIF}
function Get(Index: Integer): PPropInfo;
public
constructor Create(Instance: TPersistent; Filter: TTypeKinds);
{$IFDEF HasExtRtti}
constructor Create(Instance: TPersistent; Filter: TTypeKinds; AddExtVisibility: TVisibilityClasses);
{$ENDIF}
destructor Destroy; override;
function Contains(P: PPropInfo): Boolean;
procedure Delete(Index: Integer);
procedure Intersect(List: TPropInfoList);
procedure Sort;
property Count: Integer read FCount;
property Items[Index: Integer]: PPropInfo read Get; default;
{$IFDEF HasExtRtti}
property ExtVisibility: TVisibilityClasses read FExtVisibility;
property Ext[Index: Integer]: PPropInfoEx read GetExt;
{$ENDIF}
end;
//==============================================================================
type
TStringsPropEditorDlg = class(TStringsPropEditorFrm)
public
Editor: TPropertyEditor;
end;
TKeyValPropEditorDlg = class(TKeyValPropEditorFrm)
public
Editor: TPropertyEditor;
end;
TPagesPropEditorDlg = class(TPagesPropEditorFrm)
public
Editor: TPropertyEditor;
end;
{ TCustomShortCutGrabBox }
TCustomShortCutGrabBox = class(TCustomPanel)
private
FAllowedShifts: TShiftState;
FGrabButton: TButton;
FMainOkButton: TCustomButton;
FKey: Word;
FKeyComboBox: TComboBox;
FShiftButtons: TShiftState;
FShiftState: TShiftState;
FCheckBoxes: array[TShiftStateEnum] of TCheckBox;
FGrabForm: TForm;
function GetKey: Word;
function GetShiftCheckBox(Shift: TShiftStateEnum): TCheckBox;
procedure SetAllowedShifts(const AValue: TShiftState);
procedure SetKey(const AValue: Word);
procedure SetShiftButtons(const AValue: TShiftState);
procedure SetShiftState(const AValue: TShiftState);
// Event handlers
procedure GrabButtonClick(Sender: TObject);
procedure ShiftCheckBoxClick(Sender: TObject);
procedure GrabFormKeyDown(Sender: TObject; var AKey: Word; AShift: TShiftState);
procedure KeyComboboxEditingDone(Sender: TObject);
protected
procedure Loaded; override;
procedure RealSetText(const {%H-}Value: TCaption); override;
procedure UpdateShiftButtons;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
function ShiftToStr(s: TShiftStateEnum): string;
public
constructor Create(TheOwner: TComponent); override;
function GetDefaultShiftButtons: TShiftState;
property ShiftState: TShiftState read FShiftState write SetShiftState;
property Key: Word read GetKey write SetKey;
property ShiftButtons: TShiftState read FShiftButtons write SetShiftButtons;
property AllowedShifts: TShiftState read FAllowedShifts write SetAllowedShifts;
property KeyComboBox: TComboBox read FKeyComboBox;
property GrabButton: TButton read FGrabButton;
property MainOkButton: TCustomButton read FMainOkButton write FMainOkButton;
property ShiftCheckBox[Shift: TShiftStateEnum]: TCheckBox read GetShiftCheckBox;
end;
{ TShortCutGrabBox }
TShortCutGrabBox = class(TCustomShortCutGrabBox)
published
property Align;
property Alignment;
property AllowedShifts;
property Anchors;
property AutoSize;
property BevelInner;
property BevelOuter;
property BevelWidth;
property BorderSpacing;
property BorderStyle;
property BorderWidth;
property Caption;
property ChildSizing;
property ClientHeight;
property ClientWidth;
property Color;
property Constraints;
property DockSite;
property DragCursor;
property DragKind;
property DragMode;
property Enabled;
property Font;
property FullRepaint;
property Key;
property OnClick;
property OnDblClick;
property OnDockDrop;
property OnDockOver;
property OnDragDrop;
property OnDragOver;
property OnEndDock;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnGetDockCaption;
property OnGetSiteInfo;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnResize;
property OnStartDock;
property OnStartDrag;
property OnUnDock;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShiftButtons;
property ShiftState;
property ShowHint;
property TabOrder;
property TabStop;
property UseDockManager default True;
property Visible;
end;
//==============================================================================
// Global flags:
var
GReferenceExpandable: Boolean = true;
GShowReadOnlyProps: Boolean = true;
// default Hook - set by IDE
var
GlobalDesignHook: TPropertyEditorHook;
function ClassTypeInfo(Value: TClass): PTypeInfo;
function GetClassUnitName(Value: TClass): string;
procedure CreateComponentEvent(AComponent: TComponent; const EventName: string);
function ClassNameToComponentName(const AClassName: string): string;
function ControlAcceptsStreamableChildComponent(aControl: TWinControl;
aComponentClass: TComponentClass; aLookupRoot: TPersistent): boolean;
procedure LazSetMethodProp(Instance : TObject;PropInfo : PPropInfo; Value : TMethod);
procedure WritePublishedProperties(Instance: TPersistent);
procedure EditCollection(AComponent: TComponent; ACollection: TCollection; APropName: String);
procedure EditCollectionNoAddDel(AComponent: TComponent; ACollection: TCollection; APropName: String);
// Returns true if given property should be displayed on the property list
// filtered by AFilter and APropNameFilter.
function IsInteresting(AEditor: TPropertyEditor;
const AFilter: TTypeKinds; const APropNameFilter: String): Boolean;
function GetOrdField(Field: Pointer; FieldInfo: PTypeInfo): Int64; overload;
procedure SetOrdField(Field: Pointer; FieldInfo: PTypeInfo; Value: Int64); overload;
function GetEnumField(Field: Pointer; FieldInfo: PTypeInfo): String; overload;
procedure SetEnumField(Field: Pointer; FieldInfo: PTypeInfo; const Value: string); overload;
function GetSetField(Field: Pointer; FieldInfo: PTypeInfo; Brackets: Boolean): String; overload;
procedure SetSetField(Field: Pointer; FieldInfo: PTypeInfo; const Value: string); overload;
function GetStringField(Field: Pointer; FieldInfo: PTypeInfo): String; overload;
procedure SetStringField(Field: Pointer; FieldInfo: PTypeInfo; const Value: string); overload;
function GetWideStringField(Field: Pointer; FieldInfo: PTypeInfo): WideString; overload;
procedure SetWideStringField(Field: Pointer; FieldInfo: PTypeInfo; const Value: WideString); overload;
function GetUnicodeStringField(Field: Pointer; FieldInfo: PTypeInfo): UnicodeString; overload;
procedure SetUnicodeStringField(Field: Pointer; FieldInfo: PTypeInfo; const Value: UnicodeString); overload;
function GetRawbyteStringField(Field: Pointer; FieldInfo: PTypeInfo): RawByteString; overload;
procedure SetRawbyteStringField(Field: Pointer; FieldInfo: PTypeInfo; const Value: RawByteString); overload;
function GetFloatField(Field: Pointer; FieldInfo: PTypeInfo): Extended; overload;
procedure SetFloatField(Field: Pointer; FieldInfo: PTypeInfo; const Value: Extended); overload;
function GetObjectField(Field: Pointer; FieldInfo: PTypeInfo; MinClass: TClass = nil): TObject; overload;
procedure SetObjectField(Field: Pointer; FieldInfo: PTypeInfo; const Value: TObject); overload;
function GetPointerField(Field: Pointer; FieldInfo: PTypeInfo): Pointer; overload;
procedure SetPointerField(Field: Pointer; FieldInfo: PTypeInfo; const Value: Pointer); overload;
function GetMethodField(Field: Pointer; FieldInfo: PTypeInfo): TMethod; overload;
procedure SetMethodField(Field: Pointer; FieldInfo: PTypeInfo; const Value: TMethod); overload;
function GetInterfaceField(Field: Pointer; FieldInfo: PTypeInfo): IInterface; overload;
procedure SetInterfaceField(Field: Pointer; FieldInfo: PTypeInfo; const Value: IInterface); overload;
function GetVariantField(Field: Pointer; FieldInfo: PTypeInfo): Variant; overload;
procedure SetVariantField(Field: Pointer; FieldInfo: PTypeInfo; const Value: Variant); overload;
Function GetPointerProp(Instance: TObject; PropInfo: PPropInfo): Pointer; overload;
Procedure SetPointerProp(Instance: TObject; PropInfo: PPropInfo; Value: Pointer); overload;
function dbgs(peh: TPropEditHint): string; overload;
const
NoDefaultValue = Longint($80000000); // magic number for properties with nodefault modifier
implementation
var
ListPropertyEditors: TList = nil;
VirtualKeyStrings: TStringHashList = nil;
procedure RegisterListPropertyEditor(AnEditor: TListPropertyEditor);
begin
if ListPropertyEditors=nil then
ListPropertyEditors:=TList.Create;
ListPropertyEditors.Add(AnEditor);
end;
procedure UnregisterListPropertyEditor(AnEditor: TListPropertyEditor);
begin
if ListPropertyEditors=nil then exit;
ListPropertyEditors.Remove(AnEditor);
end;
procedure UpdateListPropertyEditors(AnObject: TObject);
var
i: integer;
Editor: TListPropertyEditor;
begin
if ListPropertyEditors=nil then exit;
for i:=0 to ListPropertyEditors.Count-1 do begin
Editor:=TListPropertyEditor(ListPropertyEditors[i]);
if (Editor.GetComponent(0)=AnObject)
and (Editor.OnSubPropertiesChanged<>nil) then
Editor.UpdateSubProperties;
end;
end;
type
{ TSelectableComponentEnumerator }
TSelectableComponentEnumerator = class(TComponent)
public
List: TFPList;
Flags: TSelectableComponentFlags;
Root: TComponent;
procedure GetSelectableComponents(ARoot: TComponent);
procedure Gather(Child: TComponent);
end;
{ TSelectionEditor }
constructor TSelectionEditor.Create(ADesigner: TIDesigner;
AHook: TPropertyEditorHook);
begin
inherited Create(ADesigner, AHook);
FDesigner := ADesigner;
FHook := AHook;
end;
function TSelectionEditor.GetAttributes: TSelectionEditorAttributes;
begin
Result := [];
end;
procedure TSelectionEditor.FilterProperties(
ASelection: TPersistentSelectionList; AProperties: TPropertyEditorList);
begin
end;
{ TBaseSelectionEditor }
constructor TBaseSelectionEditor.Create(ADesigner: TIDesigner;
AHook: TPropertyEditorHook);
begin
end;
{ TPagesPropertyEditor }
procedure TPagesPropertyEditor.AssignItems(OldItmes, NewItems: TStrings);
var
Unchanged, Index, PageIndex: Integer;
DummyNotebook: TNotebook;
APage: TPage;
PageComponent: TPersistent;
NoteBook: TNoteBook;
begin
// search for unchanged pages
Unchanged := 0;
while (Unchanged < NewItems.Count) and (Unchanged < OldItmes.Count)
and (NewItems.Objects[Unchanged] = OldItmes.Objects[Unchanged])
and (NewItems[Unchanged] = TPage(OldItmes.Objects[Unchanged]).Name) do
Inc(Unchanged);
if (Unchanged = OldItmes.Count) and (Unchanged = NewItems.Count) then Exit;
NoteBook := TNotebook(FOwnerComponent);
DummyNotebook := TNotebook.Create(nil);
try
// move all unused/changed pages to dummy
for Index := OldItmes.Count - 1 downto Unchanged do
begin
APage := TPage(OldItmes.Objects[Index]);
APage.Parent := DummyNotebook;
end;
// add NewItems or changed pages to notebook
for Index := Unchanged to NewItems.Count - 1 do
begin
if Assigned(NewItems.Objects[Index]) then begin
APage := TPage(NewItems.Objects[Index]);
end else begin
PageIndex := NoteBook.Pages.Add(NewItems[Index]);
APage := TPage(NoteBook.Pages.Objects[PageIndex]);
end;
APage.Parent := NoteBook;
if IsValidIdent(NewItems[Index]) then APage.Name := NewItems[Index];
APage.Caption := NewItems[Index];
PropertyHook.PersistentAdded(APage, False);
end;
// delete all unused OldItmes pages
for Index := DummyNotebook.PageCount - 1 downto 0 do
begin
APage := TPage(DummyNotebook.Pages.Objects[Index]);
APage.Parent := nil;;
DummyNotebook.Pages.Delete(Index);
PageComponent := TPersistent(APage);
PropertyHook.DeletePersistent(PageComponent);
end;
finally
DummyNotebook.Free;
end;
end;
procedure TPagesPropertyEditor.Edit;
var
TheDialog: TPagesPropEditorDlg;
Old, New: TStrings;
begin
Old := TStrings(GetObjectValue);
TheDialog := CreateDlg(Old);
try
if (TheDialog.ShowModal = mrOK) then begin
New := TheDialog.ListBox.Items;
AssignItems(Old, TheDialog.ListBox.Items);
SetPtrValue(New);
end;
finally
TheDialog.Free;
end;
end;
function TPagesPropertyEditor.CreateDlg(s: TStrings): TPagesPropEditorDlg;
begin
Result := TPagesPropEditorDlg.Create(Application);
Result.Editor := Self;
Result.ListBox.Items.Assign(s);
end;
function TPagesPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paDialog, paRevertable, paReadOnly];
end;
{ TRecordPropertyEditor }
procedure TRecordPropertyEditor.LoadRecord;
var
PropInfo: PPropInfo;
Instance: TPersistent;
AMethod: TMethod;
begin
if FRecordData=nil then
raise EPropertyError.CreateFmt(SErrCannotReadProperty, [GetName]);
PropInfo:=GetPropInfo;
Instance:=FPropList^[0].Instance;
if (PropInfo=nil) or (Instance=nil) then
raise EPropertyError.CreateFmt(SErrCannotReadProperty, [GetName]);
case (PropInfo^.PropProcs) and 3 of
ptField: ;
ptStatic,
ptVirtual:
begin
if (PropInfo^.PropProcs and 3)=ptStatic then
AMethod.Code:=PropInfo^.GetProc
else
AMethod.Code:=PCodePointer(Pointer(Instance.ClassType)+{%H-}PtrUInt(PropInfo^.GetProc))^;
AMethod.Data:=Instance;
if ((PropInfo^.PropProcs shr 6) and 1)<>0 then begin
GetRecordData(AMethod,true,PropInfo^.Index);
end else begin
GetRecordData(AMethod,false,0);
end;
end;
else
raise EPropertyError.CreateFmt(SErrCannotReadProperty, [GetName]);
end;
end;
procedure TRecordPropertyEditor.GetRecordData(const aMethod: TMethod; WithIndex: boolean;
Index: Longint);
begin
raise EPropertyError.CreateFmt(SErrCannotReadProperty, [GetName]);
if aMethod.Code<>nil then ;
if WithIndex and (Index>=0) then ;
end;
constructor TRecordPropertyEditor.Create(Hook: TPropertyEditorHook; APropCount: Integer);
begin
inherited Create(Hook, APropCount);
end;
destructor TRecordPropertyEditor.Destroy;
begin
if FReadAccess in [ptStatic,ptVirtual] then
ReAllocMem(FRecordData,0);
inherited Destroy;
end;
function TRecordPropertyEditor.AllEqual: Boolean;
begin
Result:=True; // ToDo: Maybe all sub-properties should be compared for equality.
end;
function TRecordPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [{paMultiSelect, }paSubProperties, paReadOnly];
end;
procedure TRecordPropertyEditor.GetProperties(Proc: TGetPropEditProc);
{$IFDEF HasExtRtti}
var
PropInfo: PPropInfo;
aTypeData: PTypeData;
i: Integer;
FieldTypeInfo: PTypeInfo;
FieldCnt: LongInt;
Editor: TPropertyEditor;
Instance: TPersistent;
FieldList: PExtendedFieldInfoTable;
Field: PExtendedVmtFieldEntry;
EdClass: TPropertyEditorClass;
{$ENDIF}
begin
{$IFDEF HasExtRtti}
Instance:=FPropList^[0].Instance;
PropInfo:=GetPropInfo;
if PropInfo=nil then
exit;
aTypeData:=GetTypeData(PropInfo^.PropType);
FieldCnt:=GetFieldList(PropInfo^.PropType,FieldList,[vcPublic,vcPublished]);
// create field editors
if CanReadFields then begin
if FRecordData=nil then
case (PropInfo^.PropProcs) and 3 of
ptField:
// direct access
FRecordData:=PByte(Instance)+{%H-}PtrUInt(PropInfo^.GetProc);
else
// local cache
FRecordData:=AllocMem(aTypeData^.RecSize);
end;
for i:=0 to FieldCnt-1 do begin
Field:=FieldList^[i];
FieldTypeInfo:=Field^.FieldType^;
EdClass:=GetEditorClass('',FieldTypeInfo,nil);
Editor := EdClass.Create(PropertyHook,1);
Editor.SetRecordFieldEntry(0, PByte(FRecordData)+Field^.FieldOffset, Field^.Name, FieldTypeInfo);
Editor.Initialize;
if ((PropCount > 1) and not (paMultiSelect in Editor.GetAttributes))
or not Editor.ValueAvailable
then begin
Editor.Free;
end else begin
Proc(Editor);
end;
end;
end;
{$ELSE}
if Proc<>nil then ;
{$ENDIF}
end;
function TRecordPropertyEditor.GetValue: string;
begin
if FHideRecordName then
Result:=''
else
Result:='(' + GetPropType^.Name + ')';
end;
procedure TRecordPropertyEditor.Initialize;
var
PropInfo: PPropInfo;
begin
inherited Initialize;
PropInfo:=GetPropInfo;
if PropInfo=nil then
exit;
// check read and write access
FReadAccess:=(PropInfo^.PropProcs) and 3;
FCanReadFields:=FReadAccess in [ptField{,ptStatic,ptVirtual}];
FWriteAccess:=(PropInfo^.PropProcs shr 2) and 3;
FCanWriteFields:=FWriteAccess=ptField;
end;
function TRecordPropertyEditor.ValueIsStreamed: boolean;
begin
Result:=false;
end;
{ TSelectableComponentEnumerator }
procedure TSelectableComponentEnumerator.GetSelectableComponents(
ARoot: TComponent);
begin
Root:=ARoot;
if List=nil then
List:=TFPList.Create;
if Root=nil then exit;
if not (scfWithoutRoot in Flags) then List.Add(Root);
TSelectableComponentEnumerator(Root).GetChildren(@Gather,Root);
end;
procedure TSelectableComponentEnumerator.Gather(Child: TComponent);
var
OldRoot: TComponent;
begin
if not ((Child is TControl)
and (csNoDesignSelectable in TControl(Child).ControlStyle))
then
List.Add(Child);
OldRoot:=Root;
try
if csInline in Child.ComponentState then begin
if scfWithoutInlineChilds in Flags then exit;
if (Child is TControl)
and (csOwnedChildrenNotSelectable in TControl(Child).ControlStyle) then
exit;
Root:=Child;
end;
TSelectableComponentEnumerator(Child).GetChildren(@Gather,Root);
finally
Root:=OldRoot;
end;
end;
procedure GetSelectableComponents(Root: TComponent;
Flags: TSelectableComponentFlags; var ComponentList: TFPList);
var
e: TSelectableComponentEnumerator;
begin
e:=TSelectableComponentEnumerator.Create(nil);
try
e.List:=ComponentList;
e.Flags:=Flags;
e.GetSelectableComponents(Root);
ComponentList:=e.List;
finally
e.Free;
end;
end;
procedure LazSetMethodProp(Instance: TObject; PropInfo: PPropInfo;
Value: TMethod);
type
PMethod = ^TMethod;
TSetMethodProcIndex=procedure(index:longint;p:TMethod) of object;
TSetMethodProc=procedure(p:TMethod) of object;
var
AMethod : TMethod;
begin
case (PropInfo^.PropProcs shr 2) and 3 of
ptfield:
PMethod(Pointer(Instance)+{%H-}PtrUInt(PropInfo^.SetProc))^ := Value;
ptstatic,
ptvirtual :
begin
if ((PropInfo^.PropProcs shr 2) and 3)=ptStatic then
AMethod.Code:=PropInfo^.SetProc
else
AMethod.Code:=PPointer(Pointer(Instance.ClassType)+{%H-}PtrUInt(PropInfo^.SetProc))^;
AMethod.Data:=Instance;
if (Value.Code=nil) and (Value.Data<>nil) then begin
// this is a fake method
// Comparing fake methods with OldValue=NewValue results always in
// true. Therefore this will fail:
// if FMethod=NewValue then exit;
// FMethod:=NewValue;
// Change the method two times
try
Value.Code:=Pointer(1);
if ((PropInfo^.PropProcs shr 6) and 1)<>0 then
TSetMethodProcIndex(AMethod)(PropInfo^.Index,Value)
else
TSetMethodProc(AMethod)(Value);
except
end;
Value.Code:=nil;
end;
if ((PropInfo^.PropProcs shr 6) and 1)<>0 then
TSetMethodProcIndex(AMethod)(PropInfo^.Index,Value)
else
TSetMethodProc(AMethod)(Value);
end;
end;
end;
// -----------------------------------------------------------
procedure WritePublishedProperties(Instance: TPersistent);
var
TypeInfo: PTypeInfo;
TypeData: PTypeData;
PropInfo: PPropInfo;
PropData: ^TPropData;
CurCount: integer;
begin
TypeInfo:=Instance.ClassInfo;
TypeData:=GetTypeData(TypeInfo);
debugln('WritePublishedProperties Instance=',DbgS(Instance),' ',Instance.ClassName,' TypeData^.PropCount=',dbgs(TypeData^.PropCount));
if Instance is TComponent then
debugln(' TComponent(Instance).Name=',TComponent(Instance).Name);
// read all properties and remove doubles
TypeInfo:=Instance.ClassInfo;
repeat
// read all property infos of current class
TypeData:=GetTypeData(TypeInfo);
// skip unitname
PropData:=AlignToPtr(PByte(@TypeData^.UnitName)+Length(TypeData^.UnitName)+1);
// read property count
CurCount:=PWord(PropData)^;
PropInfo:=PPropInfo(@PropData^.PropList);
debugln(' UnitName=',TypeData^.UnitName,' Type=',TypeInfo^.Name,' CurPropCount=',dbgs(CurCount));
{writeln('TPropInfoList.Create D ',CurCount,' TypeData^.ClassType=',DbgS(TypeData^.ClassType));
writeln('TPropInfoList.Create E ClassName="',TypeData^.ClassType.ClassName,'"',
' TypeInfo=',DbgS(TypeInfo),
' TypeData^.ClassType.ClassInfo=',DbgS(TypeData^.ClassType.ClassInfo),
' TypeData^.ClassType.ClassParent=',DbgS(TypeData^.ClassType.ClassParent),
' TypeData^.ParentInfo=',DbgS(TypeData^.ParentInfo),
'');
CurParent:=TypeData^.ClassType.ClassParent;
if CurParent<>nil then begin
writeln('TPropInfoList.Create F CurParent.ClassName=',CurParent.ClassName,
' CurParent.ClassInfo=',DbgS(CurParent.ClassInfo),
'');
end;}
// read properties
while CurCount>0 do begin
// point PropInfo to next propinfo record.
// Located at Name[Length(Name)+1] !
debugln(' Property ',PropInfo^.Name,' Type=',PropInfo^.PropType^.Name);
PropInfo:=PPropInfo(AlignToPtr(pointer(@PropInfo^.Name)+PByte(@PropInfo^.Name)^+1));
dec(CurCount);
end;
TypeInfo:=TypeData^.ParentInfo;
if TypeInfo=nil then break;
until false;
end;
//------------------------------------------------------------------------------
const
{ TypeKinds see typinfo.pp
TTypeKind = (tkUnknown,tkInteger,tkChar,tkEnumeration,tkFloat,
tkSet,tkMethod,tkSString,tkLString,tkAString,
tkWString,tkVariant,tkArray,tkRecord,tkInterface,
tkClass,tkObject,tkWChar,tkBool,tkInt64,tkQWord,
tkDynArray,tkInterfaceRaw,tkProcVar,tkUString,tkUChar,
tkHelper);
}
// default property editor classes
PropClassMap:array[TypInfo.TTypeKind] of TPropertyEditorClass=(
nil, // tkUnknown
TIntegerPropertyEditor, // tkInteger
TCharpropertyEditor, // tkChar
TEnumPropertyEditor, // tkEnumeration
TFloatPropertyEditor, // tkFloat
TSetPropertyEditor, // tkSet
TMethodPropertyEditor, // tkMethod
TStringPropertyEditor, // tkSString
TStringPropertyEditor, // tkLString
TStringPropertyEditor, // tkAString
TWideStringPropertyEditor, // tkWString
TPropertyEditor, // tkVariant
nil, // tkArray
TRecordPropertyEditor, // tkRecord
TInterfacePropertyEditor, // tkInterface
TClassPropertyEditor, // tkClass
nil, // tkObject
TPropertyEditor, // tkWChar
TBoolPropertyEditor, // tkBool
TInt64PropertyEditor, // tkInt64
TQWordPropertyEditor, // tkQWord
nil, // tkDynArray
nil, // tkInterfaceRaw,
nil, // tkProcVar
TUnicodeStringPropertyEditor,// tkUString
nil // tkUChar
{$IF declared(tkHelper)}
,nil // tkHelper
{$ENDIF}
{$IF declared(tkFile)}
,nil // tkFile
{$ENDIF}
{$IF declared(tkClassRef)}
,nil // tkClassRef
{$ENDIF}
{$IF declared(tkPointer)}
,nil // tkPointer
{$ENDIF}
);
var
PropertyEditorMapperList:TFPList;
PropertyClassList:TFPList;
SelectionEditorClassList:TFPList;
type
PPropertyClassRec=^TPropertyClassRec;
TPropertyClassRec=record
PropertyType:PTypeInfo;
PropertyName:shortstring;
PersistentClass:TClass;
EditorClass:TPropertyEditorClass;
end;
PPropertyEditorMapperRec=^TPropertyEditorMapperRec;
TPropertyEditorMapperRec=record
Mapper:TPropertyEditorMapperFunc;
end;
PSelectionEditorClassRec=^TSelectionEditorClassRec;
TSelectionEditorClassRec=record
ComponentClass:TComponentClass;
EditorClass:TSelectionEditorClass;
end;
{ TPropInfoList }
constructor TPropInfoList.Create(Instance:TPersistent; Filter:TTypeKinds);
var
ListCapacity: integer;
procedure Add(PropInfo: PPropInfo{$IFDEF HasExtRtti}; Ext: PPropInfoEx{$ENDIF});
var
i: Integer;
begin
if PropInfo^.PropType^.Kind in Filter then begin
// check if name already exists in list
i:=FCount-1;
while (i>=0) and (CompareText(FList^[i]^.Name,PropInfo^.Name)<>0) do
dec(i);
if (i<0) then begin
// add property info
if FCount=ListCapacity then begin
if ListCapacity<16 then
ListCapacity:=16
else
ListCapacity:=ListCapacity*2;
ReAllocMem(FList,ListCapacity*SizeOf(Pointer));
{$IFDEF HasExtRtti}
ReAllocMem(FListExt,ListCapacity*SizeOf(Pointer));
{$ENDIF}
end;
FList^[FCount]:=PropInfo;
{$IFDEF HasExtRtti}
FListExt^[FCount]:=Ext;
{$ENDIF}
inc(FCount);
end;
end;
end;
var
aTypeInfo: PTypeInfo;
TypeData: PTypeData;
PropInfo: PPropInfo;
PropData: ^TPropData;
{$IFDEF HasExtRtti}
PropList: PPropListEx;
PropInfoEx: PPropInfoEx;
{$ENDIF}
CurCount: integer;
//CurParent: TClass;
begin
aTypeInfo:=Instance.ClassInfo;
// read all published properties and remove doubles
TypeData:=GetTypeData(aTypeInfo);
ListCapacity:=TypeData^.PropCount;
ReAllocMem(FList,ListCapacity * SizeOf(Pointer));
{$IFDEF HASEXTRTTI}
ReAllocMem(FListExt,ListCapacity * SizeOf(Pointer));
{$ENDIF}
aTypeInfo:=Instance.ClassInfo;
FCount:=0;
repeat
// read all property infos of current class
TypeData:=GetTypeData(aTypeInfo);
// skip unitname
PropData:=AlignToPtr(Pointer(@TypeData^.UnitName)+Length(TypeData^.UnitName)+1);
// read property count
CurCount:=PropData^.PropCount;
PropInfo:=PPropInfo(@PropData^.PropList);
{writeln('TPropInfoList.Create D ',CurCount,' TypeData^.ClassType=',DbgS(TypeData^.ClassType));
writeln('TPropInfoList.Create E ClassName="',TypeData^.ClassType.ClassName,'"',
' TypeInfo=',DbgS(aTypeInfo),
' TypeData^.ClassType.ClassInfo=',DbgS(TypeData^.ClassType.ClassInfo),
' TypeData^.ClassType.ClassParent=',DbgS(TypeData^.ClassType.ClassParent),
' TypeData^.ParentInfo=',DbgS(TypeData^.ParentInfo),
'');
CurParent:=TypeData^.ClassType.ClassParent;
if CurParent<>nil then begin
writeln('TPropInfoList.Create F CurParent.ClassName=',CurParent.ClassName,
' CurParent.ClassInfo=',DbgS(CurParent.ClassInfo),
'');
end;}
// read properties
while CurCount>0 do begin
Add(PropInfo{$IFDEF HasExtRtti},nil{$ENDIF});
// point PropInfo to next propinfo record.
// Located at Name[Length(Name)+1] !
PropInfo:=PPropInfo(AlignToPtr(pointer(@PropInfo^.Name)+PByte(@PropInfo^.Name)^+1));
dec(CurCount);
end;
{$IFDEF HasExtRtti}
if FExtVisibility<>[] then begin
CurCount:=GetPropListEx(aTypeInfo,PropList,FExtVisibility);
try
while CurCount>0 do begin
dec(CurCount);
PropInfoEx:=PropList^[CurCount];
Add(PropInfoEx^.Info,PropInfoEx);
end;
finally
Freemem(PropList);
end;
end;
{$ENDIF}
aTypeInfo:=TypeData^.ParentInfo;
until aTypeInfo=nil;
Sort;
end;
{$IFDEF HasExtRtti}
constructor TPropInfoList.Create(Instance: TPersistent; Filter: TTypeKinds;
AddExtVisibility: TVisibilityClasses);
begin
FExtVisibility:=AddExtVisibility;
Create(Instance,Filter);
end;
{$ENDIF}
destructor TPropInfoList.Destroy;
begin
if FList<>nil then FreeMem(FList);
{$IFDEF HasExtRtti}
if FListExt<>nil then FreeMem(FListExt);
{$ENDIF HasExtRtti}
end;
function TPropInfoList.Contains(P:PPropInfo):Boolean;
var
I: Integer;
begin
for I := 0 to FCount - 1 do
begin
with FList^[I]^ do
begin
if (PropType^.Kind=P^.PropType^.Kind) and (CompareText(Name,P^.Name)=0) then
begin
Result := True;
Exit;
end;
end;
end;
Result := False;
end;
procedure TPropInfoList.Delete(Index:Integer);
begin
Dec(FCount);
if Index >= FCount then exit;
System.Move(FList^[Index+1],FList^[Index],(FCount-Index) * SizeOf(Pointer));
{$IFDEF HasExtRtti}
System.Move(FListExt^[Index+1],FListExt^[Index],(FCount-Index) * SizeOf(Pointer));
{$ENDIF}
end;
function TPropInfoList.Get(Index:Integer):PPropInfo;
begin
Result:=FList^[Index];
end;
{$IFDEF HasExtRtti}
function TPropInfoList.GetExt(Index: Integer): PPropInfoEx;
begin
Result:=FListExt^[Index];
end;
{$ENDIF}
procedure TPropInfoList.Intersect(List:TPropInfoList);
var
i:Integer;
begin
for i:=FCount-1 downto 0 do
if not List.Contains(FList^[i]) then Delete(i);
end;
procedure TPropInfoList.Sort;
procedure QuickSort(L, R: Integer);
var
i, j: Longint;
p: PPropInfo;
h: Pointer;
begin
repeat
i := L;
j := R;
p := FList^[(L + R) div 2];
repeat
while CompareText(p^.Name, FList^[i]^.Name) > 0 do
inc(i);
while CompareText(p^.Name, FList^[j]^.Name) < 0 do
dec(j);
if i <= j then
begin
h := FList^[i];
Flist^[i] := FList^[j];
FList^[j] := h;
{$IFDEF HasExtRtti}
h := FListExt^[i];
FListExt^[i] := FListExt^[j];
FListExt^[j] := h;
{$ENDIF}
inc(i);
dec(j);
end;
until i > j;
if L < j then
QuickSort(L, j);
L := i;
until i >= R;
end;
begin
if Count > 0 then
QuickSort(0, Count - 1);
end;
//------------------------------------------------------------------------------
procedure RegisterSelectionEditor(AComponentClass: TComponentClass; AEditorClass: TSelectionEditorClass);
var
p:PSelectionEditorClassRec;
begin
if not Assigned(AComponentClass) or not Assigned(AEditorClass) then
Exit;
if not Assigned(SelectionEditorClassList) then
SelectionEditorClassList:=TFPList.Create;
New(p);
p^.ComponentClass:=AComponentClass;
p^.EditorClass:=AEditorClass;
SelectionEditorClassList.Add(p);
end;
procedure GetSelectionEditorClasses(AComponent: TComponent; AEditorList: TSelectionEditorClassList);
var
i:LongInt;
begin
if not Assigned(AComponent) or not Assigned(AEditorList) then
Exit;
if not Assigned(SelectionEditorClassList) then
Exit;
for i:=0 to SelectionEditorClassList.Count-1 do begin
with PSelectionEditorClassRec(SelectionEditorClassList[i])^ do begin
if AComponent.InheritsFrom(ComponentClass) then
AEditorList.Add(EditorClass);
end;
end;
end;
procedure GetSelectionEditorClasses(ASelection: TPersistentSelectionList;
AEditorList: TSelectionEditorClassList);
var
tmp:TSelectionEditorClassList;
i,j:LongInt;
sel:TPersistent;
begin
if not Assigned(ASelection) or (ASelection.Count=0) or not Assigned(AEditorList) then
Exit;
tmp:=TSelectionEditorClassList.Create;
try
for i:=0 to ASelection.Count-1 do begin
sel:=ASelection[i];
if not (sel is TComponent) then
Continue;
GetSelectionEditorClasses(TComponent(sel),tmp);
{ if there are no classes yet, we pick them as is, otherwise we remove all
those from the existing list that are not part of the new list }
if AEditorList.Count=0 then
AEditorList.Assign(tmp)
else begin
for j:=AEditorList.Count-1 downto 0 do begin
if tmp.IndexOf(AEditorList[j])<0 then
AEditorList.Delete(j);
end;
end;
tmp.Clear;
end;
finally
tmp.Free;
end;
end;
{ GetComponentProperties }
procedure RegisterPropertyEditor(PropertyType:PTypeInfo;
PersistentClass: TClass; const PropertyName:shortstring;
EditorClass:TPropertyEditorClass);
var
P:PPropertyClassRec;
begin
if PropertyType=nil then exit;
if PropertyClassList=nil then
PropertyClassList:=TFPList.Create;
New(P);
P^.PropertyType:=PropertyType;
P^.PersistentClass:=PersistentClass;
P^.PropertyName:=PropertyName;
P^.EditorClass:=EditorClass;
PropertyClassList.Insert(0,P);
end;
procedure RegisterPropertyEditorMapper(Mapper:TPropertyEditorMapperFunc);
var
P:PPropertyEditorMapperRec;
begin
if PropertyEditorMapperList=nil then
PropertyEditorMapperList:=TFPList.Create;
New(P);
P^.Mapper:=Mapper;
PropertyEditorMapperList.Insert(0,P);
end;
function GetEditorClass(PropInfo:PPropInfo; Obj:TPersistent): TPropertyEditorClass;
var
I: Integer;
begin
Result := nil;
if PropertyEditorMapperList<>nil then begin
for I:=0 to PropertyEditorMapperList.Count-1 do begin
with PPropertyEditorMapperRec(PropertyEditorMapperList[I])^ do begin
Result:=Mapper(Obj,PropInfo);
if Result<>nil then break;
end;
end;
end;
Result:=GetEditorClass(PropInfo^.Name,PropInfo^.PropType,Obj);
end;
function GetEditorClass(PropName: shortstring; Info: PTypeInfo; Obj: TPersistent
): TPropertyEditorClass;
var
P, C: PPropertyClassRec;
I: Integer;
TypeData: PTypeData;
begin
Result := nil;
I:=0;
C:=nil;
TypeData:=GetTypeData(Info);
while I < PropertyClassList.Count do begin
P:=PropertyClassList[I];
if ((P^.PropertyType=Info) or
((P^.PropertyType^.Kind=Info^.Kind) and
(P^.PropertyType^.Name=Info^.Name)
)
) or
( (Info^.Kind=tkClass) and
(P^.PropertyType^.Kind=tkClass) and
TypeData^.ClassType.InheritsFrom(
GetTypeData(P^.PropertyType)^.ClassType)
)
then
if ((P^.PersistentClass=nil) or ((Obj<>nil) and (Obj.InheritsFrom(P^.PersistentClass))))
and ((P^.PropertyName='') or (CompareText(P^.PropertyName,PropName)=0))
then
if (C=nil) or // see if P is better match than C
((C^.PersistentClass=nil) and (P^.PersistentClass<>nil)) or
((C^.PropertyName='') and (P^.PropertyName<>''))
or // P's proptype match is exact,but C's does not
((C^.PropertyType<>Info) and (P^.PropertyType=Info))
or // P's proptype is more specific than C's proptype
((P^.PropertyType<>C^.PropertyType) and
(P^.PropertyType^.Kind=tkClass) and
(C^.PropertyType^.Kind=tkClass) and
GetTypeData(P^.PropertyType)^.ClassType.InheritsFrom(
GetTypeData(C^.PropertyType)^.ClassType))
or // P's component class is more specific than C's component class
((P^.PersistentClass<>nil) and (C^.PersistentClass<>nil) and
(P^.PersistentClass<>C^.PersistentClass) and
(P^.PersistentClass.InheritsFrom(C^.PersistentClass)))
then
C:=P;
Inc(I);
end;
if C<>nil then
Result:=C^.EditorClass
else begin
if (Info^.Kind<>tkClass)
or (TypeData^.ClassType.InheritsFrom(TPersistent))
or (TypeData^.PropCount > 0) then
Result:=PropClassMap[Info^.Kind]
else
Result:=nil;
end;
if (Result<>nil) and Result.InheritsFrom(THiddenPropertyEditor) then
Result:=nil;
end;
procedure GetPersistentProperties(ASelection: TPersistentSelectionList;
AFilter: TTypeKinds; AHook: TPropertyEditorHook; AProc: TGetPropEditProc;
APropInfoFilterFunc: TPropInfoFilterFunc;
AEditorFilterFunc: TPropertyEditorFilterFunc
{$IFDEF HasExtRtti};ExtVisibility: TVisibilityClasses = []{$ENDIF});
var
I, J, SelCount: Integer;
ClassTyp: TClass;
Candidates: TPropInfoList;
PropLists: TFPList;
PropEditor: TPropertyEditor;
PropEditorList: TPropertyEditorList;
SelEditor: TBaseSelectionEditor;
SelEditorList: TSelectionEditorClassList;
EdClass: TPropertyEditorClass;
PropInfo: PPropInfo;
AddEditor: Boolean;
Instance: TPersistent;
Designer: TIDesigner;
begin
if (ASelection = nil) or (ASelection.Count = 0) then Exit;
SelCount := ASelection.Count;
Instance := ASelection[0];
ClassTyp := Instance.ClassType;
// Create a property candidate list of all properties that can be found in
// every component in the list and in the Filter
Candidates := TPropInfoList.Create(Instance, AFilter{$IFDEF HasExtRtti},ExtVisibility{$ENDIF});
try
// check each property candidate
for I := Candidates.Count - 1 downto 0 do
begin
PropInfo := Candidates[I];
// check if property is readable
if (PropInfo^.GetProc=nil)
or ((not GShowReadOnlyProps) and (PropInfo^.PropType^.Kind <> tkClass)
and (PropInfo^.SetProc = nil))
or (Assigned(APropInfoFilterFunc) and (not APropInfoFilterFunc(PropInfo)))
then begin
Candidates.Delete(I);
Continue;
end;
EdClass := GetEditorClass(PropInfo, Instance);
if EdClass = nil
then begin
Candidates.Delete(I);
Continue;
end;
// create a test property editor for the property
PropEditor := EdClass.Create(AHook,1);
PropEditor.SetPropEntry(0, Instance, PropInfo);
PropEditor.Initialize;
// check for multiselection, ValueAvailable and customfilter
if ((SelCount > 1) and not (paMultiSelect in PropEditor.GetAttributes))
or not PropEditor.ValueAvailable
or (Assigned(AEditorFilterFunc) and not AEditorFilterFunc(PropEditor))
then
Candidates.Delete(I);
PropEditor.Free;
end;
PropEditorList := TPropertyEditorList.Create(True);
try
PropLists := TFPList.Create;
try
PropLists.Count := SelCount;
// Create a property info list for each component in the selection
for I := 0 to SelCount - 1 do
PropLists[i] := TPropInfoList.Create(ASelection[I], AFilter{$IFDEF HasExtRtti},ExtVisibility{$ENDIF});
// Eliminate each property in Candidates that is not in all property lists
for I := 0 to SelCount - 1 do
Candidates.Intersect(TPropInfoList(PropLists[I]));
// Eliminate each property in the property list that are not in Candidates
for I := 0 to SelCount - 1 do
TPropInfoList(PropLists[I]).Intersect(Candidates);
// PropList now has a matrix of PropInfo's.
// -> create a property editor for each property
for I := 0 to Candidates.Count - 1 do
begin
EdClass := GetEditorClass(Candidates[I], Instance);
if EdClass = nil then Continue;
PropEditor := EdClass.Create(AHook, SelCount);
AddEditor := True;
for J := 0 to SelCount - 1 do
begin
if (ASelection[J].ClassType <> ClassTyp) and
(GetEditorClass(TPropInfoList(PropLists[J])[I], ASelection[J])<>EdClass) then
begin
AddEditor := False;
Break;
end;
PropEditor.SetPropEntry(J, ASelection[J], TPropInfoList(PropLists[J])[I]);
end;
if AddEditor then
begin
PropEditor.Initialize;
if not PropEditor.ValueAvailable then AddEditor:=false;
end;
if AddEditor then
PropEditorList.Add(PropEditor)
else
PropEditor.Free;
end;
finally
for I := 0 to PropLists.Count - 1 do
TPropInfoList(PropLists[I]).Free;
PropLists.Free;
end;
SelEditorList := TSelectionEditorClassList.Create;
try
GetSelectionEditorClasses(ASelection, SelEditorList);
{ is it safe to assume that the whole selection has the same designer? }
Designer := FindRootDesigner(ASelection[0]);
for I := 0 to SelEditorList.Count - 1 do begin
SelEditor := SelEditorList[I].Create(Designer, AHook);
try
if seaFilterProperties in SelEditor.GetAttributes then
SelEditor.FilterProperties(ASelection, PropEditorList);
finally
SelEditor.Free;
end;
end;
finally
SelEditorList.Free;
end;
{ no longer free the editors }
PropEditorList.FreeObjects := False;
for I := 0 to PropEditorList.Count - 1 do
AProc(PropEditorList[I]);
finally
PropEditorList.Free;
end;
finally
Candidates.Free;
end;
end;
procedure GetPersistentProperties(ASelection: TPersistentSelectionList;
AFilter: TTypeKinds; AHook: TPropertyEditorHook; AProc: TGetPropEditProc;
AEditorFilterFunc: TPropertyEditorFilterFunc);
begin
GetPersistentProperties(ASelection,AFilter,AHook,AProc,nil,AEditorFilterFunc);
end;
procedure GetPersistentProperties(AItem: TPersistent;
AFilter: TTypeKinds; AHook: TPropertyEditorHook; AProc: TGetPropEditProc;
AEditorFilterFunc: TPropertyEditorFilterFunc);
var
Selection: TPersistentSelectionList;
begin
if AItem = nil then Exit;
Selection := TPersistentSelectionList.Create;
try
Selection.Add(AItem);
GetPersistentProperties(Selection,AFilter,AHook,AProc,AEditorFilterFunc);
finally
Selection.Free;
end;
end;
{ TPropertyEditor }
constructor TPropertyEditor.Create(Hook: TPropertyEditorHook; APropCount:Integer);
var
PropListSize: Integer;
begin
FPropertyHook:=Hook;
PropListSize:=APropCount * SizeOf(TInstProp);
GetMem(FPropList,PropListSize);
FillByte(FPropList^,PropListSize,0);
FPropCount:=APropCount;
end;
destructor TPropertyEditor.Destroy;
begin
if FPropList<>nil then
FreeMem(FPropList,FPropCount * SizeOf(TInstProp));
end;
procedure TPropertyEditor.Activate;
begin
//
end;
procedure TPropertyEditor.Deactivate;
begin
//
end;
function TPropertyEditor.AllEqual:Boolean;
begin
Result:=FPropCount=1;
end;
procedure TPropertyEditor.Edit;
type
TGetStrFunc = function(const StrValue:ansistring):Integer of object;
var
I:Integer;
Values: TStringList;
AddValue: TGetStrFunc;
begin
if not AutoFill then Exit;
Values:=TStringList.Create;
Values.UseLocale := False;
Values.Sorted:=paSortList in GetAttributes;
try
AddValue := @Values.Add;
GetValues(TGetStrProc((@AddValue)^));
if Values.Count > 0 then begin
I:=Values.IndexOf(FirstValue)+1;
if I=Values.Count then I:=0;
FirstValue:=Values[I];
end;
finally
Values.Free;
end;
end;
procedure TPropertyEditor.Edit(AOwnerComponent: TComponent);
begin
FOwnerComponent := AOwnerComponent;
Edit;
FOwnerComponent := Nil;
end;
procedure TPropertyEditor.ShowValue;
begin
end;
function TPropertyEditor.AutoFill:Boolean;
begin
Result:=paValueList in GetAttributes;
end;
function TPropertyEditor.CallStoredFunction: Boolean;
begin
with FPropList^[0] do begin
if PropInfo=nil then
exit(false);
Result := (Instance <> nil) and IsStoredProp(Instance, PropInfo);
end;
end;
{$IFDEF UseOINormalCheckBox}
function TPropertyEditor.DrawCheckbox(ACanvas: TCanvas; const ARect: TRect;
IsTrue: Boolean): TRect;
// Draws a Checkbox using theme services for editing booleans.
// Returns the output rectangle adjusted for new text location.
var
Details: TThemedElementDetails;
Check: TThemedButton;
BRect: TRect;
Sz: TSize;
TopMargin: Integer;
VisVal: String;
begin
VisVal := GetVisualValue;
// Draw the box using theme services.
if (VisVal = '') or (VisVal = oisMixed) then
Check := tbCheckBoxMixedNormal
else if IsTrue then
Check := tbCheckBoxCheckedNormal
else
Check := tbCheckBoxUncheckedNormal;
Details := ThemeServices.GetElementDetails(Check);
Sz := TCustomCheckBoxThemed.GetCheckBoxSize(ScreenInfo.PixelsPerInchX);
TopMargin := (ARect.Bottom - ARect.Top - Sz.cy) div 2;
BRect := ARect;
// Left varies by widgetset and theme etc. Real Checkbox itself has a left margin.
Inc(BRect.Left, 3); // ToDo: How to find out the real margin?
Result := BRect; // Result Rect will be used for text.
Inc(BRect.Top, TopMargin);
BRect.Right := BRect.Left + Sz.cx;
BRect.Bottom := BRect.Top + Sz.cy;
ThemeServices.DrawElement(ACanvas.Handle, Details, BRect, nil);
// Text will be written after the box.
Inc(Result.Left, Sz.cx + 4);
end;
{$ENDIF}
function TPropertyEditor.DrawCheckValue(ACanvas: TCanvas; const ARect: TRect;
AState: TPropEditDrawState; IsTrue: Boolean): TRect;
// Draws Boolean value as text or Checkbox depending on user setting from PropertyHook.
// Uses either theme services (func DrawCheckbox) or TCheckBoxThemed depending
// on UseOINormalCheckBox define.
// Returns Rect for textual part if it must be drawn, otherwise Result.Top = -100.
{$IFnDEF UseOINormalCheckBox}
var
BRect: TRect;
VisVal: string;
stat: TCheckBoxState;
{$ENDIF}
begin
Result.Top := 0;
if FPropertyHook.GetCheckboxForBoolean then
begin // Checkbox for Booleans.
{$IFnDEF UseOINormalCheckBox}
Result.Top := -100; // No need to call PropDrawValue further.
BRect := ARect;
Inc(BRect.Left, CheckBoxThemedLeftOffs);
VisVal := GetVisualValue;
if (VisVal = '') or (VisVal = oisMixed) then
stat := cbGrayed
else if VisVal = '(True)' then
stat := cbChecked
else
stat := cbUnchecked;
TCheckBoxThemed.PaintSelf(ACanvas, VisVal, BRect, stat, False, False, False,
False, taRightJustify);
{$ELSE}
Result := DrawCheckbox(ACanvas, ARect, IsTrue);
{$ENDIF}
end
else
Result := ARect; // Classic Combobox for Booleans.
end;
function TPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result:=[paMultiSelect,paRevertable];
end;
function TPropertyEditor.IsReadOnly: boolean;
begin
Result:=paReadOnly in GetAttributes;
end;
function TPropertyEditor.GetComponent(Index: Integer): TPersistent;
begin
Result:=FPropList^[Index].Instance;
end;
function TPropertyEditor.GetUnitName(Index: Integer): string;
begin
Result:=GetClassUnitName(GetComponent(Index).ClassType);
end;
function TPropertyEditor.GetPropTypeUnitName(Index: Integer): string;
type
PPropData = ^TPropData;
var
aPersistent: TPersistent;
CurPropInfo: PPropInfo;
hp: PTypeData;
pd: PPropData;
i: Integer;
UpperName: ShortString;
ATypeInfo: PTypeInfo;
NameFound: Boolean;
ThePropType: PTypeInfo;
begin
Result:='';
aPersistent:=GetComponent(Index);
UpperName:=UpCase(GetName);
ThePropType:=GetPropType;
ATypeInfo:=PTypeInfo(aPersistent.ClassInfo);
while Assigned(ATypeInfo) do begin
// skip the name
hp:=GetTypeData(ATypeInfo);
// the class info rtti the property rtti follows immediatly
pd:=AlignToPtr(Pointer(Pointer(@hp^.UnitName)+Length(hp^.UnitName)+1));
CurPropInfo:=PPropInfo(@pd^.PropList);
NameFound:=false;
for i:=1 to pd^.PropCount do begin
// found a property of that name ?
if Upcase(CurPropInfo^.Name)=UpperName then begin
DebugLn(['TPropertyEditor.GetPropTypeUnitName ',hp^.UnitName,' IsSamePropInfo=',CurPropInfo^.PropType=ThePropType]);
NameFound:=true;
if CurPropInfo^.PropType=ThePropType then
Result:=hp^.UnitName;
end;
// skip to next property
CurPropInfo:=PPropInfo(AlignToPtr(Pointer(@CurPropInfo^.Name)+Byte(CurPropInfo^.Name[0])+1));
end;
if not NameFound then break;
// parent class
ATypeInfo:=hp^.ParentInfo;
end;
end;
function TPropertyEditor.GetPropertyPath(Index: integer): string;
begin
Result:=GetComponent(Index).ClassName+'.'+GetName;
end;
function TPropertyEditor.GetFloatValue:Extended;
begin
Result:=GetFloatValueAt(0);
end;
procedure SetIndexValues(P: PPropInfo; var Index, IValue : Longint);
begin
Index:=((P^.PropProcs shr 6) and 1);
if Index<>0 then
IValue:=P^.Index
else
IValue:=0;
end;
function TPropertyEditor.GetFloatValueAt(Index:Integer):Extended;
begin
Result:=FPropList^[Index].GetFloat;
end;
function TPropertyEditor.GetMethodValue:TMethod;
begin
Result:=GetMethodValueAt(0);
end;
// workaround for buggy rtl function
function LazGetMethodProp(Instance: TObject; PropInfo: PPropInfo): TMethod;
type
TGetMethodProcIndex=function(Index: Longint): TMethod of object;
TGetMethodProc=function(): TMethod of object;
PMethod = ^TMethod;
var
value: PMethod;
AMethod : TMethod;
begin
Result.Code:=nil;
Result.Data:=nil;
case (PropInfo^.PropProcs) and 3 of
ptfield:
begin
Value:=PMethod(Pointer(Instance)+{%H-}PtrUInt(PropInfo^.GetProc));
if Value<>nil then
Result:=Value^;
end;
ptstatic,
ptvirtual :
begin
if (PropInfo^.PropProcs and 3)=ptStatic then
AMethod.Code:=PropInfo^.GetProc
else
AMethod.Code:=PPointer(Pointer(Instance.ClassType)
+{%H-}PtrUInt(PropInfo^.GetProc))^;
AMethod.Data:=Instance;
if ((PropInfo^.PropProcs shr 6) and 1)<>0 then
Result:=TGetMethodProcIndex(AMethod)(PropInfo^.Index)
else
Result:=TGetMethodProc(AMethod)();
end;
end;
end;
function TPropertyEditor.GetMethodValueAt(Index: Integer):TMethod;
begin
Result:=FPropList^[Index].GetMethod;
end;
function TPropertyEditor.GetEditLimit: Integer;
begin
Result := 255;
end;
function TPropertyEditor.GetName: shortstring;
begin
with FPropList^[0] do begin
if PropInfo<>nil then
Result:=PropInfo^.Name
else if FieldName<>nil then
Result:=FieldName^
else
Result:='';
end;
end;
function TPropertyEditor.GetOrdValue: Longint;
begin
Result:=GetOrdValueAt(0);
end;
function TPropertyEditor.GetOrdValueAt(Index: Integer): Longint;
begin
Result:=FPropList^[Index].GetOrd;
end;
function TPropertyEditor.GetObjectValue: TObject;
begin
Result:=GetObjectValueAt(0);
end;
function TPropertyEditor.GetObjectValue(MinClass: TClass): TObject;
begin
Result:=GetObjectValueAt(0, MinClass);
end;
function TPropertyEditor.GetObjectValueAt(Index: Integer): TObject;
begin
Result:=FPropList^[Index].GetObject;
end;
function TPropertyEditor.GetObjectValueAt(Index: Integer; MinClass: TClass): TObject;
begin
Result:=FPropList^[Index].GetObject(MinClass);
end;
function TPropertyEditor.GetDefaultOrdValue: Longint;
var
APropInfo: PPropInfo;
begin
APropInfo:=FPropList^[0].PropInfo;
if APropInfo<>nil then
Result:=APropInfo^.Default
else
Result:=0;
end;
function TPropertyEditor.GetSetValue(Brackets: boolean): AnsiString;
begin
Result:=FPropList^[0].GetSet(Brackets);
end;
function TPropertyEditor.GetSetValueAt(Index: Integer; Brackets: boolean): AnsiString;
begin
Result:=FPropList^[Index].GetSet(Brackets);
end;
function TPropertyEditor.GetPrivateDirectory:ansistring;
begin
Result:='';
if PropertyHook<>nil then
Result:=PropertyHook.GetPrivateDirectory;
end;
procedure TPropertyEditor.DrawValue(const AValue: string; ACanvas: TCanvas;
const ARect: TRect; AState: TPropEditDrawState);
var
Style : TTextStyle;
begin
FillChar(Style{%H-},SizeOf(Style),0);
With Style do begin
Alignment := taLeftJustify;
Layout := tlCenter;
Opaque := False;
Clipping := True;
ShowPrefix := False;
WordBreak := False;
SingleLine := True;
ExpandTabs := True;
SystemFont := False;
end;
ACanvas.TextRect(ARect,ARect.Left+3,ARect.Top,AValue, Style);
end;
procedure TPropertyEditor.GetProperties(Proc:TGetPropEditProc);
begin
end;
function TPropertyEditor.GetPropInfo: PPropInfo;
begin
Result:=FPropList^[0].PropInfo;
end;
function TPropertyEditor.GetInstProp: PInstProp;
begin
Result:=@FPropList^[0];
end;
function TPropertyEditor.GetEnumValueAt(Index: Integer): string;
begin
Result:=FPropList^[Index].GetEnum;
end;
function TPropertyEditor.GetPropType: PTypeInfo;
begin
with FPropList^[0] do begin
if FieldTypeInfo<>nil then
Result:=FieldTypeInfo
else
Result:=PropInfo^.PropType;
end;
end;
function TPropertyEditor.GetStrValue: AnsiString;
begin
Result:=GetStrValueAt(0);
end;
function TPropertyEditor.GetStrValueAt(Index:Integer): AnsiString;
begin
Result:=FPropList^[Index].GetString;
end;
function TPropertyEditor.GetVarValue: Variant;
begin
Result:=GetVarValueAt(0);
end;
function TPropertyEditor.GetVarValueAt(Index:Integer): Variant;
begin
Result:=FPropList^[Index].GetVariant;
end;
function TPropertyEditor.GetWideStrValue: WideString;
begin
Result:=GetWideStrValueAt(0);
end;
function TPropertyEditor.GetWideStrValueAt(Index: Integer): WideString;
begin
Result:=FPropList^[Index].GetWideString;
end;
function TPropertyEditor.HasDefaultValue: Boolean;
var
APropInfo: PPropInfo;
begin
APropInfo:=FPropList^[0].PropInfo;
if APropInfo=nil then exit(true);
Result := APropInfo^.Default<>NoDefaultValue;
end;
function TPropertyEditor.GetUnicodeStrValue: UnicodeString;
begin
Result:=GetUnicodeStrValueAt(0);
end;
function TPropertyEditor.GetUnicodeStrValueAt(Index: Integer): UnicodeString;
begin
Result:=FPropList^[Index].GetUnicodeString;
end;
function TPropertyEditor.GetValue:ansistring;
begin
Result:=oisUnknown;
end;
function TPropertyEditor.GetHint(HintType: TPropEditHint; x, y: integer): string;
var
TypeHint: String;
begin
Result := GetName + LineEnding + oisValue + ' ' + GetVisualValue;
case GetPropType^.Kind of
tkInteger : TypeHint:=oisInteger;
tkInt64 : TypeHint:=oisInt64;
tkBool : TypeHint:=oisBoolean;
tkEnumeration : TypeHint:=oisEnumeration;
tkChar, tkWChar : TypeHint:=oisChar;
tkUnknown : TypeHint:=oisUnknown;
tkObject : TypeHint:=oisObject;
tkClass : TypeHint:=oisClass;
tkQWord : TypeHint:=oisWord;
tkString, tkLString, tkAString, tkWString : TypeHint:=oisString;
tkFloat : TypeHint:=oisFloat;
tkSet : TypeHint:=oisSet;
tkMethod : TypeHint:=oisMethod;
tkVariant : TypeHint:=oisVariant;
tkArray : TypeHint:=oisArray;
tkRecord : TypeHint:=oisRecord;
tkInterface : TypeHint:=oisInterface;
else
TypeHint:='';
end;
if TypeHint<>'' then
Result:=Result+LineEnding+TypeHint;
end;
function TPropertyEditor.GetDefaultValue: ansistring;
begin
if not HasDefaultValue then
raise EPropertyError.Create('No property default available');
Result:='';
end;
function TPropertyEditor.GetVisualValue: ansistring;
begin
if AllEqual then
begin
Result:=GetValue;
{$IFDEF LCLCarbon}
Result:=StringReplace(Result,LineEnding,LineFeedSymbolUTF8,[rfReplaceAll])
{$ENDIF}
end
else
Result:='';
end;
procedure TPropertyEditor.GetValues(Proc:TGetStrProc);
begin
end;
procedure TPropertyEditor.Initialize;
begin
with FPropList^[0] do begin
if Instance<>nil then
begin
if PropInfo=nil then
raise Exception.Create('TPropertyEditor.Initialize 20240902134758 '+dbgsName(Self));
end else if Field<>nil then begin
if FieldTypeInfo=nil then
raise Exception.Create('TPropertyEditor.Initialize 20240902134825 '+dbgsName(Self));
end else
raise Exception.Create('TPropertyEditor.Initialize 20240902134831 '+dbgsName(Self));
end;
end;
procedure TPropertyEditor.Modified(Index: integer);
var
PropName: ShortString;
begin
if PropertyHook = nil then exit;
with FPropList^[Index] do begin
if PropInfo<>nil then
PropName:=PropInfo^.Name
else
PropName:='';
end;
PropertyHook.Modified(Self, PropName);
end;
procedure TPropertyEditor.SetPropEntry(Index:Integer;
AnInstance:TPersistent; APropInfo:PPropInfo);
begin
FPropList^[Index]:=Default(TInstProp);
with FPropList^[Index] do begin
Instance:=AnInstance;
PropInfo:=APropInfo;
end;
end;
procedure TPropertyEditor.SetRecordFieldEntry(Index: Integer; AnInstance: Pointer;
aName: PShortString; AFieldInfo: PTypeInfo);
begin
FPropList^[Index]:=Default(TInstProp);
with FPropList^[Index] do begin
Field:=AnInstance;
FieldName:=aName;
FieldTypeInfo:=AFieldInfo;
end;
end;
procedure TPropertyEditor.SetFloatValue(const NewValue: Extended);
var
I: Integer;
begin
for I:=0 to FPropCount-1 do
with FPropList^[I] do begin
SetFloat(NewValue);
Modified(I);
end;
end;
procedure TPropertyEditor.SetMethodValue(const NewValue: TMethod);
var
I: Integer;
begin
for I:=0 to FPropCount-1 do
with FPropList^[I] do begin
SetMethod(NewValue);
Modified(I);
end;
end;
procedure TPropertyEditor.SetInt64Value(const NewValue: Int64);
var
I: Integer;
begin
for I:=0 to FPropCount-1 do
with FPropList^[I] do begin
SetOrd(NewValue);
Modified(I);
end;
end;
procedure TPropertyEditor.SetIntfValue(const NewValue: IInterface);
var
I: Integer;
begin
for I := 0 to FPropCount - 1 do
with FPropList^[I] do begin
SetInterface(NewValue);
Modified(I);
end;
end;
procedure TPropertyEditor.SetOrdValue(const NewValue: Longint);
var
I: Integer;
begin
for I := 0 to FPropCount - 1 do
with FPropList^[I] do begin
SetOrd(NewValue);
Modified(I);
end;
end;
procedure TPropertyEditor.SetPtrValue(const NewValue: Pointer);
var
I: Integer;
begin
for I := 0 to FPropCount - 1 do
with FPropList^[I] do begin
SetPointerValue(NewValue);
Modified(I);
end;
end;
procedure TPropertyEditor.SetStrValue(const NewValue: AnsiString);
var
I: Integer;
begin
for I:=0 to FPropCount-1 do
with FPropList^[I] do begin
SetString(NewValue);
Modified(I);
end;
end;
procedure TPropertyEditor.SetWideStrValue(const NewValue: WideString);
var
I: Integer;
begin
for I:=0 to FPropCount-1 do
with FPropList^[I] do begin
SetWideString(NewValue);
Modified(I);
end;
end;
procedure TPropertyEditor.SetUnicodeStrValue(const NewValue: UnicodeString);
var
I: Integer;
begin
for I:=0 to FPropCount-1 do
with FPropList^[I] do begin
SetUnicodeString(NewValue);
Modified(I);
end;
end;
procedure TPropertyEditor.SetVarValue(const NewValue: Variant);
var
I: Integer;
begin
for I:=0 to FPropCount-1 do
with FPropList^[I] do begin
SetVariant(NewValue); // todo field
Modified(I);
end;
end;
procedure TPropertyEditor.Revert;
var
I: Integer;
begin
if PropertyHook<>nil then
for I:=0 to FPropCount-1 do
with FPropList^[I] do PropertyHook.Revert(Instance,PropInfo); // todo field
end;
procedure TPropertyEditor.RevertToInherited;
var
i: Integer;
AncestorInstProp: TInstProp;
Changed: Boolean;
InstProp: TInstProp;
NewOrdValue, OldOrdValue: Int64;
OldStr, NewStr: String;
OldWideStr, NewWideStr: WideString;
OldUString, NewUString: UnicodeString;
OldFloat, NewFloat: Extended;
OldObj, NewObj: TObject;
OldMethod, NewMethod: TMethod;
OldInterface, NewInterface: IInterface;
begin
if PropertyHook=nil then exit;
Changed:=false;
try
for i:=0 to FPropCount-1 do
begin
InstProp:=FPropList^[i];
if not PropertyHook.GetAncestorInstance(InstProp,AncestorInstProp) then
continue;
case InstProp.GetKind of
tkInteger,tkChar,tkEnumeration,tkBool,tkInt64,tkQWord:
begin
OldOrdValue:=InstProp.GetOrd;
NewOrdValue:=AncestorInstProp.GetOrd;
if OldOrdValue=NewOrdValue then continue;
Changed:=true;
InstProp.SetOrd(NewOrdValue);
end;
tkSet:
begin
OldStr:=InstProp.GetSet(false);
NewStr:=AncestorInstProp.GetSet(false);
if OldStr=NewStr then continue;
Changed:=true;
InstProp.SetSet(NewStr);
end;
tkString,tkLString,tkAString:
begin
OldStr:=InstProp.GetString;
NewStr:=AncestorInstProp.GetString;
if OldStr=NewStr then continue;
Changed:=true;
InstProp.SetString(NewStr);
end;
tkWString:
begin
OldWideStr:=InstProp.GetWideString;
NewWideStr:=AncestorInstProp.GetWideString;
if OldWideStr=NewWideStr then continue;
Changed:=true;
InstProp.SetWideString(NewWideStr);
end;
tkUString:
begin
OldUString:=InstProp.GetUnicodeString;
NewUString:=AncestorInstProp.GetUnicodeString;
if OldUString=NewUString then continue;
Changed:=true;
InstProp.SetUnicodeString(NewUString);
end;
tkFloat:
begin
OldFloat:=InstProp.GetFloat;
NewFloat:=AncestorInstProp.GetFloat;
if OldFloat=NewFloat then continue;
Changed:=true;
InstProp.SetFloat(NewFloat);
end;
tkClass:
begin
OldObj:=InstProp.GetObject;
NewObj:=AncestorInstProp.GetObject;
if OldObj=NewObj then continue;
Changed:=true;
InstProp.SetObject(NewObj);
end;
tkMethod:
begin
OldMethod:=InstProp.GetMethod;
NewMethod:=AncestorInstProp.GetMethod;
if SameMethod(OldMethod,NewMethod) then continue;
Changed:=true;
InstProp.SetMethod(NewMethod);
end;
tkInterface:
begin
OldInterface:=InstProp.GetInterface;
NewInterface:=AncestorInstProp.GetInterface;
if OldInterface=NewInterface then continue;
Changed:=true;
InstProp.SetInterface(NewInterface);
end;
else
end;
end;
finally
if Changed then
Modified;
end;
end;
procedure TPropertyEditor.SetValue(const NewValue:ansistring);
begin
end;
function TPropertyEditor.ValueAvailable:Boolean;
var
I:Integer;
begin
Result:=True;
for I:=0 to FPropCount-1 do
begin
if (FPropList^[I].Instance is TComponent)
and (csCheckPropAvail in TComponent(FPropList^[I].Instance).ComponentStyle)
then begin
try
GetValue;
AllEqual;
except
Result:=False;
end;
Exit;
end;
end;
end;
function TPropertyEditor.GetInt64Value:Int64;
begin
Result:=GetInt64ValueAt(0);
end;
function TPropertyEditor.GetInt64ValueAt(Index:Integer):Int64;
begin
Result:=FPropList^[Index].GetOrd;
end;
function TPropertyEditor.GetIntfValue: IInterface;
begin
Result := GetIntfValueAt(0);
end;
function TPropertyEditor.GetIntfValueAt(Index: Integer): IInterface;
begin
Result:=FPropList^[Index].GetInterface;
end;
{ these three procedures implement the default render behavior of the
object inspector's drop down list editor. You don't need to
override the two measure procedures if the default width or height don't
need to be changed. }
procedure TPropertyEditor.ListMeasureHeight(const AValue: ansistring;
Index: Integer; ACanvas: TCanvas; var AHeight: Integer);
begin
AHeight := ACanvas.TextHeight(AValue);
end;
procedure TPropertyEditor.ListMeasureWidth(const AValue: ansistring;
Index: Integer; ACanvas: TCanvas; var AWidth: Integer);
begin
//
end;
procedure TPropertyEditor.ListDrawValue(const AValue: ansistring; Index: Integer;
ACanvas: TCanvas; const ARect: TRect; AState: TPropEditDrawState);
var
Style : TTextStyle;
begin
FillChar(Style{%H-},SizeOf(Style),0);
With Style do begin
Alignment := taLeftJustify;
Layout := tlCenter;
Opaque := False;
Clipping := True;
ShowPrefix := True;
WordBreak := False;
SingleLine := True;
SystemFont := False;
end;
ACanvas.TextRect(ARect, ARect.Left+2,ARect.Top,AValue, Style);
end;
{ these three procedures implement the default render behavior of the
object inspector's property row. You don't need to override the measure
procedure if the default height don't need to be changed. }
procedure TPropertyEditor.PropMeasureHeight(const NewValue: ansistring;
ACanvas: TCanvas; var AHeight: Integer);
begin
//
end;
procedure TPropertyEditor.PropDrawName(ACanvas: TCanvas; const ARect: TRect;
AState: TPropEditDrawState);
var
Style : TTextStyle;
begin
FillChar(Style{%H-},SizeOf(Style),0);
With Style do begin
Alignment := taLeftJustify;
Layout := tlCenter;
Opaque := False;
Clipping := True;
ShowPrefix := False;
WordBreak := False;
SingleLine := True;
ExpandTabs := True;
SystemFont := False;
end;
ACanvas.TextRect(ARect,ARect.Left+2,ARect.Top,GetName,Style);
end;
procedure TPropertyEditor.PropDrawValue(ACanvas: TCanvas; const ARect: TRect;
AState: TPropEditDrawState);
begin
DrawValue(GetVisualValue,ACanvas,ARect,AState);
end;
procedure TPropertyEditor.UpdateSubProperties;
begin
if (OnSubPropertiesChanged<>nil) and SubPropertiesNeedsUpdate then
OnSubPropertiesChanged(Self);
end;
function TPropertyEditor.SubPropertiesNeedsUpdate: boolean;
begin
Result:=false;
end;
function TPropertyEditor.ValueIsStreamed: boolean;
begin
Result := CallStoredFunction;
if Result and HasDefaultValue then
Result := GetDefaultValue<>GetVisualValue;
end;
function TPropertyEditor.IsRevertableToInherited: boolean;
begin
Result:=(paRevertable in GetAttributes) and (GetComponent(0) is TComponent)
and (csAncestor in TComponent(GetComponent(0)).ComponentState)
and (PropertyHook<>nil)
and (GetPropType^.Kind in
[tkInteger,tkChar,tkEnumeration,tkBool,tkInt64,tkQWord,
tkSet,
tkString,tkLString,tkAString,
tkWString,
tkUString,
tkFloat,
tkClass,
tkMethod,
tkInterface]);
end;
function TPropertyEditor.GetVerbCount: Integer;
begin
Result:=0;
if HasDefaultValue then
inc(Result); // show a menu item for default value only if there is default value
if IsRevertableToInherited then
inc(Result); // show a menu item for 'Revert to inherited'
end;
function TPropertyEditor.GetVerb(Index: Integer): string;
var
i: Integer;
begin
Result := '';
i:=-1;
if HasDefaultValue then begin
inc(i);
if i=Index then begin
Result := Format(oisSetToDefault, [GetDefaultValue]);
exit;
end;
end;
if IsRevertableToInherited then begin
inc(i);
if i=Index then begin
Result := oisRevertToInherited;
exit;
end;
end;
end;
procedure TPropertyEditor.PrepareItem(Index: Integer; const AnItem: TMenuItem);
begin
// overridden by descendants
end;
procedure TPropertyEditor.ExecuteVerb(Index: Integer);
var
i: Integer;
begin
i:=-1;
if HasDefaultValue then begin
inc(i);
if i=Index then begin
SetValue(GetDefaultValue);
exit;
end;
end;
if IsRevertableToInherited then begin
inc(i);
if i=Index then begin
RevertToInherited;
exit;
end;
end;
end;
{ TInstProp }
function TInstProp.GetTypeInfo: PTypeInfo;
begin
if PropInfo<>nil then
Result:=PropInfo^.PropType
else
Result:=FieldTypeInfo;
end;
function TInstProp.GetKind: TTypeKind;
begin
if PropInfo<>nil then
Result:=PropInfo^.PropType^.Kind
else
Result:=FieldTypeInfo^.Kind;
end;
function TInstProp.GetOrd: int64;
begin
if Field<>nil then
Result:=GetOrdField(Field,FieldTypeInfo)
else
Result:=GetOrdProp(Instance,PropInfo);
end;
procedure TInstProp.SetOrd(const Value: int64);
begin
if Field<>nil then
SetOrdField(Field,FieldTypeInfo,Value)
else
SetOrdProp(Instance,PropInfo,Value);
end;
function TInstProp.GetEnum: string;
begin
if Field<>nil then
Result:=GetEnumField(Field,FieldTypeInfo)
else
Result:=GetEnumProp(Instance,PropInfo);
end;
procedure TInstProp.SetEnum(const Value: string);
begin
if Field<>nil then
SetEnumField(Field,FieldTypeInfo,Value)
else
SetEnumProp(Instance,PropInfo,Value);
end;
function TInstProp.GetSet(Brackets: boolean): string;
begin
if Field<>nil then
Result:=GetSetField(Field,FieldTypeInfo,Brackets)
else
Result:=GetSetProp(Instance,PropInfo,Brackets);
end;
procedure TInstProp.SetSet(const Value: string);
begin
if Field<>nil then
SetSetField(Field,FieldTypeInfo,Value)
else
SetSetProp(Instance,PropInfo,Value);
end;
function TInstProp.GetString: AnsiString;
begin
if Field<>nil then
Result:=GetStringField(Field,FieldTypeInfo)
else
Result:=GetStrProp(Instance,PropInfo);
end;
procedure TInstProp.SetString(const Value: string);
begin
if Field<>nil then
SetStringField(Field,FieldTypeInfo,Value)
else
SetStrProp(Instance,PropInfo,Value);
end;
function TInstProp.GetWideString: WideString;
begin
if Field<>nil then
Result:=GetWideStringField(Field,FieldTypeInfo)
else
Result:=GetWideStrProp(Instance,PropInfo);
end;
procedure TInstProp.SetWideString(const Value: WideString);
begin
if Field<>nil then
SetWideStringField(Field,FieldTypeInfo,Value)
else
SetWideStrProp(Instance,PropInfo,Value);
end;
function TInstProp.GetUnicodeString: UnicodeString;
begin
if Field<>nil then
Result:=GetUnicodeStringField(Field,FieldTypeInfo)
else
Result:=GetUnicodeStrProp(Instance,PropInfo);
end;
procedure TInstProp.SetUnicodeString(const Value: UnicodeString);
begin
if Field<>nil then
SetUnicodeStringField(Field,FieldTypeInfo,Value)
else
SetUnicodeStrProp(Instance,PropInfo,Value);
end;
function TInstProp.GetRawByteString: RawByteString;
begin
if Field<>nil then
Result:=GetRawbyteStringField(Field,FieldTypeInfo)
else
Result:=GetRawbyteStrProp(Instance,PropInfo);
end;
procedure TInstProp.SetRawByteString(const Value: RawByteString);
begin
if Field<>nil then
SetRawbyteStringField(Field,FieldTypeInfo,Value)
else
SetRawByteStrProp(Instance,PropInfo,Value);
end;
function TInstProp.GetFloat: Extended;
begin
if Field<>nil then
Result:=GetFloatField(Field,FieldTypeInfo)
else
Result:=GetFloatProp(Instance,PropInfo);
end;
procedure TInstProp.SetFloat(const Value: Extended);
begin
if Field<>nil then
SetFloatField(Field,FieldTypeInfo,Value)
else
SetFloatProp(Instance,PropInfo,Value);
end;
function TInstProp.GetObject(MinClass: TClass): TObject;
begin
if Field<>nil then
Result:=GetObjectField(Field,FieldTypeInfo,MinClass)
else
Result:=GetObjectProp(Instance,PropInfo,MinClass);
end;
procedure TInstProp.SetObject(const Value: TObject);
begin
if Field<>nil then
SetObjectField(Field,FieldTypeInfo,Value)
else
SetObjectProp(Instance,PropInfo,Value);
end;
function TInstProp.GetPointerValue: Pointer;
begin
if Field<>nil then
Result:=GetPointerField(Field,FieldTypeInfo)
else
Result:=GetPointerProp(Instance,PropInfo);
end;
procedure TInstProp.SetPointerValue(const Value: Pointer);
begin
if Field<>nil then
SetPointerField(Field,FieldTypeInfo,Value)
else
SetPointerProp(Instance,PropInfo,Value);
end;
function TInstProp.GetMethod: TMethod;
begin
if Field<>nil then
Result:=GetMethodField(Field,FieldTypeInfo)
else
Result:=GetMethodProp(Instance,PropInfo);
end;
procedure TInstProp.SetMethod(const Value: TMethod);
begin
if Field<>nil then
SetMethodField(Field,FieldTypeInfo,Value)
else
LazSetMethodProp(Instance,PropInfo,Value);
end;
function TInstProp.GetInterface: IInterface;
begin
if Field<>nil then
Result:=GetInterfaceField(Field,FieldTypeInfo)
else
Result:=GetInterfaceProp(Instance,PropInfo);
end;
procedure TInstProp.SetInterface(const Value: IInterface);
begin
if Field<>nil then
SetInterfaceField(Field,FieldTypeInfo,Value)
else
SetInterfaceProp(Instance,PropInfo,Value);
end;
function TInstProp.GetVariant: Variant;
begin
if Field<>nil then
Result:=GetVariantField(Field,FieldTypeInfo)
else
Result:=GetVariantProp(Instance,PropInfo);
end;
procedure TInstProp.SetVariant(const Value: Variant);
begin
if Field<>nil then
SetVariantField(Field,FieldTypeInfo,Value)
else
SetVariantProp(Instance,PropInfo,Value);
end;
{ TOrdinalPropertyEditor }
function TOrdinalPropertyEditor.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 TOrdinalPropertyEditor.GetEditLimit: Integer;
begin
Result := 63;
end;
function TOrdinalPropertyEditor.GetValue: ansistring;
begin
Result:=OrdValueToVisualValue(GetOrdValue);
end;
function TOrdinalPropertyEditor.GetDefaultValue: ansistring;
begin
Result:=OrdValueToVisualValue(GetDefaultOrdValue);
end;
function TOrdinalPropertyEditor.OrdValueToVisualValue(OrdValue: longint): string;
begin
Result:=IntToStr(OrdValue);
end;
{ TIntegerPropertyEditor }
function TIntegerPropertyEditor.OrdValueToVisualValue(OrdValue: longint): string;
begin
with GetTypeData(GetPropType)^ do begin
{debugln('TIntegerPropertyEditor.OrdValueToVisualValue ',GetName,' ',dbgs(ord(OrdType)),' ',dbgs(OrdValue));
case OrdType of
otSByte : debugln('TIntegerPropertyEditor.OrdValueToVisualValue otSByte ',dbgs(ShortInt(OrdValue)));
otUByte : debugln('TIntegerPropertyEditor.OrdValueToVisualValue otUByte ',dbgs(Byte(OrdValue)));
otSWord : debugln('TIntegerPropertyEditor.OrdValueToVisualValue otSWord ',dbgs(SmallInt(OrdValue)));
otUWord : debugln('TIntegerPropertyEditor.OrdValueToVisualValue otUWord ',dbgs(Word(OrdValue)));
otULong : debugln('TIntegerPropertyEditor.OrdValueToVisualValue otULong ',dbgs(Cardinal(OrdValue)));
else debugln('TIntegerPropertyEditor.OrdValueToVisualValue ??? ',dbgs(OrdValue));
end;}
case OrdType of
otSByte : Result:= IntToStr(ShortInt(OrdValue));
otUByte : Result:= IntToStr(Byte(OrdValue));
otSWord : Result:= IntToStr(Integer(SmallInt(OrdValue)));// double conversion needed due to compiler bug 3534
otUWord : Result:= IntToStr(Word(OrdValue));
otULong : Result:= IntToStr(Cardinal(OrdValue));
else Result := IntToStr(OrdValue);
end;
//debugln('TIntegerPropertyEditor.OrdValueToVisualValue ',Result);
end;
end;
procedure TIntegerPropertyEditor.SetValue(const NewValue: AnsiString);
procedure Error(const Args: array of const);
begin
raise EPropertyError.CreateResFmt(@SOutOfRange, Args);
end;
var
L: Int64;
begin
L := StrToInt64(NewValue);
with GetTypeData(GetPropType)^ do
if OrdType = otULong then
begin // unsigned compare and reporting needed
if (L < Cardinal(MinValue)) or (L > Cardinal(MaxValue)) then begin
// bump up to Int64 to get past the %d in the format string
Error([Int64(Cardinal(MinValue)), Int64(Cardinal(MaxValue))]);
exit;
end
end
else if (L < MinValue) or (L > MaxValue) then begin
Error([MinValue, MaxValue]);
exit;
end;
SetOrdValue(integer(L));
end;
{ TCharPropertyEditor }
function TCharPropertyEditor.OrdValueToVisualValue(OrdValue: longint): string;
var
Ch: Char;
begin
Ch := Chr(OrdValue);
if Ch in [#33..#127] then
Result := Ch
else
Result:='#'+IntToStr(Ord(Ch));
end;
procedure TCharPropertyEditor.SetValue(const NewValue: ansistring);
var
L: Longint;
begin
if Length(NewValue) = 0 then L := 0 else
if Length(NewValue) = 1 then L := Ord(NewValue[1]) else
if NewValue[1] = '#' then L := StrToInt(Copy(NewValue, 2, Maxint)) else
begin
{raise EPropertyError.CreateRes(@SInvalidPropertyValue)};
exit;
end;
with GetTypeData(GetPropType)^ do
//Only Chars < #$80 are valid single-byte UTF-8 codepoints,
//so use this instead of MaxValue (255 for tkChar), since LCL is UTF-8
if (L < MinValue) or (L > $7F) then begin
{raise EPropertyError.CreateResFmt(@SOutOfRange, [MinValue, MaxValue])};
exit;
end;
SetOrdValue(L);
end;
{ TEnumPropertyEditor }
function TEnumPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paValueList, paSortList, paRevertable];
end;
function TEnumPropertyEditor.OrdValueToVisualValue(OrdValue: longint): string;
var
L: Longint;
TypeData: PTypeData;
begin
L := OrdValue;
TypeData := GetTypeData(GetPropType);
with TypeData^ do
if (L < MinValue) or (L > MaxValue) then
L := MaxValue;
Result := GetEnumName(GetPropType, L);
end;
function TEnumPropertyEditor.GetVisualValue: ansistring;
begin
if FInvalid then
Result := oisInvalid
else
Result := inherited GetVisualValue;
end;
procedure TEnumPropertyEditor.GetValues(Proc: TGetStrProc);
var
I: Integer;
EnumType: PTypeInfo;
s: String;
begin
EnumType := GetPropType;
with GetTypeData(EnumType)^ do
for I := MinValue to MaxValue do begin
s := GetEnumName(EnumType, I);
Proc(s);
end;
end;
procedure TEnumPropertyEditor.SetValue(const NewValue: ansistring);
var
I: Integer;
begin
I := GetEnumValue(GetPropType, NewValue);
FInvalid := I < 0;
if not FInvalid then
SetOrdValue(I);
end;
{ TBoolPropertyEditor }
function TBoolPropertyEditor.OrdValueToVisualValue(OrdValue: longint): string;
begin
if OrdValue = 0 then
Result := 'False'
else
Result := 'True';
if FPropertyHook.GetCheckboxForBoolean then
Result := '(' + Result + ')';
end;
function TBoolPropertyEditor.GetVisualValue: ansistring;
begin
Result := inherited GetVisualValue;
if Result = '' then
Result := oisMixed;
end;
procedure TBoolPropertyEditor.GetValues(Proc: TGetStrProc);
begin
Proc('False');
Proc('True');
end;
procedure TBoolPropertyEditor.SetValue(const NewValue: ansistring);
var
I: Integer;
begin
if (CompareText(NewValue, 'False') = 0)
or (CompareText(NewValue, '(False)') = 0)
or (CompareText(NewValue, 'F') = 0) then
I := 0
else
if (CompareText(NewValue, 'True') = 0)
or (CompareText(NewValue, '(True)') = 0)
or (CompareText(NewValue, 'T') = 0) then
I := 1
else
I := StrToInt(NewValue);
SetOrdValue(I);
end;
procedure TBoolPropertyEditor.PropDrawValue(ACanvas: TCanvas; const ARect: TRect;
AState: TPropEditDrawState);
var
TxtRect: TRect;
begin
TxtRect := DrawCheckValue(ACanvas, ARect, AState, GetOrdValue<>0);
if TxtRect.Top <> -100 then
inherited PropDrawValue(ACanvas, TxtRect, AState);
end;
{ TInt64PropertyEditor }
function TInt64PropertyEditor.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 TInt64PropertyEditor.GetEditLimit: Integer;
begin
Result := 63;
end;
function TInt64PropertyEditor.GetValue: ansistring;
begin
Result := IntToStr(GetInt64Value);
end;
procedure TInt64PropertyEditor.SetValue(const NewValue: ansistring);
begin
SetInt64Value(StrToInt64(NewValue));
end;
{ TQWordPropertyEditor }
function TQWordPropertyEditor.GetValue: ansistring;
begin
Result := IntToStr(QWord(GetInt64Value));
end;
procedure TQWordPropertyEditor.SetValue(const NewValue: ansistring);
begin
SetInt64Value(Int64(StrToQWord(NewValue)));
end;
{ TFloatPropertyEditor }
function TFloatPropertyEditor.FloatInRange(AValue: Extended; AType: TFloatType): Boolean;
{$ifndef FPC_HAS_TYPE_DOUBLE}
const MaxDouble = Math.MaxSingle;
{$endif}
{$ifndef FPC_HAS_TYPE_EXTENDED}
const MaxExtended = MaxDouble;
{$endif}
{$ifndef FPC_HAS_TYPE_COMP}
const
MaxComp = 9223372036854775807;
MinComp = -9223372036854775808;
{$endif}
begin
try
case AType of
ftSingle: Result := {$ifndef FPC_HAS_TYPE_DOUBLE}
//Extended=Single, so anything out of range of a Single will be +/-Infinity
not IsInfinite(AValue);
{$else}
(AValue <= MaxSingle) and (AValue >= -MaxSingle);
{$endif}
ftDouble: Result := {$ifndef FPC_HAS_TYPE_EXTENDED}
//Extended=Double, so anything out of range of a Double will be +/-Infinity
not IsInfinite(AValue);
{$else}
(AValue <= MaxDouble) and (AValue >= -MaxDouble);
{$endif}
ftExtended: Result := not IsInfinite(AValue);
ftComp: Result := (AValue <= MaxComp) and (AValue >= MinComp);
ftCurr: Result := (AValue <= MaxCurrency) and (AValue >= MinCurrency);
end;
except
//Currency comparisons can cause Floating Point overflow on Win64 (i.e. compared with +/-MaxDouble, +/-MaxExtended, MaxComp, MinComp, +/-Inf)
//and on Win32 (i.e with +/-MaxExtended), not tested other platforms
Result := False;
end;
end;
function TFloatPropertyEditor.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 TFloatPropertyEditor.FormatValue(const AValue: Extended): ansistring;
const
Precisions: array[TFloatType] of Integer = (7, 15, 19, 19, 19);
var
FS: TFormatSettings;
begin
FS := DefaultFormatSettings;
FS.DecimalSeparator := '.'; //It's Pascal sourcecode representation of a float, not a textual (i18n) one
Result := FloatToStrF(AValue, ffGeneral,
Precisions[GetTypeData(GetPropType)^.FloatType], 0, FS);
end;
function TFloatPropertyEditor.GetDefaultValue: ansistring;
begin
if not HasDefaultValue then
raise EPropertyError.Create('No property default available');
Result:=FormatValue(0);
end;
function TFloatPropertyEditor.GetValue: ansistring;
begin
Result := FormatValue(GetFloatValue);
end;
procedure TFloatPropertyEditor.SetValue(const NewValue: ansistring);
var
FS: TFormatSettings;
NewFloat: Extended;
fType: TFloatType;
begin
//writeln('TFloatPropertyEditor.SetValue A ',NewValue,' ',StrToFloat(NewValue));
FS := DefaultFormatSettings;
FS.DecimalSeparator := '.'; //after all, this is Pascal, so we expect a period
if not TryStrToFloat(NewValue, NewFloat, FS) then
//if this failed, assume the user entered DS from his current locale
NewFloat := StrToFloat(NewValue, DefaultFormatSettings);
//conversion succeeded, out of range input gets converted to +/-Inf as well, not only literal user input as '+Inf'
//so check user input instead of IsInfinite now
if (Pos('inf',LowerCase(NewValue)) > 0) then
raise EPropertyError.Create(oisInfinityNotSupported);
//Check NaN before checking for range, since you cannot compare NaN to anything
if IsNan(NewFloat) then
raise EPropertyError.Create(oisNaNNotSupported);
fType := GetTypeData(GetPropType)^.FloatType;
if not FloatInRange(NewFloat, fType) then
raise EPropertyError.Create(oisValueOutOfRange);
SetFloatValue(NewFloat);
//writeln('TFloatPropertyEditor.SetValue B ',GetValue);
end;
{ TStringPropertyEditor }
function TStringPropertyEditor.AllEqual: Boolean;
var
I: Integer;
V: ansistring;
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 TStringPropertyEditor.GetEditLimit: Integer;
begin
if GetPropType^.Kind = tkSString then
Result := GetTypeData(GetPropType)^.MaxLength
else
Result := $0FFF;
end;
function TStringPropertyEditor.GetValue: ansistring;
begin
Result := GetStrValue;
end;
procedure TStringPropertyEditor.SetValue(const NewValue: ansistring);
begin
SetStrValue(NewValue);
end;
{ TPasswordStringPropertyEditor }
function TPasswordStringPropertyEditor.GetPassword: string;
begin
if GetVisualValue<>'' then
Result:='*****'
else
Result:='';
end;
procedure TPasswordStringPropertyEditor.PropDrawValue(ACanvas: TCanvas;
const ARect: TRect; AState: TPropEditDrawState);
begin
DrawValue(GetPassword,ACanvas,ARect,AState);
end;
{ TWideStringPropertyEditor }
function TWideStringPropertyEditor.AllEqual: Boolean;
var
I: Integer;
V: widestring;
begin
Result := False;
if PropCount > 1 then begin
V := GetWideStrValue;
for I := 1 to PropCount - 1 do
if GetWideStrValueAt(I) <> V then Exit;
end;
Result := True;
end;
function TWideStringPropertyEditor.GetValue: ansistring;
begin
Result:=UTF8Encode(GetWideStrValue);
end;
procedure TWideStringPropertyEditor.SetValue(const NewValue: ansistring);
begin
SetWideStrValue(UTF8Decode(NewValue));
end;
{ TPasswordWideStringPropertyEditor }
function TPasswordWideStringPropertyEditor.GetPassword: WideString;
begin
if GetVisualValue<>'' then
Result:='*****'
else
Result:='';
end;
procedure TPasswordWideStringPropertyEditor.PropDrawValue(ACanvas: TCanvas;
const ARect: TRect; AState: TPropEditDrawState);
begin
DrawValue(UTF8Encode(GetPassword),ACanvas,ARect,AState);
end;
{ TUnicodeStringPropertyEditor }
function TUnicodeStringPropertyEditor.AllEqual: Boolean;
var
I: Integer;
V: UnicodeString;
begin
Result := False;
if PropCount > 1 then begin
V := GetUnicodeStrValue;
for I := 1 to PropCount - 1 do
if GetUnicodeStrValueAt(I) <> V then Exit;
end;
Result := True;
end;
function TUnicodeStringPropertyEditor.GetValue: ansistring;
begin
Result:=UTF8Encode(GetUnicodeStrValue);
end;
procedure TUnicodeStringPropertyEditor.SetValue(const NewValue: ansistring);
begin
SetUnicodeStrValue(UTF8Decode(NewValue));
end;
{ TNestedPropertyEditor }
constructor TNestedPropertyEditor.Create(Parent: TPropertyEditor);
begin
FParentEditor:=Parent;
FPropertyHook:=Parent.PropertyHook;
FPropList:=Parent.FPropList;
FPropCount:=Parent.PropCount;
end;
destructor TNestedPropertyEditor.Destroy;
begin
end;
{ TSetElementPropertyEditor }
constructor TSetElementPropertyEditor.Create(Parent: TPropertyEditor;
AElement: Integer);
begin
inherited Create(Parent);
FElement := AElement;
end;
// The IntegerSet (a set of size of an integer)
// don't know if this is always valid
type
TIntegerSet = set of 0..SizeOf(Integer) * 8 - 1;
function TSetElementPropertyEditor.AllEqual: Boolean;
var
I: Integer;
S: TIntegerSet;
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 TSetElementPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paValueList, paSortList];
end;
function TSetElementPropertyEditor.GetName: shortstring;
begin
Result := GetEnumName(GetTypeData(GetPropType)^.CompType, FElement);
end;
function TSetElementPropertyEditor.GetValue: ansistring;
var
S: TIntegerSet;
begin
Integer(S) := GetOrdValue;
Result := BooleanIdents[FElement in S];
if FPropertyHook.GetCheckboxForBoolean then
Result := '(' + Result + ')';
end;
function TSetElementPropertyEditor.GetVerbCount: Integer;
begin
Result:=0;
end;
function TSetElementPropertyEditor.GetVisualValue: ansistring;
begin
Result := inherited GetVisualValue;
if Result = '' then
Result := oisMixed;
end;
procedure TSetElementPropertyEditor.GetValues(Proc: TGetStrProc);
begin
Proc(BooleanIdents[False]);
Proc(BooleanIdents[True]);
end;
procedure TSetElementPropertyEditor.SetValue(const NewValue: ansistring);
var
S: TIntegerSet;
begin
Integer(S) := GetOrdValue;
if (CompareText(NewValue, 'True') = 0)
or (CompareText(NewValue, '(True)') = 0) then
Include(S, FElement)
else
Exclude(S, FElement);
SetOrdValue(Integer(S));
end;
function TSetElementPropertyEditor.ValueIsStreamed: boolean;
var
S1, S2: TIntegerSet;
begin
Result := CallStoredFunction;
if Result and HasDefaultValue then
begin
Integer(S1) := GetOrdValue;
Integer(S2) := GetDefaultOrdValue;
Result := (FElement in S1) <> (FElement in S2);
end;
end;
procedure TSetElementPropertyEditor.PropDrawValue(ACanvas: TCanvas; const ARect: TRect;
AState: TPropEditDrawState);
var
S: TIntegerSet;
TxtRect: TRect;
begin
Integer(S) := GetOrdValue;
TxtRect := DrawCheckValue(ACanvas, ARect, AState, FElement in S);
if TxtRect.Top <> -100 then
inherited PropDrawValue(ACanvas, TxtRect, AState);
end;
{ TSetPropertyEditor }
function TSetPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paSubProperties, paReadOnly, paRevertable];
end;
function TSetPropertyEditor.GetEditLimit: Integer;
begin
Result := 0;
end;
procedure TSetPropertyEditor.GetProperties(Proc: TGetPropEditProc);
var
I: Integer;
EnumType: PTypeInfo;
begin
EnumType := GetTypeData(GetPropType)^.CompType;
with GetTypeData(EnumType)^ do
for I := MinValue to MaxValue do
Proc(TSetElementPropertyEditor.Create(Self, I));
end;
procedure TSetPropertyEditor.SetValue(const NewValue: ansistring);
var
S: TIntegerSet;
TypeInfo: PTypeInfo;
I: Integer;
begin
S := [];
TypeInfo := GetTypeData(GetPropType)^.CompType;
for I := 0 to SizeOf(Integer) * 8 - 1 do
if Pos(GetEnumName(TypeInfo, I), NewValue) > 0 then
Include(S, I);
SetOrdValue(Integer(S));
end;
function TSetPropertyEditor.OrdValueToVisualValue(OrdValue: longint): string;
var
S: TIntegerSet;
TypeInfo: PTypeInfo;
I: Integer;
begin
Integer(S) := OrdValue;
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;
{ TStructurePropertyEditor }
function TStructurePropertyEditor.EditorFilter(const AEditor: TPropertyEditor): Boolean;
begin
Result := IsInteresting(AEditor, SubPropsTypeFilter, SubPropsNameFilter);
end;
procedure TStructurePropertyEditor.ListSubProps(Prop: TPropertyEditor);
begin
FSubProps.Add(Prop);
end;
procedure TStructurePropertyEditor.SetSubPropsTypeFilter(const AValue: TTypeKinds);
begin
if FSubPropsTypeFilter = AValue then exit;
FSubPropsTypeFilter := AValue;
end;
constructor TStructurePropertyEditor.Create(Hook: TPropertyEditorHook; APropCount: Integer);
begin
inherited Create(Hook, APropCount);
FSubPropsTypeFilter := tkAny;
end;
destructor TStructurePropertyEditor.Destroy;
begin
FreeAndNil(FSubProps);
inherited Destroy;
end;
function TStructurePropertyEditor.AllEqual: Boolean;
begin
Result:=true;
end;
{ TListElementPropertyEditor }
constructor TListElementPropertyEditor.Create(Parent: TListPropertyEditor;
AnIndex: integer);
begin
inherited Create(Parent);
FList:=Parent;
FIndex:=AnIndex;
end;
destructor TListElementPropertyEditor.Destroy;
begin
inherited Destroy;
end;
function TListElementPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result:=List.GetElementAttributes(Self);
end;
function TListElementPropertyEditor.GetName: shortstring;
begin
Result:=List.GetElementName(Self);
end;
procedure TListElementPropertyEditor.GetProperties(Proc: TGetPropEditProc);
begin
List.GetElementProperties(Self,Proc);
end;
function TListElementPropertyEditor.GetValue: ansistring;
begin
Result:=List.GetElementValue(Self);
end;
procedure TListElementPropertyEditor.GetValues(Proc: TGetStrProc);
begin
List.GetElementValues(Self,Proc);
end;
procedure TListElementPropertyEditor.SetValue(const NewValue: ansistring);
begin
List.SetElementValue(Self,NewValue);
end;
{ TListPropertyEditor }
function TListPropertyEditor.GetElementCount: integer;
begin
if not IsSaving then
Result:=SavedElements.Count
else
Result:=ReadElementCount;
end;
function TListPropertyEditor.GetElement(Index: integer): TPersistent;
var
ElementCount: integer;
begin
// do some checks
if (Index<0) then
raise Exception.Create('TListPropertyEditor.GetElement Index='+IntToStr(Index));
ElementCount:=GetElementCount;
if Index>=ElementCount then
raise Exception.Create('TListPropertyEditor.GetElement Index='+IntToStr(Index)
+' Count='+IntToStr(ElementCount));
// get element
if not IsSaving then
Result:=TPersistent(SavedElements[Index])
else
Result:=ReadElement(Index);
end;
function TListPropertyEditor.GetElement(Element: TListElementPropertyEditor
): TPersistent;
begin
Result:=GetElement(Element.TheIndex);
end;
function TListPropertyEditor.GetElementPropEditor(Index: integer
): TListElementPropertyEditor;
// called by GetProperties to get the element property editors
begin
if not IsSaving then
Result:=TListElementPropertyEditor(SavedPropertyEditors[Index])
else
Result:=CreateElementPropEditor(Index);
end;
procedure TListPropertyEditor.SaveElements;
begin
if IsSaving then exit;
BeginSaveElement;
FreeElementPropertyEditors;
DoSaveElements;
FSubPropertiesChanged:=false;
EndSaveElement;
end;
function TListPropertyEditor.SubPropertiesNeedsUpdate: boolean;
var i: integer;
begin
Result:=true;
if FSubPropertiesChanged then exit;
FSubPropertiesChanged:=true;
if SavedList<>GetComponent(0) then exit;
if ReadElementCount<>SavedElements.Count then exit;
for i:=0 to SavedElements.Count-1 do
if TPersistent(SavedElements[i])<>ReadElement(i) then exit;
Result:=false;
FSubPropertiesChanged:=false;
end;
function TListPropertyEditor.ReadElementCount: integer;
var
TheList: TObject;
begin
TheList := GetObjectValue;
if TheList is TList then
Result := TList(TheList).Count
else
Result := 0;
end;
function TListPropertyEditor.ReadElement(Index: integer): TPersistent;
var
obj: TObject;
begin
obj := TObject(TList(GetObjectValue).Items[Index]);
if obj is TPersistent then
Result:=TPersistent(obj)
else
raise EInvalidOperation.CreateFmt('List element %d is not a TPersistent descendant', [Index]);
end;
function TListPropertyEditor.CreateElementPropEditor(Index: integer
): TListElementPropertyEditor;
begin
Result:=TListElementPropertyEditor.Create(Self,Index);
end;
procedure TListPropertyEditor.BeginSaveElement;
begin
inc(FSaveElementLock);
end;
procedure TListPropertyEditor.EndSaveElement;
begin
dec(FSaveElementLock);
if FSaveElementLock<0 then
DebugLn('TListPropertyEditor.EndSaveElement ERROR: FSaveElementLock=',
IntToStr(FSaveElementLock));
end;
procedure TListPropertyEditor.DoSaveElements;
var
i, ElementCount: integer;
begin
SavedList:=GetComponent(0);
ElementCount:=GetElementCount;
SavedElements.Count:=ElementCount;
for i:=0 to ElementCount-1 do
SavedElements[i]:=GetElement(i);
SavedPropertyEditors.Count:=ElementCount;
for i:=0 to ElementCount-1 do
SavedPropertyEditors[i]:=GetElementPropEditor(i);
end;
procedure TListPropertyEditor.FreeElementPropertyEditors;
var
i: integer;
begin
for i:=0 to SavedPropertyEditors.Count-1 do
TObject(SavedPropertyEditors[i]).Free;
SavedPropertyEditors.Clear;
end;
function TListPropertyEditor.GetElementAttributes(
Element: TListElementPropertyEditor
): TPropertyAttributes;
begin
Result:= [paReadOnly];
end;
function TListPropertyEditor.GetElementName(Element: TListElementPropertyEditor
): shortstring;
begin
Result:='';
end;
procedure TListPropertyEditor.GetElementProperties(
Element: TListElementPropertyEditor; Proc: TGetPropEditProc);
begin
end;
function TListPropertyEditor.GetElementValue(Element: TListElementPropertyEditor
): ansistring;
begin
Result:='';
end;
procedure TListPropertyEditor.GetElementValues(
Element: TListElementPropertyEditor; Proc: TGetStrProc);
begin
end;
procedure TListPropertyEditor.SetElementValue(
Element: TListElementPropertyEditor; NewValue: ansistring);
begin
end;
function TListPropertyEditor.IsSaving: boolean;
begin
Result:=SaveElementLock>0;
end;
constructor TListPropertyEditor.Create(Hook: TPropertyEditorHook;
APropCount: Integer);
begin
inherited Create(Hook, APropCount);
SavedElements:=TList.Create;
SavedPropertyEditors:=TList.Create;
end;
destructor TListPropertyEditor.Destroy;
begin
UnregisterListPropertyEditor(Self);
FreeElementPropertyEditors;
FreeAndNil(SavedPropertyEditors);
FreeAndNil(SavedElements);
inherited Destroy;
end;
function TListPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result:= [paSubProperties, paDynamicSubProps, paReadOnly, paDialog];
end;
procedure TListPropertyEditor.GetProperties(Proc: TGetPropEditProc);
var
i, ElementCount: integer;
begin
SaveElements;
ElementCount:=GetElementCount;
for i:=0 to ElementCount-1 do
Proc(GetElementPropEditor(i));
end;
function TListPropertyEditor.GetValue: AnsiString;
var
ElementCount: integer;
begin
ElementCount:=GetElementCount;
if ElementCount<>1 then
Result:=IntToStr(GetElementCount)+' items'
else
Result:='1 item';
end;
procedure TListPropertyEditor.Initialize;
begin
inherited Initialize;
RegisterListPropertyEditor(Self);
SaveElements;
end;
const
CollectionForm: TCollectionPropertyEditorForm = nil;
// - - - - - - - - - - - - - - - - - - - - - - - - - -
function TCollectionPropertyEditor.ReadElement(Index: integer): TPersistent;
var
Collection: TCollection;
begin
Collection:=TCollection(GetObjectValue);
Result:=Collection.Items[Index];
end;
function TCollectionPropertyEditor.GetElementAttributes(
Element: TListElementPropertyEditor): TPropertyAttributes;
begin
Result := [paSubProperties, paReadOnly];
end;
function TCollectionPropertyEditor.GetElementName(
Element: TListElementPropertyEditor): shortstring;
begin
Result:=inherited GetElementName(Element);
end;
procedure TCollectionPropertyEditor.GetElementProperties(
Element: TListElementPropertyEditor; Proc: TGetPropEditProc);
begin
GetPersistentProperties(GetElement(Element),tkProperties,PropertyHook,Proc,nil);
end;
function TCollectionPropertyEditor.GetElementValue(
Element: TListElementPropertyEditor): ansistring;
begin
Result:=IntToStr(TCollectionItem(GetElement(Element)).ID);
end;
procedure TCollectionPropertyEditor.GetElementValues(
Element: TListElementPropertyEditor; Proc: TGetStrProc);
begin
inherited GetElementValues(Element, Proc);
end;
procedure TCollectionPropertyEditor.SetElementValue(
Element: TListElementPropertyEditor; NewValue: ansistring);
begin
inherited SetElementValue(Element, NewValue);
end;
function TCollectionPropertyEditor.ReadElementCount: integer;
var
Collection: TObject;
begin
Collection := GetObjectValue;
if Collection is TCollection then
Result := TCollection(Collection).Count
else
Result := 0;
end;
function TCollectionPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paDialog, paReadOnly];
end;
class function TCollectionPropertyEditor.ShowCollectionEditor(
ACollection: TCollection;
OwnerPersistent: TPersistent;
const PropName: String): TCustomForm;
begin
if CollectionForm = nil then
CollectionForm := TCollectionPropertyEditorForm.Create(Application);
CollectionForm.SetCollection(ACollection, OwnerPersistent, PropName);
CollectionForm.actAdd.Visible := true;
CollectionForm.actDel.Visible := true;
CollectionForm.AddButton.Left := 0;
CollectionForm.DeleteButton.Left := 1;
CollectionForm.DividerToolButton.Show;
CollectionForm.DividerToolButton.Left := CollectionForm.DeleteButton.Left + 1;
SetPopupModeParentForPropertyEditor(CollectionForm);
CollectionForm.EnsureVisible;
CollectionForm.UpdateButtons;
Result:=CollectionForm;
end;
procedure TCollectionPropertyEditor.Edit;
var
TheCollection: TCollection;
begin
TheCollection := TCollection(GetObjectValue);
if TheCollection = nil then
raise Exception.Create('Collection=nil');
ShowCollectionEditor(TheCollection, GetComponent(0), GetName);
end;
{ TDisabledCollectionPropertyEditor }
function TDisabledCollectionPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paDialog, paReadOnly, paDisableSubProperties];
end;
{ TNoAddDeleteCollectionPropertyEditor }
class function TNoAddDeleteCollectionPropertyEditor.ShowCollectionEditor(
ACollection: TCollection; OwnerPersistent: TPersistent;
const PropName: String): TCustomForm;
begin
if CollectionForm = nil then
CollectionForm := TCollectionPropertyEditorForm.Create(Application);
CollectionForm.SetCollection(ACollection, OwnerPersistent, PropName);
CollectionForm.actAdd.Visible := false;
CollectionForm.actDel.Visible := false;
CollectionForm.DividerToolButton.Hide;
SetPopupModeParentForPropertyEditor(CollectionForm);
CollectionForm.EnsureVisible;
CollectionForm.UpdateButtons;
Result := CollectionForm;
end;
{ TClassPropertyEditor }
function TClassPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paSubProperties, paReadOnly];
end;
procedure TClassPropertyEditor.GetProperties(Proc: TGetPropEditProc);
var
selection: TPersistentSelectionList;
begin
selection := GetSelections;
if selection = nil then exit;
GetPersistentProperties(
selection, SubPropsTypeFilter + [tkClass], PropertyHook, Proc, @EditorFilter);
selection.Free;
end;
function TClassPropertyEditor.GetSelections: TPersistentSelectionList;
var
i: Integer;
subItem: TPersistent;
begin
Result := TPersistentSelectionList.Create;
try
for i := 0 to PropCount - 1 do begin
subItem := TPersistent(GetObjectValueAt(i));
if subItem <> nil then
Result.Add(subItem);
end;
except
Result.Free;
raise;
end;
end;
function TClassPropertyEditor.GetValue: String;
begin
if FHideClassName then
Result:=''
else
Result:='(' + GetPropType^.Name + ')';
end;
function TClassPropertyEditor.ValueIsStreamed: boolean;
var
I: Integer;
begin
Result := inherited ValueIsStreamed;
if not Result then
Exit;
if FSubProps=nil then
begin
FSubProps := TObjectList.Create(True);
GetProperties(@ListSubProps);
end;
for I := 0 to FSubProps.Count-1 do
if TPropertyEditor(FSubProps[I]).ValueIsStreamed then
Exit(True);
Result := False;
end;
{ TMethodPropertyEditor }
function TMethodPropertyEditor.AllEqual: Boolean;
var
I: Integer;
CurFirstValue, AnotherValue: TMethod;
begin
Result := False;
if PropCount > 1 then begin
CurFirstValue := GetMethodValue;
for I := 1 to PropCount - 1 do begin
AnotherValue := GetMethodValueAt(I);
// Note: compare Code and Data
if (AnotherValue.Code <> CurFirstValue.Code)
or (AnotherValue.Data <> CurFirstValue.Data) then
Exit;
end;
end;
Result := True;
end;
procedure TMethodPropertyEditor.Edit;
{ If the method does not exist in current lookuproot: create it
Then jump to the source.
For inherited methods this means: A new method is created and a call of
the ancestor value is added. Then the IDE jumps to the new method body.
}
var
NewMethodName: String;
r: TModalResult;
begin
NewMethodName := GetValue;
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.Edit OldValue="',NewMethodName,'" FromLookupRoot=',(IsValidIdent(NewMethodName, True, True) and PropertyHook.MethodFromLookupRoot(GetMethodValue))]);
DumpStack;
{$ENDIF}
if IsValidIdent(NewMethodName)
and PropertyHook.MethodFromLookupRoot(GetMethodValue) then
begin
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.Edit Show']);
{$ENDIF}
PropertyHook.ShowMethod(NewMethodName);
end else begin
// the current method is from the another class (e.g. ancestor or frame)
if IsValidIdent(NewMethodName) then
r:=QuestionDlg('Override or jump',
'The event "'+GetName+'" currently points to an inherited method.',
mtConfirmation,[mrYes,'Create Override',mrOk,'Jump to inherited method',mrCancel],
0)
else
r:=mrYes;
case r of
mrYes:
begin
// -> add an override with the default name
NewMethodName := GetFormMethodName;
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.Edit NewValue="',NewMethodName,'"']);
{$ENDIF}
Assert(IsValidIdent(NewMethodName),'Method name "'+NewMethodName+'" must be an identifier');
NewMethodName:=PropertyHook.LookupRoot.ClassName+'.'+NewMethodName;
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.Edit CreateMethod "',NewMethodName,'"...']);
{$ENDIF}
SetMethodValue(PropertyHook.CreateMethod(NewMethodName, GetPropType,
GetComponent(0), GetPropertyPath(0)));
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.Edit CHANGED new method=',GetValue]);
{$ENDIF}
PropertyHook.RefreshPropertyValues;
ShowValue;
end;
mrOk:
begin
// -> jump to ancestor method
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.Edit Jump to ancestor method ',NewMethodName]);
{$ENDIF}
PropertyHook.ShowMethod(NewMethodName);
end;
end;
end;
end;
procedure TMethodPropertyEditor.ShowValue;
var
CurMethodName: String;
begin
CurMethodName:=GetValue;
PropertyHook.ShowMethod(CurMethodName);
end;
function TMethodPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paDialog, paValueList, paSortList, paRevertable];
end;
function TMethodPropertyEditor.GetEditLimit: Integer;
begin
Result := 2*MaxIdentLength+1; // clasname.methodname
end;
function TrimNonAscii(const Txt: String): String;
// ToDo: Find a similar function from FPC libs and use it instead.
var
I: Integer;
begin
Result := Txt;
for I := Length(Result) downto 1 do
if not (
(Result[I] in ['a'..'z', 'A'..'Z', '_']) or
(I > 1) and (Result[I] in ['0'..'9'])
)
then
Delete(Result, I, 1);
end;
function TrimDotsAndBrackets(const Txt: String): String;
var
I: Integer;
begin
Result := Txt;
for I := Length(Result) downto 1 do
if Result[I] in ['.','[',']'] then
Delete(Result, I, 1);
end;
function TrimEventName(const aName: shortstring): shortstring;
begin
Result := aName;
if (Length(Result) >= 2)
and (Result[1] in ['O','o']) and (Result[2] in ['N','n'])
then
Delete(Result, 1, 2);
end;
function TMethodPropertyEditor.GetTrimmedEventName: shortstring;
begin
Result := TrimEventName(GetName);
end;
function MethodNameSub(Root: TPersistent): shortstring;
begin
if Root is TCustomForm then
Result := 'Form'
else
if Root is TDataModule then
Result := 'DataModule'
else
if Root is TFrame then
Result := 'Frame'
else
Result := '';
end;
function TMethodPropertyEditor.GetFormMethodName: shortstring;
// returns the default name for a new method
begin
Result := '';
if PropertyHook.LookupRoot=nil then exit;
if GetComponent(0) = PropertyHook.LookupRoot then begin
Result := MethodNameSub(PropertyHook.LookupRoot);
if Result = '' then
Result := ClassNameToComponentName(PropertyHook.GetRootClassName);
end
else
Result := TrimNonAscii(PropertyHook.GetObjectName(GetComponent(0), FOwnerComponent));
if Result = '' then
exit;
Result := Result + GetTrimmedEventName;
end;
class function TMethodPropertyEditor.GetDefaultMethodName(Root, Component: TComponent;
const RootClassName, ComponentName, PropName: shortstring): shortstring;
// returns the default name for a new method
begin
Result := '';
if Root=nil then exit;
if Component = Root then begin
Result := MethodNameSub(Root);
if Result = '' then
Result := ClassNameToComponentName(RootClassName);
end
else
Result := TrimDotsAndBrackets(ComponentName);
if Result <> '' then
Result := Result + TrimEventName(PropName)
else
DebugLn(['TMethodPropertyEditor.GetDefaultMethodName cannot create name - should never happen']);
end;
function TMethodPropertyEditor.GetValue: ansistring;
begin
if Assigned(PropertyHook) then
Result:=PropertyHook.GetMethodName(GetMethodValue,GetComponent(0))
else begin
Result:='';
debugln(['TMethodPropertyEditor.GetValue : PropertyHook=Nil Name=',GetName,' Data=',dbgs(GetMethodValue.Data)]);
end;
end;
procedure TMethodPropertyEditor.GetValues(Proc: TGetStrProc);
begin
//DebugLn('### TMethodPropertyEditor.GetValues');
Proc(oisNone);
PropertyHook.GetCompatibleMethods(GetInstProp, Proc);
end;
procedure TMethodPropertyEditor.SetValue(const NewValue: ansistring);
var
CreateNewMethodSrc: Boolean;
CurValue: string;
NewMethodExists, NewMethodIsCompatible, NewMethodIsPublished,
NewIdentIsMethod: boolean;
IsNil: Boolean;
NewMethod: TMethod;
begin
CurValue := GetValue;
if CurValue = NewValue then exit;
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.SetValue CurValue="',CurValue,'" NewValue="',NewValue,'"']);
{$ENDIF}
IsNil := (NewValue='') or (NewValue=oisNone);
if (not IsNil) and (not IsValidIdent(NewValue)) then
begin
MessageDlg(oisIncompatibleIdentifier,
Format(oisIsNotAValidMethodName,[NewValue]),
mtError, [mbCancel, mbIgnore], 0);
exit;
end;
NewMethodExists := (not IsNil) and
PropertyHook.CompatibleMethodExists(NewValue, GetInstProp,
NewMethodIsCompatible, NewMethodIsPublished, NewIdentIsMethod);
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.SetValue NewValue="',NewValue,'" IsCompatible=',NewMethodIsCompatible,' IsPublished=',NewMethodIsPublished,' IsMethod=',NewIdentIsMethod]);
{$ENDIF}
if NewMethodExists then
begin
if not NewIdentIsMethod then
begin
if MessageDlg(oisIncompatibleIdentifier,
Format(oisTheIdentifierIsNotAMethodPressCancelToUndoPressIgn,
[NewValue, LineEnding, LineEnding]),
mtWarning, [mbCancel, mbIgnore], 0)<>mrIgnore
then
exit;
end;
if not NewMethodIsPublished then
begin
if MessageDlg(oisIncompatibleMethod,
Format(oisTheMethodIsNotPublishedPressCancelToUndoPressIgnor,
[NewValue, LineEnding, LineEnding]),
mtWarning, [mbCancel, mbIgnore], 0)<>mrIgnore
then
exit;
end;
if not NewMethodIsCompatible then
begin
if MessageDlg(oisIncompatibleMethod,
Format(oisTheMethodIsIncompatibleToThisEventPressCancelToUnd,
[NewValue, GetName, LineEnding, LineEnding]),
mtWarning, [mbCancel, mbIgnore], 0)<>mrIgnore
then
exit;
end;
end;
if IsNil then
begin
// clear
NewMethod.Data := nil;
NewMethod.Code := nil;
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.SetValue SET to NIL']);
{$ENDIF}
SetMethodValue(NewMethod);
end
else
if IsValidIdent(CurValue) and
not NewMethodExists and
PropertyHook.MethodFromLookupRoot(GetMethodValue) then
begin
// rename the method
// Note:
// All other not selected properties that use this method, contain just
// the TMethod record. So, changing the name in the jitform will change
// all other event names in all other components automatically.
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.SetValue RENAME']);
{$ENDIF}
PropertyHook.RenameMethod(CurValue, NewValue)
end else
begin
// change value and create method src if needed
CreateNewMethodSrc := not NewMethodExists;
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.SetValue CHANGE new method=',CreateNewMethodSrc]);
{$ENDIF}
SetMethodValue(
PropertyHook.CreateMethod(NewValue, GetPropType,
GetComponent(0), GetPropertyPath(0)));
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.SetValue CHANGED new method=',CreateNewMethodSrc]);
{$ENDIF}
if CreateNewMethodSrc then
begin
{$IFDEF VerboseMethodPropEdit}
debugln(['TMethodPropertyEditor.SetValue SHOW "',NewValue,'"']);
{$ENDIF}
PropertyHook.ShowMethod(NewValue);
end;
end;
{$IFDEF VerboseMethodPropEdit}
DebugLn('### TMethodPropertyEditor.SetValue END NewValue=',GetValue);
{$ENDIF}
end;
{ TPersistentPropertyEditor }
function TPersistentPropertyEditor.FilterFunc(
const ATestEditor: TPropertyEditor): Boolean;
begin
Result := not (paNotNestable in ATestEditor.GetAttributes);
end;
function TPersistentPropertyEditor.GetPersistentReference: TPersistent;
begin
Result := TPersistent(GetObjectValue);
end;
function TPersistentPropertyEditor.GetSelections: TPersistentSelectionList;
begin
if (GetPersistentReference <> nil) and AllEqual then
Result := inherited GetSelections
else
Result := nil;
end;
function TPersistentPropertyEditor.CheckNewValue(APersistent: TPersistent): boolean;
begin
Result:=true;
end;
function TPersistentPropertyEditor.ComponentsAllEqual: Boolean;
// Called from AllEqual of TComponentOneFormPropertyEditor and TComponentPropertyEditor.
var
I: Integer;
AComponent: TComponent;
begin
Result:=False;
AComponent:=TComponent(GetObjectValue);
if PropCount > 1 then
for I := 1 to PropCount - 1 do
if TComponent(GetObjectValueAt(I)) <> AComponent then
Exit;
if (PropertyHook<>nil) and PropertyHook.ComponentPropertyOnlyDesign then
Result:=(AComponent=nil) or (csDesigning in AComponent.ComponentState)
else
Result:=true;
end;
function TPersistentPropertyEditor.AllEqual: Boolean;
var
I: Integer;
LInstance: TPersistent;
begin
Result := False;
LInstance := TPersistent(GetObjectValue);
if PropCount > 1 then
for I := 1 to PropCount - 1 do
if TPersistent(GetObjectValueAt(I)) <> LInstance then
Exit;
Result := True;
end;
procedure TPersistentPropertyEditor.Edit;
var
Temp: TPersistent;
Designer: TIDesigner;
AComponent: TComponent;
begin
Temp := GetPersistentReference;
if Temp is TComponent then begin
AComponent:=TComponent(Temp);
Designer:=FindRootDesigner(AComponent);
if (Designer<>nil)
and (Designer.GetShiftState * [ssCtrl, ssLeft] = [ssCtrl, ssLeft]) then
Designer.SelectOnlyThisComponent(AComponent)
else
inherited Edit;
end else
inherited Edit;
end;
function TPersistentPropertyEditor.GetAttributes: TPropertyAttributes;
var
Info: PPropInfo;
begin
Result := [paMultiSelect];
Info:=GetPropInfo;
if (Info<>nil) and Assigned(Info^.SetProc) then
Result := Result + [paValueList, paSortList, paRevertable, paVolatileSubProperties]
else
Result := Result + [paReadOnly];
if GReferenceExpandable and (GetPersistentReference <> nil) and AllEqual then
Result := Result + [paSubProperties];
end;
function TPersistentPropertyEditor.GetEditLimit: Integer;
begin
Result := MaxIdentLength;
end;
function TPersistentPropertyEditor.GetValue: AnsiString;
var
Component: TComponent;
APersistent: TPersistent;
begin
Result := '';
APersistent := GetPersistentReference;
if APersistent is TComponent then begin
Component := TComponent(APersistent);
if Assigned(PropertyHook) then
Result := PropertyHook.GetComponentName(Component)
else begin
if Assigned(Component) then
Result := Component.Name;
end;
end else if APersistent <> nil then
Result := inherited GetValue;
end;
procedure TPersistentPropertyEditor.GetValues(Proc: TGetStrProc);
begin
Proc(oisNone);
if Assigned(PropertyHook) then
PropertyHook.GetComponentNames(GetTypeData(GetPropType), Proc);
end;
procedure TPersistentPropertyEditor.SetValue(const NewValue: ansistring);
var
Persistent: TPersistent;
begin
if NewValue=GetValue then exit;
Persistent := nil;
if (NewValue <> '') and (NewValue<>oisNone) then begin
if Assigned(PropertyHook) then begin
Persistent := PropertyHook.GetComponent(NewValue);
if not (Persistent is GetTypeData(GetPropType)^.ClassType) then begin
raise EPropertyError.Create(oisInvalidPropertyValue);
end;
end;
end;
if GetPersistentReference=Persistent then exit;
if not CheckNewValue(Persistent) then exit;
SetPtrValue(Persistent);
if Assigned(PropertyHook) then begin
PropertyHook.ObjectReferenceChanged(Self,Persistent);
end;
end;
{ TComponentOneFormPropertyEditor }
function TComponentOneFormPropertyEditor.AllEqual: Boolean;
begin
Result:=ComponentsAllEqual;
end;
procedure TComponentOneFormPropertyEditor.GetValues(Proc: TGetStrProc);
procedure TraverseComponents(Root: TComponent);
var
i: integer;
begin
for i := 0 to Root.ComponentCount - 1 do
if (fIgnoreClass=nil) or not (Root.Components[i] is fIgnoreClass) then
Proc(Root.Components[i].Name);
end;
begin
Proc(oisNone);
if Assigned(PropertyHook) and (PropertyHook.FLookupRoot is TComponent) then
TraverseComponents(TComponent(PropertyHook.FLookupRoot));
end;
{ TCoolBarControlPropertyEditor }
constructor TCoolBarControlPropertyEditor.Create(Hook: TPropertyEditorHook; APropCount: Integer);
begin
inherited Create(Hook, APropCount);
fIgnoreClass := TCustomCoolBar;
end;
{ TComponentPropertyEditor }
function TComponentPropertyEditor.GetComponentReference: TComponent;
begin
Result := TComponent(GetObjectValue);
end;
function TComponentPropertyEditor.AllEqual: Boolean;
begin
Result:=ComponentsAllEqual;
end;
{ TInterfacePropertyEditor }
function TInterfacePropertyEditor.AllEqual: Boolean;
var
I: Integer;
Component: TComponent;
begin
Result := False;
Component := GetComponentReference;
if PropCount > 1 then
for I := 1 to PropCount - 1 do
if GetComponent(GetIntfValueAt(I)) <> Component then
Exit;
if (PropertyHook<>nil) and PropertyHook.ComponentPropertyOnlyDesign then
Result:=(Component=nil) or (csDesigning in Component.ComponentState)
else
Result := True;
end;
procedure TInterfacePropertyEditor.Edit;
var
Temp: TPersistent;
Designer: TIDesigner;
AComponent: TComponent;
begin
Temp := GetComponentReference;
if Temp is TComponent then begin
AComponent:=TComponent(Temp);
Designer:=FindRootDesigner(AComponent);
if (Designer<>nil)
and (Designer.GetShiftState * [ssCtrl, ssLeft] = [ssCtrl, ssLeft]) then
Designer.SelectOnlyThisComponent(AComponent)
else
inherited Edit;
end else
inherited Edit;
end;
function TInterfacePropertyEditor.GetAttributes: TPropertyAttributes;
var
Info: PPropInfo;
begin
Result := [paMultiSelect];
Info:=GetPropInfo;
if (Info<>nil) and Assigned(Info^.SetProc) then
Result := Result + [paValueList, paSortList, paRevertable, paVolatileSubProperties]
else
Result := Result + [paReadOnly];
if GReferenceExpandable and (GetComponentReference <> nil) and AllEqual then
Result := Result + [paSubProperties];
end;
function TInterfacePropertyEditor.GetComponent(const AInterface: IInterface): TComponent;
var
ComponentRef: IInterfaceComponentReference;
begin
Result := nil;
if not Assigned(AInterface) then
Exit;
if not Supports(AInterface, IInterfaceComponentReference, ComponentRef) then
Exit;
Result := ComponentRef.GetComponent;
end;
function TInterfacePropertyEditor.GetComponentReference: TComponent;
begin
Result := GetComponent(GetIntfValue);
end;
function TInterfacePropertyEditor.GetSelections: TPersistentSelectionList;
var
I: Integer;
SubItem: TPersistent;
begin
if AllEqual then
begin
Result := TPersistentSelectionList.Create;
try
for I := 0 to PropCount - 1 do
begin
SubItem := GetComponent(GetIntfValueAt(I));
if Assigned(SubItem) then
Result.Add(SubItem);
end;
except
Result.Free;
raise;
end;
end
else
Result := nil;
end;
procedure TInterfacePropertyEditor.GetValues(Proc: TGetStrProc);
var
ID: TGUID;
procedure TraverseComponents(Root: TComponent);
var
i: integer;
begin
for i := 0 to Root.ComponentCount - 1 do
if Supports(Root.Components[i], ID) then
Proc(Root.Components[i].Name);
end;
begin
ID := GetTypeData(GetPropType)^.GUID;
Proc(oisNone);
if Assigned(PropertyHook) and (PropertyHook.FLookupRoot is TComponent) then
TraverseComponents(TComponent(PropertyHook.FLookupRoot));
end;
procedure TInterfacePropertyEditor.SetValue(const NewValue: string);
var
Intf: IInterface;
Component: TComponent;
begin
if NewValue = GetValue then
Exit;
if (NewValue = '') or (NewValue = oisNone) then
Intf := nil
else
begin
if Assigned(PropertyHook) then
begin
Component := PropertyHook.GetComponent(NewValue);
if not Assigned(Component) or not Supports(Component, GetTypeData(GetPropType)^.GUID) then
raise EPropertyError.Create(oisInvalidPropertyValue);
Intf := Component;
end
else
Intf := nil;
end;
SetIntfValue(Intf);
end;
function TInterfacePropertyEditor.GetValue: AnsiString;
var
Component: TComponent;
begin
Result := '';
Component := GetComponentReference;
if Assigned(Component) then begin
if Assigned(PropertyHook) then
Result := PropertyHook.GetComponentName(Component)
else
Result := Component.Name;
end;
end;
{ TComponentNamePropertyEditor }
function TComponentNamePropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [];
end;
function TComponentNamePropertyEditor.GetEditLimit: Integer;
begin
Result := MaxIdentLength;
end;
function TComponentNamePropertyEditor.GetValue: ansistring;
begin
Result:=inherited GetValue;
end;
procedure TComponentNamePropertyEditor.SetValue(const NewValue: ansistring);
begin
if not IsValidIdent(NewValue) then
raise Exception.Create(Format(oisComponentNameIsNotAValidIdentifier, [NewValue]));
inherited SetValue(NewValue);
PropertyHook.ComponentRenamed(TComponent(GetComponent(0)));
end;
{ TDatePropertyEditor }
function TDatePropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paRevertable];
end;
function TDatePropertyEditor.GetValue: string;
var
DT: TDateTime;
begin
DT := TDateTime(GetFloatValue);
if DT = 0.0 then
Result := ''
else
Result := DateToStr(DT);
end;
procedure TDatePropertyEditor.SetValue(const Value: string);
var
DT: TDateTime;
begin
if Value = '' then
DT := 0.0
else
DT := StrToDate(Value);
SetFloatValue(DT);
end;
{ TTimePropertyEditor }
function TTimePropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paRevertable];
end;
function TTimePropertyEditor.GetValue: string;
var
DT: TDateTime;
begin
DT := TDateTime(GetFloatValue);
if DT = 0.0 then Result := '' else
Result := TimeToStr(DT);
end;
procedure TTimePropertyEditor.SetValue(const Value: string);
var
DT: TDateTime;
begin
if Value = '' then DT := 0.0
else DT := StrToTime(Value);
SetFloatValue(DT);
end;
{ TDateTimePropertyEditor }
function TDateTimePropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paRevertable];
end;
function TDateTimePropertyEditor.GetValue: string;
var
DT: TDateTime;
begin
DT := TDateTime(GetFloatValue);
if DT = 0.0 then Result := '' else
Result := DateTimeToStr(DT);
end;
procedure TDateTimePropertyEditor.SetValue(const Value: string);
var
DT: TDateTime;
ok: Boolean;
begin
if Value = '' then DT := 0.0
else begin
ok:=false;
// first try date+time
try
DT := StrToDateTime(Value);
ok:=true;
except
end;
// then try date without time
if not ok then
try
DT := StrToDate(Value);
ok:=true;
except
end;
// then try time without date
if not ok then
try
DT := StrToTime(Value);
ok:=true;
except
end;
// if all fails then raise exception
if not ok then
StrToDateTime(Value);
end;
SetFloatValue(DT);
end;
const
VarTypeStr: array[0..16] of record
VarType: Word;
Name: String;
end = (
(VarType: varempty; Name: 'Unassigned'),
(VarType: varnull; Name: 'Null'),
(VarType: varsmallint; Name: 'SmallInt'),
(VarType: varinteger; Name: 'Integer'),
(VarType: varsingle; Name: 'Single'),
(VarType: vardouble; Name: 'Double'),
(VarType: varcurrency; Name: 'Currency'),
(VarType: vardate; Name: 'Date'),
(VarType: varolestr; Name: 'OleStr'),
(VarType: varboolean; Name: 'Boolean'),
(VarType: varshortint; Name: 'ShortInt'),
(VarType: varbyte; Name: 'Byte'),
(VarType: varword; Name: 'Word'),
(VarType: varlongword; Name: 'LongWord'),
(VarType: varint64; Name: 'Int64'),
(VarType: varqword; Name: 'QWord'),
(VarType: varstring; Name: 'String')
);
function GetVarTypeName(AVarType: tvartype): String;
var
I: Integer;
begin
Result := '';
for I := Low(VarTypeStr) to High(VarTypeStr) do
if VarTypeStr[I].VarType = AVarType then
Exit(VarTypeStr[I].Name);
end;
function GetVarTypeByName(AName: String): tvartype;
var
I: Integer;
begin
Result := varempty;
for I := Low(VarTypeStr) to High(VarTypeStr) do
if CompareText(VarTypeStr[I].Name, AName) = 0 then
Exit(VarTypeStr[I].VarType);
end;
type
{ TVarTypeProperty }
TVarTypeProperty = class(TNestedProperty)
function GetName: shortstring; override;
function GetAttributes: TPropertyAttributes; override;
procedure GetValues(Proc: TGetStrProc); override;
function GetValue: ansistring; override;
procedure SetValue(const NewValue: ansistring); override;
end;
{ TVarTypeProperty }
function TVarTypeProperty.GetName: shortstring;
begin
Result := 'Type';
end;
function TVarTypeProperty.GetAttributes: TPropertyAttributes;
begin
Result := [paValueList];
end;
procedure TVarTypeProperty.GetValues(Proc: TGetStrProc);
var
I: Integer;
begin
for I := Low(VarTypeStr) to High(VarTypeStr) do
Proc(VarTypeStr[I].Name);
end;
function TVarTypeProperty.GetValue: ansistring;
begin
Result := GetVarTypeName(VarType(GetVarValue));
if Result = '' then
Result := 'Unknown'; // Is there resourcestring for that?
end;
procedure TVarTypeProperty.SetValue(const NewValue: ansistring);
var
V: Variant;
VT: tvartype;
begin
V := GetVarValue;
VT := GetVarTypeByName(NewValue);
case VT of
varempty:
VarClear(V);
varnull:
V := Null;
else
try
VarCast(V, V, VT);
except
VarClear(V);
end;
end;
SetVarValue(V);
end;
{ TVariantPropertyEditor }
function TVariantPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paSubProperties];
end;
procedure TVariantPropertyEditor.GetProperties(Proc:TGetPropEditProc);
begin
Proc(TVarTypeProperty.Create(Self));
end;
function TVariantPropertyEditor.GetValue: string;
begin
if VarType(GetVarValue) <> varnull then
Result := VarToStrDef(GetVarValue, 'Unknown') // Is there resourcestring for that?
else
Result := '(Null)';
end;
procedure TVariantPropertyEditor.SetValue(const Value: string);
var
V: Variant;
begin
try
V := Value;
except
V := 0; // Some backup value.
end;
SetVarValue(V);
end;
{ TModalResultPropertyEditor }
function TModalResultPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paValueList, paRevertable];
end;
function TModalResultPropertyEditor.OrdValueToVisualValue(OrdValue: longint): string;
var
CurValue: Longint;
begin
CurValue := OrdValue;
case CurValue of
Low(ModalResultStr)..High(ModalResultStr):
Result := ModalResultStr[CurValue];
else
Result := IntToStr(CurValue);
end;
end;
procedure TModalResultPropertyEditor.GetValues(Proc: TGetStrProc);
var
I: Integer;
begin
for I := Low(ModalResultStr) to High(ModalResultStr) do Proc(ModalResultStr[I]);
end;
procedure TModalResultPropertyEditor.SetValue(const NewValue: ansistring);
var
I: Integer;
begin
if NewValue = '' then begin
SetOrdValue(0);
Exit;
end;
for I := Low(ModalResultStr) to High(ModalResultStr) do
if CompareText(ModalResultStr[I], NewValue) = 0 then
begin
SetOrdValue(I);
Exit;
end;
inherited SetValue(NewValue);
end;
{ TShortCutPropertyEditor }
const
ShortCuts: array[0..135] 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,
Byte('A') or scMeta,
Byte('B') or scMeta,
Byte('C') or scMeta,
Byte('D') or scMeta,
Byte('E') or scMeta,
Byte('F') or scMeta,
Byte('G') or scMeta,
Byte('H') or scMeta,
Byte('I') or scMeta,
Byte('J') or scMeta,
Byte('K') or scMeta,
Byte('L') or scMeta,
Byte('M') or scMeta,
Byte('N') or scMeta,
Byte('O') or scMeta,
Byte('P') or scMeta,
Byte('Q') or scMeta,
Byte('R') or scMeta,
Byte('S') or scMeta,
Byte('T') or scMeta,
Byte('U') or scMeta,
Byte('V') or scMeta,
Byte('W') or scMeta,
Byte('X') or scMeta,
Byte('Y') or scMeta,
Byte('Z') or scMeta,
Byte('A') or scCtrl or scAlt,
Byte('B') or scCtrl or scAlt,
Byte('C') or scCtrl or scAlt,
Byte('D') or scCtrl or scAlt,
Byte('E') or scCtrl or scAlt,
Byte('F') or scCtrl or scAlt,
Byte('G') or scCtrl or scAlt,
Byte('H') or scCtrl or scAlt,
Byte('I') or scCtrl or scAlt,
Byte('J') or scCtrl or scAlt,
Byte('K') or scCtrl or scAlt,
Byte('L') or scCtrl or scAlt,
Byte('M') or scCtrl or scAlt,
Byte('N') or scCtrl or scAlt,
Byte('O') or scCtrl or scAlt,
Byte('P') or scCtrl or scAlt,
Byte('Q') or scCtrl or scAlt,
Byte('R') or scCtrl or scAlt,
Byte('S') or scCtrl or scAlt,
Byte('T') or scCtrl or scAlt,
Byte('U') or scCtrl or scAlt,
Byte('V') or scCtrl or scAlt,
Byte('W') or scCtrl or scAlt,
Byte('X') or scCtrl or scAlt,
Byte('Y') or scCtrl or scAlt,
Byte('Z') or scCtrl or scAlt,
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,
VK_ESCAPE);
procedure TShortCutPropertyEditor.Edit;
var
Box: TShortCutGrabBox;
OldValue, NewValue: TShortCut;
OldKey: Word;
OldShift: TShiftState;
Dlg: TForm;
BtnPanel: TButtonPanel;
begin
Dlg:=TForm.Create(Application);
try
Dlg.BorderIcons:=[biSystemMenu];
Dlg.Caption:=oisSelectShortCut;
Dlg.Position:=poScreenCenter;
Dlg.Constraints.MinWidth:=350;
Dlg.Constraints.MinHeight:=30;
Dlg.Width:=350;
Dlg.Height:=120;
Box:=TShortCutGrabBox.Create(Dlg);
Box.BorderSpacing.Around:=6;
Box.Parent:=Dlg;
Box.Align:=alClient;
OldValue := TShortCut(GetOrdValue);
ShortCutToKey(OldValue,OldKey,OldShift);
Box.ShiftState:=OldShift;
Box.Key:=OldKey;
BtnPanel:=TButtonPanel.Create(Dlg);
BtnPanel.Parent:=Dlg;
BtnPanel.Align:=alBottom;
BtnPanel.ShowButtons:=[pbOk,pbCancel];
Dlg.AutoSize:=true;
if Dlg.ShowModal=mrOk then begin
NewValue:=Menus.ShortCut(Box.Key,Box.ShiftState);
if OldValue<>NewValue then
SetOrdValue(NewValue);
end;
finally
Dlg.Free;
end;
end;
function TShortCutPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paValueList, paRevertable, paDialog];
end;
function TShortCutPropertyEditor.OrdValueToVisualValue(OrdValue: longint): string;
var
CurValue: TShortCut;
begin
CurValue := TShortCut(OrdValue);
if CurValue = scNone then
Result := oisNone
else
Result := ShortCutToText(CurValue);
end;
procedure TShortCutPropertyEditor.GetValues(Proc: TGetStrProc);
var
I: Integer;
begin
Proc(oisNone);
{$IFDEF Darwin}
for I := 1 to High(ShortCuts) do Proc(ShortCutToText(ShortCuts[I]));
{$ELSE}
for I := 1 to 26 do Proc(ShortCutToText(ShortCuts[I]));
for I := 53 to High(ShortCuts) do Proc(ShortCutToText(ShortCuts[I]));
{$ENDIF}
end;
procedure TShortCutPropertyEditor.SetValue(const Value: string);
var
NewValue: TShortCut;
begin
NewValue := 0;
if (Value <> '') and (AnsiCompareText(Value, oisNone) <> 0) then
begin
NewValue := TextToShortCut(Value);
if NewValue = 0 then
raise EPropertyError.Create(oisInvalidPropertyValue);
end;
SetOrdValue(NewValue);
end;
{ TTabOrderPropertyEditor }
function TTabOrderPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [];
end;
{ TCaptionPropertyEditor }
function TCaptionPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paAutoUpdate, paRevertable];
end;
{ TMenuItemCaptionEditor }
procedure TMenuItemCaptionEditor.SetValue(const NewValue: ansistring);
var
Designer: TIDesigner;
MI: TMenuItem;
Inst: TPersistent;
begin
Inst := GetComponent(0);
if (NewValue = cLineCaption) and (Inst is TMenuItem) then
begin
MI := TMenuItem(Inst);
if AnsiStartsStr('MenuItem', MI.Name) then
begin
Designer:=FindRootDesigner(MI);
if Designer<>nil then
MI.Name:=Designer.UniqueName('Separator');
end;
end;
SetStrValue(NewValue);
end;
{ TStringsPropertyEditor }
procedure TStringsPropertyEditor.Edit;
var
TheDialog: TStringsPropEditorDlg;
begin
TheDialog := CreateDlg(TStrings(GetObjectValue));
try
if (TheDialog.ShowModal = mrOK) then
SetPtrValue(TheDialog.Memo.Lines);
finally
TheDialog.Free;
end;
end;
function TStringsPropertyEditor.CreateDlg(s: TStrings): TStringsPropEditorDlg;
begin
Result := TStringsPropEditorDlg.Create(Application);
Result.Editor := Self;
Result.Memo.Text := s.Text;
Result.MemoChange(nil); // force call OnChange event
end;
function TStringsPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paDialog, paRevertable, paReadOnly];
end;
{ TValueListPropertyEditor }
procedure TValueListPropertyEditor.Edit;
var
TheDialog: TKeyValPropEditorDlg;
begin
TheDialog := CreateDlg(TStrings(GetObjectValue));
try
if (TheDialog.ShowModal = mrOK) then
SetPtrValue(TheDialog.ValueListEdit.Strings);
finally
TheDialog.Free;
end;
end;
function TValueListPropertyEditor.CreateDlg(s: TStrings): TKeyValPropEditorDlg;
begin
Result := TKeyValPropEditorDlg.Create(Application);
Result.Editor := Self;
Result.ValueListEdit.Strings.Assign(s);
Result.ValueListEdit.Invalidate;
end;
function TValueListPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paDialog, paRevertable, paReadOnly];
end;
{ TStringMultilinePropertyEditor }
procedure TStringMultilinePropertyEditor.Edit;
var
TheDialog : TStringsPropEditorDlg;
AString : string;
LineEndPos: Integer;
begin
AString := GetStrValue;
TheDialog := TStringsPropEditorDlg.Create(nil);
try
TheDialog.Editor := Self;
TheDialog.Memo.Text := AString;
TheDialog.MemoChange(nil);
if (TheDialog.ShowModal = mrOK) then
begin
AString := TheDialog.Memo.Text;
LineEndPos := Length(AString) - Length(LineEnding) + 1;
//erase the last lineending if any
if Copy(AString, LineEndPos, Length(LineEnding)) = LineEnding then
Delete(AString, LineEndPos, Length(LineEnding));
SetStrValue(AString);
end;
finally
TheDialog.Free;
end;
end;
function TStringMultilinePropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paDialog, paRevertable, paAutoUpdate];
end;
{ TCursorPropertyEditor }
function TCursorPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paMultiSelect, paSortList, paValueList, paRevertable];
end;
function TCursorPropertyEditor.OrdValueToVisualValue(OrdValue: longint): string;
begin
Result := CursorToString(TCursor(OrdValue));
end;
procedure TCursorPropertyEditor.GetValues(Proc: TGetStrProc);
begin
GetCursorValues(Proc);
end;
procedure TCursorPropertyEditor.SetValue(const NewValue: ansistring);
var
CValue: Longint;
begin
CValue:=0;
if IdentToCursor(NewValue, CValue) then
SetOrdValue(CValue)
else
inherited SetValue(NewValue);
end;
{ TFileNamePropertyEditor }
function TFileNamePropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result:=[paDialog,paRevertable];
end;
procedure TFileNamePropertyEditor.Edit;
begin
With CreateFileDialog do
Try
Filter:=GetFilter;
Options:=GetDialogOptions;
FileName:=GetStrValue;
InitialDir:=GetInitialDirectory;
Title:=GetDialogTitle;
If Execute then
SetFilename(Filename);
Finally
Free;
end;
end;
function TFileNamePropertyEditor.GetFilter: String;
begin
Result:=oisAllFiles+' ('+GetAllFilesMask+')|'+GetAllFilesMask;
end;
function TFileNamePropertyEditor.GetDialogOptions: TOpenOptions;
begin
Result:=DefaultOpenDialogOptions;
end;
function TFileNamePropertyEditor.GetDialogTitle: string;
begin
Result:=oisSelectAFile;
end;
function TFileNamePropertyEditor.GetInitialDirectory: string;
begin
Result:='';
end;
procedure TFileNamePropertyEditor.SetFilename(const Filename: string);
begin
SetStrValue(Filename);
end;
function TFileNamePropertyEditor.CreateFileDialog: TOpenDialog;
begin
Result:=TOpenDialog.Create(nil);
end;
{ TDirectoryPropertyEditor }
function TDirectoryPropertyEditor.CreateFileDialog: TOpenDialog;
begin
Result:=TSelectDirectoryDialog.Create(nil);
Result.Options:=Result.Options+[ofFileMustExist];
end;
{ TURLPropertyEditor }
procedure TURLPropertyEditor.SetFilename(const Filename: string);
function FilenameToURL(const Filename: string): string;
var
i: Integer;
begin
Result:=Filename;
{$push}
{$warnings off}
if PathDelim<>'/' then
for i:=1 to length(Result) do
if Result[i]=PathDelim then
Result[i]:='/';
{$pop}
if Result<>'' then
Result:='file://'+Result;
end;
begin
inherited SetFilename(FilenameToURL(Filename));
end;
{ TURLDirectoryPropertyEditor }
function TURLDirectoryPropertyEditor.CreateFileDialog: TOpenDialog;
begin
Result:=TSelectDirectoryDialog.Create(nil);
Result.Options:=Result.Options+[ofFileMustExist];
end;
{ TFileDlgFilterProperty }
function TFileDlgFilterProperty.GetAttributes: TPropertyAttributes;
begin
Result:=inherited GetAttributes + [paDialog];
end;
procedure TFileDlgFilterProperty.Edit;
begin
with TFileFilterPropEditForm.Create(Application) do
try
Filter:=GetStrValue;
if ShowModal=mrOk then begin
SetStrValue(Filter);
Modified;
end;
finally
Free;
end;
end;
{ TSessionPropertiesPropertyEditor }
function TSessionPropertiesPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result:=[paDialog,paRevertable,paReadOnly];
end;
procedure TSessionPropertiesPropertyEditor.Edit;
begin
With TSelectPropertiesForm.Create(Application) do
Try
PropertyComponent:=GetComponent(0) as TComponent;
SelectedProperties:=GetStrValue;
Caption:=Format(oisPropertiesOf, [TComponent(GetComponent(0)).Name]);
If (ShowModal=mrOK) then
SetStrValue(SelectedProperties);
Finally
Free;
end;
end;
{ TConstraintsPropertyEditor }
function TConstraintsPropertyEditor.GetVerbCount: Integer;
begin
Result:=2;
end;
function TConstraintsPropertyEditor.GetVerb(Index: Integer): string;
var
s: String;
c: TControl;
begin
case Index of
0: s := oisSetMaxConstraints;
1: s := oisSetMinConstraints;
else s := '';
end;
c := GetComponent(0) as TControl;
Result := Format(s, [c.Height, c.Width]);
end;
procedure TConstraintsPropertyEditor.PrepareItem(Index: Integer;
const AnItem: TMenuItem);
var
c: TControl;
begin
c := GetComponent(0) as TControl;
case Index of
0:
begin
// set max constraints
AnItem.Enabled := (c.Constraints.MaxHeight<>c.Height)
or (c.Constraints.MaxWidth<>c.Width);
AnItem.Hint := oisSetMaxConstraintsHint;
end;
1:
begin
// set min constraints
AnItem.Enabled := (c.Constraints.MinHeight<>c.Height)
or (c.Constraints.MinWidth<>c.Width);
AnItem.Hint := oisSetMinConstraintsHint;
end;
end;
end;
procedure TConstraintsPropertyEditor.ExecuteVerb(Index: Integer);
var
c: TControl;
begin
c := GetComponent(0) as TControl;
case Index of
0: begin
c.Constraints.MaxHeight := c.Height;
c.Constraints.MaxWidth := c.Width;
end;
1: begin
c.Constraints.MinHeight := c.Height;
c.Constraints.MinWidth := c.Width;
end;
end;
end;
//==============================================================================
{ TPropertyEditorHook }
function TPropertyEditorHook.CreateMethod(const aName: ShortString;
ATypeInfo: PTypeInfo; APersistent: TPersistent; const APropertyPath: string
): TMethod;
var
i: Integer;
Handler: TPropHookCreateMethod;
begin
Result.Code := nil;
Result.Data := nil;
if IsValidIdent(aName,true,true) and Assigned(ATypeInfo) then
begin
i := GetHandlerCount(htCreateMethod);
while GetNextHandlerIndex(htCreateMethod, i) do
begin
Handler := TPropHookCreateMethod(FHandlers[htCreateMethod][i]);
Result := Handler(aName, ATypeInfo, APersistent, APropertyPath);
if Assigned(Result.Data) or Assigned(Result.Code) then exit;
end;
end;
end;
function TPropertyEditorHook.GetMethodName(const Method: TMethod;
PropOwner: TObject): String;
var
i: Integer;
begin
i:=GetHandlerCount(htGetMethodName);
if GetNextHandlerIndex(htGetMethodName,i) then begin
Result:=TPropHookGetMethodName(FHandlers[htGetMethodName][i])(Method,PropOwner,LookupRoot);
end else begin
// search the method name with the given code pointer
if Assigned(Method.Code) then begin
if Method.Data<>nil then begin
Result:=TObject(Method.Data).MethodName(Method.Code);
if Result='' then
Result:='<Unpublished>';
end else
Result:='<No LookupRoot>';
end else
Result:='';
end;
end;
procedure TPropertyEditorHook.GetMethods(TypeData: PTypeData;
const Proc: TGetStrProc);
var
i: Integer;
begin
i:=GetHandlerCount(htGetMethods);
while GetNextHandlerIndex(htGetMethods,i) do
TPropHookGetMethods(FHandlers[htGetMethods][i])(TypeData,Proc);
end;
procedure TPropertyEditorHook.GetCompatibleMethods(InstProp: PInstProp;
const Proc: TGetStrProc);
var
i: Integer;
begin
i:=GetHandlerCount(htGetCompatibleMethods);
while GetNextHandlerIndex(htGetCompatibleMethods,i) do
TPropHookGetCompatibleMethods(FHandlers[htGetCompatibleMethods][i])(InstProp,Proc);
end;
function TPropertyEditorHook.MethodExists(const aName: String;
TypeData: PTypeData;
var MethodIsCompatible, MethodIsPublished, IdentIsMethod: boolean):boolean;
var
i: Integer;
Handler: TPropHookMethodExists;
begin
// check if a published method with given aName exists in LookupRoot
Result:=IsValidIdent(aName) and Assigned(FLookupRoot);
if not Result then exit;
i:=GetHandlerCount(htMethodExists);
if i>=0 then begin
while GetNextHandlerIndex(htMethodExists,i) do begin
Handler:=TPropHookMethodExists(FHandlers[htMethodExists][i]);
Result:=Handler(aName,TypeData,
MethodIsCompatible,MethodIsPublished,IdentIsMethod);
end;
end else begin
Result:=(LookupRoot.MethodAddress(aName)<>nil);
MethodIsCompatible:=Result;
MethodIsPublished:=Result;
IdentIsMethod:=Result;
end;
end;
function TPropertyEditorHook.CompatibleMethodExists(const aName: String;
InstProp: PInstProp; out MethodIsCompatible, MethodIsPublished,
IdentIsMethod: boolean): boolean;
var
i: Integer;
Handler: TPropHookCompatibleMethodExists;
begin
MethodIsCompatible:=false;
MethodIsPublished:=false;
IdentIsMethod:=false;
// check if a published method with given aName exists in LookupRoot
Result:=IsValidIdent(aName) and Assigned(FLookupRoot);
if not Result then exit;
i:=GetHandlerCount(htCompatibleMethodExists);
if i>=0 then begin
while GetNextHandlerIndex(htCompatibleMethodExists,i) do begin
Handler:=TPropHookCompatibleMethodExists(FHandlers[htCompatibleMethodExists][i]);
Result:=Handler(aName,InstProp,
MethodIsCompatible,MethodIsPublished,IdentIsMethod);
end;
end else begin
Result:=(LookupRoot.MethodAddress(aName)<>nil);
MethodIsCompatible:=Result;
MethodIsPublished:=Result;
IdentIsMethod:=Result;
end;
end;
procedure TPropertyEditorHook.RenameMethod(const CurName, NewName: String);
// rename published method in LookupRoot object and source
var
i: Integer;
begin
i:=GetHandlerCount(htRenameMethod);
while GetNextHandlerIndex(htRenameMethod,i) do
TPropHookRenameMethod(FHandlers[htRenameMethod][i])(CurName,NewName);
end;
procedure TPropertyEditorHook.ShowMethod(const aName: String);
// jump cursor to published method body
var
i: Integer;
begin
i:=GetHandlerCount(htShowMethod);
while GetNextHandlerIndex(htShowMethod,i) do
TPropHookShowMethod(FHandlers[htShowMethod][i])(aName);
end;
function TPropertyEditorHook.MethodFromAncestor(const Method: TMethod): boolean;
var
AncestorClass: TClass;
i: Integer;
Handler: TPropHookMethodFromAncestor;
begin
// check if given Method is not in LookupRoot source,
// but in one of its ancestors
i := GetHandlerCount(htMethodFromAncestor);
if GetNextHandlerIndex(htMethodFromAncestor, i) then
begin
Handler := TPropHookMethodFromAncestor(FHandlers[htMethodFromAncestor][i]);
Result := Handler(Method);
end
else
begin
Result := Assigned(Method.Data) and Assigned(Method.Code);
if Result then
begin
AncestorClass := TObject(Method.Data).ClassParent;
Result := Assigned(AncestorClass) and (AncestorClass.MethodName(Method.Code)<>'');
end;
end;
end;
function TPropertyEditorHook.MethodFromLookupRoot(const Method: TMethod
): boolean;
var
Root: TPersistent;
i: Integer;
Handler: TPropHookMethodFromLookupRoot;
begin
// check if given Method is in LookupRoot source,
Root:=LookupRoot;
if Root=nil then exit(false);
i := GetHandlerCount(htMethodFromLookupRoot);
if GetNextHandlerIndex(htMethodFromLookupRoot, i) then
begin
Handler := TPropHookMethodFromLookupRoot(FHandlers[htMethodFromLookupRoot][i]);
Result := Handler(Method);
end
else
begin
Result := (TObject(Method.Data)=Root) and Assigned(Method.Code)
and (Root.MethodName(Method.Code)<>'');
end;
end;
procedure TPropertyEditorHook.ChainCall(const AMethodName, InstanceName,
InstanceMethod: ShortString; TypeData: PTypeData);
var
i: Integer;
Handler: TPropHookChainCall;
begin
i:=GetHandlerCount(htChainCall);
while GetNextHandlerIndex(htChainCall,i) do begin
Handler:=TPropHookChainCall(FHandlers[htChainCall][i]);
Handler(AMethodName,InstanceName,InstanceMethod,TypeData);
end;
end;
function TPropertyEditorHook.GetComponent(const ComponentPath: string): TComponent;
var
i: Integer;
begin
Result := nil;
if not Assigned(LookupRoot) then
Exit;
i := GetHandlerCount(htGetComponent);
while GetNextHandlerIndex(htGetComponent, i) and (Result = nil) do
Result := TPropHookGetComponent(FHandlers[htGetComponent][i])(ComponentPath);
// Note: TWriter only allows pascal identifiers for names, but in general
// there is no restriction.
if (Result = nil) and (LookupRoot is TComponent) then
Result := TComponent(LookupRoot).FindComponent(ComponentPath);
end;
function TPropertyEditorHook.GetComponentName(AComponent: TComponent): String;
var
i: Integer;
CompName, OwnerName: String;
Handler: TPropHookGetComponentName;
begin
Result := '';
if AComponent = nil then
Exit;
i := GetHandlerCount(htGetComponentName);
while GetNextHandlerIndex(htGetComponentName, i) and (Result = '') do
begin
Handler := TPropHookGetComponentName(FHandlers[htGetComponentName][i]);
Result := Handler(AComponent);
end;
if Result = '' then
begin
CompName := AComponent.Name;
if (AComponent.Owner<>LookupRoot) and (AComponent.Owner<>nil) then
OwnerName := AComponent.Owner.Name;
{ if CompName='' then
DebugLn('TPropertyEditorHook.GetComponentName: AComponent.Name is empty, '+
'AComponent.Owner.Name="' + OwnerName+'".');
if OwnerName='' then
DebugLn('TPropertyEditorHook.GetComponentName: AComponent.Owner.Name is empty.');
}
Result := CompName;
if OwnerName<>'' then
begin
Result := OwnerName;
if CompName<>'' then
Result := Result+'.'+CompName;
end;
end;
end;
procedure TPropertyEditorHook.GetComponentNames(TypeData: PTypeData;
const Proc: TGetStrProc);
procedure TraverseComponents(Root: TComponent);
var
i: integer;
begin
for i := 0 to Root.ComponentCount - 1 do
if (Root.Components[i] is TypeData^.ClassType) then
Proc(Root.Components[i].Name);
end;
var
i: integer;
Handler: TPropHookGetComponentNames;
begin
if not Assigned(LookupRoot) then
Exit;
i := GetHandlerCount(htGetComponentNames);
if i > 0 then
begin
while GetNextHandlerIndex(htGetComponentNames, i) do
begin
Handler := TPropHookGetComponentNames(FHandlers[htGetComponentNames][i]);
Handler(TypeData, Proc);
end;
end
else if LookupRoot is TComponent then
// No handler -> only traverse local form/datamodule components
TraverseComponents(TComponent(LookupRoot));
end;
function TPropertyEditorHook.GetRootClassName: ShortString;
var
i: Integer;
Handler: TPropHookGetRootClassName;
begin
Result := '';
i := GetHandlerCount(htGetRootClassName);
while GetNextHandlerIndex(htGetRootClassName, i) and (Result = '') do
begin
Handler := TPropHookGetRootClassName(FHandlers[htGetRootClassName][i]);
Result := Handler();
end;
if (Result='') and Assigned(LookupRoot) then
Result := LookupRoot.ClassName;
end;
function TPropertyEditorHook.GetAncestorInstance(const InstProp: TInstProp; out
AncestorInstProp: TInstProp): boolean;
var
i: Integer;
Handler: TPropHookGetAncestorInstProp;
begin
Result:=false;
if (InstProp.Instance=nil) or (InstProp.PropInfo=nil) then exit;
i := GetHandlerCount(htGetAncestorInstProp);
while GetNextHandlerIndex(htGetAncestorInstProp, i) and (not Result) do
begin
Handler := TPropHookGetAncestorInstProp(FHandlers[htGetAncestorInstProp][i]);
Result := Handler(InstProp,AncestorInstProp);
end;
end;
function TPropertyEditorHook.AddClicked(ADesigner: TIDesigner;
MouseDownComponent: TComponent; Button: TMouseButton; Shift: TShiftState; X,
Y: Integer; var AComponentClass: TComponentClass; var NewParent: TComponent
): boolean;
var
i: Integer;
Handler: TPropHookAddClicked;
begin
i := GetHandlerCount(htAddClicked);
while GetNextHandlerIndex(htAddClicked, i) do
begin
Handler := TPropHookAddClicked(FHandlers[htAddClicked][i]);
Result := Handler(ADesigner,MouseDownComponent,Button,Shift,X,Y,
AComponentClass,NewParent);
if not Result then exit;
if AComponentClass=nil then
exit(false);
end;
Result := True;
end;
function TPropertyEditorHook.BeforeAddPersistent(Sender: TObject;
APersistentClass: TPersistentClass; Parent: TPersistent): boolean;
var
i: Integer;
Handler: TPropHookBeforeAddPersistent;
begin
i := GetHandlerCount(htBeforeAddPersistent);
while GetNextHandlerIndex(htBeforeAddPersistent, i) do
begin
Handler := TPropHookBeforeAddPersistent(FHandlers[htBeforeAddPersistent][i]);
Result := Handler(Sender,APersistentClass,Parent);
if not Result then exit;
end;
Result := True;
end;
procedure TPropertyEditorHook.ComponentRenamed(AComponent: TComponent);
var
i: Integer;
begin
i := GetHandlerCount(htComponentRenamed);
while GetNextHandlerIndex(htComponentRenamed, i) do
TPropHookComponentRenamed(FHandlers[htComponentRenamed][i])(AComponent);
end;
procedure TPropertyEditorHook.PersistentAdded(APersistent: TPersistent; Select: boolean);
var
i: Integer;
begin
i := GetHandlerCount(htPersistentAdded);
while GetNextHandlerIndex(htPersistentAdded, i) do
TPropHookPersistentAdded(FHandlers[htPersistentAdded][i])(APersistent, Select);
end;
procedure TPropertyEditorHook.PersistentDeleting(APersistent: TPersistent);
// call this to tell all IDE parts to remove all references from the APersistent
var
i: Integer;
begin
i:=GetHandlerCount(htPersistentDeleting);
while GetNextHandlerIndex(htPersistentDeleting,i) do
TPropHookPersistentDel(FHandlers[htPersistentDeleting][i])(APersistent);
end;
procedure TPropertyEditorHook.PersistentDeleted(APersistent: TPersistent);
var
i: Integer;
begin
i:=GetHandlerCount(htPersistentDeleted);
while GetNextHandlerIndex(htPersistentDeleted,i) do
TPropHookPersistentDel(FHandlers[htPersistentDeleted][i])(APersistent);
end;
procedure TPropertyEditorHook.DeletePersistent(var APersistent: TPersistent);
// Call this to actually free APersistent
// One of the hooks will free it.
var
i: Integer;
begin
if APersistent=nil then exit;
i:=GetHandlerCount(htDeletePersistent);
if i>0 then begin
while (APersistent<>nil) and GetNextHandlerIndex(htDeletePersistent,i) do
TPropHookDeletePersistent(FHandlers[htDeletePersistent][i])(APersistent);
end else
FreeThenNil(APersistent);
end;
procedure TPropertyEditorHook.GetSelection(const ASelection: TPersistentSelectionList);
var
i: Integer;
Handler: TPropHookGetSelection;
begin
if ASelection=nil then exit;
ASelection.Clear;
i:=GetHandlerCount(htGetSelectedPersistents);
while GetNextHandlerIndex(htGetSelectedPersistents,i) do begin
Handler:=TPropHookGetSelection(FHandlers[htGetSelectedPersistents][i]);
Handler(ASelection);
end;
end;
procedure TPropertyEditorHook.SetSelection(
const ASelection: TPersistentSelectionList);
var
i: Integer;
Handler: TPropHookSetSelection;
APersistent: TPersistent;
NewLookupRoot: TPersistent;
begin
// update LookupRoot
NewLookupRoot:=LookupRoot;
if (ASelection<>nil) and (ASelection.Count>0) then begin
APersistent:=ASelection[0];
if APersistent<>nil then
NewLookupRoot:=GetLookupRootForComponent(APersistent);
end;
LookupRoot:=NewLookupRoot;
// set selection
if ASelection=nil then exit;
//debulgn(['TPropertyEditorHook.SetSelection A ASelection.Count=',ASelection.Count]);
i:=GetHandlerCount(htSetSelectedPersistents);
while GetNextHandlerIndex(htSetSelectedPersistents,i) do begin
Handler:=TPropHookSetSelection(FHandlers[htSetSelectedPersistents][i]);
Handler(ASelection);
end;
//debugln(['TPropertyEditorHook.SetSelection END ASelection.Count=',ASelection.Count]);
end;
procedure TPropertyEditorHook.Unselect(const APersistent: TPersistent);
var
Selection: TPersistentSelectionList;
begin
Selection := TPersistentSelectionList.Create;
try
GetSelection(Selection);
if Selection.IndexOf(APersistent)>=0 then begin
Selection.Remove(APersistent);
SetSelection(Selection);
end;
finally
Selection.Free;
end;
end;
function TPropertyEditorHook.IsSelected(const APersistent: TPersistent): boolean;
var
Selection: TPersistentSelectionList;
begin
Selection := TPersistentSelectionList.Create;
try
GetSelection(Selection);
Result:=Selection.IndexOf(APersistent)>=0;
finally
Selection.Free;
end;
end;
procedure TPropertyEditorHook.SelectOnlyThis(const APersistent: TPersistent);
var
NewSelection: TPersistentSelectionList;
begin
NewSelection := TPersistentSelectionList.Create;
try
if APersistent<>nil then
NewSelection.Add(APersistent);
SetSelection(NewSelection);
finally
NewSelection.Free;
end;
end;
procedure TPropertyEditorHook.AddDependency(const AClass: TClass;
const AnUnitname: shortstring);
var
i: Integer;
begin
i:=GetHandlerCount(htAddDependency);
while GetNextHandlerIndex(htAddDependency,i) do
TPropHookAddDependency(FHandlers[htAddDependency][i])(AClass,AnUnitName);
end;
function TPropertyEditorHook.GetObject(const aName: ShortString): TPersistent;
var
i: Integer;
begin
Result:=nil;
i:=GetHandlerCount(htGetObject);
while GetNextHandlerIndex(htGetObject,i) and (Result=nil) do
Result:=TPropHookGetObject(FHandlers[htGetObject][i])(aName);
end;
function TPropertyEditorHook.GetObjectName(Instance: TPersistent;
AOwnerComp: TComponent): String;
var
i: Integer;
begin
Result:='';
i:=GetHandlerCount(htGetObjectName);
if i>0 then begin
while GetNextHandlerIndex(htGetObjectName,i) and (Result='') do
Result:=TPropHookGetObjectName(FHandlers[htGetObject][i])(Instance);
end else
if Instance is TComponent then
Result:=TComponent(Instance).Name
else if instance is TCollectionItem then
Result:=TCollectionItem(Instance).GetNamePath
else begin
Assert(Assigned(AOwnerComp),'TPropertyEditorHook.GetObjectName: AOwnerComp not assigned.');
Result:=AOwnerComp.Name + ClassNameToComponentName(Instance.ClassName);
end;
end;
procedure TPropertyEditorHook.GetObjectNames(TypeData: PTypeData;
const Proc: TGetStrProc);
var
i: Integer;
begin
i:=GetHandlerCount(htGetObjectNames);
while GetNextHandlerIndex(htGetObjectNames,i) do
TPropHookGetObjectNames(FHandlers[htGetObjectNames][i])(TypeData,Proc);
end;
procedure TPropertyEditorHook.ObjectReferenceChanged(Sender: TObject;
NewObject: TPersistent);
var
i: Integer;
begin
i:=GetHandlerCount(htObjectPropertyChanged);
while GetNextHandlerIndex(htObjectPropertyChanged,i) do
TPropHookObjectPropertyChanged(FHandlers[htObjectPropertyChanged][i])(
Sender,NewObject);
end;
procedure TPropertyEditorHook.Modified(Sender: TObject; PropName: ShortString);
var
i: Integer;
AForm: TCustomForm;
Editor: TPropertyEditor;
List: TFPList;
APersistent: TPersistent;
ARoot: TPersistent;
begin
i := GetHandlerCount(htModified);
while GetNextHandlerIndex(htModified,i) do
TPropHookModified(FHandlers[htModified][i])(Sender);
if PropName>'' then
begin
i := GetHandlerCount(htModifiedWithName);
while GetNextHandlerIndex(htModifiedWithName,i) do
TPropHookModifiedWithName(FHandlers[htModifiedWithName][i])(Sender, PropName);
end;
if Sender is TPropertyEditor then
begin
// mark the designer form of every selected persistent
Editor := TPropertyEditor(Sender);
List := TFPList.Create;
try
for i := 0 to Editor.PropCount - 1 do
begin
// for every selected persistent ...
APersistent := Editor.GetComponent(i);
if APersistent = nil then Continue;
if List.IndexOf(APersistent) >= 0 then Continue;
List.Add(APersistent);
// ... get the lookuproot ...
ARoot := GetLookupRootForComponent(APersistent);
if ARoot = nil then Continue;
if (ARoot <> APersistent) and (List.IndexOf(ARoot) >= 0) then Continue;
List.Add(ARoot);
if ARoot is TControl then
TControl(ARoot).Invalidate;
// ... get the designer ...
AForm := GetDesignerForm(ARoot);
if Assigned(AForm) and Assigned(AForm.Designer) then
AForm.Designer.Modified; // ... and mark it modified
end;
finally
List.Free;
end;
end
else
if Assigned(FLookupRoot) then
begin
AForm := GetDesignerForm(FLookupRoot);
if Assigned(AForm) and Assigned(AForm.Designer) then
AForm.Designer.Modified;
end;
end;
procedure TPropertyEditorHook.DesignerMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
i: Integer;
Handler: TMouseEvent;
begin
i := GetHandlerCount(htDesignerMouseDown);
while GetNextHandlerIndex(htDesignerMouseDown, i) do
begin
Handler := TMouseEvent(FHandlers[htDesignerMouseDown][i]);
Handler(Sender, Button, Shift, X, Y);
end;
end;
procedure TPropertyEditorHook.DesignerMouseUp(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
i: Integer;
Handler: TMouseEvent;
begin
i := GetHandlerCount(htDesignerMouseUp);
while GetNextHandlerIndex(htDesignerMouseUp, i) do
begin
Handler := TMouseEvent(FHandlers[htDesignerMouseUp][i]);
Handler(Sender, Button, Shift, X, Y);
end;
end;
procedure TPropertyEditorHook.Revert(Instance:TPersistent; PropInfo:PPropInfo);
var
i: Integer;
begin
i:=GetHandlerCount(htRevert);
while GetNextHandlerIndex(htRevert,i) do
TPropHookRevert(FHandlers[htRevert][i])(Instance,PropInfo);
end;
procedure TPropertyEditorHook.RefreshPropertyValues;
var
i: Integer;
begin
i:=GetHandlerCount(htRefreshPropertyValues);
while GetNextHandlerIndex(htRefreshPropertyValues,i) do
TPropHookRefreshPropertyValues(FHandlers[htRefreshPropertyValues][i])();
end;
function TPropertyEditorHook.GetCheckboxForBoolean: Boolean;
var
i: Integer;
begin
Result:=False;
i:=GetHandlerCount(htGetCheckboxForBoolean);
if i > 0 then
TPropHookGetCheckboxForBoolean(FHandlers[htGetCheckboxForBoolean][0])(Result);
end;
procedure TPropertyEditorHook.RemoveAllHandlersForObject(const HandlerObject: TObject);
var
HookType: TPropHookType;
begin
for HookType:=Low(FHandlers) to High(FHandlers) do
if FHandlers[HookType]<>nil then
FHandlers[HookType].RemoveAllMethodsOfObject(HandlerObject);
end;
procedure TPropertyEditorHook.AddHandlerChangeLookupRoot(
const OnChangeLookupRoot: TPropHookChangeLookupRoot);
begin
AddHandler(htChangeLookupRoot,TMethod(OnChangeLookupRoot));
end;
procedure TPropertyEditorHook.RemoveHandlerChangeLookupRoot(
const OnChangeLookupRoot: TPropHookChangeLookupRoot);
begin
RemoveHandler(htChangeLookupRoot,TMethod(OnChangeLookupRoot));
end;
procedure TPropertyEditorHook.AddHandlerCreateMethod(
const OnCreateMethod: TPropHookCreateMethod);
begin
AddHandler(htCreateMethod,TMethod(OnCreateMethod));
end;
procedure TPropertyEditorHook.RemoveHandlerCreateMethod(
const OnCreateMethod: TPropHookCreateMethod);
begin
RemoveHandler(htCreateMethod,TMethod(OnCreateMethod));
end;
procedure TPropertyEditorHook.AddHandlerGetMethodName(
const OnGetMethodName: TPropHookGetMethodName);
begin
AddHandler(htGetMethodName,TMethod(OnGetMethodName));
end;
procedure TPropertyEditorHook.RemoveHandlerGetMethodName(
const OnGetMethodName: TPropHookGetMethodName);
begin
RemoveHandler(htGetMethodName,TMethod(OnGetMethodName));
end;
procedure TPropertyEditorHook.AddHandlerGetMethods(
const OnGetMethods: TPropHookGetMethods);
begin
AddHandler(htGetMethods,TMethod(OnGetMethods));
end;
procedure TPropertyEditorHook.RemoveHandlerGetMethods(
const OnGetMethods: TPropHookGetMethods);
begin
RemoveHandler(htGetMethods,TMethod(OnGetMethods));
end;
procedure TPropertyEditorHook.AddHandlerCompatibleMethodExists(
const OnMethodExists: TPropHookCompatibleMethodExists);
begin
AddHandler(htCompatibleMethodExists,TMethod(OnMethodExists));
end;
procedure TPropertyEditorHook.RemoveHandlerCompatibleMethodExists(
const OnMethodExists: TPropHookCompatibleMethodExists);
begin
RemoveHandler(htCompatibleMethodExists,TMethod(OnMethodExists));
end;
procedure TPropertyEditorHook.AddHandlerGetCompatibleMethods(
const OnGetMethods: TPropHookGetCompatibleMethods);
begin
AddHandler(htGetCompatibleMethods,TMethod(OnGetMethods));
end;
procedure TPropertyEditorHook.RemoveHandlerGetCompatibleMethods(
const OnGetMethods: TPropHookGetCompatibleMethods);
begin
RemoveHandler(htGetCompatibleMethods,TMethod(OnGetMethods));
end;
procedure TPropertyEditorHook.AddHandlerMethodExists(
const OnMethodExists: TPropHookMethodExists);
begin
AddHandler(htMethodExists,TMethod(OnMethodExists));
end;
procedure TPropertyEditorHook.RemoveHandlerMethodExists(
const OnMethodExists: TPropHookMethodExists);
begin
RemoveHandler(htMethodExists,TMethod(OnMethodExists));
end;
procedure TPropertyEditorHook.AddHandlerRenameMethod(
const OnRenameMethod: TPropHookRenameMethod);
begin
AddHandler(htRenameMethod,TMethod(OnRenameMethod));
end;
procedure TPropertyEditorHook.RemoveHandlerRenameMethod(
const OnRenameMethod: TPropHookRenameMethod);
begin
RemoveHandler(htRenameMethod,TMethod(OnRenameMethod));
end;
procedure TPropertyEditorHook.AddHandlerShowMethod(
const OnShowMethod: TPropHookShowMethod);
begin
AddHandler(htShowMethod,TMethod(OnShowMethod));
end;
procedure TPropertyEditorHook.RemoveHandlerShowMethod(
const OnShowMethod: TPropHookShowMethod);
begin
RemoveHandler(htShowMethod,TMethod(OnShowMethod));
end;
procedure TPropertyEditorHook.AddHandlerMethodFromAncestor(
const OnMethodFromAncestor: TPropHookMethodFromAncestor);
begin
AddHandler(htMethodFromAncestor,TMethod(OnMethodFromAncestor));
end;
procedure TPropertyEditorHook.RemoveHandlerMethodFromAncestor(
const OnMethodFromAncestor: TPropHookMethodFromAncestor);
begin
RemoveHandler(htMethodFromAncestor,TMethod(OnMethodFromAncestor));
end;
procedure TPropertyEditorHook.AddHandlerMethodFromLookupRoot(
const OnMethodFromLookupRoot: TPropHookMethodFromLookupRoot);
begin
AddHandler(htMethodFromLookupRoot,TMethod(OnMethodFromLookupRoot));
end;
procedure TPropertyEditorHook.RemoveHandlerMethodFromLookupRoot(
const OnMethodFromLookupRoot: TPropHookMethodFromLookupRoot);
begin
RemoveHandler(htMethodFromLookupRoot,TMethod(OnMethodFromLookupRoot));
end;
procedure TPropertyEditorHook.AddHandlerChainCall(
const OnChainCall: TPropHookChainCall);
begin
AddHandler(htChainCall,TMethod(OnChainCall));
end;
procedure TPropertyEditorHook.RemoveHandlerChainCall(
const OnChainCall: TPropHookChainCall);
begin
RemoveHandler(htChainCall,TMethod(OnChainCall));
end;
procedure TPropertyEditorHook.AddHandlerGetComponent(
const OnGetComponent: TPropHookGetComponent);
begin
AddHandler(htGetComponent,TMethod(OnGetComponent));
end;
procedure TPropertyEditorHook.RemoveHandlerGetComponent(
const OnGetComponent: TPropHookGetComponent);
begin
RemoveHandler(htGetComponent,TMethod(OnGetComponent));
end;
procedure TPropertyEditorHook.AddHandlerGetComponentName(
const OnGetComponentName: TPropHookGetComponentName);
begin
AddHandler(htGetComponentName,TMethod(OnGetComponentName));
end;
procedure TPropertyEditorHook.RemoveHandlerGetComponentName(
const OnGetComponentName: TPropHookGetComponentName);
begin
RemoveHandler(htGetComponentName,TMethod(OnGetComponentName));
end;
procedure TPropertyEditorHook.AddHandlerGetComponentNames(
const OnGetComponentNames: TPropHookGetComponentNames);
begin
AddHandler(htGetComponentNames,TMethod(OnGetComponentNames));
end;
procedure TPropertyEditorHook.RemoveHandlerGetComponentNames(
const OnGetComponentNames: TPropHookGetComponentNames);
begin
RemoveHandler(htGetComponentNames,TMethod(OnGetComponentNames));
end;
procedure TPropertyEditorHook.AddHandlerAddClicked(
const Handler: TPropHookAddClicked);
begin
AddHandler(htAddClicked,TMethod(Handler));
end;
procedure TPropertyEditorHook.RemoveHandlerAddClicked(
const Handler: TPropHookAddClicked);
begin
RemoveHandler(htAddClicked,TMethod(Handler));
end;
procedure TPropertyEditorHook.AddHandlerGetRootClassName(
const OnGetRootClassName: TPropHookGetRootClassName);
begin
AddHandler(htGetRootClassName,TMethod(OnGetRootClassName));
end;
procedure TPropertyEditorHook.RemoveHandlerGetRootClassName(
const OnGetRootClassName: TPropHookGetRootClassName);
begin
RemoveHandler(htGetRootClassName,TMethod(OnGetRootClassName));
end;
procedure TPropertyEditorHook.AddHandlerGetAncestorInstProp(
const OnGetAncestorInstProp: TPropHookGetAncestorInstProp);
begin
AddHandler(htGetAncestorInstProp,TMethod(OnGetAncestorInstProp));
end;
procedure TPropertyEditorHook.RemoveHandlerGetAncestorInstProp(
const OnGetAncestorInstProp: TPropHookGetAncestorInstProp);
begin
RemoveHandler(htGetAncestorInstProp,TMethod(OnGetAncestorInstProp));
end;
procedure TPropertyEditorHook.AddHandlerBeforeAddPersistent(
const OnBeforeAddPersistent: TPropHookBeforeAddPersistent);
begin
AddHandler(htBeforeAddPersistent,TMethod(OnBeforeAddPersistent));
end;
procedure TPropertyEditorHook.RemoveHandlerBeforeAddPersistent(
const OnBeforeAddPersistent: TPropHookBeforeAddPersistent);
begin
RemoveHandler(htBeforeAddPersistent,TMethod(OnBeforeAddPersistent));
end;
procedure TPropertyEditorHook.AddHandlerComponentRenamed(
const OnComponentRenamed: TPropHookComponentRenamed);
begin
AddHandler(htComponentRenamed,TMethod(OnComponentRenamed));
end;
procedure TPropertyEditorHook.RemoveHandlerComponentRenamed(
const OnComponentRenamed: TPropHookComponentRenamed);
begin
RemoveHandler(htComponentRenamed,TMethod(OnComponentRenamed));
end;
procedure TPropertyEditorHook.AddHandlerPersistentAdded(
const OnPersistentAdded: TPropHookPersistentAdded);
begin
AddHandler(htPersistentAdded,TMethod(OnPersistentAdded));
end;
procedure TPropertyEditorHook.RemoveHandlerPersistentAdded(
const OnPersistentAdded: TPropHookPersistentAdded);
begin
RemoveHandler(htPersistentAdded,TMethod(OnPersistentAdded));
end;
procedure TPropertyEditorHook.AddHandlerPersistentDeleting(
const OnPersistentDeleting: TPropHookPersistentDel);
begin
AddHandler(htPersistentDeleting,TMethod(OnPersistentDeleting));
end;
procedure TPropertyEditorHook.RemoveHandlerPersistentDeleting(
const OnPersistentDeleting: TPropHookPersistentDel);
begin
RemoveHandler(htPersistentDeleting,TMethod(OnPersistentDeleting));
end;
procedure TPropertyEditorHook.AddHandlerPersistentDeleted(
const OnPersistentDeleted: TPropHookPersistentDel);
begin
AddHandler(htPersistentDeleted,TMethod(OnPersistentDeleted));
end;
procedure TPropertyEditorHook.RemoveHandlerPersistentDeleted(
const OnPersistentDeleted: TPropHookPersistentDel);
begin
RemoveHandler(htPersistentDeleted,TMethod(OnPersistentDeleted));
end;
procedure TPropertyEditorHook.AddHandlerDeletePersistent(
const OnDeletePersistent: TPropHookDeletePersistent);
begin
AddHandler(htDeletePersistent,TMethod(OnDeletePersistent));
end;
procedure TPropertyEditorHook.RemoveHandlerDeletePersistent(
const OnDeletePersistent: TPropHookDeletePersistent);
begin
RemoveHandler(htDeletePersistent,TMethod(OnDeletePersistent));
end;
procedure TPropertyEditorHook.AddHandlerGetSelection(
const OnGetSelection: TPropHookGetSelection);
begin
AddHandler(htGetSelectedPersistents,TMethod(OnGetSelection));
end;
procedure TPropertyEditorHook.RemoveHandlerGetSelection(
const OnGetSelection: TPropHookGetSelection);
begin
RemoveHandler(htGetSelectedPersistents,TMethod(OnGetSelection));
end;
procedure TPropertyEditorHook.AddHandlerSetSelection(
const OnSetSelection: TPropHookSetSelection);
begin
AddHandler(htSetSelectedPersistents,TMethod(OnSetSelection));
end;
procedure TPropertyEditorHook.RemoveHandlerSetSelection(
const OnSetSelection: TPropHookSetSelection);
begin
RemoveHandler(htSetSelectedPersistents,TMethod(OnSetSelection));
end;
procedure TPropertyEditorHook.AddHandlerGetObject(const OnGetObject: TPropHookGetObject);
begin
AddHandler(htGetObject,TMethod(OnGetObject));
end;
procedure TPropertyEditorHook.RemoveHandlerGetObject(
const OnGetObject: TPropHookGetObject);
begin
RemoveHandler(htGetObject,TMethod(OnGetObject));
end;
procedure TPropertyEditorHook.AddHandlerGetObjectName(
const OnGetObjectName: TPropHookGetObjectName);
begin
AddHandler(htGetObjectName,TMethod(OnGetObjectName));
end;
procedure TPropertyEditorHook.RemoveHandlerGetObjectName(
const OnGetObjectName: TPropHookGetObjectName);
begin
RemoveHandler(htGetObjectName,TMethod(OnGetObjectName));
end;
procedure TPropertyEditorHook.AddHandlerGetObjectNames(
const OnGetObjectNames: TPropHookGetObjectNames);
begin
AddHandler(htGetObjectNames,TMethod(OnGetObjectNames));
end;
procedure TPropertyEditorHook.RemoveHandlerGetObjectNames(
const OnGetObjectNames: TPropHookGetObjectNames);
begin
RemoveHandler(htGetObjectNames,TMethod(OnGetObjectNames));
end;
procedure TPropertyEditorHook.AddHandlerObjectPropertyChanged(
const OnObjectPropertyChanged: TPropHookObjectPropertyChanged);
begin
AddHandler(htObjectPropertyChanged,TMethod(OnObjectPropertyChanged));
end;
procedure TPropertyEditorHook.RemoveHandlerObjectPropertyChanged(
const OnObjectPropertyChanged: TPropHookObjectPropertyChanged);
begin
RemoveHandler(htObjectPropertyChanged,TMethod(OnObjectPropertyChanged));
end;
procedure TPropertyEditorHook.AddHandlerModified(const OnModified: TPropHookModified);
begin
AddHandler(htModified,TMethod(OnModified));
end;
procedure TPropertyEditorHook.RemoveHandlerModified(const OnModified: TPropHookModified);
begin
RemoveHandler(htModified,TMethod(OnModified));
end;
procedure TPropertyEditorHook.AddHandlerModifiedWithName(
const OnModified: TPropHookModifiedWithName);
begin
AddHandler(htModifiedWithName,TMethod(OnModified));
end;
procedure TPropertyEditorHook.RemoveHandlerModifiedWithName(
const OnModified: TPropHookModifiedWithName);
begin
RemoveHandler(htModifiedWithName,TMethod(OnModified));
end;
procedure TPropertyEditorHook.AddHandlerDesignerMouseDown(
const OnMouseDown: TMouseEvent);
begin
AddHandler(htDesignerMouseDown,TMethod(OnMouseDown));
end;
procedure TPropertyEditorHook.AddHandlerDesignerMouseUp(
const OnMouseUp: TMouseEvent);
begin
AddHandler(htDesignerMouseUp,TMethod(OnMouseUp));
end;
procedure TPropertyEditorHook.RemoveHandlerDesignerMouseDown(
const OnMouseDown: TMouseEvent);
begin
RemoveHandler(htDesignerMouseDown,TMethod(OnMouseDown));
end;
procedure TPropertyEditorHook.RemoveHandlerDesignerMouseUp(
const OnMouseUp: TMouseEvent);
begin
RemoveHandler(htDesignerMouseUp,TMethod(OnMouseUp));
end;
procedure TPropertyEditorHook.AddHandlerRevert(const OnRevert: TPropHookRevert);
begin
AddHandler(htRevert,TMethod(OnRevert));
end;
procedure TPropertyEditorHook.RemoveHandlerRevert(const OnRevert: TPropHookRevert);
begin
RemoveHandler(htRevert,TMethod(OnRevert));
end;
procedure TPropertyEditorHook.AddHandlerRefreshPropertyValues(
const OnRefreshPropertyValues: TPropHookRefreshPropertyValues);
begin
AddHandler(htRefreshPropertyValues,TMethod(OnRefreshPropertyValues));
end;
procedure TPropertyEditorHook.RemoveHandlerRefreshPropertyValues(
const OnRefreshPropertyValues: TPropHookRefreshPropertyValues);
begin
RemoveHandler(htRefreshPropertyValues,TMethod(OnRefreshPropertyValues));
end;
procedure TPropertyEditorHook.AddHandlerAddDependency(
const OnAddDependency: TPropHookAddDependency);
begin
AddHandler(htAddDependency,TMethod(OnAddDependency));
end;
procedure TPropertyEditorHook.RemoveHandlerAddDependency(
const OnAddDependency: TPropHookAddDependency);
begin
RemoveHandler(htAddDependency,TMethod(OnAddDependency));
end;
procedure TPropertyEditorHook.AddHandlerGetCheckboxForBoolean(
const OnGetCheckboxForBoolean: TPropHookGetCheckboxForBoolean);
begin
AddHandler(htGetCheckboxForBoolean,TMethod(OnGetCheckboxForBoolean));
end;
procedure TPropertyEditorHook.SetLookupRoot(APersistent: TPersistent);
var
i: Integer;
begin
if FLookupRoot=APersistent then exit;
if FLookupRoot is TComponent then
RemoveFreeNotification(TComponent(FLookupRoot));
FLookupRoot:=APersistent;
if FLookupRoot is TComponent then
FreeNotification(TComponent(FLookupRoot));
i:=GetHandlerCount(htChangeLookupRoot);
while GetNextHandlerIndex(htChangeLookupRoot,i) do
TPropHookChangeLookupRoot(FHandlers[htChangeLookupRoot][i])();
end;
procedure TPropertyEditorHook.AddHandler(HookType: TPropHookType;
const Handler: TMethod);
begin
if Handler.Code=nil then
RaiseGDBException('TPropertyEditorHook.AddHandler');
if FHandlers[HookType]=nil then
FHandlers[HookType]:=TMethodList.Create;
FHandlers[HookType].Add(Handler);
end;
procedure TPropertyEditorHook.RemoveHandler(HookType: TPropHookType;
const Handler: TMethod);
begin
if FHandlers[HookType]<>nil then
FHandlers[HookType].Remove(Handler);
end;
function TPropertyEditorHook.GetHandlerCount(HookType: TPropHookType): integer;
begin
if FHandlers[HookType]<>nil then
Result:=FHandlers[HookType].Count
else
Result:=0;
end;
function TPropertyEditorHook.GetNextHandlerIndex(HookType: TPropHookType;
var i: integer): boolean;
begin
if FHandlers[HookType]<>nil then
Result:=FHandlers[HookType].NextDownIndex(i)
else begin
i:=-1;
Result:=false;
end;
end;
procedure TPropertyEditorHook.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation=opRemove) and (AComponent=FLookupRoot) then
LookupRoot:=nil;
end;
destructor TPropertyEditorHook.Destroy;
var
HookType: TPropHookType;
begin
for HookType:=Low(FHandlers) to high(FHandlers) do
FreeThenNil(FHandlers[HookType]);
inherited Destroy;
end;
function KeyStringToVKCode(const s: string): word;
var
i: PtrInt;
Data: Pointer;
begin
Result:=VK_UNKNOWN;
if KeyStringIsIrregular(s) then begin
Result:=word(StrToIntDef(copy(s,7,length(s)-8),VK_UNKNOWN));
exit;
end;
if (s<>'none') and (s<>'') then begin
if VirtualKeyStrings=nil then begin
VirtualKeyStrings:=TStringHashList.Create(true);
for i:=1 to 255 do
VirtualKeyStrings.Add(KeyAndShiftStateToKeyString(word(i),[]), {%H-}Pointer(i));
end;
end else
exit;
Data:=VirtualKeyStrings.Data[s];
if Data<>nil then
Result:=word({%H-}PtrUInt(Data));
end;
function GetClassUnitName(Value: TClass): string;
begin
if Value=nil then
Result:=''
else
Result:=GetSourceClassUnitName(Value)
end;
procedure CreateComponentEvent(AComponent: TComponent; const EventName: string);
var
CurDesigner: TIDesigner;
PropInfo: PPropInfo;
Hook: TPropertyEditorHook;
PersistentList: TPersistentSelectionList;
MethodPropEditor: TMethodPropertyEditor;
begin
CurDesigner:=FindRootDesigner(AComponent);
if CurDesigner=nil then exit;
// search method
PropInfo:=GetPropInfo(AComponent,EventName);
//writeln('CreateComponentEvent B ',PropInfo<>nil,' ',PropInfo^.PropType<>nil,' ',PropInfo^.PropType^.Kind=tkMethod,' ',(PropInfo^.GetProc<>nil),' ',(PropInfo^.SetProc<>nil));
if (PropInfo=nil)
or (PropInfo^.PropType=nil)
or (PropInfo^.PropType^.Kind<>tkMethod)
or (PropInfo^.GetProc=nil)
or (PropInfo^.SetProc=nil) then
exit;
MethodPropEditor:=nil;
PersistentList:=nil;
try
PersistentList := TPersistentSelectionList.Create;
PersistentList.Add(AComponent);
Hook:=GlobalDesignHook;
MethodPropEditor := TMethodPropertyEditor.Create(Hook,1);
MethodPropEditor.SetPropEntry(0, AComponent, PropInfo);
MethodPropEditor.Initialize;
MethodPropEditor.Edit;
finally
MethodPropEditor.Free;
PersistentList.Free;
end;
end;
function ClassNameToComponentName(const AClassName: string): string;
begin
Result:=AClassName;
if (length(Result)>2) and (Result[1] in ['T','t'])
and (not (Result[2] in ['0'..'9'])) then
System.Delete(Result,1,1);
end;
function ControlAcceptsStreamableChildComponent(aControl: TWinControl;
aComponentClass: TComponentClass; aLookupRoot: TPersistent): boolean;
{off $DEFINE VerboseAddDesigner}
var
Parent: TWinControl;
begin
Result:=false;
if not (csAcceptsControls in aControl.ControlStyle) then
begin
{$IFDEF VerboseAddDesigner}
debugln(['ControlAcceptsStreamableChildComponent missing csAcceptsControls in ',DbgSName(aControl)]);
{$ENDIF}
exit;
end;
if aComponentClass.InheritsFrom(TControl)
and not aControl.CheckChildClassAllowed(aComponentClass, False) then
begin
{$IFDEF VerboseAddDesigner}
debugln(['ControlAcceptsStreamableChildComponent aControl=',DbgSName(aControl),' CheckChildClassAllowed forbids ',DbgSName(aComponentClass)]);
{$ENDIF}
exit;
end;
// the LookupRoot allows children
if aControl=aLookupRoot then
exit(true);
// TWriter only supports children of LookupRoot and LookupRoot.Components
if (aControl.Owner <> aLookupRoot) and (aControl <> aLookupRoot) then
begin
{$IFDEF VerboseAddDesigner}
debugln(['ControlAcceptsStreamableChildComponent wrong lookuproot aControl=',DbgSName(aControl),' aLookupRoot=',DbgSName(aLookupRoot),' aControl.Owner=',DbgSName(aControl.Owner)]);
{$ENDIF}
exit;
end;
// TWriter does not support children on nested components
// (i.e. csInline , e.g. on a frame) nor any of its components
Parent:=aControl;
while (Parent<>nil) and (Parent<>aLookupRoot) do begin
if csInline in Parent.ComponentState then begin
{$IFDEF VerboseAddDesigner}
debugln(['ControlAcceptsStreamableChildComponent aControl=',DbgSName(aControl),' Parent=',DbgSName(Parent),' csInline']);
{$ENDIF}
exit;
end;
Parent:=Parent.Parent;
end;
Result:=true;
end;
function ClassTypeInfo(Value: TClass): PTypeInfo;
begin
Result := PTypeInfo(Value.ClassInfo);
end;
procedure EditCollection(AComponent: TComponent; ACollection: TCollection; APropName: String);
begin
TCollectionPropertyEditor.ShowCollectionEditor(ACollection, AComponent, APropName);
end;
procedure EditCollectionNoAddDel(AComponent: TComponent; ACollection: TCollection; APropName: String);
begin
TNoAddDeleteCollectionPropertyEditor.ShowCollectionEditor(ACollection, AComponent, APropName);
end;
function IsInteresting(AEditor: TPropertyEditor; const AFilter: TTypeKinds;
const APropNameFilter: String): Boolean;
var
visited: TFPList;
// check set element names against AFilter
function IsPropInSet( const ATypeInfo: PTypeInfo ) : Boolean;
var
EnumType: PTypeInfo;
i: Integer;
begin
Result := False;
if (ATypeInfo^.Kind <> tkSet) then exit;
// Get TypeInfo of set type.
EnumType := GetTypeData(ATypeInfo)^.CompType;
with GetTypeData(EnumType)^ do
for i := MinValue to MaxValue do
begin
Result := MultiWordSearch(APropNameFilter, GetEnumName(EnumType,i));
if Result then
Break;
end;
end;
//check if class has property name
function IsPropInClass( const ATypeInfo: PTypeInfo ) : Boolean;
var
propInfo: PPropInfo;
propList: PPropList;
i, propCount: Integer;
quSubclass: TFPList;
icurClass: Integer = 0;
begin
Result := False;
quSubclass := TFPList.Create;
quSubclass.Add(ATypeInfo);
while icurClass < quSubclass.Count do
begin
propCount := GetPropList(quSubclass.Items[icurClass], propList);
for i := 0 to propCount - 1 do
begin
propInfo := propList^[i];
Result := MultiWordSearch(APropNameFilter, propInfo^.Name);
if Result then break;
//if encounter a Set check its elements name.
if (propInfo^.PropType^.Kind = tkSet) then
begin
Result := IsPropInSet(propInfo^.PropType);
if Result then break;
end;
//queue subclasses(only once) to check later.
if (propInfo^.PropType^.Kind = tkClass) then
if quSubclass.IndexOf(propInfo^.PropType) >= 0 then Continue
else quSubclass.Add(propInfo^.PropType);
end;
if Assigned(propList) then FreeMem(propList);
//no need to check subclasses if result is already true.
if Result then break;
inc(icurClass);
end;
quSubclass.Free;
end;
// Add AForceShow to display T****PropertyEditor when subproperties found.
// and name of class is not the same as filter
procedure Rec(A: TPropertyEditor; AForceShow: Boolean = False);
var
propList: PPropList;
i: Integer;
ti: PTypeInfo;
edClass: TPropertyEditorClass;
ed: TPropertyEditor;
obj: TPersistent;
PropCnt: LongInt;
begin
ti := A.GetPropType;
//DebugLn('IsInteresting: ', ti^.Name);
Result := ti^.Kind <> tkClass;
if Result then
begin
if (APropNameFilter = '') or AForceShow then
exit;
Result := MultiWordSearch(APropNameFilter, A.GetName); // Check single Props
// Check if check Set has element.
if (ti^.Kind = tkSet) and (A.ClassType <> TSetElementPropertyEditor) then
Result := Result or IsPropInSet(A.GetPropType);
exit;
end;
// Subproperties can change if user selects another object =>
// we must show the property, even if it is not interesting currently.
//Result := paVolatileSubProperties in A.GetAttributes; // Not really needed?
//if Result then exit;
if tkClass in AFilter then
begin
// We want classes => any non-trivial editor is immediately interesting.
Result := A.ClassType <> TClassPropertyEditor;
if Result then
begin
// if no SubProperties check against filter name
if (APropNameFilter = '') then
exit;
Result := MultiWordSearch(APropNameFilter, A.GetName);
if (paSubProperties in A.GetAttributes) then
Result := Result or IsPropInClass(A.GetPropType);
exit;
end;
end
else if A.GetAttributes * [paSubProperties, paVolatileSubProperties] = [] then
exit;
obj := TPersistent(A.GetObjectValue);
// At this stage, there is nothing interesting left in empty objects.
if obj = nil then exit;
// Class properties may directly or indirectly refer to the same class,
// so we must avoid infinite recursion.
if visited.IndexOf(ti) >= 0 then exit;
visited.Add(ti);
// actual published properties can be different since the instance can be inherited
// so update type info from the instance
ti := obj.ClassInfo;
PropCnt := GetPropList(ti, propList);
try
for i := 0 to PropCnt - 1 do begin
if not (propList^[i]^.PropType^.Kind in AFilter + [tkClass]) then continue;
edClass := GetEditorClass(propList^[i], obj);
if edClass = nil then continue;
ed := edClass.Create(AEditor.FPropertyHook, 1);
try
ed.SetPropEntry(0, obj, propList^[i]);
ed.Initialize;
// filter TClassPropertyEditor name recursively
Rec(ed, MultiWordSearch(APropNameFilter, A.GetName));
finally
ed.Free;
end;
if Result then break;
end;
finally
FreeMem(propList);
end;
visited.Delete(visited.Count - 1);
end;
begin
visited := TFPList.Create;
try
//DebugLn('IsInteresting -> ', AEditor.GetPropInfo^.Name, ': ', AEditor.GetPropInfo^.PropType^.Name);
Rec(AEditor);
//DebugLn('IsInteresting <- ', BoolToStr(Result, true));
finally
visited.Free;
end;
end;
function GetOrdField(Field: Pointer; FieldInfo: PTypeInfo): Int64;
var
Signed: Boolean;
DataSize: Integer;
OrdType: TOrdType;
begin
Result:=0;
Signed := false;
DataSize := 4;
case FieldInfo^.Kind of
tkChar, tkBool:
DataSize:=1;
tkWChar:
DataSize:=2;
tkSet,
tkEnumeration,
tkInteger:
begin
OrdType:=GetTypeData(FieldInfo)^.OrdType;
case OrdType of
otSByte,otUByte: DataSize := 1;
otSWord,otUWord: DataSize := 2;
end;
Signed := OrdType in [otSByte,otSWord,otSLong];
end;
tkInt64 :
begin
DataSize:=8;
Signed:=true;
end;
tkQword :
begin
DataSize:=8;
Signed:=false;
end;
end;
if Signed then begin
case DataSize of
1: Result:=PShortInt(Field)^;
2: Result:=PSmallInt(Field)^;
4: Result:=PLongint(Field)^;
8: Result:=PInt64(Field)^;
end;
end else begin
case DataSize of
1: Result:=PByte(Field)^;
2: Result:=PWord(Field)^;
4: Result:=PLongint(Field)^;
8: Result:=PInt64(Field)^;
end;
end;
end;
procedure SetOrdField(Field: Pointer; FieldInfo: PTypeInfo; Value: Int64);
var
DataSize: Integer;
begin
if FieldInfo^.Kind in [tkInt64,tkQword] then
DataSize := 8
else
DataSize := 4;
if not (FieldInfo^.Kind in [tkInt64,tkQword,tkClass,tkInterface,tkInterfaceRaw,tkDynArray]) then
begin
// cut off unnecessary stuff
case GetTypeData(FieldInfo)^.OrdType of
otSWord,otUWord:
begin
Value:=Value and $ffff;
DataSize := 2;
end;
otSByte,otUByte:
begin
Value:=Value and $ff;
DataSize := 1;
end;
end;
end;
case DataSize of
1: PByte(Field)^:=Byte(Value);
2: PWord(Field)^:=Word(Value);
4: PLongint(Field)^:=Longint(Value);
8: PInt64(Field)^:=Value;
end;
end;
function GetEnumField(Field: Pointer; FieldInfo: PTypeInfo): String;
begin
Result:=GetEnumName(FieldInfo, GetOrdField(Field, FieldInfo));
end;
procedure SetEnumField(Field: Pointer; FieldInfo: PTypeInfo; const Value: string);
var
PV: Integer;
begin
PV:=GetEnumValue(FieldInfo, Value);
if (PV<0) then
raise EPropertyError.CreateFmt(SErrUnknownEnumValue, [Value]);
SetOrdField(Field, FieldInfo, PV);
end;
function GetSetField(Field: Pointer; FieldInfo: PTypeInfo; Brackets: Boolean): String;
begin
Result:=SetToString(FieldInfo,GetOrdField(Field,FieldInfo),Brackets);
end;
procedure SetSetField(Field: Pointer; FieldInfo: PTypeInfo; const Value: string);
begin
SetOrdField(Field,FieldInfo,StringToSet(FieldInfo,Value));
end;
function GetStringField(Field: Pointer; FieldInfo: PTypeInfo): String;
begin
Result:='';
case FieldInfo^.Kind of
tkWString:
Result:=AnsiString(GetWideStringField(Field,FieldInfo));
tkUString:
Result := AnsiString(GetUnicodeStringField(Field,FieldInfo));
tkSString:
Result := PShortString(Field)^;
tkAString:
Result := PAnsiString(Field)^;
end;
end;
procedure SetStringField(Field: Pointer; FieldInfo: PTypeInfo; const Value: string);
begin
case FieldInfo^.Kind of
tkWString:
SetWideStringField(Field,FieldInfo,WideString(Value));
tkUString:
SetUnicodeStringField(Field,FieldInfo,UnicodeString(Value));
tkSString:
PShortString(Field)^:=Value;
tkAString:
PAnsiString(Field)^:=Value;
end;
end;
function GetWideStringField(Field: Pointer; FieldInfo: PTypeInfo): WideString;
begin
Result:='';
case FieldInfo^.Kind of
tkSString,tkAString:
Result := WideString(GetStringField(Field,FieldInfo));
tkUString :
Result := GetUnicodeStringField(Field,FieldInfo);
tkWString:
Result := PWideString(Field)^;
end;
end;
procedure SetWideStringField(Field: Pointer; FieldInfo: PTypeInfo; const Value: WideString);
begin
case FieldInfo^.Kind of
tkSString,tkAString:
SetStringField(Field,FieldInfo,AnsiString(Value));
tkUString:
SetUnicodeStringField(Field,FieldInfo,Value);
tkWString:
PWideString(Field)^:=Value;
end;
end;
function GetUnicodeStringField(Field: Pointer; FieldInfo: PTypeInfo): UnicodeString;
begin
Result:='';
case FieldInfo^.Kind of
tkSString,tkAString:
Result := UnicodeString(GetStringField(Field,FieldInfo));
tkWString:
Result := GetWideStringField(Field,FieldInfo);
tkUString :
Result := PUnicodeString(Field)^;
end;
end;
procedure SetUnicodeStringField(Field: Pointer; FieldInfo: PTypeInfo; const Value: UnicodeString
);
begin
case FieldInfo^.Kind of
tkSString,tkAString:
SetStringField(Field,FieldInfo,AnsiString(Value));
tkWString:
SetWideStringField(Field,FieldInfo,Value);
tkUString:
PUnicodeString(Field)^:=Value;
end;
end;
function GetRawbyteStringField(Field: Pointer; FieldInfo: PTypeInfo): RawByteString;
begin
Result:='';
case FieldInfo^.Kind of
tkWString:
Result := RawByteString(GetWideStringField(Field,FieldInfo));
tkUString:
Result := RawByteString(GetUnicodeStringField(Field,FieldInfo));
tkSString:
Result := RawByteString(GetStringField(Field,FieldInfo));
tkAString:
Result := PAnsiString(Field)^;
end;
end;
procedure SetRawbyteStringField(Field: Pointer; FieldInfo: PTypeInfo; const Value: RawByteString
);
begin
case FieldInfo^.Kind of
tkWString:
SetWideStringField(Field,FieldInfo,WideString(Value));
tkUString:
SetUnicodeStringField(Field,FieldInfo,UnicodeString(Value));
tkSString:
SetStringField(Field,FieldInfo,Value);
tkAString:
PAnsiString(Field)^:=Value;
else
end;
end;
function GetFloatField(Field: Pointer; FieldInfo: PTypeInfo): Extended;
begin
Result:=0.0;
case GetTypeData(FieldInfo)^.FloatType of
ftSingle:
Result:=PSingle(Field)^;
ftDouble:
Result:=PDouble(Field)^;
ftExtended:
Result:=PExtended(Field)^;
ftComp:
Result:=PComp(Field)^;
ftCurr:
Result:=PCurrency(Field)^;
end;
end;
procedure SetFloatField(Field: Pointer; FieldInfo: PTypeInfo; const Value: Extended);
begin
Case GetTypeData(FieldInfo)^.FloatType of
ftSingle:
PSingle(Field)^:=Value;
ftDouble:
PDouble(Field)^:=Value;
ftExtended:
PExtended(Field)^:=Value;
{$ifdef FPC_COMP_IS_INT64}
ftComp:
PComp(Field)^:=trunc(Value);
{$else FPC_COMP_IS_INT64}
ftComp:
PComp(Field)^:=Comp(Value);
{$endif FPC_COMP_IS_INT64}
ftCurr:
PCurrency(Field)^:=Value;
end;
end;
function GetObjectField(Field: Pointer; FieldInfo: PTypeInfo; MinClass: TClass): TObject;
begin
Result:=TObject(PPointer(Field)^);
if (MinClass<>nil) and (Result<>nil) Then
if not Result.InheritsFrom(MinClass) then
Result:=nil;
if FieldInfo=nil then ;
end;
procedure SetObjectField(Field: Pointer; FieldInfo: PTypeInfo; const Value: TObject);
begin
PPointer(Field)^:=Pointer(Value);
if FieldInfo=nil then ;
end;
function GetPointerField(Field: Pointer; FieldInfo: PTypeInfo): Pointer;
begin
Result:=PPointer(Field)^;
if FieldInfo=nil then ;
end;
procedure SetPointerField(Field: Pointer; FieldInfo: PTypeInfo; const Value: Pointer);
begin
PPointer(Field)^:=Value;
if FieldInfo=nil then ;
end;
function GetMethodField(Field: Pointer; FieldInfo: PTypeInfo): TMethod;
begin
Result:=PMethod(Field)^;
if FieldInfo=nil then ;
end;
procedure SetMethodField(Field: Pointer; FieldInfo: PTypeInfo; const Value: TMethod);
begin
PMethod(Field)^:=Value;
if FieldInfo=nil then ;
end;
function GetInterfaceField(Field: Pointer; FieldInfo: PTypeInfo): IInterface;
begin
Result:=IInterface(PPointer(Field)^);
if FieldInfo=nil then ;
end;
procedure SetInterfaceField(Field: Pointer; FieldInfo: PTypeInfo; const Value: IInterface);
begin
PInterface(Field)^:=Value;
if FieldInfo=nil then ;
end;
function GetVariantField(Field: Pointer; FieldInfo: PTypeInfo): Variant;
begin
Result:=PVariant(Field)^;
end;
procedure SetVariantField(Field: Pointer; FieldInfo: PTypeInfo; const Value: Variant);
begin
PVariant(Field)^:=Value;
end;
Function GetPointerProp(Instance: TObject; PropInfo : PPropInfo): Pointer;
Type
TGetPointerProcIndex = function (index:longint): Pointer of object;
TGetPointerProc = function (): Pointer of object;
var
AMethod : TMethod;
begin
case (PropInfo^.PropProcs) and 3 of
ptField:
Result := PPointer(Pointer(Instance) + LongWord(PropInfo^.GetProc))^;
ptStatic,
ptVirtual:
begin
if (PropInfo^.PropProcs and 3)=ptStatic then
AMethod.Code:=PropInfo^.GetProc
else
AMethod.Code:=PCodePointer(Pointer(Instance.ClassType)+PtrUInt(PropInfo^.GetProc))^;
AMethod.Data:=Instance;
if ((PropInfo^.PropProcs shr 6) and 1)<>0 then
Result:=TGetPointerProcIndex(AMethod)(PropInfo^.Index)
else
Result:=TGetPointerProc(AMethod)();
end;
else
raise EPropertyError.CreateFmt(SErrCannotReadProperty, [PropInfo^.Name]);
end;
end;
Procedure SetPointerProp(Instance: TObject; PropInfo : PPropInfo; Value: Pointer);
type
TSetPointerProcIndex = procedure(index: longint; p: pointer) of object;
TSetPointerProc = procedure(p: pointer) of object;
var
AMethod : TMethod;
begin
case (PropInfo^.PropProcs shr 2) and 3 of
ptField:
PPointer(Pointer(Instance) + LongWord(PropInfo^.SetProc))^:=Value;
ptStatic,
ptVirtual:
begin
if ((PropInfo^.PropProcs shr 2) and 3)=ptStatic then
AMethod.Code:=PropInfo^.SetProc
else
AMethod.Code:=PCodePointer(Pointer(Instance.ClassType)+PtrUInt(PropInfo^.SetProc))^;
AMethod.Data:=Instance;
if ((PropInfo^.PropProcs shr 6) and 1)<>0 then
TSetPointerProcIndex(AMethod)(PropInfo^.Index,Value)
else
TSetPointerProc(AMethod)(Value);
end;
else
raise EPropertyError.CreateFmt(SErrCannotWriteToProperty, [PropInfo^.Name]);
end;
end;
function dbgs(peh: TPropEditHint): string;
begin
writestr(Result,peh);
end;
{ TNoteBookActiveControlPropertyEditor }
function TNoteBookActiveControlPropertyEditor.CheckNewValue(APersistent: TPersistent): boolean;
var
AComponent: TPersistent;
Notebook: TCustomTabControl;
begin
Result:=true;
if APersistent=nil then exit;
AComponent:=GetComponent(0);
if not (AComponent is TCustomTabControl) then
raise Exception.Create('invalid instance for this property editor');
Notebook:=TCustomTabControl(AComponent);
if Notebook.IndexOf(APersistent)<0 then
raise Exception.Create('only children are allowed for this property');
end;
function TNoteBookActiveControlPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result:=(inherited GetAttributes)-[paMultiSelect];
end;
procedure TNoteBookActiveControlPropertyEditor.GetValues(Proc: TGetStrProc);
var
AComponent: TPersistent;
Notebook: TCustomTabControl;
i: Integer;
begin
Proc(oisNone);
AComponent:=GetComponent(0);
if not (AComponent is TCustomTabControl) then exit;
Notebook:=TCustomTabControl(AComponent);
for i:=0 to Notebook.PageCount-1 do
Proc(Notebook.Page[i].Name);
end;
{ TCustomShortCutGrabBox }
procedure TCustomShortCutGrabBox.SetKey(const AValue: Word);
var
s: String;
i: LongInt;
begin
if FKey=AValue then exit;
FKey:=AValue;
s:=KeyAndShiftStateToKeyString(FKey,[]);
{$IFDEF VerboseKeyboard}
debugln(['TCustomShortCutGrabBox.SetKey ',Key,' "',s,'"']);
{$ENDIF}
i:=KeyComboBox.Items.IndexOf(s);
if i>=0 then
KeyComboBox.ItemIndex:=i
else if KeyStringIsIrregular(s) then begin
KeyComboBox.Items.Add(s);
KeyComboBox.ItemIndex:=KeyComboBox.Items.IndexOf(s);
end else
KeyComboBox.ItemIndex:=0;
end;
procedure TCustomShortCutGrabBox.GrabButtonClick(Sender: TObject);
begin
FGrabForm:=TForm.Create(Self);
FGrabForm.BorderStyle:=bsDialog;
FGrabForm.KeyPreview:=true;
FGrabForm.Position:=poScreenCenter;
FGrabForm.OnKeyDown:=@GrabFormKeyDown;
FGrabForm.Caption:=oisPressAKey;
with TLabel.Create(Self) do begin
Caption:=oisPressAKeyEGCtrlP;
BorderSpacing.Around:=50;
Parent:=FGrabForm;
end;
FGrabForm.Width:=200;
FGrabForm.Height:=50;
FGrabForm.AutoSize:=true;
FGrabForm.ShowModal;
// After getting a key, focus the main form's OK button. User can just click Enter.
if (Key <> VK_UNKNOWN) and Assigned(MainOkButton) then
MainOkButton.SetFocus;
FreeAndNil(FGrabForm);
end;
procedure TCustomShortCutGrabBox.ShiftCheckBoxClick(Sender: TObject);
var
s: TShiftStateEnum;
begin
for s:=Low(TShiftStateEnum) to High(TShiftStateEnum) do
if FCheckBoxes[s]=Sender then
if FCheckBoxes[s].Checked then
Include(FShiftState,s)
else
Exclude(FShiftState,s);
end;
procedure TCustomShortCutGrabBox.GrabFormKeyDown(Sender: TObject;
var AKey: Word; AShift: TShiftState);
begin
{$IFDEF VerboseKeyboard}
DebugLn(['TCustomShortCutGrabBox.GrabFormKeyDown ',AKey,' ',dbgs(AShift)]);
DumpStack;
{$ENDIF}
if not (AKey in [VK_CONTROL, VK_LCONTROL, VK_RCONTROL,
VK_SHIFT, VK_LSHIFT, VK_RSHIFT,
VK_MENU, VK_LMENU, VK_RMENU,
VK_LWIN, VK_RWIN,
VK_PROCESSKEY,
VK_MODECHANGE,
VK_UNKNOWN, VK_UNDEFINED])
then begin
if (AKey=VK_ESCAPE) and (AShift=[]) then begin
Key:=VK_UNKNOWN;
ShiftState:=[];
end else begin
Key:=AKey;
ShiftState:=AShift;
end;
FGrabForm.ModalResult:=mrOk;
end;
end;
procedure TCustomShortCutGrabBox.KeyComboboxEditingDone(Sender: TObject);
begin
Key:=KeyStringToVKCode(KeyComboBox.Text);
end;
function TCustomShortCutGrabBox.GetShiftCheckBox(Shift: TShiftStateEnum): TCheckBox;
begin
Result:=FCheckBoxes[Shift];
end;
function TCustomShortCutGrabBox.GetKey: Word;
begin
Result:=FKey;
if (FKey = 0) then
FShiftState:=[];
end;
procedure TCustomShortCutGrabBox.SetAllowedShifts(const AValue: TShiftState);
begin
if FAllowedShifts=AValue then exit;
FAllowedShifts:=AValue;
ShiftState:=ShiftState*FAllowedShifts;
end;
procedure TCustomShortCutGrabBox.SetShiftButtons(const AValue: TShiftState);
begin
if FShiftButtons=AValue then exit;
FShiftButtons:=AValue;
UpdateShiftButtons;
end;
procedure TCustomShortCutGrabBox.SetShiftState(const AValue: TShiftState);
var
s: TShiftStateEnum;
begin
if FShiftState=AValue then exit;
FShiftState:=AValue;
for s:=low(TShiftStateEnum) to High(TShiftStateEnum) do
if FCheckBoxes[s]<>nil then
FCheckBoxes[s].Checked:=s in FShiftState;
end;
procedure TCustomShortCutGrabBox.Loaded;
begin
inherited Loaded;
UpdateShiftButtons;
end;
procedure TCustomShortCutGrabBox.RealSetText(const Value: TCaption);
begin
// do not allow to set caption
end;
procedure TCustomShortCutGrabBox.UpdateShiftButtons;
var
s: TShiftStateEnum;
LastCheckBox: TCheckBox;
begin
if [csLoading,csDestroying]*ComponentState<>[] then exit;
LastCheckBox:=nil;
DisableAlign;
try
for s:=low(TShiftStateEnum) to High(TShiftStateEnum) do begin
if s in FShiftButtons then begin
if FCheckBoxes[s]=nil then begin
FCheckBoxes[s]:=TCheckBox.Create(Self);
with FCheckBoxes[s] do begin
Name:='CheckBox'+ShiftToStr(s);
Caption:=ShiftToStr(s);
AutoSize:=true;
Checked:=s in FShiftState;
if LastCheckBox<>nil then
AnchorToNeighbour(akLeft,6,LastCheckBox)
else
AnchorParallel(akLeft,0,Self);
AnchorParallel(akTop,0,Self);
AnchorParallel(akBottom,0,Self);
Parent:=Self;
OnClick:=@ShiftCheckBoxClick;
end;
end;
LastCheckBox:=FCheckBoxes[s];
end else begin
FreeAndNil(FCheckBoxes[s]);
end;
end;
if LastCheckBox<>nil then
FKeyComboBox.AnchorToNeighbour(akLeft,6,LastCheckBox)
else
FKeyComboBox.AnchorParallel(akLeft,0,Self);
finally
EnableAlign;
end;
end;
procedure TCustomShortCutGrabBox.Notification(AComponent: TComponent;
Operation: TOperation);
var
s: TShiftStateEnum;
begin
inherited Notification(AComponent, Operation);
if Operation=opRemove then begin
if AComponent=FGrabButton then
FGrabButton:=nil;
if AComponent=FKeyComboBox then
FKeyComboBox:=nil;
if AComponent=FGrabForm then
FGrabForm:=nil;
for s:=Low(TShiftStateEnum) to High(TShiftStateEnum) do
if FCheckBoxes[s]=AComponent then begin
FCheckBoxes[s]:=nil;
Exclude(FShiftButtons,s);
end;
end;
end;
function TCustomShortCutGrabBox.ShiftToStr(s: TShiftStateEnum): string;
begin
case s of
ssShift: Result:='Shift';
ssAlt: Result:='Alt';
ssCtrl: Result:='Ctrl';
ssMeta: Result:='Meta';
ssSuper: Result:='Super';
ssHyper: {$IFDEF Darwin}
Result:='Cmd';
{$ELSE}
Result:='Hyper';
{$ENDIF}
ssAltGr: Result:='AltGr';
ssCaps: Result:='Caps';
ssNum: Result:='Numlock';
ssScroll: Result:='Scroll';
else Result:='Modifier'+IntToStr(ord(s));
end;
end;
constructor TCustomShortCutGrabBox.Create(TheOwner: TComponent);
procedure AddKeyToCombobox(i: integer);
var
s: String;
begin
s := KeyAndShiftStateToKeyString(i, []);
if not KeyStringIsIrregular(s) then
FKeyComboBox.Items.Add(s);
end;
var
i: Integer;
ShSt: TShiftStateEnum;
begin
inherited Create(TheOwner);
FAllowedShifts:=[ssShift, ssAlt, ssCtrl,
ssMeta, ssSuper, ssHyper, ssAltGr,
ssCaps, ssNum, ssScroll];
FGrabButton:=TButton.Create(Self);
with FGrabButton do begin
Name:='GrabButton';
Caption:=srGrabKey;
Align:=alRight;
AutoSize:=true;
Parent:=Self;
OnClick:=@GrabButtonClick;
end;
FKeyComboBox:=TComboBox.Create(Self);
with FKeyComboBox do begin
Name:='FKeyComboBox';
AutoSize:=true;
Items.BeginUpdate;
AddKeyToCombobox(0);
for i:=VK_BACK to VK_SCROLL do
AddKeyToCombobox(i);
for i:=VK_BROWSER_BACK to VK_OEM_CLEAR do
AddKeyToCombobox(i);
Items.EndUpdate;
OnEditingDone:=@KeyComboboxEditingDone;
Parent:=Self;
AnchorToNeighbour(akRight,6,FGrabButton);
AnchorVerticalCenterTo(FGrabButton);
Constraints.MinWidth:=130;
end;
BevelOuter:=bvNone;
ShiftButtons:=GetDefaultShiftButtons;
ShiftState:=[];
Key:=VK_UNKNOWN;
KeyComboBox.Text:=KeyAndShiftStateToKeyString(Key,[]);
// Fix TabOrders. The controls were created in "wrong" order.
i:=FGrabButton.TabOrder; // GrabButton was created first.
for ShSt:=Low(FCheckBoxes) to High(FCheckBoxes) do begin
if Assigned(FCheckBoxes[ShSt]) then begin
FCheckBoxes[ShSt].TabOrder:=i;
Inc(i);
end;
end;
FKeyComboBox.TabOrder:=i;
FGrabButton.TabOrder:=i+1;
end;
function TCustomShortCutGrabBox.GetDefaultShiftButtons: TShiftState;
begin
{$IFDEF Darwin}
Result:=[ssCtrl,ssShift,ssAlt,ssMeta];
{$ELSE}
Result:=[ssCtrl,ssShift,ssAlt];
{$ENDIF}
end;
procedure InitPropEdits;
begin
// Don't create PropertyClassList and PropertyEditorMapperList lists here.
// RegisterPropertyEditor and RegisterPropertyEditorMapper create them,
// and they are called from many initialization sections in unpredictable order.
// register the standard property editors
RegisterPropertyEditor(TypeInfo(AnsiString), TComponent, 'Name', TComponentNamePropertyEditor);
RegisterPropertyEditor(TypeInfo(TTranslateString), TCustomLabel, 'Caption', TStringMultilinePropertyEditor);
RegisterPropertyEditor(TypeInfo(TTranslateString), TCustomStaticText, 'Caption', TStringMultilinePropertyEditor);
RegisterPropertyEditor(TypeInfo(TTranslateString), TCustomCheckBox, 'Caption', TStringMultilinePropertyEditor);
RegisterPropertyEditor(TypeInfo(TTranslateString), TCustomSpeedButton, 'Caption', TStringMultilinePropertyEditor);
RegisterPropertyEditor(TypeInfo(TTranslateString), TMenuItem, 'Caption', TMenuItemCaptionEditor);
RegisterPropertyEditor(TypeInfo(TTranslateString), TComponent, 'Hint', TStringMultilinePropertyEditor);
RegisterPropertyEditor(TypeInfo(TCaption), TGridColumnTitle, 'Caption', TStringMultilinePropertyEditor);
RegisterPropertyEditor(TypeInfo(TTabOrder), TControl, 'TabOrder', TTabOrderPropertyEditor);
RegisterPropertyEditor(TypeInfo(ShortString), nil, '', TCaptionPropertyEditor);
RegisterPropertyEditor(TypeInfo(TStrings), nil, '', TStringsPropertyEditor);
RegisterPropertyEditor(TypeInfo(TFileName), nil, '', TFileNamePropertyEditor);
RegisterPropertyEditor(TypeInfo(AnsiString), nil, 'SessionProperties', TSessionPropertiesPropertyEditor);
RegisterPropertyEditor(TypeInfo(TModalResult), nil, 'ModalResult', TModalResultPropertyEditor);
RegisterPropertyEditor(TypeInfo(TShortCut), nil, '', TShortCutPropertyEditor);
//RegisterPropertyEditor(DummyClassForPropTypes.PTypeInfos('TDate'), nil,'',TDatePropertyEditor);
//RegisterPropertyEditor(DummyClassForPropTypes.PTypeInfos('TTime'), nil,'',TTimePropertyEditor);
RegisterPropertyEditor(TypeInfo(TDateTime), nil, '', TDateTimePropertyEditor);
RegisterPropertyEditor(TypeInfo(TCursor), nil, '', TCursorPropertyEditor);
RegisterPropertyEditor(TypeInfo(TComponent), nil, '', TComponentPropertyEditor);
RegisterPropertyEditor(TypeInfo(TComponent), nil, 'ActiveControl', TComponentOneFormPropertyEditor);
RegisterPropertyEditor(TypeInfo(TControl), TCoolBand, 'Control', TCoolBarControlPropertyEditor);
RegisterPropertyEditor(TypeInfo(TCollection), nil, '', TCollectionPropertyEditor);
RegisterPropertyEditor(TypeInfo(TFlowPanelControlList), TFlowPanel, 'ControlList', TNoAddDeleteCollectionPropertyEditor);
RegisterPropertyEditor(TypeInfo(TControl), TFlowPanelControl, 'Control', THiddenPropertyEditor);
RegisterPropertyEditor(TypeInfo(AnsiString), TFileDialog, 'Filter', TFileDlgFilterProperty);
RegisterPropertyEditor(TypeInfo(AnsiString), TFilterComboBox, 'Filter', TFileDlgFilterProperty);
RegisterPropertyEditor(TypeInfo(AnsiString), TFileNameEdit, 'Filter', TFileDlgFilterProperty);
RegisterPropertyEditor(TypeInfo(AnsiString), TCustomPropertyStorage, 'Filename', TFileNamePropertyEditor);
RegisterPropertyEditor(TypeInfo(TStrings), TValueListEditor, 'Strings', TValueListPropertyEditor);
RegisterPropertyEditor(TypeInfo(TCustomPage), TCustomTabControl, 'ActivePage', TNoteBookActiveControlPropertyEditor);
RegisterPropertyEditor(TypeInfo(TSizeConstraints), TControl, 'Constraints', TConstraintsPropertyEditor);
RegisterPropertyEditor(TypeInfo(TStrings), TNoteBook, 'Pages', TPagesPropertyEditor);
RegisterPropertyEditor(TypeInfo(TTranslateString), TCustomTaskDialog, 'Text', TStringMultilinePropertyEditor);
RegisterPropertyEditor(TypeInfo(TTranslateString), TCustomTaskDialog, 'ExpandedText', TStringMultilinePropertyEditor);
RegisterPropertyEditor(TypeInfo(TTranslateString), TCustomTaskDialog, 'FooterText', TStringMultilinePropertyEditor);
// Property is hidden and editing disabled by HiddenPropertyEditor :
RegisterPropertyEditor(TypeInfo(TAnchorSide), TControl, 'AnchorSideLeft', THiddenPropertyEditor);
RegisterPropertyEditor(TypeInfo(TAnchorSide), TControl, 'AnchorSideTop', THiddenPropertyEditor);
RegisterPropertyEditor(TypeInfo(TAnchorSide), TControl, 'AnchorSideRight', THiddenPropertyEditor);
RegisterPropertyEditor(TypeInfo(TAnchorSide), TControl, 'AnchorSideBottom', THiddenPropertyEditor);
RegisterPropertyEditor(TypeInfo(LongInt), TControl, 'ClientWidth', THiddenPropertyEditor);
RegisterPropertyEditor(TypeInfo(LongInt), TControl, 'ClientHeight', THiddenPropertyEditor);
RegisterPropertyEditor(TypeInfo(AnsiString), TCustomForm, 'LCLVersion', THiddenPropertyEditor);
RegisterPropertyEditor(TypeInfo(AnsiString), TCustomFrame, 'LCLVersion', THiddenPropertyEditor);
// since fpc 2.6.0 WordBool, LongBool and QWordBool only allow 0 and 1
RegisterPropertyEditor(TypeInfo(WordBool), nil, '', TBoolPropertyEditor);
RegisterPropertyEditor(TypeInfo(LongBool), nil, '', TBoolPropertyEditor);
RegisterPropertyEditor(TypeInfo(QWordBool), nil, '', TBoolPropertyEditor);
RegisterPropertyEditor(TypeInfo(IInterface), nil, '', TInterfacePropertyEditor);
RegisterPropertyEditor(TypeInfo(Variant), nil, '', TVariantPropertyEditor);
end;
procedure FinalPropEdits;
var
i: integer;
pm: PPropertyEditorMapperRec;
pc: PPropertyClassRec;
sec: PSelectionEditorClassRec;
begin
if PropertyEditorMapperList<>nil then begin
for i:=0 to PropertyEditorMapperList.Count-1 do begin
pm:=PPropertyEditorMapperRec(PropertyEditorMapperList.Items[i]);
Dispose(pm);
end;
FreeAndNil(PropertyEditorMapperList);
end;
if PropertyClassList<>nil then begin
for i:=0 to PropertyClassList.Count-1 do begin
pc:=PPropertyClassRec(PropertyClassList[i]);
Dispose(pc);
end;
FreeAndNil(PropertyClassList);
end;
if Assigned(SelectionEditorClassList) then begin
for i:=0 to SelectionEditorClassList.Count-1 do begin
sec:=PSelectionEditorClassRec(SelectionEditorClassList[i]);
Dispose(sec);
end;
FreeAndNil(SelectionEditorClassList);
end;
FreeAndNil(ListPropertyEditors);
FreeAndNil(VirtualKeyStrings);
end;
initialization
InitPropEdits;
finalization
FinalPropEdits;
end.