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: Juha Manninen
22 
23   Abstract:
24     - TPublishModuleDialog
25     The dialog for TPublishModuleOptions to publish projects and packages.
26 
27 }
28 unit PublishModuleDlg;
29 
30 {$mode objfpc}{$H+}
31 
32 interface
33 
34 uses
35   Classes, SysUtils, StrUtils, Zipper,
36   // LCL
37   LCLType, Forms, StdCtrls, Dialogs, Buttons, ButtonPanel, LCLIntf,
38   // LazUtils
39   FileUtil, LazFileUtils, LazStringUtils, LazLoggerBase, UITypes, LazUTF8,
40   // BuildIntf
41   ProjPackIntf, CompOptsIntf, PublishModuleIntf,
42   // IdeIntf
43   IDEWindowIntf, IDEHelpIntf, IDEDialogs, IDEImagesIntf, LazIDEIntf,
44   // IDE
45   ProjectDefs, Project, PackageDefs, IDEOptionDefs, InputHistory,
46   LazarusIDEStrConsts, IDEProcs, EnvironmentOpts, CompilerOptions;
47 
48 type
49   { TPublishModuleDialog }
50 
51   TPublishModuleDialog = class(TForm)
52     ButtonPanel1: TButtonPanel;
53     OpenInFileManCheckbox: TCheckBox;
54     DestDirGroupBox: TGroupBox;
55     DestDirComboBox: TComboBox;
56     BrowseDestDirBitBtn: TBitBtn;
57     FilterCombobox: TComboBox;
58     FilterSimpleSyntaxCheckbox: TCheckBox;
59     NoteLabel: TLabel;
60     OptionsGroupbox: TGroupBox;
61     CompressCheckbox: TCheckBox;
62     UseFiltersCheckbox: TCheckBox;
63     procedure BrowseDestDirBitBtnCLICK(Sender: TObject);
64     procedure FormClose(Sender: TObject; var {%H-}CloseAction: TCloseAction);
65     procedure FormCreate(Sender: TObject);
66     procedure HelpButtonClick(Sender: TObject);
67     procedure OkButtonCLICK(Sender: TObject);
68     procedure SaveSettingsButtonClick(Sender: TObject);
69     procedure UseFiltersCheckboxClick(Sender: TObject);
70   private
71     FOptions: TPublishModuleOptions;
72     procedure SetComboBox(AComboBox: TComboBox; const NewText: string;
73                           MaxItemCount: integer);
74     procedure LoadHistoryLists;
75     procedure SaveHistoryLists;
76     procedure SetOptions(const AValue: TPublishModuleOptions);
CheckFilternull77     function CheckFilter: boolean;
78   public
79     constructor Create(TheOwner: TComponent); override;
80     destructor Destroy; override;
81     procedure LoadFromOptions(SrcOpts: TPublishModuleOptions);
82     procedure SaveToOptions(DestOpts: TPublishModuleOptions);
83     property Options: TPublishModuleOptions read FOptions write SetOptions;
84   end;
85 
86   { TPublisher }
87 
88   TPublisher = class(TFileSearcher)
89   private
90     FOptions: TPublishModuleOptions;
91     FProjPack: TIDEProjPackBase;
92     FSrcDir, FDestDir: string;
93     // TopDir contains all project/package directories.
94     //  Some of them may be above the main project/package directory.
95     FTopDir: string;
96     // Project/package member files already copied. Not copied again by filters.
97     FCopiedFiles: TStringListUTF8Fast;
98     // Copying by filters failed.
99     FCopyFailedCount: Integer;
100     FProjDirs: TStringListUTF8Fast;
101     FBackupDir, FLibDir: String;
102     procedure AdjustTopDir(const AFileName: string);
CopyAFilenull103     function CopyAFile(const AFileName: string): TModalResult;
CopyProjectFilesnull104     function CopyProjectFiles: TModalResult;
CopyPackageFilesnull105     function CopyPackageFiles: TModalResult;
WriteProjectInfonull106     function WriteProjectInfo: TModalResult;
WritePackageInfonull107     function WritePackageInfo: TModalResult;
IsDrivenull108     function IsDrive(const AName: String): Boolean;
Compressnull109     function Compress: TModalResult;
110   protected
111     procedure DoFileFound; override;    // Called by TFileSearcher.Search.
112     procedure DoDirectoryFound; override;
113   public
114     constructor Create(AOptions: TPublishModuleOptions);
115     destructor Destroy; override;
Runnull116     function Run: TModalResult;
117   end;
118 
119 
ShowPublishDialognull120 function ShowPublishDialog(AOptions: TPublishModuleOptions): TModalResult;
PublishAModulenull121 function PublishAModule(AOptions: TPublishModuleOptions): TModalResult;
122 
123 
124 implementation
125 
126 {$R *.lfm}
127 
ShowPublishDialognull128 function ShowPublishDialog(AOptions: TPublishModuleOptions): TModalResult;
129 begin
130   with TPublishModuleDialog.Create(nil) do
131   try
132     Options:=AOptions;
133     Result:=ShowModal;
134   finally
135     Free;
136   end;
137 end;
138 
PublishAModulenull139 function PublishAModule(AOptions: TPublishModuleOptions): TModalResult;
140 begin
141   with TPublisher.Create(AOptions) do
142   try
143     Result := Run;
144   finally
145     Free;
146   end;
147 end;
148 
149 { TPublisher }
150 
151 constructor TPublisher.Create(AOptions: TPublishModuleOptions);
152 var
153   COpts: TBaseCompilerOptions;
154 begin
155   inherited Create;
156   FOptions := AOptions;
157   FProjPack := FOptions.Owner as TIDEProjPackBase;
158   FTopDir := FProjPack.Directory;     // Initial value for TopDir. It may change.
159   FSrcDir := FTopDir;
160   FDestDir := TrimAndExpandDirectory(RealPublishDir(FOptions));
161   FBackupDir := AppendPathDelim(FSrcDir
162                        + EnvironmentOptions.BackupInfoProjectFiles.SubDirectory);
163   COpts := FProjPack.LazCompilerOptions as TBaseCompilerOptions;
164   FLibDir := COpts.GetUnitOutPath(True,coptParsed);
165   FCopiedFiles := TStringListUTF8Fast.Create;
166   FProjDirs := TStringListUTF8Fast.Create;
167 end;
168 
169 destructor TPublisher.Destroy;
170 begin
171   FCopiedFiles.Free;
172   FProjDirs.Free;
173   inherited Destroy;
174 end;
175 
176 // The next 2 methods will be called from TFileSearcher.Search.
177 
178 procedure TPublisher.DoFileFound;
179 // Copy a found file if it passes the filter.
180 var
181   CurDir: string;
182 begin
183   if FCopiedFiles.IndexOf(FileName) >= 0 then
184     Exit;
185   CurDir := ExtractFilePath(FileName);
186   if (CurDir = FBackupDir) or (CurDir = FLibDir) then
187     Exit;
188   if AnsiStartsStr(FDestDir, CurDir) then
189     Exit;
190   if FOptions.FileCanBePublished(FileName) then
191     if CopyAFile(FileName) <> mrOK then
192       Inc(FCopyFailedCount);
193 end;
194 
195 procedure TPublisher.DoDirectoryFound;
196 begin
197   // Directory is already created by the cffCreateDestDirectory flag.
198 end;
199 
200 // Methods below are for copying project/package members.
201 
202 procedure TPublisher.AdjustTopDir(const AFileName: string);
203 // Adjust the actual top directory. It will differ from the
204 //  main dir when project/package has files up in directory structure.
205 var
206   RelPath, UpALevel: string;
207   Adjusted: Boolean;
208 begin
209   UpALevel := '..' + DirectorySeparator;
210   RelPath := ExtractRelativePath(FTopDir, AFilename);
211   Adjusted := False;
212   while LazStartsStr(UpALevel, RelPath) do
213   begin
214     FTopDir := FTopDir + UpALevel; // This file is in upper dir. Move TopDir up, too.
215     Delete(RelPath, 1, 3);
216     Adjusted := True;
217   end;
218   if Adjusted then
219     FTopDir := ResolveDots(FTopDir);
220 end;
221 
TPublisher.CopyAFilenull222 function TPublisher.CopyAFile(const AFileName: string): TModalResult;
223 var
224   RelPath, LfmFile: string;
225   Drive: String;
226 begin
227   Result := mrOK;
228   if FCopiedFiles.IndexOf(AFilename) >= 0 then exit;     // Already copied.
229   RelPath := ExtractRelativePath(FTopDir, AFilename);
230   Drive := ExtractFileDrive(RelPath);
231   if Trim(Drive) <> '' then
232     RelPath := StringReplace(RelPath, AppendPathDelim(Drive), '', [rfIgnoreCase]);
233   if CopyFile(AFilename, FDestDir+RelPath, [cffCreateDestDirectory,cffPreserveTime]) then
234   begin
235     FCopiedFiles.Add(AFilename);
236     if FilenameHasPascalExt(AFilename) then
237     begin    // Copy .lfm or .dfm file even if it is not part of project/package.
238       LfmFile := ChangeFileExt(AFilename, '.lfm');
239       if not FileExistsUTF8(LfmFile) then
240       begin
241         LfmFile := ChangeFileExt(AFilename, '.dfm');
242         if not FileExistsUTF8(LfmFile) then
243           LfmFile := '';
244       end;
245       if LfmFile <> '' then
246         Result := CopyAFile(LfmFile);  // Recursive call.
247     end;
248   end
249   else
250     Result := mrCancel;
251 end;
252 
TPublisher.CopyProjectFilesnull253 function TPublisher.CopyProjectFiles: TModalResult;
254 var
255   CurProject: TProject;
256   CurUnitInfo: TUnitInfo;
257   i: Integer;
258   RelatedFile: String;
259   CurDir: String;
260 begin
261   Result := mrOK;
262   CurProject := TProject(FProjPack);
263   FProjDirs.Clear;
264   FProjDirs.Sorted := True;
265   FProjDirs.Duplicates := dupIgnore;
266   // First adjust the TopDir based on relative file paths.
267   for i:=0 to CurProject.UnitCount-1 do
268   begin
269     CurUnitInfo := CurProject.Units[i];
270     if CurUnitInfo.IsPartOfProject then
271     begin
272       AdjustTopDir(CurUnitInfo.Filename);
273       CurDir := ExtractFilePath(CurUnitInfo.Filename);
274       FProjDirs.Add(CurDir);
275     end;
276   end;
277   // Then copy the project files
278   for i:=0 to CurProject.UnitCount-1 do
279   begin
280     CurUnitInfo := CurProject.Units[i];
281     if CurUnitInfo.IsPartOfProject then
282     begin
283       Result := CopyAFile(CurUnitInfo.Filename);
284       if Result<> mrOk then Exit;
285       if CurUnitInfo.IsMainUnit then
286       begin                // Copy the main resource file in any case.
287         RelatedFile := ChangeFileExt(CurUnitInfo.Filename, '.res');
288         if FileExistsUTF8(RelatedFile) then
289           Result := CopyAFile(RelatedFile);
290         RelatedFile := ChangeFileExt(CurUnitInfo.Filename, '.ico');
291         if FileExistsUTF8(RelatedFile) then
292           Result := CopyAFile(RelatedFile);
293       end;
294     end;
295   end;
296 end;
297 
TPublisher.CopyPackageFilesnull298 function TPublisher.CopyPackageFiles: TModalResult;
299 var
300   CurPackage: TLazPackage;
301   PkgFile: TPkgFile;
302   i: Integer;
303 begin
304   // Copy Package
305   Result := mrOK;
306   CurPackage := TLazPackage(FProjPack);
307   // First adjust the TopDir based on relative file paths.
308   for i:=0 to CurPackage.FileCount-1 do
309   begin
310     PkgFile := CurPackage.Files[i];
311     AdjustTopDir(PkgFile.Filename);
312   end;
313   // Then copy the package files
314   for i:=0 to CurPackage.FileCount-1 do
315   begin
316     PkgFile := CurPackage.Files[i];
317     CopyAFile(PkgFile.Filename);
318   end;
319 end;
320 
TPublisher.WriteProjectInfonull321 function TPublisher.WriteProjectInfo: TModalResult;
322 var
323   CurProject: TProject;
324   NewProjFilename: string;
325 begin
326   CurProject := TProject(FOptions.Owner);
327   NewProjFilename := FDestDir + ExtractRelativePath(FTopDir, CurProject.ProjectInfoFile);
328   DeleteFileUTF8(NewProjFilename);
329   Assert(CurProject.PublishOptions = FOptions, 'CurProject.PublishOptions <> FOptions');
330   FCopiedFiles.Add(CurProject.ProjectInfoFile); // Do not later by filter.
331   Result := CurProject.WriteProject(
332       CurProject.PublishOptions.WriteFlags+pwfSkipSessionInfo+[pwfIgnoreModified],
333       NewProjFilename,nil);
334   if Result<>mrOk then
335     DebugLn('Hint: [TPublisher] CurProject.WriteProject failed');
336 end;
337 
WritePackageInfonull338 function TPublisher.WritePackageInfo: TModalResult;
339 begin
340   Result := mrOK;
341   // ToDo
342 end;
343 
IsDrivenull344 function TPublisher.IsDrive(const AName: String): Boolean;
345 var
346   Drive: String;
347 begin
348   Drive := ExtractFileDrive(AName);
349   Result := (Trim(Drive) <> '') and (AppendPathDelim(Drive) = AName);
350 end;
351 
Compressnull352 function TPublisher.Compress: TModalResult;
353 var
354   Zipper: TZipper;
355   ZipFileEntries: TZipFileEntries;
356   CurProject: TProject;
357   I: Integer;
358   ZipDestDir: String;
359   RelPath, Drive: String;
360 begin
361   Result := mrNone;
362   CurProject := TProject(FOptions.Owner);
363   if CurProject = nil then
364     Exit;
365 
366   ZipFileEntries := TZipFileEntries.Create(TZipFileEntry);
367   try
368     if DirPathExists(FDestDir) then
369     begin
370       for I := 0 to FCopiedFiles.Count - 1 do
371       begin
372         RelPath := ExtractRelativePath(FTopDir, FCopiedFiles[I]);
373         Drive := ExtractFileDrive(RelPath);
374         if Trim(Drive) <> '' then
375           RelPath := StringReplace(RelPath, AppendPathDelim(Drive), '', [rfIgnoreCase]);
376         ZipFileEntries.AddFileEntry(FDestDir + RelPath, RelPath);
377       end;
378 
379       if (ZipFileEntries.Count > 0) then
380       begin
381         Zipper := TZipper.Create;
382         try
383           ZipDestDir := AppendPathDelim(LazarusIDE.GetPrimaryConfigPath);
384           Zipper.FileName := ChangeFileExt(ZipDestDir + ExtractFileName(CurProject.ProjectInfoFile), '.zip');
385           try
386             Zipper.ZipFiles(ZipFileEntries);
387             if FileExists(Zipper.FileName) then
388             begin
389               DeleteDirectory(FDestDir, True);
390               if CopyFile(Zipper.FileName, AppendPathDelim(FDestDir) + ExtractFileName(Zipper.FileName), [cffCreateDestDirectory,cffPreserveTime]) then
391               begin
392                 DeleteFile(Zipper.FileName);
393                 Result := mrOK;
394               end;
395             end;
396             except
397               on E: EZipError do
398                 IDEMessageDialog(lisError, E.Message, mtInformation, [mbOk]);
399             end;
400         finally
401           Zipper.Free;
402         end;
403       end;
404     end;
405   finally
406     ZipFileEntries.Free;
407   end;
408 end;
409 
TPublisher.Runnull410 function TPublisher.Run: TModalResult;
411 var
412   I: Integer;
413 begin
414   Result:=mrCancel;
415 
416   if FDestDir='' then begin
417     IDEMessageDialog(lisInvalidPublishingDirectory,
418       lisEmptyDestinationForPublishing, mtError, [mbCancel]);
419     exit;
420   end;
421   // Don't try to copy to a subdirectory of FSrcDir.
422   if (CompareFilenames(FSrcDir,FDestDir)=0) then
423   begin
424     IDEMessageDialog(lisInvalidPublishingDirectory,
425       Format(lisSourceAndDestinationAreSame,
426              [FSrcDir, LineEnding, FDestDir, LineEnding]),
427       mtError, [mbCancel]);
428     exit;
429   end;
430 
431   // clear destination directory
432   if DirPathExists(FDestDir) then
433   begin
434     // ask user, if destination can be deleted
435     if IDEMessageDialog(lisClearDirectory,
436       Format(lisInOrderToCreateACleanCopyOfTheProjectPackageAllFil,
437              [LineEnding+LineEnding, FDestDir]),
438       mtConfirmation, [mbYes,mbNo])<>mrYes
439     then
440       exit;
441 
442     if (not DeleteDirectory(ChompPathDelim(FDestDir),true)) then
443     begin
444       IDEMessageDialog(lisUnableToCleanUpDestinationDirectory,
445         Format(lisUnableToCleanUpPleaseCheckPermissions, [FDestDir, LineEnding]),
446         mtError,[mbOk]);
447       exit;
448     end;
449   end;
450 
451   // Write a project/package files and then info file
452   if FOptions is TPublishProjectOptions then
453   begin
454     Result := CopyProjectFiles;
455     if Result <> mrOk then
456     begin
457       IDEMessageDialog(lisError, lisCopyFilesFailed, mtInformation,[mbOk]);
458       exit;
459     end;
460     Result := WriteProjectInfo;
461     if Result <> mrOk then
462     begin
463       IDEMessageDialog(lisError, lisWriteProjectInfoFailed, mtInformation,[mbOk]);
464       exit;
465     end;
466   end
467   else begin
468     Result := CopyPackageFiles;
469     if Result <> mrOk then
470     begin
471       IDEMessageDialog(lisError, lisCopyFilesFailed, mtInformation,[mbOk]);
472       exit;
473     end;
474     Result := WritePackageInfo;
475     if Result <> mrOk then
476     begin
477       IDEMessageDialog(lisError, lisWritePackageInfoFailed, mtInformation,[mbOk]);
478       exit;
479     end;
480 
481   end;
482   if Result<>mrOk then exit;
483 
484   // Copy extra files in project/package directory
485   if FOptions.UseFileFilters then
486   begin
487     FCopyFailedCount:=0;
488     for I := 0 to FProjDirs.Count - 1 do
489     begin
490       if IsDrive(FProjDirs.Strings[I]) then
491         Search(FProjDirs.Strings[I], '', False)
492       else
493         Search(FProjDirs.Strings[I]);
494     end;
495     if FCopyFailedCount <> 0 then
496     begin
497       IDEMessageDialog(lisError, lisCopyFilesFailed, mtInformation,[mbOk]);
498       DebugLn('Hint: [TPublisher] Copying files failed');
499       exit(mrCancel);
500     end;
501   end;
502 
503   // Compress the resulting project/package
504   if FOptions.CompressFinally then
505     Result := Compress;
506 
507   if Result = mrOK then
508   begin
509     IDEMessageDialog(lisSuccess, Format(lisPublishedTo, [FDestDir]),
510       mtInformation, [mbOk]);
511     if FOptions.OpenInFileMan then
512       OpenDocument(FDestDir);
513   end;
514 end;
515 
516 { TPublishModuleDialog }
517 
518 constructor TPublishModuleDialog.Create(TheOwner: TComponent);
519 begin
520   inherited Create(TheOwner);
521   Position:=poScreenCenter;
522   IDEDialogLayoutList.ApplyLayout(Self, 600, 350);
523   LoadHistoryLists;
524 end;
525 
526 destructor TPublishModuleDialog.Destroy;
527 begin
528   SaveHistoryLists;
529   inherited Destroy;
530 end;
531 
532 procedure TPublishModuleDialog.FormClose(Sender: TObject; var CloseAction: TCloseAction);
533 begin
534   IDEDialogLayoutList.SaveLayout(Self);
535 end;
536 
537 procedure TPublishModuleDialog.FormCreate(Sender: TObject);
538 begin
539   DestDirGroupBox.Caption:=lisDestinationDirectory;
540   NoteLabel.Caption:=lisPublishModuleNote;
541   UseFiltersCheckbox.Caption:=lisUseFilterForExtraFiles;
542   FilterSimpleSyntaxCheckbox.Caption:=lisSimpleSyntax;
543   FilterSimpleSyntaxCheckbox.Hint:=lisNormallyTheFilterIsARegularExpressionInSimpleSynta;
544 
545   OptionsGroupbox.Caption:=lisOptions;
546   CompressCheckbox.Caption:=lisCompress;
547   CompressCheckbox.Hint:=lisCompressHint;
548   OpenInFileManCheckbox.Caption:=lisOpenInFileMan;
549   OpenInFileManCheckbox.Hint:=lisOpenInFileManHint;
550 
551   ButtonPanel1.OkButton.Caption:=lisMenuOk;
552   ButtonPanel1.OKButton.OnClick:=@OkButtonCLICK;
553   ButtonPanel1.CloseButton.Caption:=lisSaveSettings;
554   ButtonPanel1.CloseButton.ModalResult:=mrNone;
555   ButtonPanel1.CloseButton.Kind:=bkCustom;
556   ButtonPanel1.CloseButton.LoadGlyphFromStock(idButtonSave);
557   if ButtonPanel1.CloseButton.Glyph.Empty then
558     IDEImages.AssignImage(ButtonPanel1.CloseButton, 'laz_save');
559   ButtonPanel1.CloseButton.OnClick:=@SaveSettingsButtonCLICK;
560   ButtonPanel1.HelpButton.OnClick:=@HelpButtonClick;
561   DestDirComboBox.DropDownCount:=EnvironmentOptions.DropDownCount;
562   FilterCombobox.DropDownCount:=EnvironmentOptions.DropDownCount;
563 end;
564 
565 procedure TPublishModuleDialog.BrowseDestDirBitBtnCLICK(Sender: TObject);
566 var
567   SelectDirDialog: TSelectDirectoryDialog;
568   NewDir: String;
569 begin
570   SelectDirDialog:=TSelectDirectoryDialog.Create(Self);
571   InputHistories.ApplyFileDialogSettings(SelectDirDialog);
572   SelectDirDialog.Title:=lisChooseDirectory;
573   if SelectDirDialog.Execute then begin
574     NewDir:=ExpandFileNameUTF8(SelectDirDialog.Filename);
575     SetComboBox(DestDirComboBox,NewDir,20);
576   end;
577   SelectDirDialog.Free;
578 end;
579 
580 procedure TPublishModuleDialog.HelpButtonClick(Sender: TObject);
581 begin
582   LazarusHelp.ShowHelpForIDEControl(Self);
583 end;
584 
585 procedure TPublishModuleDialog.OkButtonCLICK(Sender: TObject);
586 begin
587   if not CheckFilter then exit;
588   if Options<>nil then
589     SaveToOptions(Options);
590 end;
591 
592 procedure TPublishModuleDialog.SaveSettingsButtonClick(Sender: TObject);
593 begin
594   if not CheckFilter then exit;
595   if Options<>nil then
596     SaveToOptions(Options);
597 end;
598 
599 procedure TPublishModuleDialog.UseFiltersCheckboxClick(Sender: TObject);
600 begin
601   FilterCombobox.Enabled := (Sender as TCheckBox).Checked;
602   FilterSimpleSyntaxCheckbox.Enabled := FilterCombobox.Enabled;
603 end;
604 
605 procedure TPublishModuleDialog.SetComboBox(AComboBox: TComboBox;
606   const NewText: string; MaxItemCount: integer);
607 begin
608   AComboBox.AddHistoryItem(NewText,MaxItemCount,true,false);
609 end;
610 
611 procedure TPublishModuleDialog.LoadHistoryLists;
612 var
613   hl: THistoryList;
614 begin
615   // destination directories
616   hl:=InputHistories.HistoryLists.GetList(hlPublishModuleDestDirs,true,rltFile);
617   hl.AppendEntry(GetForcedPathDelims('$(TestDir)/publishedproject/'));
618   hl.AppendEntry(GetForcedPathDelims('$(TestDir)/publishedpackage/'));
619   hl.AppendEntry(GetForcedPathDelims('$(ProjPath)/published/'));
620   DestDirComboBox.Items.Assign(hl);
621 
622   // file filter
623   hl:=InputHistories.HistoryLists.GetList(hlPublishModuleFileFilter,true,rltFile);
624   if hl.Count=0 then
625     hl.Add(DefPublModIncFilter);
626   FilterCombobox.Items.Assign(hl);
627 end;
628 
629 procedure TPublishModuleDialog.SaveHistoryLists;
630 var
631   hl: THistoryList;
632 begin
633   // destination directories
634   SetComboBox(DestDirComboBox,DestDirComboBox.Text,20);
635   hl:=InputHistories.HistoryLists.GetList(hlPublishModuleDestDirs,true,rltFile);
636   hl.Assign(DestDirComboBox.Items);
637 
638   // file filters
639   SetComboBox(FilterCombobox,FilterCombobox.Text,20);
640   hl:=InputHistories.HistoryLists.GetList(hlPublishModuleFileFilter,true,rltFile);
641   hl.Assign(FilterCombobox.Items);
642 end;
643 
644 procedure TPublishModuleDialog.SetOptions(const AValue: TPublishModuleOptions);
645 begin
646   if FOptions=AValue then exit;
647   FOptions:=AValue;
648   if FOptions is TPublishPackageOptions then
649     Caption:=lisPkgEditPublishPackage
650   else
651     Caption:=lisPublishProject;
652   LoadFromOptions(FOptions);
653 end;
654 
CheckFilternull655 function TPublishModuleDialog.CheckFilter: boolean;
656 begin
657   Result:=false;
658   if Options<>nil then begin
659     if not Options.FilterValid then begin
660       if IDEMessageDialog(lisCCOErrorCaption, lisInvalidFilter,
661                           mtError, [mbIgnore,mbCancel]) = mrCancel
662       then exit;
663     end;
664   end;
665   Result:=true;
666 end;
667 
668 procedure TPublishModuleDialog.LoadFromOptions(SrcOpts: TPublishModuleOptions);
669 begin
670   // destination
671   SetComboBox(DestDirComboBox,SrcOpts.DestinationDirectory,20);
672 
673   // file filters
674   CompressCheckbox.Checked:=SrcOpts.CompressFinally;
675   OpenInFileManCheckbox.Checked := SrcOpts.OpenInFileMan;
676   UseFiltersCheckbox.Checked:=SrcOpts.UseFileFilters;
677   FilterSimpleSyntaxCheckbox.Checked:=SrcOpts.FilterSimpleSyntax;
678   SetComboBox(FilterCombobox,SrcOpts.FileFilter,20);
679 end;
680 
681 procedure TPublishModuleDialog.SaveToOptions(DestOpts: TPublishModuleOptions);
682 begin
683   // destination
684   DestOpts.DestinationDirectory:=DestDirComboBox.Text;
685 
686   // file filters
687   DestOpts.CompressFinally:=CompressCheckbox.Checked;
688   DestOpts.OpenInFileMan:=OpenInFileManCheckbox.Checked;
689   DestOpts.UseFileFilters:=UseFiltersCheckbox.Checked;
690   DestOpts.FilterSimpleSyntax:=FilterSimpleSyntaxCheckbox.Checked;
691   DestOpts.FileFilter:=FilterCombobox.Text;
692 end;
693 
694 end.
695 
696