{ This file is part of the Free Component Library. Copyright (c) 2017 Michael Van Canneyt, member of the Free Pascal development team Frame to display the object inspector. See the file COPYING.FPC, included in this distribution, for details about the copyright. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} unit fraReportObjectInspector; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, RTTIGrids, Forms, Controls, ComCtrls, ExtCtrls, StdCtrls, fpreport, fpreportdesignobjectlist; type { TObjectInspectorFrame } TSelectElementEvent = Procedure (Sender : TObject; Selected : TComponent) of Object; TObjectInspectorFrame = class(TFrame) ILTree: TImageList; LPropertyGrid: TLabel; Panel1: TPanel; Panel2: TPanel; PGReport: TTIPropertyGrid; Splitter1: TSplitter; TVReport: TTreeView; procedure PGReportModified(Sender: TObject); procedure TVReportSelectionChanged(Sender: TObject); private FISC: Boolean; FList: TReportObjectList; FOnModified: TNotifyEvent; FOnSelectElement: TSelectElementEvent; FReport: TFPReport; procedure AddElementChildren(AParentNode: TTreeNode; AParent: TFPReportElementWithChildren); function AddElementNode(AIndex: Integer; AParentNode: TTreeNode; AElement: TFPReportElement): TTreeNode; function GetNodeNameForElement(E: TComponent): String; function GetSRT: Boolean; procedure SetNodeProps(N: TTreeNode; E: TComponent); procedure SetReport(AValue: TFPReport); procedure SetSRT(AValue: Boolean); procedure UpdateReportTree; Protected Property IgnoreSelectionChange : Boolean Read FISC Write FISC; public Procedure UpdateSelection; procedure RefreshReportTree; Procedure RefreshOI; Procedure SelectControls(AList : TReportObjectList); Property Objectlist : TReportObjectList Read FList; Property ShowReportTree : Boolean Read GetSRT Write SetSRT; Property Report : TFPReport Read FReport Write SetReport; Property OnSelectElement : TSelectElementEvent Read FOnSelectElement Write FOnSelectElement; Property OnModified : TNotifyEvent Read FOnModified Write FOnModified; end; implementation uses propeditutils; {$R *.lfm} Const iiReport = 0; iiPage = 1; iiband = 2; iiElement = 3; Resourcestring SPage = 'Page %d'; SReport = 'Report'; SNoNameBand = '%d: Unnamed band %s'; SNoNameElement = '%d: Unnamed element %s'; SPGCaption = 'Properties of %s'; Smultiple = 'multiple (%d) elements'; SNoSelection = 'No selection'; { TObjectInspectorFrame } function TObjectInspectorFrame.GetSRT: Boolean; begin Result:=TVReport.Visible; end; function TObjectInspectorFrame.GetNodeNameForElement(E: TComponent): String; begin Result:=E.Name; if (Result<>'') then exit; if e is TFPCustomReport then Result:=SReport else if E is TFPReportCustomPage then Result:=Format(SPage,[(E as TFPReportCustomPage).PageIndex+1]) else if E is TFPReportCustomBand then Result:=Format(SNoNameBand,[E.ComponentIndex,E.ClassName]) else Result:=Format(SNoNameElement,[E.ComponentIndex,E.ClassName]) end; procedure TObjectInspectorFrame.SetNodeProps(N : TTreeNode; E : TComponent); begin if e is TFPCustomReport then N.ImageIndex:=iiReport else if E is TFPReportCustomPage then N.ImageIndex:=iiPage else if E is TFPReportCustomBand then N.ImageIndex:=iiBand else N.ImageIndex:=iiElement; N.Text:=GetNodeNameForElement(E); N.SelectedIndex:=N.ImageIndex; N.Data:=E; end; function TObjectInspectorFrame.AddElementNode(AIndex: Integer; AParentNode: TTreeNode; AElement: TFPReportElement): TTreeNode; Var N : TTreeNode; begin N:=TVReport.Items.AddChild(AParentNode,''); SetNodeProps(N,AElement); if AElement is TFPReportElementWithChildren then AddElementChildren(N,AElement as TFPReportElementWithChildren); Result:=N; end; procedure TObjectInspectorFrame.TVReportSelectionChanged(Sender: TObject); Var N : TTreeNode; C : TComponent; begin if IgnoreSelectionChange then exit; N:=TVReport.Selected; if Assigned(N) then C:=TComponent(N.Data) else C:=Nil; if Assigned(OnSelectElement) then OnSelectElement(Self,C); end; procedure TObjectInspectorFrame.UpdateReportTree; Var I: Integer; E : TFPReportElement; N : TTreeNode; begin For I:=0 to ObjectList.Count-1 do begin E:=ObjectList[i].Element; N:=TVReport.Items.FindNodeWithData(E); if Assigned(N) then N.Text:=GetNodeNameForElement(E); end; end; procedure TObjectInspectorFrame.PGReportModified(Sender: TObject); begin UpdateReportTree; If Assigned(FOnModified) then FOnModified(Self); end; procedure TObjectInspectorFrame.AddElementChildren(AParentNode : TTreeNode; AParent : TFPReportElementWithChildren); Var I : Integer; begin For I:=0 to AParent.ChildCount-1 do AddElementNode(I,AparentNode,AParent.Child[i]); end; procedure TObjectInspectorFrame.RefreshReportTree; Var PN,N : TTreeNode; S : String; I : Integer; begin With TVReport.Items do try IgnoreSelectionChange:=True; BeginUpdate; Clear; if Not Assigned(FReport) then exit; PN:=AddChild(Nil,'Report'); SetNodeProps(PN,FReport); For I:=0 to FReport.PageCount-1 do begin S:=Format(SPage,[I+1]); if (FReport.Pages[i].Name<>'') then S:=S+': '+FReport.Pages[i].Name; N:=AddChild(PN,S); SetNodeProps(N,FReport.Pages[i]); AddElementChildren(N,FReport.Pages[i]); end; PN.Expand(True); finally EndUpdate; IgnoreSelectionChange:=False; end; end; procedure TObjectInspectorFrame.RefreshOI; begin PGReport.RefreshPropertyValues; end; procedure TObjectInspectorFrame.SetReport(AValue: TFPReport); begin if FReport=AValue then Exit; FReport:=AValue; if ShowReportTree then RefreshReportTree; end; procedure TObjectInspectorFrame.SetSRT(AValue: Boolean); begin if AValue=GetSRT then exit; TVReport.Visible:=AValue; if AValue then RefreshReportTree; end; procedure TObjectInspectorFrame.UpdateSelection; Var I : integer; L : TPersistentSelectionList; S : String; begin // Update grid L:=TPersistentSelectionList.Create; try L.BeginUpdate; try if Assigned(ObjectList) then For I:=0 to ObjectList.Count-1 do if ObjectList[i].Selected then L.Add(ObjectList[i].Element); if (L.Count=0) and Assigned(FReport) then L.Add(FReport); PGReport.Selection:=L; finally L.EndUpdate; end; // Update tree, select first element if L.Count>0 then begin IgnoreSelectionChange:=True; try TVReport.Selected:=TVReport.Items.FindNodeWithData(L.Items[0]); finally IgnoreSelectionChange:=False; end; end; // Update caption if L.Count>1 then S:=Format(SPGCaption,[Format(Smultiple,[L.Count])]) else if L.Count=1 then S:=Format(SPGCaption,[GetNodeNameForElement(TComponent(L.Items[0]))]) else S:=SNoSelection; LPropertyGrid.Caption:=S; Finally L.Free; end; end; procedure TObjectInspectorFrame.SelectControls(AList: TReportObjectList); begin FList:=AList; UpdateSelection; end; end.