{ *************************************************************************** * * * This source is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This code 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. See the GNU * * General Public License for more details. * * * * A copy of the GNU General Public License is available on the World * * Wide Web at . You can also * * obtain it by writing to the Free Software Foundation, * * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. * * * *************************************************************************** Author: Mattias Gaertner Abstract: TPackageEditorForm is the form of a package editor. } unit PackageEditor; {$mode objfpc}{$H+} {off $DEFINE VerbosePkgEditDrag} interface uses // RTL, FCL Classes, SysUtils, Contnrs, // LCL Forms, Controls, StdCtrls, ComCtrls, Buttons, Graphics, Menus, Dialogs, ExtCtrls, ImgList, LCLType, LCLIntf, // LazControls TreeFilterEdit, // Codetools CodeToolManager, CodeCache, DirectoryCacher, FileProcs, // LazUtils FileUtil, LazFileUtils, LazFileCache, AvgLvlTree, LazLoggerBase, LazTracer, // BuildIntf ProjectIntf, PackageDependencyIntf, PackageIntf, PackageLinkIntf, IDEOptionsIntf, NewItemIntf, ComponentReg, // IDEIntf IDEImagesIntf, MenuIntf, LazIDEIntf, FormEditingIntf, IDEHelpIntf, InputHistory, IdeIntfStrConsts, IDEWindowIntf, IDEDialogs, IDEOptEditorIntf, SrcEditorIntf, // IdeConfig EnvironmentOpts, SearchPathProcs, ParsedCompilerOpts, CompilerOptions, // IDE MainBase, DialogProcs, LazarusIDEStrConsts, IDEDefs, PackageSystem, PackageDefs, AddToPackageDlg, AddPkgDependencyDlg, ComponentPalette, AddFPMakeDependencyDlg, ProjPackChecks, PkgVirtualUnitEditor, CleanPkgDeps, MissingPkgFilesDlg, ProjPackFilePropGui, ProjPackEditing, BasePkgManager; const PackageEditorMenuRootName = 'PackageEditor'; PackageEditorMenuFilesRootName = 'PackageEditorFiles'; PackageEditorWindowPrefix = 'PackageEditor_'; var // General actions for the Files and Required packages root nodes. // Duplicates actions found under the "Add" button. PkgEditMenuAddDiskFile: TIDEMenuCommand; PkgEditMenuAddNewDiskFiles: TIDEMenuCommand; PkgEditMenuAddNewFile: TIDEMenuCommand; PkgEditMenuAddNewComp: TIDEMenuCommand; PkgEditMenuAddNewReqr: TIDEMenuCommand; PkgEditMenuAddNewFPMakeReqr: TIDEMenuCommand; // selected files PkgEditMenuOpenFile: TIDEMenuCommand; PkgEditMenuRemoveFile: TIDEMenuCommand; PkgEditMenuReAddFile: TIDEMenuCommand; PkgEditMenuCopyMoveToDirectory: TIDEMenuCommand; PkgEditMenuEditVirtualUnit: TIDEMenuCommand; PkgEditMenuSectionFileType: TIDEMenuSection; // directories PkgEditMenuExpandDirectory: TIDEMenuCommand; PkgEditMenuCollapseDirectory: TIDEMenuCommand; PkgEditMenuUseAllUnitsInDirectory: TIDEMenuCommand; PkgEditMenuUseNoUnitsInDirectory: TIDEMenuCommand; PkgEditMenuOpenFolder: TIDEMenuCommand; // dependencies PkgEditMenuRemoveDependency: TIDEMenuCommand; PkgEditMenuReAddDependency: TIDEMenuCommand; PkgEditMenuDepStoreFileNameDefault: TIDEMenuCommand; PkgEditMenuDepStoreFileNamePreferred: TIDEMenuCommand; PkgEditMenuDepClearStoredFileName: TIDEMenuCommand; PkgEditMenuCleanDependencies: TIDEMenuCommand; // all files PkgEditMenuFindInFiles: TIDEMenuCommand; PkgEditMenuSortFiles: TIDEMenuCommand; PkgEditMenuFixFilesCase: TIDEMenuCommand; PkgEditMenuShowMissingFiles: TIDEMenuCommand; // package PkgEditMenuSave: TIDEMenuCommand; PkgEditMenuSaveAs: TIDEMenuCommand; PkgEditMenuRevert: TIDEMenuCommand; PkgEditMenuPublish: TIDEMenuCommand; // compile PkgEditMenuCompile: TIDEMenuCommand; PkgEditMenuRecompileClean: TIDEMenuCommand; PkgEditMenuRecompileAllRequired: TIDEMenuCommand; PkgEditMenuCreateMakefile: TIDEMenuCommand; PkgEditMenuCreateFpmakeFile: TIDEMenuCommand; PkgEditMenuViewPackageSource: TIDEMenuCommand; type TOnPkgEvent = function(Sender: TObject; APackage: TLazPackage): TModalResult of object; TOnAddPkgToProject = function(Sender: TObject; APackage: TLazPackage; OnlyTestIfPossible: boolean): TModalResult of object; TOnCompilePackage = function(Sender: TObject; APackage: TLazPackage; CompileClean, CompileRequired: boolean): TModalResult of object; TOnCreateNewPkgFile = function(Sender: TObject; Params: TAddToPkgResult): TModalResult of object; TOnDeleteAmbiguousFiles = function(Sender: TObject; APackage: TLazPackage; const Filename: string): TModalResult of object; TOnFreePkgEditor = procedure(APackage: TLazPackage) of object; TOnOpenFile = function(Sender: TObject; const Filename: string): TModalResult of object; TOnOpenPkgFile = function(Sender: TObject; PkgFile: TPkgFile): TModalResult of object; TOnSavePackage = function(Sender: TObject; APackage: TLazPackage; SaveAs: boolean): TModalResult of object; TIDEPackageOptsDlgAction = ( iodaRead, iodaWrite, iodaRestore ); { TPETVSelectedView } TPETVSelectedView = record NeedEndUpdate: boolean; OldScrollLeft: integer; OldScrollTop: integer; OldNodePath: string; RestoreFilter: boolean; OldFilter: string; end; { TPackageEditorForm } TPackageEditorForm = class(TBasePackageEditor,IFilesEditorInterface) MenuItem1: TMenuItem; mnuAddNewDiskFiles: TMenuItem; mnuAddFPMakeReq: TMenuItem; mnuAddDiskFile: TMenuItem; mnuAddNewFile: TMenuItem; mnuAddNewComp: TMenuItem; mnuAddNewReqr: TMenuItem; MoveDownBtn: TSpeedButton; MoveUpBtn: TSpeedButton; DirectoryHierarchyButton: TSpeedButton; OpenButton: TSpeedButton; FilterEdit: TTreeFilterEdit; FilterPanel: TPanel; AddPopupMenu: TPopupMenu; SortAlphabeticallyButton: TSpeedButton; Splitter1: TSplitter; // toolbar ToolBar: TToolBar; // toolbuttons SaveBitBtn: TToolButton; CompileBitBtn: TToolButton; UseBitBtn: TToolButton; AddBitBtn: TToolButton; RemoveBitBtn: TToolButton; OptionsBitBtn: TToolButton; MoreBitBtn: TToolButton; HelpBitBtn: TToolButton; // items ItemsTreeView: TTreeView; // properties PropsGroupBox: TGroupBox; PropsPageControl: TPageControl; CommonOptionsTabSheet: TTabSheet; // statusbar StatusBar: TStatusBar; // hidden components UsePopupMenu: TPopupMenu; ItemsPopupMenu: TPopupMenu; MorePopupMenu: TPopupMenu; procedure AddToProjectClick(Sender: TObject); procedure ChangeFileTypeMenuItemClick(Sender: TObject); procedure CleanDependenciesMenuItemClick(Sender: TObject); procedure ClearDependencyFilenameMenuItemClick(Sender: TObject); procedure CollapseDirectoryMenuItemClick(Sender: TObject); procedure CompileAllCleanClick(Sender: TObject); procedure CompileBitBtnClick(Sender: TObject); procedure CompileCleanClick(Sender: TObject); procedure CopyMoveToDirMenuItemClick(Sender: TObject); procedure CreateMakefileClick(Sender: TObject); procedure CreateFpmakeFileClick(Sender: TObject); procedure DirectoryHierarchyButtonClick(Sender: TObject); procedure EditVirtualUnitMenuItemClick(Sender: TObject); procedure ExpandDirectoryMenuItemClick(Sender: TObject); procedure FilterEditAfterFilter(Sender: TObject); procedure FilterEditKeyDown(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState); procedure FindInFilesMenuItemClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormDropFiles(Sender: TObject; const FileNames: array of String); procedure ItemsPopupMenuPopup(Sender: TObject); procedure ItemsTreeViewAdvancedCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; {%H-}State: TCustomDrawState; Stage: TCustomDrawStage; var {%H-}PaintImages, {%H-}DefaultDraw: Boolean); procedure ItemsTreeViewDragDrop(Sender, Source: TObject; X, Y: Integer); procedure ItemsTreeViewDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); procedure ItemsTreeViewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure mnuAddDiskFileClick(Sender: TObject); procedure mnuAddFPMakeReqClick(Sender: TObject); procedure mnuAddNewDiskFilesClick(Sender: TObject); procedure mnuAddNewCompClick(Sender: TObject); procedure mnuAddNewReqrClick(Sender: TObject); procedure mnuAddNewFileClick(Sender: TObject); procedure MorePopupMenuPopup(Sender: TObject); procedure ItemsTreeViewDblClick(Sender: TObject); procedure ItemsTreeViewSelectionChanged(Sender: TObject); procedure FixFilesCaseMenuItemClick(Sender: TObject); procedure HelpBitBtnClick(Sender: TObject); procedure InstallClick(Sender: TObject); procedure MoveDownBtnClick(Sender: TObject); procedure MoveUpBtnClick(Sender: TObject); procedure OnIdle(Sender: TObject; var {%H-}Done: Boolean); procedure OpenButtonClick(Sender: TObject); procedure OpenFolderMenuItemClick(Sender: TObject); procedure OptionsBitBtnClick(Sender: TObject); procedure PackageEditorFormClose(Sender: TObject; var {%H-}CloseAction: TCloseAction); procedure PackageEditorFormCloseQuery(Sender: TObject; var CanClose: boolean); procedure PublishClick(Sender: TObject); procedure ReAddMenuItemClick(Sender: TObject); procedure RemoveBitBtnClick(Sender: TObject); procedure RevertClick(Sender: TObject); procedure SaveAsClick(Sender: TObject); procedure SaveBitBtnClick(Sender: TObject); procedure SetDepDefaultFilenameMenuItemClick(Sender: TObject); procedure SetDepPreferredFilenameMenuItemClick(Sender: TObject); procedure ShowMissingFilesMenuItemClick(Sender: TObject); procedure SortAlphabeticallyButtonClick(Sender: TObject); procedure SortFilesMenuItemClick(Sender: TObject); procedure UninstallClick(Sender: TObject); procedure UseAllUnitsInDirectoryMenuItemClick(Sender: TObject); procedure UseNoUnitsInDirectoryMenuItemClick(Sender: TObject); procedure UsePopupMenuPopup(Sender: TObject); procedure ViewPkgSourceClick(Sender: TObject); procedure ViewPkgTodosClick(Sender: TObject); private FIdleConnected: boolean; FCompiling: boolean; FCompileDesignTimePkg: boolean; FLazPackage: TLazPackage; FNextSelectedPart: TPENodeData;// select this file/dependency on next update FFilesNode: TTreeNode; FRequiredPackagesNode: TTreeNode; FRemovedFilesNode: TTreeNode; FRemovedRequiredNode: TTreeNode; FPlugins: TStringList; // ComponentClassName, Objects=TPkgComponent FPropGui: TProjPackFilePropGui; FShowDirectoryHierarchy: boolean; FSortAlphabetically: boolean; FDirSummaryLabel: TLabel; FOptionsShownOfFile: TPkgFile; fUpdateLock: integer; fForcedFlags: TPEFlags; procedure DoAddNewFile(NewItem: TNewIDEItemTemplate); function CreateToolButton(AName, ACaption, AHint, AImageName: String; AOnClick: TNotifyEvent): TToolButton; function CreateDivider: TToolButton; procedure SetDependencyDefaultFilename(AsPreferred: boolean); procedure SetIdleConnected(AValue: boolean); procedure SetShowDirectoryHierarchy(const AValue: boolean); procedure SetSortAlphabetically(const AValue: boolean); procedure SetupComponents; procedure CreatePackageFileEditors; function TreeViewGetImageIndex({%H-}Str: String; Data: TObject; var {%H-}AIsEnabled: Boolean): Integer; procedure UpdatePending; procedure StoreItemsTVSelectedNode(out OldView: TPETVSelectedView; StoreFilter: boolean); procedure RestoreItemsTVSelectedNode(const OldView: TPETVSelectedView); function CanUpdate(Flag: TPEFlag; Immediately: boolean): boolean; procedure UpdateTitle(Immediately: boolean = false); procedure UpdateFiles(Immediately: boolean = false); procedure UpdateRemovedFiles(Immediately: boolean = false); procedure UpdateRequiredPackages(Immediately: boolean = false); procedure UpdatePEProperties(Immediately: boolean = false); procedure UpdateButtons(Immediately: boolean = false); procedure UpdateStatusBar(Immediately: boolean = false); function GetDependencyToUpdate(Immediately: boolean): TPkgDependencyID; procedure GetDirectorySummary(DirNode: TTreeNode; out FileCount, HasRegisterProcCount, AddToUsesPkgSectionCount: integer); procedure ExtendUnitIncPathForNewUnit(const AnUnitFilename, AnIncludeFile: string; var IgnoreUnitPaths: TFilenameToStringTree); procedure ExtendIncPathForNewIncludeFile(const AnIncludeFile: string; var IgnoreIncPaths: TFilenameToStringTree); function CanBeAddedToProject: boolean; procedure PackageListAvailable(Sender: TObject); function PassesFilter(rec: PIDEOptionsGroupRec): Boolean; procedure TraverseSettings(AOptions: TAbstractPackageFileIDEOptions; anAction: TIDEPackageOptsDlgAction); procedure FileOptionsToGui; procedure GuiToFileOptions(Restore: boolean); procedure FileOptionsChange(Sender: TObject); procedure CallRegisterProcCheckBoxChange(Sender: TObject); procedure AddToUsesPkgSectionCheckBoxChange(Sender: TObject); procedure ApplyDependencyButtonClick(Sender: TObject); procedure RegisteredListBoxDrawItem({%H-}Control: TWinControl; Index: Integer; ARect: TRect; {%H-}State: TOwnerDrawState); procedure DisableI18NForLFMCheckBoxChange(Sender: TObject); procedure SelectFileNode(const AFileName: string); protected fFlags: TPEFlags; procedure SetLazPackage(const AValue: TLazPackage); override; property IdleConnected: boolean read FIdleConnected write SetIdleConnected; public constructor Create(TheOwner: TComponent); override; destructor Destroy; override; function CanCloseEditor: TModalResult; override; procedure DoCompile(CompileClean, CompileRequired, WarnIDEPkg: boolean); procedure DoFindInFiles; procedure DoFixFilesCase; procedure DoShowMissingFiles; procedure DoMoveCurrentFile(Offset: integer); procedure DoMoveDependency(Offset: integer); procedure DoPublishPackage; procedure DoEditVirtualUnit; procedure DoExpandCollapseDirectory(ExpandIt: Boolean); procedure DoUseUnitsInDirectory(Use: boolean); procedure DoRevert; procedure DoSave(SaveAs: boolean); procedure DoSortFiles; function ShowNewCompDialog: TModalResult; function ShowAddDepDialog: TModalResult; function ShowAddFPMakeDepDialog: TModalResult; function PkgNameToFormName(const PkgName: string): string; function GetSingleSelectedDependency: TPkgDependency; function GetSingleSelectedFile: TPkgFile; public // IFilesEditorInterface function FilesEditTreeView: TTreeView; function FilesEditForm: TCustomForm; function FilesOwner: TObject; // = Lazpackage function FilesOwnerName: string; function TVNodeFiles: TTreeNode; function TVNodeRequiredPackages: TTreeNode; function FilesBaseDirectory: string; function FilesOwnerReadOnly: boolean; function FirstRequiredDependency: TPkgDependency; function ExtendUnitSearchPath(NewUnitPaths: string): boolean; function ExtendIncSearchPath(NewIncPaths: string): boolean; function GetNodeItem(NodeData: TPENodeData): TObject; function GetNodeDataItem(TVNode: TTreeNode; out NodeData: TPENodeData; out Item: TObject): boolean; function GetNodeFilename(Node: TTreeNode): string; function IsDirectoryNode(Node: TTreeNode): boolean; procedure BeginUpdate; procedure EndUpdate; procedure UpdateAll(Immediately: boolean = false); override; public property LazPackage: TLazPackage read FLazPackage write SetLazPackage; property SortAlphabetically: boolean read FSortAlphabetically write SetSortAlphabetically; property ShowDirectoryHierarchy: boolean read FShowDirectoryHierarchy write SetShowDirectoryHierarchy; property FilesNode: TTreeNode read FFilesNode; property RequiredPackagesNode: TTreeNode read FRequiredPackagesNode; end; { TPackageEditors } TPackageEditors = class private FItems: TFPList; // list of TPackageEditorForm FOnAddToProject: TOnAddPkgToProject; FOnAfterWritePackage: TIDEOptionsWriteEvent; FOnBeforeReadPackage: TNotifyEvent; FOnCompilePackage: TOnCompilePackage; FOnCopyMoveFiles: TNotifyEvent; FOnCreateNewFile: TOnCreateNewPkgFile; FOnCreateMakefile: TOnPkgEvent; FOnCreateFpmakeFile: TOnPkgEvent; FOnDeleteAmbiguousFiles: TOnDeleteAmbiguousFiles; FOnDragDropTreeView: TDragDropEvent; FOnDragOverTreeView: TOnDragOverTreeView; FOnShowFindInFiles: TOnPkgEvent; FOnFreeEditor: TOnFreePkgEditor; FOnGetIDEFileInfo: TGetIDEFileStateEvent; FOnInstallPackage: TOnPkgEvent; FOnOpenFile: TOnOpenFile; FOnOpenPackage: TOnPkgEvent; FOnOpenPkgFile: TOnOpenPkgFile; FOnPublishPackage: TOnPkgEvent; FOnRevertPackage: TOnPkgEvent; FOnSavePackage: TOnSavePackage; FOnUninstallPackage: TOnPkgEvent; FOnViewPackageSource: TOnPkgEvent; FOnViewPackageToDos: TOnPkgEvent; function GetEditors(Index: integer): TPackageEditorForm; public constructor Create; destructor Destroy; override; function Count: integer; procedure Clear; procedure Remove(Editor: TPackageEditorForm); function IndexOfPackage(Pkg: TLazPackage): integer; function IndexOfPackage(const PkgName: string): integer; function FindEditor(Pkg: TLazPackage): TPackageEditorForm; overload; function FindEditor(const PkgName: string): TPackageEditorForm; overload; function CreateEditor(Pkg: TLazPackage; DoDisableAutoSizing: boolean): TPackageEditorForm; function OpenEditor(Pkg: TLazPackage; BringToFront: boolean): TPackageEditorForm; function OpenFile(Sender: TObject; const Filename: string): TModalResult; function OpenPkgFile(Sender: TObject; PkgFile: TPkgFile): TModalResult; function OpenDependency(Sender: TObject; Dependency: TPkgDependency): TModalResult; procedure DoFreeEditor(Pkg: TLazPackage); function CreateNewFile(Sender: TObject; Params: TAddToPkgResult): TModalResult; function SavePackage(APackage: TLazPackage; SaveAs: boolean): TModalResult; function RevertPackage(APackage: TLazPackage): TModalResult; function PublishPackage(APackage: TLazPackage): TModalResult; function CompilePackage(APackage: TLazPackage; CompileClean,CompileRequired: boolean): TModalResult; procedure UpdateAllEditors(Immediately: boolean); function ShouldNotBeInstalled(APackage: TLazPackage): boolean;// possible, but probably a bad idea function InstallPackage(APackage: TLazPackage): TModalResult; function UninstallPackage(APackage: TLazPackage): TModalResult; function ViewPkgSource(APackage: TLazPackage): TModalResult; function ViewPkgToDos(APackage: TLazPackage): TModalResult; function FindInFiles(APackage: TLazPackage): TModalResult; function DeleteAmbiguousFiles(APackage: TLazPackage; const Filename: string): TModalResult; function AddToProject(APackage: TLazPackage; OnlyTestIfPossible: boolean): TModalResult; function CreateMakefile(APackage: TLazPackage): TModalResult; function CreateFpmakeFile(APackage: TLazPackage): TModalResult; function TreeViewToPkgEditor(TV: TTreeView): TPackageEditorForm; procedure ActiveEditorChanged(Sender: TObject); public property Editors[Index: integer]: TPackageEditorForm read GetEditors; property OnAddToProject: TOnAddPkgToProject read FOnAddToProject write FOnAddToProject; property OnAfterWritePackage: TIDEOptionsWriteEvent read FOnAfterWritePackage write FOnAfterWritePackage; property OnBeforeReadPackage: TNotifyEvent read FOnBeforeReadPackage write FOnBeforeReadPackage; property OnCompilePackage: TOnCompilePackage read FOnCompilePackage write FOnCompilePackage; property OnCopyMoveFiles: TNotifyEvent read FOnCopyMoveFiles write FOnCopyMoveFiles; property OnCreateFpmakeFile: TOnPkgEvent read FOnCreateFpmakeFile write FOnCreateFpmakeFile; property OnCreateMakeFile: TOnPkgEvent read FOnCreateMakefile write FOnCreateMakefile; property OnCreateNewFile: TOnCreateNewPkgFile read FOnCreateNewFile write FOnCreateNewFile; property OnDeleteAmbiguousFiles: TOnDeleteAmbiguousFiles read FOnDeleteAmbiguousFiles write FOnDeleteAmbiguousFiles; property OnDragDropTreeView: TDragDropEvent read FOnDragDropTreeView write FOnDragDropTreeView; property OnDragOverTreeView: TOnDragOverTreeView read FOnDragOverTreeView write FOnDragOverTreeView; property OnShowFindInFiles: TOnPkgEvent read FOnShowFindInFiles write FOnShowFindInFiles; property OnFreeEditor: TOnFreePkgEditor read FOnFreeEditor write FOnFreeEditor; property OnGetIDEFileInfo: TGetIDEFileStateEvent read FOnGetIDEFileInfo write FOnGetIDEFileInfo; property OnInstallPackage: TOnPkgEvent read FOnInstallPackage write FOnInstallPackage; property OnOpenFile: TOnOpenFile read FOnOpenFile write FOnOpenFile; property OnOpenPackage: TOnPkgEvent read FOnOpenPackage write FOnOpenPackage; property OnOpenPkgFile: TOnOpenPkgFile read FOnOpenPkgFile write FOnOpenPkgFile; property OnPublishPackage: TOnPkgEvent read FOnPublishPackage write FOnPublishPackage; property OnRevertPackage: TOnPkgEvent read FOnRevertPackage write FOnRevertPackage; property OnSavePackage: TOnSavePackage read FOnSavePackage write FOnSavePackage; property OnUninstallPackage: TOnPkgEvent read FOnUninstallPackage write FOnUninstallPackage; property OnViewPackageSource: TOnPkgEvent read FOnViewPackageSource write FOnViewPackageSource; property OnViewPackageToDos: TOnPkgEvent read FOnViewPackageToDos write FOnViewPackageToDos; end; var PackageEditors: TPackageEditors; procedure RegisterStandardPackageEditorMenuItems; implementation uses NewDialog; {$R *.lfm} var ImageIndexFiles: integer; ImageIndexRemovedFiles: integer; ImageIndexUnit: integer; ImageIndexRegisterUnit: integer; ImageIndexLFM: integer; ImageIndexLRS: integer; ImageIndexInclude: integer; ImageIndexIssues: integer; ImageIndexText: integer; ImageIndexBinary: integer; ImageIndexDirectory: integer; procedure RegisterStandardPackageEditorMenuItems; var AParent: TIDEMenuSection; begin PackageEditorMenuRoot :=RegisterIDEMenuRoot(PackageEditorMenuRootName); PackageEditorMenuFilesRoot:=RegisterIDEMenuRoot(PackageEditorMenuFilesRootName); // register the section for operations on selected files PkgEditMenuSectionFile:=RegisterIDEMenuSection(PackageEditorMenuFilesRoot,'File'); AParent:=PkgEditMenuSectionFile; PkgEditMenuAddDiskFile:=RegisterIDEMenuCommand(AParent,'Add disk file',lisPckEditAddFilesFromFileSystem); PkgEditMenuAddNewDiskFiles:=RegisterIDEMenuCommand(AParent,'Add new disk files',lisAddNewFilesFromFileSystem); PkgEditMenuAddNewFile:=RegisterIDEMenuCommand(AParent,'New file',lisA2PNewFile); PkgEditMenuAddNewComp:=RegisterIDEMenuCommand(AParent,'New component',lisMenuNewComponent); PkgEditMenuAddNewReqr:=RegisterIDEMenuCommand(AParent,'New requirement',lisProjAddNewRequirement); PkgEditMenuAddNewFPMakeReqr:=RegisterIDEMenuCommand(AParent,'New FPMake requirement',lisProjAddNewFPMakeRequirement); // PkgEditMenuOpenFile:=RegisterIDEMenuCommand(AParent,'Open File',lisOpen); PkgEditMenuRemoveFile:=RegisterIDEMenuCommand(AParent,'Remove File',lisPckEditRemoveFile); PkgEditMenuReAddFile:=RegisterIDEMenuCommand(AParent,'ReAdd File',lisPckEditReAddFile); PkgEditMenuCopyMoveToDirectory:=RegisterIDEMenuCommand(AParent, 'Copy/Move File to Directory', lisCopyMoveFileToDirectory); PkgEditMenuEditVirtualUnit:=RegisterIDEMenuCommand(AParent,'Edit Virtual File',lisPEEditVirtualUnit); PkgEditMenuSectionFileType:=RegisterIDESubMenu(AParent,'File Type',lisAF2PFileType); // register the section for operations on directories PkgEditMenuSectionDirectory:=RegisterIDEMenuSection(PackageEditorMenuFilesRoot,'Directory'); AParent:=PkgEditMenuSectionDirectory; PkgEditMenuExpandDirectory:=RegisterIDEMenuCommand(AParent,'Expand directory',lisPEExpandDirectory); PkgEditMenuCollapseDirectory:=RegisterIDEMenuCommand(AParent, 'Collapse directory', lisPECollapseDirectory); PkgEditMenuUseAllUnitsInDirectory:=RegisterIDEMenuCommand(AParent, 'Use all units in directory', lisPEUseAllUnitsInDirectory); PkgEditMenuUseNoUnitsInDirectory:=RegisterIDEMenuCommand(AParent, 'Use no units in directory', lisPEUseNoUnitsInDirectory); PkgEditMenuOpenFolder:=RegisterIDEMenuCommand(AParent, 'Open folder', lisMenuOpenFolder); // register the section for operations on dependencies PkgEditMenuSectionDependency:=RegisterIDEMenuSection(PackageEditorMenuFilesRoot,'Dependency'); AParent:=PkgEditMenuSectionDependency; PkgEditMenuRemoveDependency:=RegisterIDEMenuCommand(AParent,'Remove Dependency',lisPckEditRemoveDependency); PkgEditMenuReAddDependency:=RegisterIDEMenuCommand(AParent,'ReAdd Dependency',lisPckEditReAddDependency); PkgEditMenuDepStoreFileNameDefault:=RegisterIDEMenuCommand(AParent,'Dependency Store Filename As Default',lisPckEditStoreFileNameAsDefaultForThisDependency); PkgEditMenuDepStoreFileNamePreferred:=RegisterIDEMenuCommand(AParent,'Dependency Store Filename As Preferred',lisPckEditStoreFileNameAsPreferredForThisDependency); PkgEditMenuDepClearStoredFileName:=RegisterIDEMenuCommand(AParent,'Dependency Clear Stored Filename',lisPckEditClearDefaultPreferredFilenameOfDependency); PkgEditMenuCleanDependencies:=RegisterIDEMenuCommand(AParent, 'Clean up dependencies', lisPckEditCleanUpDependencies); // register the section for operations on all files PkgEditMenuSectionFiles:=RegisterIDEMenuSection(PackageEditorMenuRoot,'Files'); AParent:=PkgEditMenuSectionFiles; PkgEditMenuFindInFiles:=RegisterIDEMenuCommand(AParent,'Find in files',srkmecFindInFiles + ' ...'); PkgEditMenuSortFiles:=RegisterIDEMenuCommand(AParent,'Sort Files Permanently',lisPESortFiles); PkgEditMenuFixFilesCase:=RegisterIDEMenuCommand(AParent,'Fix Files Case',lisPEFixFilesCase); PkgEditMenuShowMissingFiles:=RegisterIDEMenuCommand(AParent, 'Show Missing Files', lisPEShowMissingFiles); // register the section for using the package PkgEditMenuSectionUse:=RegisterIDEMenuSection(PackageEditorMenuRoot,'Use'); // register the section for saving the package PkgEditMenuSectionSave:=RegisterIDEMenuSection(PackageEditorMenuRoot,'Save'); AParent:=PkgEditMenuSectionSave; PkgEditMenuSave:=RegisterIDEMenuCommand(AParent, 'Save', lisPckEditSavePackage); PkgEditMenuSaveAs:=RegisterIDEMenuCommand(AParent, 'Save As', lisPESavePackageAs); PkgEditMenuRevert:=RegisterIDEMenuCommand(AParent, 'Revert', lisPERevertPackage); PkgEditMenuPublish:=RegisterIDEMenuCommand(AParent,'Publish',lisPkgEditPublishPackage); // register the section for compiling the package PkgEditMenuSectionCompile:=RegisterIDEMenuSection(PackageEditorMenuRoot,'Compile'); AParent:=PkgEditMenuSectionCompile; PkgEditMenuCompile:=RegisterIDEMenuCommand(AParent,'Compile',lisCompile); PkgEditMenuRecompileClean:=RegisterIDEMenuCommand(AParent,'Recompile Clean',lisPckEditRecompileClean); PkgEditMenuRecompileAllRequired:=RegisterIDEMenuCommand(AParent,'Recompile All Required',lisPckEditRecompileAllRequired); PkgEditMenuCreateFpmakeFile:=RegisterIDEMenuCommand(AParent,'Create fpmake.pp',lisPckEditCreateFpmakeFile); PkgEditMenuCreateMakefile:=RegisterIDEMenuCommand(AParent,'Create Makefile',lisPckEditCreateMakefile); // register the section for adding to or removing from package PkgEditMenuSectionAddRemove:=RegisterIDEMenuSection(PackageEditorMenuRoot,'AddRemove'); // register the section for other things PkgEditMenuSectionMisc:=RegisterIDEMenuSection(PackageEditorMenuRoot,'Misc'); AParent:=PkgEditMenuSectionMisc; PkgEditMenuViewPackageSource:=RegisterIDEMenuCommand(AParent,'View Package Source',lisPckEditViewPackageSource); end; { TPackageEditorForm } procedure TPackageEditorForm.PublishClick(Sender: TObject); begin DoPublishPackage; end; procedure TPackageEditorForm.ReAddMenuItemClick(Sender: TObject); var PkgFile: TPkgFile; AFilename: String; Dependency: TPkgDependency; i: Integer; NodeData: TPENodeData; Item: TObject; YesToAll: TYesToAllList; begin BeginUpdate; YesToAll:=TYesToAllList.Create; try for i:=ItemsTreeView.SelectionCount-1 downto 0 do begin if not GetNodeDataItem(ItemsTreeView.Selections[i],NodeData,Item) then continue; if not NodeData.Removed then continue; if Item is TPkgFile then begin // re-add file PkgFile:=TPkgFile(Item); AFilename:=PkgFile.GetFullFilename; if TPkgFileCheck.ReAddingUnit(LazPackage, PkgFile.FileType, AFilename, PackageEditors.OnGetIDEFileInfo,YesToAll)<>mrOk then exit; //PkgFile.Filename:=AFilename; Assert(PkgFile.Filename=AFilename, 'TPackageEditorForm.ReAddMenuItemClick: Unexpected Filename.'); LazPackage.UnremovePkgFile(PkgFile); end else if Item is TPkgDependency then begin Dependency:=TPkgDependency(Item); // Re-add dependency fForcedFlags:=[pefNeedUpdateRemovedFiles,pefNeedUpdateRequiredPkgs]; if TPkgFileCheck.AddingDependency(LazPackage,Dependency,true)<>mrOk then exit; LazPackage.RemoveRemovedDependency(Dependency); PackageGraph.AddDependencyToPackage(LazPackage,Dependency); end; end; LazPackage.Modified:=True; finally YesToAll.Free; EndUpdate; end; end; type PackageSelType = (pstFile, pstDir, pstDep, pstFPMake, pstFilesNode, pstReqPackNode, pstRemFile, pstRemDep); PackageSelTypes = set of PackageSelType; procedure TPackageEditorForm.ItemsPopupMenuPopup(Sender: TObject); var UserSelection: PackageSelTypes; SingleSelectedFile: TPkgFile; SingleSelectedDep: TPkgDependency; procedure CollectSelected; var TVNode: TTreeNode; NodeData: TPENodeData; Item: TObject; CurDependency: TPkgDependency; CurFile: TPkgFile; i: Integer; begin UserSelection := []; SingleSelectedFile := Nil; SingleSelectedDep := Nil; for i := 0 to ItemsTreeView.SelectionCount-1 do begin TVNode := ItemsTreeView.Selections[i]; if GetNodeDataItem(TVNode,NodeData,Item) then begin if Item is TPkgFile then begin CurFile := TPkgFile(Item); if ItemsTreeView.SelectionCount=1 then SingleSelectedFile := CurFile; if NodeData.Removed then Include(UserSelection, pstRemFile) else Include(UserSelection, pstFile); end else if Item is TPkgDependency then begin CurDependency := TPkgDependency(Item); if (ItemsTreeView.SelectionCount=1) {and Assigned(CurDependency.RequiredPackage)} then SingleSelectedDep:=CurDependency; if CurDependency.DependencyType=pdtFPMake then Include(UserSelection, pstFPMake); if NodeData.Removed then Include(UserSelection, pstRemDep) else Include(UserSelection, pstDep); end; end else if IsDirectoryNode(TVNode) then Include(UserSelection, pstDir) else if TVNode=FFilesNode then Include(UserSelection, pstFilesNode) else if TVNode=FRequiredPackagesNode then Include(UserSelection, pstReqPackNode); end; end; procedure SetItem(Item: TIDEMenuCommand; AnOnClick: TNotifyEvent; aShow: boolean = true; AEnable: boolean = true); begin Item.OnClick:=AnOnClick; Item.Visible:=aShow; Item.Enabled:=AEnable; end; procedure AddFileTypeMenuItem; var CurPFT: TPkgFileType; VirtualFileExists: Boolean; NewMenuItem: TIDEMenuCommand; begin PkgEditMenuSectionFileType.Visible:=Assigned(SingleSelectedFile); if not PkgEditMenuSectionFileType.Visible then Exit; PkgEditMenuSectionFileType.Clear; VirtualFileExists:=(SingleSelectedFile.FileType=pftVirtualUnit) and FileExistsCached(SingleSelectedFile.GetFullFilename); for CurPFT:=Low(TPkgFileType) to High(TPkgFileType) do begin NewMenuItem:=RegisterIDEMenuCommand(PkgEditMenuSectionFileType, 'SetFileType'+IntToStr(ord(CurPFT)), GetPkgFileTypeLocalizedName(CurPFT), @ChangeFileTypeMenuItemClick); if CurPFT=SingleSelectedFile.FileType then begin // menuitem to keep the current type NewMenuItem.Enabled:=true; NewMenuItem.Checked:=true; end else if VirtualFileExists then // a virtual unit that exists can be changed into anything NewMenuItem.Enabled:=true else if not (CurPFT in PkgFileUnitTypes) then // all other files can be changed into all non unit types NewMenuItem.Enabled:=true else if FilenameHasPascalExt(SingleSelectedFile.Filename) then // a pascal file can be changed into anything NewMenuItem.Enabled:=true else // default is to not allow NewMenuItem.Enabled:=false; end; end; var OpenItemEnable, Writable: Boolean; OpenItemCapt: String; begin //debugln(['TPackageEditorForm.FilesPopupMenuPopup START ',ItemsPopupMenu.Items.Count]); PackageEditorMenuFilesRoot.MenuItem:=ItemsPopupMenu.Items; //debugln(['TPackageEditorForm.FilesPopupMenuPopup START after connect ',ItemsPopupMenu.Items.Count]); //PackageEditorMenuRoot.BeginUpdate; try CollectSelected; OpenItemCapt := lisOpen; // May be changed later. OpenItemEnable := True; Writable := not LazPackage.ReadOnly; // items for Files node and for selected files, under section PkgEditMenuSectionFile PkgEditMenuSectionFile.Visible := not (pstDir in UserSelection); if PkgEditMenuSectionFile.Visible then begin // Files root node SetItem(PkgEditMenuAddDiskFile, @mnuAddDiskFileClick, UserSelection=[pstFilesNode], Writable); SetItem(PkgEditMenuAddNewDiskFiles, @mnuAddNewDiskFilesClick, UserSelection=[pstFilesNode], Writable); SetItem(PkgEditMenuAddNewFile, @mnuAddNewFileClick, UserSelection=[pstFilesNode], Writable); SetItem(PkgEditMenuAddNewComp, @mnuAddNewCompClick, UserSelection=[pstFilesNode], Writable); // Required packages root node SetItem(PkgEditMenuAddNewReqr, @mnuAddNewReqrClick, UserSelection=[pstReqPackNode], Writable); SetItem(PkgEditMenuAddNewFPMakeReqr, @mnuAddFPMakeReqClick, UserSelection=[pstReqPackNode], Writable); // selected files SetItem(PkgEditMenuOpenFile, @OpenButtonClick, UserSelection*[pstFilesNode,pstReqPackNode,pstFPMake]=[]); SetItem(PkgEditMenuRemoveFile, @RemoveBitBtnClick, UserSelection=[pstFile], RemoveBitBtn.Enabled); SetItem(PkgEditMenuReAddFile, @ReAddMenuItemClick, UserSelection=[pstRemFile]); SetItem(PkgEditMenuCopyMoveToDirectory, @CopyMoveToDirMenuItemClick, (UserSelection=[pstFile]) and LazPackage.HasDirectory); AddFileTypeMenuItem; SetItem(PkgEditMenuEditVirtualUnit, @EditVirtualUnitMenuItemClick, Assigned(SingleSelectedFile) and (SingleSelectedFile.FileType=pftVirtualUnit), Writable); end; // items for directories, under section PkgEditMenuSectionDirectory PkgEditMenuSectionDirectory.Visible := UserSelection<=[pstDir,pstFilesNode]; if PkgEditMenuSectionDirectory.Visible then begin SetItem(PkgEditMenuExpandDirectory, @ExpandDirectoryMenuItemClick); SetItem(PkgEditMenuCollapseDirectory, @CollapseDirectoryMenuItemClick); SetItem(PkgEditMenuUseAllUnitsInDirectory, @UseAllUnitsInDirectoryMenuItemClick); SetItem(PkgEditMenuUseNoUnitsInDirectory, @UseNoUnitsInDirectoryMenuItemClick); SetItem(PkgEditMenuOpenFolder, @OpenFolderMenuItemClick); end; // items for dependencies, under section PkgEditMenuSectionDependency PkgEditMenuSectionDependency.Visible := (UserSelection*[pstDep,pstRemDep] <> []) or (ItemsTreeView.Selected=FRequiredPackagesNode); if PkgEditMenuSectionDependency.Visible then begin if Assigned(SingleSelectedDep) then case SingleSelectedDep.LoadPackageResult of lprAvailableOnline: OpenItemCapt := lisPckEditInstall; lprNotFound: if Assigned(OPMInterface) and not OPMInterface.IsPackageListLoaded then OpenItemCapt := lisPckEditCheckAvailabilityOnline else begin //OpenItemCapt := lisUENotFound; OpenItemEnable := False; end; end; SetItem(PkgEditMenuRemoveDependency, @RemoveBitBtnClick, pstdep in UserSelection, Writable); SetItem(PkgEditMenuReAddDependency,@ReAddMenuItemClick, pstRemDep in UserSelection, Writable); SetItem(PkgEditMenuDepStoreFileNameDefault, @SetDepDefaultFilenameMenuItemClick, Assigned(SingleSelectedDep), Writable); SetItem(PkgEditMenuDepStoreFileNamePreferred, @SetDepPreferredFilenameMenuItemClick, Assigned(SingleSelectedDep), Writable); SetItem(PkgEditMenuDepClearStoredFileName, @ClearDependencyFilenameMenuItemClick, Assigned(SingleSelectedDep), Writable); SetItem(PkgEditMenuCleanDependencies, @CleanDependenciesMenuItemClick, Assigned(LazPackage.FirstRequiredDependency), Writable); end; if PkgEditMenuOpenFile.MenuItem<>nil then begin PkgEditMenuOpenFile.MenuItem.Caption := OpenItemCapt; PkgEditMenuOpenFile.MenuItem.Enabled := OpenItemEnable; end; finally //PackageEditorMenuRoot.EndUpdate; SingleSelectedFile := Nil; SingleSelectedDep := Nil; end; //debugln(['TPackageEditorForm.FilesPopupMenuPopup END ',ItemsPopupMenu.Items.Count]); PackageEditorMenuRoot.WriteDebugReport(' ',true); end; procedure TPackageEditorForm.ItemsTreeViewAdvancedCustomDrawItem( Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage; var PaintImages, DefaultDraw: Boolean); var NodeData: TPENodeData; r: TRect; y: Integer; begin if Stage=cdPostPaint then begin NodeData:=GetNodeData(Node); if (NodeData<>nil) then begin if (NodeData.Typ=penFile) and (not NodeData.Removed) and (NodeData.FileType<>pftVirtualUnit) and FilenameIsAbsolute(NodeData.Name) and (not FileExistsCached(NodeData.Name)) then begin r:=Node.DisplayRect(true); ItemsTreeView.Canvas.Pen.Color:=clRed; y:=(r.Top+r.Bottom) div 2; ItemsTreeView.Canvas.Line(r.Left,y,r.Right,y); end; end; end; end; procedure TPackageEditorForm.ItemsTreeViewDragDrop(Sender, Source: TObject; X, Y: Integer); begin PackageEditors.OnDragDropTreeView(Sender, Source, X, Y); end; procedure TPackageEditorForm.ItemsTreeViewDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); var TargetTVNode: TTreeNode; TargetTVType: TTreeViewInsertMarkType; begin //debugln(['TPackageEditorForm.ItemsTreeViewDragOver ',DbgSName(Source),' State=',ord(State),' FromSelf=',Source=ItemsTreeView]); Accept:=PackageEditors.OnDragOverTreeView(Sender,Source,X,Y,TargetTVNode,TargetTVType); if Accept and (State<>dsDragLeave) then ItemsTreeView.SetInsertMark(TargetTVNode,TargetTVType) else ItemsTreeView.SetInsertMark(nil,tvimNone); end; procedure TPackageEditorForm.MorePopupMenuPopup(Sender: TObject); procedure SetItem(Item: TIDEMenuCommand; AnOnClick: TNotifyEvent; aShow: boolean = true; AEnable: boolean = true); begin //debugln(['SetItem ',Item.Caption,' Visible=',aShow,' Enable=',AEnable]); Item.OnClick:=AnOnClick; Item.Visible:=aShow; Item.Enabled:=AEnable; end; var Writable, CanPublish: Boolean; pcos: TParsedCompilerOptString; CurrentPath: String; begin PackageEditorMenuRoot.MenuItem:=MorePopupMenu.Items; //PackageEditorMenuRoot.BeginUpdate; try Writable:=(not LazPackage.ReadOnly); // under section PkgEditMenuSectionFiles SetItem(PkgEditMenuFindInFiles,@FindInFilesMenuItemClick); SetItem(PkgEditMenuSortFiles,@SortFilesMenuItemClick,(LazPackage.FileCount>1),Writable); SetItem(PkgEditMenuFixFilesCase,@FixFilesCaseMenuItemClick,(LazPackage.FileCount>0),Writable); SetItem(PkgEditMenuShowMissingFiles,@ShowMissingFilesMenuItemClick,(LazPackage.FileCount>0),Writable); // under section PkgEditMenuSectionSave SetItem(PkgEditMenuSave,@SaveBitBtnClick,true,SaveBitBtn.Enabled); SetItem(PkgEditMenuSaveAs,@SaveAsClick,true,true); SetItem(PkgEditMenuRevert,@RevertClick,true, (not LazPackage.IsVirtual) and FileExistsUTF8(LazPackage.Filename)); CanPublish:=(not LazPackage.Missing) and LazPackage.HasDirectory; for pcos in [pcosUnitPath,pcosIncludePath] do begin CurrentPath:=LazPackage.CompilerOptions.ParsedOpts.GetParsedValue(pcos); CurrentPath:=CreateRelativeSearchPath(CurrentPath,LazPackage.DirectoryExpanded); //debugln(['TPackageEditorForm.MorePopupMenuPopup Unit=',CurrentPath]); if Pos('..',CurrentPath)>0 then CanPublish:=false; end; SetItem(PkgEditMenuPublish,@PublishClick,true,CanPublish); // under section PkgEditMenuSectionCompile SetItem(PkgEditMenuCompile,@CompileBitBtnClick,true,CompileBitBtn.Enabled); SetItem(PkgEditMenuRecompileClean,@CompileCleanClick,true,CompileBitBtn.Enabled); SetItem(PkgEditMenuRecompileAllRequired,@CompileAllCleanClick,true,CompileBitBtn.Enabled); SetItem(PkgEditMenuCreateFpmakeFile,@CreateFpmakeFileClick,true,CompileBitBtn.Enabled); SetItem(PkgEditMenuCreateMakefile,@CreateMakefileClick,true,CompileBitBtn.Enabled); // under section PkgEditMenuSectionMisc SetItem(PkgEditMenuViewPackageSource,@ViewPkgSourceClick); finally //PackageEditorMenuRoot.EndUpdate; end; end; procedure TPackageEditorForm.SortAlphabeticallyButtonClick(Sender: TObject); begin SortAlphabetically:=SortAlphabeticallyButton.Down; end; procedure TPackageEditorForm.UsePopupMenuPopup(Sender: TObject); var ItemCnt: Integer; function AddPopupMenuItem(const ACaption: string; AnEvent: TNotifyEvent; EnabledFlag: boolean): TMenuItem; begin if UsePopupMenu.Items.Count<=ItemCnt then begin Result:=TMenuItem.Create(Self); UsePopupMenu.Items.Add(Result); end else begin Result:=UsePopupMenu.Items[ItemCnt]; while Result.Count>0 do Result.Delete(Result.Count-1); end; Result.Caption:=ACaption; Result.OnClick:=AnEvent; Result.Enabled:=EnabledFlag; inc(ItemCnt); end; begin ItemCnt:=0; AddPopupMenuItem(lisPckEditAddToProject, @AddToProjectClick, CanBeAddedToProject); AddPopupMenuItem(lisPckEditInstall, @InstallClick,(not LazPackage.Missing) and (LazPackage.PackageType in [lptDesignTime,lptRunAndDesignTime])); AddPopupMenuItem(lisPckEditUninstall, @UninstallClick, (LazPackage.Installed<>pitNope) or (LazPackage.AutoInstall<>pitNope)); // remove unneeded menu items while UsePopupMenu.Items.Count>ItemCnt do UsePopupMenu.Items.Delete(UsePopupMenu.Items.Count-1); end; procedure TPackageEditorForm.ItemsTreeViewDblClick(Sender: TObject); begin OpenButtonClick(Self); end; procedure TPackageEditorForm.ItemsTreeViewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); var Handled: Boolean; begin Handled := True; if (ssCtrl in Shift) then begin if Key = VK_UP then MoveUpBtnClick(Nil) else if Key = VK_DOWN then MoveDownBtnClick(Nil) else Handled := False; end else if Key = VK_RETURN then OpenButtonClick(Nil) else if Key = VK_DELETE then RemoveBitBtnClick(Nil) else if Key = VK_INSERT then mnuAddDiskFileClick(Nil) else Handled := False; if Handled then Key := VK_UNKNOWN; end; procedure TPackageEditorForm.mnuAddFPMakeReqClick(Sender: TObject); begin ShowAddFPMakeDepDialog end; procedure TPackageEditorForm.mnuAddNewDiskFilesClick(Sender: TObject); function IsNewFile(const aFilename, aValue: string): boolean; var Ext: String; IDEFileFlags: TIDEFileStateFlags; begin Result:=false; if CompareFilenames(ExtractFilename(aFilename),'fpmake.pp')=0 then exit; if CompareFilenames(aFilename,LazPackage.GetSrcFilename)=0 then exit; if not FilenameIsPascalUnit(aFilename) then begin if aValue='Include' then begin Ext:=ExtractFileExt(aFilename); if IsPascalIncExt(PChar(Ext))=pietNone then exit; end else exit; end; if LazPackage.FindPkgFile(aFilename,true,true)<>nil then exit; // already in package if PackageGraph.FindFileInAllPackages(aFilename,true,false)<>nil then exit; // already in a package PackageEditors.OnGetIDEFileInfo(Self,aFilename,[ifsPartOfProject],IDEFileFlags); if ifsPartOfProject in IDEFileFlags then exit; Result:=true; end; var Files: TFilenameToStringTree; aFilename, NewUnitName, Msg: String; Item: PStringToStringItem; Code: TCodeBuffer; NewFileType: TPkgFileType; NewFlags: TPkgFileFlags; begin if LazPackage.IsVirtual then exit; if TPkgFileCheck.ReadOnlyOk(LazPackage)<>mrOK then exit; Files:=TFilenameToStringTree.Create(true); try // collect all units from unit and include paths CollectFilesInSearchPath(LazPackage.GetUnitPath(false),Files,'Unit'); CollectFilesInSearchPath(LazPackage.GetIncludePath(false),Files,'Include'); // collect new files Msg:=''; for Item in Files do begin aFilename:=Item^.Name; if IsNewFile(aFilename,Item^.Value) then Msg+=LineEnding+CreateRelativePath(aFilename,LazPackage.Directory,true,false) else Item^.Value:=''; end; if Msg='' then begin IDEMessageDialog(lisNoNewFileFound, lisAllPasPpPIncInUnitIncludePathAreAlreadyInAProjectP, mtInformation, [ mbOk] ); exit; end; // ask user Msg:=lisAddTheFollowingFiles+Msg; if IDEMessageDialog(lisAddNewDiskFiles, Msg, mtConfirmation, [mbOk, mbCancel ])<>mrOk then exit; // add files for Item in Files do begin if Item^.Value='' then continue; aFilename:=Item^.Name; NewFlags:=[]; Code:=CodeToolBoss.LoadFile(aFilename,true,false); NewUnitName:=''; if FilenameIsPascalUnit(aFilename) then NewUnitName:=CodeToolBoss.GetSourceName(Code,false); if NewUnitName<>'' then NewFileType:=pftUnit else NewFileType:=pftInclude; if CodeToolBoss.HasInterfaceRegisterProc(Code) then Include(NewFlags,pffHasRegisterProc); LazPackage.AddFile(aFilename,NewUnitName,NewFileType,NewFlags,cpNormal); end; finally Files.Free; end; end; procedure TPackageEditorForm.mnuAddNewCompClick(Sender: TObject); begin ShowNewCompDialog; end; procedure TPackageEditorForm.mnuAddNewReqrClick(Sender: TObject); begin ShowAddDepDialog; end; procedure TPackageEditorForm.mnuAddNewFileClick(Sender: TObject); var NewItem: TNewIDEItemTemplate; begin // Reuse the "New..." dialog for "Add new file". if ShowNewIDEItemDialog(NewItem, true)=mrOk then DoAddNewFile(NewItem); end; procedure TPackageEditorForm.ItemsTreeViewSelectionChanged(Sender: TObject); begin if fUpdateLock>0 then exit; UpdatePEProperties; UpdateButtons; end; procedure TPackageEditorForm.HelpBitBtnClick(Sender: TObject); begin LazarusHelp.ShowHelpForIDEControl(Self); end; procedure TPackageEditorForm.InstallClick(Sender: TObject); begin PackageEditors.InstallPackage(LazPackage); end; procedure TPackageEditorForm.SetDepDefaultFilenameMenuItemClick(Sender: TObject); begin SetDependencyDefaultFilename(false); end; procedure TPackageEditorForm.SetDepPreferredFilenameMenuItemClick(Sender: TObject); begin SetDependencyDefaultFilename(true); end; procedure TPackageEditorForm.ClearDependencyFilenameMenuItemClick(Sender: TObject); var CurDependency: TPkgDependency; begin CurDependency:=GetSingleSelectedDependency; if CurDependency=nil then exit; if (LazPackage=nil) or LazPackage.ReadOnly then exit; if CurDependency.DefaultFilename='' then exit; CurDependency.DefaultFilename:=''; CurDependency.PreferDefaultFilename:=false; LazPackage.Modified:=true; UpdateRequiredPackages; end; procedure TPackageEditorForm.CollapseDirectoryMenuItemClick(Sender: TObject); begin DoExpandCollapseDirectory(False); end; procedure TPackageEditorForm.MoveUpBtnClick(Sender: TObject); begin if SortAlphabetically then exit; if Assigned(GetSingleSelectedFile) then DoMoveCurrentFile(-1) else if Assigned(GetSingleSelectedDependency) then DoMoveDependency(-1); end; procedure TPackageEditorForm.OnIdle(Sender: TObject; var Done: Boolean); begin if fUpdateLock>0 then exit; IdleConnected:=false; UpdatePending; end; procedure TPackageEditorForm.MoveDownBtnClick(Sender: TObject); begin if SortAlphabetically then exit; if Assigned(GetSingleSelectedFile) then DoMoveCurrentFile(1) else if Assigned(GetSingleSelectedDependency) then DoMoveDependency(1) end; procedure TPackageEditorForm.OpenButtonClick(Sender: TObject); var i: Integer; NodeData: TPENodeData; Item: TObject; begin for i:=0 to ItemsTreeView.SelectionCount-1 do begin if GetNodeDataItem(ItemsTreeView.Selections[i],NodeData,Item) then begin if Item is TPkgFile then begin if PackageEditors.OpenPkgFile(Self,TPkgFile(Item))<>mrOk then Exit; end else if Item is TPkgDependency then if not OpmAddOrOpenDependency(TPkgDependency(Item)) then Exit; end; end; OpmInstallPendingDependencies; end; procedure TPackageEditorForm.OptionsBitBtnClick(Sender: TObject); const Settings: array[Boolean] of TIDEOptionsEditorSettings = ( [], [ioesReadOnly] ); begin Package1 := LazPackage; Package1.IDEOptions.OnBeforeRead:=PackageEditors.OnBeforeReadPackage; Package1.IDEOptions.OnAfterWrite:=PackageEditors.OnAfterWritePackage; LazarusIDE.DoOpenIDEOptions(nil, Format(lisPckEditOptionsForPackage, [LazPackage.IDAsString]), [TPackageIDEOptions, TPkgCompilerOptions], Settings[LazPackage.ReadOnly]); UpdateTitle; UpdateButtons; UpdateStatusBar; end; procedure TPackageEditorForm.PackageEditorFormClose(Sender: TObject; var CloseAction: TCloseAction); begin //debugln(['TPackageEditorForm.PackageEditorFormClose ',Caption]); if LazPackage=nil then exit; end; procedure TPackageEditorForm.PackageEditorFormCloseQuery(Sender: TObject; var CanClose: boolean); begin CanClose:=CanCloseEditor=mrOK; if CanClose then Application.ReleaseComponent(Self); end; procedure TPackageEditorForm.RegisteredListBoxDrawItem(Control: TWinControl; Index: Integer; ARect: TRect; State: TOwnerDrawState); var CurComponent: TPaletteComponent; CurStr: string; CurObject: TObject; TxtH: Integer; IconWidth: Integer; IconHeight: Integer; IL: TCustomImageList; II: TImageIndex; Res: TScaledImageListResolution; l25PPIScaled: integer; begin //DebugLn('TPackageEditorForm.RegisteredListBoxDrawItem START'); if LazPackage=nil then exit; if (Index<0) or (Index>=FPlugins.Count) then exit; CurObject:=FPlugins.Objects[Index]; if CurObject is TPaletteComponent then begin // draw registered component CurComponent:=TPaletteComponent(CurObject); with FPropGui.RegisteredListBox do begin if Assigned(CurComponent.RealPage) then CurStr:=Format(lisPckEditPage,[CurComponent.ComponentClass.ClassName, CurComponent.RealPage.PageName]) else CurStr:=CurComponent.ComponentClass.ClassName; TxtH:=Canvas.TextHeight(CurStr); Canvas.FillRect(ARect); IL:=CurComponent.Images; II:=CurComponent.ImageIndex; l25PPIScaled:=ARect.Bottom - ARect.Top; //DebugLn('TPackageEditorForm.RegisteredListBoxDrawItem ',DbgSName(CurIcon),' ',CurComponent.ComponentClass.ClassName); if (IL<>nil) and (II>=0) then begin Res := IL.ResolutionForControl[0, Self]; IconWidth:=Res.Width; IconHeight:=Res.Height; Res.Draw(Canvas, ARect.Left+(l25PPIScaled-IconWidth) div 2, ARect.Top+(ARect.Bottom-ARect.Top-IconHeight) div 2, II); end; Canvas.TextOut(ARect.Left+l25PPIScaled, ARect.Top+(ARect.Bottom-ARect.Top-TxtH) div 2, CurStr); end; end; end; procedure TPackageEditorForm.RemoveBitBtnClick(Sender: TObject); var MainUnitSelected: Boolean; FileWarning, PkgWarning: String; FileCount, PkgCount: Integer; procedure CheckFileSelection(CurFile: TPkgFile); begin inc(FileCount); if CurFile.FileType=pftMainUnit then MainUnitSelected:=true; if FileWarning='' then FileWarning:=Format(lisPckEditRemoveFileFromPackage, [CurFile.Filename, LineEnding, LazPackage.IDAsString]); end; procedure CheckPkgSelection(CurDependency: TPkgDependency); begin inc(PkgCount); if PkgWarning='' then PkgWarning:=Format(lisPckEditRemoveDependencyFromPackage, [CurDependency.AsString, LineEnding, LazPackage.IDAsString]); end; function ConfirmFileDeletion: TModalResult; var mt: TMsgDlgType; s: String; begin mt:=mtConfirmation; if FileCount=1 then s:=FileWarning else s:=Format(lisRemoveFilesFromPackage, [IntToStr(FileCount), LazPackage.Name]); if MainUnitSelected then begin s+=Format(lisWarningThisIsTheMainUnitTheNewMainUnitWillBePas, [LineEnding+LineEnding, lowercase(LazPackage.Name)]); mt:=mtWarning; end; Result:=IDEMessageDialog(lisPckEditRemoveFile2, s, mt, [mbYes,mbNo]); end; function ConfirmPkgDeletion: TModalResult; var mt: TMsgDlgType; s: String; begin mt:=mtConfirmation; if PkgCount=1 then s:=PkgWarning else s:=Format(lisRemoveDependenciesFromPackage, [IntToStr(PkgCount), LazPackage.Name]); Result:=IDEMessageDialog(lisRemove2, s, mt, [mbYes, mbNo]); end; var ANode: TTreeNode; TVNode: TTreeNode; NodeData: TPENodeData; Item: TObject; FilesBranch: TTreeFilterBranch; i: Integer; begin BeginUpdate; try ANode:=ItemsTreeView.Selected; if (ANode=nil) or LazPackage.ReadOnly then begin UpdateButtons; exit; end; MainUnitSelected:=false; FileCount:=0; FileWarning:=''; PkgCount:=0; PkgWarning:=''; // check selection for i:=0 to ItemsTreeView.SelectionCount-1 do begin TVNode:=ItemsTreeView.Selections[i]; if not GetNodeDataItem(TVNode,NodeData,Item) then continue; if NodeData.Removed then continue; if Item is TPkgFile then CheckFileSelection(TPkgFile(Item)) else if Item is TPkgDependency then CheckPkgSelection(TPkgDependency(Item)); end; if (FileCount=0) and (PkgCount=0) then begin UpdateButtons; exit; end; // confirm deletion if FileCount>0 then begin if ConfirmFileDeletion<>mrYes then Exit; FilesBranch:=FilterEdit.GetExistingBranch(FFilesNode); end; if (PkgCount>0) and (ConfirmPkgDeletion<>mrYes) then Exit; // remove for i:=ItemsTreeView.SelectionCount-1 downto 0 do begin TVNode:=ItemsTreeView.Selections[i]; if not GetNodeDataItem(TVNode, NodeData, Item) then continue; if NodeData.Removed then continue; if Item is TPkgFile then begin FilesBranch.DeleteData(TVNode); LazPackage.RemoveFileSilently(TPkgFile(Item)); end else if Item is TPkgDependency then LazPackage.RemoveRequiredDepSilently(TPkgDependency(Item)); end; if FileCount>0 then // Force update for removed files only. fForcedFlags:=fForcedFlags+[pefNeedUpdateRemovedFiles]; if PkgCount>0 then fForcedFlags:=fForcedFlags+[pefNeedUpdateRemovedFiles,pefNeedUpdateRequiredPkgs]; LazPackage.Modified:=True; finally EndUpdate; end; end; procedure TPackageEditorForm.EditVirtualUnitMenuItemClick(Sender: TObject); begin DoEditVirtualUnit; end; procedure TPackageEditorForm.ExpandDirectoryMenuItemClick(Sender: TObject); begin DoExpandCollapseDirectory(True); end; procedure TPackageEditorForm.FilterEditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key = VK_RETURN then begin OpenButtonClick(Nil); Key := VK_UNKNOWN; end; end; procedure TPackageEditorForm.FindInFilesMenuItemClick(Sender: TObject); begin DoFindInFiles; end; procedure TPackageEditorForm.FormCreate(Sender: TObject); begin FPlugins:=TStringList.Create; FPropGui:=TProjPackFilePropGui.Create(CommonOptionsTabSheet, True); SetupComponents; SortAlphabetically := EnvironmentOptions.PackageEditorSortAlphabetically; ShowDirectoryHierarchy := EnvironmentOptions.PackageEditorShowDirHierarchy; if OPMInterface <> nil then OPMInterface.AddPackageListNotification(@PackageListAvailable); end; procedure TPackageEditorForm.FormDestroy(Sender: TObject); begin if OPMInterface <> nil then OPMInterface.RemovePackageListNotification(@PackageListAvailable); IdleConnected:=false; FreeAndNil(FNextSelectedPart); EnvironmentOptions.PackageEditorSortAlphabetically := SortAlphabetically; EnvironmentOptions.PackageEditorShowDirHierarchy := ShowDirectoryHierarchy; FilterEdit.ForceFilter(''); if PackageEditorMenuRoot.MenuItem=ItemsPopupMenu.Items then PackageEditorMenuRoot.MenuItem:=nil; FreeAndNil(FPropGui); PackageEditors.DoFreeEditor(LazPackage); FLazPackage:=nil; FreeAndNil(FPlugins); end; procedure TPackageEditorForm.FormDropFiles(Sender: TObject; const FileNames: array of String); var i: Integer; NewFilename, NewUnitPaths, NewIncPaths: String; YesToAll: TYesToAllList; r: TModalResult; begin {$IFDEF VerbosePkgEditDrag} debugln(['TPackageEditorForm.FormDropFiles ',length(FileNames)]); {$ENDIF} if length(FileNames)=0 then exit; YesToAll:=TYesToAllList.Create; BeginUpdate; try NewUnitPaths:=''; NewIncPaths:=''; for i:=0 to high(Filenames) do begin NewFilename:=FileNames[i]; r:=TPkgFileCheck.AddingUnit(LazPackage, NewFilename, PackageEditors.OnGetIDEFileInfo,YesToAll); if r=mrOK then LazPackage.AddFileByName(NewFilename, NewUnitPaths, NewIncPaths) else if r=mrAbort then break; end; //UpdateAll(false); // extend unit and include search path if not LazPackage.ExtendUnitSearchPath(NewUnitPaths) then exit; if not LazPackage.ExtendIncSearchPath(NewIncPaths) then exit; finally YesToAll.Free; EndUpdate; end; end; procedure TPackageEditorForm.RevertClick(Sender: TObject); begin DoRevert; end; procedure TPackageEditorForm.SaveBitBtnClick(Sender: TObject); begin DoSave(false); end; procedure TPackageEditorForm.SelectFileNode(const AFileName: string); function _FindInChildren(_Parent: TTreeNode): TTreeNode; var TVNode: TTreeNode; NodeData: TPENodeData; Item: TObject; PFile: TPkgFile; begin Result := nil; TVNode:=_Parent.GetFirstChild; while Assigned(TVNode) do begin if GetNodeDataItem(TVNode,NodeData,Item) and (Item is TPkgFile) then begin PFile := TPkgFile(Item); if SameFileName(PFile.GetFullFilename, AFileName) then Exit(TVNode); end; if TVNode.HasChildren then begin Result := _FindInChildren(TVNode); if Assigned(Result) then Exit; end; TVNode := TVNode.GetNextSibling; end; end; var FileNode: TTreeNode; begin if not Assigned(FFilesNode) then Exit; FileNode := _FindInChildren(FFilesNode); if Assigned(FileNode) then begin ItemsTreeView.BeginUpdate; try ItemsTreeView.ClearSelection; ItemsTreeView.Selected := FileNode; finally ItemsTreeView.EndUpdate; end; end; end; procedure TPackageEditorForm.SaveAsClick(Sender: TObject); begin DoSave(true); end; procedure TPackageEditorForm.SortFilesMenuItemClick(Sender: TObject); begin DoSortFiles; end; procedure TPackageEditorForm.FixFilesCaseMenuItemClick(Sender: TObject); begin DoFixFilesCase; end; procedure TPackageEditorForm.ShowMissingFilesMenuItemClick(Sender: TObject); begin DoShowMissingFiles; end; procedure TPackageEditorForm.UninstallClick(Sender: TObject); begin PackageEditors.UninstallPackage(LazPackage); end; procedure TPackageEditorForm.ViewPkgSourceClick(Sender: TObject); begin PackageEditors.ViewPkgSource(LazPackage); end; procedure TPackageEditorForm.ViewPkgTodosClick(Sender: TObject); begin PackageEditors.ViewPkgToDos(LazPackage); end; procedure TPackageEditorForm.UseAllUnitsInDirectoryMenuItemClick(Sender: TObject); begin DoUseUnitsInDirectory(true); end; procedure TPackageEditorForm.UseNoUnitsInDirectoryMenuItemClick(Sender: TObject); begin DoUseUnitsInDirectory(false); end; procedure TPackageEditorForm.OpenFolderMenuItemClick(Sender: TObject); begin OpenDocument(LazPackage.Directory); end; procedure TPackageEditorForm.mnuAddDiskFileClick(Sender: TObject); var OpenDialog: TOpenDialog; i: Integer; NewFilename, NewUnitPaths, NewIncPaths: String; r: TModalResult; YesToAll: TYesToAllList; begin // is readonly if TPkgFileCheck.ReadOnlyOk(LazPackage)<>mrOK then exit; YesToAll:=nil; OpenDialog:=TOpenDialog.Create(nil); try InputHistories.ApplyFileDialogSettings(OpenDialog); OpenDialog.InitialDir:=LazPackage.GetFileDialogInitialDir(OpenDialog.InitialDir); OpenDialog.Title:=lisOpenFile; OpenDialog.Options:=OpenDialog.Options +[ofFileMustExist,ofPathMustExist,ofAllowMultiSelect]; OpenDialog.Filter:= dlgFilterAll+' ('+GetAllFilesMask+')|'+GetAllFilesMask +'|'+dlgFilterLazarusUnit+' (*.pas;*.pp)|*.pas;*.pp' +'|'+dlgFilterLazarusProject+' (*.lpi)|*.lpi' +'|'+dlgFilterLazarusForm+' (*.lfm;*.dfm)|*.lfm;*.dfm' +'|'+dlgFilterLazarusPackage+' (*.lpk)|*.lpk' +'|'+dlgFilterLazarusProjectSource+' (*.lpr)|*.lpr'; if OpenDialog.Execute then begin InputHistories.StoreFileDialogSettings(OpenDialog); NewUnitPaths:=''; NewIncPaths:=''; YesToAll:=TYesToAllList.Create; for i:=0 to OpenDialog.Files.Count-1 do begin NewFilename:=OpenDialog.Files[i]; r:=TPkgFileCheck.AddingUnit(LazPackage, NewFilename, PackageEditors.OnGetIDEFileInfo,YesToAll); if r=mrOK then LazPackage.AddFileByName(NewFilename, NewUnitPaths, NewIncPaths) else if r=mrAbort then break; end; //UpdateAll(false); // extend unit and include search path if not LazPackage.ExtendUnitSearchPath(NewUnitPaths) then exit; if not LazPackage.ExtendIncSearchPath(NewIncPaths) then exit; end; finally YesToAll.Free; OpenDialog.Free; end; end; procedure TPackageEditorForm.AddToUsesPkgSectionCheckBoxChange(Sender: TObject); var CurFile: TPkgFile; OtherFile: TPkgFile; TVNode: TTreeNode; NodeData: TPENodeData; Item: TObject; i, j: Integer; begin if LazPackage=nil then exit; for i:=0 to ItemsTreeView.SelectionCount-1 do begin TVNode:=ItemsTreeView.Selections[i]; if not GetNodeDataItem(TVNode,NodeData,Item) then continue; if not (Item is TPkgFile) then continue; CurFile:=TPkgFile(Item); if not (CurFile.FileType in PkgFileUnitTypes) then continue; if CurFile.AddToUsesPkgSection=FPropGui.AddToUsesPkgSectionCheckBox.Checked then continue; // change flag CurFile.AddToUsesPkgSection:=FPropGui.AddToUsesPkgSectionCheckBox.Checked; if (not NodeData.Removed) and CurFile.AddToUsesPkgSection then begin // mark all other units with the same name as unused for j:=0 to LazPackage.FileCount-1 do begin OtherFile:=LazPackage.Files[j]; if (OtherFile<>CurFile) and (CompareText(OtherFile.Unit_Name,CurFile.Unit_Name)=0) then OtherFile.AddToUsesPkgSection:=false; end; end; LazPackage.Modified:=True; end; end; procedure TPackageEditorForm.AddToProjectClick(Sender: TObject); begin if LazPackage=nil then exit; PackageEditors.AddToProject(LazPackage,false); end; procedure TPackageEditorForm.ApplyDependencyButtonClick(Sender: TObject); var CurDependency: TPkgDependency; begin CurDependency:=GetSingleSelectedDependency; if (LazPackage=nil) or (CurDependency=nil) or not FPropGui.CheckApplyDependency(CurDependency) then exit; LazPackage.Modified:=True; PkgBoss.ApplyDependency(CurDependency); end; procedure TPackageEditorForm.CallRegisterProcCheckBoxChange(Sender: TObject); var CurFile: TPkgFile; TVNode: TTreeNode; NodeData: TPENodeData; Item: TObject; i: Integer; begin if LazPackage=nil then exit; for i:=0 to ItemsTreeView.SelectionCount-1 do begin TVNode:=ItemsTreeView.Selections[i]; if not GetNodeDataItem(TVNode,NodeData,Item) or not (Item is TPkgFile) then continue; CurFile:=TPkgFile(Item); if not (CurFile.FileType in PkgFileUnitTypes) or CurFile.HasRegisterProc=FPropGui.CallRegisterProcCheckBox.Checked then continue; CurFile.HasRegisterProc:=FPropGui.CallRegisterProcCheckBox.Checked; if not NodeData.Removed then LazPackage.Modified:=True; end; end; procedure TPackageEditorForm.ChangeFileTypeMenuItemClick(Sender: TObject); var CurPFT: TPkgFileType; CurFile: TPkgFile; CurItem: TIDEMenuCommand; i: Integer; TVNode: TTreeNode; NodeData: TPENodeData; Item: TObject; begin if LazPackage=nil then exit; CurItem:=TIDEMenuCommand(Sender); for CurPFT:=Low(TPkgFileType) to High(TPkgFileType) do begin if CurItem.Caption=GetPkgFileTypeLocalizedName(CurPFT) then begin for i:=0 to ItemsTreeView.SelectionCount-1 do begin TVNode:=ItemsTreeView.Selections[i]; if not GetNodeDataItem(TVNode,NodeData,Item) then continue; if not (Item is TPkgFile) then continue; CurFile:=TPkgFile(Item); if CurFile.FileType=CurPFT then continue; if (not FilenameHasPascalExt(CurFile.Filename)) and (CurPFT in PkgFileUnitTypes) then continue; CurFile.FileType:=CurPFT; if not NodeData.Removed then LazPackage.Modified:=True; end; exit; end; end; end; procedure TPackageEditorForm.CleanDependenciesMenuItemClick(Sender: TObject); var ListOfNodeInfos: TObjectList; i: Integer; Info: TCPDNodeInfo; Dependency: TPkgDependency; begin if LazPackage=nil then exit; BeginUpdate; ListOfNodeInfos:=nil; try if ShowCleanPkgDepDlg(LazPackage,ListOfNodeInfos)<>mrOk then exit; for i:=0 to ListOfNodeInfos.Count-1 do begin Info:=TCPDNodeInfo(ListOfNodeInfos[i]); Dependency:=LazPackage.FindDependencyByName(Info.Dependency); if Dependency<>nil then begin fForcedFlags:=[pefNeedUpdateRemovedFiles,pefNeedUpdateRequiredPkgs]; PackageGraph.RemoveDependencyFromPackage(LazPackage,Dependency,true); end; end; finally ListOfNodeInfos.Free; EndUpdate; end; end; procedure TPackageEditorForm.CompileAllCleanClick(Sender: TObject); begin if LazPackage=nil then exit; if MessageDlg(lisPckEditCompileEverything, lisPckEditReCompileThisAndAllRequiredPackages, mtConfirmation,[mbYes,mbNo],0)<>mrYes then exit; DoCompile(true,true,true); end; procedure TPackageEditorForm.CompileCleanClick(Sender: TObject); begin DoCompile(true,false,true); end; procedure TPackageEditorForm.CopyMoveToDirMenuItemClick(Sender: TObject); begin PackageEditors.OnCopyMoveFiles(Self); end; procedure TPackageEditorForm.CompileBitBtnClick(Sender: TObject); begin DoCompile(false,false,true); end; procedure TPackageEditorForm.CreateMakefileClick(Sender: TObject); begin PackageEditors.CreateMakefile(LazPackage); end; procedure TPackageEditorForm.CreateFpmakeFileClick(Sender: TObject); begin PackageEditors.CreateFpmakeFile(LazPackage); end; procedure TPackageEditorForm.DirectoryHierarchyButtonClick(Sender: TObject); begin ShowDirectoryHierarchy:=DirectoryHierarchyButton.Down; end; procedure TPackageEditorForm.DisableI18NForLFMCheckBoxChange(Sender: TObject); var CurFile: TPkgFile; i: Integer; TVNode: TTreeNode; NodeData: TPENodeData; Item: TObject; begin if LazPackage=nil then exit; BeginUpdate; try for i:=0 to ItemsTreeView.SelectionCount-1 do begin TVNode:=ItemsTreeView.Selections[i]; if not GetNodeDataItem(TVNode,NodeData,Item) or not (Item is TPkgFile) then continue; CurFile:=TPkgFile(Item); if not (CurFile.FileType in PkgFileUnitTypes) or CurFile.DisableI18NForLFM=FPropGui.DisableI18NForLFMCheckBox.Checked then continue; CurFile.DisableI18NForLFM:=FPropGui.DisableI18NForLFMCheckBox.Checked; if not NodeData.Removed then LazPackage.Modified:=true; end; finally EndUpdate; end; end; procedure TPackageEditorForm.SetLazPackage(const AValue: TLazPackage); begin //force editor name change when package name changed! if (FLazPackage=Nil) and ( (AValue=Nil) or (Name=PkgNameToFormName(AValue.Name)) ) then exit; if FLazPackage<>nil then begin FLazPackage.Editor:=nil; if EnvironmentOptions.LastOpenPackages.Remove(FLazPackage.Filename) then MainIDE.SaveEnvironment; end; FLazPackage:=AValue; if FLazPackage=nil then begin Name:=Name+'___off___'; exit; end; EnvironmentOptions.LastOpenPackages.Add(FLazPackage.Filename); MainIDE.SaveEnvironment; FLazPackage.Editor:=Self; // set Name and update components. UpdateAll(true); end; function TPackageEditorForm.CreateToolButton(AName, ACaption, AHint, AImageName: String; AOnClick: TNotifyEvent): TToolButton; begin Result := TToolButton.Create(Self); Result.Name := AName; Result.Caption := ACaption; Result.Hint := AHint; if AImageName <> '' then Result.ImageIndex := IDEImages.LoadImage(AImageName); Result.ShowHint := True; Result.OnClick := AOnClick; Result.AutoSize := True; Result.Parent := ToolBar; end; function TPackageEditorForm.CreateDivider: TToolButton; begin Result := TToolButton.Create(Self); Result.Style := tbsDivider; Result.AutoSize := True; Result.Parent := ToolBar; end; procedure TPackageEditorForm.SetupComponents; begin ImageIndexFiles := IDEImages.LoadImage('pkg_files'); ImageIndexRemovedFiles := IDEImages.LoadImage('pkg_removedfiles'); ImageIndexUnit := IDEImages.LoadImage('pkg_unit'); ImageIndexRegisterUnit := IDEImages.LoadImage('pkg_registerunit'); ImageIndexLFM := IDEImages.LoadImage('pkg_lfm'); ImageIndexLRS := IDEImages.LoadImage('pkg_lrs'); ImageIndexInclude := IDEImages.LoadImage('pkg_include'); ImageIndexIssues := IDEImages.LoadImage('pkg_issues'); ImageIndexText := IDEImages.LoadImage('pkg_text'); ImageIndexBinary := IDEImages.LoadImage('pkg_binary'); ImageIndexDirectory := IDEImages.LoadImage('pkg_files'); ItemsTreeView.Images := IDEImages.Images_16; ToolBar.Images := IDEImages.Images_16; FilterEdit.OnGetImageIndex:=@TreeViewGetImageIndex; SaveBitBtn := CreateToolButton('SaveBitBtn', lisMenuSave, lisPckEditSavePackage, 'laz_save', @SaveBitBtnClick); CompileBitBtn := CreateToolButton('CompileBitBtn', lisCompile, lisPckEditCompilePackage, 'pkg_compile', @CompileBitBtnClick); UseBitBtn := CreateToolButton('UseBitBtn', lisUse, lisClickToSeeTheChoices, 'pkg_install', nil); UseBitBtn.Style:=tbsButtonDrop; CreateDivider; AddBitBtn := CreateToolButton('AddBitBtn', lisAdd, lisClickToSeeTheChoices, 'laz_add', nil); AddBitBtn.Style:=tbsButtonDrop; RemoveBitBtn := CreateToolButton('RemoveBitBtn', lisRemove, lisPckEditRemoveSelectedItem, 'laz_delete', @RemoveBitBtnClick); CreateDivider; OptionsBitBtn := CreateToolButton('OptionsBitBtn', lisOptions, lisPckEditEditGeneralOptions, 'pkg_properties', @OptionsBitBtnClick); HelpBitBtn := CreateToolButton('HelpBitBtn', GetButtonCaption(idButtonHelp), lisMenuOnlineHelp, 'btn_help', @HelpBitBtnClick); MoreBitBtn := CreateToolButton('MoreBitBtn', lisMoreSub, lisPkgEdMoreFunctionsForThePackage, '', nil); MoreBitBtn.Style:=tbsButtonDrop; UseBitBtn.DropdownMenu := UsePopupMenu; AddBitBtn.DropdownMenu := AddPopupMenu; MoreBitBtn.DropdownMenu := MorePopupMenu; mnuAddDiskFile.Caption := lisPckEditAddFilesFromFileSystem; mnuAddNewDiskFiles.Caption := lisAddNewFilesFromFileSystem; mnuAddNewFile.Caption := lisA2PNewFile; mnuAddNewComp.Caption := lisMenuNewComponent; mnuAddNewReqr.Caption := lisProjAddNewRequirement; mnuAddFPMakeReq.Caption := lisProjAddNewFPMakeRequirement; // Buttons on FilterPanel IDEImages.AssignImage(OpenButton, 'laz_open'); OpenButton.Hint:=lisOpenFile2; SortAlphabeticallyButton.Hint:=lisPESortFilesAlphabetically; IDEImages.AssignImage(SortAlphabeticallyButton, 'pkg_sortalphabetically'); DirectoryHierarchyButton.Hint:=lisPEShowDirectoryHierarchy; IDEImages.AssignImage(DirectoryHierarchyButton, 'pkg_hierarchical'); // Up / Down buttons IDEImages.AssignImage(MoveUpBtn, 'arrow_up'); IDEImages.AssignImage(MoveDownBtn, 'arrow_down'); MoveUpBtn.Hint:=lisMoveSelectedUp; MoveDownBtn.Hint:=lisMoveSelectedDown; // file properties FPropGui.AddToUsesPkgSectionCheckBox.OnChange := @AddToUsesPkgSectionCheckBoxChange; FPropGui.CallRegisterProcCheckBox.OnChange := @CallRegisterProcCheckBoxChange; FPropGui.RegisteredListBox.OnDrawItem := @RegisteredListBoxDrawItem; FPropGui.DisableI18NForLFMCheckBox.OnChange := @DisableI18NForLFMCheckBoxChange; // dependency properties FPropGui.OnGetPkgDep := @GetDependencyToUpdate; FPropGui.ApplyDependencyButton.OnClick := @ApplyDependencyButtonClick; ItemsTreeView.BeginUpdate; FFilesNode:=ItemsTreeView.Items.Add(nil, dlgEnvFiles); FFilesNode.ImageIndex:=ImageIndexFiles; FFilesNode.SelectedIndex:=FFilesNode.ImageIndex; FRequiredPackagesNode:=ItemsTreeView.Items.Add(nil, lisPckEditRequiredPackages); FRequiredPackagesNode.ImageIndex:=FPropGui.ImageIndexRequired; FRequiredPackagesNode.SelectedIndex:=FRequiredPackagesNode.ImageIndex; ItemsTreeView.EndUpdate; PropsGroupBox.Caption:=lisPckEditFileProperties; CommonOptionsTabSheet.Caption:=lisPckEditCommonOptions; FDirSummaryLabel:=TLabel.Create(Self); FDirSummaryLabel.Name:='DirSummaryLabel'; FDirSummaryLabel.Parent:=CommonOptionsTabSheet; CreatePackageFileEditors; end; procedure TPackageEditorForm.SetDependencyDefaultFilename(AsPreferred: boolean); var NewFilename: String; CurDependency: TPkgDependency; begin if LazPackage=nil then exit; CurDependency:=GetSingleSelectedDependency; if CurDependency=nil then begin debugln(['Info: [TPackageEditorForm.SetDependencyDefaultFilename] CurDependency=nil']); exit; end; if LazPackage.ReadOnly then begin debugln(['Info: [TPackageEditorForm.SetDependencyDefaultFilename] ReadOnly']); exit; end; if CurDependency.RequiredPackage=nil then begin debugln(['Info: [TPackageEditorForm.SetDependencyDefaultFilename] RequiredPackage=nil']); exit; end; NewFilename:=CurDependency.RequiredPackage.Filename; if (NewFilename=CurDependency.DefaultFilename) and (CurDependency.PreferDefaultFilename=AsPreferred) then begin debugln(['Info: [TPackageEditorForm.SetDependencyDefaultFilename] PreferDefaultFilename=AsPreferred']); exit; end; BeginUpdate; try CurDependency.DefaultFilename:=NewFilename; CurDependency.PreferDefaultFilename:=AsPreferred; LazPackage.Modified:=true; UpdateRequiredPackages; debugln(['Info: TPackageEditorForm.SetDependencyDefaultFilename ',CurDependency.PackageName,' DefaultFilename:=',NewFilename,' AsPreferred=',AsPreferred]); finally EndUpdate; end; end; procedure TPackageEditorForm.SetIdleConnected(AValue: boolean); begin if csDestroying in ComponentState then AValue:=false; if FIdleConnected=AValue then Exit; FIdleConnected:=AValue; if IdleConnected then Application.AddOnIdleHandler(@OnIdle) else Application.RemoveOnIdleHandler(@OnIdle); end; procedure TPackageEditorForm.SetShowDirectoryHierarchy(const AValue: boolean); begin //debugln(['TPackageEditorForm.SetShowDirectoryHierachy Old=',FShowDirectoryHierarchy,' New=',AValue]); if FShowDirectoryHierarchy=AValue then exit; FShowDirectoryHierarchy:=AValue; DirectoryHierarchyButton.Down:=FShowDirectoryHierarchy; FilterEdit.ShowDirHierarchy:=FShowDirectoryHierarchy; end; procedure TPackageEditorForm.SetSortAlphabetically(const AValue: boolean); begin if FSortAlphabetically=AValue then exit; FSortAlphabetically:=AValue; SortAlphabeticallyButton.Down:=FSortAlphabetically; FilterEdit.SortData:=FSortAlphabetically; end; procedure TPackageEditorForm.UpdateAll(Immediately: boolean); begin if csDestroying in ComponentState then exit; if LazPackage=nil then exit; Name:=PkgNameToFormName(LazPackage.Name); if fForcedFlags<>[] then fFlags:=fFlags+fForcedFlags // Flags forcing a partial update else fFlags:=fFlags+[ // Otherwise all flags. pefNeedUpdateTitle, pefNeedUpdateFiles, pefNeedUpdateRemovedFiles, pefNeedUpdateRequiredPkgs, pefNeedUpdateProperties, pefNeedUpdateButtons, pefNeedUpdateApplyDependencyButton, pefNeedUpdateStatusBar]; if Immediately then UpdatePending else IdleConnected:=true; end; procedure TPackageEditorForm.DoAddNewFile(NewItem: TNewIDEItemTemplate); var NewFilename, NewUnitName: String; NewFileType: TPkgFileType; NewFlags: TPkgFileFlags; Desc: TProjectFileDescriptor; CodeBuffer: TCodeBuffer; begin if not (NewItem is TNewItemProjectFile) then exit; // create new file Desc:=TNewItemProjectFile(NewItem).Descriptor; NewFilename:=''; if LazarusIDE.DoNewFile(Desc,NewFilename,'', [nfOpenInEditor,nfCreateDefaultSrc,nfIsNotPartOfProject],LazPackage)<>mrOk then exit; // success -> now add it to package NewUnitName:=''; NewFileType:=FileNameToPkgFileType(NewFilename); NewFlags:=[]; if (NewFileType in PkgFileUnitTypes) then begin Include(NewFlags,pffAddToPkgUsesSection); CodeBuffer:=CodeToolBoss.LoadFile(NewFilename,true,false); if CodeBuffer<>nil then begin NewUnitName:=CodeToolBoss.GetSourceName(CodeBuffer,false); if CodeToolBoss.HasInterfaceRegisterProc(CodeBuffer) then Include(NewFlags,pffHasRegisterProc); end else NewUnitName:=ExtractFilenameOnly(NewFilename); end; DebugLn(['TPackageEditorForm.DoAddNewFile: NewUnitName=', NewUnitName, ', NewFilename=', NewFilename]); LazPackage.AddFile(NewFilename,NewUnitName,NewFileType,NewFlags,cpNormal); FreeAndNil(FNextSelectedPart); FNextSelectedPart:=TPENodeData.Create(penFile,NewFilename,false); end; function TPackageEditorForm.ShowNewCompDialog: TModalResult; var IgnoreUnitPaths: TFilenameToStringTree; function PkgDependsOn(PkgName: string): boolean; begin if PkgName='' then exit(false); Result:=PackageGraph.FindDependencyRecursively(LazPackage.FirstRequiredDependency,PkgName)<>nil; end; procedure AddNewComponent(AddParams: TAddToPkgResult); begin ExtendUnitIncPathForNewUnit(AddParams.UnitFilename, '', IgnoreUnitPaths); // add file with AddParams do begin Assert(FilenameIsAbsolute(UnitFilename), 'AddNewComponent: Filename is relative.'); // This file can also replace an existing file. if LazPackage.FindPkgFile(UnitFilename,true,false)=nil then LazPackage.AddFile(UnitFilename, Unit_Name, FileType, PkgFileFlags, cpNormal) else LazPackage.Modified:=True; FreeAndNil(FNextSelectedPart); FNextSelectedPart:=TPENodeData.Create(penFile, UnitFilename, false); PackageEditors.DeleteAmbiguousFiles(LazPackage, UnitFilename); end; // open file in editor PackageEditors.CreateNewFile(Self,AddParams); end; var AddParams, OldParams: TAddToPkgResult; begin if LazPackage.ReadOnly then begin UpdateButtons; exit(mrCancel); end; Result:=ShowAddToPackageDlg(LazPackage, AddParams); if Result<>mrOk then exit; PackageGraph.BeginUpdate(false); IgnoreUnitPaths:=nil; try while AddParams<>nil do begin AddNewComponent(AddParams); OldParams:=AddParams; AddParams:=AddParams.Next; OldParams.Next:=nil; OldParams.Free; end; AddParams.Free; Assert(LazPackage.Modified, 'TPackageEditorForm.ShowAddDialog: LazPackage.Modified = False'); finally IgnoreUnitPaths.Free; PackageGraph.EndUpdate; end; end; function TPackageEditorForm.ShowAddDepDialog: TModalResult; var Deps: TPkgDependencyList; i: Integer; begin if LazPackage.ReadOnly then begin UpdateButtons; exit(mrCancel); end; Result:=ShowAddPkgDependencyDlg(LazPackage, Deps); try if (Result<>mrOk) or (Deps.Count=0) then exit; PackageGraph.BeginUpdate(false); try // add all dependencies fForcedFlags := [pefNeedUpdateRequiredPkgs]; FreeAndNil(FNextSelectedPart); for i := 0 to Deps.Count-1 do PackageGraph.AddDependencyToPackage(LazPackage, Deps[i]); FNextSelectedPart := TPENodeData.Create(penDependency, Deps[Deps.Count-1].PackageName, false); Assert(LazPackage.Modified, 'TPackageEditorForm.ShowAddDepDialog: LazPackage.Modified = False'); finally PackageGraph.EndUpdate; end; finally Deps.Free; end; end; function TPackageEditorForm.ShowAddFPMakeDepDialog: TModalResult; var Deps: TPkgDependencyList; i: Integer; begin if LazPackage.ReadOnly then begin UpdateButtons; exit(mrCancel); end; Result:=ShowAddFPMakeDependencyDlg(LazPackage, Deps); try if (Result<>mrOk) or (Deps.Count=0) then exit; PackageGraph.BeginUpdate(false); try // add all dependencies fForcedFlags := [pefNeedUpdateRequiredPkgs]; FreeAndNil(FNextSelectedPart); for i := 0 to Deps.Count-1 do PackageGraph.AddDependencyToPackage(LazPackage, Deps[i]); FNextSelectedPart := TPENodeData.Create(penDependency, Deps[Deps.Count-1].PackageName, false); Assert(LazPackage.Modified, 'TPackageEditorForm.ShowAddFPMakeDepDialog: LazPackage.Modified = False'); finally PackageGraph.EndUpdate; end; finally Deps.Free; end; end; function TPackageEditorForm.PkgNameToFormName(const PkgName: string): string; begin Result:=PackageEditorWindowPrefix+StringReplace(PkgName,'.','_',[rfReplaceAll]); end; procedure TPackageEditorForm.BeginUpdate; begin inc(fUpdateLock); end; procedure TPackageEditorForm.EndUpdate; begin if fUpdateLock=0 then RaiseGDBException(''); dec(fUpdateLock); if fUpdateLock=0 then IdleConnected:=true; end; procedure TPackageEditorForm.UpdateTitle(Immediately: boolean); var NewCaption: String; s: string; begin if not CanUpdate(pefNeedUpdateTitle,Immediately) then exit; s:=FLazPackage.Name+' V'+FLazPackage.Version.AsString; NewCaption:=Format(lisPckEditPackage, [s]); if LazPackage.Modified then NewCaption:=NewCaption+'*'; Caption:=NewCaption; end; procedure TPackageEditorForm.UpdateButtons(Immediately: boolean); var i: Integer; TVNode: TTreeNode; NodeData: TPENodeData; Item: TObject; Writable: Boolean; ActiveFileCnt: Integer; ActiveDepCount: Integer; FileCount: Integer; DepCount: Integer; begin if not CanUpdate(pefNeedUpdateButtons,Immediately) then exit; FileCount:=0; DepCount:=0; ActiveFileCnt:=0; ActiveDepCount:=0; for i:=0 to ItemsTreeView.SelectionCount-1 do begin TVNode:=ItemsTreeView.Selections[i]; if not GetNodeDataItem(TVNode,NodeData,Item) then continue; if Item is TPkgFile then begin inc(FileCount); if not NodeData.Removed then inc(ActiveFileCnt); end else if Item is TPkgDependency then begin inc(DepCount); if not NodeData.Removed then inc(ActiveDepCount); end; end; Writable:=not LazPackage.ReadOnly; SaveBitBtn.Enabled:=Writable and (LazPackage.IsVirtual or LazPackage.Modified); CompileBitBtn.Enabled:=(not LazPackage.IsVirtual) and LazPackage.CompilerOptions.HasCommands; AddBitBtn.Enabled:=Writable; RemoveBitBtn.Enabled:=Writable and (ActiveFileCnt+ActiveDepCount>0); OpenButton.Enabled:=(FileCount+DepCount>0); end; function TPackageEditorForm.TreeViewGetImageIndex(Str: String; Data: TObject; var AIsEnabled: Boolean): Integer; var PkgFile: TPkgFile; Item: TObject; NodeData: TPENodeData; begin Result:=-1; if not (Data is TPENodeData) then exit; NodeData:=TPENodeData(Data); Item:=GetNodeItem(NodeData); if Item=nil then exit; if Item is TPkgFile then begin PkgFile:=TPkgFile(Item); case PkgFile.FileType of pftUnit,pftVirtualUnit,pftMainUnit: if PkgFile.HasRegisterProc then Result:=ImageIndexRegisterUnit else Result:=ImageIndexUnit; pftLFM: Result:=ImageIndexLFM; pftLRS: Result:=ImageIndexLRS; pftInclude: Result:=ImageIndexInclude; pftIssues: Result:=ImageIndexIssues; pftText: Result:=ImageIndexText; pftBinary: Result:=ImageIndexBinary; else Result:=-1{%H-}; end; end else if Item is TPkgDependency then Result:=FPropGui.GetDependencyImageIndex(TPkgDependency(Item)); end; procedure TPackageEditorForm.UpdatePending; var OldView: TPETVSelectedView; begin StoreItemsTVSelectedNode(OldView,false); try if pefNeedUpdateTitle in fFlags then UpdateTitle(true); if pefNeedUpdateFiles in fFlags then UpdateFiles(true); if pefNeedUpdateRemovedFiles in fFlags then UpdateRemovedFiles(true); if pefNeedUpdateRequiredPkgs in fFlags then UpdateRequiredPackages(true); if pefNeedUpdateProperties in fFlags then UpdatePEProperties(true); if pefNeedUpdateButtons in fFlags then UpdateButtons(true); //if pefNeedUpdateApplyDependencyButton in fFlags then // FPropGui.UpdateApplyDependencyButton(true); if pefNeedUpdateStatusBar in fFlags then UpdateStatusBar(true); with FPropGui.CallRegisterProcCheckBox do // adjust top of groupbox now. FPropGui.RegisteredPluginsGroupBox.Top := ScaleDesignToForm(Height); IdleConnected:=false; finally RestoreItemsTVSelectedNode(OldView); fForcedFlags:=[]; end; end; procedure TPackageEditorForm.StoreItemsTVSelectedNode(out OldView: TPETVSelectedView; StoreFilter: boolean); var SelNode: TTreeNode; begin if ItemsTreeView.Items.IsUpdating then begin OldView:=Default(TPETVSelectedView); end else begin ItemsTreeView.BeginUpdate; OldView.NeedEndUpdate:=true; OldView.OldScrollLeft:=ItemsTreeView.ScrolledLeft; OldView.OldScrollTop:=ItemsTreeView.ScrolledTop; OldView.OldNodePath:=''; SelNode:=ItemsTreeView.Selected; if SelNode<>nil then OldView.OldNodePath:=SelNode.GetTextPath; end; if StoreFilter and not OldView.RestoreFilter then begin OldView.RestoreFilter:=true; OldView.OldFilter:=FilterEdit.ForceFilter(''); end; end; procedure TPackageEditorForm.RestoreItemsTVSelectedNode( const OldView: TPETVSelectedView); var SelNode: TTreeNode; begin if not OldView.NeedEndUpdate then exit; // restore selected node and scroll position try if OldView.RestoreFilter then begin FilterEdit.Filter:=OldView.OldFilter; FilterEdit.InvalidateFilter; // Needed when OldFilter = '' end; SelNode:=ItemsTreeView.Selected; if (SelNode=nil) and (OldView.OldNodePath<>'') then ItemsTreeView.Selected:=ItemsTreeView.Items.FindNodeWithTextPath(OldView.OldNodePath); ItemsTreeView.ScrolledLeft:=OldView.OldScrollLeft; ItemsTreeView.ScrolledTop:=OldView.OldScrollTop; finally ItemsTreeView.EndUpdate; end; if OldView.RestoreFilter then begin UpdatePEProperties; UpdateButtons; end; end; function TPackageEditorForm.CanUpdate(Flag: TPEFlag; Immediately: boolean): boolean; begin Result:=false; if csDestroying in ComponentState then exit; if LazPackage=nil then exit; if (fUpdateLock>0) and not Immediately then begin Include(fFlags,Flag); IdleConnected:=true; end else begin Exclude(fFlags,Flag); Result:=true; end; end; procedure TPackageEditorForm.UpdateFiles(Immediately: boolean); var i: Integer; CurFile: TPkgFile; FilesBranch: TTreeFilterBranch; Filename: String; NodeData: TPENodeData; OldView: TPETVSelectedView; begin if not CanUpdate(pefNeedUpdateFiles,Immediately) then exit; StoreItemsTVSelectedNode(OldView,true); try // files belonging to package FilesBranch:=FilterEdit.GetCleanBranch(FFilesNode); FPropGui.FreeNodeData(penFile); FilesBranch.ClearNodeData; FilterEdit.SelectedPart:=nil; FilterEdit.ShowDirHierarchy:=ShowDirectoryHierarchy; FilterEdit.SortData:=SortAlphabetically; FilterEdit.ImageIndexDirectory:=ImageIndexDirectory; // collect and sort files for i:=0 to LazPackage.FileCount-1 do begin CurFile:=LazPackage.Files[i]; NodeData:=FPropGui.CreateNodeData(penFile,CurFile.Filename,false); NodeData.FileType:=CurFile.FileType; Filename:=CurFile.GetShortFilename(true); if Filename='' then continue; if (FNextSelectedPart<>nil) and (FNextSelectedPart.Typ=penFile) and (FNextSelectedPart.Name=NodeData.Name) then FilterEdit.SelectedPart:=NodeData; FilesBranch.AddNodeData(Filename, NodeData, CurFile.Filename); end; if (FNextSelectedPart<>nil) and (FNextSelectedPart.Typ=penFile) then FreeAndNil(FNextSelectedPart); finally RestoreItemsTVSelectedNode(OldView); end; end; procedure TPackageEditorForm.UpdateRemovedFiles(Immediately: boolean = false); var i: Integer; CurFile: TPkgFile; RemovedBranch: TTreeFilterBranch; NodeData: TPENodeData; OldView: TPETVSelectedView; begin if not CanUpdate(pefNeedUpdateRemovedFiles,Immediately) then exit; StoreItemsTVSelectedNode(OldView,true); try if LazPackage.RemovedFilesCount>0 then begin // Create root node for removed files if not done yet. if FRemovedFilesNode=nil then begin FRemovedFilesNode:=ItemsTreeView.Items.Add(FRequiredPackagesNode, lisPckEditRemovedFiles); FRemovedFilesNode.ImageIndex:=ImageIndexRemovedFiles; FRemovedFilesNode.SelectedIndex:=FRemovedFilesNode.ImageIndex; end; RemovedBranch:=FilterEdit.GetCleanBranch(FRemovedFilesNode); RemovedBranch.ClearNodeData; for i:=0 to LazPackage.RemovedFilesCount-1 do begin CurFile:=LazPackage.RemovedFiles[i]; NodeData:=FPropGui.CreateNodeData(penFile,CurFile.Filename,true); RemovedBranch.AddNodeData(CurFile.GetShortFilename(true), NodeData); end; RemovedBranch.InvalidateBranch; end else begin // No more removed files left -> delete the root node if FRemovedFilesNode<>nil then begin FilterEdit.DeleteBranch(FRemovedFilesNode); FilterEdit.InvalidateFilter; FreeAndNil(FRemovedFilesNode); end; end; finally RestoreItemsTVSelectedNode(OldView); end; end; procedure TPackageEditorForm.UpdateRequiredPackages(Immediately: boolean); var Dependency: TPkgDependency; RequiredBranch, RemovedBranch: TTreeFilterBranch; NodeData: TPENodeData; OldView: TPETVSelectedView; begin if not CanUpdate(pefNeedUpdateRequiredPkgs,Immediately) then exit; StoreItemsTVSelectedNode(OldView,true); try // required packages RequiredBranch:=FilterEdit.GetCleanBranch(FRequiredPackagesNode); RequiredBranch.ClearNodeData; FPropGui.FreeNodeData(penDependency); Dependency:=LazPackage.FirstRequiredDependency; FilterEdit.SelectedPart:=nil; while Dependency<>nil do begin NodeData:=FPropGui.CreateNodeData(penDependency,Dependency.PackageName,false); if (FNextSelectedPart<>nil) and (FNextSelectedPart.Typ=penDependency) and (FNextSelectedPart.Name=NodeData.Name) then FilterEdit.SelectedPart:=NodeData; RequiredBranch.AddNodeData(Dependency.AsString(False,True)+OPNote(Dependency), NodeData); Dependency:=Dependency.NextRequiresDependency; end; if (FNextSelectedPart<>nil) and (FNextSelectedPart.Typ=penDependency) then FreeAndNil(FNextSelectedPart); RequiredBranch.InvalidateBranch; // removed required packages Dependency:=LazPackage.FirstRemovedDependency; if Dependency<>nil then begin if FRemovedRequiredNode=nil then begin FRemovedRequiredNode:=ItemsTreeView.Items.Add(nil,lisPckEditRemovedRequiredPackages); FRemovedRequiredNode.ImageIndex:=FPropGui.ImageIndexRemovedRequired; FRemovedRequiredNode.SelectedIndex:=FRemovedRequiredNode.ImageIndex; end; RemovedBranch:=FilterEdit.GetCleanBranch(FRemovedRequiredNode); RemovedBranch.ClearNodeData; while Dependency<>nil do begin NodeData:=FPropGui.CreateNodeData(penDependency,Dependency.PackageName,true); RemovedBranch.AddNodeData(Dependency.AsString(False,True)+OPNote(Dependency), NodeData); Dependency:=Dependency.NextRequiresDependency; end; RemovedBranch.InvalidateBranch; end else begin if FRemovedRequiredNode<>nil then begin FilterEdit.DeleteBranch(FRemovedRequiredNode); FreeAndNil(FRemovedRequiredNode); end; end; FNextSelectedPart:=nil; finally RestoreItemsTVSelectedNode(OldView); end; end; procedure MergeMultiBool(var b: TMultiBool; NewValue: boolean); begin case b of mubNone : if NewValue then b:=mubAllTrue else b:=mubAllFalse; mubAllTrue : if not NewValue then b:=mubMixed; mubAllFalse: if NewValue then b:=mubMixed; mubMixed: ; end; end; procedure TPackageEditorForm.UpdatePEProperties(Immediately: boolean); var CurFile, SingleSelectedFile: TPkgFile; CurDependency, SingleSelectedDep: TPkgDependency; CurComponent: TPkgComponent; CurLine, CurFilename: string; TVNode, SingleSelectedDirectory, SingleSelectedNode: TTreeNode; NodeData: TPENodeData; Item: TObject; i, j: Integer; SelFileCount, SelDepCount, SelUnitCount, SelDirCount, SelHasLFMCount: Integer; FileCount, HasRegisterProcCount, AddToUsesPkgSectionCount: integer; SelHasRegisterProc, SelAddToUsesPkgSection, SelDisableI18NForLFM: TMultiBool; aVisible, OnlyFilesWithUnitsSelected, SingleSelectedRemoved: Boolean; begin if not CanUpdate(pefNeedUpdateProperties,Immediately) then exit; GuiToFileOptions(False); FPlugins.Clear; // check selection SingleSelectedNode:=nil; SingleSelectedDep:=nil; SingleSelectedFile:=nil; SingleSelectedDirectory:=nil; SingleSelectedRemoved:=false; SelFileCount:=0; SelDepCount:=0; SelHasRegisterProc:=mubNone; SelAddToUsesPkgSection:=mubNone; SelDisableI18NForLFM:=mubNone; SelUnitCount:=0; SelHasLFMCount:=0; SelDirCount:=0; for i:=0 to ItemsTreeView.SelectionCount-1 do begin TVNode:=ItemsTreeView.Selections[i]; if GetNodeDataItem(TVNode,NodeData,Item) then begin if Item is TPkgFile then begin CurFile:=TPkgFile(Item); inc(SelFileCount); SingleSelectedFile:=CurFile; SingleSelectedNode:=TVNode; SingleSelectedRemoved:=NodeData.Removed; MergeMultiBool(SelHasRegisterProc,CurFile.HasRegisterProc); if CurFile.FileType in PkgFileUnitTypes then begin inc(SelUnitCount); MergeMultiBool(SelAddToUsesPkgSection,CurFile.AddToUsesPkgSection); if CurFile.FileType in PkgFileRealUnitTypes then begin CurFilename:=CurFile.GetFullFilename; if FilenameIsAbsolute(CurFilename) and FileExistsCached(ChangeFileExt(CurFilename,'.lfm')) then begin inc(SelHasLFMCount); MergeMultiBool(SelDisableI18NForLFM,CurFile.DisableI18NForLFM); end; end; // fetch all registered plugins for j:=0 to CurFile.ComponentCount-1 do begin CurComponent:=CurFile.Components[j]; CurLine:=CurComponent.ComponentClass.ClassName; FPlugins.AddObject(CurLine,CurComponent); end; end; end else if Item is TPkgDependency then begin inc(SelDepCount); CurDependency:=TPkgDependency(Item); SingleSelectedDep:=CurDependency; SingleSelectedNode:=TVNode; SingleSelectedRemoved:=NodeData.Removed; end; end else if IsDirectoryNode(TVNode) or (TVNode=FFilesNode) then begin inc(SelDirCount); SingleSelectedDirectory:=TVNode; SingleSelectedNode:=TVNode; end //else if TVNode=FRequiredPackagesNode then // DebugLn('UpdatePEProperties: Required packages selected'); end; if (SelFileCount+SelDepCount+SelDirCount>1) then begin // it is a multi selection SingleSelectedFile:=nil; SingleSelectedDep:=nil; SingleSelectedDirectory:=nil; SingleSelectedNode:=nil; end; //debugln(['TPackageEditorForm.UpdatePEProperties SelFileCount=',SelFileCount,' SelDepCount=',SelDepCount,' SelDirCount=',SelDirCount,' SelUnitCount=',SelUnitCount]); //debugln(['TPackageEditorForm.UpdatePEProperties FSingleSelectedFile=',SingleSelectedFile<>nil,' FSingleSelectedDependency=',SingleSelectedDep<>nil,' SingleSelectedDirectory=',SingleSelectedDirectory<>nil]); OnlyFilesWithUnitsSelected:= (SelFileCount>0) and (SelDepCount=0) and (SelDirCount=0) and (SelUnitCount>0); FPropGui.ControlVisible := OnlyFilesWithUnitsSelected; FPropGui.ControlEnabled := not LazPackage.ReadOnly; DisableAlign; try FPropGui.SetAddToUsesCB(SelAddToUsesPkgSection); // 'Add to uses' of files FPropGui.SetCallRegisterProcCB(SelHasRegisterProc); // 'RegisterProc' of files FPropGui.SetRegisteredPluginsGB(FPlugins); // registered plugins // Min/Max version of dependency (only single selection) FPropGui.ControlVisible := SingleSelectedDep<>nil; FPropGui.SetMinMaxVisibility; // disable i18n for lfm FPropGui.ControlVisible := OnlyFilesWithUnitsSelected and (SelHasLFMCount>0) and LazPackage.EnableI18N and LazPackage.EnableI18NForLFM; FPropGui.SetDisableI18NCB(SelDisableI18NForLFM); // move up/down (only single selection) aVisible := (FilterEdit.Filter='') and (not (SortAlphabetically or SingleSelectedRemoved)) and ((SingleSelectedFile<>nil) or (SingleSelectedDep<>nil)); MoveUpBtn.Enabled :=aVisible and Assigned(SingleSelectedNode.GetPrevVisibleSibling); MoveDownBtn.Enabled:=aVisible and Assigned(SingleSelectedNode.GetNextVisibleSibling); // directory summary (only single selection) FDirSummaryLabel.Visible:=(SelFileCount=0) and (SelDepCount=0) and (SelDirCount=1); if SelFileCount>0 then begin PropsGroupBox.Enabled:=true; PropsGroupBox.Caption:=lisPckEditFileProperties; end else if SingleSelectedDep<>nil then begin PropsGroupBox.Enabled:=not SingleSelectedRemoved; PropsGroupBox.Caption:=lisPckEditDependencyProperties; FPropGui.SetMinMaxValues(SingleSelectedDep); FPropGui.UpdateApplyDependencyButton; end else if SingleSelectedDirectory<>nil then begin PropsGroupBox.Enabled:=true; PropsGroupBox.Caption:=lisPckEditFileProperties; GetDirectorySummary(SingleSelectedDirectory, FileCount,HasRegisterProcCount,AddToUsesPkgSectionCount); FDirSummaryLabel.Caption:=Format( lisFilesHasRegisterProcedureInPackageUsesSection, [IntToStr(FileCount), IntToStr(HasRegisterProcCount), IntToStr(AddToUsesPkgSectionCount)]); end else begin PropsGroupBox.Enabled:=false; PropsGroupBox.Caption:=lisPckEditDependencyProperties; end; if SingleSelectedFile<>nil then begin for i := 2 to PropsPageControl.PageCount -1 do PropsPageControl.pages[i].Visible := True; FileOptionsToGui; PropsPageControl.ShowTabs := PropsPageControl.PageCount > 1; end else begin for i := 2 to PropsPageControl.PageCount -1 do PropsPageControl.pages[i].Visible := False; PropsPageControl.ShowTabs := False; end; finally EnableAlign; end; end; function TPackageEditorForm.GetSingleSelectedDependency: TPkgDependency; var i: Integer; NodeData: TPENodeData; Item: TObject; begin Result:=nil; for i:=0 to ItemsTreeView.SelectionCount-1 do begin if not GetNodeDataItem(ItemsTreeView.Selections[i],NodeData,Item) then continue; if Item is TPkgDependency then begin if Result<>nil then Exit(nil); // not single selected Result:=TPkgDependency(Item); end else Exit(nil); end; end; function TPackageEditorForm.GetSingleSelectedFile: TPkgFile; var i: Integer; TVNode: TTreeNode; NodeData: TPENodeData; Item: TObject; begin Result:=nil; for i:=0 to ItemsTreeView.SelectionCount-1 do begin TVNode:=ItemsTreeView.Selections[i]; if not GetNodeDataItem(TVNode,NodeData,Item) then continue; if Item is TPkgFile then begin if Result<>nil then begin // not single selected Result:=nil; break; end; Result:=TPkgFile(Item); break; end else if Item is TPkgDependency then begin Result:=nil; break; end; end; end; function TPackageEditorForm.GetDependencyToUpdate(Immediately: boolean): TPkgDependencyID; begin if CanUpdate(pefNeedUpdateApplyDependencyButton,Immediately) then Result:=GetSingleSelectedDependency else Result:=nil; end; procedure TPackageEditorForm.UpdateStatusBar(Immediately: boolean); var StatusText: String; begin if not CanUpdate(pefNeedUpdateStatusBar,Immediately) then exit; if LazPackage.IsVirtual and (not LazPackage.ReadOnly) then begin StatusText:=Format(lisPckEditpackageNotSaved, [LazPackage.Name]); end else begin StatusText:=LazPackage.Filename; end; if LazPackage.ReadOnly then StatusText:=Format(lisPckEditReadOnly, [StatusText]); if LazPackage.Modified then StatusText:=Format(lisPckEditModified, [StatusText]); StatusBar.SimpleText:=StatusText; end; function TPackageEditorForm.GetNodeItem(NodeData: TPENodeData): TObject; begin Result:=nil; if (LazPackage=nil) or (NodeData=nil) then exit; case NodeData.Typ of penFile: if NodeData.Removed then Result:=LazPackage.FindRemovedPkgFile(NodeData.Name) else Result:=LazPackage.FindPkgFile(NodeData.Name,true,true); penDependency: if NodeData.Removed then Result:=LazPackage.FindRemovedDependencyByName(NodeData.Name) else Result:=LazPackage.FindDependencyByName(NodeData.Name); end; end; function TPackageEditorForm.GetNodeDataItem(TVNode: TTreeNode; out NodeData: TPENodeData; out Item: TObject): boolean; begin Result:=false; Item:=nil; NodeData:=GetNodeData(TVNode); Item:=GetNodeItem(NodeData); Result:=Item<>nil; end; function TPackageEditorForm.IsDirectoryNode(Node: TTreeNode): boolean; begin Result:=(Node<>nil) and (Node.Data=nil) and Node.HasAsParent(FFilesNode); end; function TPackageEditorForm.GetNodeFilename(Node: TTreeNode): string; var Item: TFileNameItem; begin Result:=''; if Node=nil then exit; if Node=FFilesNode then exit(FilesBaseDirectory); Item:=TFileNameItem(Node.Data); if (Item is TFileNameItem) then begin Result:=Item.Filename; end else if Node.HasAsParent(FFilesNode) then begin // directory node Result:=Node.Text; end else exit; if not FilenameIsAbsolute(Result) then Result:=AppendPathDelim(FilesBaseDirectory)+Result; end; procedure TPackageEditorForm.GetDirectorySummary(DirNode: TTreeNode; out FileCount, HasRegisterProcCount, AddToUsesPkgSectionCount: integer); procedure Traverse(Node: TTreeNode); var CurFile: TPkgFile; NodeData: TPENodeData; begin NodeData:=GetNodeData(Node); if NodeData<>nil then begin if NodeData.Typ=penFile then begin CurFile:=LazPackage.FindPkgFile(NodeData.Name,true,true); if CurFile<>nil then begin inc(FileCount); if CurFile.HasRegisterProc then inc(HasRegisterProcCount); if CurFile.AddToUsesPkgSection then inc(AddToUsesPkgSectionCount); end; end; end; Node:=Node.GetFirstChild; while Node<>nil do begin Traverse(Node); Node:=Node.GetNextSibling; end; end; begin FileCount:=0; HasRegisterProcCount:=0; AddToUsesPkgSectionCount:=0; Traverse(DirNode); end; procedure TPackageEditorForm.ExtendUnitIncPathForNewUnit(const AnUnitFilename, AnIncludeFile: string; var IgnoreUnitPaths: TFilenameToStringTree); var NewDirectory: String; UnitPath: String; ShortDirectory: String; NewIncDirectory: String; ShortIncDirectory: String; IncPath: String; UnitPathPos: Integer; IncPathPos: Integer; begin if LazPackage=nil then exit; // check if directory is already in the unit path of the package NewDirectory:=ExtractFilePath(AnUnitFilename); ShortDirectory:=NewDirectory; LazPackage.ShortenFilename(ShortDirectory,true); if ShortDirectory='' then exit; ShortIncDirectory:=''; LazPackage.LongenFilename(NewDirectory); NewDirectory:=ChompPathDelim(NewDirectory); UnitPath:=LazPackage.GetUnitPath(false); UnitPathPos:=SearchDirectoryInMaskedSearchPath(UnitPath,NewDirectory); IncPathPos:=1; if AnIncludeFile<>'' then begin NewIncDirectory:=ChompPathDelim(ExtractFilePath(AnIncludeFile)); ShortIncDirectory:=NewIncDirectory; LazPackage.ShortenFilename(ShortIncDirectory,false); if ShortIncDirectory<>'' then begin LazPackage.LongenFilename(NewIncDirectory); NewIncDirectory:=ChompPathDelim(NewIncDirectory); IncPath:=LazPackage.GetIncludePath(false); IncPathPos:=SearchDirectoryInMaskedSearchPath(IncPath,NewIncDirectory); end; end; if UnitPathPos<1 then begin // ask user to add the unit path if (IgnoreUnitPaths<>nil) and (IgnoreUnitPaths.Contains(ShortDirectory)) then exit; if MessageDlg(lisPkgEditNewUnitNotInUnitpath, Format(lisPkgEditTheFileIsCurrentlyNotInTheUnitpathOfThePackage, [AnUnitFilename, LineEnding, LineEnding+LineEnding, ShortDirectory]), mtConfirmation,[mbYes,mbNo],0)<>mrYes then begin if IgnoreUnitPaths=nil then IgnoreUnitPaths:=TFilenameToStringTree.Create(false); IgnoreUnitPaths.Add(ShortDirectory,''); exit; end; // add path LazPackage.CompilerOptions.MergeToUnitPaths(ShortDirectory); end; if IncPathPos<1 then // the unit is in unitpath, but the include file not in the incpath // -> auto extend the include path LazPackage.CompilerOptions.MergeToIncludePaths(ShortIncDirectory); end; procedure TPackageEditorForm.ExtendIncPathForNewIncludeFile( const AnIncludeFile: string; var IgnoreIncPaths: TFilenameToStringTree); var NewDirectory: String; ShortDirectory: String; IncPath: String; IncPathPos: LongInt; begin if LazPackage=nil then exit; // check if directory is already in the unit path of the package NewDirectory:=ExtractFilePath(AnIncludeFile); ShortDirectory:=NewDirectory; LazPackage.ShortenFilename(ShortDirectory,false); if ShortDirectory='' then exit; LazPackage.LongenFilename(NewDirectory); NewDirectory:=ChompPathDelim(NewDirectory); IncPath:=LazPackage.GetIncludePath(false); IncPathPos:=SearchDirectoryInMaskedSearchPath(IncPath,NewDirectory); if IncPathPos>0 then exit; // ask user to add the unit path if (IgnoreIncPaths<>nil) and (IgnoreIncPaths.Contains(ShortDirectory)) then exit; if MessageDlg(lisPENewFileNotInIncludePath, Format(lisPETheFileIsCurrentlyNotInTheIncludePathOfThePackageA, [AnIncludeFile, LineEnding, ShortDirectory]), mtConfirmation,[mbYes,mbNo],0)<>mrYes then begin if IgnoreIncPaths=nil then IgnoreIncPaths:=TFilenameToStringTree.Create(false); IgnoreIncPaths.Add(ShortDirectory,''); exit; end; // add path LazPackage.CompilerOptions.MergeToIncludePaths(ShortDirectory); end; function TPackageEditorForm.ExtendUnitSearchPath(NewUnitPaths: string): boolean; begin Result:=LazPackage.ExtendUnitSearchPath(NewUnitPaths); end; function TPackageEditorForm.ExtendIncSearchPath(NewIncPaths: string): boolean; begin Result:=LazPackage.ExtendIncSearchPath(NewIncPaths); end; function TPackageEditorForm.FilesEditTreeView: TTreeView; begin Result:=ItemsTreeView; end; function TPackageEditorForm.FilesEditForm: TCustomForm; begin Result:=Self; end; function TPackageEditorForm.FilesOwner: TObject; begin Result:=LazPackage; end; function TPackageEditorForm.FilesOwnerName: string; begin Result:=Format(lisPackage2, [LazPackage.Name]); end; function TPackageEditorForm.TVNodeFiles: TTreeNode; begin Result:=FFilesNode; end; function TPackageEditorForm.TVNodeRequiredPackages: TTreeNode; begin Result:=FRequiredPackagesNode; end; function TPackageEditorForm.FilesBaseDirectory: string; begin Result:=LazPackage.DirectoryExpanded; end; function TPackageEditorForm.FilesOwnerReadOnly: boolean; begin Result:=LazPackage.ReadOnly; end; procedure TPackageEditorForm.FilterEditAfterFilter(Sender: TObject); var LPackage: TIDEPackage; begin if Assigned(SourceEditorManagerIntf) and Assigned(PackageEditingInterface) and Assigned(SourceEditorManagerIntf.ActiveEditor) then begin PackageEditingInterface.GetPackageOfSourceEditor(LPackage, SourceEditorManagerIntf.ActiveEditor); if (LPackage is TLazPackage) and (TLazPackage(LPackage).Editor = Self) then SelectFileNode(SourceEditorManagerIntf.ActiveEditor.FileName); end; end; function TPackageEditorForm.FirstRequiredDependency: TPkgDependency; begin Result:=LazPackage.FirstRequiredDependency; end; function TPackageEditorForm.CanBeAddedToProject: boolean; begin if LazPackage=nil then exit(false); Result:=PackageEditors.AddToProject(LazPackage,true)=mrOk; end; procedure TPackageEditorForm.PackageListAvailable(Sender: TObject); begin //DebugLn(['TPackageEditorForm.PackageListAvailable: ', LazPackage.Name]); UpdateRequiredPackages; end; procedure TPackageEditorForm.DoSave(SaveAs: boolean); begin GuiToFileOptions(False); PackageEditors.SavePackage(LazPackage,SaveAs); UpdateTitle; UpdateButtons; UpdateStatusBar; end; procedure TPackageEditorForm.DoCompile(CompileClean, CompileRequired, WarnIDEPkg: boolean); var MsgResult: Integer; begin if WarnIDEPkg and not FCompileDesignTimePkg and (LazPackage.PackageType=lptDesignTime) then begin MsgResult:=IDEQuestionDialog(dlgMsgWinColorUrgentWarning, Format(lisPackageIsDesigntimeOnlySoItShouldOnlyBeCompiledInt, [ LazPackage.Name, #13]), mtWarning, [mrYes, lisCompileWithProjectSettings, mrYesToAll, lisCompileAndDoNotAskAgain, mrCancel]); case MsgResult of mrYes: ; mrYesToAll: FCompileDesignTimePkg:=true; // store setting only while running the IDE // when IDE restarts, ask again else exit; end; end; CompileBitBtn.Enabled:=False; FCompiling:=True; PackageEditors.CompilePackage(LazPackage,CompileClean,CompileRequired); FCompiling:=False; UpdateTitle; UpdateButtons; UpdateStatusBar; end; procedure TPackageEditorForm.DoFindInFiles; begin PackageEditors.FindInFiles(LazPackage); end; procedure TPackageEditorForm.DoRevert; begin if MessageDlg(lisPkgEditRevertPackage, Format(lisPkgEditDoYouReallyWantToForgetAllChangesToPackageAnd, [LazPackage.IDAsString]), mtConfirmation,[mbYes,mbNo],0)<>mrYes then exit; PackageEditors.RevertPackage(LazPackage); UpdateAll(false); end; procedure TPackageEditorForm.DoPublishPackage; begin PackageEditors.PublishPackage(LazPackage); end; procedure TPackageEditorForm.DoEditVirtualUnit; var PkgFile: TPkgFile; begin if LazPackage=nil then exit; PkgFile:=GetSingleSelectedFile; if (PkgFile=nil) or (PkgFile.FileType<>pftVirtualUnit) or (LazPackage.IndexOfPkgFile(PkgFile)<0) then exit; if ShowEditVirtualPackageDialog(PkgFile)=mrOk then UpdateFiles; end; procedure TPackageEditorForm.DoExpandCollapseDirectory(ExpandIt: Boolean); var CurNode: TTreeNode; begin CurNode:=ItemsTreeView.Selected; if not (IsDirectoryNode(CurNode) or (CurNode=FFilesNode)) then exit; ItemsTreeView.BeginUpdate; if ExpandIt then CurNode.Expand(true) else CurNode.Collapse(true); ItemsTreeView.EndUpdate; end; procedure TPackageEditorForm.DoUseUnitsInDirectory(Use: boolean); procedure Traverse(Node: TTreeNode); var PkgFile: TPkgFile; NodeData: TPENodeData; begin NodeData:=GetNodeData(Node); if (NodeData<>nil) and (NodeData.Typ=penFile) then begin PkgFile:=LazPackage.FindPkgFile(NodeData.Name,true,true); if (PkgFile<>nil) and (PkgFile.FileType in [pftUnit,pftVirtualUnit]) then begin if PkgFile.AddToUsesPkgSection<>Use then begin PkgFile.AddToUsesPkgSection:=Use; LazPackage.Modified:=true; end; end; end; Node:=Node.GetFirstChild; while Node<>nil do begin Traverse(Node); Node:=Node.GetNextSibling; end; end; var CurNode: TTreeNode; begin if not ShowDirectoryHierarchy then exit; CurNode:=ItemsTreeView.Selected; if not (IsDirectoryNode(CurNode) or (CurNode=FFilesNode)) then exit; Traverse(CurNode); UpdatePEProperties; end; procedure TPackageEditorForm.DoMoveCurrentFile(Offset: integer); var OldIndex, NewIndex: Integer; FilesBranch: TTreeFilterBranch; PkgFile: TPkgFile; begin PkgFile:=GetSingleSelectedFile; if (LazPackage=nil) or (PkgFile=nil) then exit; OldIndex:=LazPackage.IndexOfPkgFile(PkgFile); if OldIndex<0 then exit; NewIndex:=OldIndex+Offset; if (NewIndex<0) or (NewIndex>=LazPackage.FileCount) then exit; FilesBranch:=FilterEdit.GetExistingBranch(FFilesNode); LazPackage.MoveFile(OldIndex,NewIndex); FilesBranch.Move(OldIndex,NewIndex); UpdatePEProperties; UpdateStatusBar; end; procedure TPackageEditorForm.DoMoveDependency(Offset: integer); var OldIndex, NewIndex: Integer; RequiredBranch: TTreeFilterBranch; Moved: Boolean; Dependency: TPkgDependency; begin Dependency:=GetSingleSelectedDependency; if (LazPackage=nil) or (Dependency=nil) then exit; if Offset<0 then Moved := LazPackage.MoveRequiredDependencyUp(Dependency) else Moved := LazPackage.MoveRequiredDependencyDown(Dependency); if not Moved then exit; RequiredBranch:=FilterEdit.GetExistingBranch(FRequiredPackagesNode); OldIndex:=RequiredBranch.Items.IndexOf(Dependency.AsString(False,True)+OPNote(Dependency)); NewIndex:=OldIndex+Offset; RequiredBranch.Move(OldIndex,NewIndex); UpdatePEProperties; UpdateStatusBar; end; procedure TPackageEditorForm.DoSortFiles; var TreeSelection: TStringList; begin TreeSelection:=ItemsTreeView.StoreCurrentSelection; LazPackage.SortFiles; ItemsTreeView.ApplyStoredSelection(TreeSelection); end; procedure TPackageEditorForm.DoFixFilesCase; begin LazPackage.FixFilesCaseSensitivity; end; procedure TPackageEditorForm.DoShowMissingFiles; begin ShowMissingPkgFilesDialog(LazPackage); end; constructor TPackageEditorForm.Create(TheOwner: TComponent); begin inherited Create(TheOwner); end; destructor TPackageEditorForm.Destroy; begin inherited Destroy; end; function TPackageEditorForm.CanCloseEditor: TModalResult; var MsgResult: Integer; begin Result:=mrOK; //debugln(['TPackageEditorForm.CanCloseEditor ',Caption]); if (LazPackage<>nil) and (not (lpfDestroying in LazPackage.Flags)) then begin if LazPackage.ReadOnly then LazPackage.Modified:=false // clear modified flag, so that it will be closed else if LazPackage.Modified then begin MsgResult:=MessageDlg(lisPkgMangSavePackage, Format(lisPckEditPackageHasChangedSavePackage, [LazPackage.IDAsString, LineEnding]), mtConfirmation,[mbYes,mbNo,mbAbort],0); case MsgResult of mrYes: MsgResult:=PackageEditors.SavePackage(LazPackage,false); mrNo: LazPackage.UserIgnoreChangeStamp:=LazPackage.ChangeStamp; end; if MsgResult=mrAbort then Result:=mrAbort else LazPackage.Modified:=false; // clear modified flag, so that it will be closed end; if not MainIDE.IDEIsClosing then begin if FCompiling then begin DebugLn(['TPackageEditorForm.CanCloseEditor: ', Caption, ' compiling, do not close.']); Result:=mrCancel; end; if Result=mrOK then begin EnvironmentOptions.LastOpenPackages.Remove(LazPackage.Filename); MainIDE.SaveEnvironment; end; end; end; //debugln(['TPackageEditorForm.CanCloseEditor Result=',dbgs(Result),' ',Caption]); end; procedure TPackageEditorForm.TraverseSettings(AOptions: TAbstractPackageFileIDEOptions; anAction: TIDEPackageOptsDlgAction); procedure Traverse(Control: TWinControl); var i: Integer; begin if Control <> nil then begin if Control is TAbstractIDEOptionsEditor then with TAbstractIDEOptionsEditor(Control) do case anAction of iodaRead: ReadSettings(AOptions); iodaWrite: WriteSettings(AOptions); iodaRestore: RestoreSettings(AOptions); end; for i := 0 to Control.ControlCount -1 do if Control.Controls[i] is TWinControl then Traverse(TWinControl(Control.Controls[i])); end; end; begin Traverse(PropsPageControl); end; procedure TPackageEditorForm.CreatePackageFileEditors; var Instance: TAbstractIDEOptionsEditor; i, j: integer; Rec: PIDEOptionsGroupRec; AGroupCaption: string; ACaption: string; ItemTabSheet: TTabSheet; begin IDEEditorGroups.Resort; for i := 0 to IDEEditorGroups.Count - 1 do begin Rec := IDEEditorGroups[i]; //DebugLn(['TPackageEditorForm.CreatePackageFileEditors ',Rec^.GroupClass.ClassName]); if PassesFilter(Rec) then begin if Rec^.GroupClass<>nil then AGroupCaption := Rec^.GroupClass.GetGroupCaption else AGroupCaption := ''; for j := 0 to Rec^.Items.Count - 1 do begin ItemTabSheet := PropsPageControl.AddTabSheet; ItemTabSheet.Align := alClient; Instance := Rec^.Items[j]^.EditorClass.Create(Self); // Instance.OnLoadIDEOptions := @LoadIDEOptions; // Instance.OnSaveIDEOptions := @SaveIDEOptions; // In principle the parameter should be a TAbstractOptionsEditorDialog, // but in this case this is not available, so pass nil. // Better would be to change the structure of the classes to avoid this // problem. Instance.Setup(Nil); Instance.OnChange := @FileOptionsChange; Instance.Tag := Rec^.Items[j]^.Index; Instance.Parent := ItemTabSheet; Instance.Rec := Rec^.Items[j]; ACaption := Instance.GetTitle; if AGroupCaption <> ACaption then ACaption := AGroupCaption + ' - ' + ACaption; ItemTabSheet.Caption := ACaption; end; end; end; end; procedure TPackageEditorForm.FileOptionsToGui; type TStage = (sBefore, sRead, sAfter); var i: integer; Rec: PIDEOptionsGroupRec; InstCls: TAbstractPackageFileIDEOptionsClass; Instance: TAbstractPackageFileIDEOptions; InstanceList: TFPList; stag: TStage; PkgFile: TPkgFile; begin PkgFile:=GetSingleSelectedFile; if not Assigned(PkgFile) then exit; FOptionsShownOfFile := PkgFile; for stag:=low(TStage) to High(TStage) do begin InstanceList:=TFPList.Create; for i := 0 to IDEEditorGroups.Count - 1 do begin Rec := IDEEditorGroups[i]; if not PassesFilter(Rec) then Continue; InstCls := TAbstractPackageFileIDEOptionsClass(Rec^.GroupClass); Instance := TAbstractPackageFileIDEOptions(InstCls.GetInstance(LazPackage, FOptionsShownOfFile)); if (InstanceList.IndexOf(Instance)<0) and Assigned(Instance) then begin InstanceList.Add(Instance); case stag of sBefore: Instance.DoBeforeRead; sRead: TraverseSettings(Instance,iodaRead); sAfter: Instance.DoAfterRead; end; end; end; if stag=sRead then TraverseSettings(nil,iodaRead); // load settings that does not belong to any group InstanceList.Free; end; end; procedure TPackageEditorForm.GuiToFileOptions(Restore: boolean); type TStage = (sBefore, sWrite, sAfter); var i: integer; Rec: PIDEOptionsGroupRec; InstCls: TAbstractPackageFileIDEOptionsClass; Instance: TAbstractPackageFileIDEOptions; stag: TStage; begin if Assigned(FOptionsShownOfFile) then begin for stag:=low(TStage) to High(TStage) do begin for i := 0 to IDEEditorGroups.Count - 1 do begin Rec := IDEEditorGroups[i]; if not PassesFilter(Rec) then Continue; InstCls := TAbstractPackageFileIDEOptionsClass(Rec^.GroupClass); Instance := TAbstractPackageFileIDEOptions(InstCls.GetInstance(LazPackage, FOptionsShownOfFile)); if Assigned(Instance) then begin case stag of sBefore: Instance.DoBeforeWrite(Restore); sWrite: if Restore then TraverseSettings(Instance,iodaRestore) else TraverseSettings(Instance,iodaWrite); sAfter: Instance.DoAfterWrite(Restore); end; end; end; // save settings that do not belong to any group if stag=sWrite then if Restore then TraverseSettings(nil,iodaRestore) else TraverseSettings(nil,iodaWrite); end; end; end; procedure TPackageEditorForm.FileOptionsChange(Sender: TObject); begin LazPackage.Modified := True; end; function TPackageEditorForm.PassesFilter(rec: PIDEOptionsGroupRec): Boolean; begin Result := (Rec^.GroupClass.InheritsFrom(TAbstractPackageFileIDEOptions)) and (Rec^.Items <> nil); end; { TPackageEditors } function TPackageEditors.GetEditors(Index: integer): TPackageEditorForm; begin Result:=TPackageEditorForm(FItems[Index]); end; function TPackageEditors.IndexOfPackage(const PkgName: string): integer; var I: Integer; begin for I := 0 to Count-1 do if Assigned(Editors[I].LazPackage) and SameText(ExtractFileNameOnly(Editors[I].LazPackage.Filename), PkgName) then Exit(I); Result := -1; end; constructor TPackageEditors.Create; begin FItems:=TFPList.Create; end; procedure TPackageEditors.ActiveEditorChanged(Sender: TObject); var LPackage: TIDEPackage; LForm: TPackageEditorForm; begin if Assigned(SourceEditorManagerIntf.ActiveEditor) then begin PackageEditingInterface.GetPackageOfSourceEditor(LPackage, SourceEditorManagerIntf.ActiveEditor); if (LPackage is TLazPackage) and (TLazPackage(LPackage).Editor is TPackageEditorForm) then begin LForm := TPackageEditorForm(TLazPackage(LPackage).Editor); LForm.SelectFileNode(SourceEditorManagerIntf.ActiveEditor.FileName); end; end; end; destructor TPackageEditors.Destroy; begin if SourceEditorManagerIntf <> nil then SourceEditorManagerIntf.UnRegisterChangeEvent(semEditorActivate,@ActiveEditorChanged); Clear; FreeAndNil(FItems); inherited Destroy; end; function TPackageEditors.Count: integer; begin Result:=FItems.Count; end; procedure TPackageEditors.Clear; begin FItems.Clear; end; procedure TPackageEditors.Remove(Editor: TPackageEditorForm); begin if FItems<>nil then FItems.Remove(Editor); end; function TPackageEditors.IndexOfPackage(Pkg: TLazPackage): integer; begin Result:=Count-1; while (Result>=0) and (Editors[Result].LazPackage<>Pkg) do dec(Result); end; function TPackageEditors.FindEditor(Pkg: TLazPackage): TPackageEditorForm; var i: Integer; begin i:=IndexOfPackage(Pkg); if i>=0 then Result:=Editors[i] else Result:=nil; end; function TPackageEditors.CreateEditor(Pkg: TLazPackage; DoDisableAutoSizing: boolean): TPackageEditorForm; begin Result:=FindEditor(Pkg); if Result<>nil then begin if DoDisableAutoSizing then Result.DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TAnchorDockMaster Delayed'){$ENDIF}; end else begin Result:=TPackageEditorForm(TPackageEditorForm.NewInstance); {$IFDEF DebugDisableAutoSizing} if DoDisableAutoSizing then Result.DisableAutoSizing('TAnchorDockMaster Delayed') else Result.DisableAutoSizing('TPackageEditors.OpenEditor'); {$ELSE} Result.DisableAutoSizing; {$ENDIF} Result.Create(LazarusIDE.OwningComponent); Result.LazPackage:=Pkg; FItems.Add(Result); if not DoDisableAutoSizing then Result.EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TPackageEditors.OpenEditor'){$ENDIF}; end; end; function TPackageEditors.OpenEditor(Pkg: TLazPackage; BringToFront: boolean ): TPackageEditorForm; begin Result:=CreateEditor(Pkg,true); try IDEWindowCreators.ShowForm(Result, BringToFront); finally Result.EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TAnchorDockMaster Delayed'){$ENDIF}; end; end; function TPackageEditors.OpenFile(Sender: TObject; const Filename: string): TModalResult; begin if Assigned(OnOpenFile) then Result:=OnOpenFile(Sender,Filename) else Result:=mrCancel; end; function TPackageEditors.OpenPkgFile(Sender: TObject; PkgFile: TPkgFile): TModalResult; begin if Assigned(OnOpenPkgFile) then Result:=OnOpenPkgFile(Sender,PkgFile) else Result:=mrCancel; end; function TPackageEditors.OpenDependency(Sender: TObject; Dependency: TPkgDependency): TModalResult; var APackage: TLazPackage; begin Result:=mrCancel; if PackageGraph.OpenDependency(Dependency,false)=lprSuccess then begin if Dependency.DependencyType=pdtLazarus then begin APackage:=Dependency.RequiredPackage; if Assigned(OnOpenPackage) then Result:=OnOpenPackage(Sender,APackage); end else ShowMessage('It is not possible to open FPMake packages.'); end; end; procedure TPackageEditors.DoFreeEditor(Pkg: TLazPackage); begin if FItems<>nil then FItems.Remove(Pkg.Editor); if Assigned(OnFreeEditor) then OnFreeEditor(Pkg); end; function TPackageEditors.FindEditor(const PkgName: string): TPackageEditorForm; var i: Integer; begin i:=IndexOfPackage(PkgName); if i>=0 then Result:=Editors[i] else Result:=nil; end; function TPackageEditors.CreateNewFile(Sender: TObject; Params: TAddToPkgResult): TModalResult; begin Result:=mrCancel; if Assigned(OnCreateNewFile) then Result:=OnCreateNewFile(Sender,Params) else Result:=mrCancel; end; function TPackageEditors.SavePackage(APackage: TLazPackage; SaveAs: boolean): TModalResult; begin if Assigned(OnSavePackage) then Result:=OnSavePackage(Self,APackage,SaveAs) else Result:=mrCancel; end; function TPackageEditors.CompilePackage(APackage: TLazPackage; CompileClean, CompileRequired: boolean): TModalResult; begin if Assigned(OnCompilePackage) then Result:=OnCompilePackage(Self,APackage,CompileClean,CompileRequired) else Result:=mrCancel; end; procedure TPackageEditors.UpdateAllEditors(Immediately: boolean); var i: Integer; begin for i:=0 to Count-1 do Editors[i].UpdateAll(Immediately); end; function TPackageEditors.ShouldNotBeInstalled(APackage: TLazPackage): boolean; var Dep: TPkgDependency; CurPkg: TLazPackage; begin if APackage.Missing then exit(true) else if (APackage.FindUnitWithRegister<>nil) or (APackage.Provides.Count>0) then exit(false); Dep:=APackage.FirstRequiredDependency; while Dep<>nil do begin CurPkg:=Dep.RequiredPackage; if (CurPkg<>nil) then begin if (CurPkg.FindUnitWithRegister<>nil) or (CurPkg.Provides.Count>0) then exit(false); end; Dep:=Dep.NextRequiresDependency; end; Result:=true; end; function TPackageEditors.InstallPackage(APackage: TLazPackage): TModalResult; begin if ShouldNotBeInstalled(APackage) then begin if IDEQuestionDialog(lisNotAnInstallPackage, Format(lisThePackageDoesNotHaveAnyRegisterProcedureWhichTypi, [APackage.Name, LineEnding+LineEnding]), mtWarning, [mrIgnore, lisInstallItILikeTheFat, mrCancel, lisCancel], '') <> mrIgnore then exit(mrCancel); end; if Assigned(OnInstallPackage) then Result:=OnInstallPackage(Self,APackage) else Result:=mrCancel; end; function TPackageEditors.UninstallPackage(APackage: TLazPackage): TModalResult; begin if Assigned(OnUninstallPackage) then Result:=OnUninstallPackage(Self,APackage) else Result:=mrCancel; end; function TPackageEditors.ViewPkgSource(APackage: TLazPackage): TModalResult; begin if Assigned(OnViewPackageSource) then Result:=OnViewPackageSource(Self,APackage) else Result:=mrCancel; end; function TPackageEditors.ViewPkgToDos(APackage: TLazPackage): TModalResult; begin if Assigned(OnViewPackageToDos) then Result:=OnViewPackageToDos(Self,APackage) else Result:=mrCancel; end; function TPackageEditors.FindInFiles(APackage: TLazPackage): TModalResult; begin if Assigned(OnShowFindInFiles) then Result:=OnShowFindInFiles(Self,APackage) else Result:=mrCancel; end; function TPackageEditors.DeleteAmbiguousFiles(APackage: TLazPackage; const Filename: string): TModalResult; begin if Assigned(OnDeleteAmbiguousFiles) then Result:=OnDeleteAmbiguousFiles(Self,APackage,Filename) else Result:=mrOk; end; function TPackageEditors.AddToProject(APackage: TLazPackage; OnlyTestIfPossible: boolean): TModalResult; begin if Assigned(OnAddToProject) then Result:=OnAddToProject(Self,APackage,OnlyTestIfPossible) else Result:=mrCancel; end; function TPackageEditors.CreateMakefile(APackage: TLazPackage): TModalResult; begin if Assigned(OnCreateMakeFile) then Result:=OnCreateMakeFile(Self,APackage) else Result:=mrCancel; end; function TPackageEditors.CreateFpmakeFile(APackage: TLazPackage): TModalResult; begin if Assigned(OnCreateFpmakefile) then Result:=OnCreateFpmakefile(Self,APackage) else Result:=mrCancel; end; function TPackageEditors.TreeViewToPkgEditor(TV: TTreeView): TPackageEditorForm; var aParent: TWinControl; begin Result:=nil; if TV.Name<>'ItemsTreeView' then exit; aParent:=TV; repeat if aParent=nil then exit; aParent:=aParent.Parent; until aParent is TPackageEditorForm; Result:=TPackageEditorForm(aParent); end; function TPackageEditors.RevertPackage(APackage: TLazPackage): TModalResult; begin if Assigned(OnRevertPackage) then Result:=OnRevertPackage(Self,APackage) else Result:=mrCancel; end; function TPackageEditors.PublishPackage(APackage: TLazPackage): TModalResult; begin if Assigned(OnPublishPackage) then Result:=OnPublishPackage(Self,APackage) else Result:=mrCancel; end; initialization PackageEditors:=nil; IDEWindowsGlobalOptions.Add(PackageEditorWindowPrefix, False); end.