mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-27 17:53:57 +02:00
900 lines
29 KiB
ObjectPascal
900 lines
29 KiB
ObjectPascal
{ $Id$ }
|
|
{
|
|
/***************************************************************************
|
|
installpkgsetdlg.pas
|
|
--------------------
|
|
|
|
|
|
***************************************************************************/
|
|
|
|
***************************************************************************
|
|
* *
|
|
* This source is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This code is distributed in the hope that it will be useful, but *
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
* General Public License for more details. *
|
|
* *
|
|
* A copy of the GNU General Public License is available on the World *
|
|
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
|
|
* obtain it by writing to the Free Software Foundation, *
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
* *
|
|
***************************************************************************
|
|
|
|
Author: Mattias Gaertner
|
|
|
|
Abstract:
|
|
Dialog to edit the package set installed in the IDE.
|
|
}
|
|
unit InstallPkgSetDlg;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, contnrs, LCLProc, Forms, Controls, Graphics, Dialogs,
|
|
KeywordFuncLists, StdCtrls, Buttons, FileUtil, ExtCtrls, ComCtrls, EditBtn,
|
|
LCLType, AVL_Tree, Laz2_XMLCfg, TreeFilterEdit, PackageIntf, IDEImagesIntf,
|
|
IDEHelpIntf, IDEDialogs, LazarusIDEStrConsts, EnvironmentOpts, InputHistory,
|
|
LazConf, IDEProcs, PackageDefs, PackageSystem, PackageLinks,
|
|
IDEContextHelpEdit;
|
|
|
|
type
|
|
TOnCheckInstallPackageList =
|
|
procedure(PkgIDs: TObjectList; RemoveConflicts: boolean; out Ok: boolean) of object;
|
|
|
|
{ TInstallPkgSetDialog }
|
|
|
|
TInstallPkgSetDialog = class(TForm)
|
|
AddToInstallButton: TBitBtn;
|
|
AvailableTreeView: TTreeView;
|
|
AvailablePkgGroupBox: TGroupBox;
|
|
HelpButton: TBitBtn;
|
|
CancelButton: TBitBtn;
|
|
ExportButton: TButton;
|
|
BtnPanel: TPanel;
|
|
InstallTreeView: TTreeView;
|
|
lblMiddle: TLabel;
|
|
AvailableFilterEdit: TTreeFilterEdit;
|
|
NoteLabel: TLabel;
|
|
PkgInfoMemo: TMemo;
|
|
PkgInfoGroupBox: TGroupBox;
|
|
ImportButton: TButton;
|
|
SaveAndExitButton: TBitBtn;
|
|
InstallPkgGroupBox: TGroupBox;
|
|
SaveAndRebuildButton: TBitBtn;
|
|
UninstallButton: TBitBtn;
|
|
procedure AddToInstallButtonClick(Sender: TObject);
|
|
procedure AvailableTreeViewDblClick(Sender: TObject);
|
|
procedure AvailableTreeViewKeyPress(Sender: TObject; var Key: char);
|
|
procedure AvailableTreeViewSelectionChanged(Sender: TObject);
|
|
procedure ExportButtonClick(Sender: TObject);
|
|
procedure HelpButtonClick(Sender: TObject);
|
|
procedure ImportButtonClick(Sender: TObject);
|
|
procedure InstallButtonClick(Sender: TObject);
|
|
procedure InstallTreeViewDblClick(Sender: TObject);
|
|
procedure InstallPkgSetDialogCreate(Sender: TObject);
|
|
procedure InstallPkgSetDialogDestroy(Sender: TObject);
|
|
procedure InstallPkgSetDialogResize(Sender: TObject);
|
|
procedure InstallTreeViewSelectionChanged(Sender: TObject);
|
|
procedure SaveAndExitButtonClick(Sender: TObject);
|
|
procedure UninstallButtonClick(Sender: TObject);
|
|
private
|
|
FNewInstalledPackages: TObjectList; // list of TLazPackageID (not TLazPackage)
|
|
FOldInstalledPackages: TPkgDependency;
|
|
FOnCheckInstallPackageList: TOnCheckInstallPackageList;
|
|
fAvailablePackages: TAVLTree;// tree of TLazPackageID (all available packages and links)
|
|
FRebuildIDE: boolean;
|
|
FSelectedPkg: TLazPackage;
|
|
ImgIndexPackage: integer;
|
|
ImgIndexInstallPackage: integer;
|
|
ImgIndexInstalledPackage: integer;
|
|
ImgIndexUninstallPackage: integer;
|
|
ImgIndexCirclePackage: integer;
|
|
ImgIndexMissingPackage: integer;
|
|
procedure SetOldInstalledPackages(const AValue: TPkgDependency);
|
|
procedure AssignOldInstalledPackagesToList;
|
|
function PackageInInstallList(PkgName: string): boolean;
|
|
function GetPkgImgIndex(APackage: TLazPackage; InInstallList: boolean): integer;
|
|
function GetAvailablePkgImageIndex(Str: String; Data: TObject; var AIsEnabled: Boolean): Integer;
|
|
procedure UpdateAvailablePackages(Immediately: boolean = false);
|
|
procedure UpdateNewInstalledPackages;
|
|
procedure OnIteratePackages(APackageID: TLazPackageID);
|
|
function DependencyToStr(Dependency: TPkgDependency): string;
|
|
procedure ClearNewInstalledPackages;
|
|
function CheckSelection: boolean;
|
|
procedure UpdateButtonStates;
|
|
procedure UpdatePackageInfo(Tree: TTreeView);
|
|
function NewInstalledPackagesContains(APackageID: TLazPackageID): boolean;
|
|
function IndexOfNewInstalledPackageID(APackageID: TLazPackageID): integer;
|
|
function IndexOfNewInstalledPkgByName(const APackageName: string): integer;
|
|
procedure SavePackageListToFile(const AFilename: string);
|
|
procedure LoadPackageListFromFile(const AFilename: string);
|
|
function ExtractNameFromPkgID(ID: string): string;
|
|
procedure AddToInstall;
|
|
procedure AddToUninstall;
|
|
public
|
|
function GetNewInstalledPackages: TObjectList;
|
|
property OldInstalledPackages: TPkgDependency read FOldInstalledPackages
|
|
write SetOldInstalledPackages;
|
|
property NewInstalledPackages: TObjectList read FNewInstalledPackages;
|
|
property RebuildIDE: boolean read FRebuildIDE write FRebuildIDE;
|
|
property OnCheckInstallPackageList: TOnCheckInstallPackageList
|
|
read FOnCheckInstallPackageList write FOnCheckInstallPackageList;
|
|
end;
|
|
|
|
function ShowEditInstallPkgsDialog(OldInstalledPackages: TPkgDependency;
|
|
CheckInstallPackageList: TOnCheckInstallPackageList;
|
|
var NewInstalledPackages: TObjectList; // list of TLazPackageID (must be freed)
|
|
var RebuildIDE: boolean): TModalResult;
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
function ShowEditInstallPkgsDialog(OldInstalledPackages: TPkgDependency;
|
|
CheckInstallPackageList: TOnCheckInstallPackageList;
|
|
var NewInstalledPackages: TObjectList; // list of TLazPackageID
|
|
var RebuildIDE: boolean): TModalResult;
|
|
var
|
|
InstallPkgSetDialog: TInstallPkgSetDialog;
|
|
begin
|
|
NewInstalledPackages:=nil;
|
|
InstallPkgSetDialog:=TInstallPkgSetDialog.Create(nil);
|
|
try
|
|
InstallPkgSetDialog.OldInstalledPackages:=OldInstalledPackages;
|
|
// InstallPkgSetDialog.UpdateAvailablePackages;
|
|
InstallPkgSetDialog.UpdateButtonStates;
|
|
InstallPkgSetDialog.OnCheckInstallPackageList:=CheckInstallPackageList;
|
|
Result:=InstallPkgSetDialog.ShowModal;
|
|
NewInstalledPackages:=InstallPkgSetDialog.GetNewInstalledPackages;
|
|
RebuildIDE:=InstallPkgSetDialog.RebuildIDE;
|
|
finally
|
|
InstallPkgSetDialog.Free;
|
|
end;
|
|
end;
|
|
|
|
{ TInstallPkgSetDialog }
|
|
|
|
procedure TInstallPkgSetDialog.InstallPkgSetDialogCreate(Sender: TObject);
|
|
begin
|
|
InstallTreeView.Images := IDEImages.Images_16;
|
|
AvailableTreeView.Images := IDEImages.Images_16;
|
|
ImgIndexPackage := IDEImages.LoadImage(16, 'item_package');
|
|
ImgIndexInstalledPackage := IDEImages.LoadImage(16, 'pkg_installed');
|
|
ImgIndexInstallPackage := IDEImages.LoadImage(16, 'pkg_package_autoinstall');
|
|
ImgIndexUninstallPackage := IDEImages.LoadImage(16, 'pkg_package_uninstall');
|
|
ImgIndexCirclePackage := IDEImages.LoadImage(16, 'pkg_package_circle');
|
|
ImgIndexMissingPackage := IDEImages.LoadImage(16, 'pkg_conflict');
|
|
|
|
Caption:=lisInstallUninstallPackages;
|
|
NoteLabel.Caption:=lisToInstallYouMustCompileAndRestartTheIDE;
|
|
|
|
AvailablePkgGroupBox.Caption:=lisDoNotInstall;
|
|
AvailableFilterEdit.OnGetImageIndex:=@GetAvailablePkgImageIndex;
|
|
|
|
ExportButton.Caption:=lisExportList;
|
|
ImportButton.Caption:=lisImportList;
|
|
UninstallButton.Caption:=lisUninstallSelection;
|
|
UninstallButton.LoadGlyphFromLazarusResource('arrow_right');
|
|
InstallPkgGroupBox.Caption:=lisPckEditInstall;
|
|
AddToInstallButton.Caption:=lisInstallSelection;
|
|
AddToInstallButton.LoadGlyphFromLazarusResource('arrow_left');
|
|
PkgInfoGroupBox.Caption := lisPackageInfo;
|
|
SaveAndRebuildButton.Caption:=lisSaveAndRebuildIDE;
|
|
SaveAndExitButton.Caption:=lisSaveAndExitDialog;
|
|
HelpButton.Caption:=lisMenuHelp;
|
|
CancelButton.Caption:=lisCancel;
|
|
|
|
fAvailablePackages:=TAVLTree.Create(@CompareLazPackageIDNames);
|
|
FNewInstalledPackages:=TObjectList.Create(true);
|
|
ActiveControl:=AvailableFilterEdit;
|
|
PkgInfoMemo.Clear;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.InstallButtonClick(Sender: TObject);
|
|
begin
|
|
if not CheckSelection then exit;
|
|
RebuildIDE:=true;
|
|
ModalResult:=mrOk;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.InstallTreeViewDblClick(Sender: TObject);
|
|
begin
|
|
AddToUninstall;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.AvailableTreeViewSelectionChanged(Sender: TObject);
|
|
begin
|
|
UpdateButtonStates;
|
|
UpdatePackageInfo(AvailableTreeView);
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.ExportButtonClick(Sender: TObject);
|
|
var
|
|
SaveDialog: TSaveDialog;
|
|
AFilename: string;
|
|
begin
|
|
SaveDialog:=TSaveDialog.Create(nil);
|
|
try
|
|
InputHistories.ApplyFileDialogSettings(SaveDialog);
|
|
SaveDialog.InitialDir:=GetPrimaryConfigPath;
|
|
SaveDialog.Title:='Export package list (*.xml)';
|
|
SaveDialog.Options:=SaveDialog.Options+[ofPathMustExist];
|
|
if SaveDialog.Execute then begin
|
|
AFilename:=CleanAndExpandFilename(SaveDialog.Filename);
|
|
if ExtractFileExt(AFilename)='' then
|
|
AFilename:=AFilename+'.xml';
|
|
SavePackageListToFile(AFilename);
|
|
end;
|
|
InputHistories.StoreFileDialogSettings(SaveDialog);
|
|
finally
|
|
SaveDialog.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.HelpButtonClick(Sender: TObject);
|
|
begin
|
|
LazarusHelp.ShowHelpForIDEControl(Self);
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.ImportButtonClick(Sender: TObject);
|
|
var
|
|
OpenDialog: TOpenDialog;
|
|
AFilename: string;
|
|
begin
|
|
OpenDialog:=TSaveDialog.Create(nil);
|
|
try
|
|
InputHistories.ApplyFileDialogSettings(OpenDialog);
|
|
OpenDialog.InitialDir:=GetPrimaryConfigPath;
|
|
OpenDialog.Title:='Import package list (*.xml)';
|
|
OpenDialog.Options:=OpenDialog.Options+[ofPathMustExist,ofFileMustExist];
|
|
if OpenDialog.Execute then begin
|
|
AFilename:=CleanAndExpandFilename(OpenDialog.Filename);
|
|
LoadPackageListFromFile(AFilename);
|
|
end;
|
|
InputHistories.StoreFileDialogSettings(OpenDialog);
|
|
finally
|
|
OpenDialog.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.AddToInstallButtonClick(Sender: TObject);
|
|
begin
|
|
AddToInstall;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.AvailableTreeViewDblClick(Sender: TObject);
|
|
begin
|
|
AddToInstall;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.AvailableTreeViewKeyPress(Sender: TObject; var Key: char);
|
|
begin
|
|
if Key = char(VK_RETURN) then
|
|
AddToInstall;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.InstallPkgSetDialogDestroy(Sender: TObject);
|
|
begin
|
|
ClearNewInstalledPackages;
|
|
FNewInstalledPackages.Free;
|
|
fAvailablePackages.Free;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.InstallPkgSetDialogResize(Sender: TObject);
|
|
var
|
|
w: Integer;
|
|
begin
|
|
w:=ClientWidth div 2-InstallPkgGroupBox.BorderSpacing.Left*3;
|
|
if w<1 then w:=1;
|
|
InstallPkgGroupBox.Width:=w;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.InstallTreeViewSelectionChanged(Sender: TObject);
|
|
begin
|
|
UpdateButtonStates;
|
|
UpdatePackageInfo(InstallTreeView);
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.SaveAndExitButtonClick(Sender: TObject);
|
|
begin
|
|
if not CheckSelection then exit;
|
|
RebuildIDE:=false;
|
|
ModalResult:=mrOk;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.UninstallButtonClick(Sender: TObject);
|
|
begin
|
|
AddToUninstall;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.SetOldInstalledPackages(const AValue: TPkgDependency);
|
|
begin
|
|
if FOldInstalledPackages=AValue then exit;
|
|
FOldInstalledPackages:=AValue;
|
|
AssignOldInstalledPackagesToList;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.AssignOldInstalledPackagesToList;
|
|
var
|
|
Dependency: TPkgDependency;
|
|
Cnt: Integer;
|
|
NewPackageID: TLazPackageID;
|
|
begin
|
|
ClearNewInstalledPackages;
|
|
Cnt:=0;
|
|
Dependency:=OldInstalledPackages;
|
|
while Dependency<>nil do begin
|
|
NewPackageID:=TLazPackageID.Create;
|
|
if (Dependency.LoadPackageResult=lprSuccess)
|
|
and (Dependency.RequiredPackage<>nil) then begin
|
|
// packages can be freed while the dialog runs => use packageid instead
|
|
NewPackageID.AssignID(Dependency.RequiredPackage);
|
|
end else begin
|
|
NewPackageID.Name:=Dependency.PackageName;
|
|
end;
|
|
FNewInstalledPackages.Add(NewPackageID);
|
|
Dependency:=Dependency.NextRequiresDependency;
|
|
inc(Cnt);
|
|
end;
|
|
UpdateNewInstalledPackages;
|
|
end;
|
|
|
|
function TInstallPkgSetDialog.PackageInInstallList(PkgName: string): boolean;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
//for i:=0 to InstallTreeView.Items.TopLvlCount-1 do
|
|
//debugln(['TInstallPkgSetDialog.PackageInInstallList ',i,' ',ExtractNameFromPkgID(InstallTreeView.Items.TopLvlItems[i].Text),' ',PkgName]);
|
|
for i:=0 to InstallTreeView.Items.TopLvlCount-1 do
|
|
if SysUtils.CompareText(
|
|
ExtractNameFromPkgID(InstallTreeView.Items.TopLvlItems[i].Text),PkgName)=0
|
|
then
|
|
exit(true);
|
|
Result:=false;
|
|
end;
|
|
|
|
function TInstallPkgSetDialog.GetPkgImgIndex(APackage: TLazPackage;
|
|
InInstallList: boolean): integer;
|
|
begin
|
|
if APackage.Installed<>pitNope then begin
|
|
// is not currently installed
|
|
if InInstallList then begin
|
|
// is installed and will be installed
|
|
Result:=ImgIndexPackage;
|
|
end
|
|
else begin
|
|
// is installed and will be uninstalled
|
|
Result:=ImgIndexUninstallPackage;
|
|
end;
|
|
end else begin
|
|
// is currently installed
|
|
if InInstallList then begin
|
|
// is not installed and will be installed
|
|
Result:=ImgIndexInstallPackage;
|
|
end
|
|
else begin
|
|
// is not installed and will be not be installed
|
|
Result:=ImgIndexPackage;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TInstallPkgSetDialog.GetAvailablePkgImageIndex(Str: String; Data: TObject;
|
|
var AIsEnabled: Boolean): Integer;
|
|
begin
|
|
Result:=ImgIndexPackage;
|
|
if (Data is TLazPackage) then
|
|
Result:=GetPkgImgIndex(TLazPackage(Data),false);
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.UpdateAvailablePackages(Immediately: boolean);
|
|
var
|
|
ANode: TAVLTreeNode;
|
|
Pkg: TLazPackageID;
|
|
PkgName: String;
|
|
DuplCheck: TStringList; // Add pkg names also here to filter out duplicates.
|
|
FilteredBranch: TTreeFilterBranch;
|
|
begin
|
|
DuplCheck:=TStringList.Create;
|
|
try
|
|
if fAvailablePackages.Count=0 then
|
|
PackageGraph.IteratePackages(fpfSearchAllExisting,@OnIteratePackages);
|
|
FilteredBranch := AvailableFilterEdit.GetBranch(Nil); // All items are top level.
|
|
ANode:=fAvailablePackages.FindLowest;
|
|
while ANode<>nil do begin
|
|
Pkg:=TLazPackageID(ANode.Data);
|
|
if (not (Pkg is TLazPackage))
|
|
or (TLazPackage(Pkg).PackageType in [lptDesignTime,lptRunAndDesignTime])
|
|
then begin
|
|
if (not PackageInInstallList(Pkg.Name)) then begin
|
|
PkgName:=Pkg.IDAsString;
|
|
if (DuplCheck.IndexOf(PkgName)<0) then begin
|
|
DuplCheck.Add(PkgName);
|
|
FilteredBranch.AddNodeData(PkgName, Pkg);
|
|
end;
|
|
end;
|
|
end;
|
|
ANode:=fAvailablePackages.FindSuccessor(ANode);
|
|
end;
|
|
AvailableFilterEdit.InvalidateFilter;
|
|
finally
|
|
DuplCheck.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.UpdateNewInstalledPackages;
|
|
var
|
|
s: String;
|
|
NewPackageID: TLazPackageID;
|
|
i: Integer;
|
|
sl: TStringList;
|
|
TVNode: TTreeNode;
|
|
APackage: TLazPackage;
|
|
ImgIndex: LongInt;
|
|
begin
|
|
sl:=TStringList.Create;
|
|
for i:=0 to FNewInstalledPackages.Count-1 do begin
|
|
NewPackageID:=TLazPackageID(FNewInstalledPackages[i]);
|
|
APackage:=PackageGraph.FindPackageWithName(NewPackageID.Name,nil);
|
|
if APackage<>nil then
|
|
NewPackageID:=APackage;
|
|
s:=NewPackageID.IDAsString;
|
|
sl.AddObject(s,NewPackageID);
|
|
end;
|
|
sl.Sort;
|
|
InstallTreeView.BeginUpdate;
|
|
InstallTreeView.Items.Clear;
|
|
for i:=0 to sl.Count-1 do begin
|
|
TVNode:=InstallTreeView.Items.Add(nil,sl[i]);
|
|
NewPackageID:=TLazPackageID(sl.Objects[i]);
|
|
ImgIndex:=ImgIndexInstallPackage;
|
|
if NewPackageID is TLazPackage then begin
|
|
APackage:=TLazPackage(NewPackageID);
|
|
ImgIndex:=GetPkgImgIndex(APackage,true);
|
|
end;
|
|
TVNode.ImageIndex:=ImgIndex;
|
|
TVNode.SelectedIndex:=ImgIndex;
|
|
end;
|
|
InstallTreeView.EndUpdate;
|
|
sl.Free;
|
|
UpdateAvailablePackages;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.OnIteratePackages(APackageID: TLazPackageID);
|
|
begin
|
|
//debugln('TInstallPkgSetDialog.OnIteratePackages ',APackageID.IDAsString);
|
|
if (fAvailablePackages.Find(APackageID)=nil) then
|
|
fAvailablePackages.Add(APackageID);
|
|
end;
|
|
|
|
function TInstallPkgSetDialog.DependencyToStr(Dependency: TPkgDependency): string;
|
|
begin
|
|
Result:='';
|
|
if Dependency=nil then exit;
|
|
if (Dependency.LoadPackageResult=lprSuccess)
|
|
and (Dependency.RequiredPackage<>nil) then
|
|
Result:=Dependency.RequiredPackage.IDAsString
|
|
else
|
|
Result:=Dependency.PackageName;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.ClearNewInstalledPackages;
|
|
begin
|
|
FNewInstalledPackages.Clear;
|
|
end;
|
|
|
|
function TInstallPkgSetDialog.CheckSelection: boolean;
|
|
begin
|
|
OnCheckInstallPackageList(FNewInstalledPackages,true,Result);
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.UpdateButtonStates;
|
|
var
|
|
Cnt: Integer;
|
|
Dependency: TPkgDependency;
|
|
s: String;
|
|
ListChanged: Boolean;
|
|
begin
|
|
UninstallButton.Enabled:=InstallTreeView.Selected<>nil;
|
|
AddToInstallButton.Enabled:=AvailableTreeView.Selected<>nil;
|
|
// check for changes
|
|
ListChanged:=false;
|
|
Cnt:=0;
|
|
Dependency:=OldInstalledPackages;
|
|
while Dependency<>nil do begin
|
|
s:=Dependency.PackageName;
|
|
if not PackageInInstallList(s) then begin
|
|
ListChanged:=true;
|
|
break;
|
|
end;
|
|
Dependency:=Dependency.NextRequiresDependency;
|
|
inc(Cnt);
|
|
end;
|
|
if InstallTreeView.Items.TopLvlCount<>Cnt then
|
|
ListChanged:=true;
|
|
SaveAndExitButton.Enabled:=ListChanged;
|
|
SaveAndRebuildButton.Enabled:=ListChanged;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.UpdatePackageInfo(Tree: TTreeView);
|
|
var
|
|
InfoStr: string;
|
|
|
|
procedure AddState(const NewState: string);
|
|
begin
|
|
if (InfoStr<>'') and (InfoStr[length(InfoStr)]<>' ') then
|
|
InfoStr:=InfoStr+', ';
|
|
InfoStr:=InfoStr+NewState;
|
|
end;
|
|
|
|
var
|
|
PkgName: String;
|
|
PkgID: TLazPackageID;
|
|
Author: String;
|
|
Description: String;
|
|
PkgLink: TPackageLink;
|
|
XMLConfig: TXMLConfig;
|
|
begin
|
|
if Tree = nil then Exit;
|
|
PkgName := '';
|
|
if Tree.Selected <> nil then
|
|
PkgName := Tree.Selected.Text;
|
|
|
|
if PkgName = '' then Exit;
|
|
if Assigned(FSelectedPkg) and (PkgName = FSelectedPkg.IDAsString) then Exit;
|
|
|
|
PkgInfoMemo.Clear;
|
|
PkgID := TLazPackageID.Create;
|
|
try
|
|
PkgID.StringToID(PkgName);
|
|
FSelectedPkg := PackageGraph.FindPackageWithID(PkgID);
|
|
|
|
Author:='';
|
|
Description:='';
|
|
if FSelectedPkg <> nil then begin
|
|
Author:=FSelectedPkg.Author;
|
|
Description:=FSelectedPkg.Description;
|
|
end else begin
|
|
// package not loaded -> read values from .lpk
|
|
PkgLink:=PkgLinks.FindLinkWithPackageID(PkgID);
|
|
if (PkgLink<>nil) and FileExistsCached(PkgLink.GetEffectiveFilename) then begin
|
|
// load the package file
|
|
try
|
|
XMLConfig:=TXMLConfig.Create(PkgLink.GetEffectiveFilename);
|
|
try
|
|
Author:=XMLConfig.GetValue('Package/Author/Value','');
|
|
Description:=XMLConfig.GetValue('Package/Description/Value','');
|
|
finally
|
|
XMLConfig.Free;
|
|
end;
|
|
except
|
|
on E: Exception do begin
|
|
DebugLn('TInstallPkgSetDialog.UpdatePackageInfo ERROR: ',E.Message);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
if Author<>'' then
|
|
PkgInfoMemo.Lines.Add(lisPckOptsAuthor + ': ' + Author);
|
|
if Description<>'' then
|
|
PkgInfoMemo.Lines.Add(lisPckOptsDescriptionAbstract
|
|
+ ': ' + Description);
|
|
if FSelectedPkg<>nil then
|
|
begin
|
|
PkgInfoMemo.Lines.Add(Format(lisOIPFilename, [FSelectedPkg.Filename]));
|
|
InfoStr:=lisCurrentState;
|
|
if FSelectedPkg.Installed<>pitNope then
|
|
AddState(lisInstalled)
|
|
else
|
|
AddState(lisNotInstalled);
|
|
if FSelectedPkg.AutoCreated then
|
|
AddState(lisPckExplAutoCreated);
|
|
PkgInfoMemo.Lines.Add(InfoStr);
|
|
end;
|
|
finally
|
|
PkgId.Free;
|
|
end;
|
|
end;
|
|
|
|
function TInstallPkgSetDialog.NewInstalledPackagesContains(
|
|
APackageID: TLazPackageID): boolean;
|
|
begin
|
|
Result:=IndexOfNewInstalledPackageID(APackageID)>=0;
|
|
end;
|
|
|
|
function TInstallPkgSetDialog.IndexOfNewInstalledPackageID(
|
|
APackageID: TLazPackageID): integer;
|
|
begin
|
|
Result:=FNewInstalledPackages.Count-1;
|
|
while (Result>=0)
|
|
and (TLazPackageID(FNewInstalledPackages[Result]).Compare(APackageID)<>0) do
|
|
dec(Result);
|
|
end;
|
|
|
|
function TInstallPkgSetDialog.IndexOfNewInstalledPkgByName(
|
|
const APackageName: string): integer;
|
|
begin
|
|
Result:=FNewInstalledPackages.Count-1;
|
|
while (Result>=0)
|
|
and (CompareText(TLazPackageID(FNewInstalledPackages[Result]).Name,
|
|
APackageName)<>0)
|
|
do
|
|
dec(Result);
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.SavePackageListToFile(const AFilename: string);
|
|
var
|
|
XMLConfig: TXMLConfig;
|
|
i: Integer;
|
|
LazPackageID: TLazPackageID;
|
|
begin
|
|
try
|
|
XMLConfig:=TXMLConfig.CreateClean(AFilename);
|
|
try
|
|
XMLConfig.SetDeleteValue('Packages/Count',FNewInstalledPackages.Count,0);
|
|
for i:=0 to FNewInstalledPackages.Count-1 do begin
|
|
LazPackageID:=TLazPackageID(FNewInstalledPackages[i]);
|
|
XMLConfig.SetDeleteValue('Packages/Item'+IntToStr(i)+'/ID',
|
|
LazPackageID.IDAsString,'');
|
|
end;
|
|
InvalidateFileStateCache;
|
|
XMLConfig.Flush;
|
|
finally
|
|
XMLConfig.Free;
|
|
end;
|
|
except
|
|
on E: Exception do begin
|
|
MessageDlg(lisCodeToolsDefsWriteError,
|
|
Format(lisErrorWritingPackageListToFile, [#13, AFilename, #13, E.Message
|
|
]), mtError, [mbCancel], 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.LoadPackageListFromFile(const AFilename: string);
|
|
|
|
function PkgNameExists(List: TObjectList; ID: TLazPackageID): boolean;
|
|
var
|
|
i: Integer;
|
|
LazPackageID: TLazPackageID;
|
|
begin
|
|
if List<>nil then
|
|
for i:=0 to List.Count-1 do begin
|
|
LazPackageID:=TLazPackageID(List[i]);
|
|
if CompareText(LazPackageID.Name,ID.Name)=0 then begin
|
|
Result:=true;
|
|
exit;
|
|
end;
|
|
end;
|
|
Result:=false;
|
|
end;
|
|
|
|
var
|
|
XMLConfig: TXMLConfig;
|
|
i: Integer;
|
|
LazPackageID: TLazPackageID;
|
|
NewCount: LongInt;
|
|
NewList: TObjectList;
|
|
ID: String;
|
|
begin
|
|
NewList:=nil;
|
|
LazPackageID:=nil;
|
|
try
|
|
XMLConfig:=TXMLConfig.Create(AFilename);
|
|
try
|
|
NewCount:=XMLConfig.GetValue('Packages/Count',0);
|
|
LazPackageID:=TLazPackageID.Create;
|
|
for i:=0 to NewCount-1 do begin
|
|
// get ID
|
|
ID:=XMLConfig.GetValue('Packages/Item'+IntToStr(i)+'/ID','');
|
|
if ID='' then continue;
|
|
// parse ID
|
|
if not LazPackageID.StringToID(ID) then continue;
|
|
// ignore doubles
|
|
if PkgNameExists(NewList,LazPackageID) then continue;
|
|
// add
|
|
if NewList=nil then NewList:=TObjectList.Create(true);
|
|
NewList.Add(LazPackageID);
|
|
LazPackageID:=TLazPackageID.Create;
|
|
end;
|
|
// clean up old list
|
|
ClearNewInstalledPackages;
|
|
FNewInstalledPackages.Free;
|
|
// assign new list
|
|
FNewInstalledPackages:=NewList;
|
|
NewList:=nil;
|
|
UpdateNewInstalledPackages;
|
|
UpdateButtonStates;
|
|
finally
|
|
XMLConfig.Free;
|
|
LazPackageID.Free;
|
|
NewList.Free;
|
|
end;
|
|
except
|
|
on E: Exception do begin
|
|
MessageDlg(lisCodeToolsDefsReadError,
|
|
Format(lisErrorReadingPackageListFromFile, [#13, AFilename, #13,
|
|
E.Message]), mtError, [mbCancel], 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TInstallPkgSetDialog.ExtractNameFromPkgID(ID: string): string;
|
|
var
|
|
p: Integer;
|
|
begin
|
|
p:=1;
|
|
while (p<=length(ID)) and IsIdentChar[ID[p]] do inc(p);
|
|
Result:=copy(ID,1,p-1);
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.AddToInstall;
|
|
var
|
|
i: Integer;
|
|
NewPackageID: TLazPackageID;
|
|
j: LongInt;
|
|
APackage: TLazPackage;
|
|
Additions: TObjectList;
|
|
TVNode: TTreeNode;
|
|
PkgName: String;
|
|
ConflictDep: TPkgDependency;
|
|
begin
|
|
Additions:=TObjectList.Create(false);
|
|
NewPackageID:=TLazPackageID.Create;
|
|
try
|
|
for i:=0 to AvailableTreeView.Items.TopLvlCount-1 do begin
|
|
TVNode:=AvailableTreeView.Items.TopLvlItems[i];
|
|
if not TVNode.MultiSelected then continue;
|
|
PkgName:=TVNode.Text;
|
|
// check string
|
|
if not NewPackageID.StringToID(PkgName) then begin
|
|
TVNode.Selected:=false;
|
|
debugln('TInstallPkgSetDialog.AddToInstallButtonClick invalid ID: ',
|
|
PkgName);
|
|
continue;
|
|
end;
|
|
// check if already in list
|
|
if NewInstalledPackagesContains(NewPackageID) then begin
|
|
MessageDlg(lisDuplicate,
|
|
Format(lisThePackageIsAlreadyInTheList, [NewPackageID.Name]), mtError,
|
|
[mbCancel],0);
|
|
TVNode.Selected:=false;
|
|
exit;
|
|
end;
|
|
// check if a package with same name is already in the list
|
|
j:=IndexOfNewInstalledPkgByName(NewPackageID.Name);
|
|
if j>=0 then begin
|
|
MessageDlg(lisConflict,
|
|
Format(lisThereIsAlreadyAPackageInTheList, [NewPackageID.Name]),
|
|
mtError,[mbCancel],0);
|
|
TVNode.Selected:=false;
|
|
exit;
|
|
end;
|
|
// check if package is loaded and has some attributes that prevents
|
|
// installation in the IDE
|
|
APackage:=PackageGraph.FindPackageWithID(NewPackageID);
|
|
if APackage<>nil then begin
|
|
if APackage.PackageType in [lptRunTime,lptRunTimeOnly] then begin
|
|
IDEMessageDialog(lisNotADesigntimePackage,
|
|
Format(lisThePackageIsNotADesignTimePackageItCanNotBeInstall, [
|
|
APackage.IDAsString]), mtError,
|
|
[mbCancel]);
|
|
TVNode.Selected:=false;
|
|
exit;
|
|
end;
|
|
ConflictDep:=PackageGraph.FindRuntimePkgOnlyRecursively(
|
|
APackage.FirstRequiredDependency);
|
|
if ConflictDep<>nil then begin
|
|
IDEMessageDialog(lisNotADesigntimePackage,
|
|
Format(lisThePackageCanNotBeInstalledBecauseItRequiresWhichI, [
|
|
APackage.Name, ConflictDep.AsString]),
|
|
mtError,[mbCancel]);
|
|
TVNode.Selected:=false;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// ok => add to list
|
|
Additions.Add(NewPackageID);
|
|
NewPackageID:=TLazPackageID.Create;
|
|
end;
|
|
// all ok => add to list
|
|
for i:=0 to Additions.Count-1 do
|
|
FNewInstalledPackages.Add(Additions[i]);
|
|
Additions.Clear;
|
|
UpdateNewInstalledPackages;
|
|
UpdateButtonStates;
|
|
finally
|
|
// clean up
|
|
NewPackageID.Free;
|
|
for i:=0 to Additions.Count-1 do
|
|
TObject(Additions[i]).Free;
|
|
Additions.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TInstallPkgSetDialog.AddToUninstall;
|
|
var
|
|
i: Integer;
|
|
OldPackageID: TLazPackageID;
|
|
APackage: TLazPackage;
|
|
Deletions: TObjectList;
|
|
DelPackageID: TLazPackageID;
|
|
j: LongInt;
|
|
TVNode: TTreeNode;
|
|
PkgName: String;
|
|
begin
|
|
OldPackageID := nil;
|
|
Deletions:=TObjectList.Create(true);
|
|
try
|
|
for i:=0 to InstallTreeView.Items.TopLvlCount-1 do begin
|
|
TVNode:=InstallTreeView.Items.TopLvlItems[i];
|
|
if not TVNode.MultiSelected then continue;
|
|
if OldPackageID = nil then
|
|
OldPackageID:=TLazPackageID.Create;
|
|
PkgName:=TVNode.Text;
|
|
if not OldPackageID.StringToID(PkgName) then begin
|
|
TVNode.Selected:=false;
|
|
debugln('TInstallPkgSetDialog.AddToUninstallButtonClick invalid ID: ',
|
|
PkgName);
|
|
continue;
|
|
end;
|
|
// ok => add to deletions
|
|
Deletions.Add(OldPackageID);
|
|
DelPackageID:=OldPackageID;
|
|
OldPackageID := nil;
|
|
// get package
|
|
APackage:=PackageGraph.FindPackageWithID(DelPackageID);
|
|
if APackage<>nil then begin
|
|
// check if package is a base package
|
|
if APackage.AutoCreated
|
|
or PackageGraph.IsStaticBasePackage(APackage.Name) then begin
|
|
TVNode.Selected:=false;
|
|
MessageDlg(lisUninstallImpossible,
|
|
Format(lisThePackageCanNotBeUninstalledBecauseItIsNeededByTh, [
|
|
APackage.Name]), mtError, [mbCancel], 0);
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// ok => remove from list
|
|
InstallTreeView.Selected:=nil;
|
|
for i:=0 to Deletions.Count-1 do begin
|
|
DelPackageID:=TLazPackageID(Deletions[i]);
|
|
j:=IndexOfNewInstalledPackageID(DelPackageID);
|
|
FNewInstalledPackages.Delete(j);
|
|
end;
|
|
|
|
UpdateNewInstalledPackages;
|
|
UpdateButtonStates;
|
|
finally
|
|
OldPackageID.Free;
|
|
Deletions.Free;
|
|
end;
|
|
end;
|
|
|
|
function TInstallPkgSetDialog.GetNewInstalledPackages: TObjectList;
|
|
var
|
|
i: Integer;
|
|
NewPackageID: TLazPackageID;
|
|
begin
|
|
Result:=TObjectList.Create(true);
|
|
for i:=0 to FNewInstalledPackages.Count-1 do begin
|
|
NewPackageID:=TLazPackageID.Create;
|
|
NewPackageID.AssignID(TLazPackageID(FNewInstalledPackages[i]));
|
|
Result.Add(NewPackageID);
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|