1 {
2  ***************************************************************************
3  *                                                                         *
4  *   This source is free software; you can redistribute it and/or modify   *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This code is distributed in the hope that it will be useful, but      *
10  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
12  *   General Public License for more details.                              *
13  *                                                                         *
14  *   A copy of the GNU General Public License is available on the World    *
15  *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
16  *   obtain it by writing to the Free Software Foundation,                 *
17  *   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.   *
18  *                                                                         *
19  ***************************************************************************
20 
21   Author: Mattias Gaertner
22 
23   Abstract:
24     TPackageEditorForm is the form of a package editor.
25 }
26 unit PackageEditor;
27 
28 {$mode objfpc}{$H+}
29 
30 {off $DEFINE VerbosePkgEditDrag}
31 
32 interface
33 
34 uses
35   // RTL, FCL
36   Classes, SysUtils, contnrs,
37   // LCL
38   Forms, Controls, StdCtrls, ComCtrls, Buttons, Graphics, Menus, Dialogs,
39   ExtCtrls, LCLType, LCLProc,
40   TreeFilterEdit,
41   // LazUtils
42   FileUtil, LazFileUtils, LazFileCache, AvgLvlTree,
43   // IDEIntf
44   IDEImagesIntf, MenuIntf, LazIDEIntf, ProjectIntf,
45   FormEditingIntf, PackageDependencyIntf, PackageIntf, IDEHelpIntf, IDEOptionsIntf,
46   NewItemIntf, IDEWindowIntf, IDEDialogs, ComponentReg,
47   // IDE
48   MainBase, IDEProcs, LazarusIDEStrConsts, IDEDefs, CompilerOptions,
49   EnvironmentOpts, DialogProcs, InputHistory, PackageDefs, AddToPackageDlg,
50   AddPkgDependencyDlg, AddFPMakeDependencyDlg, ProjPackChecks, PkgVirtualUnitEditor,
51   MissingPkgFilesDlg, PackageSystem, CleanPkgDeps, ImgList;
52 
53 const
54   PackageEditorMenuRootName = 'PackageEditor';
55   PackageEditorMenuFilesRootName = 'PackageEditorFiles';
56   PackageEditorWindowPrefix = 'PackageEditor_';
57 var
58   // General actions for the Files and Required packages root nodes.
59   // Duplicates actions found under the "Add" button.
60   PkgEditMenuAddDiskFile: TIDEMenuCommand;
61   PkgEditMenuAddNewFile: TIDEMenuCommand;
62   PkgEditMenuAddNewComp: TIDEMenuCommand;
63   PkgEditMenuAddNewReqr: TIDEMenuCommand;
64   PkgEditMenuAddNewFPMakeReqr: TIDEMenuCommand;
65 
66   // selected files
67   PkgEditMenuOpenFile: TIDEMenuCommand;
68   PkgEditMenuRemoveFile: TIDEMenuCommand;
69   PkgEditMenuReAddFile: TIDEMenuCommand;
70   PkgEditMenuCopyMoveToDirectory: TIDEMenuCommand;
71   PkgEditMenuEditVirtualUnit: TIDEMenuCommand;
72   PkgEditMenuSectionFileType: TIDEMenuSection;
73 
74   // directories
75   PkgEditMenuExpandDirectory: TIDEMenuCommand;
76   PkgEditMenuCollapseDirectory: TIDEMenuCommand;
77   PkgEditMenuUseAllUnitsInDirectory: TIDEMenuCommand;
78   PkgEditMenuUseNoUnitsInDirectory: TIDEMenuCommand;
79 
80   // dependencies
81   PkgEditMenuRemoveDependency: TIDEMenuCommand;
82   PkgEditMenuReAddDependency: TIDEMenuCommand;
83   PkgEditMenuDepStoreFileNameDefault: TIDEMenuCommand;
84   PkgEditMenuDepStoreFileNamePreferred: TIDEMenuCommand;
85   PkgEditMenuDepClearStoredFileName: TIDEMenuCommand;
86   PkgEditMenuCleanDependencies: TIDEMenuCommand;
87 
88   // all files
89   PkgEditMenuFindInFiles: TIDEMenuCommand;
90   PkgEditMenuSortFiles: TIDEMenuCommand;
91   PkgEditMenuFixFilesCase: TIDEMenuCommand;
92   PkgEditMenuShowMissingFiles: TIDEMenuCommand;
93 
94   // package
95   PkgEditMenuSave: TIDEMenuCommand;
96   PkgEditMenuSaveAs: TIDEMenuCommand;
97   PkgEditMenuRevert: TIDEMenuCommand;
98   PkgEditMenuPublish: TIDEMenuCommand;
99 
100   // compile
101   PkgEditMenuCompile: TIDEMenuCommand;
102   PkgEditMenuRecompileClean: TIDEMenuCommand;
103   PkgEditMenuRecompileAllRequired: TIDEMenuCommand;
104   PkgEditMenuCreateMakefile: TIDEMenuCommand;
105   PkgEditMenuCreateFpmakeFile: TIDEMenuCommand;
106   PkgEditMenuViewPackageSource: TIDEMenuCommand;
107 
108 type
endernull109   TOnPkgEvent = function(Sender: TObject; APackage: TLazPackage): TModalResult of object;
110   TOnAddPkgToProject =
endernull111     function(Sender: TObject; APackage: TLazPackage;
112              OnlyTestIfPossible: boolean): TModalResult of object;
113   TOnCompilePackage =
endernull114     function(Sender: TObject; APackage: TLazPackage;
115              CompileClean, CompileRequired: boolean): TModalResult of object;
116   TOnCreateNewPkgFile =
endernull117     function(Sender: TObject; Params: TAddToPkgResult): TModalResult  of object;
118   TOnDeleteAmbiguousFiles =
endernull119     function(Sender: TObject; APackage: TLazPackage;
120              const Filename: string): TModalResult of object;
121   TOnFreePkgEditor = procedure(APackage: TLazPackage) of object;
122   TOnOpenFile =
endernull123     function(Sender: TObject; const Filename: string): TModalResult of object;
124   TOnOpenPkgFile =
endernull125     function(Sender: TObject; PkgFile: TPkgFile): TModalResult of object;
126   TOnSavePackage =
endernull127     function(Sender: TObject; APackage: TLazPackage;
128              SaveAs: boolean): TModalResult of object;
129 
130   TPENodeType = (
131     penFile,
132     penDependency
133     );
134 
135   { TPENodeData }
136 
137   TPENodeData = class(TTFENodeData)
138   public
139     Typ: TPENodeType;
140     Name: string; // file or package name
141     Removed: boolean;
142     FileType: TPkgFileType;
143     Next: TPENodeData;
144     constructor Create(aTyp: TPENodeType; aName: string; aRemoved: boolean);
145   end;
146 
147   { IFilesEditorInterface
148     An editor with a TTreeView with files and dependencies }
149 
150   IFilesEditorInterface = interface
FilesEditTreeViewnull151     function FilesEditTreeView: TTreeView;
TVNodeFilesnull152     function TVNodeFiles: TTreeNode;
TVNodeRequiredPackagesnull153     function TVNodeRequiredPackages: TTreeNode;
FilesEditFormnull154     function FilesEditForm: TCustomForm;
FilesOwnernull155     function FilesOwner: TObject; // TProject or TLazPackage
FilesOwnerNamenull156     function FilesOwnerName: string; // for debugging purposes
157     procedure BeginUpdate;
158     procedure EndUpdate;
GetNodeDatanull159     function GetNodeData(TVNode: TTreeNode): TPENodeData;
GetNodeItemnull160     function GetNodeItem(NodeData: TPENodeData): TObject;
GetNodeDataItemnull161     function GetNodeDataItem(TVNode: TTreeNode; out NodeData: TPENodeData;
162       out Item: TObject): boolean;
GetNodeFilenamenull163     function GetNodeFilename(Node: TTreeNode): string;
IsDirectoryNodenull164     function IsDirectoryNode(Node: TTreeNode): boolean;
FilesBaseDirectorynull165     function FilesBaseDirectory: string;
FilesOwnerReadOnlynull166     function FilesOwnerReadOnly: boolean;
FirstRequiredDependencynull167     function FirstRequiredDependency: TPkgDependency;
ExtendUnitSearchPathnull168     function ExtendUnitSearchPath(NewUnitPaths: string): boolean;
ExtendIncSearchPathnull169     function ExtendIncSearchPath(NewIncPaths: string): boolean;
170     procedure UpdateAll(Immediately: boolean = false);
171   end;
172 
173   TPEFlag = (
174     pefNeedUpdateTitle,
175     pefNeedUpdateFiles,
176     pefNeedUpdateRemovedFiles,
177     pefNeedUpdateRequiredPkgs,
178     pefNeedUpdateProperties,
179     pefNeedUpdateButtons,
180     pefNeedUpdateApplyDependencyButton,
181     pefNeedUpdateStatusBar
182     );
183   TPEFlags = set of TPEFlag;
184 
185   { TPackageEditorForm }
186 
187   TPackageEditorForm = class(TBasePackageEditor,IFilesEditorInterface)
188     MenuItem1: TMenuItem;
189     mnuAddFPMakeReq: TMenuItem;
190     mnuAddDiskFile: TMenuItem;
191     mnuAddNewFile: TMenuItem;
192     mnuAddNewComp: TMenuItem;
193     mnuAddNewReqr: TMenuItem;
194     MoveDownBtn: TSpeedButton;
195     MoveUpBtn: TSpeedButton;
196     DirectoryHierarchyButton: TSpeedButton;
197     OpenButton: TSpeedButton;
198     DisableI18NForLFMCheckBox: TCheckBox;
199     FilterEdit: TTreeFilterEdit;
200     FilterPanel: TPanel;
201     AddPopupMenu: TPopupMenu;
202     SortAlphabeticallyButton: TSpeedButton;
203     Splitter1: TSplitter;
204     // toolbar
205     ToolBar: TToolBar;
206     // toolbuttons
207     SaveBitBtn: TToolButton;
208     CompileBitBtn: TToolButton;
209     UseBitBtn: TToolButton;
210     AddBitBtn: TToolButton;
211     RemoveBitBtn: TToolButton;
212     OptionsBitBtn: TToolButton;
213     MoreBitBtn: TToolButton;
214     HelpBitBtn: TToolButton;
215     // items
216     ItemsTreeView: TTreeView;
217     // properties
218     PropsGroupBox: TGroupBox;
219     // file properties
220     CallRegisterProcCheckBox: TCheckBox;
221     AddToUsesPkgSectionCheckBox: TCheckBox;
222     RegisteredPluginsGroupBox: TGroupBox;
223     RegisteredListBox: TListBox;
224     // dependency properties
225     UseMinVersionCheckBox: TCheckBox;
226     MinVersionEdit: TEdit;
227     UseMaxVersionCheckBox: TCheckBox;
228     MaxVersionEdit: TEdit;
229     ApplyDependencyButton: TButton;
230     // statusbar
231     StatusBar: TStatusBar;
232     // hidden components
233     UsePopupMenu: TPopupMenu;
234     ItemsPopupMenu: TPopupMenu;
235     MorePopupMenu: TPopupMenu;
236     procedure AddToProjectClick(Sender: TObject);
237     procedure AddToUsesPkgSectionCheckBoxChange(Sender: TObject);
238     procedure ApplyDependencyButtonClick(Sender: TObject);
239     procedure CallRegisterProcCheckBoxChange(Sender: TObject);
240     procedure ChangeFileTypeMenuItemClick(Sender: TObject);
241     procedure CleanDependenciesMenuItemClick(Sender: TObject);
242     procedure ClearDependencyFilenameMenuItemClick(Sender: TObject);
243     procedure CollapseDirectoryMenuItemClick(Sender: TObject);
244     procedure CompileAllCleanClick(Sender: TObject);
245     procedure CompileBitBtnClick(Sender: TObject);
246     procedure CompileCleanClick(Sender: TObject);
247     procedure CopyMoveToDirMenuItemClick(Sender: TObject);
248     procedure CreateMakefileClick(Sender: TObject);
249     procedure CreateFpmakeFileClick(Sender: TObject);
250     procedure DirectoryHierarchyButtonClick(Sender: TObject);
251     procedure DisableI18NForLFMCheckBoxChange(Sender: TObject);
252     procedure EditVirtualUnitMenuItemClick(Sender: TObject);
253     procedure ExpandDirectoryMenuItemClick(Sender: TObject);
254     procedure FilterEditKeyDown(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState);
255     procedure FindInFilesMenuItemClick(Sender: TObject);
256     procedure FormCreate(Sender: TObject);
257     procedure FormDestroy(Sender: TObject);
258     procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
259     procedure ItemsPopupMenuPopup(Sender: TObject);
260     procedure ItemsTreeViewAdvancedCustomDrawItem(Sender: TCustomTreeView;
261       Node: TTreeNode; {%H-}State: TCustomDrawState; Stage: TCustomDrawStage;
262       var {%H-}PaintImages, {%H-}DefaultDraw: Boolean);
263     procedure ItemsTreeViewDragDrop(Sender, Source: TObject; X, Y: Integer);
264     procedure ItemsTreeViewDragOver(Sender, Source: TObject; X, Y: Integer;
265       State: TDragState; var Accept: Boolean);
266     procedure ItemsTreeViewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
267     procedure mnuAddDiskFileClick(Sender: TObject);
268     procedure mnuAddFPMakeReqClick(Sender: TObject);
269     procedure mnuAddNewCompClick(Sender: TObject);
270     procedure mnuAddNewReqrClick(Sender: TObject);
271     procedure mnuAddNewFileClick(Sender: TObject);
272     procedure MorePopupMenuPopup(Sender: TObject);
273     procedure ItemsTreeViewDblClick(Sender: TObject);
274     procedure ItemsTreeViewSelectionChanged(Sender: TObject);
275     procedure FixFilesCaseMenuItemClick(Sender: TObject);
276     procedure HelpBitBtnClick(Sender: TObject);
277     procedure InstallClick(Sender: TObject);
278     procedure MaxVersionEditChange(Sender: TObject);
279     procedure MinVersionEditChange(Sender: TObject);
280     procedure MoveDownBtnClick(Sender: TObject);
281     procedure MoveUpBtnClick(Sender: TObject);
282     procedure OnIdle(Sender: TObject; var {%H-}Done: Boolean);
283     procedure OpenFileMenuItemClick(Sender: TObject);
284     procedure OptionsBitBtnClick(Sender: TObject);
285     procedure PackageEditorFormClose(Sender: TObject; var {%H-}CloseAction: TCloseAction);
286     procedure PackageEditorFormCloseQuery(Sender: TObject; var CanClose: boolean);
287     procedure PublishClick(Sender: TObject);
288     procedure ReAddMenuItemClick(Sender: TObject);
289     procedure RegisteredListBoxDrawItem({%H-}Control: TWinControl; Index: Integer;
290                                         ARect: TRect; {%H-}State: TOwnerDrawState);
291     procedure RemoveBitBtnClick(Sender: TObject);
292     procedure RevertClick(Sender: TObject);
293     procedure SaveAsClick(Sender: TObject);
294     procedure SaveBitBtnClick(Sender: TObject);
295     procedure SetDepDefaultFilenameMenuItemClick(Sender: TObject);
296     procedure SetDepPreferredFilenameMenuItemClick(Sender: TObject);
297     procedure ShowMissingFilesMenuItemClick(Sender: TObject);
298     procedure SortAlphabeticallyButtonClick(Sender: TObject);
299     procedure SortFilesMenuItemClick(Sender: TObject);
300     procedure UninstallClick(Sender: TObject);
301     procedure UseAllUnitsInDirectoryMenuItemClick(Sender: TObject);
302     procedure UseMaxVersionCheckBoxChange(Sender: TObject);
303     procedure UseMinVersionCheckBoxChange(Sender: TObject);
304     procedure UseNoUnitsInDirectoryMenuItemClick(Sender: TObject);
305     procedure UsePopupMenuPopup(Sender: TObject);
306     procedure ViewPkgSourceClick(Sender: TObject);
307     procedure ViewPkgTodosClick(Sender: TObject);
308   private
309     FIdleConnected: boolean;
310     FCompiling: boolean;
311     FCompileDesignTimePkg: boolean;
312     FLazPackage: TLazPackage;
313     FNextSelectedPart: TPENodeData;// select this file/dependency on next update
314     FFilesNode: TTreeNode;
315     FRequiredPackagesNode: TTreeNode;
316     FRemovedFilesNode: TTreeNode;
317     FRemovedRequiredNode: TTreeNode;
318     FPlugins: TStringList; // ComponentClassName, Objects=TPkgComponent
319     FShowDirectoryHierarchy: boolean;
320     FSortAlphabetically: boolean;
321     FDirSummaryLabel: TLabel;
322     FFirstNodeData: array[TPENodeType] of TPENodeData;
323     fUpdateLock: integer;
324     fForcedFlags: TPEFlags;
325     procedure DoAddNewFile(NewItem: TNewIDEItemTemplate);
326     procedure FreeNodeData(Typ: TPENodeType);
CreateNodeDatanull327     function CreateNodeData(Typ: TPENodeType; aName: string; aRemoved: boolean): TPENodeData;
GetSingleSelectedDepnull328     function GetSingleSelectedDep: TPkgDependency;
329     procedure SetDependencyDefaultFilename(AsPreferred: boolean);
330     procedure SetIdleConnected(AValue: boolean);
331     procedure SetShowDirectoryHierarchy(const AValue: boolean);
332     procedure SetSortAlphabetically(const AValue: boolean);
333     procedure SetupComponents;
OnTreeViewGetImageIndexnull334     function OnTreeViewGetImageIndex({%H-}Str: String; Data: TObject; var {%H-}AIsEnabled: Boolean): Integer;
335     procedure UpdateNodeImage(TVNode: TTreeNode);
336     procedure UpdateNodeImage(TVNode: TTreeNode; NodeData: TPENodeData; Item: TObject);
337     procedure UpdatePending;
CanUpdatenull338     function CanUpdate(Flag: TPEFlag; Immediately: boolean): boolean;
339     procedure UpdateTitle(Immediately: boolean = false);
340     procedure UpdateFiles(Immediately: boolean = false);
341     procedure UpdateRemovedFiles(Immediately: boolean = false);
342     procedure UpdateRequiredPkgs(Immediately: boolean = false);
343     procedure UpdatePEProperties(Immediately: boolean = false);
344     procedure UpdateButtons(Immediately: boolean = false);
345     procedure UpdateApplyDependencyButton(Immediately: boolean = false);
346     procedure UpdateStatusBar(Immediately: boolean = false);
347     procedure GetDirectorySummary(DirNode: TTreeNode;
348         out FileCount, HasRegisterProcCount, AddToUsesPkgSectionCount: integer);
349     procedure ExtendUnitIncPathForNewUnit(const AnUnitFilename,
350       AnIncludeFile: string; var IgnoreUnitPaths: TFilenameToStringTree);
351     procedure ExtendIncPathForNewIncludeFile(const AnIncludeFile: string;
352       var IgnoreIncPaths: TFilenameToStringTree);
CanBeAddedToProjectnull353     function CanBeAddedToProject: boolean;
354   protected
355     fFlags: TPEFlags;
356     procedure SetLazPackage(const AValue: TLazPackage); override;
357     property IdleConnected: boolean read FIdleConnected write SetIdleConnected;
358   public
359     constructor Create(TheOwner: TComponent); override;
360     destructor Destroy; override;
361     procedure DoCompile(CompileClean, CompileRequired, WarnIDEPkg: boolean);
362     procedure DoFindInFiles;
363     procedure DoFixFilesCase;
364     procedure DoShowMissingFiles;
365     procedure DoMoveCurrentFile(Offset: integer);
366     procedure DoMoveDependency(Offset: integer);
367     procedure DoPublishPackage;
368     procedure DoEditVirtualUnit;
369     procedure DoExpandCollapseDirectory(ExpandIt: Boolean);
370     procedure DoUseUnitsInDirectory(Use: boolean);
371     procedure DoRevert;
372     procedure DoSave(SaveAs: boolean);
373     procedure DoSortFiles;
DoOpenPkgFilenull374     function DoOpenPkgFile(PkgFile: TPkgFile): TModalResult;
ShowNewCompDialognull375     function ShowNewCompDialog: TModalResult;
ShowAddDepDialognull376     function ShowAddDepDialog: TModalResult;
ShowAddFPMakeDepDialognull377     function ShowAddFPMakeDepDialog: TModalResult;
PkgNameToFormNamenull378     function PkgNameToFormName(const PkgName: string): string;
GetSingleSelectedDependencynull379     function GetSingleSelectedDependency: TPkgDependency;
GetSingleSelectedFilenull380     function GetSingleSelectedFile: TPkgFile;
381   public
382     // IFilesEditorInterface
FilesEditTreeViewnull383     function FilesEditTreeView: TTreeView;
FilesEditFormnull384     function FilesEditForm: TCustomForm;
FilesOwnernull385     function FilesOwner: TObject; // = Lazpackage
FilesOwnerNamenull386     function FilesOwnerName: string;
TVNodeFilesnull387     function TVNodeFiles: TTreeNode;
TVNodeRequiredPackagesnull388     function TVNodeRequiredPackages: TTreeNode;
FilesBaseDirectorynull389     function FilesBaseDirectory: string;
FilesOwnerReadOnlynull390     function FilesOwnerReadOnly: boolean;
FirstRequiredDependencynull391     function FirstRequiredDependency: TPkgDependency;
ExtendUnitSearchPathnull392     function ExtendUnitSearchPath(NewUnitPaths: string): boolean;
ExtendIncSearchPathnull393     function ExtendIncSearchPath(NewIncPaths: string): boolean;
GetNodeDatanull394     function GetNodeData(TVNode: TTreeNode): TPENodeData;
GetNodeItemnull395     function GetNodeItem(NodeData: TPENodeData): TObject;
GetNodeDataItemnull396     function GetNodeDataItem(TVNode: TTreeNode; out NodeData: TPENodeData;
397       out Item: TObject): boolean;
GetNodeFilenamenull398     function GetNodeFilename(Node: TTreeNode): string;
IsDirectoryNodenull399     function IsDirectoryNode(Node: TTreeNode): boolean;
400     procedure BeginUpdate;
401     procedure EndUpdate;
402     procedure UpdateAll(Immediately: boolean = false); override;
403   public
404     property LazPackage: TLazPackage read FLazPackage write SetLazPackage;
405     property SortAlphabetically: boolean read FSortAlphabetically write SetSortAlphabetically;
406     property ShowDirectoryHierarchy: boolean read FShowDirectoryHierarchy write SetShowDirectoryHierarchy;
407     property FilesNode: TTreeNode read FFilesNode;
408     property RequiredPackagesNode: TTreeNode read FRequiredPackagesNode;
409   end;
410 
411 
412   { TPackageEditors }
413 
414   TPackageEditors = class
415   private
416     FItems: TFPList; // list of TPackageEditorForm
417     FOnAddToProject: TOnAddPkgToProject;
418     FOnAfterWritePackage: TIDEOptionsWriteEvent;
419     FOnBeforeReadPackage: TNotifyEvent;
420     FOnCompilePackage: TOnCompilePackage;
421     FOnCopyMoveFiles: TNotifyEvent;
422     FOnCreateNewFile: TOnCreateNewPkgFile;
423     FOnCreateMakefile: TOnPkgEvent;
424     FOnCreateFpmakeFile: TOnPkgEvent;
425     FOnDeleteAmbiguousFiles: TOnDeleteAmbiguousFiles;
426     FOnDragDropTreeView: TDragDropEvent;
427     FOnDragOverTreeView: TOnDragOverTreeView;
428     FOnShowFindInFiles: TOnPkgEvent;
429     FOnFreeEditor: TOnFreePkgEditor;
430     FOnGetIDEFileInfo: TGetIDEFileStateEvent;
431     FOnGetUnitRegisterInfo: TOnGetUnitRegisterInfo;
432     FOnInstallPackage: TOnPkgEvent;
433     FOnOpenFile: TOnOpenFile;
434     FOnOpenPackage: TOnPkgEvent;
435     FOnOpenPkgFile: TOnOpenPkgFile;
436     FOnPublishPackage: TOnPkgEvent;
437     FOnRevertPackage: TOnPkgEvent;
438     FOnSavePackage: TOnSavePackage;
439     FOnUninstallPackage: TOnPkgEvent;
440     FOnViewPackageSource: TOnPkgEvent;
441     FOnViewPackageToDos: TOnPkgEvent;
GetEditorsnull442     function GetEditors(Index: integer): TPackageEditorForm;
443   public
444     constructor Create;
445     destructor Destroy; override;
Countnull446     function Count: integer;
447     procedure Clear;
448     procedure Remove(Editor: TPackageEditorForm);
IndexOfPackagenull449     function IndexOfPackage(Pkg: TLazPackage): integer;
IndexOfPackagenull450     function IndexOfPackage(const PkgName: string): integer;
FindEditornull451     function FindEditor(Pkg: TLazPackage): TPackageEditorForm; overload;
FindEditornull452     function FindEditor(const PkgName: string): TPackageEditorForm; overload;
CreateEditornull453     function CreateEditor(Pkg: TLazPackage; DoDisableAutoSizing: boolean): TPackageEditorForm;
OpenEditornull454     function OpenEditor(Pkg: TLazPackage; BringToFront: boolean): TPackageEditorForm;
OpenFilenull455     function OpenFile(Sender: TObject; const Filename: string): TModalResult;
OpenPkgFilenull456     function OpenPkgFile(Sender: TObject; PkgFile: TPkgFile): TModalResult;
OpenDependencynull457     function OpenDependency(Sender: TObject;
458                             Dependency: TPkgDependency): TModalResult;
459     procedure DoFreeEditor(Pkg: TLazPackage);
CreateNewFilenull460     function CreateNewFile(Sender: TObject; Params: TAddToPkgResult): TModalResult;
SavePackagenull461     function SavePackage(APackage: TLazPackage; SaveAs: boolean): TModalResult;
RevertPackagenull462     function RevertPackage(APackage: TLazPackage): TModalResult;
PublishPackagenull463     function PublishPackage(APackage: TLazPackage): TModalResult;
CompilePackagenull464     function CompilePackage(APackage: TLazPackage;
465                             CompileClean,CompileRequired: boolean): TModalResult;
466     procedure UpdateAllEditors(Immediately: boolean);
ShouldNotBeInstallednull467     function ShouldNotBeInstalled(APackage: TLazPackage): boolean;// possible, but probably a bad idea
InstallPackagenull468     function InstallPackage(APackage: TLazPackage): TModalResult;
UninstallPackagenull469     function UninstallPackage(APackage: TLazPackage): TModalResult;
ViewPkgSourcenull470     function ViewPkgSource(APackage: TLazPackage): TModalResult;
ViewPkgToDosnull471     function ViewPkgToDos(APackage: TLazPackage): TModalResult;
FindInFilesnull472     function FindInFiles(APackage: TLazPackage): TModalResult;
DeleteAmbiguousFilesnull473     function DeleteAmbiguousFiles(APackage: TLazPackage;
474                                   const Filename: string): TModalResult;
AddToProjectnull475     function AddToProject(APackage: TLazPackage;
476                           OnlyTestIfPossible: boolean): TModalResult;
CreateMakefilenull477     function CreateMakefile(APackage: TLazPackage): TModalResult;
CreateFpmakeFilenull478     function CreateFpmakeFile(APackage: TLazPackage): TModalResult;
TreeViewToPkgEditornull479     function TreeViewToPkgEditor(TV: TTreeView): TPackageEditorForm;
480   public
481     property Editors[Index: integer]: TPackageEditorForm read GetEditors;
482     property OnAddToProject: TOnAddPkgToProject read FOnAddToProject
483                                                 write FOnAddToProject;
484     property OnAfterWritePackage: TIDEOptionsWriteEvent read FOnAfterWritePackage
485                                                write FOnAfterWritePackage;
486     property OnBeforeReadPackage: TNotifyEvent read FOnBeforeReadPackage
487                                                write FOnBeforeReadPackage;
488     property OnCompilePackage: TOnCompilePackage read FOnCompilePackage
489                                                  write FOnCompilePackage;
490     property OnCopyMoveFiles: TNotifyEvent read FOnCopyMoveFiles
491                                            write FOnCopyMoveFiles;
492     property OnCreateFpmakeFile: TOnPkgEvent read FOnCreateFpmakeFile
493                                                      write FOnCreateFpmakeFile;
494     property OnCreateMakeFile: TOnPkgEvent read FOnCreateMakefile
495                                                      write FOnCreateMakefile;
496     property OnCreateNewFile: TOnCreateNewPkgFile read FOnCreateNewFile
497                                                   write FOnCreateNewFile;
498     property OnDeleteAmbiguousFiles: TOnDeleteAmbiguousFiles
499                      read FOnDeleteAmbiguousFiles write FOnDeleteAmbiguousFiles;
500     property OnDragDropTreeView: TDragDropEvent read FOnDragDropTreeView
501                                                       write FOnDragDropTreeView;
502     property OnDragOverTreeView: TOnDragOverTreeView read FOnDragOverTreeView
503                                                       write FOnDragOverTreeView;
504     property OnShowFindInFiles: TOnPkgEvent read FOnShowFindInFiles write FOnShowFindInFiles;
505     property OnFreeEditor: TOnFreePkgEditor read FOnFreeEditor
506                                             write FOnFreeEditor;
507     property OnGetIDEFileInfo: TGetIDEFileStateEvent read FOnGetIDEFileInfo
508                                                      write FOnGetIDEFileInfo;
509     property OnGetUnitRegisterInfo: TOnGetUnitRegisterInfo
510                        read FOnGetUnitRegisterInfo write FOnGetUnitRegisterInfo;
511     property OnInstallPackage: TOnPkgEvent read FOnInstallPackage
512                                                  write FOnInstallPackage;
513     property OnOpenFile: TOnOpenFile read FOnOpenFile write FOnOpenFile;
514     property OnOpenPackage: TOnPkgEvent read FOnOpenPackage
515                                            write FOnOpenPackage;
516     property OnOpenPkgFile: TOnOpenPkgFile read FOnOpenPkgFile
517                                            write FOnOpenPkgFile;
518     property OnPublishPackage: TOnPkgEvent read FOnPublishPackage
519                                                write FOnPublishPackage;
520     property OnRevertPackage: TOnPkgEvent read FOnRevertPackage
521                                                write FOnRevertPackage;
522     property OnSavePackage: TOnSavePackage read FOnSavePackage
523                                            write FOnSavePackage;
524     property OnUninstallPackage: TOnPkgEvent read FOnUninstallPackage
525                                                  write FOnUninstallPackage;
526     property OnViewPackageSource: TOnPkgEvent read FOnViewPackageSource
527                                                  write FOnViewPackageSource;
528     property OnViewPackageToDos: TOnPkgEvent read FOnViewPackageToDos
529                                                  write FOnViewPackageToDos;
530   end;
531 
532 var
533   PackageEditors: TPackageEditors;
534 
535 procedure RegisterStandardPackageEditorMenuItems;
536 
537 implementation
538 
539 uses
540   NewDialog;
541 
542 {$R *.lfm}
543 
544 var
545   ImageIndexFiles: integer;
546   ImageIndexRemovedFiles: integer;
547   ImageIndexRequired: integer;
548   ImageIndexRemovedRequired: integer;
549   ImageIndexUnit: integer;
550   ImageIndexRegisterUnit: integer;
551   ImageIndexLFM: integer;
552   ImageIndexLRS: integer;
553   ImageIndexInclude: integer;
554   ImageIndexIssues: integer;
555   ImageIndexText: integer;
556   ImageIndexBinary: integer;
557   ImageIndexConflict: integer;
558   ImageIndexDirectory: integer;
559 
560 procedure RegisterStandardPackageEditorMenuItems;
561 var
562   AParent: TIDEMenuSection;
563 begin
564   PackageEditorMenuRoot     :=RegisterIDEMenuRoot(PackageEditorMenuRootName);
565   PackageEditorMenuFilesRoot:=RegisterIDEMenuRoot(PackageEditorMenuFilesRootName);
566 
567   // register the section for operations on selected files
568   PkgEditMenuSectionFile:=RegisterIDEMenuSection(PackageEditorMenuFilesRoot,'File');
569   AParent:=PkgEditMenuSectionFile;
570   PkgEditMenuAddDiskFile:=RegisterIDEMenuCommand(AParent,'Add disk file',lisPckEditAddFilesFromFileSystem);
571   PkgEditMenuAddNewFile:=RegisterIDEMenuCommand(AParent,'New file',lisA2PNewFile);
572   PkgEditMenuAddNewComp:=RegisterIDEMenuCommand(AParent,'New component',lisMenuNewComponent);
573   PkgEditMenuAddNewReqr:=RegisterIDEMenuCommand(AParent,'New requirement',lisProjAddNewRequirement);
574   PkgEditMenuAddNewFPMakeReqr:=RegisterIDEMenuCommand(AParent,'New FPMake requirement',lisProjAddNewFPMakeRequirement);
575   //
576   PkgEditMenuOpenFile:=RegisterIDEMenuCommand(AParent,'Open File',lisOpen);
577   PkgEditMenuRemoveFile:=RegisterIDEMenuCommand(AParent,'Remove File',lisPckEditRemoveFile);
578   PkgEditMenuReAddFile:=RegisterIDEMenuCommand(AParent,'ReAdd File',lisPckEditReAddFile);
579   PkgEditMenuCopyMoveToDirectory:=RegisterIDEMenuCommand(AParent, 'Copy/Move File to Directory', lisCopyMoveFileToDirectory);
580   PkgEditMenuEditVirtualUnit:=RegisterIDEMenuCommand(AParent,'Edit Virtual File',lisPEEditVirtualUnit);
581   PkgEditMenuSectionFileType:=RegisterIDESubMenu(AParent,'File Type',lisAF2PFileType);
582 
583   // register the section for operations on directories
584   PkgEditMenuSectionDirectory:=RegisterIDEMenuSection(PackageEditorMenuFilesRoot,'Directory');
585   AParent:=PkgEditMenuSectionDirectory;
586   PkgEditMenuExpandDirectory:=RegisterIDEMenuCommand(AParent,'Expand directory',lisPEExpandDirectory);
587   PkgEditMenuCollapseDirectory:=RegisterIDEMenuCommand(AParent, 'Collapse directory', lisPECollapseDirectory);
588   PkgEditMenuUseAllUnitsInDirectory:=RegisterIDEMenuCommand(AParent, 'Use all units in directory', lisPEUseAllUnitsInDirectory);
589   PkgEditMenuUseNoUnitsInDirectory:=RegisterIDEMenuCommand(AParent, 'Use no units in directory', lisPEUseNoUnitsInDirectory);
590 
591   // register the section for operations on dependencies
592   PkgEditMenuSectionDependency:=RegisterIDEMenuSection(PackageEditorMenuFilesRoot,'Dependency');
593   AParent:=PkgEditMenuSectionDependency;
594   PkgEditMenuRemoveDependency:=RegisterIDEMenuCommand(AParent,'Remove Dependency',lisPckEditRemoveDependency);
595   PkgEditMenuReAddDependency:=RegisterIDEMenuCommand(AParent,'ReAdd Dependency',lisPckEditReAddDependency);
596   PkgEditMenuDepStoreFileNameDefault:=RegisterIDEMenuCommand(AParent,'Dependency Store Filename As Default',lisPckEditStoreFileNameAsDefaultForThisDependency);
597   PkgEditMenuDepStoreFileNamePreferred:=RegisterIDEMenuCommand(AParent,'Dependency Store Filename As Preferred',lisPckEditStoreFileNameAsPreferredForThisDependency);
598   PkgEditMenuDepClearStoredFileName:=RegisterIDEMenuCommand(AParent,'Dependency Clear Stored Filename',lisPckEditClearDefaultPreferredFilenameOfDependency);
599   PkgEditMenuCleanDependencies:=RegisterIDEMenuCommand(AParent, 'Clean up dependencies', lisPckEditCleanUpDependencies);
600 
601   // register the section for operations on all files
602   PkgEditMenuSectionFiles:=RegisterIDEMenuSection(PackageEditorMenuRoot,'Files');
603   AParent:=PkgEditMenuSectionFiles;
604   PkgEditMenuFindInFiles:=RegisterIDEMenuCommand(AParent,'Find in files',srkmecFindInFiles + ' ...');
605   PkgEditMenuSortFiles:=RegisterIDEMenuCommand(AParent,'Sort Files Permanently',lisPESortFiles);
606   PkgEditMenuFixFilesCase:=RegisterIDEMenuCommand(AParent,'Fix Files Case',lisPEFixFilesCase);
607   PkgEditMenuShowMissingFiles:=RegisterIDEMenuCommand(AParent, 'Show Missing Files', lisPEShowMissingFiles);
608 
609   // register the section for using the package
610   PkgEditMenuSectionUse:=RegisterIDEMenuSection(PackageEditorMenuRoot,'Use');
611 
612   // register the section for saving the package
613   PkgEditMenuSectionSave:=RegisterIDEMenuSection(PackageEditorMenuRoot,'Save');
614   AParent:=PkgEditMenuSectionSave;
615   PkgEditMenuSave:=RegisterIDEMenuCommand(AParent, 'Save', lisPckEditSavePackage);
616   PkgEditMenuSaveAs:=RegisterIDEMenuCommand(AParent, 'Save As', lisPESavePackageAs);
617   PkgEditMenuRevert:=RegisterIDEMenuCommand(AParent, 'Revert', lisPERevertPackage);
618   PkgEditMenuPublish:=RegisterIDEMenuCommand(AParent,'Publish',lisPkgEditPublishPackage);
619 
620   // register the section for compiling the package
621   PkgEditMenuSectionCompile:=RegisterIDEMenuSection(PackageEditorMenuRoot,'Compile');
622   AParent:=PkgEditMenuSectionCompile;
623   PkgEditMenuCompile:=RegisterIDEMenuCommand(AParent,'Compile',lisCompile);
624   PkgEditMenuRecompileClean:=RegisterIDEMenuCommand(AParent,'Recompile Clean',lisPckEditRecompileClean);
625   PkgEditMenuRecompileAllRequired:=RegisterIDEMenuCommand(AParent,'Recompile All Required',lisPckEditRecompileAllRequired);
626   PkgEditMenuCreateFpmakeFile:=RegisterIDEMenuCommand(AParent,'Create fpmake.pp',lisPckEditCreateFpmakeFile);
627   PkgEditMenuCreateMakefile:=RegisterIDEMenuCommand(AParent,'Create Makefile',lisPckEditCreateMakefile);
628 
629   // register the section for adding to or removing from package
630   PkgEditMenuSectionAddRemove:=RegisterIDEMenuSection(PackageEditorMenuRoot,'AddRemove');
631 
632   // register the section for other things
633   PkgEditMenuSectionMisc:=RegisterIDEMenuSection(PackageEditorMenuRoot,'Misc');
634   AParent:=PkgEditMenuSectionMisc;
635   PkgEditMenuViewPackageSource:=RegisterIDEMenuCommand(AParent,'View Package Source',lisPckEditViewPackageSource);
636 end;
637 
DependencyAsStringnull638 function DependencyAsString(ADependency: TPkgDependency): string;
639 // A display text for a dependency including min/max versions + other info.
640 // ToDo: Modify Dependency.AsString output to replace this function,
641 //       or create a new method for the task.
642 var
643   aFilename: String;
644 begin
645   Result:=ADependency.AsString;
646   if ADependency.DefaultFilename<>'' then begin
647     aFilename:=ADependency.MakeFilenameRelativeToOwner(ADependency.DefaultFilename);
648     if ADependency.PreferDefaultFilename then
649       Result:=Result+' in '+aFilename // like the 'in' keyword in uses section
650     else
651       Result:=Format(lisPckEditDefault, [Result, aFilename]);
652   end;
653   if ADependency.DependencyType=pdtFPMake then
654     Result:=Result+' '+lisPckEditFPMakePackage;
655 end;
656 
657 { TPENodeData }
658 
659 constructor TPENodeData.Create(aTyp: TPENodeType; aName: string; aRemoved: boolean);
660 begin
661   Typ:=aTyp;
662   Name:=aName;
663   Removed:=aRemoved;
664 end;
665 
666 { TPackageEditorForm }
667 
668 procedure TPackageEditorForm.PublishClick(Sender: TObject);
669 begin
670   DoPublishPackage;
671 end;
672 
673 procedure TPackageEditorForm.ReAddMenuItemClick(Sender: TObject);
674 var
675   PkgFile: TPkgFile;
676   AFilename: String;
677   Dependency: TPkgDependency;
678   i: Integer;
679   TVNode: TTreeNode;
680   NodeData: TPENodeData;
681   Item: TObject;
682 begin
683   BeginUpdate;
684   try
685     for i:=ItemsTreeView.SelectionCount-1 downto 0 do begin
686       TVNode:=ItemsTreeView.Selections[i];
687       if not GetNodeDataItem(TVNode,NodeData,Item) then continue;
688       if not NodeData.Removed then continue;
689       if Item is TPkgFile then begin
690         // re-add file
691         PkgFile:=TPkgFile(Item);
692         AFilename:=PkgFile.GetFullFilename;
693         if PkgFile.FileType in PkgFileRealUnitTypes then begin
694           if not CheckAddingPackageUnit(LazPackage,d2ptUnit,
695             PackageEditors.OnGetIDEFileInfo,AFilename) then exit;
696         end else if PkgFile.FileType=pftVirtualUnit then begin
697           if not CheckAddingPackageUnit(LazPackage,d2ptVirtualUnit,
698             PackageEditors.OnGetIDEFileInfo,AFilename) then exit;
699         end else begin
700           if not CheckAddingPackageUnit(LazPackage,d2ptFile,
701             PackageEditors.OnGetIDEFileInfo,AFilename) then exit;
702         end;
703         PkgFile.Filename:=AFilename;
704         LazPackage.UnremovePkgFile(PkgFile);
705       end
706       else if Item is TPkgDependency then begin
707         Dependency:=TPkgDependency(Item);
708         // Re-add dependency
709         fForcedFlags:=[pefNeedUpdateRemovedFiles,pefNeedUpdateRequiredPkgs];
710         if CheckAddingPackageDependency(LazPackage,Dependency,false,true)<>mrOk then exit;
711         LazPackage.RemoveRemovedDependency(Dependency);
712         PackageGraph.AddDependencyToPackage(LazPackage,Dependency);
713       end;
714     end;
715     LazPackage.Modified:=True;
716   finally
717     EndUpdate;
718   end;
719 end;
720 
721 type
722   PackageSelType = (pstFile, pstDir, pstDep, pstFPMake, pstFilesNode,
723                      pstReqPackNode, pstRemFile, pstRemDep);
724   PackageSelTypes = set of PackageSelType;
725 
726 procedure TPackageEditorForm.ItemsPopupMenuPopup(Sender: TObject);
727 var
728   UserSelection: PackageSelTypes;
729   SingleSelectedFile: TPkgFile;
730   SingleSelectedDep: TPkgDependency;
731 
732   procedure CollectSelected;
733   var
734     TVNode: TTreeNode;
735     NodeData: TPENodeData;
736     Item: TObject;
737     CurDependency: TPkgDependency;
738     CurFile: TPkgFile;
739     i: Integer;
740   begin
741     UserSelection := [];
742     SingleSelectedFile := Nil;
743     SingleSelectedDep := Nil;
744     for i := 0 to ItemsTreeView.SelectionCount-1 do begin
745       TVNode := ItemsTreeView.Selections[i];
746       if GetNodeDataItem(TVNode,NodeData,Item) then begin
747         if Item is TPkgFile then begin
748           CurFile := TPkgFile(Item);
749           if ItemsTreeView.SelectionCount=1 then
750             SingleSelectedFile := CurFile;
751           if NodeData.Removed then
752             Include(UserSelection, pstRemFile)
753           else
754             Include(UserSelection, pstFile);
755         end else if Item is TPkgDependency then begin
756           CurDependency := TPkgDependency(Item);
757           if (ItemsTreeView.SelectionCount=1) and Assigned(CurDependency.RequiredPackage) then
758             SingleSelectedDep:=CurDependency;
759           if CurDependency.DependencyType=pdtFPMake then
760             Include(UserSelection, pstFPMake);
761           if NodeData.Removed then
762             Include(UserSelection, pstRemDep)
763           else
764             Include(UserSelection, pstDep);
765         end;
766       end
767       else if IsDirectoryNode(TVNode) then
768         Include(UserSelection, pstDir)
769       else if TVNode=FFilesNode then
770         Include(UserSelection, pstFilesNode)
771       else if TVNode=FRequiredPackagesNode then
772         Include(UserSelection, pstReqPackNode);
773     end;
774   end;
775 
776   procedure SetItem(Item: TIDEMenuCommand; AnOnClick: TNotifyEvent;
777                     aShow: boolean = true; AEnable: boolean = true);
778   begin
779     Item.OnClick:=AnOnClick;
780     Item.Visible:=aShow;
781     Item.Enabled:=AEnable;
782   end;
783 
784   procedure AddFileTypeMenuItem;
785   var
786     CurPFT: TPkgFileType;
787     VirtualFileExists: Boolean;
788     NewMenuItem: TIDEMenuCommand;
789   begin
790     if Assigned(SingleSelectedFile) then
791     begin
792       PkgEditMenuSectionFileType.Clear;
793       VirtualFileExists:=(SingleSelectedFile.FileType=pftVirtualUnit)
794                       and FileExistsCached(SingleSelectedFile.GetFullFilename);
795       for CurPFT:=Low(TPkgFileType) to High(TPkgFileType) do begin
796         NewMenuItem:=RegisterIDEMenuCommand(PkgEditMenuSectionFileType,
797                         'SetFileType'+IntToStr(ord(CurPFT)),
798                         GetPkgFileTypeLocalizedName(CurPFT),
799                         @ChangeFileTypeMenuItemClick);
800         if CurPFT=SingleSelectedFile.FileType then
801         begin
802           // menuitem to keep the current type
803           NewMenuItem.Enabled:=true;
804           NewMenuItem.Checked:=true;
805         end else if VirtualFileExists then
806           // a virtual unit that exists can be changed into anything
807           NewMenuItem.Enabled:=true
808         else if (not (CurPFT in PkgFileUnitTypes)) then
809           // all other files can be changed into all non unit types
810           NewMenuItem.Enabled:=true
811         else if FilenameIsPascalUnit(SingleSelectedFile.Filename) then
812           // a pascal file can be changed into anything
813           NewMenuItem.Enabled:=true
814         else
815           // default is to not allow
816           NewMenuItem.Enabled:=false;
817       end;
818     end
819     else
820       PkgEditMenuSectionFileType.Visible:=False;
821   end;
822 
823 var
824   Writable: Boolean;
825 begin
826   //debugln(['TPackageEditorForm.FilesPopupMenuPopup START ',ItemsPopupMenu.Items.Count]);
827   PackageEditorMenuFilesRoot.MenuItem:=ItemsPopupMenu.Items;
828   //debugln(['TPackageEditorForm.FilesPopupMenuPopup START after connect ',ItemsPopupMenu.Items.Count]);
829   //PackageEditorMenuRoot.BeginUpdate;
830   try
831     CollectSelected;
832     Writable := not LazPackage.ReadOnly;
833 
834     // items for Files node and for selected files, under section PkgEditMenuSectionFile
835     PkgEditMenuSectionFile.Visible := not (pstDir in UserSelection);
836     if PkgEditMenuSectionFile.Visible then
837     begin
838       // Files root node
839       SetItem(PkgEditMenuAddDiskFile, @mnuAddDiskFileClick, UserSelection=[pstFilesNode],
840               Writable);
841       SetItem(PkgEditMenuAddNewFile, @mnuAddNewFileClick, UserSelection=[pstFilesNode],
842               Writable);
843       SetItem(PkgEditMenuAddNewComp, @mnuAddNewCompClick, UserSelection=[pstFilesNode],
844               Writable);
845       SetItem(PkgEditMenuAddNewReqr, @mnuAddNewReqrClick, UserSelection=[pstReqPackNode],
846               Writable);
847       SetItem(PkgEditMenuAddNewFPMakeReqr, @mnuAddFPMakeReqClick, UserSelection=[pstReqPackNode],
848               Writable);
849       // selected files
850       SetItem(PkgEditMenuOpenFile, @OpenFileMenuItemClick,
851               UserSelection*[pstFilesNode,pstReqPackNode,pstFPMake]=[]);
852       SetItem(PkgEditMenuReAddFile, @ReAddMenuItemClick, UserSelection=[pstRemFile]);
853       SetItem(PkgEditMenuCopyMoveToDirectory, @CopyMoveToDirMenuItemClick,
854               (UserSelection=[pstFile]) and LazPackage.HasDirectory);
855       SetItem(PkgEditMenuRemoveFile, @RemoveBitBtnClick, UserSelection=[pstFile],
856               RemoveBitBtn.Enabled);
857       AddFileTypeMenuItem;
858       SetItem(PkgEditMenuEditVirtualUnit, @EditVirtualUnitMenuItemClick,
859               Assigned(SingleSelectedFile) and (SingleSelectedFile.FileType=pftVirtualUnit),
860               Writable);
861     end;
862 
863     // items for directories, under section PkgEditMenuSectionDirectory
864     PkgEditMenuSectionDirectory.Visible := UserSelection<=[pstDir,pstFilesNode];
865     if PkgEditMenuSectionDirectory.Visible then
866     begin
867       SetItem(PkgEditMenuExpandDirectory, @ExpandDirectoryMenuItemClick);
868       SetItem(PkgEditMenuCollapseDirectory, @CollapseDirectoryMenuItemClick);
869       SetItem(PkgEditMenuUseAllUnitsInDirectory, @UseAllUnitsInDirectoryMenuItemClick);
870       SetItem(PkgEditMenuUseNoUnitsInDirectory, @UseNoUnitsInDirectoryMenuItemClick);
871     end;
872 
873     // items for dependencies, under section PkgEditMenuSectionDependency
874     PkgEditMenuSectionDependency.Visible := (UserSelection*[pstDep,pstRemDep] <> [])
875                                   or (ItemsTreeView.Selected=FRequiredPackagesNode);
876     if PkgEditMenuSectionDependency.Visible then
877     begin
878       SetItem(PkgEditMenuRemoveDependency, @RemoveBitBtnClick,
879               pstdep in UserSelection, Writable);
880       SetItem(PkgEditMenuReAddDependency,@ReAddMenuItemClick,
881               pstRemDep in UserSelection, Writable);
882       SetItem(PkgEditMenuDepStoreFileNameDefault, @SetDepDefaultFilenameMenuItemClick,
883               Assigned(SingleSelectedDep), Writable);
884       SetItem(PkgEditMenuDepStoreFileNamePreferred, @SetDepPreferredFilenameMenuItemClick,
885               Assigned(SingleSelectedDep), Writable);
886       SetItem(PkgEditMenuDepClearStoredFileName, @ClearDependencyFilenameMenuItemClick,
887               Assigned(SingleSelectedDep), Writable);
888       SetItem(PkgEditMenuCleanDependencies, @CleanDependenciesMenuItemClick,
889               Assigned(LazPackage.FirstRequiredDependency), Writable);
890     end;
891 
892   finally
893     //PackageEditorMenuRoot.EndUpdate;
894   end;
895   //debugln(['TPackageEditorForm.FilesPopupMenuPopup END ',ItemsPopupMenu.Items.Count]); PackageEditorMenuRoot.WriteDebugReport('  ',true);
896 end;
897 
898 procedure TPackageEditorForm.ItemsTreeViewAdvancedCustomDrawItem(
899   Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState;
900   Stage: TCustomDrawStage; var PaintImages, DefaultDraw: Boolean);
901 var
902   NodeData: TPENodeData;
903   r: TRect;
904   y: Integer;
905 begin
906   if Stage=cdPostPaint then begin
907     NodeData:=GetNodeData(Node);
908     if (NodeData<>nil) then begin
909       if  (NodeData.Typ=penFile) and (not NodeData.Removed)
910       and (NodeData.FileType<>pftVirtualUnit) and FilenameIsAbsolute(NodeData.Name)
911       and (not FileExistsCached(NodeData.Name))
912       then begin
913         r:=Node.DisplayRect(true);
914         ItemsTreeView.Canvas.Pen.Color:=clRed;
915         y:=(r.Top+r.Bottom) div 2;
916         ItemsTreeView.Canvas.Line(r.Left,y,r.Right,y);
917       end;
918     end;
919   end;
920 end;
921 
922 procedure TPackageEditorForm.ItemsTreeViewDragDrop(Sender, Source: TObject; X, Y: Integer);
923 begin
924   PackageEditors.OnDragDropTreeView(Sender, Source, X, Y);
925 end;
926 
927 procedure TPackageEditorForm.ItemsTreeViewDragOver(Sender, Source: TObject; X, Y: Integer;
928   State: TDragState; var Accept: Boolean);
929 var
930   TargetTVNode: TTreeNode;
931   TargetTVType: TTreeViewInsertMarkType;
932 begin
933   //debugln(['TPackageEditorForm.ItemsTreeViewDragOver ',DbgSName(Source),' State=',ord(State),' FromSelf=',Source=ItemsTreeView]);
934   Accept:=PackageEditors.OnDragOverTreeView(Sender,Source,X,Y,TargetTVNode,TargetTVType);
935   if Accept and (State<>dsDragLeave) then
936     ItemsTreeView.SetInsertMark(TargetTVNode,TargetTVType)
937   else
938     ItemsTreeView.SetInsertMark(nil,tvimNone);
939 end;
940 
941 procedure TPackageEditorForm.MorePopupMenuPopup(Sender: TObject);
942 
943   procedure SetItem(Item: TIDEMenuCommand; AnOnClick: TNotifyEvent;
944                     aShow: boolean = true; AEnable: boolean = true);
945   begin
946     //debugln(['SetItem ',Item.Caption,' Visible=',aShow,' Enable=',AEnable]);
947     Item.OnClick:=AnOnClick;
948     Item.Visible:=aShow;
949     Item.Enabled:=AEnable;
950   end;
951 
952 var
953   Writable, CanPublish: Boolean;
954   pcos: TParsedCompilerOptString;
955   CurrentPath: String;
956 begin
957   PackageEditorMenuRoot.MenuItem:=MorePopupMenu.Items;
958   //PackageEditorMenuRoot.BeginUpdate;
959   try
960     Writable:=(not LazPackage.ReadOnly);
961 
962     // under section PkgEditMenuSectionFiles
963     SetItem(PkgEditMenuFindInFiles,@FindInFilesMenuItemClick);
964     SetItem(PkgEditMenuSortFiles,@SortFilesMenuItemClick,(LazPackage.FileCount>1),Writable);
965     SetItem(PkgEditMenuFixFilesCase,@FixFilesCaseMenuItemClick,(LazPackage.FileCount>0),Writable);
966     SetItem(PkgEditMenuShowMissingFiles,@ShowMissingFilesMenuItemClick,(LazPackage.FileCount>0),Writable);
967 
968     // under section PkgEditMenuSectionSave
969     SetItem(PkgEditMenuSave,@SaveBitBtnClick,true,SaveBitBtn.Enabled);
970     SetItem(PkgEditMenuSaveAs,@SaveAsClick,true,true);
971     SetItem(PkgEditMenuRevert,@RevertClick,true,
972             (not LazPackage.IsVirtual) and FileExistsUTF8(LazPackage.Filename));
973     CanPublish:=(not LazPackage.Missing) and LazPackage.HasDirectory;
974     for pcos in [pcosUnitPath,pcosIncludePath] do
975     begin
976       CurrentPath:=LazPackage.CompilerOptions.ParsedOpts.GetParsedValue(pcos);
977       CurrentPath:=CreateRelativeSearchPath(CurrentPath,LazPackage.DirectoryExpanded);
978       //debugln(['TPackageEditorForm.MorePopupMenuPopup Unit=',CurrentPath]);
979       if Pos('..',CurrentPath)>0 then
980         CanPublish:=false;
981     end;
982     SetItem(PkgEditMenuPublish,@PublishClick,true,CanPublish);
983 
984     // under section PkgEditMenuSectionCompile
985     SetItem(PkgEditMenuCompile,@CompileBitBtnClick,true,CompileBitBtn.Enabled);
986     SetItem(PkgEditMenuRecompileClean,@CompileCleanClick,true,CompileBitBtn.Enabled);
987     SetItem(PkgEditMenuRecompileAllRequired,@CompileAllCleanClick,true,CompileBitBtn.Enabled);
988     SetItem(PkgEditMenuCreateFpmakeFile,@CreateFpmakeFileClick,true,CompileBitBtn.Enabled);
989     SetItem(PkgEditMenuCreateMakefile,@CreateMakefileClick,true,CompileBitBtn.Enabled);
990 
991     // under section PkgEditMenuSectionMisc
992     SetItem(PkgEditMenuViewPackageSource,@ViewPkgSourceClick);
993   finally
994     //PackageEditorMenuRoot.EndUpdate;
995   end;
996 end;
997 
998 procedure TPackageEditorForm.SortAlphabeticallyButtonClick(Sender: TObject);
999 begin
1000   SortAlphabetically:=SortAlphabeticallyButton.Down;
1001 end;
1002 
1003 procedure TPackageEditorForm.UsePopupMenuPopup(Sender: TObject);
1004 var
1005   ItemCnt: Integer;
1006 
AddPopupMenuItemnull1007   function AddPopupMenuItem(const ACaption: string; AnEvent: TNotifyEvent;
1008     EnabledFlag: boolean): TMenuItem;
1009   begin
1010     if UsePopupMenu.Items.Count<=ItemCnt then begin
1011       Result:=TMenuItem.Create(Self);
1012       UsePopupMenu.Items.Add(Result);
1013     end else begin
1014       Result:=UsePopupMenu.Items[ItemCnt];
1015       while Result.Count>0 do Result.Delete(Result.Count-1);
1016     end;
1017     Result.Caption:=ACaption;
1018     Result.OnClick:=AnEvent;
1019     Result.Enabled:=EnabledFlag;
1020     inc(ItemCnt);
1021   end;
1022 
1023 begin
1024   ItemCnt:=0;
1025 
1026   AddPopupMenuItem(lisPckEditAddToProject, @AddToProjectClick,
1027                    CanBeAddedToProject);
1028   AddPopupMenuItem(lisPckEditInstall, @InstallClick,(not LazPackage.Missing)
1029            and (LazPackage.PackageType in [lptDesignTime,lptRunAndDesignTime]));
1030   AddPopupMenuItem(lisPckEditUninstall, @UninstallClick,
1031           (LazPackage.Installed<>pitNope) or (LazPackage.AutoInstall<>pitNope));
1032 
1033   // remove unneeded menu items
1034   while UsePopupMenu.Items.Count>ItemCnt do
1035     UsePopupMenu.Items.Delete(UsePopupMenu.Items.Count-1);
1036 end;
1037 
1038 procedure TPackageEditorForm.ItemsTreeViewDblClick(Sender: TObject);
1039 begin
1040   OpenFileMenuItemClick(Self);
1041 end;
1042 
1043 procedure TPackageEditorForm.ItemsTreeViewKeyDown(Sender: TObject;
1044   var Key: Word; Shift: TShiftState);
1045 var
1046   Handled: Boolean;
1047 begin
1048   Handled := True;
1049   if (ssCtrl in Shift) then
1050   begin
1051     if Key = VK_UP then
1052       MoveUpBtnClick(Nil)
1053     else if Key = VK_DOWN then
1054       MoveDownBtnClick(Nil)
1055     else
1056       Handled := False;
1057   end
1058   else if Key = VK_RETURN then
1059     OpenFileMenuItemClick(Nil)
1060   else if Key = VK_DELETE then
1061     RemoveBitBtnClick(Nil)
1062   else if Key = VK_INSERT then
1063     mnuAddDiskFileClick(Nil)
1064   else
1065     Handled := False;
1066 
1067   if Handled then
1068     Key := VK_UNKNOWN;
1069 end;
1070 
1071 procedure TPackageEditorForm.mnuAddFPMakeReqClick(Sender: TObject);
1072 begin
1073   ShowAddFPMakeDepDialog
1074 end;
1075 
1076 procedure TPackageEditorForm.mnuAddNewCompClick(Sender: TObject);
1077 begin
1078   ShowNewCompDialog;
1079 end;
1080 
1081 procedure TPackageEditorForm.mnuAddNewReqrClick(Sender: TObject);
1082 begin
1083   ShowAddDepDialog;
1084 end;
1085 
1086 procedure TPackageEditorForm.mnuAddNewFileClick(Sender: TObject);
1087 var
1088   NewItem: TNewIDEItemTemplate;
1089 begin
1090   // Reuse the "New..." dialog for "Add new file".
1091   if ShowNewIDEItemDialog(NewItem, true)=mrOk then
1092     DoAddNewFile(NewItem);
1093 end;
1094 
1095 procedure TPackageEditorForm.ItemsTreeViewSelectionChanged(Sender: TObject);
1096 begin
1097   if fUpdateLock>0 then exit;
1098   UpdatePEProperties;
1099   UpdateButtons;
1100 end;
1101 
1102 procedure TPackageEditorForm.HelpBitBtnClick(Sender: TObject);
1103 begin
1104   LazarusHelp.ShowHelpForIDEControl(Self);
1105 end;
1106 
1107 procedure TPackageEditorForm.InstallClick(Sender: TObject);
1108 begin
1109   PackageEditors.InstallPackage(LazPackage);
1110 end;
1111 
1112 procedure TPackageEditorForm.MaxVersionEditChange(Sender: TObject);
1113 begin
1114   UpdateApplyDependencyButton;
1115 end;
1116 
1117 procedure TPackageEditorForm.MinVersionEditChange(Sender: TObject);
1118 begin
1119   UpdateApplyDependencyButton;
1120 end;
1121 
1122 procedure TPackageEditorForm.SetDepDefaultFilenameMenuItemClick(Sender: TObject);
1123 begin
1124   SetDependencyDefaultFilename(false);
1125 end;
1126 
1127 procedure TPackageEditorForm.SetDepPreferredFilenameMenuItemClick(Sender: TObject);
1128 begin
1129   SetDependencyDefaultFilename(true);
1130 end;
1131 
1132 procedure TPackageEditorForm.ClearDependencyFilenameMenuItemClick(Sender: TObject);
1133 var
1134   CurDependency: TPkgDependency;
1135 begin
1136   if (LazPackage=nil) or LazPackage.ReadOnly then exit;
1137   CurDependency:=GetSingleSelectedDependency;
1138   if CurDependency.DefaultFilename='' then exit;
1139   CurDependency.DefaultFilename:='';
1140   CurDependency.PreferDefaultFilename:=false;
1141   LazPackage.Modified:=true;
1142   UpdateRequiredPkgs;
1143 end;
1144 
1145 procedure TPackageEditorForm.CollapseDirectoryMenuItemClick(Sender: TObject);
1146 begin
1147   DoExpandCollapseDirectory(False);
1148 end;
1149 
1150 procedure TPackageEditorForm.MoveUpBtnClick(Sender: TObject);
1151 begin
1152   if SortAlphabetically then exit;
1153   if Assigned(GetSingleSelectedFile) then
1154     DoMoveCurrentFile(-1)
1155   else if Assigned(GetSingleSelectedDependency) then
1156     DoMoveDependency(-1);
1157 end;
1158 
1159 procedure TPackageEditorForm.OnIdle(Sender: TObject; var Done: Boolean);
1160 begin
1161   if fUpdateLock>0 then exit;
1162   IdleConnected:=false;
1163   UpdatePending;
1164 end;
1165 
1166 procedure TPackageEditorForm.MoveDownBtnClick(Sender: TObject);
1167 begin
1168   if SortAlphabetically then exit;
1169   if Assigned(GetSingleSelectedFile) then
1170     DoMoveCurrentFile(1)
1171   else if Assigned(GetSingleSelectedDependency) then
1172     DoMoveDependency(1);
1173 end;
1174 
1175 procedure TPackageEditorForm.OpenFileMenuItemClick(Sender: TObject);
1176 var
1177   CurFile: TPkgFile;
1178   CurDependency: TPkgDependency;
1179   i: Integer;
1180   TVNode: TTreeNode;
1181   NodeData: TPENodeData;
1182   Item: TObject;
1183 begin
1184   for i:=0 to ItemsTreeView.SelectionCount-1 do begin
1185     TVNode:=ItemsTreeView.Selections[i];
1186     if GetNodeDataItem(TVNode,NodeData,Item) then begin
1187       if Item is TPkgFile then begin
1188         CurFile:=TPkgFile(Item);
1189         if DoOpenPkgFile(CurFile)<>mrOk then exit;
1190       end else if Item is TPkgDependency then begin
1191         CurDependency:=TPkgDependency(Item);
1192         if PackageEditors.OpenDependency(Self,CurDependency)<>mrOk then exit;
1193       end;
1194     end;
1195   end;
1196 end;
1197 
1198 procedure TPackageEditorForm.OptionsBitBtnClick(Sender: TObject);
1199 const
1200   Settings: array[Boolean] of TIDEOptionsEditorSettings = (
1201     [],
1202     [ioesReadOnly]
1203   );
1204 begin
1205   Package1 := LazPackage;
1206   Package1.IDEOptions.OnBeforeRead:=PackageEditors.OnBeforeReadPackage;
1207   Package1.IDEOptions.OnAfterWrite:=PackageEditors.OnAfterWritePackage;
1208   LazarusIDE.DoOpenIDEOptions(nil,
1209     Format(lisPckEditCompilerOptionsForPackage, [LazPackage.IDAsString]),
1210     [TPackageIDEOptions, TPkgCompilerOptions], Settings[LazPackage.ReadOnly]);
1211   UpdateTitle;
1212   UpdateButtons;
1213   UpdateStatusBar;
1214 end;
1215 
1216 procedure TPackageEditorForm.PackageEditorFormClose(Sender: TObject;
1217   var CloseAction: TCloseAction);
1218 begin
1219   //debugln(['TPackageEditorForm.PackageEditorFormClose ',Caption]);
1220   if LazPackage=nil then exit;
1221 end;
1222 
1223 procedure TPackageEditorForm.PackageEditorFormCloseQuery(Sender: TObject;
1224   var CanClose: boolean);
1225 var
1226   MsgResult: Integer;
1227 begin
1228   //debugln(['TPackageEditorForm.PackageEditorFormCloseQuery ',Caption]);
1229   if (LazPackage<>nil) and (not (lpfDestroying in LazPackage.Flags)) then
1230   begin
1231     if (not LazPackage.ReadOnly) and LazPackage.Modified then
1232     begin
1233       MsgResult:=MessageDlg(lisPkgMangSavePackage,
1234         Format(lisPckEditPackageHasChangedSavePackage, [LazPackage.IDAsString, LineEnding]),
1235         mtConfirmation,[mbYes,mbNo,mbAbort],0);
1236       case MsgResult of
1237         mrYes:
1238           MsgResult:=PackageEditors.SavePackage(LazPackage,false);
1239         mrNo:
1240           LazPackage.UserIgnoreChangeStamp:=LazPackage.ChangeStamp;
1241       end;
1242       if MsgResult=mrAbort then CanClose:=false;
1243       LazPackage.Modified:=false; // clear modified flag, so that it will be closed
1244     end;
1245     if CanClose and not MainIDE.IDEIsClosing then
1246     begin
1247       if FCompiling then begin
1248         DebugLn(['TPackageEditorForm.CanCloseEditor: ', Caption, ' compiling, do not close.']);
1249         CanClose:=false;
1250       end
1251       else begin
1252         EnvironmentOptions.LastOpenPackages.Remove(LazPackage.Filename);
1253         MainIDE.SaveEnvironment;
1254       end;
1255     end;
1256   end;
1257   //debugln(['TPackageEditorForm.PackageEditorFormCloseQuery CanClose=',CanClose,' ',Caption]);
1258   if CanClose then
1259     Application.ReleaseComponent(Self);
1260 end;
1261 
1262 procedure TPackageEditorForm.RegisteredListBoxDrawItem(Control: TWinControl;
1263   Index: Integer; ARect: TRect; State: TOwnerDrawState);
1264 var
1265   CurComponent: TPkgComponent;
1266   CurStr: string;
1267   CurObject: TObject;
1268   TxtH: Integer;
1269   IconWidth: Integer;
1270   IconHeight: Integer;
1271   IL: TCustomImageList;
1272   II: TImageIndex;
1273   Res: TScaledImageListResolution;
1274 begin
1275   //DebugLn('TPackageEditorForm.RegisteredListBoxDrawItem START');
1276   if LazPackage=nil then exit;
1277   if (Index<0) or (Index>=FPlugins.Count) then exit;
1278   CurObject:=FPlugins.Objects[Index];
1279   if CurObject is TPkgComponent then begin
1280     // draw registered component
1281     CurComponent:=TPkgComponent(CurObject);
1282     with RegisteredListBox.Canvas do begin
1283       if Assigned(CurComponent.RealPage) then
1284         CurStr:=Format(lisPckEditPage,[CurComponent.ComponentClass.ClassName,
1285                                        CurComponent.RealPage.PageName])
1286       else
1287         CurStr:=CurComponent.ComponentClass.ClassName;
1288       TxtH:=TextHeight(CurStr);
1289       FillRect(ARect);
1290       IL:=CurComponent.Images;
1291       II:=CurComponent.ImageIndex;
1292       //DebugLn('TPackageEditorForm.RegisteredListBoxDrawItem ',DbgSName(CurIcon),' ',CurComponent.ComponentClass.ClassName);
1293       if (IL<>nil) and (II>=0) then begin
1294         Res := IL.ResolutionForControl[0, Self];
1295         IconWidth:=Res.Width;
1296         IconHeight:=Res.Height;
1297         Res.Draw(RegisteredListBox.Canvas,
1298              ARect.Left+(25-IconWidth) div 2,
1299              ARect.Top+(ARect.Bottom-ARect.Top-IconHeight) div 2,
1300              II);
1301       end;
1302       TextOut(ARect.Left+25,
1303               ARect.Top+(ARect.Bottom-ARect.Top-TxtH) div 2,
1304               CurStr);
1305     end;
1306   end;
1307 end;
1308 
1309 procedure TPackageEditorForm.RemoveBitBtnClick(Sender: TObject);
1310 var
1311   MainUnitSelected: Boolean;
1312   FileWarning, PkgWarning: String;
1313   FileCount, PkgCount: Integer;
1314 
1315   procedure CheckFileSelection(CurFile: TPkgFile);
1316   begin
1317     inc(FileCount);
1318     if CurFile.FileType=pftMainUnit then
1319       MainUnitSelected:=true;
1320     if FileWarning='' then
1321       FileWarning:=Format(lisPckEditRemoveFileFromPackage,
1322                           [CurFile.Filename, LineEnding, LazPackage.IDAsString]);
1323   end;
1324 
1325   procedure CheckPkgSelection(CurDependency: TPkgDependency);
1326   begin
1327     inc(PkgCount);
1328     if PkgWarning='' then
1329       PkgWarning:=Format(lisPckEditRemoveDependencyFromPackage,
1330                     [CurDependency.AsString, LineEnding, LazPackage.IDAsString]);
1331   end;
1332 
ConfirmFileDeletionnull1333   function ConfirmFileDeletion: TModalResult;
1334   var
1335     mt: TMsgDlgType;
1336     s: String;
1337   begin
1338     mt:=mtConfirmation;
1339     if FileCount=1 then
1340       s:=FileWarning
1341     else
1342       s:=Format(lisRemoveFilesFromPackage, [IntToStr(FileCount), LazPackage.Name]);
1343     if MainUnitSelected then begin
1344       s+=Format(lisWarningThisIsTheMainUnitTheNewMainUnitWillBePas,
1345                 [LineEnding+LineEnding, lowercase(LazPackage.Name)]);
1346       mt:=mtWarning;
1347     end;
1348     Result:=IDEMessageDialog(lisPckEditRemoveFile2, s, mt, [mbYes,mbNo]);
1349   end;
1350 
ConfirmPkgDeletionnull1351   function ConfirmPkgDeletion: TModalResult;
1352   var
1353     mt: TMsgDlgType;
1354     s: String;
1355   begin
1356     mt:=mtConfirmation;
1357     if PkgCount=1 then
1358       s:=PkgWarning
1359     else
1360       s:=Format(lisRemoveDependenciesFromPackage, [IntToStr(PkgCount), LazPackage.Name]);
1361     Result:=IDEMessageDialog(lisRemove2, s, mt, [mbYes, mbNo]);
1362   end;
1363 
1364 var
1365   ANode: TTreeNode;
1366   TVNode: TTreeNode;
1367   NodeData: TPENodeData;
1368   Item: TObject;
1369   FilesBranch: TTreeFilterBranch;
1370   i: Integer;
1371 begin
1372   BeginUpdate;
1373   try
1374     ANode:=ItemsTreeView.Selected;
1375     if (ANode=nil) or LazPackage.ReadOnly then begin
1376       UpdateButtons;
1377       exit;
1378     end;
1379 
1380     MainUnitSelected:=false;
1381     FileCount:=0;
1382     FileWarning:='';
1383     PkgCount:=0;
1384     PkgWarning:='';
1385 
1386     // check selection
1387     for i:=0 to ItemsTreeView.SelectionCount-1 do begin
1388       TVNode:=ItemsTreeView.Selections[i];
1389       if not GetNodeDataItem(TVNode,NodeData,Item) then continue;
1390       if NodeData.Removed then continue;
1391       if Item is TPkgFile then
1392         CheckFileSelection(TPkgFile(Item))
1393       else if Item is TPkgDependency then
1394         CheckPkgSelection(TPkgDependency(Item));
1395     end;
1396     if (FileCount=0) and (PkgCount=0) then begin
1397       UpdateButtons;
1398       exit;
1399     end;
1400 
1401     // confirm deletion
1402     if FileCount>0 then begin
1403       if ConfirmFileDeletion<>mrYes then Exit;
1404       FilesBranch:=FilterEdit.GetExistingBranch(FFilesNode);
1405     end;
1406     if (PkgCount>0) and (ConfirmPkgDeletion<>mrYes) then Exit;
1407 
1408     // remove
1409     for i:=ItemsTreeView.SelectionCount-1 downto 0 do begin
1410       TVNode:=ItemsTreeView.Selections[i];
1411       if not GetNodeDataItem(TVNode, NodeData, Item) then continue;
1412       if NodeData.Removed then continue;
1413       if Item is TPkgFile then begin
1414         FilesBranch.DeleteData(TVNode);
1415         LazPackage.RemoveFileSilently(TPkgFile(Item));
1416       end
1417       else if Item is TPkgDependency then
1418         LazPackage.RemoveRequiredDepSilently(TPkgDependency(Item));
1419     end;
1420     if FileCount>0 then        // Force update for removed files only.
1421       fForcedFlags:=fForcedFlags+[pefNeedUpdateRemovedFiles];
1422     if PkgCount>0 then
1423       fForcedFlags:=fForcedFlags+[pefNeedUpdateRemovedFiles,pefNeedUpdateRequiredPkgs];
1424     LazPackage.Modified:=True;
1425 
1426   finally
1427     EndUpdate;
1428   end;
1429 end;
1430 
1431 procedure TPackageEditorForm.EditVirtualUnitMenuItemClick(Sender: TObject);
1432 begin
1433   DoEditVirtualUnit;
1434 end;
1435 
1436 procedure TPackageEditorForm.ExpandDirectoryMenuItemClick(Sender: TObject);
1437 begin
1438   DoExpandCollapseDirectory(True);
1439 end;
1440 
1441 procedure TPackageEditorForm.FilterEditKeyDown(Sender: TObject; var Key: Word;
1442   Shift: TShiftState);
1443 begin
1444   if Key = VK_RETURN then
1445   begin
1446     OpenFileMenuItemClick(Nil);
1447     Key := VK_UNKNOWN;
1448   end;
1449 end;
1450 
1451 procedure TPackageEditorForm.FindInFilesMenuItemClick(Sender: TObject);
1452 begin
1453   DoFindInFiles;
1454 end;
1455 
1456 procedure TPackageEditorForm.FormCreate(Sender: TObject);
1457 begin
1458   FPlugins:=TStringList.Create;
1459   SetupComponents;
1460   SortAlphabetically := EnvironmentOptions.PackageEditorSortAlphabetically;
1461   ShowDirectoryHierarchy := EnvironmentOptions.PackageEditorShowDirHierarchy;
1462 end;
1463 
1464 procedure TPackageEditorForm.FormDestroy(Sender: TObject);
1465 var
1466   nt: TPENodeType;
1467 begin
1468   IdleConnected:=true;
1469   FreeAndNil(FNextSelectedPart);
1470   EnvironmentOptions.PackageEditorSortAlphabetically := SortAlphabetically;
1471   EnvironmentOptions.PackageEditorShowDirHierarchy := ShowDirectoryHierarchy;
1472   FilterEdit.ForceFilter('');
1473   for nt:=Low(TPENodeType) to High(TPENodeType) do
1474     FreeNodeData(nt);
1475   if PackageEditorMenuRoot.MenuItem=ItemsPopupMenu.Items then
1476     PackageEditorMenuRoot.MenuItem:=nil;
1477   PackageEditors.DoFreeEditor(LazPackage);
1478   FLazPackage:=nil;
1479   FreeAndNil(FPlugins);
1480 end;
1481 
1482 procedure TPackageEditorForm.FormDropFiles(Sender: TObject;
1483   const FileNames: array of String);
1484 var
1485   i: Integer;
1486   NewUnitPaths, NewIncPaths: String;
1487 begin
1488   {$IFDEF VerbosePkgEditDrag}
1489   debugln(['TPackageEditorForm.FormDropFiles ',length(FileNames)]);
1490   {$ENDIF}
1491   if length(FileNames)=0 then exit;
1492   BeginUpdate;
1493   try
1494     NewUnitPaths:='';
1495     NewIncPaths:='';
1496     for i:=0 to high(Filenames) do
1497       LazPackage.AddFileByName(FileNames[i], NewUnitPaths, NewIncPaths);
1498     //UpdateAll(false);
1499     // extend unit and include search path
1500     if not LazPackage.ExtendUnitSearchPath(NewUnitPaths) then exit;
1501     if not LazPackage.ExtendIncSearchPath(NewIncPaths) then exit;
1502   finally
1503     EndUpdate;
1504   end;
1505 end;
1506 
1507 procedure TPackageEditorForm.RevertClick(Sender: TObject);
1508 begin
1509   DoRevert;
1510 end;
1511 
1512 procedure TPackageEditorForm.SaveBitBtnClick(Sender: TObject);
1513 begin
1514   DoSave(false);
1515 end;
1516 
1517 procedure TPackageEditorForm.SaveAsClick(Sender: TObject);
1518 begin
1519   DoSave(true);
1520 end;
1521 
1522 procedure TPackageEditorForm.SortFilesMenuItemClick(Sender: TObject);
1523 begin
1524   DoSortFiles;
1525 end;
1526 
1527 procedure TPackageEditorForm.FixFilesCaseMenuItemClick(Sender: TObject);
1528 begin
1529   DoFixFilesCase;
1530 end;
1531 
1532 procedure TPackageEditorForm.ShowMissingFilesMenuItemClick(Sender: TObject);
1533 begin
1534   DoShowMissingFiles;
1535 end;
1536 
1537 procedure TPackageEditorForm.UninstallClick(Sender: TObject);
1538 begin
1539   PackageEditors.UninstallPackage(LazPackage);
1540 end;
1541 
1542 procedure TPackageEditorForm.UseAllUnitsInDirectoryMenuItemClick(Sender: TObject);
1543 begin
1544   DoUseUnitsInDirectory(true);
1545 end;
1546 
1547 procedure TPackageEditorForm.ViewPkgSourceClick(Sender: TObject);
1548 begin
1549   PackageEditors.ViewPkgSource(LazPackage);
1550 end;
1551 
1552 procedure TPackageEditorForm.ViewPkgTodosClick(Sender: TObject);
1553 begin
1554   PackageEditors.ViewPkgToDos(LazPackage);
1555 end;
1556 
1557 procedure TPackageEditorForm.FreeNodeData(Typ: TPENodeType);
1558 var
1559   NodeData: TPENodeData;
1560   n: TPENodeData;
1561 begin
1562   NodeData:=FFirstNodeData[Typ];
1563   while NodeData<>nil do begin
1564     n:=NodeData;
1565     NodeData:=NodeData.Next;
1566     if Assigned(n.Branch) Then
1567       n.Branch.FreeNodeData(n.Node);
1568     n.Free;
1569   end;
1570   FFirstNodeData[Typ]:=nil;
1571 end;
1572 
TPackageEditorForm.CreateNodeDatanull1573 function TPackageEditorForm.CreateNodeData(Typ: TPENodeType; aName: string;
1574   aRemoved: boolean): TPENodeData;
1575 begin
1576   Result:=TPENodeData.Create(Typ,aName,aRemoved);
1577   Result.Next:=FFirstNodeData[Typ];
1578   FFirstNodeData[Typ]:=Result;
1579 end;
1580 
1581 procedure TPackageEditorForm.UseMaxVersionCheckBoxChange(Sender: TObject);
1582 begin
1583   MaxVersionEdit.Enabled:=UseMaxVersionCheckBox.Checked;
1584   UpdateApplyDependencyButton;
1585 end;
1586 
1587 procedure TPackageEditorForm.UseMinVersionCheckBoxChange(Sender: TObject);
1588 begin
1589   MinVersionEdit.Enabled:=UseMinVersionCheckBox.Checked;
1590   UpdateApplyDependencyButton;
1591 end;
1592 
1593 procedure TPackageEditorForm.UseNoUnitsInDirectoryMenuItemClick(Sender: TObject);
1594 begin
1595   DoUseUnitsInDirectory(false);
1596 end;
1597 
1598 procedure TPackageEditorForm.mnuAddDiskFileClick(Sender: TObject);
1599 var
1600   OpenDialog: TOpenDialog;
1601   i: Integer;
1602   NewUnitPaths, NewIncPaths: String;
1603 begin
1604   OpenDialog:=TOpenDialog.Create(nil);
1605   try
1606     InputHistories.ApplyFileDialogSettings(OpenDialog);
1607     OpenDialog.InitialDir:=LazPackage.GetFileDialogInitialDir(OpenDialog.InitialDir);
1608     OpenDialog.Title:=lisOpenFile;
1609     OpenDialog.Options:=OpenDialog.Options
1610                           +[ofFileMustExist,ofPathMustExist,ofAllowMultiSelect];
1611     OpenDialog.Filter:=
1612       dlgFilterAll+' ('+GetAllFilesMask+')|'+GetAllFilesMask
1613       +'|'+dlgFilterLazarusUnit+' (*.pas;*.pp)|*.pas;*.pp'
1614       +'|'+dlgFilterLazarusProject+' (*.lpi)|*.lpi'
1615       +'|'+dlgFilterLazarusForm+' (*.lfm;*.dfm)|*.lfm;*.dfm'
1616       +'|'+dlgFilterLazarusPackage+' (*.lpk)|*.lpk'
1617       +'|'+dlgFilterLazarusProjectSource+' (*.lpr)|*.lpr';
1618     if OpenDialog.Execute then begin
1619       InputHistories.StoreFileDialogSettings(OpenDialog);
1620       NewUnitPaths:='';
1621       NewIncPaths:='';
1622       for i:=0 to OpenDialog.Files.Count-1 do
1623         LazPackage.AddFileByName(OpenDialog.Files[i], NewUnitPaths, NewIncPaths);
1624       //UpdateAll(false);
1625       // extend unit and include search path
1626       if not LazPackage.ExtendUnitSearchPath(NewUnitPaths) then exit;
1627       if not LazPackage.ExtendIncSearchPath(NewIncPaths) then exit;
1628     end;
1629   finally
1630     OpenDialog.Free;
1631   end;
1632 end;
1633 
1634 procedure TPackageEditorForm.AddToUsesPkgSectionCheckBoxChange(Sender: TObject);
1635 var
1636   CurFile: TPkgFile;
1637   OtherFile: TPkgFile;
1638   TVNode: TTreeNode;
1639   NodeData: TPENodeData;
1640   Item: TObject;
1641   i, j: Integer;
1642 begin
1643   if LazPackage=nil then exit;
1644   for i:=0 to ItemsTreeView.SelectionCount-1 do begin
1645     TVNode:=ItemsTreeView.Selections[i];
1646     if not GetNodeDataItem(TVNode,NodeData,Item) then continue;
1647     if not (Item is TPkgFile) then continue;
1648     CurFile:=TPkgFile(Item);
1649     if not (CurFile.FileType in PkgFileUnitTypes) then continue;
1650     if CurFile.AddToUsesPkgSection=AddToUsesPkgSectionCheckBox.Checked then continue;
1651     // change flag
1652     CurFile.AddToUsesPkgSection:=AddToUsesPkgSectionCheckBox.Checked;
1653     if (not NodeData.Removed) and CurFile.AddToUsesPkgSection then begin
1654       // mark all other units with the same name as unused
1655       for j:=0 to LazPackage.FileCount-1 do begin
1656         OtherFile:=LazPackage.Files[j];
1657         if (OtherFile<>CurFile)
1658         and (CompareText(OtherFile.Unit_Name,CurFile.Unit_Name)=0) then
1659           OtherFile.AddToUsesPkgSection:=false;
1660       end;
1661     end;
1662     LazPackage.ModifySilently;
1663   end;
1664 end;
1665 
1666 procedure TPackageEditorForm.AddToProjectClick(Sender: TObject);
1667 begin
1668   if LazPackage=nil then exit;
1669   PackageEditors.AddToProject(LazPackage,false);
1670 end;
1671 
1672 procedure TPackageEditorForm.ApplyDependencyButtonClick(Sender: TObject);
1673 var
1674   Flags: TPkgDependencyFlags;
1675   MinVers, MaxVers: TPkgVersion;
1676   CurDependency: TPkgDependency;
1677 begin
1678   CurDependency:=GetSingleSelectedDependency;
1679   if (LazPackage=nil) or (CurDependency=nil) then exit;
1680 
1681   MinVers:=TPkgVersion.Create;
1682   MaxVers:=TPkgVersion.Create;
1683   try
1684     // Assign relevant data to temp variables
1685     Flags:=CurDependency.Flags;
1686     MinVers.Assign(CurDependency.MinVersion);
1687     MaxVers.Assign(CurDependency.MinVersion);
1688 
1689     // read minimum version
1690     if UseMinVersionCheckBox.Checked then begin
1691       Include(Flags, pdfMinVersion);
1692       if not MinVers.ReadString(MinVersionEdit.Text) then begin
1693         MessageDlg(lisPckEditInvalidMinimumVersion,
1694           Format(lisPckEditTheMinimumVersionIsNotAValidPackageVersion,
1695                  [MinVersionEdit.Text, LineEnding]),
1696           mtError,[mbCancel],0);
1697         exit;
1698       end;
1699     end
1700     else
1701       Exclude(Flags, pdfMinVersion);
1702 
1703     // read maximum version
1704     if UseMaxVersionCheckBox.Checked then begin
1705       Include(Flags, pdfMaxVersion);
1706       if not MaxVers.ReadString(MaxVersionEdit.Text) then begin
1707         MessageDlg(lisPckEditInvalidMaximumVersion,
1708           Format(lisPckEditTheMaximumVersionIsNotAValidPackageVersion,
1709                  [MaxVersionEdit.Text, LineEnding]),
1710           mtError,[mbCancel],0);
1711         exit;
1712       end;
1713     end
1714     else
1715       Exclude(Flags, pdfMaxVersion);
1716 
1717     // Assign changes back to the dependency
1718     CurDependency.Flags := Flags;
1719     CurDependency.MinVersion.Assign(MinVers);
1720     CurDependency.MaxVersion.Assign(MaxVers);
1721 
1722     UpdateNodeImage(ItemsTreeView.Selected);
1723     //fForcedFlags:=[pefNeedUpdateRequiredPkgs];
1724     LazPackage.Modified:=True;
1725   finally
1726     MaxVers.Free;
1727     MinVers.Free;
1728   end;
1729 end;
1730 
1731 procedure TPackageEditorForm.CallRegisterProcCheckBoxChange(Sender: TObject);
1732 var
1733   CurFile: TPkgFile;
1734   TVNode: TTreeNode;
1735   NodeData: TPENodeData;
1736   Item: TObject;
1737   i: Integer;
1738 begin
1739   if LazPackage=nil then exit;
1740   for i:=0 to ItemsTreeView.SelectionCount-1 do begin
1741     TVNode:=ItemsTreeView.Selections[i];
1742     if not GetNodeDataItem(TVNode,NodeData,Item) then continue;
1743     if not (Item is TPkgFile) then continue;
1744     CurFile:=TPkgFile(Item);
1745     if not (CurFile.FileType in PkgFileUnitTypes) then continue;
1746     if CurFile.HasRegisterProc=CallRegisterProcCheckBox.Checked then continue;
1747     CurFile.HasRegisterProc:=CallRegisterProcCheckBox.Checked;
1748     if not NodeData.Removed then
1749       LazPackage.ModifySilently;
1750     UpdateNodeImage(TVNode, NodeData, Item);
1751   end;
1752 end;
1753 
1754 procedure TPackageEditorForm.ChangeFileTypeMenuItemClick(Sender: TObject);
1755 var
1756   CurPFT: TPkgFileType;
1757   CurFile: TPkgFile;
1758   CurItem: TIDEMenuCommand;
1759   i: Integer;
1760   TVNode: TTreeNode;
1761   NodeData: TPENodeData;
1762   Item: TObject;
1763 begin
1764   if LazPackage=nil then exit;
1765   CurItem:=TIDEMenuCommand(Sender);
1766   for CurPFT:=Low(TPkgFileType) to High(TPkgFileType) do begin
1767     if CurItem.Caption=GetPkgFileTypeLocalizedName(CurPFT) then begin
1768       for i:=0 to ItemsTreeView.SelectionCount-1 do begin
1769         TVNode:=ItemsTreeView.Selections[i];
1770         if not GetNodeDataItem(TVNode,NodeData,Item) then continue;
1771         if not (Item is TPkgFile) then continue;
1772         CurFile:=TPkgFile(Item);
1773         if CurFile.FileType=CurPFT then continue;
1774         if (not FilenameIsPascalUnit(CurFile.Filename))
1775         and (CurPFT in PkgFileUnitTypes) then
1776           continue;
1777         CurFile.FileType:=CurPFT;
1778         if not NodeData.Removed then
1779           LazPackage.ModifySilently;
1780       end;
1781       exit;
1782     end;
1783   end;
1784 end;
1785 
1786 procedure TPackageEditorForm.CleanDependenciesMenuItemClick(Sender: TObject);
1787 var
1788   ListOfNodeInfos: TObjectList;
1789   i: Integer;
1790   Info: TCPDNodeInfo;
1791   Dependency: TPkgDependency;
1792 begin
1793   if LazPackage=nil then exit;
1794   BeginUpdate;
1795   ListOfNodeInfos:=nil;
1796   try
1797     if ShowCleanPkgDepDlg(LazPackage,ListOfNodeInfos)<>mrOk then exit;
1798     for i:=0 to ListOfNodeInfos.Count-1 do begin
1799       Info:=TCPDNodeInfo(ListOfNodeInfos[i]);
1800       Dependency:=LazPackage.FindDependencyByName(Info.Dependency);
1801       if Dependency<>nil then begin
1802         fForcedFlags:=[pefNeedUpdateRemovedFiles,pefNeedUpdateRequiredPkgs];
1803         PackageGraph.RemoveDependencyFromPackage(LazPackage,Dependency,true);
1804       end;
1805     end;
1806   finally
1807     ListOfNodeInfos.Free;
1808     EndUpdate;
1809   end;
1810 end;
1811 
1812 procedure TPackageEditorForm.CompileAllCleanClick(Sender: TObject);
1813 begin
1814   if LazPackage=nil then exit;
1815   if MessageDlg(lisPckEditCompileEverything,
1816     lisPckEditReCompileThisAndAllRequiredPackages,
1817     mtConfirmation,[mbYes,mbNo],0)<>mrYes then exit;
1818   DoCompile(true,true,true);
1819 end;
1820 
1821 procedure TPackageEditorForm.CompileCleanClick(Sender: TObject);
1822 begin
1823   DoCompile(true,false,true);
1824 end;
1825 
1826 procedure TPackageEditorForm.CopyMoveToDirMenuItemClick(Sender: TObject);
1827 begin
1828   PackageEditors.OnCopyMoveFiles(Self);
1829 end;
1830 
1831 procedure TPackageEditorForm.CompileBitBtnClick(Sender: TObject);
1832 begin
1833   DoCompile(false,false,true);
1834 end;
1835 
1836 procedure TPackageEditorForm.CreateMakefileClick(Sender: TObject);
1837 begin
1838   PackageEditors.CreateMakefile(LazPackage);
1839 end;
1840 
1841 procedure TPackageEditorForm.CreateFpmakeFileClick(Sender: TObject);
1842 begin
1843   PackageEditors.CreateFpmakeFile(LazPackage);
1844 end;
1845 
1846 procedure TPackageEditorForm.DirectoryHierarchyButtonClick(Sender: TObject);
1847 begin
1848   ShowDirectoryHierarchy:=DirectoryHierarchyButton.Down;
1849 end;
1850 
1851 procedure TPackageEditorForm.DisableI18NForLFMCheckBoxChange(Sender: TObject);
1852 var
1853   CurFile: TPkgFile;
1854   i: Integer;
1855   TVNode: TTreeNode;
1856   NodeData: TPENodeData;
1857   Item: TObject;
1858 begin
1859   if LazPackage=nil then exit;
1860   BeginUpdate;
1861   try
1862     for i:=0 to ItemsTreeView.SelectionCount-1 do begin
1863       TVNode:=ItemsTreeView.Selections[i];
1864       if not GetNodeDataItem(TVNode,NodeData,Item) then continue;
1865       if not (Item is TPkgFile) then continue;
1866       CurFile:=TPkgFile(Item);
1867       if not (CurFile.FileType in PkgFileUnitTypes) then continue;
1868       if CurFile.DisableI18NForLFM=DisableI18NForLFMCheckBox.Checked then
1869         continue;
1870       CurFile.DisableI18NForLFM:=DisableI18NForLFMCheckBox.Checked;
1871       if not NodeData.Removed then
1872         LazPackage.Modified:=true;
1873     end;
1874   finally
1875     EndUpdate;
1876   end;
1877 end;
1878 
1879 procedure TPackageEditorForm.SetLazPackage(const AValue: TLazPackage);
1880 begin
1881   //force editor name change when package name changed!
1882   if (FLazPackage=Nil)
1883   and ( (AValue=Nil) or (Name=PkgNameToFormName(AValue.Name)) )
1884   then
1885     exit;
1886   if FLazPackage<>nil then
1887   begin
1888     FLazPackage.Editor:=nil;
1889     if EnvironmentOptions.LastOpenPackages.Remove(FLazPackage.Filename) then
1890       MainIDE.SaveEnvironment;
1891   end;
1892   FLazPackage:=AValue;
1893   if FLazPackage=nil then begin
1894     Name:=Name+'___off___';
1895     exit;
1896   end;
1897   EnvironmentOptions.LastOpenPackages.Add(FLazPackage.Filename);
1898   MainIDE.SaveEnvironment;
1899   FLazPackage.Editor:=Self;
1900   // set Name and update components.
1901   UpdateAll(true);
1902 end;
1903 
1904 procedure TPackageEditorForm.SetupComponents;
1905 
CreateToolButtonnull1906   function CreateToolButton(AName, ACaption, AHint, AImageName: String; AOnClick: TNotifyEvent): TToolButton;
1907   begin
1908     Result := TToolButton.Create(Self);
1909     Result.Name := AName;
1910     Result.Caption := ACaption;
1911     Result.Hint := AHint;
1912     if AImageName <> '' then
1913       Result.ImageIndex := IDEImages.LoadImage(AImageName);
1914     Result.ShowHint := True;
1915     Result.OnClick := AOnClick;
1916     Result.AutoSize := True;
1917     Result.Parent := ToolBar;
1918   end;
1919 
CreateDividernull1920   function CreateDivider: TToolButton;
1921   begin
1922     Result := TToolButton.Create(Self);
1923     Result.Style := tbsDivider;
1924     Result.AutoSize := True;
1925     Result.Parent := ToolBar;
1926   end;
1927 
1928 begin
1929   ImageIndexFiles           := IDEImages.LoadImage('pkg_files');
1930   ImageIndexRemovedFiles    := IDEImages.LoadImage('pkg_removedfiles');
1931   ImageIndexRequired        := IDEImages.LoadImage('pkg_required');
1932   ImageIndexRemovedRequired := IDEImages.LoadImage('pkg_removedrequired');
1933   ImageIndexUnit            := IDEImages.LoadImage('pkg_unit');
1934   ImageIndexRegisterUnit    := IDEImages.LoadImage('pkg_registerunit');
1935   ImageIndexLFM             := IDEImages.LoadImage('pkg_lfm');
1936   ImageIndexLRS             := IDEImages.LoadImage('pkg_lrs');
1937   ImageIndexInclude         := IDEImages.LoadImage('pkg_include');
1938   ImageIndexIssues          := IDEImages.LoadImage('pkg_issues');
1939   ImageIndexText            := IDEImages.LoadImage('pkg_text');
1940   ImageIndexBinary          := IDEImages.LoadImage('pkg_binary');
1941   ImageIndexConflict        := IDEImages.LoadImage('pkg_conflict');
1942   ImageIndexDirectory       := IDEImages.LoadImage('pkg_files');
1943 
1944   ItemsTreeView.Images := IDEImages.Images_16;
1945   ToolBar.Images := IDEImages.Images_16;
1946   FilterEdit.OnGetImageIndex:=@OnTreeViewGetImageIndex;
1947 
1948   SaveBitBtn    := CreateToolButton('SaveBitBtn', lisMenuSave, lisPckEditSavePackage, 'laz_save', @SaveBitBtnClick);
1949   CompileBitBtn := CreateToolButton('CompileBitBtn', lisCompile, lisPckEditCompilePackage, 'pkg_compile', @CompileBitBtnClick);
1950   UseBitBtn     := CreateToolButton('UseBitBtn', lisUse, lisClickToSeeTheChoices, 'pkg_install', nil);
1951   UseBitBtn.Style:=tbsButtonDrop;
1952   CreateDivider;
1953   AddBitBtn     := CreateToolButton('AddBitBtn', lisAdd, lisClickToSeeTheChoices, 'laz_add', nil);
1954   AddBitBtn.Style:=tbsButtonDrop;
1955   RemoveBitBtn  := CreateToolButton('RemoveBitBtn', lisRemove, lisPckEditRemoveSelectedItem, 'laz_delete', @RemoveBitBtnClick);
1956   CreateDivider;
1957   OptionsBitBtn := CreateToolButton('OptionsBitBtn', lisOptions, lisPckEditEditGeneralOptions, 'pkg_properties', @OptionsBitBtnClick);
1958   HelpBitBtn    := CreateToolButton('HelpBitBtn', GetButtonCaption(idButtonHelp), lisMenuOnlineHelp, 'btn_help', @HelpBitBtnClick);
1959   MoreBitBtn    := CreateToolButton('MoreBitBtn', lisMoreSub, lisPkgEdMoreFunctionsForThePackage, '', nil);
1960   MoreBitBtn.Style:=tbsButtonDrop;
1961 
1962   UseBitBtn.DropdownMenu := UsePopupMenu;
1963   AddBitBtn.DropdownMenu := AddPopupMenu;
1964   MoreBitBtn.DropdownMenu := MorePopupMenu;
1965 
1966   mnuAddDiskFile.Caption := lisPckEditAddFilesFromFileSystem;
1967   mnuAddNewFile.Caption := lisA2PNewFile;
1968   mnuAddNewComp.Caption := lisMenuNewComponent;
1969   mnuAddNewReqr.Caption := lisProjAddNewRequirement;
1970   mnuAddFPMakeReq.Caption := lisProjAddNewFPMakeRequirement;
1971 
1972   // Buttons on FilterPanel
1973   IDEImages.AssignImage(OpenButton, 'laz_open');
1974   OpenButton.Hint:=lisOpenFile2;
1975   SortAlphabeticallyButton.Hint:=lisPESortFilesAlphabetically;
1976   IDEImages.AssignImage(SortAlphabeticallyButton, 'pkg_sortalphabetically');
1977   DirectoryHierarchyButton.Hint:=lisPEShowDirectoryHierarchy;
1978   IDEImages.AssignImage(DirectoryHierarchyButton, 'pkg_hierarchical');
1979 
1980   // Up / Down buttons
1981   IDEImages.AssignImage(MoveUpBtn, 'arrow_up');
1982   IDEImages.AssignImage(MoveDownBtn, 'arrow_down');
1983   MoveUpBtn.Hint:=lisMoveSelectedUp;
1984   MoveDownBtn.Hint:=lisMoveSelectedDown;
1985 
1986   ItemsTreeView.BeginUpdate;
1987   FFilesNode:=ItemsTreeView.Items.Add(nil, dlgEnvFiles);
1988   FFilesNode.ImageIndex:=ImageIndexFiles;
1989   FFilesNode.SelectedIndex:=FFilesNode.ImageIndex;
1990   FRequiredPackagesNode:=ItemsTreeView.Items.Add(nil, lisPckEditRequiredPackages);
1991   FRequiredPackagesNode.ImageIndex:=ImageIndexRequired;
1992   FRequiredPackagesNode.SelectedIndex:=FRequiredPackagesNode.ImageIndex;
1993   ItemsTreeView.EndUpdate;
1994 
1995   PropsGroupBox.Caption:=lisPckEditFileProperties;
1996 
1997   CallRegisterProcCheckBox.Caption:=lisPckEditRegisterUnit;
1998   CallRegisterProcCheckBox.Hint:=Format(lisPckEditCallRegisterProcedureOfSelectedUnit, ['"', '"']);
1999 
2000   AddToUsesPkgSectionCheckBox.Caption:=lisPkgMangUseUnit;
2001   AddToUsesPkgSectionCheckBox.Hint:=lisPkgMangAddUnitToUsesClause;
2002 
2003   DisableI18NForLFMCheckBox.Caption:=lisPckDisableI18NOfLfm;
2004   DisableI18NForLFMCheckBox.Hint:=lisPckWhenTheFormIsSavedTheIDECanStoreAllTTranslateString;
2005 
2006   UseMinVersionCheckBox.Caption:=lisPckEditMinimumVersion;
2007   UseMaxVersionCheckBox.Caption:=lisPckEditMaximumVersion;
2008   ApplyDependencyButton.Caption:=lisPckEditApplyChanges;
2009   RegisteredPluginsGroupBox.Caption:=lisPckEditRegisteredPlugins;
2010   RegisteredListBox.ItemHeight:=ComponentPaletteImageHeight;
2011 
2012   FDirSummaryLabel:=TLabel.Create(Self);
2013   with FDirSummaryLabel do
2014   begin
2015     Name:='DirSummaryLabel';
2016     Parent:=PropsGroupBox;
2017   end;
2018 end;
2019 
2020 procedure TPackageEditorForm.SetDependencyDefaultFilename(AsPreferred: boolean);
2021 var
2022   NewFilename: String;
2023   CurDependency: TPkgDependency;
2024 begin
2025   if LazPackage=nil then exit;
2026   CurDependency:=GetSingleSelectedDependency;
2027   if CurDependency=nil then exit;
2028   if LazPackage.ReadOnly then exit;
2029   if CurDependency.RequiredPackage=nil then exit;
2030   NewFilename:=CurDependency.RequiredPackage.Filename;
2031   if (NewFilename=CurDependency.DefaultFilename)
2032   and (CurDependency.PreferDefaultFilename=AsPreferred) then
2033     exit;
2034   BeginUpdate;
2035   try
2036     CurDependency.DefaultFilename:=NewFilename;
2037     CurDependency.PreferDefaultFilename:=AsPreferred;
2038     LazPackage.Modified:=true;
2039     UpdateRequiredPkgs;
2040   finally
2041     EndUpdate;
2042   end;
2043 end;
2044 
2045 procedure TPackageEditorForm.SetIdleConnected(AValue: boolean);
2046 begin
2047   if csDestroying in ComponentState then
2048     AValue:=false;
2049   if FIdleConnected=AValue then Exit;
2050   FIdleConnected:=AValue;
2051   if IdleConnected then
2052     Application.AddOnIdleHandler(@OnIdle)
2053   else
2054     Application.RemoveOnIdleHandler(@OnIdle);
2055 end;
2056 
2057 procedure TPackageEditorForm.SetShowDirectoryHierarchy(const AValue: boolean);
2058 begin
2059   //debugln(['TPackageEditorForm.SetShowDirectoryHierachy Old=',FShowDirectoryHierarchy,' New=',AValue]);
2060   if FShowDirectoryHierarchy=AValue then exit;
2061   FShowDirectoryHierarchy:=AValue;
2062   DirectoryHierarchyButton.Down:=FShowDirectoryHierarchy;
2063   FilterEdit.ShowDirHierarchy:=FShowDirectoryHierarchy;
2064   FilterEdit.InvalidateFilter;
2065 end;
2066 
2067 procedure TPackageEditorForm.SetSortAlphabetically(const AValue: boolean);
2068 begin
2069   if FSortAlphabetically=AValue then exit;
2070   FSortAlphabetically:=AValue;
2071   SortAlphabeticallyButton.Down:=FSortAlphabetically;
2072   FilterEdit.SortData:=FSortAlphabetically;
2073   FilterEdit.InvalidateFilter;
2074 end;
2075 
2076 procedure TPackageEditorForm.UpdateAll(Immediately: boolean);
2077 begin
2078   if csDestroying in ComponentState then exit;
2079   if LazPackage=nil then exit;
2080   Name:=PkgNameToFormName(LazPackage.Name);
2081   if fForcedFlags<>[] then
2082     fFlags:=fFlags+fForcedFlags  // Flags forcing a partial update
2083   else
2084     fFlags:=fFlags+[             // Otherwise all flags.
2085       pefNeedUpdateTitle,
2086       pefNeedUpdateFiles,
2087       pefNeedUpdateRemovedFiles,
2088       pefNeedUpdateRequiredPkgs,
2089       pefNeedUpdateProperties,
2090       pefNeedUpdateButtons,
2091       pefNeedUpdateApplyDependencyButton,
2092       pefNeedUpdateStatusBar];
2093   if Immediately then
2094     UpdatePending
2095   else
2096     IdleConnected:=true;
2097 end;
2098 
2099 procedure TPackageEditorForm.DoAddNewFile(NewItem: TNewIDEItemTemplate);
2100 var
2101   NewFilename: String;
2102   DummyResult: TModalResult;
2103   NewFileType: TPkgFileType;
2104   NewPkgFileFlags: TPkgFileFlags;
2105   Desc: TProjectFileDescriptor;
2106   NewUnitName: String;
2107   HasRegisterProc: Boolean;
2108 begin
2109   if NewItem is TNewItemProjectFile then begin
2110     // create new file
2111     Desc:=TNewItemProjectFile(NewItem).Descriptor;
2112     NewFilename:='';
2113     DummyResult:=LazarusIDE.DoNewFile(Desc,NewFilename,'',
2114       [nfOpenInEditor,nfCreateDefaultSrc,nfIsNotPartOfProject],LazPackage);
2115     if DummyResult=mrOk then begin
2116       // success -> now add it to package
2117       NewUnitName:='';
2118       NewFileType:=FileNameToPkgFileType(NewFilename);
2119       NewPkgFileFlags:=[];
2120       if (NewFileType in PkgFileUnitTypes) then begin
2121         Include(NewPkgFileFlags,pffAddToPkgUsesSection);
2122         NewUnitName:=ExtractFilenameOnly(NewFilename);
2123         if Assigned(PackageEditors.OnGetUnitRegisterInfo) then begin
2124           HasRegisterProc:=false;
2125           PackageEditors.OnGetUnitRegisterInfo(Self,NewFilename,
2126             NewUnitName,HasRegisterProc);
2127           if HasRegisterProc then
2128             Include(NewPkgFileFlags,pffHasRegisterProc);
2129         end;
2130       end;
2131       LazPackage.AddFile(NewFilename,NewUnitName,NewFileType,
2132                                               NewPkgFileFlags, cpNormal);
2133       FreeAndNil(FNextSelectedPart);
2134       FNextSelectedPart:=TPENodeData.Create(penFile,NewFilename,false);
2135     end;
2136   end;
2137 end;
2138 
ShowNewCompDialognull2139 function TPackageEditorForm.ShowNewCompDialog: TModalResult;
2140 var
2141   IgnoreUnitPaths: TFilenameToStringTree;
2142 
PkgDependsOnnull2143   function PkgDependsOn(PkgName: string): boolean;
2144   begin
2145     if PkgName='' then exit(false);
2146     Result:=PackageGraph.FindDependencyRecursively(LazPackage.FirstRequiredDependency,PkgName)<>nil;
2147   end;
2148 
2149   procedure AddNewComponent(AddParams: TAddToPkgResult);
2150   begin
2151     ExtendUnitIncPathForNewUnit(AddParams.UnitFilename, '', IgnoreUnitPaths);
2152     // add file
2153     with AddParams do
2154     begin
2155       Assert(FilenameIsAbsolute(UnitFilename), 'AddNewComponent: Filename is relative.');
2156       // This file can also replace an existing file.
2157       if LazPackage.FindPkgFile(UnitFilename,true,false)=nil then
2158         LazPackage.AddFile(UnitFilename, Unit_Name, FileType, PkgFileFlags, cpNormal)
2159       else
2160         LazPackage.Modified:=True;
2161       FreeAndNil(FNextSelectedPart);
2162       FNextSelectedPart:=TPENodeData.Create(penFile, UnitFilename, false);
2163       PackageEditors.DeleteAmbiguousFiles(LazPackage, UnitFilename);
2164     end;
2165     // open file in editor
2166     PackageEditors.CreateNewFile(Self,AddParams);
2167   end;
2168 
2169 var
2170   AddParams, OldParams: TAddToPkgResult;
2171 begin
2172   if LazPackage.ReadOnly then begin
2173     UpdateButtons;
2174     exit(mrCancel);
2175   end;
2176 
2177   Result:=ShowAddToPackageDlg(LazPackage, AddParams);
2178   if Result<>mrOk then exit;
2179 
2180   PackageGraph.BeginUpdate(false);
2181   IgnoreUnitPaths:=nil;
2182   try
2183     while AddParams<>nil do begin
2184       AddNewComponent(AddParams);
2185       OldParams:=AddParams;
2186       AddParams:=AddParams.Next;
2187       OldParams.Next:=nil;
2188       OldParams.Free;
2189     end;
2190     AddParams.Free;
2191     Assert(LazPackage.Modified, 'TPackageEditorForm.ShowAddDialog: LazPackage.Modified = False');
2192   finally
2193     IgnoreUnitPaths.Free;
2194     PackageGraph.EndUpdate;
2195   end;
2196 end;
2197 
TPackageEditorForm.ShowAddDepDialognull2198 function TPackageEditorForm.ShowAddDepDialog: TModalResult;
2199 var
2200   Deps: TPkgDependencyList;
2201   i: Integer;
2202 begin
2203   if LazPackage.ReadOnly then begin
2204     UpdateButtons;
2205     exit(mrCancel);
2206   end;
2207   Result:=ShowAddPkgDependencyDlg(LazPackage, Deps);
2208   try
2209     if (Result<>mrOk) or (Deps.Count=0) then exit;
2210     PackageGraph.BeginUpdate(false);
2211     try
2212       // add all dependencies
2213       fForcedFlags := [pefNeedUpdateRequiredPkgs];
2214       FreeAndNil(FNextSelectedPart);
2215       for i := 0 to Deps.Count-1 do
2216         PackageGraph.AddDependencyToPackage(LazPackage, Deps[i]);
2217       FNextSelectedPart := TPENodeData.Create(penDependency,
2218                                             Deps[Deps.Count-1].PackageName, false);
2219       Assert(LazPackage.Modified, 'TPackageEditorForm.ShowAddDepDialog: LazPackage.Modified = False');
2220     finally
2221       PackageGraph.EndUpdate;
2222     end;
2223   finally
2224     Deps.Free;
2225   end;
2226 end;
2227 
TPackageEditorForm.ShowAddFPMakeDepDialognull2228 function TPackageEditorForm.ShowAddFPMakeDepDialog: TModalResult;
2229 var
2230   Deps: TPkgDependencyList;
2231   i: Integer;
2232 begin
2233   if LazPackage.ReadOnly then begin
2234     UpdateButtons;
2235     exit(mrCancel);
2236   end;
2237   Result:=ShowAddFPMakeDependencyDlg(LazPackage, Deps);
2238   try
2239     if (Result<>mrOk) or (Deps.Count=0) then exit;
2240     PackageGraph.BeginUpdate(false);
2241     try
2242       // add all dependencies
2243       fForcedFlags := [pefNeedUpdateRequiredPkgs];
2244       FreeAndNil(FNextSelectedPart);
2245       for i := 0 to Deps.Count-1 do
2246         PackageGraph.AddDependencyToPackage(LazPackage, Deps[i]);
2247       FNextSelectedPart := TPENodeData.Create(penDependency,
2248                                             Deps[Deps.Count-1].PackageName, false);
2249       Assert(LazPackage.Modified, 'TPackageEditorForm.ShowAddFPMakeDepDialog: LazPackage.Modified = False');
2250     finally
2251       PackageGraph.EndUpdate;
2252     end;
2253   finally
2254     Deps.Free;
2255   end;
2256 
2257 end;
2258 
TPackageEditorForm.PkgNameToFormNamenull2259 function TPackageEditorForm.PkgNameToFormName(const PkgName: string): string;
2260 begin
2261   Result:=PackageEditorWindowPrefix+StringReplace(PkgName,'.','_',[rfReplaceAll]);
2262 end;
2263 
TPackageEditorForm.GetSingleSelectedDependencynull2264 function TPackageEditorForm.GetSingleSelectedDependency: TPkgDependency;
2265 var
2266   i: Integer;
2267   TVNode: TTreeNode;
2268   NodeData: TPENodeData;
2269   Item: TObject;
2270 begin
2271   Result:=nil;
2272   for i:=0 to ItemsTreeView.SelectionCount-1 do begin
2273     TVNode:=ItemsTreeView.Selections[i];
2274     if not GetNodeDataItem(TVNode,NodeData,Item) then continue;
2275     if Item is TPkgFile then begin
2276       Result:=nil;
2277       break;
2278     end else if Item is TPkgDependency then begin
2279       if Result<>nil then begin
2280         // not single selected
2281         Result:=nil;
2282         break;
2283       end;
2284       Result:=TPkgDependency(Item);
2285     end;
2286   end;
2287 end;
2288 
TPackageEditorForm.GetSingleSelectedFilenull2289 function TPackageEditorForm.GetSingleSelectedFile: TPkgFile;
2290 var
2291   i: Integer;
2292   TVNode: TTreeNode;
2293   NodeData: TPENodeData;
2294   Item: TObject;
2295 begin
2296   Result:=nil;
2297   for i:=0 to ItemsTreeView.SelectionCount-1 do begin
2298     TVNode:=ItemsTreeView.Selections[i];
2299     if not GetNodeDataItem(TVNode,NodeData,Item) then continue;
2300     if Item is TPkgFile then begin
2301       if Result<>nil then begin
2302         // not single selected
2303         Result:=nil;
2304         break;
2305       end;
2306       Result:=TPkgFile(Item);
2307       break;
2308     end else if Item is TPkgDependency then begin
2309       Result:=nil;
2310       break;
2311     end;
2312   end;
2313 end;
2314 
2315 procedure TPackageEditorForm.BeginUpdate;
2316 begin
2317   inc(fUpdateLock);
2318 end;
2319 
2320 procedure TPackageEditorForm.EndUpdate;
2321 begin
2322   if fUpdateLock=0 then
2323     RaiseGDBException('');
2324   dec(fUpdateLock);
2325   if fUpdateLock=0 then
2326     IdleConnected:=true;
2327 end;
2328 
2329 procedure TPackageEditorForm.UpdateTitle(Immediately: boolean);
2330 var
2331   NewCaption: String;
2332   s: string;
2333 begin
2334   if not CanUpdate(pefNeedUpdateTitle,Immediately) then exit;
2335   s:=FLazPackage.Name+' V'+FLazPackage.Version.AsString;
2336   NewCaption:=Format(lisPckEditPackage, [s]);
2337   if LazPackage.Modified then
2338     NewCaption:=NewCaption+'*';
2339   Caption:=NewCaption;
2340 end;
2341 
2342 procedure TPackageEditorForm.UpdateNodeImage(TVNode: TTreeNode);
2343 var
2344   NodeData: TPENodeData;
2345   Item: TObject;
2346 begin
2347   if GetNodeDataItem(TVNode, NodeData, Item) then
2348     UpdateNodeImage(TVNode, NodeData, Item);
2349 end;
2350 
2351 procedure TPackageEditorForm.UpdateNodeImage(TVNode: TTreeNode;
2352   NodeData: TPENodeData; Item: TObject);
2353 var
2354   PkgDependency: TPkgDependency;
2355   ImgIndex: Integer;
2356   Ena: Boolean;
2357 begin
2358   Assert(Assigned(Item), 'TPackageEditorForm.UpdateNodeImage: Item = Nil.');
2359   if Item is TPkgDependency then begin
2360     PkgDependency:=TPkgDependency(Item);
2361     // Try to load the package again. Min/max version may have changed.
2362     PkgDependency.LoadPackageResult := lprUndefined;
2363     PackageGraph.OpenDependency(PkgDependency, False);
2364   end;
2365   Ena := True;                      // Neither Ena nor the String param are used.
2366   ImgIndex := OnTreeViewGetImageIndex('', NodeData, Ena);
2367   TVNode.ImageIndex:=ImgIndex;
2368   TVNode.SelectedIndex:=ImgIndex;
2369 end;
2370 
2371 procedure TPackageEditorForm.UpdateButtons(Immediately: boolean);
2372 var
2373   i: Integer;
2374   TVNode: TTreeNode;
2375   NodeData: TPENodeData;
2376   Item: TObject;
2377   Writable: Boolean;
2378   ActiveFileCnt: Integer;
2379   ActiveDepCount: Integer;
2380   FileCount: Integer;
2381   DepCount: Integer;
2382 begin
2383   if not CanUpdate(pefNeedUpdateButtons,Immediately) then exit;
2384 
2385   FileCount:=0;
2386   DepCount:=0;
2387   ActiveFileCnt:=0;
2388   ActiveDepCount:=0;
2389   for i:=0 to ItemsTreeView.SelectionCount-1 do begin
2390     TVNode:=ItemsTreeView.Selections[i];
2391     if not GetNodeDataItem(TVNode,NodeData,Item) then continue;
2392     if Item is TPkgFile then begin
2393       inc(FileCount);
2394       if not NodeData.Removed then
2395         inc(ActiveFileCnt);
2396     end else if Item is TPkgDependency then begin
2397       inc(DepCount);
2398       if not NodeData.Removed then
2399         inc(ActiveDepCount);
2400     end;
2401   end;
2402 
2403   Writable:=not LazPackage.ReadOnly;
2404   SaveBitBtn.Enabled:=Writable and (LazPackage.IsVirtual or LazPackage.Modified);
2405   CompileBitBtn.Enabled:=(not LazPackage.IsVirtual) and LazPackage.CompilerOptions.HasCommands;
2406   AddBitBtn.Enabled:=Writable;
2407   RemoveBitBtn.Enabled:=Writable and (ActiveFileCnt+ActiveDepCount>0);
2408   OpenButton.Enabled:=(FileCount+DepCount>0);
2409 end;
2410 
OnTreeViewGetImageIndexnull2411 function TPackageEditorForm.OnTreeViewGetImageIndex(Str: String; Data: TObject;
2412                                              var AIsEnabled: Boolean): Integer;
2413 var
2414   PkgFile: TPkgFile;
2415   Item: TObject;
2416   PkgDependency: TPkgDependency;
2417   NodeData: TPENodeData;
2418 begin
2419   Result:=-1;
2420   if not (Data is TPENodeData) then exit;
2421   NodeData:=TPENodeData(Data);
2422   Item:=GetNodeItem(NodeData);
2423   if Item=nil then exit;
2424   if Item is TPkgFile then begin
2425     PkgFile:=TPkgFile(Item);
2426     case PkgFile.FileType of
2427       pftUnit,pftVirtualUnit,pftMainUnit:
2428         if PkgFile.HasRegisterProc then
2429           Result:=ImageIndexRegisterUnit
2430         else
2431           Result:=ImageIndexUnit;
2432       pftLFM: Result:=ImageIndexLFM;
2433       pftLRS: Result:=ImageIndexLRS;
2434       pftInclude: Result:=ImageIndexInclude;
2435       pftIssues: Result:=ImageIndexIssues;
2436       pftText: Result:=ImageIndexText;
2437       pftBinary: Result:=ImageIndexBinary;
2438       else
2439         Result:=-1;
2440     end;
2441   end
2442   else if Item is TPkgDependency then begin
2443     PkgDependency:=TPkgDependency(Item);
2444     if PkgDependency.Removed then
2445       Result:=ImageIndexRemovedRequired
2446     else if PkgDependency.LoadPackageResult=lprSuccess then
2447       Result:=ImageIndexRequired
2448     else
2449       Result:=ImageIndexConflict;
2450   end;
2451 end;
2452 
2453 procedure TPackageEditorForm.UpdatePending;
2454 begin
2455   ItemsTreeView.BeginUpdate;
2456   try
2457     if pefNeedUpdateTitle in fFlags then
2458       UpdateTitle(true);
2459     if pefNeedUpdateFiles in fFlags then
2460       UpdateFiles(true);
2461     if pefNeedUpdateRemovedFiles in fFlags then
2462       UpdateRemovedFiles(true);
2463     if pefNeedUpdateRequiredPkgs in fFlags then
2464       UpdateRequiredPkgs(true);
2465     if pefNeedUpdateProperties in fFlags then
2466       UpdatePEProperties(true);
2467     if pefNeedUpdateButtons in fFlags then
2468       UpdateButtons(true);
2469     if pefNeedUpdateApplyDependencyButton in fFlags then
2470       UpdateApplyDependencyButton(true);
2471     if pefNeedUpdateStatusBar in fFlags then
2472       UpdateStatusBar(true);
2473     IdleConnected:=false;
2474   finally
2475     ItemsTreeView.EndUpdate;
2476     fForcedFlags:=[];
2477   end;
2478 end;
2479 
CanUpdatenull2480 function TPackageEditorForm.CanUpdate(Flag: TPEFlag; Immediately: boolean): boolean;
2481 begin
2482   Result:=false;
2483   if csDestroying in ComponentState then exit;
2484   if LazPackage=nil then exit;
2485   if (fUpdateLock>0) and not Immediately then begin
2486     Include(fFlags,Flag);
2487     IdleConnected:=true;
2488     Result:=false;
2489   end else begin
2490     Exclude(fFlags,Flag);
2491     Result:=true;
2492   end;
2493 end;
2494 
2495 procedure TPackageEditorForm.UpdateFiles(Immediately: boolean);
2496 var
2497   i: Integer;
2498   CurFile: TPkgFile;
2499   FilesBranch: TTreeFilterBranch;
2500   Filename: String;
2501   NodeData: TPENodeData;
2502   OldFilter : String;
2503 begin
2504   if not CanUpdate(pefNeedUpdateFiles,Immediately) then exit;
2505   OldFilter := FilterEdit.ForceFilter('');
2506 
2507   // files belonging to package
2508   FilesBranch:=FilterEdit.GetCleanBranch(FFilesNode);
2509   FreeNodeData(penFile);
2510   FilesBranch.ClearNodeData;
2511   FilterEdit.SelectedPart:=nil;
2512   FilterEdit.ShowDirHierarchy:=ShowDirectoryHierarchy;
2513   FilterEdit.SortData:=SortAlphabetically;
2514   FilterEdit.ImageIndexDirectory:=ImageIndexDirectory;
2515   // collect and sort files
2516   for i:=0 to LazPackage.FileCount-1 do begin
2517     CurFile:=LazPackage.Files[i];
2518     NodeData:=CreateNodeData(penFile,CurFile.Filename,false);
2519     NodeData.FileType:=CurFile.FileType;
2520     Filename:=CurFile.GetShortFilename(true);
2521     if Filename='' then continue;
2522     if (FNextSelectedPart<>nil) and (FNextSelectedPart.Typ=penFile)
2523     and (FNextSelectedPart.Name=NodeData.Name)
2524     then
2525       FilterEdit.SelectedPart:=NodeData;
2526     FilesBranch.AddNodeData(Filename, NodeData, CurFile.Filename);
2527   end;
2528   if (FNextSelectedPart<>nil) and (FNextSelectedPart.Typ=penFile) then
2529     FreeAndNil(FNextSelectedPart);
2530 
2531   FilterEdit.Filter := OldFilter;            // This triggers ApplyFilter
2532   FilterEdit.InvalidateFilter;
2533   UpdatePEProperties;
2534   UpdateButtons;
2535 end;
2536 
2537 procedure TPackageEditorForm.UpdateRemovedFiles(Immediately: boolean = false);
2538 var
2539   i: Integer;
2540   CurFile: TPkgFile;
2541   RemovedBranch: TTreeFilterBranch;
2542   NodeData: TPENodeData;
2543 begin
2544   if not CanUpdate(pefNeedUpdateRemovedFiles,Immediately) then exit;
2545 
2546   if LazPackage.RemovedFilesCount>0 then begin
2547     // Create root node for removed files if not done yet.
2548     if FRemovedFilesNode=nil then begin
2549       FRemovedFilesNode:=ItemsTreeView.Items.Add(FRequiredPackagesNode,
2550                                                  lisPckEditRemovedFiles);
2551       FRemovedFilesNode.ImageIndex:=ImageIndexRemovedFiles;
2552       FRemovedFilesNode.SelectedIndex:=FRemovedFilesNode.ImageIndex;
2553     end;
2554     RemovedBranch:=FilterEdit.GetCleanBranch(FRemovedFilesNode);
2555     RemovedBranch.ClearNodeData;
2556     for i:=0 to LazPackage.RemovedFilesCount-1 do begin
2557       CurFile:=LazPackage.RemovedFiles[i];
2558       NodeData:=CreateNodeData(penFile,CurFile.Filename,true);
2559       RemovedBranch.AddNodeData(CurFile.GetShortFilename(true), NodeData);
2560     end;
2561     RemovedBranch.InvalidateBranch;
2562   end
2563   else begin
2564     // No more removed files left -> delete the root node
2565     if FRemovedFilesNode<>nil then begin
2566       FilterEdit.DeleteBranch(FRemovedFilesNode);
2567       FreeAndNil(FRemovedFilesNode);
2568       FilterEdit.InvalidateFilter;
2569     end;
2570   end;
2571 
2572   UpdatePEProperties;
2573   UpdateButtons;
2574 end;
2575 
2576 procedure TPackageEditorForm.UpdateRequiredPkgs(Immediately: boolean);
2577 var
2578   CurDependency: TPkgDependency;
2579   RequiredBranch, RemovedBranch: TTreeFilterBranch;
2580   OldFilter: String;
2581   NodeData: TPENodeData;
2582 begin
2583   if not CanUpdate(pefNeedUpdateRequiredPkgs,Immediately) then exit;
2584 
2585   OldFilter := FilterEdit.ForceFilter('');
2586 
2587   // required packages
2588   RequiredBranch:=FilterEdit.GetCleanBranch(FRequiredPackagesNode);
2589   FreeNodeData(penDependency);
2590   RequiredBranch.ClearNodeData;
2591   CurDependency:=LazPackage.FirstRequiredDependency;
2592   FilterEdit.SelectedPart:=nil;
2593   while CurDependency<>nil do begin
2594     NodeData:=CreateNodeData(penDependency,CurDependency.PackageName,false);
2595     if (FNextSelectedPart<>nil) and (FNextSelectedPart.Typ=penDependency)
2596     and (FNextSelectedPart.Name=NodeData.Name)
2597     then
2598       FilterEdit.SelectedPart:=NodeData;
2599     RequiredBranch.AddNodeData(DependencyAsString(CurDependency), NodeData);
2600     CurDependency:=CurDependency.NextRequiresDependency;
2601   end;
2602   if (FNextSelectedPart<>nil) and (FNextSelectedPart.Typ=penDependency) then
2603     FreeAndNil(FNextSelectedPart);
2604   RequiredBranch.InvalidateBranch;
2605 
2606   // removed required packages
2607   CurDependency:=LazPackage.FirstRemovedDependency;
2608   if CurDependency<>nil then begin
2609     if FRemovedRequiredNode=nil then begin
2610       FRemovedRequiredNode:=ItemsTreeView.Items.Add(nil,lisPckEditRemovedRequiredPackages);
2611       FRemovedRequiredNode.ImageIndex:=ImageIndexRemovedRequired;
2612       FRemovedRequiredNode.SelectedIndex:=FRemovedRequiredNode.ImageIndex;
2613     end;
2614     RemovedBranch:=FilterEdit.GetCleanBranch(FRemovedRequiredNode);
2615     RemovedBranch.ClearNodeData;
2616     while CurDependency<>nil do begin
2617       NodeData:=CreateNodeData(penDependency,CurDependency.PackageName,true);
2618       RemovedBranch.AddNodeData(DependencyAsString(CurDependency), NodeData);
2619       CurDependency:=CurDependency.NextRequiresDependency;
2620     end;
2621     RemovedBranch.InvalidateBranch;
2622   end else begin
2623     if FRemovedRequiredNode<>nil then begin
2624       FilterEdit.DeleteBranch(FRemovedRequiredNode);
2625       FreeAndNil(FRemovedRequiredNode);
2626     end;
2627   end;
2628   FNextSelectedPart:=nil;
2629   if OldFilter <> '' then begin
2630     FilterEdit.Filter := OldFilter;            // This triggers ApplyFilter
2631     FilterEdit.InvalidateFilter;
2632   end;
2633   UpdatePEProperties;
2634   UpdateButtons;
2635 end;
2636 
2637 procedure TPackageEditorForm.UpdatePEProperties(Immediately: boolean);
2638 type
2639   TMultiBool = (mubNone, mubAllTrue, mubAllFalse, mubMixed);
2640 
2641   procedure MergeMultiBool(var b: TMultiBool; NewValue: boolean);
2642   begin
2643     case b of
2644     mubNone: if NewValue then b:=mubAllTrue else b:=mubAllFalse;
2645     mubAllTrue: if not NewValue then b:=mubMixed;
2646     mubAllFalse: if NewValue then b:=mubMixed;
2647     mubMixed: ;
2648     end;
2649   end;
2650 
2651   procedure SetCheckBox(Box: TCheckBox; aVisible: boolean; State: TMultiBool);
2652   begin
2653     Box.Visible:=aVisible;
2654     case State of
2655     mubAllTrue:
2656       begin
2657         Box.State:=cbChecked;
2658         Box.AllowGrayed:=false;
2659       end;
2660     mubAllFalse:
2661       begin
2662         Box.State:=cbUnchecked;
2663         Box.AllowGrayed:=false;
2664       end;
2665     mubMixed:
2666       begin
2667         Box.AllowGrayed:=true;
2668         Box.State:=cbGrayed;
2669       end;
2670     end;
2671   end;
2672 
2673 var
2674   CurFile: TPkgFile;
2675   CurDependency: TPkgDependency;
2676   CurComponent: TPkgComponent;
2677   CurLine, CurFilename: string;
2678   i, j: Integer;
2679   NodeData: TPENodeData;
2680   Item: TObject;
2681   SelFileCount: Integer;
2682   SelDepCount: Integer;
2683   SelHasRegisterProc: TMultiBool;
2684   SelAddToUsesPkgSection: TMultiBool;
2685   SelDisableI18NForLFM: TMultiBool;
2686   SelUnitCount: Integer;
2687   SelDirCount: Integer;
2688   SelHasLFMCount: Integer;
2689   OnlyFilesSelected: Boolean;
2690   OnlyFilesWithUnitsSelected: Boolean;
2691   aVisible: Boolean;
2692   TVNode: TTreeNode;
2693   SingleSelectedNode: TTreeNode;
2694   SingleSelectedFile: TPkgFile;
2695   SingleSelectedDep: TPkgDependency;
2696   SingleSelectedDirectory: TTreeNode;
2697   SingleSelectedRemoved: Boolean;
2698   FileCount: integer;
2699   HasRegisterProcCount: integer;
2700   AddToUsesPkgSectionCount: integer;
2701 begin
2702   if not CanUpdate(pefNeedUpdateProperties,Immediately) then exit;
2703 
2704   FPlugins.Clear;
2705 
2706   // check selection
2707   SingleSelectedNode:=nil;
2708   SingleSelectedDep:=nil;
2709   SingleSelectedFile:=nil;
2710   SingleSelectedDirectory:=nil;
2711   SingleSelectedRemoved:=false;
2712   SelFileCount:=0;
2713   SelDepCount:=0;
2714   SelHasRegisterProc:=mubNone;
2715   SelAddToUsesPkgSection:=mubNone;
2716   SelDisableI18NForLFM:=mubNone;
2717   SelUnitCount:=0;
2718   SelHasLFMCount:=0;
2719   SelDirCount:=0;
2720   for i:=0 to ItemsTreeView.SelectionCount-1 do begin
2721     TVNode:=ItemsTreeView.Selections[i];
2722     if GetNodeDataItem(TVNode,NodeData,Item) then begin
2723       if Item is TPkgFile then begin
2724         CurFile:=TPkgFile(Item);
2725         inc(SelFileCount);
2726         SingleSelectedFile:=CurFile;
2727         SingleSelectedNode:=TVNode;
2728         SingleSelectedRemoved:=NodeData.Removed;
2729         MergeMultiBool(SelHasRegisterProc,CurFile.HasRegisterProc);
2730         if CurFile.FileType in PkgFileUnitTypes then begin
2731           inc(SelUnitCount);
2732           MergeMultiBool(SelAddToUsesPkgSection,CurFile.AddToUsesPkgSection);
2733           if (CurFile.FileType in PkgFileRealUnitTypes) then
2734           begin
2735             CurFilename:=CurFile.GetFullFilename;
2736             if FilenameIsAbsolute(CurFilename)
2737                 and FileExistsCached(ChangeFileExt(CurFilename,'.lfm'))
2738             then begin
2739               inc(SelHasLFMCount);
2740               MergeMultiBool(SelDisableI18NForLFM,CurFile.DisableI18NForLFM);
2741             end;
2742           end;
2743           // fetch all registered plugins
2744           for j:=0 to CurFile.ComponentCount-1 do begin
2745             CurComponent:=CurFile.Components[j];
2746             CurLine:=CurComponent.ComponentClass.ClassName;
2747             FPlugins.AddObject(CurLine,CurComponent);
2748           end;
2749         end;
2750       end else if Item is TPkgDependency then begin
2751         inc(SelDepCount);
2752         CurDependency:=TPkgDependency(Item);
2753         SingleSelectedDep:=CurDependency;
2754         SingleSelectedNode:=TVNode;
2755         SingleSelectedRemoved:=NodeData.Removed;
2756       end;
2757     end else if IsDirectoryNode(TVNode) or (TVNode=FFilesNode) then begin
2758       inc(SelDirCount);
2759       SingleSelectedDirectory:=TVNode;
2760       SingleSelectedNode:=TVNode;
2761     end;
2762   end;
2763 
2764   if (SelFileCount+SelDepCount+SelDirCount>1) then begin
2765     // it is a multi selection
2766     SingleSelectedFile:=nil;
2767     SingleSelectedDep:=nil;
2768     SingleSelectedDirectory:=nil;
2769     SingleSelectedNode:=nil;
2770   end;
2771   OnlyFilesSelected:=(SelFileCount>0) and (SelDepCount=0) and (SelDirCount=0);
2772   OnlyFilesWithUnitsSelected:=OnlyFilesSelected and (SelUnitCount>0);
2773 
2774   //debugln(['TPackageEditorForm.UpdatePEProperties SelFileCount=',SelFileCount,' SelDepCount=',SelDepCount,' SelDirCount=',SelDirCount,' SelUnitCount=',SelUnitCount]);
2775   //debugln(['TPackageEditorForm.UpdatePEProperties SingleSelectedFile=',SingleSelectedFile<>nil,' SingleSelectedDependency=',SingleSelectedDep<>nil,' SingleSelectedDirectory=',SingleSelectedDirectory<>nil]);
2776 
2777   DisableAlign;
2778   try
2779     // move up/down (only single selection)
2780     aVisible:=(not (SortAlphabetically or SingleSelectedRemoved))
2781        and ((SingleSelectedFile<>nil) or (SingleSelectedDep<>nil));
2782     MoveUpBtn.Enabled  :=aVisible and Assigned(SingleSelectedNode.GetPrevVisibleSibling);
2783     MoveDownBtn.Enabled:=aVisible and Assigned(SingleSelectedNode.GetNextVisibleSibling);
2784 
2785     // Min/Max version of dependency (only single selection)
2786     aVisible:=SingleSelectedDep<>nil;
2787     UseMinVersionCheckBox.Visible:=aVisible;
2788     MinVersionEdit.Visible:=aVisible;
2789     UseMaxVersionCheckBox.Visible:=aVisible;
2790     MaxVersionEdit.Visible:=aVisible;
2791     ApplyDependencyButton.Visible:=aVisible;
2792 
2793     // 'RegisterProc' of files (supports multi selection)
2794     SetCheckBox(CallRegisterProcCheckBox,OnlyFilesWithUnitsSelected, SelHasRegisterProc);
2795     CallRegisterProcCheckBox.Enabled:=(not LazPackage.ReadOnly);
2796 
2797     // 'Add to uses' of files (supports multi selection)
2798     SetCheckBox(AddToUsesPkgSectionCheckBox,OnlyFilesWithUnitsSelected, SelAddToUsesPkgSection);
2799     AddToUsesPkgSectionCheckBox.Enabled:=(not LazPackage.ReadOnly);
2800 
2801     // disable i18n for lfm (supports multi selection)
2802     SetCheckBox(DisableI18NForLFMCheckBox,
2803      OnlyFilesWithUnitsSelected and (SelHasLFMCount>0) and LazPackage.EnableI18N
2804      and LazPackage.EnableI18NForLFM,
2805      SelDisableI18NForLFM);
2806     DisableI18NForLFMCheckBox.Enabled:=(not LazPackage.ReadOnly);
2807 
2808     // registered plugins (supports multi selection)
2809     RegisteredPluginsGroupBox.Visible:=OnlyFilesWithUnitsSelected;
2810     RegisteredPluginsGroupBox.Enabled:=(not LazPackage.ReadOnly);
2811     if not RegisteredPluginsGroupBox.Visible then
2812       FPlugins.Clear;
2813     RegisteredListBox.Items.Assign(FPlugins);
2814 
2815     // directory summary (only single selection)
2816     FDirSummaryLabel.Visible:=(SelFileCount=0) and (SelDepCount=0) and (SelDirCount=1);
2817 
2818     if SelFileCount>0 then begin
2819       PropsGroupBox.Enabled:=true;
2820       PropsGroupBox.Caption:=lisPckEditFileProperties;
2821     end
2822     else if SingleSelectedDep<>nil then begin
2823       PropsGroupBox.Enabled:=not SingleSelectedRemoved;
2824       PropsGroupBox.Caption:=lisPckEditDependencyProperties;
2825       UseMinVersionCheckBox.Checked:=pdfMinVersion in SingleSelectedDep.Flags;
2826       MinVersionEdit.Text:=SingleSelectedDep.MinVersion.AsString;
2827       MinVersionEdit.Enabled:=pdfMinVersion in SingleSelectedDep.Flags;
2828       UseMaxVersionCheckBox.Checked:=pdfMaxVersion in SingleSelectedDep.Flags;
2829       MaxVersionEdit.Text:=SingleSelectedDep.MaxVersion.AsString;
2830       MaxVersionEdit.Enabled:=pdfMaxVersion in SingleSelectedDep.Flags;
2831       UpdateApplyDependencyButton;
2832     end
2833     else if SingleSelectedDirectory<>nil then begin
2834       PropsGroupBox.Enabled:=true;
2835       GetDirectorySummary(SingleSelectedDirectory,
2836         FileCount,HasRegisterProcCount,AddToUsesPkgSectionCount);
2837       FDirSummaryLabel.Caption:=Format(
2838         lisFilesHasRegisterProcedureInPackageUsesSection, [IntToStr(FileCount),
2839         IntToStr(HasRegisterProcCount), IntToStr(AddToUsesPkgSectionCount)]);
2840     end
2841     else begin
2842       PropsGroupBox.Enabled:=false;
2843     end;
2844   finally
2845     EnableAlign;
2846   end;
2847 end;
2848 
TPackageEditorForm.GetSingleSelectedDepnull2849 function TPackageEditorForm.GetSingleSelectedDep: TPkgDependency;
2850 var
2851   i: Integer;
2852   TVNode: TTreeNode;
2853   NodeData: TPENodeData;
2854   Item: TObject;
2855 begin
2856   Result:=nil;
2857   for i:=0 to ItemsTreeView.SelectionCount-1 do begin
2858     TVNode:=ItemsTreeView.Selections[i];
2859     if not GetNodeDataItem(TVNode,NodeData,Item) then continue;
2860     if Item is TPkgFile then begin
2861       Result:=nil;
2862       break;
2863     end else if Item is TPkgDependency then begin
2864       if Result<>nil then begin
2865         Result:=nil;
2866         break;
2867       end;
2868       Result:=TPkgDependency(Item);
2869     end;
2870   end;
2871 end;
2872 
2873 procedure TPackageEditorForm.UpdateApplyDependencyButton(Immediately: boolean);
2874 var
2875   CurDependency: TPkgDependency;
2876   DependencyChanged: Boolean;
2877   AVersion: TPkgVersion;
2878 begin
2879   if not CanUpdate(pefNeedUpdateApplyDependencyButton,Immediately) then exit;
2880   CurDependency:=GetSingleSelectedDependency;
2881   DependencyChanged:=false;
2882   if (CurDependency<>nil) then begin
2883     // check min version
2884     if UseMinVersionCheckBox.Checked<>(pdfMinVersion in CurDependency.Flags) then
2885       DependencyChanged:=true;
2886     if UseMinVersionCheckBox.Checked then begin
2887       AVersion:=TPkgVersion.Create;
2888       if AVersion.ReadString(MinVersionEdit.Text)
2889       and (AVersion.Compare(CurDependency.MinVersion)<>0) then
2890         DependencyChanged:=true;
2891       AVersion.Free;
2892     end;
2893     // check max version
2894     if UseMaxVersionCheckBox.Checked<>(pdfMaxVersion in CurDependency.Flags) then
2895       DependencyChanged:=true;
2896     if UseMaxVersionCheckBox.Checked then begin
2897       AVersion:=TPkgVersion.Create;
2898       if AVersion.ReadString(MaxVersionEdit.Text)
2899       and (AVersion.Compare(CurDependency.MaxVersion)<>0) then
2900         DependencyChanged:=true;
2901       AVersion.Free;
2902     end;
2903   end;
2904   ApplyDependencyButton.Enabled:=DependencyChanged;
2905 end;
2906 
2907 procedure TPackageEditorForm.UpdateStatusBar(Immediately: boolean);
2908 var
2909   StatusText: String;
2910 begin
2911   if not CanUpdate(pefNeedUpdateStatusBar,Immediately) then exit;
2912 
2913   if LazPackage.IsVirtual and (not LazPackage.ReadOnly) then begin
2914     StatusText:=Format(lisPckEditpackageNotSaved, [LazPackage.Name]);
2915   end else begin
2916     StatusText:=LazPackage.Filename;
2917   end;
2918   if LazPackage.ReadOnly then
2919     StatusText:=Format(lisPckEditReadOnly, [StatusText]);
2920   if LazPackage.Modified then
2921     StatusText:=Format(lisPckEditModified, [StatusText]);
2922   StatusBar.SimpleText:=StatusText;
2923 end;
2924 
TPackageEditorForm.GetNodeDatanull2925 function TPackageEditorForm.GetNodeData(TVNode: TTreeNode): TPENodeData;
2926 var
2927   o: TObject;
2928 begin
2929   Result:=nil;
2930   if (TVNode=nil) then exit;
2931   o:=TObject(TVNode.Data);
2932   if o is TFileNameItem then
2933     o:=TObject(TFileNameItem(o).Data);
2934   if o is TPENodeData then
2935     Result:=TPENodeData(o);
2936 end;
2937 
GetNodeItemnull2938 function TPackageEditorForm.GetNodeItem(NodeData: TPENodeData): TObject;
2939 begin
2940   Result:=nil;
2941   if (LazPackage=nil) or (NodeData=nil) then exit;
2942   case NodeData.Typ of
2943   penFile:
2944     if NodeData.Removed then
2945       Result:=LazPackage.FindRemovedPkgFile(NodeData.Name)
2946     else
2947       Result:=LazPackage.FindPkgFile(NodeData.Name,true,true);
2948   penDependency:
2949     if NodeData.Removed then
2950       Result:=LazPackage.FindRemovedDependencyByName(NodeData.Name)
2951     else
2952       Result:=LazPackage.FindDependencyByName(NodeData.Name);
2953   end;
2954 end;
2955 
GetNodeDataItemnull2956 function TPackageEditorForm.GetNodeDataItem(TVNode: TTreeNode; out
2957   NodeData: TPENodeData; out Item: TObject): boolean;
2958 begin
2959   Result:=false;
2960   Item:=nil;
2961   NodeData:=GetNodeData(TVNode);
2962   Item:=GetNodeItem(NodeData);
2963   Result:=Item<>nil;
2964 end;
2965 
TPackageEditorForm.IsDirectoryNodenull2966 function TPackageEditorForm.IsDirectoryNode(Node: TTreeNode): boolean;
2967 begin
2968   Result:=(Node<>nil) and (Node.Data=nil) and Node.HasAsParent(FFilesNode);
2969 end;
2970 
TPackageEditorForm.GetNodeFilenamenull2971 function TPackageEditorForm.GetNodeFilename(Node: TTreeNode): string;
2972 var
2973   Item: TFileNameItem;
2974 begin
2975   Result:='';
2976   if Node=nil then exit;
2977   if Node=FFilesNode then
2978     exit(FilesBaseDirectory);
2979   Item:=TFileNameItem(Node.Data);
2980   if (Item is TFileNameItem) then begin
2981     Result:=Item.Filename;
2982   end else if Node.HasAsParent(FFilesNode) then begin
2983     // directory node
2984     Result:=Node.Text;
2985   end else
2986     exit;
2987   if not FilenameIsAbsolute(Result) then
2988     Result:=AppendPathDelim(FilesBaseDirectory)+Result;
2989 end;
2990 
2991 procedure TPackageEditorForm.GetDirectorySummary(DirNode: TTreeNode; out
2992   FileCount, HasRegisterProcCount, AddToUsesPkgSectionCount: integer);
2993 
2994   procedure Traverse(Node: TTreeNode);
2995   var
2996     CurFile: TPkgFile;
2997     NodeData: TPENodeData;
2998   begin
2999     NodeData:=GetNodeData(Node);
3000     if NodeData<>nil then begin
3001       if NodeData.Typ=penFile then begin
3002         CurFile:=LazPackage.FindPkgFile(NodeData.Name,true,true);
3003         if CurFile<>nil then begin
3004           inc(FileCount);
3005           if CurFile.HasRegisterProc then inc(HasRegisterProcCount);
3006           if CurFile.AddToUsesPkgSection then inc(AddToUsesPkgSectionCount);
3007         end;
3008       end;
3009     end;
3010     Node:=Node.GetFirstChild;
3011     while Node<>nil do begin
3012       Traverse(Node);
3013       Node:=Node.GetNextSibling;
3014     end;
3015   end;
3016 
3017 begin
3018   FileCount:=0;
3019   HasRegisterProcCount:=0;
3020   AddToUsesPkgSectionCount:=0;
3021   Traverse(DirNode);
3022 end;
3023 
3024 procedure TPackageEditorForm.ExtendUnitIncPathForNewUnit(const AnUnitFilename,
3025   AnIncludeFile: string;
3026   var IgnoreUnitPaths: TFilenameToStringTree);
3027 var
3028   NewDirectory: String;
3029   UnitPath: String;
3030   ShortDirectory: String;
3031   NewIncDirectory: String;
3032   ShortIncDirectory: String;
3033   IncPath: String;
3034   UnitPathPos: Integer;
3035   IncPathPos: Integer;
3036 begin
3037   if LazPackage=nil then exit;
3038   // check if directory is already in the unit path of the package
3039   NewDirectory:=ExtractFilePath(AnUnitFilename);
3040   ShortDirectory:=NewDirectory;
3041   LazPackage.ShortenFilename(ShortDirectory,true);
3042   if ShortDirectory='' then exit;
3043   ShortIncDirectory:='';
3044   LazPackage.LongenFilename(NewDirectory);
3045   NewDirectory:=ChompPathDelim(NewDirectory);
3046 
3047   UnitPath:=LazPackage.GetUnitPath(false);
3048   UnitPathPos:=SearchDirectoryInSearchPath(UnitPath,NewDirectory,1);
3049   IncPathPos:=1;
3050   if AnIncludeFile<>'' then begin
3051     NewIncDirectory:=ChompPathDelim(ExtractFilePath(AnIncludeFile));
3052     ShortIncDirectory:=NewIncDirectory;
3053     LazPackage.ShortenFilename(ShortIncDirectory,false);
3054     if ShortIncDirectory<>'' then begin
3055       LazPackage.LongenFilename(NewIncDirectory);
3056       NewIncDirectory:=ChompPathDelim(NewIncDirectory);
3057       IncPath:=LazPackage.GetIncludePath(false);
3058       IncPathPos:=SearchDirectoryInSearchPath(IncPath,NewIncDirectory,1);
3059     end;
3060   end;
3061   if UnitPathPos<1 then begin
3062     // ask user to add the unit path
3063     if (IgnoreUnitPaths<>nil) and (IgnoreUnitPaths.Contains(ShortDirectory))
3064     then exit;
3065     if MessageDlg(lisPkgEditNewUnitNotInUnitpath,
3066         Format(lisPkgEditTheFileIsCurrentlyNotInTheUnitpathOfThePackage,
3067                [AnUnitFilename, LineEnding, LineEnding+LineEnding, ShortDirectory]),
3068         mtConfirmation,[mbYes,mbNo],0)<>mrYes
3069     then begin
3070       if IgnoreUnitPaths=nil then
3071         IgnoreUnitPaths:=TFilenameToStringTree.Create(false);
3072       IgnoreUnitPaths.Add(ShortDirectory,'');
3073       exit;
3074     end;
3075     // add path
3076     LazPackage.CompilerOptions.MergeToUnitPaths(ShortDirectory);
3077   end;
3078   if IncPathPos<1 then
3079     // the unit is in unitpath, but the include file not in the incpath
3080     // -> auto extend the include path
3081     LazPackage.CompilerOptions.MergeToIncludePaths(ShortIncDirectory);
3082 end;
3083 
3084 procedure TPackageEditorForm.ExtendIncPathForNewIncludeFile(
3085   const AnIncludeFile: string; var IgnoreIncPaths: TFilenameToStringTree);
3086 var
3087   NewDirectory: String;
3088   ShortDirectory: String;
3089   IncPath: String;
3090   IncPathPos: LongInt;
3091 begin
3092   if LazPackage=nil then exit;
3093   // check if directory is already in the unit path of the package
3094   NewDirectory:=ExtractFilePath(AnIncludeFile);
3095   ShortDirectory:=NewDirectory;
3096   LazPackage.ShortenFilename(ShortDirectory,false);
3097   if ShortDirectory='' then exit;
3098   LazPackage.LongenFilename(NewDirectory);
3099   NewDirectory:=ChompPathDelim(NewDirectory);
3100   IncPath:=LazPackage.GetIncludePath(false);
3101   IncPathPos:=SearchDirectoryInSearchPath(IncPath,NewDirectory,1);
3102   if IncPathPos>0 then exit;
3103   // ask user to add the unit path
3104   if (IgnoreIncPaths<>nil) and (IgnoreIncPaths.Contains(ShortDirectory))
3105   then exit;
3106   if MessageDlg(lisPENewFileNotInIncludePath,
3107      Format(lisPETheFileIsCurrentlyNotInTheIncludePathOfThePackageA,
3108             [AnIncludeFile, LineEnding, ShortDirectory]),
3109       mtConfirmation,[mbYes,mbNo],0)<>mrYes
3110   then begin
3111     if IgnoreIncPaths=nil then
3112       IgnoreIncPaths:=TFilenameToStringTree.Create(false);
3113     IgnoreIncPaths.Add(ShortDirectory,'');
3114     exit;
3115   end;
3116   // add path
3117   LazPackage.CompilerOptions.MergeToIncludePaths(ShortDirectory);
3118 end;
3119 
TPackageEditorForm.ExtendUnitSearchPathnull3120 function TPackageEditorForm.ExtendUnitSearchPath(NewUnitPaths: string): boolean;
3121 begin
3122   Result:=LazPackage.ExtendUnitSearchPath(NewUnitPaths);
3123 end;
3124 
TPackageEditorForm.ExtendIncSearchPathnull3125 function TPackageEditorForm.ExtendIncSearchPath(NewIncPaths: string): boolean;
3126 begin
3127   Result:=LazPackage.ExtendIncSearchPath(NewIncPaths);
3128 end;
3129 
FilesEditTreeViewnull3130 function TPackageEditorForm.FilesEditTreeView: TTreeView;
3131 begin
3132   Result:=ItemsTreeView;
3133 end;
3134 
FilesEditFormnull3135 function TPackageEditorForm.FilesEditForm: TCustomForm;
3136 begin
3137   Result:=Self;
3138 end;
3139 
FilesOwnernull3140 function TPackageEditorForm.FilesOwner: TObject;
3141 begin
3142   Result:=LazPackage;
3143 end;
3144 
TPackageEditorForm.FilesOwnerNamenull3145 function TPackageEditorForm.FilesOwnerName: string;
3146 begin
3147   Result:=Format(lisPackage2, [LazPackage.Name]);
3148 end;
3149 
TVNodeFilesnull3150 function TPackageEditorForm.TVNodeFiles: TTreeNode;
3151 begin
3152   Result:=FFilesNode;
3153 end;
3154 
TVNodeRequiredPackagesnull3155 function TPackageEditorForm.TVNodeRequiredPackages: TTreeNode;
3156 begin
3157   Result:=FRequiredPackagesNode;
3158 end;
3159 
FilesBaseDirectorynull3160 function TPackageEditorForm.FilesBaseDirectory: string;
3161 begin
3162   Result:=LazPackage.DirectoryExpanded;
3163 end;
3164 
TPackageEditorForm.FilesOwnerReadOnlynull3165 function TPackageEditorForm.FilesOwnerReadOnly: boolean;
3166 begin
3167   Result:=LazPackage.ReadOnly;
3168 end;
3169 
TPackageEditorForm.FirstRequiredDependencynull3170 function TPackageEditorForm.FirstRequiredDependency: TPkgDependency;
3171 begin
3172   Result:=LazPackage.FirstRequiredDependency;
3173 end;
3174 
TPackageEditorForm.CanBeAddedToProjectnull3175 function TPackageEditorForm.CanBeAddedToProject: boolean;
3176 begin
3177   if LazPackage=nil then exit(false);
3178   Result:=PackageEditors.AddToProject(LazPackage,true)=mrOk;
3179 end;
3180 
3181 procedure TPackageEditorForm.DoSave(SaveAs: boolean);
3182 begin
3183   PackageEditors.SavePackage(LazPackage,SaveAs);
3184   UpdateTitle;
3185   UpdateButtons;
3186   UpdateStatusBar;
3187 end;
3188 
3189 procedure TPackageEditorForm.DoCompile(CompileClean, CompileRequired,
3190   WarnIDEPkg: boolean);
3191 var
3192   MsgResult: Integer;
3193 begin
3194   if WarnIDEPkg and not FCompileDesignTimePkg
3195       and (LazPackage.PackageType=lptDesignTime) then
3196   begin
3197     MsgResult:=IDEQuestionDialog(dlgMsgWinColorUrgentWarning,
3198         Format(lisPackageIsDesigntimeOnlySoItShouldOnlyBeCompiledInt, [
3199           LazPackage.Name, #13]),
3200         mtWarning, [mrYes, lisCompileWithProjectSettings,
3201         mrYesToAll, lisCompileAndDoNotAskAgain, mrCancel]);
3202     case MsgResult of
3203     mrYes: ;
3204     mrYesToAll:
3205       FCompileDesignTimePkg:=true; // store setting only while running the IDE
3206                                    // when IDE restarts, ask again
3207     else exit;
3208     end;
3209   end;
3210   CompileBitBtn.Enabled:=False;
3211   FCompiling:=True;
3212   PackageEditors.CompilePackage(LazPackage,CompileClean,CompileRequired);
3213   FCompiling:=False;
3214   UpdateTitle;
3215   UpdateButtons;
3216   UpdateStatusBar;
3217 end;
3218 
3219 procedure TPackageEditorForm.DoFindInFiles;
3220 begin
3221   PackageEditors.FindInFiles(LazPackage);
3222 end;
3223 
3224 procedure TPackageEditorForm.DoRevert;
3225 begin
3226   if MessageDlg(lisPkgEditRevertPackage,
3227     Format(lisPkgEditDoYouReallyWantToForgetAllChangesToPackageAnd, [LazPackage.IDAsString]),
3228     mtConfirmation,[mbYes,mbNo],0)<>mrYes
3229   then exit;
3230   PackageEditors.RevertPackage(LazPackage);
3231   UpdateAll(false);
3232 end;
3233 
3234 procedure TPackageEditorForm.DoPublishPackage;
3235 begin
3236   PackageEditors.PublishPackage(LazPackage);
3237 end;
3238 
3239 procedure TPackageEditorForm.DoEditVirtualUnit;
3240 var
3241   PkgFile: TPkgFile;
3242 begin
3243   if LazPackage=nil then exit;
3244   PkgFile:=GetSingleSelectedFile;
3245   if (PkgFile=nil)
3246   or (PkgFile.FileType<>pftVirtualUnit)
3247   or (LazPackage.IndexOfPkgFile(PkgFile)<0)
3248   then exit;
3249   if ShowEditVirtualPackageDialog(PkgFile)=mrOk then
3250     UpdateFiles;
3251 end;
3252 
3253 procedure TPackageEditorForm.DoExpandCollapseDirectory(ExpandIt: Boolean);
3254 var
3255   CurNode: TTreeNode;
3256 begin
3257   CurNode:=ItemsTreeView.Selected;
3258   if not (IsDirectoryNode(CurNode) or (CurNode=FFilesNode)) then exit;
3259   ItemsTreeView.BeginUpdate;
3260   if ExpandIt then
3261     CurNode.Expand(true)
3262   else
3263     CurNode.Collapse(true);
3264   ItemsTreeView.EndUpdate;
3265 end;
3266 
3267 procedure TPackageEditorForm.DoUseUnitsInDirectory(Use: boolean);
3268 
3269   procedure Traverse(Node: TTreeNode);
3270   var
3271     PkgFile: TPkgFile;
3272     NodeData: TPENodeData;
3273   begin
3274     NodeData:=GetNodeData(Node);
3275     if (NodeData<>nil) and (NodeData.Typ=penFile) then
3276     begin
3277       PkgFile:=LazPackage.FindPkgFile(NodeData.Name,true,true);
3278       if (PkgFile<>nil) and (PkgFile.FileType in [pftUnit,pftVirtualUnit]) then
3279       begin
3280         if PkgFile.AddToUsesPkgSection<>Use then
3281         begin
3282           PkgFile.AddToUsesPkgSection:=Use;
3283           LazPackage.Modified:=true;
3284         end;
3285       end;
3286     end;
3287     Node:=Node.GetFirstChild;
3288     while Node<>nil do
3289     begin
3290       Traverse(Node);
3291       Node:=Node.GetNextSibling;
3292     end;
3293   end;
3294 
3295 var
3296   CurNode: TTreeNode;
3297 begin
3298   if not ShowDirectoryHierarchy then exit;
3299   CurNode:=ItemsTreeView.Selected;
3300   if not (IsDirectoryNode(CurNode) or (CurNode=FFilesNode)) then exit;
3301   Traverse(CurNode);
3302   UpdatePEProperties;
3303 end;
3304 
3305 procedure TPackageEditorForm.DoMoveCurrentFile(Offset: integer);
3306 var
3307   PkgFile: TPkgFile;
3308   OldIndex, NewIndex: Integer;
3309   FilesBranch: TTreeFilterBranch;
3310 begin
3311   PkgFile:=GetSingleSelectedFile;
3312   if (LazPackage=nil) or (PkgFile=nil) then exit;
3313   OldIndex:=LazPackage.IndexOfPkgFile(PkgFile);
3314   if OldIndex<0 then exit;
3315   NewIndex:=OldIndex+Offset;
3316   if (NewIndex<0) or (NewIndex>=LazPackage.FileCount) then exit;
3317   FilesBranch:=FilterEdit.GetExistingBranch(FFilesNode);
3318   LazPackage.MoveFile(OldIndex,NewIndex);
3319   FilesBranch.Move(OldIndex,NewIndex);
3320   UpdatePEProperties;
3321   UpdateStatusBar;
3322   FilterEdit.InvalidateFilter;
3323 end;
3324 
3325 procedure TPackageEditorForm.DoMoveDependency(Offset: integer);
3326 var
3327   CurDependency: TPkgDependency;
3328   OldIndex, NewIndex: Integer;
3329   RequiredBranch: TTreeFilterBranch;
3330   Moved: Boolean;
3331 begin
3332   CurDependency:=GetSingleSelectedDependency;
3333   if (LazPackage=nil) or (CurDependency=nil) then exit;
3334   if Offset<0 then
3335     Moved := LazPackage.MoveRequiredDependencyUp(CurDependency)
3336   else
3337     Moved := LazPackage.MoveRequiredDependencyDown(CurDependency);
3338   if not Moved then exit;
3339   LazPackage.ModifySilently;
3340   RequiredBranch:=FilterEdit.GetExistingBranch(FRequiredPackagesNode);
3341   OldIndex:=RequiredBranch.Items.IndexOf(DependencyAsString(CurDependency));
3342   NewIndex:=OldIndex+Offset;
3343   RequiredBranch.Move(OldIndex,NewIndex);
3344   UpdatePEProperties;
3345   UpdateStatusBar;
3346   FilterEdit.InvalidateFilter;
3347 end;
3348 
3349 procedure TPackageEditorForm.DoSortFiles;
3350 var
3351   TreeSelection: TStringList;
3352 begin
3353   TreeSelection:=ItemsTreeView.StoreCurrentSelection;
3354   LazPackage.SortFiles;
3355   ItemsTreeView.ApplyStoredSelection(TreeSelection);
3356 end;
3357 
DoOpenPkgFilenull3358 function TPackageEditorForm.DoOpenPkgFile(PkgFile: TPkgFile): TModalResult;
3359 begin
3360   Result:=PackageEditors.OpenPkgFile(Self,PkgFile);
3361 end;
3362 
3363 procedure TPackageEditorForm.DoFixFilesCase;
3364 begin
3365   LazPackage.FixFilesCaseSensitivity;
3366 end;
3367 
3368 procedure TPackageEditorForm.DoShowMissingFiles;
3369 begin
3370   ShowMissingPkgFilesDialog(LazPackage);
3371 end;
3372 
3373 constructor TPackageEditorForm.Create(TheOwner: TComponent);
3374 begin
3375   inherited Create(TheOwner);
3376 end;
3377 
3378 destructor TPackageEditorForm.Destroy;
3379 begin
3380   inherited Destroy;
3381 end;
3382 
3383 { TPackageEditors }
3384 
TPackageEditors.GetEditorsnull3385 function TPackageEditors.GetEditors(Index: integer): TPackageEditorForm;
3386 begin
3387   Result:=TPackageEditorForm(FItems[Index]);
3388 end;
3389 
TPackageEditors.IndexOfPackagenull3390 function TPackageEditors.IndexOfPackage(const PkgName: string): integer;
3391 var
3392   I: Integer;
3393 begin
3394   for I := 0 to Count-1 do
3395     if Assigned(Editors[I].LazPackage) and
3396       SameText(ExtractFileNameOnly(Editors[I].LazPackage.Filename), PkgName)
3397     then
3398       Exit(I);
3399 
3400   Result := -1;
3401 end;
3402 
3403 constructor TPackageEditors.Create;
3404 begin
3405   FItems:=TFPList.Create;
3406 end;
3407 
3408 destructor TPackageEditors.Destroy;
3409 begin
3410   Clear;
3411   FreeAndNil(FItems);
3412   inherited Destroy;
3413 end;
3414 
TPackageEditors.Countnull3415 function TPackageEditors.Count: integer;
3416 begin
3417   Result:=FItems.Count;
3418 end;
3419 
3420 procedure TPackageEditors.Clear;
3421 begin
3422   FItems.Clear;
3423 end;
3424 
3425 procedure TPackageEditors.Remove(Editor: TPackageEditorForm);
3426 begin
3427   if FItems<>nil then
3428     FItems.Remove(Editor);
3429 end;
3430 
TPackageEditors.IndexOfPackagenull3431 function TPackageEditors.IndexOfPackage(Pkg: TLazPackage): integer;
3432 begin
3433   Result:=Count-1;
3434   while (Result>=0) and (Editors[Result].LazPackage<>Pkg) do dec(Result);
3435 end;
3436 
FindEditornull3437 function TPackageEditors.FindEditor(Pkg: TLazPackage): TPackageEditorForm;
3438 var
3439   i: Integer;
3440 begin
3441   i:=IndexOfPackage(Pkg);
3442   if i>=0 then
3443     Result:=Editors[i]
3444   else
3445     Result:=nil;
3446 end;
3447 
TPackageEditors.CreateEditornull3448 function TPackageEditors.CreateEditor(Pkg: TLazPackage;
3449   DoDisableAutoSizing: boolean): TPackageEditorForm;
3450 begin
3451   Result:=FindEditor(Pkg);
3452   if Result<>nil then begin
3453     if DoDisableAutoSizing then
3454       Result.DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TAnchorDockMaster Delayed'){$ENDIF};
3455   end else begin
3456     Result:=TPackageEditorForm(TPackageEditorForm.NewInstance);
3457     {$IFDEF DebugDisableAutoSizing}
3458     if DoDisableAutoSizing then
3459       Result.DisableAutoSizing('TAnchorDockMaster Delayed')
3460     else
3461       Result.DisableAutoSizing('TPackageEditors.OpenEditor');
3462     {$ELSE}
3463     Result.DisableAutoSizing;
3464     {$ENDIF}
3465     Result.Create(LazarusIDE.OwningComponent);
3466     Result.LazPackage:=Pkg;
3467     FItems.Add(Result);
3468     if not DoDisableAutoSizing then
3469       Result.EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TPackageEditors.OpenEditor'){$ENDIF};
3470   end;
3471 end;
3472 
TPackageEditors.OpenEditornull3473 function TPackageEditors.OpenEditor(Pkg: TLazPackage; BringToFront: boolean
3474   ): TPackageEditorForm;
3475 begin
3476   Result:=CreateEditor(Pkg,true);
3477   try
3478     IDEWindowCreators.ShowForm(Result, BringToFront);
3479   finally
3480     Result.EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TAnchorDockMaster Delayed'){$ENDIF};
3481   end;
3482 end;
3483 
TPackageEditors.OpenFilenull3484 function TPackageEditors.OpenFile(Sender: TObject; const Filename: string): TModalResult;
3485 begin
3486   if Assigned(OnOpenFile) then
3487     Result:=OnOpenFile(Sender,Filename)
3488   else
3489     Result:=mrCancel;
3490 end;
3491 
OpenPkgFilenull3492 function TPackageEditors.OpenPkgFile(Sender: TObject; PkgFile: TPkgFile): TModalResult;
3493 begin
3494   if Assigned(OnOpenPkgFile) then
3495     Result:=OnOpenPkgFile(Sender,PkgFile)
3496   else
3497     Result:=mrCancel;
3498 end;
3499 
TPackageEditors.OpenDependencynull3500 function TPackageEditors.OpenDependency(Sender: TObject;
3501   Dependency: TPkgDependency): TModalResult;
3502 var
3503   APackage: TLazPackage;
3504 begin
3505   Result:=mrCancel;
3506   if PackageGraph.OpenDependency(Dependency,false)=lprSuccess then
3507   begin
3508     if Dependency.DependencyType=pdtLazarus then
3509     begin
3510       APackage:=Dependency.RequiredPackage;
3511       if Assigned(OnOpenPackage) then Result:=OnOpenPackage(Sender,APackage);
3512     end
3513     else
3514       ShowMessage('It is not possible to open FPMake packages.');
3515   end;
3516 end;
3517 
3518 procedure TPackageEditors.DoFreeEditor(Pkg: TLazPackage);
3519 begin
3520   if FItems<>nil then
3521     FItems.Remove(Pkg.Editor);
3522   if Assigned(OnFreeEditor) then OnFreeEditor(Pkg);
3523 end;
3524 
FindEditornull3525 function TPackageEditors.FindEditor(const PkgName: string): TPackageEditorForm;
3526 var
3527   i: Integer;
3528 begin
3529   i:=IndexOfPackage(PkgName);
3530   if i>=0 then
3531     Result:=Editors[i]
3532   else
3533     Result:=nil;
3534 end;
3535 
CreateNewFilenull3536 function TPackageEditors.CreateNewFile(Sender: TObject;
3537   Params: TAddToPkgResult): TModalResult;
3538 begin
3539   Result:=mrCancel;
3540   if Assigned(OnCreateNewFile) then
3541     Result:=OnCreateNewFile(Sender,Params)
3542   else
3543     Result:=mrCancel;
3544 end;
3545 
SavePackagenull3546 function TPackageEditors.SavePackage(APackage: TLazPackage;
3547   SaveAs: boolean): TModalResult;
3548 begin
3549   if Assigned(OnSavePackage) then
3550     Result:=OnSavePackage(Self,APackage,SaveAs)
3551   else
3552     Result:=mrCancel;
3553 end;
3554 
TPackageEditors.CompilePackagenull3555 function TPackageEditors.CompilePackage(APackage: TLazPackage;
3556   CompileClean, CompileRequired: boolean): TModalResult;
3557 begin
3558   if Assigned(OnCompilePackage) then
3559     Result:=OnCompilePackage(Self,APackage,CompileClean,CompileRequired)
3560   else
3561     Result:=mrCancel;
3562 end;
3563 
3564 procedure TPackageEditors.UpdateAllEditors(Immediately: boolean);
3565 var
3566   i: Integer;
3567 begin
3568   for i:=0 to Count-1 do
3569     Editors[i].UpdateAll(Immediately);
3570 end;
3571 
ShouldNotBeInstallednull3572 function TPackageEditors.ShouldNotBeInstalled(APackage: TLazPackage): boolean;
3573 var
3574   Dep: TPkgDependency;
3575   CurPkg: TLazPackage;
3576 begin
3577   if APackage.Missing then
3578     exit(true)
3579   else if (APackage.FindUnitWithRegister<>nil) or (APackage.Provides.Count>0) then
3580     exit(false);
3581   Dep:=APackage.FirstRequiredDependency;
3582   while Dep<>nil do begin
3583     CurPkg:=Dep.RequiredPackage;
3584     if (CurPkg<>nil) then begin
3585       if (CurPkg.FindUnitWithRegister<>nil) or (CurPkg.Provides.Count>0) then
3586         exit(false);
3587     end;
3588     Dep:=Dep.NextRequiresDependency;
3589   end;
3590   Result:=true;
3591 end;
3592 
TPackageEditors.InstallPackagenull3593 function TPackageEditors.InstallPackage(APackage: TLazPackage): TModalResult;
3594 begin
3595   if ShouldNotBeInstalled(APackage) then begin
3596     if IDEQuestionDialog(lisNotAnInstallPackage,
3597       Format(lisThePackageDoesNotHaveAnyRegisterProcedureWhichTypi,
3598              [APackage.Name, LineEnding+LineEnding]),
3599       mtWarning, [mrIgnore, lisInstallItILikeTheFat,
3600                   mrCancel, lisCancel], '') <> mrIgnore
3601     then exit(mrCancel);
3602   end;
3603   if Assigned(OnInstallPackage) then
3604     Result:=OnInstallPackage(Self,APackage)
3605   else
3606     Result:=mrCancel;
3607 end;
3608 
UninstallPackagenull3609 function TPackageEditors.UninstallPackage(APackage: TLazPackage): TModalResult;
3610 begin
3611   if Assigned(OnUninstallPackage) then
3612     Result:=OnUninstallPackage(Self,APackage)
3613   else
3614     Result:=mrCancel;
3615 end;
3616 
ViewPkgSourcenull3617 function TPackageEditors.ViewPkgSource(APackage: TLazPackage): TModalResult;
3618 begin
3619   if Assigned(OnViewPackageSource) then
3620     Result:=OnViewPackageSource(Self,APackage)
3621   else
3622     Result:=mrCancel;
3623 end;
3624 
ViewPkgToDosnull3625 function TPackageEditors.ViewPkgToDos(APackage: TLazPackage): TModalResult;
3626 begin
3627   if Assigned(OnViewPackageToDos) then
3628     Result:=OnViewPackageToDos(Self,APackage)
3629   else
3630     Result:=mrCancel;
3631 end;
3632 
TPackageEditors.FindInFilesnull3633 function TPackageEditors.FindInFiles(APackage: TLazPackage): TModalResult;
3634 begin
3635   if Assigned(OnShowFindInFiles) then
3636     Result:=OnShowFindInFiles(Self,APackage)
3637   else
3638     Result:=mrCancel;
3639 end;
3640 
TPackageEditors.DeleteAmbiguousFilesnull3641 function TPackageEditors.DeleteAmbiguousFiles(APackage: TLazPackage;
3642   const Filename: string): TModalResult;
3643 begin
3644   if Assigned(OnDeleteAmbiguousFiles) then
3645     Result:=OnDeleteAmbiguousFiles(Self,APackage,Filename)
3646   else
3647     Result:=mrOk;
3648 end;
3649 
TPackageEditors.AddToProjectnull3650 function TPackageEditors.AddToProject(APackage: TLazPackage;
3651   OnlyTestIfPossible: boolean): TModalResult;
3652 begin
3653   if Assigned(OnAddToProject) then
3654     Result:=OnAddToProject(Self,APackage,OnlyTestIfPossible)
3655   else
3656     Result:=mrCancel;
3657 end;
3658 
CreateMakefilenull3659 function TPackageEditors.CreateMakefile(APackage: TLazPackage): TModalResult;
3660 begin
3661   if Assigned(OnCreateMakeFile) then
3662     Result:=OnCreateMakeFile(Self,APackage)
3663   else
3664     Result:=mrCancel;
3665 end;
3666 
TPackageEditors.CreateFpmakeFilenull3667 function TPackageEditors.CreateFpmakeFile(APackage: TLazPackage): TModalResult;
3668 begin
3669   if Assigned(OnCreateFpmakefile) then
3670     Result:=OnCreateFpmakefile(Self,APackage)
3671   else
3672     Result:=mrCancel;
3673 end;
3674 
TreeViewToPkgEditornull3675 function TPackageEditors.TreeViewToPkgEditor(TV: TTreeView): TPackageEditorForm;
3676 var
3677   aParent: TWinControl;
3678 begin
3679   Result:=nil;
3680   if TV.Name<>'ItemsTreeView' then exit;
3681   aParent:=TV;
3682   repeat
3683     if aParent=nil then exit;
3684     aParent:=aParent.Parent;
3685   until aParent is TPackageEditorForm;
3686   Result:=TPackageEditorForm(aParent);
3687 end;
3688 
RevertPackagenull3689 function TPackageEditors.RevertPackage(APackage: TLazPackage): TModalResult;
3690 begin
3691   if Assigned(OnRevertPackage) then
3692     Result:=OnRevertPackage(Self,APackage)
3693   else
3694     Result:=mrCancel;
3695 end;
3696 
PublishPackagenull3697 function TPackageEditors.PublishPackage(APackage: TLazPackage): TModalResult;
3698 begin
3699   if Assigned(OnPublishPackage) then
3700     Result:=OnPublishPackage(Self,APackage)
3701   else
3702     Result:=mrCancel;
3703 end;
3704 
3705 initialization
3706   PackageEditors:=nil;
3707   IDEWindowsGlobalOptions.Add(PackageEditorWindowPrefix, False);
3708 
3709 end.
3710 
3711