2
***************************************************************************
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. *
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. *
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19
***************************************************************************
22
Dialog to clean up a project and its packages and to compile the project.
31
Classes, SysUtils, Math, AVL_Tree, FileProcs, Forms, Controls, Graphics,
32
Dialogs, ButtonPanel, ExtCtrls, StdCtrls, ComCtrls, Masks, LCLIntf,
34
CodeToolManager, DirectoryCacher, CodeToolsStructs,
36
IDEDialogs, IDEImagesIntf,
38
PackageDefs, PackageSystem, InputHistory, LazarusIDEStrConsts, Project,
39
DialogProcs, IDEProcs;
42
TBuildProjectDialogItem = class
48
{ TCleanBuildProjectDialog }
50
TCleanBuildProjectDialog = class(TForm)
51
ButtonPanel1: TButtonPanel;
52
DeleteButton: TButton;
53
PkgOutCheckBox: TCheckBox;
54
PkgOutMaskComboBox: TComboBox;
55
PkgSrcCheckBox: TCheckBox;
56
PkgSrcMaskComboBox: TComboBox;
57
PreviewGroupBox: TGroupBox;
58
FilesTreeView: TTreeView;
59
ProjOutCheckBox: TCheckBox;
60
ProjOutMaskComboBox: TComboBox;
61
ProjSrcCheckBox: TCheckBox;
62
ProjSrcMaskComboBox: TComboBox;
63
procedure ButtonPanel1OKButtonClick(Sender: TObject);
64
procedure DeleteButtonClick(Sender: TObject);
65
procedure FilesTreeViewMouseDown(Sender: TObject; Button: TMouseButton;
66
Shift: TShiftState; X, Y: Integer);
67
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
68
procedure FormCreate(Sender: TObject);
69
procedure FormDestroy(Sender: TObject);
70
procedure FormResize(Sender: TObject);
71
procedure PkgOutCheckBoxChange(Sender: TObject);
72
procedure PkgSrcCheckBoxChange(Sender: TObject);
73
procedure ProjOutCheckBoxChange(Sender: TObject);
74
procedure ProjOutMaskComboBoxChange(Sender: TObject);
75
procedure ProjSrcCheckBoxChange(Sender: TObject);
77
ImageIndexDirectory: Integer;
78
ImageIndexFile: Integer;
79
FIdleConnected: boolean;
80
procedure SetIdleConnected(const AValue: boolean);
81
procedure OnIdle(Sender: TObject; var Done: Boolean);
84
FUpdateNeeded: boolean;
85
procedure ClearFilesTreeView;
86
procedure UpdateFilesTreeView(Immediately: boolean = false);
87
procedure AddProjOutDirectory;
88
procedure AddProjSrcDirectories;
89
procedure AddPkgOutDirectories;
90
procedure AddPkgSrcDirectory;
91
procedure AddDirectory(aTVPath, aDirectory, aFileMask: string);
92
procedure AddDirectories(aTVPath, aSearchPath, aFileMask: string);
93
function GetAllFilesFromTree: TFilenameToStringTree;
94
function DeleteFiles: TModalResult;
95
property IdleConnected: boolean read FIdleConnected write SetIdleConnected;
97
procedure Init(AProject: TProject);
100
function ShowBuildProjectDialog(AProject: TProject): TModalResult;
104
function ShowBuildProjectDialog(AProject: TProject): TModalResult;
106
CleanBuildProjectDialog: TCleanBuildProjectDialog;
108
CleanBuildProjectDialog:=TCleanBuildProjectDialog.Create(nil);
110
CleanBuildProjectDialog.Init(AProject);
111
Result:=CleanBuildProjectDialog.ShowModal;
113
CleanBuildProjectDialog.Free;
119
{ TCleanBuildProjectDialog }
121
procedure TCleanBuildProjectDialog.FormCreate(Sender: TObject);
123
Caption:=lisCleanUpAndBuildProject;
125
ProjOutCheckBox.Caption:=lisProjectOutputDirectory;
126
ProjSrcCheckBox.Caption:=lisProjectSourceDirectories;
127
PkgOutCheckBox.Caption:=lisPackageOutputDirectories;
128
PkgSrcCheckBox.Caption:=lisPackageSourceDirectories;
129
PreviewGroupBox.Caption:=lisTheseFilesWillBeDeleted;
131
ButtonPanel1.OKButton.Caption:=lisCleanUpAndBuild;
132
ButtonPanel1.HelpButton.Caption:=lisMenuHelp;
133
ButtonPanel1.CancelButton.Caption:=lisCancel;
135
DeleteButton.Caption:=lisDelete;
137
FilesTreeView.Images:=IDEImages.Images_16;
138
ImageIndexDirectory := IDEImages.LoadImage(16, 'pkg_files');
139
ImageIndexFile := IDEImages.LoadImage(16, 'laz_delete');
141
ButtonPanel1.OKButton.ModalResult:=mrNone;
144
procedure TCleanBuildProjectDialog.FormDestroy(Sender: TObject);
148
IdleConnected:=false;
151
procedure TCleanBuildProjectDialog.FormClose(Sender: TObject;
152
var CloseAction: TCloseAction);
154
procedure StoreCombo(AComboBox: TComboBox);
156
// store all masks into one history list
157
ProjOutMaskComboBox.AddHistoryItem(AComboBox.Text,30,true,false);
161
FProject.CleanOutputFileMask:=ProjOutMaskComboBox.Text;
162
FProject.CleanSourcesFileMask:=ProjSrcMaskComboBox.Text;
163
InputHistories.CleanOutputFileMask:=PkgOutMaskComboBox.Text;
164
InputHistories.CleanSourcesFileMask:=PkgSrcMaskComboBox.Text;
166
// combine history lists
167
StoreCombo(ProjOutMaskComboBox);
168
StoreCombo(ProjSrcMaskComboBox);
169
StoreCombo(PkgOutMaskComboBox);
170
StoreCombo(PkgSrcMaskComboBox);
171
InputHistories.HistoryLists.GetList(hlCleanBuildFileMask,true,
172
rltFile).Assign(ProjOutMaskComboBox.Items);
175
procedure TCleanBuildProjectDialog.ButtonPanel1OKButtonClick(Sender: TObject);
177
if DeleteFiles<>mrOk then exit;
181
procedure TCleanBuildProjectDialog.DeleteButtonClick(Sender: TObject);
186
procedure TCleanBuildProjectDialog.FilesTreeViewMouseDown(Sender: TObject;
187
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
190
Item: TBuildProjectDialogItem;
193
Node:=FilesTreeView.GetNodeAt(X,Y);
194
if Node=nil then exit;
195
if (Button=mbLeft) and (ssDouble in Shift) and (Node.Data<>nil) then begin
196
Item:=TBuildProjectDialogItem(Node.Data);
197
Filename:=Item.Filename;
198
if Item.IsDirectory then exit;
199
Filename:=ExtractFilePath(Filename);
200
Filename:=ChompPathDelim(Filename);
201
debugln(['TBuildProjectDialog.FilesTreeViewMouseDown Filename="',Filename,'"']);
202
if FilenameIsAbsolute(Filename) then
203
OpenURL('file://'+StringReplace(Filename,'\','/',[rfReplaceAll]));
207
procedure TCleanBuildProjectDialog.FormResize(Sender: TObject);
211
r:=ProjOutCheckBox.Left
212
+Max(Max(ProjOutCheckBox.Width,ProjSrcCheckBox.Width),
213
Max(PkgOutCheckBox.Width,PkgSrcCheckBox.Width));
214
ProjOutMaskComboBox.Left:=r+10;
217
procedure TCleanBuildProjectDialog.PkgOutCheckBoxChange(Sender: TObject);
219
PkgOutMaskComboBox.Enabled:=PkgOutCheckBox.Checked;
223
procedure TCleanBuildProjectDialog.PkgSrcCheckBoxChange(Sender: TObject);
225
PkgSrcMaskComboBox.Enabled:=PkgSrcCheckBox.Checked;
229
procedure TCleanBuildProjectDialog.ProjOutCheckBoxChange(Sender: TObject);
231
ProjOutMaskComboBox.Enabled:=ProjOutCheckBox.Checked;
235
procedure TCleanBuildProjectDialog.ProjOutMaskComboBoxChange(Sender: TObject);
240
procedure TCleanBuildProjectDialog.ProjSrcCheckBoxChange(Sender: TObject);
242
ProjSrcMaskComboBox.Enabled:=ProjSrcCheckBox.Checked;
246
procedure TCleanBuildProjectDialog.SetIdleConnected(const AValue: boolean);
248
if FIdleConnected=AValue then exit;
249
FIdleConnected:=AValue;
250
if IdleConnected then
251
Application.AddOnIdleHandler(@OnIdle)
253
Application.RemoveOnIdleHandler(@OnIdle);
256
procedure TCleanBuildProjectDialog.OnIdle(Sender: TObject; var Done: Boolean);
258
if FProject=nil then exit;
259
if not FUpdateNeeded then exit;
260
IdleConnected:=false;
261
UpdateFilesTreeView(true);
264
procedure TCleanBuildProjectDialog.ClearFilesTreeView;
268
Node:=FilesTreeView.Items.GetFirstNode;
269
while Node<>nil do begin
270
if (Node.Data<>nil) then
271
TObject(Node.Data).Free;
274
FilesTreeView.Items.Clear;
277
procedure TCleanBuildProjectDialog.UpdateFilesTreeView(Immediately: boolean);
279
function CreateTVChildCounts(TVNode: TTreeNode): integer;
281
ChildNode: TTreeNode;
284
if TVNode=nil then exit;
285
ChildNode:=TVNode.GetFirstChild;
286
while ChildNode<>nil do begin
287
inc(Result,CreateTVChildCounts(ChildNode));
288
ChildNode:=ChildNode.GetNextSibling;
290
if (Result=0) and (TVNode.Count>0) then
291
// has children, but no grand children => is a directory
292
inc(Result,TVNode.Count);
294
TVNode.Text:=Format(lisCBPFiles, [TVNode.Text, IntToStr(Result)]);
301
if not Immediately then begin
306
FUpdateNeeded:=false;
308
FilesTreeView.BeginUpdate;
310
if FProject<>nil then begin
311
if ProjOutCheckBox.Checked then AddProjOutDirectory;
312
if ProjSrcCheckBox.Checked then AddProjSrcDirectories;
313
if PkgOutCheckBox.Checked then AddPkgOutDirectories;
314
if PkgSrcCheckBox.Checked then AddPkgSrcDirectory;
316
for i:=0 to FilesTreeView.Items.TopLvlCount-1 do begin
317
TVNode:=FilesTreeView.Items.TopLvlItems[i];
318
CreateTVChildCounts(TVNode);
321
FilesTreeView.EndUpdate;
324
procedure TCleanBuildProjectDialog.AddProjOutDirectory;
326
AddDirectory(lisProjectOutputDirectory,
327
FProject.CompilerOptions.GetUnitOutputDirectory(false),
328
ProjOutMaskComboBox.Text);
331
procedure TCleanBuildProjectDialog.AddProjSrcDirectories;
333
AddDirectories(lisProjectOutputDirectory,
334
FProject.SourceDirectories.CreateSearchPathFromAllFiles,
335
ProjSrcMaskComboBox.Text);
338
procedure TCleanBuildProjectDialog.AddPkgOutDirectories;
346
PackageGraph.GetAllRequiredPackages(FProject.FirstRequiredDependency,List);
347
if List=nil then exit;
348
for i:=0 to List.Count-1 do begin
349
Pkg:=TLazPackage(List[i]);
350
AddDirectory(Pkg.Name,Pkg.CompilerOptions.GetUnitOutputDirectory(false),
351
PkgOutMaskComboBox.Text);
358
procedure TCleanBuildProjectDialog.AddPkgSrcDirectory;
366
PackageGraph.GetAllRequiredPackages(FProject.FirstRequiredDependency,List);
367
if List=nil then exit;
368
for i:=0 to List.Count-1 do begin
369
Pkg:=TLazPackage(List[i]);
370
AddDirectories(Pkg.Name,Pkg.SourceDirectories.CreateSearchPathFromAllFiles,
371
PkgSrcMaskComboBox.Text);
378
procedure TCleanBuildProjectDialog.AddDirectory(aTVPath, aDirectory,
381
Cache: TCTDirectoryCache;
383
TVFiles: TStringList;
388
ParentTVNode: TTreeNode;
390
Item: TBuildProjectDialogItem;
392
//debugln(['TBuildProjectDialog.AddDirectory aTVPath="',aTVPath,'" aDirectory="',aDirectory,'" aFileMask="',aFileMask,'"']);
393
aDirectory:=ChompPathDelim(aDirectory);
394
if (aDirectory='') or (aFileMask='')
395
or (not FilenameIsAbsolute(aDirectory))
396
or (not DirPathExistsCached(aDirectory))
398
// get directory listing from cache
399
Cache:=CodeToolBoss.DirectoryCachePool.GetCache(aDirectory,true,false);
400
if Cache=nil then exit;
401
Files:=TStringList.Create;
402
TVFiles:=TStringList.Create;
403
MaskList:=TMaskList.Create(aFileMask,';');
405
if MaskList.Count=0 then exit;
406
Cache.GetFiles(Files,false);
408
//debugln(['TBuildProjectDialog.AddDirectory AllFiles="',Files.Text,'"']);
410
for i:=0 to Files.Count-1 do
411
if MaskList.Matches(Files[i]) then
412
TVFiles.Add(Files[i]);
413
//debugln(['TBuildProjectDialog.AddDirectory FilteredFiles="',TVFiles.Text,'"']);
414
if TVFiles.Count=0 then exit;
416
// create tree node for aTVPath
418
p:=System.Pos('/',aTVPath);
420
NodeText:=copy(aTVPath,1,p-1);
421
aTVPath:=Copy(aTVPath,p+1,length(aTVPath));
425
if ParentTVNode=nil then
426
TVNode:=FilesTreeView.Items.FindTopLvlNode(NodeText)
428
TVNode:=ParentTVNode.FindNode(NodeText);
430
TVNode:=FilesTreeView.Items.AddChild(ParentTVNode,NodeText);
431
TVNode.ImageIndex:=ImageIndexDirectory;
432
TVNode.SelectedIndex:=ImageIndexDirectory;
433
ParentTVNode:=TVNode;
435
// create tree node for directory
436
NodeText:=FProject.GetShortFilename(aDirectory,true);
437
TVNode:=ParentTVNode.GetFirstChild;
438
while (TVNode<>nil) and (CompareFilenames(TVNode.Text,NodeText)<0) do
439
TVNode:=TVNode.GetNextSibling;
441
TVNode:=FilesTreeView.Items.AddChild(ParentTVNode,NodeText)
442
else if (CompareFilenames(TVNode.Text,NodeText)<>0) then
443
TVNode:=FilesTreeView.Items.Add(TVNode,NodeText);
444
if TVNode.Data=nil then begin
445
Item:=TBuildProjectDialogItem.Create;
446
Item.IsDirectory:=true;
447
Item.Filename:=aDirectory;
450
TVNode.ImageIndex:=ImageIndexDirectory;
451
TVNode.SelectedIndex:=ImageIndexDirectory;
452
ParentTVNode:=TVNode;
455
aDirectory:=AppendPathDelim(aDirectory);
456
for i:=0 to TVFiles.Count-1 do begin
457
Item:=TBuildProjectDialogItem.Create;
458
Item.Filename:=aDirectory+TVFiles[i];
459
TVNode:=FilesTreeView.Items.AddChildObject(ParentTVNode,TVFiles[i],Item);
460
TVNode.ImageIndex:=ImageIndexFile;
461
TVNode.SelectedIndex:=ImageIndexFile;
470
procedure TCleanBuildProjectDialog.AddDirectories(aTVPath, aSearchPath,
477
while p<=length(aSearchPath) do begin
478
Directory:=TrimFilename(GetNextDelimitedItem(aSearchPath,';',p));
479
if FilenameIsAbsolute(Directory) then
480
AddDirectory(aTVPath,Directory,aFileMask);
484
function TCleanBuildProjectDialog.GetAllFilesFromTree: TFilenameToStringTree;
487
Item: TBuildProjectDialogItem;
489
Result:=TFilenameToStringTree.Create(false);
490
Node:=FilesTreeView.Items.GetFirstNode;
491
while Node<>nil do begin
492
if (Node.Data<>nil) and (TObject(Node.Data) is TBuildProjectDialogItem) then
494
Item:=TBuildProjectDialogItem(Node.Data);
495
if not Item.IsDirectory then
496
Result[Item.Filename]:='1';
502
function TCleanBuildProjectDialog.DeleteFiles: TModalResult;
504
Files: TFilenameToStringTree;
506
Item: PStringToStringTreeItem;
509
SourceFiles: TStringList;
512
Files:=GetAllFilesFromTree;
513
MaskList:=TMaskList.Create('*.pas;*.pp;*.p;*.inc;*.lpr;*.lpi;*.lps;*.lpk',';');
514
SourceFiles:=TStringList.Create;
516
// warn before deleting sources
517
Node:=Files.Tree.FindLowest;
518
while Node<>nil do begin
519
Item:=PStringToStringTreeItem(Node.Data);
520
Filename:=Item^.Name;
521
if MaskList.Matches(ExtractFilename(Filename)) then
522
SourceFiles.Add(Filename);
523
Node:=Files.Tree.FindSuccessor(Node);
525
if SourceFiles.Count>0 then begin
526
Result:=IDEMessageDialog(lisCCOWarningCaption,
527
Format(lisCBPReallyDeleteSourceFiles, [IntToStr(SourceFiles.Count), #13
528
+#13, copy(SourceFiles.Text, 1, 1000)]), mtWarning, [mbYes, mbNo]);
529
if Result<>mrYes then exit(mrCancel);
533
Node:=Files.Tree.FindLowest;
535
while Node<>nil do begin
536
Item:=PStringToStringTreeItem(Node.Data);
537
Node:=Files.Tree.FindSuccessor(Node);
538
Filename:=Item^.Name;
539
//debugln(['TBuildProjectDialog.DeleteFiles ',Filename,' ',FileExistsUTF8(Filename)]);
541
if FileExistsUTF8(Filename) and (not DeleteFileUTF8(Filename))
542
and (not Quiet) then begin
543
Result:=IDEQuestionDialog(lisDeleteFileFailed,
544
Format(lisPkgMangUnableToDeleteFile, ['"', Filename, '"']),
546
[mrRetry, mrCancel, mrNo, lisCCOSkip, mrNoToAll, lisSkipErrors]);
547
if Result=mrNoToAll then begin
551
if Result=mrNo then break;
552
if Result<>mrRetry then exit(mrCancel);
559
InvalidateFileStateCache;
567
procedure TCleanBuildProjectDialog.Init(AProject: TProject);
571
List:=InputHistories.HistoryLists.GetList(hlCleanBuildFileMask,true,rltFile);
572
ProjOutMaskComboBox.Items.Assign(List);
573
ProjOutMaskComboBox.Text:=AProject.CleanOutputFileMask;
574
ProjSrcMaskComboBox.Items.Assign(List);
575
ProjSrcMaskComboBox.Text:=AProject.CleanSourcesFileMask;
576
PkgOutMaskComboBox.Items.Assign(List);
577
PkgOutMaskComboBox.Text:=InputHistories.CleanOutputFileMask;
578
PkgSrcMaskComboBox.Items.Assign(List);
579
PkgSrcMaskComboBox.Text:=InputHistories.CleanSourcesFileMask;
581
if AProject.CompilerOptions.UnitOutputDirectory='' then begin
582
ProjOutCheckBox.Enabled:=false;
583
ProjOutCheckBox.Checked:=false;
584
ProjOutMaskComboBox.Enabled:=false;