{****************************************************************** JEDI-VCL Demo Copyright (C) 2002 Project JEDI Original author: Contributor(s): You may retrieve the latest version of this file at the JEDI-JVCL home page, located at http://jvcl.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1_1Final.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. ******************************************************************} unit DependencyWalkerDemoMainForm; {$I jvcl.inc} interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, JvDiagramShape, Dialogs, ComCtrls, Menus, ImgList, StdCtrls, ExtCtrls, ActnList, PersistSettings, DepWalkConsts, ToolWin, Buttons, PersistForm; type (* // (p3) interposer class for TListBox that implements IPersistSettings (for the skiplist) TListBox = class(StdCtrls.TListBox, IUnknown, IPersistSettings) private {IPersistSettings} procedure Load(Storage: TCustomIniFile); procedure Save(Storage: TCustomIniFile); end; *) TDependencyWalkerDemoMainFrm = class(TfrmPersistable) StatusBar1: TStatusBar; mmMain: TMainMenu; File1: TMenuItem; SelectFiles1: TMenuItem; N1: TMenuItem; Exit1: TMenuItem; Help1: TMenuItem; About1: TMenuItem; dlgSelectFiles: TOpenDialog; il32: TImageList; New1: TMenuItem; vertSplitter: TSplitter; pnlDiagram: TPanel; pnlSkipList: TPanel; lbSkipList: TListBox; pnlDiagramTitle: TPanel; pnlSkipListTitle: TPanel; popSkipList: TPopupMenu; Add1: TMenuItem; Delete1: TMenuItem; Edit1: TMenuItem; mnuSort: TMenuItem; N2: TMenuItem; Skiplist1: TMenuItem; Add2: TMenuItem; Delete2: TMenuItem; alMain: TActionList; acOpen: TAction; acExit: TAction; acSortName: TAction; acSortLinksTo: TAction; acSortLinksFrom: TAction; acInvertSort: TAction; acAdd: TAction; acDelete: TAction; acNew: TAction; acAbout: TAction; byName1: TMenuItem; byLinksTo1: TMenuItem; LinksFrom1: TMenuItem; N3: TMenuItem; InvertSort1: TMenuItem; popShape: TPopupMenu; acUnitStats: TAction; Statistics1: TMenuItem; Delete3: TMenuItem; N4: TMenuItem; acDelShape: TAction; acReport: TAction; Print1: TMenuItem; acFind: TAction; Find1: TMenuItem; cbToolbar: TCoolBar; tbStandard: TToolBar; tbSelectFiles: TToolButton; tbNew: TToolButton; ToolButton3: TToolButton; tbAddSkip: TToolButton; tbDelSkip: TToolButton; Actions: TImageList; tbReport: TToolButton; ToolButton7: TToolButton; tbFind: TToolButton; tbUnitStats: TToolButton; tbAbout: TToolButton; ToolButton11: TToolButton; tbDelShape: TToolButton; ToolButton13: TToolButton; acAddToSkipList: TAction; Addtoskiplist1: TMenuItem; View1: TMenuItem; acViewStatusBar: TAction; acViewSkipList: TAction; SpeedButton1: TSpeedButton; StatusBar2: TMenuItem; Skiplist2: TMenuItem; acViewToolBar: TAction; Toolbar1: TMenuItem; N6: TMenuItem; acRefresh: TAction; sb: TScrollBox; acSaveBMP: TAction; acCopy: TAction; popDiagram: TPopupMenu; CopyDiagramtoClipboard1: TMenuItem; CopyDiagramtoClipboard2: TMenuItem; N5: TMenuItem; SaveImage1: TMenuItem; N7: TMenuItem; dlgSaveImage: TSaveDialog; ToolButton1: TToolButton; ToolButton2: TToolButton; acSaveDiagram: TAction; acOpenDiagram: TAction; acParseUnit: TAction; Parseunit1: TMenuItem; N8: TMenuItem; acOptions: TAction; Options1: TMenuItem; N10: TMenuItem; Shapes1: TMenuItem; Addtoskiplist2: TMenuItem; Statistics2: TMenuItem; Delete4: TMenuItem; ParseUnit2: TMenuItem; N9: TMenuItem; N11: TMenuItem; acUnitView: TAction; ViewSource1: TMenuItem; ViewSource2: TMenuItem; acSortIntfImpl: TAction; byINterfaceImplementation1: TMenuItem; pnlStats: TPanel; Panel2: TPanel; SpeedButton2: TSpeedButton; horzSplitter: TSplitter; reStatistics: TRichEdit; acViewDetails: TAction; Statistics3: TMenuItem; acNoSort: TAction; none1: TMenuItem; procedure FormCreate(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure sbMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); procedure acOpenExecute(Sender: TObject); procedure acExitExecute(Sender: TObject); procedure acArrangeAction(Sender: TObject); procedure acInvertSortExecute(Sender: TObject); procedure acAddExecute(Sender: TObject); procedure acDeleteExecute(Sender: TObject); procedure acAboutExecute(Sender: TObject); procedure acNewExecute(Sender: TObject); procedure alMainUpdate(Action: TBasicAction; var Handled: Boolean); procedure acUnitStatsExecute(Sender: TObject); procedure acDelShapeExecute(Sender: TObject); procedure acReportExecute(Sender: TObject); procedure acFindExecute(Sender: TObject); procedure acAddToSkipListExecute(Sender: TObject); procedure acViewStatusBarExecute(Sender: TObject); procedure acViewSkipListExecute(Sender: TObject); procedure acViewToolBarExecute(Sender: TObject); procedure acRefreshExecute(Sender: TObject); procedure acSaveBMPExecute(Sender: TObject); procedure acCopyExecute(Sender: TObject); procedure acSaveDiagramExecute(Sender: TObject); procedure acOpenDiagramExecute(Sender: TObject); procedure sbMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure sbMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure sbMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure acParseUnitExecute(Sender: TObject); procedure acOptionsExecute(Sender: TObject); procedure acUnitViewExecute(Sender: TObject); procedure sbExit(Sender: TObject); procedure acViewDetailsExecute(Sender: TObject); procedure acNoSortExecute(Sender: TObject); private { Private declarations } FFocusRectAnchor: TPoint; FFocusRect: TRect; FDrawing: boolean; FPrintFormat: TPrintFormat; FFileShapes, FLoadedFiles, FSearchPaths: TStringlist; FInitialDir: string; FLeft, FTop: integer; FOffsetX, FOffsetY: integer; FReload: boolean; FIntfLineColor, FImplLineColor, FIntfSelColor, FImplSelColor: TColor; function GetPersistStorage: TPersistStorage; procedure LoadSettings; procedure SaveSettings; function FindUnit(const Filename: string; const DefaultExt: string = '.pas'): string; procedure GetSearchPaths; procedure Clear(ClearAll: boolean); procedure CreatePrintOut(Strings: TStrings; AFormat: TPrintFormat = pfText); function GetFileShape(const Filename: string; var IsNew: boolean): TJvBitmapShape; procedure ParseUnits(Files, Errors: TStrings); procedure ParseUnit(const Filename: string; Errors: TStrings); function GetUses(const Filename: string; AUsesIntf, AUsesImpl: TStrings; var ErrorMessage: string): boolean; procedure Connect(StartShape, EndShape: TJvCustomDiagramShape; IsInterface: boolean); procedure LoadSkipList; procedure SaveSkipList; function InSkipList(const Filename: string): boolean; procedure Arrange(AList: TList); procedure DoShapeClick(Sender: TObject); procedure DoShapeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure SortItems(ATag: integer; AList: TList; InvertedSort: boolean); procedure CreateDiagramBitmap(Bmp: TBitmap); procedure HighlightConnectors(AShape: TJvCustomDiagramShape); procedure DoBeginFocusRect(Sender: TObject; ARect: TRect; Button: TMouseButton; Shift: TShiftState; var Allow: boolean); procedure DoEndFocusRect(Sender: TObject; ARect: TRect; Button: TMouseButton; Shift: TShiftState); procedure DoFocusingRect(Sender: TObject; ARect: TRect; Shift: TShiftState; var Continue: boolean); procedure SetSelected(const Value: TJvCustomDiagramShape); procedure ShowInlineStats(AShape: TJvCustomDiagramShape); function GetSelected: TJvCustomDiagramShape; protected procedure Load(Storage: TPersistStorage); override; procedure Save(Storage: TPersistStorage); override; public { Public declarations } property Selected: TJvCustomDiagramShape read GetSelected write SetSelected; end; var DependencyWalkerDemoMainFrm: TDependencyWalkerDemoMainFrm; implementation uses JCLParseUses, DepWalkUtils, Clipbrd, IniFiles, StatsFrm, ShellAPI, PrintFrm, Registry, {$IFNDEF COMPILER6_UP} JvJCLUTils, JvJVCLUtils, {$ENDIF} OptionsFrm; {$R *.dfm} (* { TListBox } procedure TListBox.Load(Storage: TCustomIniFile); begin Exit; if Storage.SectionExists(Name) then begin Sorted := false; Storage.ReadSection(Name, Items); Sorted := true; end; end; procedure TListBox.Save(Storage: TCustomIniFile); var i: integer; begin Exit; Storage.EraseSection(Name); for i := 0 to Items.Count - 1 do Storage.WriteString(Name, Items[i], ''); end; *) // utility functions // (p3) copy Strings.Objects to TList procedure CopyObjects(Strings: TStrings; AList: TList); var i: integer; begin for i := 0 to Strings.Count - 1 do AList.Add(Strings.Objects[i]); end; // (p3) returns the number of links that are connected to AShape function GetNumLinksTo(AShape: TJvCustomDiagramShape): integer; var i: integer; begin Result := 0; for i := 0 to AShape.Parent.ControlCount - 1 do if (AShape.Parent.Controls[i] is TJvConnector) and (TJvConnector(AShape.Parent.Controls[i]).EndConn.Shape = AShape) then Inc(Result); end; // (p3) returns the number of links that are connected from AShape function GetNumLinksFrom(AShape: TJvCustomDiagramShape): integer; var i: integer; begin Result := 0; for i := 0 to AShape.Parent.ControlCount - 1 do if (AShape.Parent.Controls[i] is TJvConnector) and (TJvConnector(AShape.Parent.Controls[i]).StartConn.Shape = AShape) then Inc(Result); end; // (p3) retrievs the shapes that AShape is connected to and store their name and pointers in Strings procedure UsesUnits(AShape: TJvCustomDiagramShape; Strings: TStrings; const Ext: string = cPascalExt); var i: integer; begin Strings.Clear; for i := 0 to AShape.Parent.ControlCount - 1 do if (AShape.Parent.Controls[i] is TJvConnector) and (TJvConnector(AShape.Parent.Controls[i]).StartConn.Shape = AShape) then with TJvConnector(AShape.Parent.Controls[i]).EndConn do Strings.AddObject(ChangeFileExt(Shape.Caption.Text, Ext), Shape); end; // (p3) retrieves the shapes that connects to AShape and store their name and pointers in Strings procedure UsedByUnits(AShape: TJvCustomDiagramShape; Strings: TStrings; const Ext: string = cPascalExt); var i: integer; begin Strings.Clear; for i := 0 to AShape.Parent.ControlCount - 1 do if (AShape.Parent.Controls[i] is TJvConnector) and (TJvConnector(AShape.Parent.Controls[i]).EndConn.Shape = AShape) then with TJvConnector(AShape.Parent.Controls[i]).StartConn do Strings.AddObject(ChangeFileExt(Shape.Caption.Text, Ext), Shape); end; // (p3) returns the first selected shape that isn't a TJvTextShape or a TJvConnector // (NOTE: I'm relying on that TJvTextShape has a nil Caption and TJvConnectors cannot be selected) function GetFirstSelectedShape(Parent: TWInControl): TJvCustomDiagramShape; var i: integer; begin for i := 0 to Parent.ControlCount - 1 do if (Parent.Controls[i] is TJvCustomDiagramShape) and TJvCustomDiagramShape(Parent.Controls[i]).Selected and // don't be fooled by captions (they are also TJvCustomDiagramShape): not (TJvCustomDiagramShape(Parent.Controls[i]).Caption = nil) then begin Result := TJvCustomDiagramShape(Parent.Controls[i]); Exit; end; Result := nil; end; // TList sorting functions: function NameCompare(Item1, Item2: Pointer): integer; begin Result := CompareText( TJvCustomDiagramShape(Item1).Caption.Text, TJvCustomDiagramShape(Item2).Caption.Text); end; function InvertNameCompare(Item1, Item2: Pointer): integer; begin Result := -NameCompare(Item1, Item2); end; function MinLinksToCompare(Item1, Item2: Pointer): integer; begin Result := GetNumLinksTo(Item1) - GetNumLinksTo(Item2); if Result = 0 then Result := GetNumLinksFrom(Item1) - GetNumLinksFrom(Item2); if Result = 0 then NameCompare(Item1, Item2); end; function MaxLinksToCompare(Item1, Item2: Pointer): integer; begin Result := -MinLinksToCompare(Item1, Item2); end; function MinLinksFromCompare(Item1, Item2: Pointer): integer; begin Result := GetNumLinksFrom(Item1) - GetNumLinksFrom(Item2); if Result = 0 then Result := GetNumLinksTo(Item1) - GetNumLinksTo(Item2); if Result = 0 then NameCompare(Item1, Item2); end; function MaxLinksFromCompare(Item1, Item2: Pointer): integer; begin Result := -MinLinksFromCompare(Item1, Item2); end; function SortIntfCompare(Item1, Item2: Pointer): integer; begin Result := TJvBitmapShape(Item1).ImageIndex - TJvBitmapShape(Item2).ImageIndex; end; function SortImplCompare(Item1, Item2: Pointer): integer; begin Result := -SortIntfCompare(Item1, Item2); end; { TDependencyWalkerDemoMainFrm } { IPersistSettings } procedure TDependencyWalkerDemoMainFrm.Load(Storage: TPersistStorage); begin // DO NOT LOCALIZE! if not FReload then inherited; FReload := true; acInvertSort.Checked := Storage.ReadBool(ClassName, 'InvertSort', false); FInitialDir := Storage.ReadString(ClassName, 'InitialDir', ''); pnlSkipList.Width := Storage.ReadInteger(ClassName, 'vertSplitter', pnlSkipList.Width); pnlStats.Height := Storage.ReadInteger(ClassName, 'horzSplitter', pnlStats.Height); StatusBar1.Top := ClientHeight; if not acViewStatusBar.Checked = Storage.ReadBool(ClassName, acViewStatusBar.Name, acViewStatusBar.Checked) then acViewStatusBar.Execute; // toggle to other state if not acViewToolbar.Checked = Storage.ReadBool(ClassName, acViewToolbar.Name, acViewToolbar.Checked) then acViewToolbar.Execute; if not acViewSkipList.Checked = Storage.ReadBool(ClassName, acViewSkipList.Name, acViewSkipList.Checked) then acViewSkipList.Execute; if not acViewDetails.Checked = Storage.ReadBool(ClassName, acViewDetails.Name, acViewDetails.Checked) then acViewDetails.Execute; FOffsetX := Storage.ReadInteger('Options', 'ShapeWidth', 100); FOffsetY := Storage.ReadInteger('Options', 'ShapeHeight', 100); FIntfLineColor := Storage.ReadInteger('Options', 'IntfColor', clBlack); FIntfSelColor := Storage.ReadInteger('Options', 'IntfSelColor', clRed); FImplLineColor := Storage.ReadInteger('Options', 'ImplColor', clBtnShadow); FImplSelColor := Storage.ReadInteger('Options', 'ImplSelColor', clBlue); end; procedure TDependencyWalkerDemoMainFrm.Save(Storage: TPersistStorage); begin inherited; Storage.WriteBool(ClassName, 'InvertSort', acInvertSort.Checked); Storage.WriteString(ClassName, 'InitialDir', FInitialDir); Storage.WriteInteger(ClassName, 'vertSplitter', pnlSkipList.Width); Storage.WriteInteger(ClassName, 'horzSplitter', pnlStats.Height); Storage.WriteBool(ClassName, acViewStatusBar.Name, acViewStatusBar.Checked); Storage.WriteBool(ClassName, acViewToolbar.Name, acViewToolbar.Checked); Storage.WriteBool(ClassName, acViewSkipList.Name, acViewSkipList.Checked); Storage.WriteBool(ClassName, acViewDetails.Name, acViewDetails.Checked); end; // main form utility functions // (p3) highlights the connectors (arrows) going to and from AShape procedure TDependencyWalkerDemoMainFrm.HighlightConnectors(AShape: TJvCustomDiagramShape); var i: integer; C: TJvConnector; Changed: boolean; begin Changed := false; for i := 0 to AShape.Parent.ControlCount - 1 do begin if AShape.Parent.Controls[i] is TJvConnector then begin C := TJvConnector(AShape.Parent.Controls[i]); if (C.StartConn.Shape = AShape) or (C.EndConn.Shape = AShape) then begin Changed := true; if C.LineColor = FIntfLineColor then C.LineColor := FIntfSelColor else if C.LineColor = FImplLineColor then C.LineColor := FImplSelColor else Changed := false; if Changed then C.Invalidate; end else // reset to standard color begin Changed := true; if C.LineColor = FIntfSelColor then C.LineColor := FIntfLineColor else if C.LineColor = FImplSelColor then C.LineColor := FImplLineColor else Changed := false; if Changed then C.Invalidate; end; end; end; if Changed then begin AShape.Parent.Repaint; // AShape.BringToFront; end; end; // (p3) returns an existing or new shape // Filename is checked against unique list function TDependencyWalkerDemoMainFrm.GetFileShape(const Filename: string; var IsNew: boolean): TJvBitmapShape; var i: integer; AFilename: string; begin AFilename := FindUnit(Filename); i := FFileShapes.IndexOf(AFilename); IsNew := false; if i < 0 then begin IsNew := true; Result := TJvBitmapShape.Create(self); Result.Images := il32; Result.ImageIndex := cUnitUsedImageIndex; // always set "used" as default Result.Hint := AFilename; Result.ShowHint := True; Result.OnClick := DoShapeClick; Result.OnDblClick := acParseUnitExecute; Result.OnMouseDown := DoShapeMouseDown; Result.PopupMenu := popShape; Result.Top := FTop; Result.Left := FLeft; Result.Parent := sb; Result.Caption := TJvTextShape.Create(self); Result.Caption.Parent := sb; Result.Caption.Enabled := false; Result.Caption.Tag := integer(Result); Result.Caption.Text := ChangeFileExt(ExtractFilename(AFilename), ''); Result.AlignCaption(taLeftJustify); Result.BringToFront; i := FFileShapes.AddObject(AFilename, Result); end; Result := TJvBitmapShape(FFileShapes.Objects[i]); end; // (p3) connects two shapes with a single head arrow pointing towards EndShape // colors differently depending on if it's interface link or an implementation link procedure TDependencyWalkerDemoMainFrm.Connect(StartShape, EndShape: TJvCustomDiagramShape; IsInterface: boolean); var arr: TJvSingleHeadArrow; begin arr := TJvSingleHeadArrow.Create(self); with arr do begin if IsInterface then LineColor := FIntfLineColor else LineColor := FImplLineColor; // Set the start connection StartConn.Side := csRight; StartConn.Offset := StartShape.Height div 2; StartConn.Shape := StartShape; // Set the end connection EndConn.Side := csLeft; EndConn.Offset := EndShape.Height div 2; EndConn.Shape := EndShape; // Ensure the size is correct SetBoundingRect; Parent := sb; SendToBack; end; end; // (p3) Builds a list of all units used by Filename and adds the unit names to AUses // returns true if no errors, any exception message is added to ErrorMessage but th eprocessing // is not aborted function TDependencyWalkerDemoMainFrm.GetUses(const Filename: string; AUsesIntf, AUsesImpl: TStrings; var ErrorMessage: string): boolean; var UL: TUsesList; i: integer; P: PChar; begin Result := true; try with TMemoryStream.Create do try LoadFromFile(Filename); AUsesIntf.Clear; AUSesImpl.Clear; P := PChar(Memory); with TUnitGoal.Create(P) do try UL := UsesIntf; for i := 0 to UL.Count - 1 do if not InSkipList(UL.Items[i]) then AUsesIntf.Add(UL.Items[i]); UL := UsesImpl; for i := 0 to UL.Count - 1 do if not InSkipList(UL.Items[i]) then AUsesImpl.Add(UL.Items[i]); finally Free; end; finally Free; end; except on E: EFOpenError do begin Result := false; ErrorMessage := E.Message + #13#10 + SCheckPaths; end; on E: Exception do begin Result := false; ErrorMessage := E.Message; end; end; end; // (p3) reads a single file's uses. Creates, connects and positions the shapes as necessary procedure TDependencyWalkerDemoMainFrm.ParseUnit(const Filename: string; Errors: TStrings); var AUsesIntf, AUsesImpl: TStringlist; FS: TJvBitmapShape; i: integer; AFilename, ErrMsg: string; b, IsNew: boolean; begin AFilename := FindUnit(Filename); if InSkipList(AFilename) then Exit; AUsesIntf := TStringlist.Create; AUsesImpl := TStringlist.Create; try b := GetUses(AFilename, AUsesIntf, AUsesImpl, ErrMsg); if not b and (Errors <> nil) then Errors.Add(Format('%s: %s', [AFilename, ErrMsg])); FS := GetFileShape(AFilename, IsNew); if b then FS.ImageIndex := cUnitParsedImageIndex; // this is a parsed file if IsNew then begin Inc(FLeft, FOffsetX); FLoadedFiles.Add(AFilename); end; for i := 0 to AUsesIntf.Count - 1 do begin //add the used unit and connect to the parsed file Connect(FS, GetFileShape(AUsesIntf[i], IsNew), true); if IsNew then Inc(FTop, FOffsetY); end; for i := 0 to AUsesImpl.Count - 1 do begin //add the used unit and connect to the parsed file Connect(FS, GetFileShape(AUsesImpl[i], IsNew), false); if IsNew then Inc(FTop, FOffsetY); end; finally AUsesIntf.Free; AUsesImpl.Free; end; Application.ProcessMessages; end; // (p3) reads a list of filenames and calls ParseUnit for each procedure TDependencyWalkerDemoMainFrm.ParseUnits(Files, Errors: TStrings); var i, aCount: integer; begin WaitCursor; SuspendRedraw(sb, true); try for i := 0 to Files.Count - 1 do begin StatusBar1.Panels[0].Text := Files[i]; StatusBar1.Update; aCount := FFileShapes.Count; FTop := cStartY; ParseUnit(Files[i], Errors); if aCount < FFileShapes.Count then Inc(FLeft, FOffsetX); end; finally SuspendRedraw(sb, false); end; StatusBar1.Panels[0].Text := Format(SParsedStatusFmt, [Files.Count, FFileShapes.Count]); end; // (p3) tries to find Filename and return it's full path and filename // if it fails, the original Filename is returned instead function TDependencyWalkerDemoMainFrm.FindUnit(const Filename: string; const DefaultExt: string = '.pas'): string; var i: integer; begin Result := ExpandUNCFileName(Filename); if FileExists(Result) then Exit; Result := ChangeFileExt(Result, DefaultExt); if FileExists(Result) then Exit; Result := ExtractFilePath(dlgSelectFiles.FileName) + ExtractFileName(Result); if FileExists(Result) then Exit; if FSearchPaths = nil then GetSearchPaths; Result := ExtractFileName(Result); for i := 0 to FSearchPaths.Count - 1 do if FileExists(IncludeTrailingPathDelimiter(FSearchPaths[i]) + Result) then begin Result := IncludeTrailingPathDelimiter(FSearchPaths[i]) + Result; Exit; end; Result := Filename; end; // (p3) removes all shapes and links procedure TDependencyWalkerDemoMainFrm.Clear(ClearAll: boolean); // var i: integer; begin WaitCursor; FreeAndNil(FSearchPaths); FFileShapes.Clear; if ClearAll then FLoadedFiles.Clear; TJvCustomDiagramShape.DeleteAllShapes(sb); FLeft := cStartX; FTop := cStartY; // Selected := nil; StatusBar1.Panels[0].Text := SStatusReady; end; procedure TDependencyWalkerDemoMainFrm.FormCreate(Sender: TObject); begin SetStorageHandler(GetPersistStorage); FFileShapes := TStringlist.Create; FLoadedFiles := TStringlist.Create; FFileShapes.Sorted := true; FFileShapes.Duplicates := dupError; FLeft := cStartX; FTop := cStartY; LoadSettings; end; procedure TDependencyWalkerDemoMainFrm.LoadSkipList; var // i: integer; AFilename: string; begin AFilename := ExtractFilePath(Application.Exename) + 'SkipList.txt'; if FileExists(AFilename) then begin lbSkipList.Sorted := false; lbSkipList.Items.LoadFromFile(AFilename); { for i := lbSkipList.Items.Count - 1 downto 0 do begin lbSkipList.Items[i] := ExtractFileName(ChangeFileExt(lbSkipList.Items[i], '')); if lbSkipList.Items[i] = '' then lbSkipList.Items.Delete(i); end; } lbSkipList.Sorted := true; end; end; procedure TDependencyWalkerDemoMainFrm.SaveSkipList; begin lbSkipList.Items.SaveToFile(ExtractFilePath(Application.Exename) + 'SkipList.txt'); end; function TDependencyWalkerDemoMainFrm.InSkipList(const Filename: string): boolean; begin Result := (lbSkipList.Items.IndexOf(ChangeFileExt(ExtractFileName(Filename), '')) > -1); end; // (p3) arranges the shapes in AList into a grid of rows and columns // tries to make the grid as "square" as possible (Rows = Cols) procedure TDependencyWalkerDemoMainFrm.Arrange(AList: TList); var Cols, i: integer; FS: TJvCustomDiagramShape; begin if AList.Count = 0 then Exit; Cols := round(sqrt(AList.Count)); FLeft := 0; FTop := 0; for i := 0 to AList.Count - 1 do begin if (i mod Cols = 0) then // new row or first row begin FLeft := cStartX; if i = 0 then Inc(FTop, cStartY) // first row else Inc(FTop, FOffsetY); end; FS := TJvCustomDiagramShape(AList[i]); FS.SetBounds(FLeft, FTop, FS.Width, FS.Height); Inc(FLeft, FOffsetX); end; Dec(FLeft, FOffsetX); end; function iff(Condition: boolean; TrueValue, FalseValue: integer): integer; begin if Condition then Result := TrueValue else Result := FalseValue; end; procedure TDependencyWalkerDemoMainFrm.SortItems(ATag: integer; AList: TList; InvertedSort: boolean); begin case ATag of 0: if InvertedSort then AList.Sort(InvertNameCompare) else AList.Sort(NameCompare); 1: if InvertedSort then AList.Sort(MaxLinksToCompare) else AList.Sort(MinLinksToCompare); 2: if InvertedSort then AList.Sort(MaxLinksFromCompare) else AList.Sort(MinLinksFromCompare); 3: if InvertedSort then AList.Sort(SortImplCompare) else AList.Sort(SortIntfCompare); else Exit; // no sorting end; end; procedure TDependencyWalkerDemoMainFrm.CreatePrintOut(Strings: TStrings; AFormat: TPrintFormat = pfText); var i, j, ATag: integer; UsedByStrings, UsesStrings: TStringlist; AList: TList; AShape: TJvBitmapShape; begin UsedByStrings := TStringlist.Create; UsesStrings := TStringlist.Create; AList := TList.Create; try Strings.Clear; // (p3) use same sorting as in the current view (defaults to "by Name"): CopyObjects(FFileShapes, AList); if acSortName.Checked then ATag := acSortName.Tag else if acSortLinksTo.Checked then ATag := acSortLinksTo.Tag else if acSortLinksFrom.Checked then ATag := acSortLinksFrom.Tag else ATag := -1; // no need to sort: FFileShapes already sorted by name SortItems(ATag, AList, acInvertSort.Checked); for i := 0 to AList.Count - 1 do begin AShape := TJvBitmapShape(AList[i]); UsesUnits(AShape, UsesStrings, ''); UsedByUnits(AShape, UsedByStrings, ''); case AFormat of pfText: begin Strings.Add(AShape.Caption.Text); Strings.Add(' ' + SUsesColon); if UsesStrings.Count < 1 then Strings.Add(' ' + SNone) else for j := 0 to UsesStrings.Count - 1 do Strings.Add(' ' + UsesStrings[j]); Strings.Add(' ' + SUsedByColon); if UsedByStrings.Count < 1 then Strings.Add(' ' + SNone) else for j := 0 to UsedByStrings.Count - 1 do Strings.Add(' ' + UsedByStrings[j]); end; pfHTML: begin Strings.Add(Format('