unit AddPkgDependencyDlg; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Types, Laz_AVL_Tree, fgl, // LCL Forms, Controls, Dialogs, StdCtrls, ButtonPanel, LCLProc, LCLType, Graphics, LCLIntf, ExtCtrls, // LazControls ListFilterEdit, // IDEIntf IDEWindowIntf, PackageDependencyIntf, PackageIntf, IDEDialogs, IDEImagesIntf, PackageLinkIntf, MainIntf, // IDE LazarusIDEStrConsts, PackageDefs, PackageSystem, ProjPackCommon, ProjPackChecks; type TPkgDependencyList = specialize TFPGList; { TAddPkgDependencyDialog } TAddPkgDependencyDialog = class(TForm) BP: TButtonPanel; cbLocalPkg: TCheckBox; cbOnlinePkg: TCheckBox; DependMaxVersionEdit: TEdit; DependMaxVersionLabel: TLabel; DependMinVersionEdit: TEdit; DependMinVersionLabel: TLabel; DependPkgNameFilter: TListFilterEdit; DependPkgNameLabel: TLabel; DependPkgTypeLabel: TLabel; DependPkgNameListBox: TListBox; pnLocalPkg: TPanel; pnOnlinePkg: TPanel; procedure cbLocalPkgChange(Sender: TObject); procedure CloseButtonClick(Sender: TObject); procedure DependPkgNameListBoxDrawItem(Control: TWinControl; Index: Integer; ARect: TRect; State: TOwnerDrawState); procedure DependPkgNameListBoxSelectionChange(Sender: TObject; {%H-}User: boolean); procedure FormClose(Sender: TObject; var {%H-}CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); procedure OKButtonClick(Sender: TObject); function FindPackageLink(const ALazPackageID: TLazPackageID): TPackageLink; function InstallOnlinePackages(out ANeedToRebuild: Boolean): TModalResult; private fUpdating: Boolean; fSL: TStringList; fPackages: TAVLTree; // tree of TLazPackage or TPackageLink fProjPack: IProjPack; fResultDependencies: TPkgDependencyList; procedure AddUniquePackagesToList(APackageID: TLazPackageID); procedure UpdateAvailableDependencyNames; function IsInstallButtonVisible: Boolean; public constructor Create(TheOwner: TComponent); override; destructor Destroy; override; end; var AddPkgDependencyDialog: TAddPkgDependencyDialog; function ShowAddPkgDependencyDlg(AProjPack: IProjPack; out AResultDependencies: TPkgDependencyList): TModalResult; implementation {$R *.lfm} function ShowAddPkgDependencyDlg(AProjPack: IProjPack; out AResultDependencies: TPkgDependencyList): TModalResult; var AddDepDialog: TAddPkgDependencyDialog; begin AddDepDialog:=TAddPkgDependencyDialog.Create(nil); AddDepDialog.fProjPack:=AProjPack; AddDepDialog.UpdateAvailableDependencyNames; Result:=AddDepDialog.ShowModal; if Result=mrOk then begin AResultDependencies:=AddDepDialog.fResultDependencies; AddDepDialog.fResultDependencies:=nil; end else begin AResultDependencies:=nil; end; AddDepDialog.Free; end; { TAddPkgDependencyDialog } constructor TAddPkgDependencyDialog.Create(TheOwner: TComponent); begin inherited Create(TheOwner); Caption:=lisProjAddNewRequirement; fPackages:=TAVLTree.Create(@CompareLazPackageIDNames); DependPkgNameLabel.Caption:=lisProjAddPackageName; DependPkgTypeLabel.Caption:=lisProjAddPackageType; cbLocalPkg.Caption:=lisProjAddLocalPkg; cbOnlinePkg.Caption:=lisProjAddOnlinePkg; BP.CloseButton.Caption := lisPckEditInstall; DependMinVersionLabel.Caption:=lisProjAddMinimumVersionOptional; DependMinVersionEdit.Text:=''; DependMaxVersionLabel.Caption:=lisProjAddMaximumVersionOptional; DependMaxVersionEdit.Text:=''; IDEDialogLayoutList.ApplyLayout(Self,400,360); end; destructor TAddPkgDependencyDialog.Destroy; begin FreeAndNil(fPackages); inherited Destroy; end; procedure TAddPkgDependencyDialog.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin fSL.Free; fSL := nil; IDEDialogLayoutList.SaveLayout(Self); end; procedure TAddPkgDependencyDialog.FormCreate(Sender: TObject); begin fSL := TStringList.Create; DependPkgTypeLabel.Visible := OPMInterface <> nil; pnLocalPkg.Visible := OPMInterface <> nil; pnOnlinePkg.Visible := OPMInterface <> nil; BP.CloseButton.Visible := False; DependPkgNameListBox.ItemHeight := MulDiv(20, Screen.PixelsPerInch, 96); end; function TAddPkgDependencyDialog.FindPackageLink(const ALazPackageID: TLazPackageID): TPackageLink; var I: Integer; begin Result := nil; if (fSL = nil) or (fSL.Count = 0) then Exit; for I := 0 to fSL.Count - 1 do begin if TLazPackageID(fSL.Objects[I]) = ALazPackageID then begin Result := TPackageLink(fSL.Objects[I]); Break; end; end; end; procedure TAddPkgDependencyDialog.DependPkgNameListBoxDrawItem( Control: TWinControl; Index: Integer; ARect: TRect; State: TOwnerDrawState); var ItemText: string; PackageLink: TPackageLink; begin with (Control as TListBox).Canvas do begin if odSelected In State then begin Pen.Color := clHighlightText; Brush.Color := clHighlight; end else begin Pen.Color := (Control as TListBox).Font.Color; Brush.Color := (Control as TListBox).Color; if Assigned(OPMInterface) then begin PackageLink := FindPackageLink(TLazPackageID(DependPkgNameListBox.Items.Objects[Index])); if PackageLink <> nil then begin if PackageLink.Origin = ploOnline then Brush.Color := pnOnlinePkg.Color else Brush.Color := pnLocalPkg.Color end; end end; FillRect(ARect); ItemText := (Control as TListBox).Items[Index]; InflateRect(ARect, -1, -1); inc(ARect.Left,3); DrawText(Handle, PChar(ItemText), Length(ItemText), ARect, DT_LEFT or DT_VCENTER or DT_SINGLELINE); end; end; function TAddPkgDependencyDialog.IsInstallButtonVisible: Boolean; var I: Integer; PackageLink: TPackageLink; begin Result := False; if (OPMInterface = nil) or (fSL = nil) or (fSL.Count = 0) then Exit; for I := 0 to DependPkgNameListBox.Count - 1 do begin if DependPkgNameListBox.Selected[I] then begin PackageLink := FindPackageLink(TLazPackageID(DependPkgNameListBox.Items.Objects[I])); if (PackageLink <> nil) and (PackageLink.Origin = ploOnline) then begin Result := True; Break; end; end; end; end; procedure TAddPkgDependencyDialog.DependPkgNameListBoxSelectionChange( Sender: TObject; User: boolean); begin BP.CloseButton.Visible := IsInstallButtonVisible; if BP.CloseButton.Visible then BP.OKButton.Enabled := False else BP.OKButton.Enabled := True; end; procedure TAddPkgDependencyDialog.cbLocalPkgChange(Sender: TObject); begin UpdateAvailableDependencyNames; end; function TAddPkgDependencyDialog.InstallOnlinePackages(out ANeedToRebuild: Boolean): TModalResult; var I: Integer; PackageLink: TPackageLink; PkgList: TList; begin ANeedToRebuild := False; Result := mrOk; PkgList := TList.Create; try for I := 0 to DependPkgNameListBox.Count - 1 do begin if DependPkgNameListBox.Selected[I] then begin PackageLink := FindPackageLink(TLazPackageID(DependPkgNameListBox.Items.Objects[I])); if (PackageLink <> nil) and (PackageLink.Origin = ploOnline) then PkgList.Add(PackageLink); end; end; if PkgList.Count > 0 then Result := OPMInterface.InstallPackages(PkgList, ANeedToRebuild); finally PkgList.Free; PkgList := nil; end; end; procedure TAddPkgDependencyDialog.CloseButtonClick(Sender: TObject); var NeedToRebuild: Boolean; begin ModalResult := mrNone; if InstallOnlinePackages(NeedToRebuild) = mrOK then begin UpdateAvailableDependencyNames; if NeedToRebuild then begin Self.Hide; MainIDEInterface.DoBuildLazarus([]); end; end; end; procedure TAddPkgDependencyDialog.AddUniquePackagesToList(APackageID: TLazPackageID); begin if (APackageID.IDAsString<>fProjPack.IDAsString) and (fPackages.Find(APackageID)=Nil) then fPackages.Add(APackageID); end; procedure TAddPkgDependencyDialog.UpdateAvailableDependencyNames; var ANode: TAVLTreeNode; CntLocalPkg: Integer; CntOnlinePkg: Integer; begin if fUpdating then Exit; fUpdating := True; try CntLocalPkg := 0; CntOnlinePkg := 0; DependPkgNameListBox.Clear; fSL.Clear; fPackages.Clear; PackageGraph.IteratePackages(fpfSearchAllExisting,@AddUniquePackagesToList); ANode:=fPackages.FindLowest; while ANode<>nil do begin if (TPackageLink(ANode.Data).Origin = ploOnline) and (cbOnlinePkg.Checked) and Assigned(OPMInterface) then begin Inc(CntOnlinePkg); fSL.AddObject(TLazPackageID(ANode.Data).Name, TLazPackageID(ANode.Data)); end; if (TPackageLink(ANode.Data).Origin <> ploOnline) and (cbLocalPkg.Checked) then begin Inc(CntLocalPkg); fSL.AddObject(TLazPackageID(ANode.Data).Name, TLazPackageID(ANode.Data)); end; ANode:=fPackages.FindSuccessor(ANode); end; DependPkgNameFilter.Items.BeginUpdate; try DependPkgNameFilter.Items.Clear; DependPkgNameFilter.Items.Assign(fSL); DependPkgNameFilter.InvalidateFilter; finally DependPkgNameFilter.Items.EndUpdate; end; if Assigned(OPMInterface) then begin cbLocalPkg.Caption := Format(lisProjAddLocalPkg, [IntToStr(CntLocalPkg)]); cbOnlinePkg.Caption := Format(lisProjAddOnlinePkg, [IntToStr(CntOnlinePkg)]); BP.CloseButton.Visible := IsInstallButtonVisible; end; finally fUpdating := False; end; end; procedure TAddPkgDependencyDialog.OKButtonClick(Sender: TObject); var NewDependency: TPkgDependency; MinVerTest, MaxVerTest: TPkgVersion; MinMaxVerFlags: TPkgDependencyFlags; i: Integer; begin MinVerTest := Nil; MaxVerTest := Nil; MinMaxVerFlags := []; try // check minimum version if DependMinVersionEdit.Text <> '' then begin MinVerTest := TPkgVersion.Create; if not MinVerTest.ReadString(DependMinVersionEdit.Text) then begin IDEMessageDialog(lisProjAddInvalidVersion, Format(lisProjAddTheMinimumVersionIsInvalid, [DependMinVersionEdit.Text, LineEnding, LineEnding]), mtError,[mbCancel]); exit; end; MinMaxVerFlags := [pdfMinVersion]; end; // check maximum version if DependMaxVersionEdit.Text <> '' then begin MaxVerTest := TPkgVersion.Create; if not MaxVerTest.ReadString(DependMaxVersionEdit.Text) then begin IDEMessageDialog(lisProjAddInvalidVersion, Format(lisProjAddTheMaximumVersionIsInvalid, [DependMaxVersionEdit.Text, LineEnding, LineEnding]), mtError,[mbCancel]); exit; end; MinMaxVerFlags := MinMaxVerFlags + [pdfMaxVersion]; end; // Add all selected packages. fResultDependencies := TPkgDependencyList.Create; // Will be freed by the caller. if DependPkgNameListBox.SelCount > 0 then begin for i := 0 to DependPkgNameListBox.Count-1 do begin if DependPkgNameListBox.Selected[i] then begin NewDependency := TPkgDependency.Create; // Will be added to package graph. NewDependency.PackageName := DependPkgNameListBox.Items[i]; if Assigned(MinVerTest) then NewDependency.MinVersion.Assign(MinVerTest); if Assigned(MaxVerTest) then NewDependency.MaxVersion.Assign(MaxVerTest); NewDependency.Flags := NewDependency.Flags + MinMaxVerFlags; if not CheckAddingDependency(fProjPack, NewDependency) then exit; fResultDependencies.Add(NewDependency); NewDependency := nil; end; end; end; ModalResult := mrOk; finally MinVerTest.Free; MaxVerTest.Free; end; end; end.