Recent

Author Topic: Object Inspector - code  (Read 3281 times)

J-23

  • Full Member
  • ***
  • Posts: 108
Object Inspector - code
« on: April 06, 2020, 09:47:49 pm »
Builds my own: Inspector Object with additions from scratch. I need to connect to the editors stitched in the components and I started analyzing the default Inspector Object (included in Lazarus). After my observations there are a few unused property there (I think it is a residue from previous versions) as an example I will give such properties as:

Code: Pascal  [Select][+][-]
  1.    property Favorites: TOIFavoriteProperties read FFavorites write SetFavorites;    
  2.    property PropNameFilter : String read FPropNameFilter write FPropNameFilter;      
  3.  

These are the properties of the TOICustomPropertyGrid class located in the "ObjectInspector.pp" file line 267 in the Lazarus directory

I still have doubts about the procedure:

Code: Pascal  [Select][+][-]
  1. @AddPropertyEditor
  2.  

which is used by:
  GetPersistentProperties (FSelection, FFilter + [tkClass], FPropertyEditorHook,
       @AddPropertyEditor, @EditorFilter);

Code: Pascal  [Select][+][-]
  1. procedure TOICustomPropertyGrid.AddPropertyEditor(PropEditor: TPropertyEditor);
  2. var
  3.   NewRow: TOIPropertyGridRow;
  4.   WidgetSets: TLCLPlatforms;
  5. begin
  6.   WidgetSets := [];
  7.   if Favorites<>nil then begin
  8.     //debugln('TOICustomPropertyGrid.AddPropertyEditor A ',PropEditor.GetName);
  9.     if Favorites is TOIRestrictedProperties then
  10.     begin
  11.       WidgetSets := (Favorites as TOIRestrictedProperties).AreRestricted(
  12.                                                   Selection,PropEditor.GetName);
  13.       if WidgetSets = [] then
  14.       begin
  15.         PropEditor.Free;
  16.         Exit;
  17.       end;
  18.     end
  19.     else
  20.       if not Favorites.AreFavorites(Selection,PropEditor.GetName) then begin
  21.         PropEditor.Free;
  22.         exit;
  23.       end;
  24.   end;
  25.   if PropEditor is TClassPropertyEditor then
  26.   begin
  27.     (PropEditor as TClassPropertyEditor).SubPropsNameFilter := PropNameFilter;
  28.     (PropEditor as TClassPropertyEditor).SubPropsTypeFilter := FFilter;
  29.     (PropEditor as TClassPropertyEditor).HideClassName:=FHideClassNames;
  30.   end;
  31.   NewRow := TOIPropertyGridRow.Create(Self, PropEditor, nil, WidgetSets);
  32.   FRows.Add(NewRow);
  33.   if FRows.Count>1 then begin
  34.     NewRow.FPriorBrother:=Rows[FRows.Count-2];
  35.     NewRow.FPriorBrother.FNextBrother:=NewRow;
  36.   end;
  37. end;
  38.  

Condition:
Code: Pascal  [Select][+][-]
  1. if Favorites<>nil then begin
  2.  

It will never be made because the Favorites property has not been used anywhere (I think)

Now the question is, am I right that these are the remains of the previous code?

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4459
  • I like bugs.
Re: Object Inspector - code
« Reply #1 on: April 06, 2020, 11:23:47 pm »
Builds my own: Inspector Object with additions from scratch. I need to connect to the editors stitched in the components and I started analyzing the default Inspector Object (included in Lazarus).
You can also use Object Inspector directly from its IdeIntf package. Possible bugs can be fixed and missing features added if needed.

Quote
Condition:
Code: Pascal  [Select][+][-]
  1. if Favorites<>nil then begin
