1 unit AddPkgDependencyDlg;
2 
3 {$mode objfpc}{$H+}
4 
5 interface
6 
7 uses
8   Classes, SysUtils, Types, Laz_AVL_Tree, fgl,
9   // LCL
10   Forms, Controls, Dialogs, StdCtrls, ButtonPanel, LCLProc, LCLType, Graphics,
11   LCLIntf, ExtCtrls,
12   // LazControls
13   ListFilterEdit,
14   // IDEIntf
15   IDEWindowIntf, PackageDependencyIntf, PackageIntf, IDEDialogs, IDEImagesIntf, PackageLinkIntf, MainIntf,
16   // IDE
17   LazarusIDEStrConsts, PackageDefs, PackageSystem, ProjPackCommon, ProjPackChecks;
18 
19 type
20 
21   TPkgDependencyList = specialize TFPGList<TPkgDependency>;
22 
23   { TAddPkgDependencyDialog }
24 
25   TAddPkgDependencyDialog = class(TForm)
26     BP: TButtonPanel;
27     cbLocalPkg: TCheckBox;
28     cbOnlinePkg: TCheckBox;
29     DependMaxVersionEdit: TEdit;
30     DependMaxVersionLabel: TLabel;
31     DependMinVersionEdit: TEdit;
32     DependMinVersionLabel: TLabel;
33     DependPkgNameFilter: TListFilterEdit;
34     DependPkgNameLabel: TLabel;
35     DependPkgTypeLabel: TLabel;
36     DependPkgNameListBox: TListBox;
37     pnLocalPkg: TPanel;
38     pnOnlinePkg: TPanel;
39     procedure cbLocalPkgChange(Sender: TObject);
40     procedure CloseButtonClick(Sender: TObject);
41     procedure DependPkgNameListBoxDrawItem(Control: TWinControl;
42       Index: Integer; ARect: TRect; State: TOwnerDrawState);
43     procedure DependPkgNameListBoxSelectionChange(Sender: TObject; {%H-}User: boolean);
44     procedure FormClose(Sender: TObject; var {%H-}CloseAction: TCloseAction);
45     procedure FormCreate(Sender: TObject);
46     procedure OKButtonClick(Sender: TObject);
FindPackageLinknull47     function FindPackageLink(const ALazPackageID: TLazPackageID): TPackageLink;
InstallOnlinePackagesnull48     function InstallOnlinePackages(out ANeedToRebuild: Boolean): TModalResult;
49   private
50     fUpdating: Boolean;
51     fSL: TStringList;
52     fPackages: TAVLTree;  // tree of  TLazPackage or TPackageLink
53     fProjPack: IProjPack;
54     fResultDependencies: TPkgDependencyList;
55     procedure AddUniquePackagesToList(APackageID: TLazPackageID);
56     procedure UpdateAvailableDependencyNames;
IsInstallButtonVisiblenull57     function IsInstallButtonVisible: Boolean;
58   public
59     constructor Create(TheOwner: TComponent); override;
60     destructor Destroy; override;
61   end;
62 
63 var
64   AddPkgDependencyDialog: TAddPkgDependencyDialog;
65 
ShowAddPkgDependencyDlgnull66 function ShowAddPkgDependencyDlg(AProjPack: IProjPack;
67   out AResultDependencies: TPkgDependencyList): TModalResult;
68 
69 implementation
70 
71 {$R *.lfm}
72 
ShowAddPkgDependencyDlgnull73 function ShowAddPkgDependencyDlg(AProjPack: IProjPack;
74   out AResultDependencies: TPkgDependencyList): TModalResult;
75 var
76   AddDepDialog: TAddPkgDependencyDialog;
77 begin
78   AddDepDialog:=TAddPkgDependencyDialog.Create(nil);
79   AddDepDialog.fProjPack:=AProjPack;
80   AddDepDialog.UpdateAvailableDependencyNames;
81 
82   Result:=AddDepDialog.ShowModal;
83   if Result=mrOk then begin
84     AResultDependencies:=AddDepDialog.fResultDependencies;
85     AddDepDialog.fResultDependencies:=nil;
86   end else begin
87     AResultDependencies:=nil;
88   end;
89   AddDepDialog.Free;
90 end;
91 
92 { TAddPkgDependencyDialog }
93 
94 constructor TAddPkgDependencyDialog.Create(TheOwner: TComponent);
95 begin
96   inherited Create(TheOwner);
97   Caption:=lisProjAddNewRequirement;
98   fPackages:=TAVLTree.Create(@CompareLazPackageIDNames);
99 
100   DependPkgNameLabel.Caption:=lisProjAddPackageName;
101   DependPkgTypeLabel.Caption:=lisProjAddPackageType;
102   cbLocalPkg.Caption:=lisProjAddLocalPkg;
103   cbOnlinePkg.Caption:=lisProjAddOnlinePkg;
104   BP.CloseButton.Caption := lisPckEditInstall;
105   DependMinVersionLabel.Caption:=lisProjAddMinimumVersionOptional;
106   DependMinVersionEdit.Text:='';
107   DependMaxVersionLabel.Caption:=lisProjAddMaximumVersionOptional;
108   DependMaxVersionEdit.Text:='';
109 
110   IDEDialogLayoutList.ApplyLayout(Self,400,360);
111 end;
112 
113 destructor TAddPkgDependencyDialog.Destroy;
114 begin
115   FreeAndNil(fPackages);
116   inherited Destroy;
117 end;
118 
119 procedure TAddPkgDependencyDialog.FormClose(Sender: TObject; var CloseAction: TCloseAction);
120 begin
121   fSL.Free;
122   fSL := nil;
123   IDEDialogLayoutList.SaveLayout(Self);
124 end;
125 
126 procedure TAddPkgDependencyDialog.FormCreate(Sender: TObject);
127 begin
128   fSL := TStringList.Create;
129   DependPkgTypeLabel.Visible := OPMInterface <> nil;
130   pnLocalPkg.Visible := OPMInterface <> nil;
131   pnOnlinePkg.Visible := OPMInterface <> nil;
132   BP.CloseButton.Visible := False;
133   DependPkgNameListBox.ItemHeight := MulDiv(20, Screen.PixelsPerInch, 96);
134 end;
135 
TAddPkgDependencyDialog.FindPackageLinknull136 function TAddPkgDependencyDialog.FindPackageLink(const ALazPackageID:
137   TLazPackageID): TPackageLink;
138 var
139   I: Integer;
140 begin
141   Result := nil;
142   if (fSL = nil) or (fSL.Count = 0) then
143     Exit;
144   for I := 0 to fSL.Count - 1 do
145   begin
146     if TLazPackageID(fSL.Objects[I]) = ALazPackageID then
147     begin
148       Result := TPackageLink(fSL.Objects[I]);
149       Break;
150     end;
151   end;
152 end;
153 
154 procedure TAddPkgDependencyDialog.DependPkgNameListBoxDrawItem(
155   Control: TWinControl; Index: Integer; ARect: TRect; State: TOwnerDrawState);
156 var
157   ItemText: string;
158   PackageLink: TPackageLink;
159 begin
160   with (Control as TListBox).Canvas do
161   begin
162     if odSelected In State then
163     begin
164       Pen.Color := clHighlightText;
165       Brush.Color := clHighlight;
166     end
167     else
168     begin
169       Pen.Color := (Control as TListBox).Font.Color;
170       Brush.Color := (Control as TListBox).Color;
171       if Assigned(OPMInterface) then
172       begin
173         PackageLink := FindPackageLink(TLazPackageID(DependPkgNameListBox.Items.Objects[Index]));
174         if PackageLink <> nil then
175         begin
176           if PackageLink.Origin = ploOnline then
177             Brush.Color := pnOnlinePkg.Color
178           else
179             Brush.Color := pnLocalPkg.Color
180         end;
181       end
182     end;
183     FillRect(ARect);
184     ItemText := (Control as TListBox).Items[Index];
185     InflateRect(ARect, -1, -1);
186     inc(ARect.Left,3);
187     DrawText(Handle, PChar(ItemText), Length(ItemText), ARect, DT_LEFT or DT_VCENTER or DT_SINGLELINE);
188   end;
189 end;
190 
TAddPkgDependencyDialog.IsInstallButtonVisiblenull191 function TAddPkgDependencyDialog.IsInstallButtonVisible: Boolean;
192 var
193   I: Integer;
194   PackageLink: TPackageLink;
195 begin
196   Result := False;
197   if (OPMInterface = nil) or (fSL = nil) or (fSL.Count = 0) then
198     Exit;
199   for I := 0 to DependPkgNameListBox.Count - 1 do
200   begin
201     if DependPkgNameListBox.Selected[I] then
202     begin
203       PackageLink := FindPackageLink(TLazPackageID(DependPkgNameListBox.Items.Objects[I]));
204       if (PackageLink <> nil) and (PackageLink.Origin = ploOnline) then
205       begin
206         Result := True;
207         Break;
208       end;
209     end;
210   end;
211 end;
212 
213 procedure TAddPkgDependencyDialog.DependPkgNameListBoxSelectionChange(
214   Sender: TObject; User: boolean);
215 begin
216   BP.CloseButton.Visible := IsInstallButtonVisible;
217   if BP.CloseButton.Visible then
218     BP.OKButton.Enabled := False
219   else
220     BP.OKButton.Enabled := True;
221 end;
222 
223 procedure TAddPkgDependencyDialog.cbLocalPkgChange(Sender: TObject);
224 begin
225   UpdateAvailableDependencyNames;
226 end;
227 
InstallOnlinePackagesnull228 function TAddPkgDependencyDialog.InstallOnlinePackages(out ANeedToRebuild: Boolean): TModalResult;
229 var
230   I: Integer;
231   PackageLink: TPackageLink;
232   PkgList: TList;
233 begin
234   ANeedToRebuild := False;
235   Result := mrOk;
236   PkgList := TList.Create;
237   try
238     for I := 0 to DependPkgNameListBox.Count - 1 do
239     begin
240       if DependPkgNameListBox.Selected[I] then
241       begin
242         PackageLink := FindPackageLink(TLazPackageID(DependPkgNameListBox.Items.Objects[I]));
243         if (PackageLink <> nil) and (PackageLink.Origin = ploOnline) then
244           PkgList.Add(PackageLink);
245       end;
246     end;
247     if PkgList.Count > 0 then
248       Result := OPMInterface.InstallPackages(PkgList, ANeedToRebuild);
249   finally
250     PkgList.Free;
251     PkgList := nil;
252   end;
253 end;
254 
255 procedure TAddPkgDependencyDialog.CloseButtonClick(Sender: TObject);
256 var
257   NeedToRebuild: Boolean;
258 begin
259   ModalResult := mrNone;
260   if InstallOnlinePackages(NeedToRebuild) = mrOK then
261   begin
262     UpdateAvailableDependencyNames;
263     if NeedToRebuild then
264     begin
265       Self.Hide;
266       MainIDEInterface.DoBuildLazarus([]);
267     end;
268   end;
269 end;
270 
271 procedure TAddPkgDependencyDialog.AddUniquePackagesToList(APackageID: TLazPackageID);
272 begin
273   if (APackageID.IDAsString<>fProjPack.IDAsString) and (fPackages.Find(APackageID)=Nil) then
274     fPackages.Add(APackageID);
275 end;
276 
277 procedure TAddPkgDependencyDialog.UpdateAvailableDependencyNames;
278 var
279   ANode: TAVLTreeNode;
280   CntLocalPkg: Integer;
281   CntOnlinePkg: Integer;
282 begin
283   if fUpdating then
284     Exit;
285 
286   fUpdating := True;
287   try
288     CntLocalPkg := 0;
289     CntOnlinePkg := 0;
290     DependPkgNameListBox.Clear;
291     fSL.Clear;
292     fPackages.Clear;
293     PackageGraph.IteratePackages(fpfSearchAllExisting,@AddUniquePackagesToList);
294     ANode:=fPackages.FindLowest;
295     while ANode<>nil do begin
296       if (TPackageLink(ANode.Data).Origin = ploOnline) and (cbOnlinePkg.Checked) and Assigned(OPMInterface) then
297       begin
298         Inc(CntOnlinePkg);
299         fSL.AddObject(TLazPackageID(ANode.Data).Name, TLazPackageID(ANode.Data));
300       end;
301       if (TPackageLink(ANode.Data).Origin <> ploOnline) and (cbLocalPkg.Checked) then
302       begin
303         Inc(CntLocalPkg);
304         fSL.AddObject(TLazPackageID(ANode.Data).Name, TLazPackageID(ANode.Data));
305       end;
306       ANode:=fPackages.FindSuccessor(ANode);
307     end;
308     DependPkgNameFilter.Items.BeginUpdate;
309     try
310       DependPkgNameFilter.Items.Clear;
311       DependPkgNameFilter.Items.Assign(fSL);
312       DependPkgNameFilter.InvalidateFilter;
313     finally
314       DependPkgNameFilter.Items.EndUpdate;
315     end;
316     if Assigned(OPMInterface) then
317     begin
318       cbLocalPkg.Caption := Format(lisProjAddLocalPkg, [IntToStr(CntLocalPkg)]);
319       cbOnlinePkg.Caption := Format(lisProjAddOnlinePkg, [IntToStr(CntOnlinePkg)]);
320       BP.CloseButton.Visible := IsInstallButtonVisible;
321     end;
322   finally
323     fUpdating := False;
324   end;
325 end;
326 
327 procedure TAddPkgDependencyDialog.OKButtonClick(Sender: TObject);
328 var
329   NewDependency: TPkgDependency;
330   MinVerTest, MaxVerTest: TPkgVersion;
331   MinMaxVerFlags: TPkgDependencyFlags;
332   i: Integer;
333 begin
334   MinVerTest := Nil;
335   MaxVerTest := Nil;
336   MinMaxVerFlags := [];
337   try
338     // check minimum version
339     if DependMinVersionEdit.Text <> '' then
340     begin
341       MinVerTest := TPkgVersion.Create;
342       if not MinVerTest.ReadString(DependMinVersionEdit.Text) then
343       begin
344         IDEMessageDialog(lisProjAddInvalidVersion,
345           Format(lisProjAddTheMinimumVersionIsInvalid,
346                  [DependMinVersionEdit.Text, LineEnding, LineEnding]),
347           mtError,[mbCancel]);
348         exit;
349       end;
350       MinMaxVerFlags := [pdfMinVersion];
351     end;
352     // check maximum version
353     if DependMaxVersionEdit.Text <> '' then
354     begin
355       MaxVerTest := TPkgVersion.Create;
356       if not MaxVerTest.ReadString(DependMaxVersionEdit.Text) then
357       begin
358         IDEMessageDialog(lisProjAddInvalidVersion,
359           Format(lisProjAddTheMaximumVersionIsInvalid,
360                  [DependMaxVersionEdit.Text, LineEnding, LineEnding]),
361           mtError,[mbCancel]);
362         exit;
363       end;
364       MinMaxVerFlags := MinMaxVerFlags + [pdfMaxVersion];
365     end;
366 
367     // Add all selected packages.
368     fResultDependencies := TPkgDependencyList.Create; // Will be freed by the caller.
369     if DependPkgNameListBox.SelCount > 0 then
370     begin
371       for i := 0 to DependPkgNameListBox.Count-1 do
372       begin
373         if DependPkgNameListBox.Selected[i] then
374         begin
375           NewDependency := TPkgDependency.Create;   // Will be added to package graph.
376           NewDependency.PackageName := DependPkgNameListBox.Items[i];
377           if Assigned(MinVerTest) then
378             NewDependency.MinVersion.Assign(MinVerTest);
379           if Assigned(MaxVerTest) then
380             NewDependency.MaxVersion.Assign(MaxVerTest);
381           NewDependency.Flags := NewDependency.Flags + MinMaxVerFlags;
382           if not CheckAddingDependency(fProjPack, NewDependency) then exit;
383           fResultDependencies.Add(NewDependency);
384           NewDependency := nil;
385         end;
386       end;
387     end;
388     ModalResult := mrOk;
389   finally
390     MinVerTest.Free;
391     MaxVerTest.Free;
392   end;
393 end;
394 
395 end.
396 
397