mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-05 10:57:55 +02:00
460 lines
14 KiB
ObjectPascal
460 lines
14 KiB
ObjectPascal
{
|
|
*****************************************************************************
|
|
See the file COPYING.modifiedLGPL.txt, included in this distribution,
|
|
for details about the license.
|
|
*****************************************************************************
|
|
|
|
Author: Mattias Gaertner
|
|
|
|
Abstract:
|
|
Extension for the Object Inspector.
|
|
- Favorites properties
|
|
}
|
|
unit ObjInspExt;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils,
|
|
// LCL
|
|
Forms, Controls, Buttons, StdCtrls, ExtCtrls, Dialogs, Menus, ComCtrls, Grids,
|
|
CustomTimer,
|
|
// LazUtils
|
|
LazFileUtils, LazConfigStorage, LazLoggerBase,
|
|
// CodeTools
|
|
CodeToolManager, CodeCache,
|
|
// BuildIntf
|
|
BaseIDEIntf, ProjectIntf,
|
|
// IdeIntf
|
|
IdeIntfStrConsts, LazIDEIntf, ObjectInspector, OIFavoriteProperties, PropEdits, IDEDialogs,
|
|
// IDE
|
|
DialogProcs, LazConf, LazarusIDEStrConsts;
|
|
|
|
type
|
|
{ TOIAddRemoveFavoriteDlg }
|
|
|
|
TOIAddRemoveFavoriteDlg = class(TForm)
|
|
NoteLabel: TLabel;
|
|
ClassCombobox: TComboBox;
|
|
OkButton: TButton;
|
|
CancelButton: TButton;
|
|
procedure OkButtonClick(Sender: TObject);
|
|
private
|
|
FAddMode: Boolean;
|
|
FObjectInspector: TObjectInspectorDlg;
|
|
FPropertyName: string;
|
|
procedure SetAddMode(const AValue: Boolean);
|
|
procedure SetObjectInspector(const AValue: TObjectInspectorDlg);
|
|
procedure UpdateLabel;
|
|
procedure UpdateComboBox;
|
|
procedure UpdateMode;
|
|
public
|
|
constructor Create(TheOwner: TComponent); override;
|
|
public
|
|
property ObjectInspector: TObjectInspectorDlg read FObjectInspector
|
|
write SetObjectInspector;
|
|
property PropertyName: string read FPropertyName;
|
|
property AddMode: Boolean read FAddMode write SetAddMode;
|
|
end;
|
|
|
|
const
|
|
DefaultOIFavoriteConfigFilename = 'objectinspectorfavorites.xml';
|
|
|
|
var
|
|
DefaultOIFavoriteProperties: TOIFavoriteProperties;
|
|
|
|
function ShowAddRemoveFavoriteDialog(ObjInspector: TObjectInspectorDlg;
|
|
Add: Boolean): TModalResult;
|
|
function CreateDefaultOIFavoriteProperties: TOIFavoriteProperties;
|
|
function LoadOIFavoriteProperties: TOIFavoriteProperties;
|
|
procedure SaveOIFavoriteProperties(Favorites: TOIFavoriteProperties);
|
|
function GetOIFavoriteConfigFilename: string;
|
|
|
|
function FindDeclarationOfOIProperty(AnInspector: TObjectInspectorDlg;
|
|
Row: TOIPropertyGridRow; out Code: TCodeBuffer; out Caret: TPoint;
|
|
out NewTopLine: integer): Boolean;
|
|
|
|
|
|
implementation
|
|
|
|
function CreateDefaultOIFavoriteProperties: TOIFavoriteProperties;
|
|
|
|
procedure Add(ABaseClass: TPersistentClass; const APropertyName: string);
|
|
begin
|
|
Result.Add(TOIFavoriteProperty.Create(ABaseClass,APropertyName,true));
|
|
end;
|
|
|
|
begin
|
|
Result:=TOIFavoriteProperties.Create;
|
|
// TControl
|
|
Add(TComponent,'Name');
|
|
Add(TComponent,'Caption');
|
|
Add(TControl,'Anchors');
|
|
Add(TControl,'AutoSize');
|
|
Add(TControl,'OnClick');
|
|
Add(TControl,'OnEditingDone');
|
|
// miscellaneous
|
|
Add(TCustomGroupBox,'Align');
|
|
Add(TCustomImage,'Align');
|
|
Add(TCustomButton,'ModalResult');
|
|
Add(TCustomLabel,'WordWrap');
|
|
Add(TCustomEdit,'Text');
|
|
Add(TCustomMemo,'Lines');
|
|
Add(TCustomMemo,'Align');
|
|
Add(TCustomMemo,'ScrollBars');
|
|
Add(TCustomCheckBox,'Checked');
|
|
Add(TCustomRadioGroup,'Items');
|
|
Add(TCustomRadioGroup,'ItemIndex');
|
|
Add(TCustomForm,'OnCreate');
|
|
Add(TCustomForm,'OnDestroy');
|
|
Add(TCustomForm,'OnResize');
|
|
Add(TCustomListBox,'Items');
|
|
Add(TCustomListBox,'Align');
|
|
Add(TCustomTreeView,'Align');
|
|
Add(TCustomTreeView,'Options');
|
|
Add(TCustomPanel,'Align');
|
|
Add(TMenuItem,'OnClick');
|
|
Add(TCustomSpeedButton,'GroupIndex');
|
|
Add(TCustomSpeedButton,'Glyph');
|
|
Add(TCustomImage,'Picture');
|
|
Add(TCustomImage,'Align');
|
|
Add(TCustomTabControl,'Align');
|
|
Add(TScrollBox,'Align');
|
|
Add(TCustomGrid,'Align');
|
|
Add(TCustomGrid,'Options');
|
|
Add(TCustomGrid,'Columns');
|
|
Add(TCustomGrid,'ColCount');
|
|
Add(TCustomTreeView,'Align');
|
|
Add(TCustomTreeView,'Options');
|
|
Add(TCustomTimer,'OnTimer');
|
|
Result.DeleteDoubles;
|
|
end;
|
|
|
|
function ShowAddRemoveFavoriteDialog(ObjInspector: TObjectInspectorDlg;
|
|
Add: Boolean): TModalResult;
|
|
var
|
|
OIAddRemoveFavoriteDlg: TOIAddRemoveFavoriteDlg;
|
|
begin
|
|
OIAddRemoveFavoriteDlg:=TOIAddRemoveFavoriteDlg.Create(nil);
|
|
OIAddRemoveFavoriteDlg.ObjectInspector:=ObjInspector;
|
|
OIAddRemoveFavoriteDlg.AddMode:=Add;
|
|
Result:=OIAddRemoveFavoriteDlg.ShowModal;
|
|
OIAddRemoveFavoriteDlg.Free;
|
|
end;
|
|
|
|
function LoadOIFavoriteProperties: TOIFavoriteProperties;
|
|
var
|
|
ConfigStore: TConfigStorage;
|
|
begin
|
|
Result:=DefaultOIFavoriteProperties.CreateCopy;
|
|
{$IFDEF DebugFavoriteroperties}
|
|
debugln('LoadOIFavoriteProperties A FileExistsUTF8(GetOIFavoriteConfigFilename)=',dbgs(FileExistsUTF8(GetOIFavoriteConfigFilename)));
|
|
Result.WriteDebugReport;
|
|
{$ENDIF}
|
|
if not FileExistsUTF8(GetOIFavoriteConfigFilename) then exit;
|
|
try
|
|
ConfigStore:=DefaultConfigClass.Create(GetOIFavoriteConfigFilename,true);
|
|
try
|
|
Result.MergeConfig(ConfigStore,'ObjectInspector/Favorites/');
|
|
Result.Modified:=false;
|
|
finally
|
|
ConfigStore.Free;
|
|
end;
|
|
except
|
|
on E: Exception do begin
|
|
debugln('Error: LoadOIFavoriteProperties: unable to read ',
|
|
GetOIFavoriteConfigFilename);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure SaveOIFavoriteProperties(Favorites: TOIFavoriteProperties);
|
|
var
|
|
ConfigStore: TConfigStorage;
|
|
DefaultFavorites: TOIFavoriteProperties;
|
|
begin
|
|
{$IFDEF DebugFavoriteroperties}
|
|
debugln('SaveOIFavoriteProperties Favorites.Modified=',dbgs(Favorites.Modified),
|
|
' FileExistsUTF8(GetOIFavoriteConfigFilename)=',dbgs(FileExistsUTF8(GetOIFavoriteConfigFilename)));
|
|
{$ENDIF}
|
|
if (not Favorites.Modified) and FileExistsUTF8(GetOIFavoriteConfigFilename)
|
|
then
|
|
exit;
|
|
DefaultFavorites:=CreateDefaulTOIFavoriteProperties;
|
|
try
|
|
if DefaultFavorites.IsEqual(Favorites) then exit;
|
|
{$IFDEF DebugFavoriteroperties}
|
|
debugln('SaveOIFavoriteProperties is not default');
|
|
DefaultFavorites.WriteDebugReport;
|
|
Favorites.WriteDebugReport;
|
|
{$ENDIF}
|
|
try
|
|
ConfigStore:=DefaultConfigClass.Create(GetOIFavoriteConfigFilename,false);
|
|
try
|
|
Favorites.SaveNewItemsToConfig(ConfigStore,'ObjectInspector/Favorites/',
|
|
DefaultFavorites);
|
|
ConfigStore.WriteToDisk;
|
|
Favorites.Modified:=false;
|
|
finally
|
|
ConfigStore.Free;
|
|
end;
|
|
except
|
|
on E: Exception do begin
|
|
debugln('Error: LoadOIFavoriteProperties: unable to write ',
|
|
GetOIFavoriteConfigFilename);
|
|
end;
|
|
end;
|
|
finally
|
|
DefaultFavorites.Free;
|
|
end;
|
|
end;
|
|
|
|
function GetOIFavoriteConfigFilename: string;
|
|
begin
|
|
Result:=AppendPathDelim(GetPrimaryConfigPath)+DefaultOIFavoriteConfigFilename;
|
|
end;
|
|
|
|
function FindDeclarationOfOIProperty(AnInspector: TObjectInspectorDlg;
|
|
Row: TOIPropertyGridRow; out Code: TCodeBuffer; out Caret: TPoint;
|
|
out NewTopLine: integer): Boolean;
|
|
var
|
|
PropPath: String;
|
|
LookupRoot: TPersistent;
|
|
AFile: TLazProjectFile;
|
|
NewCode: TCodeBuffer;
|
|
NewX, NewY: integer;
|
|
APersistent: TPersistent;
|
|
AnUnitName: String;
|
|
InFilename: String;
|
|
FilenameOfClass: string;
|
|
begin
|
|
Result:=false;
|
|
Code:=nil;
|
|
Caret:=Point(0,0);
|
|
// check Row
|
|
if AnInspector=nil then begin
|
|
DebugLn('FindDeclarationOfOIProperty AnInspector=nil');
|
|
exit;
|
|
end;
|
|
if Row=nil then
|
|
Row:=AnInspector.GetActivePropertyRow;
|
|
if Row=nil then begin
|
|
DebugLn('FindDeclarationOfOIProperty Row=nil');
|
|
exit;
|
|
end;
|
|
if Row.Editor=nil then begin
|
|
DebugLn('FindDeclarationOfOIProperty Row.Editor=nil Row=',Row.Name);
|
|
exit;
|
|
end;
|
|
// get first instance of property
|
|
APersistent:=Row.Editor.GetComponent(0);
|
|
if APersistent=nil then begin
|
|
DebugLn('FindDeclarationOfOIProperty APersistent=nil Row=',Row.Name);
|
|
exit;
|
|
end;
|
|
// get unit name of first instance
|
|
AnUnitName:=GetClassUnitName(APersistent.ClassType);
|
|
if AnUnitName='' then begin
|
|
DebugLn('FindDeclarationOfOIProperty no RTTI unit found for APersistent.ClassType=',DbgSName(APersistent.ClassType));
|
|
exit;
|
|
end;
|
|
// get lookup root
|
|
if Row.Editor.PropertyHook=nil then begin
|
|
debugln(['FindDeclarationOfOIProperty Row.Editor.PropertyHook=nil Row=',Row.Name]);
|
|
exit;
|
|
end;
|
|
LookupRoot:=Row.Editor.PropertyHook.LookupRoot;
|
|
if LookupRoot=nil then begin
|
|
debugln(['FindDeclarationOfOIProperty Row.Editor.PropertyHook.LookupRoot=nil Row=',Row.Name]);
|
|
exit;
|
|
end;
|
|
// get file of lookup root
|
|
AFile:=LazarusIDE.GetProjectFileWithRootComponent(TComponent(LookupRoot));
|
|
if AFile=nil then begin
|
|
DebugLn('FindDeclarationOfOIProperty AFile=nil Row=',Row.Name,' LookupRoot=',DbgSName(LookupRoot));
|
|
exit;
|
|
end;
|
|
|
|
InFilename:='';
|
|
FilenameOfClass:=CodeToolBoss.DirectoryCachePool.FindUnitSourceInCompletePath(
|
|
ExtractFilePath(AFile.Filename),AnUnitName,InFilename);
|
|
if FilenameOfClass='' then begin
|
|
debugln(['FindDeclarationOfOIProperty FindUnitSourceInCompletePath failed: Row=',Row.Name,' Instance=',DbgSName(APersistent),' LookupRoot=',DbgSName(LookupRoot),' Unit not found: ',AnUnitName,' started search in directory of lookuproot: ',AFile.Filename]);
|
|
exit;
|
|
end;
|
|
if not LazarusIDE.BeginCodeTools then begin
|
|
DebugLn('FindDeclarationOfOIProperty LazarusIDE.BeginCodeTools failed');
|
|
exit;
|
|
end;
|
|
Code:=nil;
|
|
if LoadCodeBuffer(Code,FilenameOfClass,[],false)<>mrOk then begin
|
|
debugln(['FindDeclarationOfOIProperty LoadCodeBuffer failed of ',FilenameOfClass]);
|
|
exit;
|
|
end;
|
|
// find the property declaration
|
|
PropPath:=APersistent.ClassName+'.'+Row.Name;
|
|
if Row.Editor is TNestedPropertyEditor then begin
|
|
if Row.Parent=nil then begin
|
|
debugln(['FindDeclarationOfOIProperty missing parent row ',PropPath,' in unit ',Code.Filename,' Row.Editor=',DbgSName(Row.Editor)]);
|
|
exit;
|
|
end;
|
|
PropPath:=APersistent.ClassName+'.'+Row.Parent.Name+'.'+Row.Name;
|
|
end;
|
|
if not CodeToolBoss.FindDeclarationOfPropertyPath(Code,PropPath,NewCode,
|
|
NewX,NewY,NewTopLine) then
|
|
begin
|
|
debugln(['FindDeclarationOfOIProperty failed to find property ',PropPath,' in unit ',Code.Filename]);
|
|
exit;
|
|
end;
|
|
Code:=NewCode;
|
|
Caret:=Point(NewX,NewY);
|
|
//DebugLn('FindDeclarationOfOIProperty SUCCESS ',Code.Filename,' ',dbgs(Caret));
|
|
Result:=true;
|
|
end;
|
|
|
|
{ TOIAddRemoveFavoriteDlg }
|
|
|
|
procedure TOIAddRemoveFavoriteDlg.OkButtonClick(Sender: TObject);
|
|
var
|
|
NewClassName: String;
|
|
CurClass: TClass;
|
|
NewFavorite: TOIFavoriteProperty;
|
|
begin
|
|
NewClassName:=ClassCombobox.Text;
|
|
if (ObjectInspector<>nil) and (ObjectInspector.Selection<>nil)
|
|
and (ObjectInspector.Selection.Count>0) then begin
|
|
CurClass:=ObjectInspector.Selection[0].ClassType;
|
|
while CurClass.InheritsFrom(TPersistent) do begin
|
|
if CompareText(NewClassName,CurClass.ClassName)=0 then begin
|
|
NewFavorite:=TOIFavoriteProperty.Create(TPersistentClass(CurClass),
|
|
PropertyName,AddMode);
|
|
ObjectInspector.Favorites.DeleteConstraints(NewFavorite);
|
|
ObjectInspector.Favorites.Add(NewFavorite);
|
|
ObjectInspector.FavoriteGrid.BuildPropertyList;
|
|
ModalResult:=mrOk;
|
|
exit;
|
|
end;
|
|
CurClass:=CurClass.ClassParent;
|
|
end;
|
|
end;
|
|
IDEMessageDialog(lisClassNotFound,
|
|
Format(lisOIFClassNotFound, [NewClassName]), mtError, [mbOk]);
|
|
end;
|
|
|
|
procedure TOIAddRemoveFavoriteDlg.SetObjectInspector(const AValue: TObjectInspectorDlg);
|
|
var
|
|
CurRow: TOIPropertyGridRow;
|
|
begin
|
|
if FObjectInspector=AValue then exit;
|
|
FObjectInspector:=AValue;
|
|
CurRow:=ObjectInspector.GetActivePropertyRow;
|
|
if (CurRow<>nil) and (CurRow.Editor<>nil) then
|
|
FPropertyName:=CurRow.Editor.GetName;
|
|
UpdateLabel;
|
|
UpdateComboBox;
|
|
end;
|
|
|
|
procedure TOIAddRemoveFavoriteDlg.SetAddMode(const AValue: Boolean);
|
|
begin
|
|
if FAddMode=AValue then exit;
|
|
FAddMode:=AValue;
|
|
UpdateMode;
|
|
end;
|
|
|
|
procedure TOIAddRemoveFavoriteDlg.UpdateLabel;
|
|
begin
|
|
NoteLabel.Caption:=Format(lisOIFChooseABaseClassForTheFavoriteProperty, [PropertyName]);
|
|
end;
|
|
|
|
procedure TOIAddRemoveFavoriteDlg.UpdateComboBox;
|
|
var
|
|
CurClass: TClass;
|
|
NewItems: TStringList;
|
|
begin
|
|
NewItems:=TStringList.Create;
|
|
if (ObjectInspector<>nil) and (ObjectInspector.Selection<>nil)
|
|
and (ObjectInspector.Selection.Count>0) then begin
|
|
CurClass:=ObjectInspector.Selection[0].ClassType;
|
|
// add only classes, that are TPersistent and have a registered class
|
|
while CurClass.InheritsFrom(TPersistent) do begin
|
|
// add only registered classes
|
|
if GetClass(CurClass.ClassName)<>nil then
|
|
NewItems.Add(CurClass.ClassName);
|
|
CurClass:=CurClass.ClassParent;
|
|
end;
|
|
end;
|
|
ClassCombobox.Items.Assign(NewItems);
|
|
if ClassCombobox.Items.Count>0 then
|
|
ClassCombobox.ItemIndex:=0;
|
|
NewItems.Free;
|
|
end;
|
|
|
|
procedure TOIAddRemoveFavoriteDlg.UpdateMode;
|
|
begin
|
|
if AddMode then begin
|
|
Caption:=lisOIFAddToFavoriteProperties;
|
|
OkButton.Caption:=lisAdd;
|
|
end else begin
|
|
Caption:=lisOIFRemoveFromFavoriteProperties;
|
|
OkButton.Caption:=lisRemove;
|
|
end;
|
|
end;
|
|
|
|
constructor TOIAddRemoveFavoriteDlg.Create(TheOwner: TComponent);
|
|
begin
|
|
inherited CreateNew(TheOwner);
|
|
|
|
Name:='OIAddToFavoriteDlg';
|
|
Width:=300;
|
|
Height:=150;
|
|
Position:=poScreenCenter;
|
|
|
|
NoteLabel:=TLabel.Create(Self);
|
|
with NoteLabel do begin
|
|
Name:='NoteLabel';
|
|
SetBounds(5,5,Self.ClientWidth-10,50);
|
|
WordWrap:=true;
|
|
Parent:=Self;
|
|
end;
|
|
|
|
ClassCombobox:=TComboBox.Create(Self);
|
|
with ClassCombobox do begin
|
|
Name:='ClassCombobox';
|
|
SetBounds(5,60,200,Height);
|
|
Parent:=Self;
|
|
end;
|
|
|
|
OkButton:=TButton.Create(Self);
|
|
with OkButton do begin
|
|
Name:='AddButton';
|
|
SetBounds(5,100,80,25);
|
|
Caption:=lisAdd;
|
|
Parent:=Self;
|
|
OnClick:=@OkButtonClick;
|
|
end;
|
|
DefaultControl:=OkButton;
|
|
|
|
CancelButton:=TButton.Create(Self);
|
|
with CancelButton do begin
|
|
Name:='CancelButton';
|
|
SetBounds(120,100,80,25);
|
|
Caption:=lisCancel;
|
|
Parent:=Self;
|
|
ModalResult:=mrCancel;
|
|
end;
|
|
CancelControl:=CancelButton;
|
|
|
|
UpdateMode;
|
|
end;
|
|
|
|
initialization
|
|
DefaultOIFavoriteProperties:=CreateDefaultOIFavoriteProperties;
|
|
|
|
finalization
|
|
FreeAndNil(DefaultOIFavoriteProperties)
|
|
|
|
end.
|
|
|