It will never be made because the Favorites property has not been used anywhere (I think)
It is used for the "Favorites" and "Restricted" tabs in Object Inspector. You can debug the code by placing DebugLn() calls there, building Lazarus and then looking at the log output. For example uncomment the debugln already in AddPropertyEditor and see how it produces tons of output.
The test "Favorites is TOIRestrictedProperties" looks strange first but it inherits like this:
Code: Pascal  [Select][+][-]
  1. TOIRestrictedProperties = class(TOIFavoriteProperties)

PropNameFilter is used for the user's manual filtering by PropFilterEdit. It is set in procedure TObjectInspectorDlg.PropFilterEditAfterFilter.
Code: Pascal  [Select][+][-]
  1. GetActivePropertyGrid.PropNameFilter := PropFilterEdit.Filter;
You can find the assignment with "Find" or "Find in Files" easily.
Hint: "Find in Files" also has a "search in active file" option. Handy in some cases.
« Last Edit: April 06, 2020, 11:35:30 pm by JuhaManninen »
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

J-23

  • Full Member
  • ***
  • Posts: 108
Re: Object Inspector - code
« Reply #2 on: April 07, 2020, 02:26:19 pm »
Builds my own: Inspector Object with additions from scratch. I need to connect to the editors stitched in the components and I started analyzing the default Inspector Object (included in Lazarus).
You can also use Object Inspector directly from its IdeIntf package. Possible bugs can be fixed and missing features added if needed.

Quote
Condition:
Code: Pascal  [Select][+][-]
  1. if Favorites<>nil then begin
It will never be made because the Favorites property has not been used anywhere (I think)
It is used for the "Favorites" and "Restricted" tabs in Object Inspector. You can debug the code by placing DebugLn() calls there, building Lazarus and then looking at the log output. For example uncomment the debugln already in AddPropertyEditor and see how it produces tons of output.
The test "Favorites is TOIRestrictedProperties" looks strange first but it inherits like this:
Code: Pascal  [Select][+][-]
  1. TOIRestrictedProperties = class(TOIFavoriteProperties)

PropNameFilter is used for the user's manual filtering by PropFilterEdit. It is set in procedure TObjectInspectorDlg.PropFilterEditAfterFilter.
Code: Pascal  [Select][+][-]
  1. GetActivePropertyGrid.PropNameFilter := PropFilterEdit.Filter;
You can find the assignment with "Find" or "Find in Files" easily.
Hint: "Find in Files" also has a "search in active file" option. Handy in some cases.

Hello, thanks for the clarification regarding my ownership.

J-23

  • Full Member
  • ***
  • Posts: 108
Re: Object Inspector - code - PropertyEditorHook
« Reply #3 on: June 13, 2020, 09:20:59 pm »
Hello,
I want to use TCustomPropertiesGrid in my program - it is an object inspector.

The properties of the object are displayed by:
Code: Pascal  [Select][+][-]
  1. CustomPropertiesGrid.TIObject := Image1;      
  2.  


Unless it displays simple properties so there is no access to Editors - built into the component could anyone describe how to do that to access the component editors.

I guess you have to use:
Code: Pascal  [Select][+][-]
  1. PropertyEditorHook
  2.  
I just have no idea how.

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4459
  • I like bugs.
Re: Object Inspector - code
« Reply #4 on: June 15, 2020, 03:57:28 pm »
J-23, for now you must study the code of Object Inspector, Lazarus IDE and registration of component editors by yourself.
All the code is available. Use Find-in-files and bookmarks, jump to definitions, debug etc.
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

J-23

  • Full Member
  • ***
  • Posts: 108
Re: Object Inspector - code
« Reply #5 on: June 27, 2020, 10:07:24 pm »
Hi,

I'm trying to get objects to be displayed in Runtime using TOICustomPropertyGrid. However, he displays the properties without editors and I also want to have access to editors. I started analyzing Lazarus sources and this led to me:

Code: Pascal  [Select][+][-]
  1. function IsInteresting(AEditor: TPropertyEditor; const AFilter: TTypeKinds;
  2.   const APropNameFilter: String): Boolean;
  3.  
  4. var
  5.   visited: TFPList;
  6.   UpperPropName: String;
  7.  
  8.   // check set element names against AFilter
  9.   function IsPropInSet( const ATypeInfo: PTypeInfo ) : Boolean;
  10.   var
  11.     TypeInfo: PTypeInfo;
  12.     TypeData: PTypeData;
  13.     i: Integer;
  14.   begin
  15.     Result := False;
  16.     TypeInfo := ATypeInfo;
  17.  
  18.     if (TypeInfo^.Kind <> tkSet) then exit;
  19.  
  20.     TypeData := GetTypeData(TypeInfo);
  21.     // Get TypeInfo of set type.
  22.     TypeInfo := TypeData^.CompType;
  23.     TypeData := GetTypeData(TypeInfo);
  24.  
  25.     for i:= TypeData^.MinValue to TypeData^.MaxValue do
  26.     begin
  27.       Result := ContainsTextUpper( GetEnumName(TypeInfo, i), UpperPropName );
  28.       if Result then
  29.         Break;
  30.     end;
  31.   end;
  32.  
  33.   //check if class has property name
  34.   function IsPropInClass( const ATypeInfo: PTypeInfo ) : Boolean;
  35.   var
  36.     propInfo: PPropInfo;
  37.     propList: PPropList;
  38.     i, propCount: Integer;
  39.     quSubclass: TFPList;
  40.     icurClass: Integer = 0;
  41.   begin
  42.     Result := False;
  43.     quSubclass := TFPList.Create;
  44.     quSubclass.Add(ATypeInfo);
  45.  
  46.     while icurClass < quSubclass.Count do
  47.     begin
  48.       propCount := GetPropList(quSubclass.Items[icurClass], propList);
  49.  
  50.       for i := 0 to propCount - 1 do
  51.       begin
  52.         propInfo := propList^[i];
  53.  
  54.         Result := ContainsTextUpper(propInfo^.Name, UpperPropName);
  55.         if Result then break;
  56.         //if encounter a Set check its elements name.
  57.         if (propInfo^.PropType^.Kind = tkSet) then
  58.         begin
  59.           Result := IsPropInSet(propInfo^.PropType);
  60.           if Result then break;
  61.         end;
  62.         //queue subclasses(only once) to check later.
  63.         if (propInfo^.PropType^.Kind = tkClass) then
  64.           if quSubclass.IndexOf(propInfo^.PropType) >= 0 then Continue
  65.           else  quSubclass.Add(propInfo^.PropType);
  66.       end;
  67.       if Assigned(propList) then FreeMem(propList);
  68.       //no need to check subclasses if result is already true.
  69.       if Result then break;
  70.       inc(icurClass);
  71.     end;
  72.     quSubclass.Free;
  73.   end;
  74.  
  75.   // Add AForceShow to display T****PropertyEditor when subproperties found.
  76.   // and name of class is not the same as filter
  77.   procedure Rec(A: TPropertyEditor; AForceShow: Boolean = False);
  78.   var
  79.     propList: PPropList;
  80.     i: Integer;
  81.     ti: PTypeInfo;
  82.     edClass: TPropertyEditorClass;
  83.     ed: TPropertyEditor;
  84.     obj: TPersistent;
  85.     PropCnt: LongInt;
  86.   begin
  87.     ti := A.GetPropInfo^.PropType;
  88.     //DebugLn('IsInteresting: ', ti^.Name);
  89.     Result := ti^.Kind <> tkClass;
  90.     if Result then
  91.     begin
  92.       if (UpperPropName = '') or AForceShow then
  93.         exit;
  94.       // Check if check Set has element.
  95.       if (ti^.Kind = tkSet) and (A.ClassType <> TSetElementPropertyEditor) then
  96.       begin
  97.         Result := ContainsTextUpper(A.GetName, UpperPropName)
  98.                      or IsPropInSet(A.GetPropType);
  99.         exit;
  100.       end;
  101.       // Check single Props
  102.       Result := ContainsTextUpper(A.GetName, UpperPropName);
  103.       exit;
  104.     end;
  105.  
  106.     // Subroperties can change if user selects another object =>
  107.     // we must show the property, even if it is not interesting currently.
  108.     Result := paVolatileSubProperties in A.GetAttributes;
  109.     if Result then exit;
  110.  
  111.     if tkClass in AFilter then
  112.     begin
  113.       // We want classes => any non-trivial editor is immediately interesting.
  114.       Result := A.ClassType <> TClassPropertyEditor;
  115.       if Result then
  116.       begin
  117.         // if no SubProperties check against filter name
  118.         if (UpperPropName <> '') then
  119.           if (paSubProperties in A.GetAttributes) then
  120.             Result := ContainsTextUpper(A.GetName, UpperPropName)
  121.                        or IsPropInClass(A.GetPropType)
  122.           else
  123.             Result := ContainsTextUpper(A.GetName, UpperPropName);
  124.  
  125.         exit;
  126.       end;
  127.     end
  128.     else if A.GetAttributes * [paSubProperties, paVolatileSubProperties] = [] then
  129.       exit;
  130.  
  131.     obj := TPersistent(A.GetObjectValue);
  132.     // At this stage, there is nothing interesting left in empty objects.
  133.     if obj = nil then exit;
  134.  
  135.     // Class properties may directly or indirectly refer to the same class,
  136.     // so we must avoid infinite recursion.
  137.     if visited.IndexOf(ti) >= 0 then exit;
  138.     visited.Add(ti);
  139.     // actual published properties can be different since the instance can be inherited
  140.     // so update type info from the instance
  141.     ti := obj.ClassInfo;
  142.     PropCnt := GetPropList(ti, propList);
  143.     try
  144.       for i := 0 to PropCnt - 1 do begin
  145.         if not (propList^[i]^.PropType^.Kind in AFilter + [tkClass]) then continue;
  146.         edClass := GetEditorClass(propList^[i], obj);
  147.         if edClass = nil then continue;
  148.         ed := edClass.Create(AEditor.FPropertyHook, 1);
  149.         try
  150.           ed.SetPropEntry(0, obj, propList^[i]);
  151.           ed.Initialize;
  152.           // filter TClassPropertyEditor name recursively
  153.           Rec(ed, ContainsTextUpper(A.GetName, UpperPropName) );
  154.         finally
  155.           ed.Free;
  156.         end;
  157.         if Result then break;
  158.       end;
  159.     finally
  160.       FreeMem(propList);
  161.     end;
  162.     visited.Delete(visited.Count - 1);
  163.   end;
  164.  
  165. begin
  166.   visited := TFPList.Create;
  167.   try
  168.     UpperPropName := Uppercase(APropNameFilter);
  169.     //DebugLn('IsInteresting -> ', AEditor.GetPropInfo^.Name, ': ', AEditor.GetPropInfo^.PropType^.Name);
  170.     Rec(AEditor);
  171.     //DebugLn('IsInteresting <- ', BoolToStr(Result, true));
  172.   finally
  173.     visited.Free;
  174.   end;
  175. end;

The code has information like this: " // Subroperties can change if user selects another object =>
    // we must show the property, even if it is not interesting currently."

it can be found in the above code
up to this point I know what's going on here is the condition below:
Code: Pascal  [Select][+][-]
  1. Result := paVolatileSubProperties in A.GetAttributes;
  2.     if Result then exit;
which IDE editor performs to false - so that editors are available

I have this condition finished on True, hence there are no editors, however, when debugging, I cannot find at which moment I change that the condition is false

In PropEdit there is information: paVolatileSubProperties: Any change of property value causes any shown
                         subproperties to be recollected.
But she doesn't lead me to the solution.


 

TinyPortal © 2005-2018