1 { /***************************************************************************
2                  codetoolsdefines.pas  -  Lazarus IDE unit
3                  -----------------------------------------
4 
5  ***************************************************************************/
6 
7  ***************************************************************************
8  *                                                                         *
9  *   This source is free software; you can redistribute it and/or modify   *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  *   This code is distributed in the hope that it will be useful, but      *
15  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
17  *   General Public License for more details.                              *
18  *                                                                         *
19  *   A copy of the GNU General Public License is available on the World    *
20  *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
21  *   obtain it by writing to the Free Software Foundation,                 *
22  *   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.   *
23  *                                                                         *
24  ***************************************************************************
25 
26   Author: Mattias Gaertner
27 
28   Abstract:
29     - TCodeToolsDefinesEditor is an editor for the CodeTools DefineTree used by
30       the IDE. The DefineTree defines all values, that are not in the sources,
31       but are provided by for example Makefiles, compiler command lines and
32       compiler config files.
33 
34     There are three types of nodes:
35       - auto generated: These are created by the IDE.
36       - project specific: These nodes are saved in the project info file (.lpi)
37       - the rest are global nodes, saved in the codetoolsoptions.xml file.
38 
39 }
40 unit CodeToolsDefines;
41 
42 {$mode objfpc}{$H+}
43 
44 interface
45 
46 uses
47   Classes, SysUtils, Math,
48   // LCL
49   LCLType, LCLIntf, Forms, Controls, Buttons, StdCtrls,
50   ComCtrls, ExtCtrls, Menus, Graphics, Dialogs, ButtonPanel,
51   // LazUtils
52   LazFileUtils, LazLogger, LazStringUtils,
53   // SynEdit
54   SynEdit,
55   // Codetools
56   CodeToolManager, DefineTemplates,
57   // IdeIntf
58   IDEWindowIntf, IDEImagesIntf, IDEDialogs,
59   // IDE
60   LazarusIDEStrConsts, CodeToolsOptions, CodeToolsDefPreview, TransferMacros,
61   EditorOptions, InputFileDialog, LazConf, IDEProcs, EditDefineTree, CompilerOptions;
62 
63 type
64 
65   { TCodeToolsDefinesEditor }
66 
67   TCodeToolsDefinesEditor = class(TForm)
68     ButtonPanel1: TButtonPanel;
69     MenuItem1: TMenuItem;
70     MenuItem10: TMenuItem;
71     MenuItem11: TMenuItem;
72     MenuItem14: TMenuItem;
73     MenuItem16: TMenuItem;
74     MenuItem17: TMenuItem;
75     MenuItem18: TMenuItem;
76     MenuItem19: TMenuItem;
77     MenuItem23: TMenuItem;
78     MenuItem27: TMenuItem;
79     MenuItem29: TMenuItem;
80     MenuItem3: TMenuItem;
81     MenuItem30: TMenuItem;
82     ValueAsTextPage: TTabSheet;
83     ValueAsPathsPage: TTabSheet;
84     MainSplitter: TSplitter;
85     MainMenu: TMainMenu;
86 
87 
88     // edit nodes
89     EditMenuItem: TMenuItem;
90     MoveNodeUpMenuItem: TMenuItem;
91     MoveNodeDownMenuItem: TMenuItem;
92     MoveNodeLvlUpMenuItem: TMenuItem;
93     MoveNodeLvlDownMenuItem: TMenuItem;
94     InsertBehindMenuItem: TMenuItem;
95     InsertBehindDefineMenuItem: TMenuItem;
96     InsertBehindDefineRecurseMenuItem: TMenuItem;
97     InsertBehindUndefineMenuItem: TMenuItem;
98     InsertBehindUndefineRecurseMenuItem: TMenuItem;
99     InsertBehindUndefineAllMenuItem: TMenuItem;
100     InsertBehindBlockMenuItem: TMenuItem;
101     InsertBehindDirectoryMenuItem: TMenuItem;
102     InsertBehindIfMenuItem: TMenuItem;
103     InsertBehindIfDefMenuItem: TMenuItem;
104     InsertBehindIfNotDefMenuItem: TMenuItem;
105     InsertBehindElseIfMenuItem: TMenuItem;
106     InsertBehindElseMenuItem: TMenuItem;
107     InsertAsChildMenuItem: TMenuItem;
108     InsertAsChildDefineMenuItem: TMenuItem;
109     InsertAsChildDefineRecurseMenuItem: TMenuItem;
110     InsertAsChildUndefineMenuItem: TMenuItem;
111     InsertAsChildUndefineRecurseMenuItem: TMenuItem;
112     InsertAsChildUndefineAllMenuItem: TMenuItem;
113     InsertAsChildBlockMenuItem: TMenuItem;
114     InsertAsChildDirectoryMenuItem: TMenuItem;
115     InsertAsChildIfMenuItem: TMenuItem;
116     InsertAsChildIfDefMenuItem: TMenuItem;
117     InsertAsChildIfNotDefMenuItem: TMenuItem;
118     InsertAsChildElseIfMenuItem: TMenuItem;
119     InsertAsChildElseMenuItem: TMenuItem;
120     DeleteNodeMenuItem: TMenuItem;
121     ConvertActionMenuItem: TMenuItem;
122     ConvertActionToDefineMenuItem: TMenuItem;
123     ConvertActionToDefineRecurseMenuItem: TMenuItem;
124     ConvertActionToUndefineMenuItem: TMenuItem;
125     ConvertActionToUndefineRecurseMenuItem: TMenuItem;
126     ConvertActionToUndefineAllMenuItem: TMenuItem;
127     ConvertActionToBlockMenuItem: TMenuItem;
128     ConvertActionToDirectoryMenuItem: TMenuItem;
129     ConvertActionToIfMenuItem: TMenuItem;
130     ConvertActionToIfDefMenuItem: TMenuItem;
131     ConvertActionToIfNotDefMenuItem: TMenuItem;
132     ConvertActionToElseIfMenuItem: TMenuItem;
133     ConvertActionToElseMenuItem: TMenuItem;
134     CopyToClipbrdMenuItem: TMenuItem;
135     PasteFromClipbrdMenuItem: TMenuItem;
136 
137     // tools
138     ToolsMenuItem: TMenuItem;
139     OpenPreviewMenuItem: TMenuItem;
140     ShowMacroListMenuItem: TMenuItem;
141 
142     // templates
143     InsertTemplateMenuItem: TMenuItem;
144     InsertFPCProjectDefinesTemplateMenuItem: TMenuItem;
145     InsertFPCompilerDefinesTemplateMenuItem: TMenuItem;
146     InsertFPCSourceDirTemplateMenuItem: TMenuItem;
147     InsertDelphi5CompilerDefinesTemplateMenuItem: TMenuItem;
148     InsertDelphi5DirectoryTemplateMenuItem: TMenuItem;
149     InsertDelphi5ProjectTemplateMenuItem: TMenuItem;
150     InsertDelphi6CompilerDefinesTemplateMenuItem: TMenuItem;
151     InsertDelphi6DirectoryTemplateMenuItem: TMenuItem;
152     InsertDelphi6ProjectTemplateMenuItem: TMenuItem;
153     InsertDelphi7CompilerDefinesTemplateMenuItem: TMenuItem;
154     InsertDelphi7DirectoryTemplateMenuItem: TMenuItem;
155     InsertDelphi7ProjectTemplateMenuItem: TMenuItem;
156     InsertKylix3CompilerDefinesTemplateMenuItem: TMenuItem;
157     InsertKylix3DirectoryTemplateMenuItem: TMenuItem;
158     InsertKylix3ProjectTemplateMenuItem: TMenuItem;
159 
160     // define tree
161     DefineTreeView: TTreeView;
162 
163     // selected item
164     SelectedItemGroupBox: TGroupBox;
165     TypeLabel: TLabel;
166     NameLabel: TLabel;
167     NameEdit: TEdit;
168     DescriptionLabel: TLabel;
169     DescriptionEdit: TEdit;
170     VariableLabel: TLabel;
171     VariableEdit: TEdit;
172     ValueNoteBook: TPageControl;
173     ValueAsTextSynEdit: TSynEdit;
174     ValueAsFilePathsSynEdit: TSynEdit;
175     MoveFilePathUpBitBtn: TBitBtn;
176     MoveFilePathDownBitBtn: TBitBtn;
177     DeleteFilePathBitBtn: TBitBtn;
178     InsertFilePathBitBtn: TBitBtn;
179 
180     // preview
181     //DefinePreview: TCodeToolsDefinesPreview;
182 
183     // misc
184     procedure CodeToolsDefinesEditorKeyDown(Sender: TObject; var Key: Word;
185       Shift: TShiftState);
186     procedure CodeToolsDefinesEditorKeyUp(Sender: TObject; var Key: Word;
187       Shift: TShiftState);
188     procedure DefineTreeViewSelectionChanged(Sender: TObject);
189     procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
190     procedure FormCreate(Sender: TObject);
191     procedure OKButtonClick(Sender: TObject);
192 
193     // value notebook
194     procedure ValueNoteBookPageChanged(Sender: TObject);
195     procedure MoveFilePathUpBitBtnClick(Sender: TObject);
196     procedure MoveFilePathDownBitBtnClick(Sender: TObject);
197     procedure DeleteFilePathBitBtnClick(Sender: TObject);
198     procedure InsertFilePathBitBtnClick(Sender: TObject);
199 
200     // edit menu
201     procedure InsertNodeMenuItemClick(Sender: TObject);
202     procedure MoveNodeUpMenuItemClick(Sender: TObject);
203     procedure MoveNodeDownMenuItemClick(Sender: TObject);
204     procedure MoveNodeLvlUpMenuItemClick(Sender: TObject);
205     procedure MoveNodeLvlDownMenuItemClick(Sender: TObject);
206     procedure DeleteNodeMenuItemClick(Sender: TObject);
207     procedure ConvertActionMenuItemClick(Sender: TObject);
208 
209     // tools menu
210     procedure OpenPreviewMenuItemClick(Sender: TObject);
211 
212     // template menu
213     procedure InsertFPCProjectDefinesTemplateMenuItemClick(Sender: TObject);
214     procedure InsertFPCompilerDefinesTemplateMenuItemClick(Sender: TObject);
215     procedure InsertFPCSourceDirDefinesTemplateMenuItemClick(Sender: TObject);
216     procedure InsertDelphiCompilerDefinesTemplateMenuItemClick(Sender: TObject);
217     procedure InsertDelphiDirectoryTemplateMenuItemClick(Sender: TObject);
218     procedure InsertDelphiProjectTemplateMenuItemClick(Sender: TObject);
219     procedure InsertKylixCompilerDefinesTemplateMenuItemClick(Sender: TObject);
220     procedure InsertKylixDirectoryTemplateMenuItemClick(Sender: TObject);
221     procedure InsertKylixProjectTemplateMenuItemClick(Sender: TObject);
222   private
223     FDefineTree: TDefineTree;
224     FLastSelectedNode: TTreeNode;
225     FBoss: TCodeToolManager;
226     FTransferMacros: TTransferMacroList;
227     procedure CreateComponents;
CreateSeperatornull228     function CreateSeperator : TMenuItem;
229     procedure SetTransferMacros(const AValue: TTransferMacroList);
230     procedure ValueAsPathToValueAsText;
231     procedure SaveSelectedValues;
232     procedure ShowSelectedValues;
233     procedure SetTypeLabel;
ValueToFilePathTextnull234     function ValueToFilePathText(const AValue: string): string;
235     procedure InsertNewNode(Behind: boolean; DefAction: TDefineAction);
236     procedure InsertTemplate(NewTemplate: TDefineTemplate);
FindUniqueNamenull237     function FindUniqueName: string;
ConsistencyChecknull238     function ConsistencyCheck: integer;
239     procedure SetValuesEditable(AValue: boolean);
240   public
241     procedure SetOptions(ACodeToolBoss: TCodeToolManager);
242     constructor Create(TheOwner: TComponent); override;
243     destructor Destroy; override;
244     property DefineTree: TDefineTree read FDefineTree;
245     property Boss: TCodeToolManager read FBoss write FBoss;
246     property Macros: TTransferMacroList
247       read FTransferMacros write SetTransferMacros;
248   end;
249 
ShowCodeToolsDefinesEditornull250 function ShowCodeToolsDefinesEditor(ACodeToolBoss: TCodeToolManager;
251   Options: TCodeToolsOptions; Macros: TTransferMacroList): TModalResult;
252 
253 
254 implementation
255 
256 {$R *.lfm}
257 
ShowCodeToolsDefinesEditornull258 function ShowCodeToolsDefinesEditor(ACodeToolBoss: TCodeToolManager;
259   Options: TCodeToolsOptions; Macros: TTransferMacroList): TModalResult;
260 var CodeToolsDefinesEditor: TCodeToolsDefinesEditor;
261 begin
262   CodeToolsDefinesEditor:=TCodeToolsDefinesEditor.Create(nil);
263   CodeToolsDefinesEditor.SetOptions(ACodeToolBoss);
264   CodeToolsDefinesEditor.Macros:=Macros;
265   Result:=CodeToolsDefinesEditor.ShowModal;
266   if Result=mrOk then begin
267     if not CodeToolsDefinesEditor.DefineTree.IsEqual(ACodeToolBoss.DefineTree)
268     then begin
269       ACodeToolBoss.DefineTree.AssignNonAutoCreated(
270         CodeToolsDefinesEditor.DefineTree);
271       Options.ReadGlobalDefinesTemplatesFromTree(ACodeToolBoss.DefineTree);
272       Options.Save;
273     end;
274   end;
275   CodeToolsDefinesEditor.Free;
276 end;
277 
278 { TCodeToolsDefinesEditor }
279 
280 procedure TCodeToolsDefinesEditor.CodeToolsDefinesEditorKeyDown(
281   Sender: TObject; var Key: Word; Shift: TShiftState);
282 begin
283   if (Shift=[]) and (Key=VK_ESCAPE) then ModalResult:=mrCancel;
284 end;
285 
286 procedure TCodeToolsDefinesEditor.CodeToolsDefinesEditorKeyUp(Sender: TObject;
287   var Key: Word; Shift: TShiftState);
288 begin
289   if (Key=VK_ESCAPE) and (Shift=[]) then
290     ModalResult:=mrCancel;
291 end;
292 
293 procedure TCodeToolsDefinesEditor.DefineTreeViewSelectionChanged(Sender: TObject);
294 begin
295   ShowSelectedValues;
296 end;
297 
298 procedure TCodeToolsDefinesEditor.FormClose(Sender: TObject;
299   var CloseAction: TCloseAction);
300 begin
301   if CloseAction=caNone then ;
302   CodeToolsOpts.DefinesEditMainSplitterTop:=MainSplitter.Top;
303   CodeToolsOpts.Save;
304   IDEDialogLayoutList.SaveLayout(Self);
305 end;
306 
307 procedure TCodeToolsDefinesEditor.FormCreate(Sender: TObject);
308 begin
309   ButtonPanel1.OKButton.Caption:= lisOk;
310   ButtonPanel1.CancelButton.Caption:= lisCancel;
311 end;
312 
313 procedure TCodeToolsDefinesEditor.OKButtonClick(Sender: TObject);
314 begin
315   SaveSelectedValues;
316   FLastSelectedNode:=nil;
317   ModalResult:=mrOk;
318 end;
319 
320 procedure TCodeToolsDefinesEditor.ValueNoteBookPageChanged(Sender: TObject);
321 begin
322   if ValueNoteBook.PageIndex=0 then
323     ValueAsPathToValueAsText
324   else
325     ValueAsFilePathsSynEdit.Text:=ValueToFilePathText(ValueAsTextSynEdit.Text);
326 end;
327 
328 procedure TCodeToolsDefinesEditor.MoveFilePathUpBitBtnClick(Sender: TObject);
329 var y: integer;
330 begin
331   if ValueAsFilePathsSynEdit.ReadOnly then exit;
332   y:=ValueAsFilePathsSynEdit.CaretY-1;
333   if (y>0) and (y<ValueAsFilePathsSynEdit.Lines.Count) then
334     ValueAsFilePathsSynEdit.Lines.Move(y,y-1);
335 end;
336 
337 procedure TCodeToolsDefinesEditor.MoveFilePathDownBitBtnClick(Sender: TObject);
338 var y: integer;
339 begin
340   if ValueAsFilePathsSynEdit.ReadOnly then exit;
341   y:=ValueAsFilePathsSynEdit.CaretY-1;
342   if (y>=0) and (y<ValueAsFilePathsSynEdit.Lines.Count-1) then
343     ValueAsFilePathsSynEdit.Lines.Move(y,y+1);
344 end;
345 
346 procedure TCodeToolsDefinesEditor.DeleteFilePathBitBtnClick(Sender: TObject);
347 var y: integer;
348 begin
349   if ValueAsFilePathsSynEdit.ReadOnly then exit;
350   y:=ValueAsFilePathsSynEdit.CaretY-1;
351   if (y>=0) and (y<ValueAsFilePathsSynEdit.Lines.Count) then
352     ValueAsFilePathsSynEdit.Lines.Delete(y);
353 end;
354 
355 procedure TCodeToolsDefinesEditor.InsertFilePathBitBtnClick(Sender: TObject);
356 var y: integer;
357 begin
358   if ValueAsFilePathsSynEdit.ReadOnly then exit;
359   y:=ValueAsFilePathsSynEdit.CaretY-1;
360   if (y>=0) and (y<ValueAsFilePathsSynEdit.Lines.Count) then
361     ValueAsFilePathsSynEdit.Lines.Insert(y,'');
362 end;
363 
364 procedure TCodeToolsDefinesEditor.InsertNodeMenuItemClick(Sender: TObject);
365 var Behind: boolean;
366   DefAction: TDefineAction;
367 begin
368   Behind:=(TMenuItem(Sender).Parent=InsertBehindMenuItem);
369   if Sender=InsertBehindDefineMenuItem then DefAction:=da_Define
370   else if Sender=InsertBehindDefineRecurseMenuItem then DefAction:=da_DefineRecurse
371   else if Sender=InsertBehindUndefineMenuItem then DefAction:=da_Undefine
372   else if Sender=InsertBehindUndefineRecurseMenuItem then DefAction:=da_UndefineRecurse
373   else if Sender=InsertBehindUndefineAllMenuItem then DefAction:=da_UndefineAll
374   else if Sender=InsertBehindBlockMenuItem then DefAction:=da_Block
375   else if Sender=InsertBehindDirectoryMenuItem then DefAction:=da_Directory
376   else if Sender=InsertBehindIfMenuItem then DefAction:=da_If
377   else if Sender=InsertBehindIfDefMenuItem then DefAction:=da_IfDef
378   else if Sender=InsertBehindIfNotDefMenuItem then DefAction:=da_IfNDef
379   else if Sender=InsertBehindElseIfMenuItem then DefAction:=da_ElseIf
380   else if Sender=InsertBehindElseMenuItem then DefAction:=da_Else
381   else if Sender=InsertAsChildDefineMenuItem then DefAction:=da_Define
382   else if Sender=InsertAsChildDefineRecurseMenuItem then DefAction:=da_DefineRecurse
383   else if Sender=InsertAsChildUndefineMenuItem then DefAction:=da_Undefine
384   else if Sender=InsertAsChildUndefineRecurseMenuItem then DefAction:=da_UndefineRecurse
385   else if Sender=InsertAsChildUndefineAllMenuItem then DefAction:=da_UndefineAll
386   else if Sender=InsertAsChildBlockMenuItem then DefAction:=da_Block
387   else if Sender=InsertAsChildDirectoryMenuItem then DefAction:=da_Directory
388   else if Sender=InsertAsChildIfMenuItem then DefAction:=da_If
389   else if Sender=InsertAsChildIfDefMenuItem then DefAction:=da_IfDef
390   else if Sender=InsertAsChildIfNotDefMenuItem then DefAction:=da_IfNDef
391   else if Sender=InsertAsChildElseIfMenuItem then DefAction:=da_ElseIf
392   else if Sender=InsertAsChildElseMenuItem then DefAction:=da_Else
393   else DefAction:=da_None;
394   InsertNewNode(Behind,DefAction);
395 end;
396 
397 procedure TCodeToolsDefinesEditor.MoveNodeUpMenuItemClick(Sender: TObject);
398 var
399   SelTreeNode: TTreeNode;
400   SelDefNode, PrevDefNode: TDefineTemplate;
401 begin
402   SelTreeNode:=DefineTreeView.Selected;
403   SaveSelectedValues;
404   if (SelTreeNode=nil) or (SelTreeNode.GetPrevSibling=nil) then exit;
405   SelDefNode:=TDefineTemplate(SelTreeNode.Data);
406   PrevDefNode:=SelDefNode.Prior;
407   // move node up in TreeView
408   SelTreeNode.MoveTo(SelTreeNode.GetPrevSibling,naInsert);
409   // move node up in DefineTree
410   SelDefNode.Unbind;
411   SelDefNode.InsertInFront(PrevDefNode);
412   SelTreeNode.MakeVisible;
413 end;
414 
415 procedure TCodeToolsDefinesEditor.MoveNodeDownMenuItemClick(Sender: TObject);
416 var
417   SelTreeNode: TTreeNode;
418   SelDefNode, NextDefNode: TDefineTemplate;
419 begin
420   SelTreeNode:=DefineTreeView.Selected;
421   SaveSelectedValues;
422   if (SelTreeNode=nil) or (SelTreeNode.GetNextSibling=nil) then exit;
423   SelDefNode:=TDefineTemplate(SelTreeNode.Data);
424   NextDefNode:=SelDefNode.Next;
425   // move node down in TreeView
426   if SelTreeNode.GetNextSibling.GetNextSibling<>nil then
427     SelTreeNode.MoveTo(SelTreeNode.GetNextSibling.GetNextSibling,naInsert)
428   else
429     SelTreeNode.MoveTo(SelTreeNode.GetNextSibling,naAdd);
430   // move node down in DefineTree
431   SelDefNode.Unbind;
432   SelDefNode.InsertBehind(NextDefNode);
433   SelTreeNode.MakeVisible;
434 end;
435 
436 procedure TCodeToolsDefinesEditor.MoveNodeLvlUpMenuItemClick(Sender: TObject);
437 var
438   SelTreeNode: TTreeNode;
439   SelDefNode, PrevDefNode: TDefineTemplate;
440 begin
441   SelTreeNode:=DefineTreeView.Selected;
442   SaveSelectedValues;
443   if (SelTreeNode=nil) or (SelTreeNode.Parent=nil) then exit;
444   SelDefNode:=TDefineTemplate(SelTreeNode.Data);
445   if SelDefNode.IsAutoGenerated then begin
446     IDEMessageDialog(lisCodeToolsDefsNodeIsReadonly,
447       lisCodeToolsDefsAutoGeneratedNodesCanNotBeEdited,
448       mtInformation,[mbCancel]);
449     exit;
450   end;
451   // move node one lvl up in TreeView
452   if SelTreeNode.Parent.GetNextSibling<>nil then
453     SelTreeNode.MoveTo(SelTreeNode.Parent.GetNextSibling,naInsert)
454   else
455     SelTreeNode.MoveTo(SelTreeNode.Parent,naAdd);
456   // move node one lvl up in DefineTree
457   PrevDefNode:=SelDefNode.Parent;
458   SelDefNode.Unbind;
459   SelDefNode.InsertBehind(PrevDefNode);
460   SetNodeImages(SelTreeNode,true);
461   SelTreeNode.MakeVisible;
462 end;
463 
464 procedure TCodeToolsDefinesEditor.MoveNodeLvlDownMenuItemClick(Sender: TObject);
465 var
466   SelTreeNode: TTreeNode;
467   SelDefNode, PrevDefNode: TDefineTemplate;
468 begin
469   SelTreeNode:=DefineTreeView.Selected;
470   SaveSelectedValues;
471   if (SelTreeNode=nil) or (SelTreeNode.GetPrevSibling=nil) then exit;
472   SelDefNode:=TDefineTemplate(SelTreeNode.Data);
473   PrevDefNode:=SelDefNode.Prior;
474   if (SelDefNode.IsAutoGenerated) or (PrevDefNode.IsAutoGenerated) then begin
475     IDEMessageDialog(lisCodeToolsDefsNodeIsReadonly,
476       lisCodeToolsDefsAutoGeneratedNodesCanNotBeEdited,
477       mtInformation,[mbCancel]);
478     exit;
479   end;
480   if (not (PrevDefNode.Action in DefineActionBlocks)) then begin
481     IDEMessageDialog(lisCodeToolsDefsInvalidPreviousNode,
482       lisCodeToolsDefsPreviousNodeCanNotContainChildNodes,
483       mtInformation,[mbCancel]);
484     exit;
485   end;
486   // move node one lvl down in TreeView
487   SelTreeNode.MoveTo(SelTreeNode.GetPrevSibling,naAddChild);
488   // move node one lvl up in DefineTree
489   SelDefNode.Unbind;
490   PrevDefNode.AddChild(SelDefNode);
491   SetNodeImages(SelTreeNode.Parent,true);
492   SelTreeNode.MakeVisible;
493 end;
494 
495 procedure TCodeToolsDefinesEditor.DeleteNodeMenuItemClick(Sender: TObject);
496 var
497   SelTreeNode: TTreeNode;
498   SelDefNode: TDefineTemplate;
499 begin
500   SelTreeNode:=DefineTreeView.Selected;
501   SaveSelectedValues;
502   if (SelTreeNode=nil) then exit;
503   SelDefNode:=TDefineTemplate(SelTreeNode.Data);
504   if (SelDefNode.IsAutoGenerated) then begin
505     IDEMessageDialog(lisCodeToolsDefsNodeIsReadonly,
506       lisCodeToolsDefsAutoGeneratedNodesCanNotBeEdited,
507       mtInformation,[mbCancel]);
508     exit;
509   end;
510   if FLastSelectedNode=SelTreeNode then FLastSelectedNode:=nil;
511   // delete node in TreeView
512   SelTreeNode.Free;
513   // delete node in DefineTree
514   SelDefNode.Unbind;
515   SelDefNode.Free;
516 end;
517 
518 procedure TCodeToolsDefinesEditor.ConvertActionMenuItemClick(Sender: TObject);
519 var
520   NewAction: TDefineAction;
521   SelTreeNode: TTreeNode;
522   SelDefNode: TDefineTemplate;
523 begin
524   SelTreeNode:=DefineTreeView.Selected;
525   SaveSelectedValues;
526   if SelTreeNode=nil then exit;
527   SelDefNode:=TDefineTemplate(SelTreeNode.Data);
528   if (SelDefNode.IsAutoGenerated) then begin
529     IDEMessageDialog(lisCodeToolsDefsNodeIsReadonly,
530       lisCodeToolsDefsAutoGeneratedNodesCanNotBeEdited,
531       mtInformation,[mbCancel]);
532     exit;
533   end;
534   if Sender=ConvertActionToDefineMenuItem then NewAction:=da_Define
535   else if Sender=ConvertActionToDefineRecurseMenuItem then NewAction:=da_DefineRecurse
536   else if Sender=ConvertActionToUndefineMenuItem then NewAction:=da_Undefine
537   else if Sender=ConvertActionToUndefineRecurseMenuItem then NewAction:=da_UndefineRecurse
538   else if Sender=ConvertActionToUndefineAllMenuItem then NewAction:=da_UndefineAll
539   else if Sender=ConvertActionToBlockMenuItem then NewAction:=da_Block
540   else if Sender=ConvertActionToDirectoryMenuItem then NewAction:=da_Directory
541   else if Sender=ConvertActionToIfMenuItem then NewAction:=da_If
542   else if Sender=ConvertActionToIfDefMenuItem then NewAction:=da_IfDef
543   else if Sender=ConvertActionToIfNotDefMenuItem then NewAction:=da_IfNDef
544   else if Sender=ConvertActionToElseIfMenuItem then NewAction:=da_ElseIf
545   else if Sender=ConvertActionToElseMenuItem then NewAction:=da_Else
546   else NewAction:=da_None;
547   SelDefNode.Action:=NewAction;
548   SetNodeImages(SelTreeNode,false);
549   SetTypeLabel;
550 end;
551 
552 procedure TCodeToolsDefinesEditor.OpenPreviewMenuItemClick(Sender: TObject);
553 begin
554   // apply changed tree
555   CodeToolBoss.DefineTree.AssignNonAutoCreated(DefineTree);
556   try
557     // show preview
558     ShowCodeToolsDefinesValuesDialog(DefineTree,'');
559   finally
560     // restore old tree
561     CodeToolsOpts.AssignGlobalDefineTemplatesToTree(CodeToolBoss.DefineTree);
562   end;
563 end;
564 
565 procedure TCodeToolsDefinesEditor.InsertFPCProjectDefinesTemplateMenuItemClick(
566   Sender: TObject);
567 var InputFileDlg: TInputFileDialog;
568   DefaultFPCSrcDir, DefaultCompiler,
569   CompilerPath, FPCSrcDir: string;
570   DirTemplate, FPCTemplate: TDefineTemplate;
571   TargetOS, TargetProcessor: string;
572   UnitSetCache: TFPCUnitSetCache;
573 begin
574   InputFileDlg:=GetInputFileDialog;
575   InputFileDlg.Macros:=Macros;
576   with InputFileDlg do begin
577 
578     DefaultFPCSrcDir:='$(FPCSrcDir)';
579     DefaultCompiler:=DefaultCompilerPath;
580 
581     BeginUpdate;
582     Caption:=lisCodeToolsDefsCreateFPCMacrosAndPathsForAFPCProjectDirectory;
583 
584     FileCount:=3;
585 
586     FileTitles[0]:=lisCodeToolsDefsProjectDirectory;
587     FileDescs[0]:=lisCodeToolsDefsTheFreePascalProjectDirectory;
588     FileNames[0]:='';
589     FileFlags[0]:=[iftDirectory,iftNotEmpty,iftMustExist];
590 
591     FileTitles[1]:=lisCodeToolsDefscompilerPath;
592     FileDescs[1]:=BreakString(
593       lisCodeToolsDefsThePathToTheFreePascalCompilerForThisProject, 60, 0);
594     FileNames[1]:=DefaultCompiler;
595     FileFlags[1]:=[iftFilename];
596 
597     FileTitles[2]:=lisCodeToolsDefsFPCSVNSourceDirectory;
598     FileDescs[2]:=BreakString(
599       lisCodeToolsDefsTheFreePascalCVSSourceDirectory, 60, 0);
600     FileNames[2]:=DefaultFPCSrcDir;
601     FileFlags[2]:=[iftDirectory];
602 
603     EndUpdate;
604     if ShowModal=mrCancel then exit;
605 
606     FPCSrcDir:=FileNames[2];
607     if Macros<>nil then Macros.SubstituteStr(FPCSrcDir);
608     if FPCSrcDir='' then FPCSrcDir:=DefaultFPCSrcDir;
609     DebugLn('  FPCSrcDir="',FPCSrcDir,'"');
610 
611     // ask the compiler for Macros
612     CompilerPath:=FileNames[1];
613     if Macros<>nil then Macros.SubstituteStr(CompilerPath);
614     DebugLn('  CompilerPath="',CompilerPath,'"');
615     TargetOS:='';
616     TargetProcessor:='';
617 
618     UnitSetCache:=Boss.CompilerDefinesCache.FindUnitSet(CompilerPath,
619                                     TargetOS,TargetProcessor,'',FPCSrcDir,true);
620 
621     // create directory defines
622     DirTemplate:=TDefineTemplate.Create('FPC Project ('+FileNames[0]+')',
623        'Free Pascal Project Directory','',FileNames[0],da_Directory);
624 
625     if (DefaultFPCSrcDir=Filenames[2]) and (DefaultCompiler=Filenames[1]) then
626     begin
627       // a normal fpc project -> nothing special needed
628     end else begin
629       // a special fpc project -> create a world of its own
630       DirTemplate.AddChild(TDefineTemplate.Create('Reset All',
631          'Reset all values','','',da_UndefineAll));
632       FPCTemplate:=CreateFPCTemplate(UnitSetCache,CodeToolsOpts);
633       if FPCTemplate<>nil then
634         DirTemplate.AddChild(FPCTemplate);
635     end;
636 
637     DirTemplate.SetDefineOwner(CodeToolsOpts,true);
638     InsertTemplate(DirTemplate);
639   end;
640 end;
641 
642 procedure TCodeToolsDefinesEditor.InsertFPCompilerDefinesTemplateMenuItemClick(
643   Sender: TObject);
644 var InputFileDlg: TInputFileDialog;
645   CompilerPath, DefaultCompiler: string;
646   FPCTemplate: TDefineTemplate;
647   UnitSearchPath, TargetOS, TargetProcessor: string;
648 begin
649   InputFileDlg:=GetInputFileDialog;
650   InputFileDlg.Macros:=Macros;
651   with InputFileDlg do begin
652     DefaultCompiler:=DefaultCompilerPath;
653 
654     BeginUpdate;
655     Caption:=lisCodeToolsDefsCreateDefinesForFreePascalCompiler;
656     FileCount:=1;
657 
658     FileTitles[0]:=lisCodeToolsDefscompilerPath;
659     FileDescs[0]:=Format(
660       lisCodeToolsDefsThePathToTheFreePascalCompilerForExample, [LineEnding,
661        '"', GetDefaultCompilerFilename, '"', '"', '"']);
662     FileNames[0]:=DefaultCompiler;
663     FileFlags[0]:=[iftCmdLine,iftNotEmpty];
664 
665     EndUpdate;
666     if ShowModal=mrCancel then exit;
667 
668     CompilerPath:=FileNames[0];
669     if Macros<>nil then Macros.SubstituteStr(CompilerPath);
670     DebugLn('  CompilerPath="',CompilerPath,'"');
671 
672     FPCTemplate:=Boss.DefinePool.CreateFPCTemplate(CompilerPath,'',
673                                            CreateCompilerTestPascalFilename,
674                                            UnitSearchPath,
675                                            TargetOS,TargetProcessor,
676                                            CodeToolsOpts);
677     if (TargetOS='') or (TargetProcessor='') or (UnitSearchPath='') then
678       DebugLn(['TCodeToolsDefinesEditor.InsertFPCompilerDefinesTemplateMenuItemClick TargetOS="',TargetOS,'" TargetProcessor="',TargetProcessor,'"']);
679     if FPCTemplate=nil then exit;
680     FPCTemplate.Name:='Free Pascal Compiler ('+CompilerPath+')';
681     InsertTemplate(FPCTemplate);
682   end;
683 end;
684 
685 procedure TCodeToolsDefinesEditor.InsertFPCSourceDirDefinesTemplateMenuItemClick
686   (Sender: TObject);
687 var InputFileDlg: TInputFileDialog;
688   DefaultCompiler, CompilerPath, FPCSrcDir: string;
689   TargetOS, TargetProcessor: string;
690   FPCSrcTemplate: TDefineTemplate;
691   UnitSetCache: TFPCUnitSetCache;
692 begin
693   InputFileDlg:=GetInputFileDialog;
694   InputFileDlg.Macros:=Macros;
695   with InputFileDlg do begin
696     DefaultCompiler:=DefaultCompilerPath;
697 
698     BeginUpdate;
699     Caption:=lisCodeToolsDefsCreateDefinesForFreePascalSVNSources;
700     FileCount:=2;
701 
702     FileTitles[0]:=lisCodeToolsDefsFPCSVNSourceDirectory;
703     FileDescs[0]:=lisCodeToolsDefsTheFreePascalSVNSourceDir;
704     FileNames[0]:='~/fpc_sources/2.4.1/fpc';
705     FileFlags[0]:=[iftDirectory,iftNotEmpty,iftMustExist];
706 
707     FileTitles[1]:=lisCodeToolsDefsCompilerPath;
708     FileDescs[1]:=Format(
709       lisCodeToolsDefsThePathToTheFreePascalCompilerForThisSourceUsedToA, [LineEnding]);
710     FileNames[1]:=DefaultCompiler;
711     FileFlags[1]:=[iftFilename];
712 
713     EndUpdate;
714     if ShowModal=mrCancel then exit;
715 
716     // ask the compiler for Macros
717     CompilerPath:=FileNames[1];
718     if Macros<>nil then Macros.SubstituteStr(CompilerPath);
719     DebugLn('  CompilerPath="',CompilerPath,'"');
720 
721     TargetOS:='';
722     TargetProcessor:='';
723     FPCSrcDir:=FileNames[0];
724     if Macros<>nil then Macros.SubstituteStr(FPCSrcDir);
725     DebugLn('  FPCSrcDir="',FPCSrcDir,'"');
726 
727     UnitSetCache:=Boss.CompilerDefinesCache.FindUnitSet(CompilerPath,
728                                     TargetOS,TargetProcessor,'',FPCSrcDir,true);
729     // create FPC Source defines
730     FPCSrcTemplate:=CreateFPCSourceTemplate(UnitSetCache,CodeToolsOpts);
731     if FPCSrcTemplate=nil then begin
732       DebugLn('ERROR: unable to create FPC CVS Src defines for "',FPCSrcDir,'"');
733       exit;
734     end;
735 
736     // create directory defines
737     FPCSrcTemplate.Name:='FPC SVN Sources ('+FileNames[0]+')';
738 
739     FPCSrcTemplate.SetDefineOwner(CodeToolsOpts,true);
740     InsertTemplate(FPCSrcTemplate);
741   end;
742 end;
743 
744 procedure TCodeToolsDefinesEditor.InsertDelphiCompilerDefinesTemplateMenuItemClick
745   (Sender: TObject);
746 var DelphiVersion: integer;
747 begin
748   if Sender=InsertDelphi7CompilerDefinesTemplateMenuItem then
749     DelphiVersion:=7
750   else if Sender=InsertDelphi6CompilerDefinesTemplateMenuItem then
751     DelphiVersion:=6
752   else
753     DelphiVersion:=5;
754   InsertTemplate(Boss.DefinePool.CreateDelphiCompilerDefinesTemplate(
755                                                   DelphiVersion,CodeToolsOpts));
756 end;
757 
758 procedure TCodeToolsDefinesEditor.InsertDelphiDirectoryTemplateMenuItemClick(
759   Sender: TObject);
760 var InputFileDlg: TInputFileDialog;
761   DirTemplate: TDefineTemplate;
762   DelphiVersion: integer;
763   DelphiName: string;
764 begin
765   if Sender=InsertDelphi7DirectoryTemplateMenuItem then
766     DelphiVersion:=7
767   else if Sender=InsertDelphi6DirectoryTemplateMenuItem then
768     DelphiVersion:=6
769   else
770     DelphiVersion:=5;
771   DelphiName:='Delphi'+IntToStr(DelphiVersion);
772 
773   InputFileDlg:=GetInputFileDialog;
774   InputFileDlg.Macros:=Macros;
775   with InputFileDlg do begin
776     BeginUpdate;
777     Caption:=Format(lisCodeToolsDefsCreateDefinesForDirectory, [DelphiName]);
778     FileCount:=1;
779 
780     FileTitles[0]:=Format(lisCodeToolsDefsdirectory, [DelphiName]);
781     FileDescs[0]:=Format(lisCodeToolsDefsDelphiMainDirectoryDesc, [DelphiName,
782       LineEnding, DelphiName, LineEnding, IntToStr(DelphiVersion)]);
783     FileNames[0]:=GetForcedPathDelims(
784                         'C:/Programme/Borland/Delphi'+IntToStr(DelphiVersion));
785     FileFlags[0]:=[iftDirectory,iftNotEmpty,iftMustExist];
786 
787     EndUpdate;
788     if ShowModal=mrCancel then exit;
789     DirTemplate:=Boss.DefinePool.CreateDelphiDirectoryTemplate(FileNames[0],
790                                                    DelphiVersion,CodeToolsOpts);
791     if DirTemplate=nil then exit;
792     DirTemplate.Name:=DelphiName+' ('+FileNames[0]+')';
793     InsertTemplate(DirTemplate);
794   end;
795 end;
796 
797 procedure TCodeToolsDefinesEditor.InsertDelphiProjectTemplateMenuItemClick(
798   Sender: TObject);
799 var
800   InputFileDlg: TInputFileDialog;
801   ProjTemplate: TDefineTemplate;
802   DelphiVersion: integer;
803   DelphiName: string;
804 begin
805   if Sender=InsertDelphi7ProjectTemplateMenuItem then
806     DelphiVersion:=7
807   else if Sender=InsertDelphi6ProjectTemplateMenuItem then
808     DelphiVersion:=6
809   else
810     DelphiVersion:=5;
811   DelphiName:='Delphi'+IntToStr(DelphiVersion);
812 
813   InputFileDlg:=GetInputFileDialog;
814   InputFileDlg.Macros:=Macros;
815   with InputFileDlg do begin
816     BeginUpdate;
817     Caption:=Format(lisCodeToolsDefsCreateDefinesForProject, [DelphiName]);
818 
819     FileCount:=2;
820 
821     FileTitles[0]:=Format(lisCodeToolsDefsprojectDirectory2, [DelphiName]);
822     FileDescs[0]:=Format(lisCodeToolsDefsTheProjectDirectory, [DelphiName, LineEnding]);
823     FileNames[0]:=GetForcedPathDelims('C:/Programme/Borland/Delphi'
824                    +IntToStr(DelphiVersion)+'/YourProject');
825     FileFlags[0]:=[iftDirectory,iftNotEmpty,iftMustExist];
826 
827     FileTitles[1]:=Format(lisCodeToolsDefsdirectory, [DelphiName]);
828     FileDescs[1]:=Format(lisCodeToolsDefsDelphiMainDirectoryForProject, [DelphiName,
829       LineEnding, DelphiName, LineEnding, DelphiName, LineEnding, IntToStr(DelphiVersion)]);
830     FileNames[1]:=GetForcedPathDelims('C:/Programme/Borland/Delphi'+IntToStr(DelphiVersion));
831     FileFlags[1]:=[iftDirectory,iftNotEmpty,iftMustExist];
832 
833     EndUpdate;
834     if ShowModal=mrCancel then exit;
835     ProjTemplate:=Boss.DefinePool.CreateDelphiProjectTemplate(FileNames[0],
836                                       FileNames[1],DelphiVersion,CodeToolsOpts);
837     if ProjTemplate=nil then exit;
838     ProjTemplate.Name:=DelphiName+' Project ('+FileNames[0]+')';
839     InsertTemplate(ProjTemplate);
840   end;
841 end;
842 
843 procedure TCodeToolsDefinesEditor.InsertKylixCompilerDefinesTemplateMenuItemClick
844   (Sender: TObject);
845 var KylixVersion: integer;
846 begin
847   KylixVersion:=3;
848   InsertTemplate(Boss.DefinePool.CreateKylixCompilerDefinesTemplate(
849                                                    KylixVersion,CodeToolsOpts));
850 end;
851 
852 procedure TCodeToolsDefinesEditor.InsertKylixDirectoryTemplateMenuItemClick(
853   Sender: TObject);
854 var
855   InputFileDlg: TInputFileDialog;
856   DirTemplate: TDefineTemplate;
857   KylixVersion: integer;
858   KylixName: string;
859   UserName: String;
860 begin
861   KylixVersion:=3;
862   KylixName:='Kylix'+IntToStr(KylixVersion);
863 
864   UserName:=GetCurrentUserName;
865   if UserName='' then UserName:='user';
866   InputFileDlg:=GetInputFileDialog;
867   InputFileDlg.Macros:=Macros;
868   with InputFileDlg do begin
869     BeginUpdate;
870     Caption:=Format(lisCodeToolsDefsCreateDefinesForDirectory, [KylixName]);
871     FileCount:=1;
872 
873     FileTitles[0]:=Format(lisCodeToolsDefsdirectory, [KylixName]);
874     FileDescs[0]:=Format(lisCodeToolsDefsKylixMainDirectoryDesc, [KylixName,
875       LineEnding, KylixName, LineEnding, IntToStr(KylixVersion)]);
876     FileNames[0]:=GetForcedPathDelims('/home/'+UserName+'/kylix'+IntToStr(KylixVersion));
877     FileFlags[0]:=[iftDirectory,iftNotEmpty,iftMustExist];
878 
879     EndUpdate;
880     if ShowModal=mrCancel then exit;
881     DirTemplate:=Boss.DefinePool.CreateKylixDirectoryTemplate(FileNames[0],
882                                                     KylixVersion,CodeToolsOpts);
883     if DirTemplate=nil then exit;
884     DirTemplate.Name:=KylixName+' ('+FileNames[0]+')';
885     InsertTemplate(DirTemplate);
886   end;
887 end;
888 
889 procedure TCodeToolsDefinesEditor.InsertKylixProjectTemplateMenuItemClick(
890   Sender: TObject);
891 var
892   InputFileDlg: TInputFileDialog;
893   ProjTemplate: TDefineTemplate;
894   KylixVersion: integer;
895   KylixName: string;
896   UserName: String;
897 begin
898   KylixVersion:=3;
899   KylixName:='Kylix'+IntToStr(KylixVersion);
900 
901   UserName:=GetCurrentUserName;
902   if UserName='' then UserName:='user';
903   InputFileDlg:=GetInputFileDialog;
904   InputFileDlg.Macros:=Macros;
905   with InputFileDlg do begin
906     BeginUpdate;
907     Caption:=Format(lisCodeToolsDefsCreateDefinesForProject, [KylixName]);
908 
909     FileCount:=2;
910 
911     FileTitles[0]:=Format(lisCodeToolsDefsprojectDirectory2, [KylixName]);
912     FileDescs[0]:=Format(lisCodeToolsDefsTheProjectDirectory, [KylixName, LineEnding]
913       );
914     FileNames[0]:=GetForcedPathDelims('/home/'+UserName+'/kylix'
915                    +IntToStr(KylixVersion)+'/YourProject');
916     FileFlags[0]:=[iftDirectory,iftNotEmpty,iftMustExist];
917 
918     FileTitles[1]:=Format(lisCodeToolsDefsdirectory, [KylixName]);
919     FileDescs[1]:=Format(lisCodeToolsDefsKylixMainDirectoryForProject, [KylixName,
920       LineEnding, KylixName, LineEnding, KylixName, LineEnding, IntToStr(KylixVersion)
921       ]);
922     FileNames[1]:=GetForcedPathDelims('/home/'+UserName+'/kylix'+IntToStr(KylixVersion));
923     FileFlags[1]:=[iftDirectory,iftNotEmpty,iftMustExist];
924 
925     EndUpdate;
926     if ShowModal=mrCancel then exit;
927     ProjTemplate:=Boss.DefinePool.CreateDelphiProjectTemplate(FileNames[0],
928                                        FileNames[1],KylixVersion,CodeToolsOpts);
929     if ProjTemplate=nil then exit;
930     ProjTemplate.Name:=KylixName+' Project ('+FileNames[0]+')';
931     InsertTemplate(ProjTemplate);
932   end;
933 end;
934 
935 procedure TCodeToolsDefinesEditor.CreateComponents;
936 var
937   DefAction: TDefineAction;
938 begin
939   // edit nodes
940   EditMenuItem.Caption := lisEdit;
941   MoveNodeUpMenuItem.Caption:=lisCodeToolsDefsMoveNodeUp;
942   MoveNodeDownMenuItem.Caption := lisCodeToolsDefsMoveNodeDown;
943   MoveNodeLvlUpMenuItem.Caption := lisCodeToolsDefsMoveNodeOneLevelUp;
944   MoveNodeLvlDownMenuItem.Caption := lisCodeToolsDefsMoveNodeOneLevelDown;
945   InsertBehindMenuItem.Caption := lisCodeToolsDefsInsertNodeBelow;
946   InsertAsChildMenuItem.Caption := lisCodeToolsDefsInsertNodeAsChild;
947   DeleteNodeMenuItem.Caption := lisCodeToolsDefsDeleteNode;
948   ConvertActionMenuItem.Caption := lisCodeToolsDefsConvertNode;
949 
950   // insert node behind submenu
951   InsertBehindDefineMenuItem.Caption := lisCodeToolsDefsDefine;
952   InsertBehindDefineRecurseMenuItem.Caption := lisCodeToolsDefsDefineRecurse;
953   InsertBehindUndefineMenuItem.Caption := lisCodeToolsDefsUndefine;
954   InsertBehindUndefineRecurseMenuItem.Caption := lisCodeToolsDefsUndefineRecurse;
955   InsertBehindUndefineAllMenuItem.Caption := lisCodeToolsDefsUndefineAll;
956   InsertBehindBlockMenuItem.Caption := lisCodeToolsDefsBlock;
957   InsertBehindDirectoryMenuItem.Caption := lisCodeToolsDefsInsertBehindDirectory;
958   InsertBehindIfMenuItem.Caption := lisCodeToolsDefsIf;
959   InsertBehindIfDefMenuItem.Caption := lisCodeToolsDefsIfDef;
960   InsertBehindIfNotDefMenuItem.Caption := lisCodeToolsDefsIfNDef;
961   InsertBehindElseIfMenuItem.Caption := lisCodeToolsDefsElseIf;
962   InsertBehindElseMenuItem.Caption := lisCodeToolsDefsElse;
963 
964   // insert node as child submenu
965   InsertAsChildDefineMenuItem.Caption := lisCodeToolsDefsDefine;
966   InsertAsChildDefineRecurseMenuItem.Caption := lisCodeToolsDefsDefineRecurse;
967   InsertAsChildUndefineMenuItem.Caption := lisCodeToolsDefsUndefine;
968   InsertAsChildUndefineRecurseMenuItem.Caption := lisCodeToolsDefsUndefineRecurse;
969   InsertAsChildUndefineAllMenuItem.Caption := lisCodeToolsDefsUndefineAll;
970   InsertAsChildBlockMenuItem.Caption := lisCodeToolsDefsBlock;
971   InsertAsChildDirectoryMenuItem.Caption := lisCodeToolsDefsInsertBehindDirectory;
972   InsertAsChildIfMenuItem.Caption := lisCodeToolsDefsIf;
973   InsertAsChildIfDefMenuItem.Caption := lisCodeToolsDefsIfDef;
974   InsertAsChildIfNotDefMenuItem.Caption := lisCodeToolsDefsIfNDef;
975   InsertAsChildElseIfMenuItem.Caption := lisCodeToolsDefsElseIf;
976   InsertAsChildElseMenuItem.Caption := lisCodeToolsDefsElse;
977 
978   // convert node sub menu
979   ConvertActionToDefineMenuItem.Caption := lisCodeToolsDefsDefine;
980   ConvertActionToDefineRecurseMenuItem.Caption := lisCodeToolsDefsDefineRecurse;
981   ConvertActionToUndefineMenuItem.Caption := lisCodeToolsDefsUndefine;
982   ConvertActionToUndefineRecurseMenuItem.Caption := lisCodeToolsDefsUndefineRecurse;
983   ConvertActionToUndefineAllMenuItem.Caption := lisCodeToolsDefsUndefineAll;
984   ConvertActionToBlockMenuItem.Caption := lisCodeToolsDefsBlock;
985   ConvertActionToDirectoryMenuItem.Caption := lisCodeToolsDefsInsertBehindDirectory;
986   ConvertActionToIfMenuItem.Caption := lisCodeToolsDefsIf;
987   ConvertActionToIfDefMenuItem.Caption := lisCodeToolsDefsIfDef;
988   ConvertActionToIfNotDefMenuItem.Caption := lisCodeToolsDefsIfNDef;
989   ConvertActionToElseIfMenuItem.Caption := lisCodeToolsDefsElseIf;
990   ConvertActionToElseMenuItem.Caption := lisCodeToolsDefsElse;
991 
992   // tools
993   ToolsMenuItem.Caption := lisCTDefsTools;
994   OpenPreviewMenuItem.Caption := lisCTDefsOpenPreview;
995 
996   // templates
997   InsertTemplateMenuItem.Caption := lisCodeToolsDefsInsertTemplate;
998 
999   // FPC templates
1000   InsertFPCProjectDefinesTemplateMenuItem.Caption := lisCodeToolsDefsInsertFreePascalProjectTe;
1001   InsertFPCompilerDefinesTemplateMenuItem.Caption := lisCodeToolsDefsInsertFreePascalCompilerT;
1002   InsertFPCSourceDirTemplateMenuItem.Caption := lisCodeToolsDefsInsertFreePascalSVNSource;
1003 
1004   // Delphi 5 templates
1005   InsertDelphi5CompilerDefinesTemplateMenuItem.Caption := lisCodeToolsDefsInsertDelphi5CompilerTemp;
1006   InsertDelphi5DirectoryTemplateMenuItem.Caption := lisCodeToolsDefsInsertDelphi5DirectoryTem;
1007   InsertDelphi5ProjectTemplateMenuItem.Caption := lisCodeToolsDefsInsertDelphi5ProjectTempl;
1008 
1009   // Delphi 6 templates
1010   InsertDelphi6CompilerDefinesTemplateMenuItem.Caption := lisCodeToolsDefsInsertDelphi6CompilerTemp;
1011   InsertDelphi6DirectoryTemplateMenuItem.Caption := lisCodeToolsDefsInsertDelphi6DirectoryTem;
1012   InsertDelphi6ProjectTemplateMenuItem.Caption := lisCodeToolsDefsInsertDelphi6ProjectTempl;
1013 
1014   // Delphi 7 templates
1015   InsertDelphi7CompilerDefinesTemplateMenuItem.Caption := lisCodeToolsDefsInsertDelphi7CompilerTemp;
1016   InsertDelphi7DirectoryTemplateMenuItem.Caption := lisCodeToolsDefsInsertDelphi7DirectoryTem;
1017   InsertDelphi7ProjectTemplateMenuItem.Caption := lisCodeToolsDefsInsertDelphi7ProjectTempl;
1018 
1019   // Kylix 3 templates
1020   InsertKylix3CompilerDefinesTemplateMenuItem.Caption := lisCodeToolsDefsInsertKylix3CompilerTemp;
1021   InsertKylix3DirectoryTemplateMenuItem.Caption := lisCodeToolsDefsInsertKylix3DirectoryTem;
1022   InsertKylix3ProjectTemplateMenuItem.Caption := lisCodeToolsDefsInsertKylix3ProjectTempl;
1023 
1024   // selected item
1025   SelectedItemGroupBox.Caption:=lisCodeToolsDefsSelectedNode;
1026 
1027   NameLabel.Caption:=lisCodeToolsDefsName;
1028   DescriptionLabel.Caption:=lisCodeToolsDefsDescription;
1029   VariableLabel.Caption:=lisCodeToolsDefsVariable;
1030 
1031   ValueNotebook.Page[0].Caption := lisCodeToolsDefsValueAsText;
1032   ValueNotebook.Page[1].Caption := lisCodeToolsDefsValueAsFilePaths;
1033   ValueNotebook.PageIndex := 0;
1034 
1035   MoveFilePathUpBitBtn.Caption:=lisUp;
1036   MoveFilePathDownBitBtn.Caption:=lisDown;
1037   DeleteFilePathBitBtn.Caption:=lisDelete;
1038   InsertFilePathBitBtn.Caption:=lisInsert;
1039 
1040   DefineTreeView.Images := IDEImages.Images_24;
1041   DefineTreeView.StateImages := IDEImages.Images_16;
1042 
1043   DefineActionImages[Low(TDefineAction)] := -1;
1044   for DefAction := Succ(Low(TDefineAction)) to High(TDefineAction) do
1045     DefineActionImages[DefAction] := IDEImages.LoadImage('da_' + LowerCase(DefineActionNames[DefAction]), 24);
1046 
1047   AutogeneratedImage := IDEImages.LoadImage('laz_wand');
1048 end;
1049 
TCodeToolsDefinesEditor.CreateSeperatornull1050 function TCodeToolsDefinesEditor.CreateSeperator : TMenuItem;
1051 begin
1052   Result := TMenuItem.Create(Self);
1053   Result.Caption := '-';
1054 end;
1055 
1056 procedure TCodeToolsDefinesEditor.SetTransferMacros(
1057   const AValue: TTransferMacroList);
1058 begin
1059   FTransferMacros:=AValue;
1060 end;
1061 
1062 procedure TCodeToolsDefinesEditor.ValueAsPathToValueAsText;
1063 var s: string;
1064   i, j, l: integer;
1065 begin
1066   s:=ValueAsFilePathsSynEdit.Text;
1067   l:=length(s);
1068   // replace line ends with semicolon
1069   i:=1;
1070   j:=1;
1071   while i<=l do begin
1072     if s[i] in [#10,#13] then begin
1073       inc(i);
1074       if (i<l) and (s[i] in [#10,#13]) and (s[i-1]<>s[i]) then begin
1075         inc(i);
1076       end;
1077       s[j]:=';';
1078       inc(j);
1079     end else begin
1080       s[j]:=s[i];
1081       inc(i);
1082       inc(j);
1083     end;
1084   end;
1085   dec(j);
1086   while (j>=1) and (s[j]=';') do dec(j);
1087   SetLength(s,j);
1088   ValueAsTextSynEdit.Text:=s;
1089 end;
1090 
1091 procedure TCodeToolsDefinesEditor.SaveSelectedValues;
1092 var
1093   ATreeNode: TTreeNode;
1094   ADefNode: TDefineTemplate;
1095   s: string;
1096   l: integer;
1097 begin
1098   ATreeNode:=FLastSelectedNode;
1099   if (ATreeNode<>nil) then begin
1100     ADefNode:=TDefineTemplate(ATreeNode.Data);
1101     if (not ADefNode.IsAutoGenerated) then begin
1102       ADefNode.Name:=NameEdit.Text;
1103       ATreeNode.Text:=ADefNode.Name;
1104       ADefNode.Variable:=VariableEdit.Text;
1105       ADefNode.Description:=DescriptionEdit.Text;
1106       if ValueNoteBook.PageIndex=1 then
1107         ValueAsPathToValueAsText;
1108       s:=ValueAsTextSynEdit.Text;
1109       l:=length(s);
1110       if (l>0) and (s[l] in [#13,#10]) then begin
1111         // remove line end at end of Text, that was added automatically
1112         dec(l);
1113         if (l>0) and (s[l] in [#13,#10]) and (s[l]<>s[l+1]) then
1114           dec(l);
1115         SetLength(s,l);
1116       end;
1117       ADefNode.Value:=s;
1118     end;
1119     FLastSelectedNode:=nil;
1120   end;
1121 end;
1122 
1123 procedure TCodeToolsDefinesEditor.ShowSelectedValues;
1124 var
1125   SelTreeNode: TTreeNode;
1126   SelDefNode: TDefineTemplate;
1127 begin
1128   SelTreeNode:=DefineTreeView.Selected;
1129   if SelTreeNode<>FLastSelectedNode then begin
1130     SaveSelectedValues;
1131   end;
1132   if SelTreeNode<>nil then begin
1133     SelDefNode:=TDefineTemplate(SelTreeNode.Data);
1134     SetValuesEditable(not SelDefNode.IsAutoGenerated);
1135     NameEdit.Text:=SelDefNode.Name;
1136     DescriptionEdit.Text:=SelDefNode.Description;
1137     VariableEdit.Text:=SelDefNode.Variable;
1138     ValueAsTextSynEdit.Text:=SelDefNode.Value;
1139     ValueAsFilePathsSynEdit.Text:=ValueToFilePathText(SelDefNode.Value);
1140     if SelDefNode.IsAutoGenerated then begin
1141       //ValueAsTextSynEdit.Options:=ValueAsTextSynEdit.Options+[eoNoCaret];
1142       ValueAsTextSynEdit.ReadOnly:=true;
1143     end else begin
1144       //ValueAsTextSynEdit.Options:=ValueAsTextSynEdit.Options-[eoNoCaret];
1145       ValueAsTextSynEdit.ReadOnly:=false;
1146     end;
1147     ValueAsFilePathsSynEdit.Options:=ValueAsTextSynEdit.Options;
1148     ValueAsFilePathsSynEdit.ReadOnly:=ValueAsTextSynEdit.ReadOnly;
1149   end else begin
1150     SetValuesEditable(false);
1151     NameEdit.Text:='';
1152     DescriptionEdit.Text:='';
1153     VariableEdit.Text:='';
1154     ValueAsTextSynEdit.Text:='';
1155     ValueAsFilePathsSynEdit.Text:='';
1156   end;
1157   SetTypeLabel;
1158   FLastSelectedNode:=SelTreeNode;
1159 end;
1160 
1161 procedure TCodeToolsDefinesEditor.SetTypeLabel;
1162 var
1163   SelTreeNode: TTreeNode;
1164   SelDefNode: TDefineTemplate;
1165   s: string;
1166 begin
1167   SelTreeNode:=DefineTreeView.Selected;
1168   if SelTreeNode<>nil then begin
1169     SelDefNode:=TDefineTemplate(SelTreeNode.Data);
1170     s:=Format(lisCodeToolsDefsAction, [DefineActionNames[SelDefNode.Action]]);
1171     if SelDefNode.IsAutoGenerated then
1172       s:=Format(lisCodeToolsDefsautoGenerated, [s]);
1173   end else begin
1174     s:=lisCodeToolsDefsnoneSelected;
1175   end;
1176   TypeLabel.Caption:=s;
1177 end;
1178 
ValueToFilePathTextnull1179 function TCodeToolsDefinesEditor.ValueToFilePathText(const AValue: string
1180   ): string;
1181 var i: integer;
1182 begin
1183   Result:=AValue;
1184   for i:=1 to length(Result) do
1185     if Result[i]=';' then Result[i]:=#13;
1186 end;
1187 
1188 procedure TCodeToolsDefinesEditor.InsertNewNode(Behind: boolean;
1189   DefAction: TDefineAction);
1190 var SelTreeNode, NodeInFront, ParentNode,
1191   NewTreeNode: TTreeNode;
1192   NewDefNode: TDefineTemplate;
1193   NewName, NewDescription, NewVariable, NewValue: string;
1194 begin
1195   SelTreeNode:=DefineTreeView.Selected;
1196   SaveSelectedValues;
1197   NodeInFront:=nil;
1198   ParentNode:=nil;
1199   if SelTreeNode<>nil then begin
1200     // there is an selected node
1201     if Behind then begin
1202       // insert behind selected node
1203       NodeInFront:=SelTreeNode;
1204       ParentNode:=NodeInFront.Parent;
1205     end else begin
1206       // insert as last child of selected node
1207       ParentNode:=SelTreeNode;
1208       NodeInFront:=ParentNode.GetFirstChild;
1209       if NodeInFront<>nil then begin
1210         while NodeInFront.GetNextSibling<>nil do
1211           NodeInFront:=NodeInFront.GetNextSibling;
1212       end;
1213     end;
1214   end else begin
1215     // no node selected, add as last root node
1216     NodeInFront:=DefineTreeView.Items.GetLastNode;
1217   end;
1218   if (ParentNode<>nil) and (TDefineTemplate(ParentNode.Data).IsAutoGenerated)
1219   then begin
1220     IDEMessageDialog(lisCodeToolsDefsInvalidParent,
1221       Format(lisCodeToolsDefsAutoCreatedNodesReadOnly, [LineEnding]),
1222       mtInformation, [mbCancel]);
1223     exit;
1224   end;
1225   if (ParentNode<>nil)
1226   and (not (TDefineTemplate(ParentNode.Data).Action in DefineActionBlocks)) then
1227   begin
1228     IDEMessageDialog(lisCodeToolsDefsInvalidParentNode,
1229       lisCodeToolsDefsParentNodeCanNotContainCh,
1230       mtInformation,[mbCancel]);
1231     exit;
1232   end;
1233   NewName:=FindUniqueName;
1234   NewDescription:=NewName;
1235   NewVariable:='';
1236   NewValue:='';
1237   NewDefNode:=TDefineTemplate.Create(NewName,NewDescription,NewVariable,
1238                                      NewValue,DefAction);
1239   NewDefNode.Owner:=CodeToolsOpts;
1240   // add node to treeview
1241   if (NodeInFront<>nil) then
1242     // insert in front
1243     NewTreeNode:=DefineTreeView.Items.InsertObjectBehind(
1244                   NodeInFront,NewName,NewDefNode)
1245   else
1246     // add as last child
1247     NewTreeNode:=DefineTreeView.Items.AddChildObject(ParentNode,NewName,
1248                                                      NewDefNode);
1249 
1250   // add node to define tree
1251   if NodeInFront<>nil then
1252     NewDefNode.InsertBehind(TDefineTemplate(NodeInFront.Data))
1253   else if ParentNode<>nil then
1254     TDefineTemplate(ParentNode.Data).AddChild(NewDefNode)
1255   else
1256     FDefineTree.Add(NewDefNode);
1257 
1258   SetNodeImages(NewTreeNode,true);
1259   DefineTreeView.Selected:=NewTreeNode;
1260   ShowSelectedValues;
1261 end;
1262 
1263 procedure TCodeToolsDefinesEditor.InsertTemplate(NewTemplate: TDefineTemplate);
1264 
1265   procedure AddChilds(ATreeNode: TTreeNode);
1266   var ADefNode, ChildDefNode: TDefineTemplate;
1267     ChildTreeNode: TTreeNode;
1268   begin
1269     if ATreeNode=nil then exit;
1270     ADefNode:=TDefineTemplate(ATreeNode.Data);
1271     ChildDefNode:=ADefNode.FirstChild;
1272     while ChildDefNode<>nil do begin
1273       ChildTreeNode:=DefineTreeView.Items.AddChildObject(ATreeNode,
1274                                                 ChildDefNode.Name,ChildDefNode);
1275       AddChilds(ChildTreeNode);
1276       ChildDefNode:=ChildDefNode.Next;
1277     end;
1278   end;
1279 
1280 var
1281   SelTreeNode, NewTreeNode: TTreeNode;
1282   SelDefNode: TDefineTemplate;
1283 begin
1284   SaveSelectedValues;
1285   if NewTemplate=nil then exit;
1286   NewTemplate.RemoveFlags([dtfAutoGenerated]);
1287   FLastSelectedNode:=nil;
1288   SelTreeNode:=DefineTreeView.Selected;
1289   if SelTreeNode<>nil then begin
1290     // insert behind selected node
1291     SelDefNode:=TDefineTemplate(SelTreeNode.Data);
1292     // insert in TreeView
1293     NewTreeNode:=DefineTreeView.Items.InsertObjectBehind(SelTreeNode,
1294                            NewTemplate.Name,NewTemplate);
1295     // insert in DefineTree
1296     NewTemplate.InsertBehind(SelDefNode);
1297   end else begin
1298     // add as last root node
1299     // add in TreeView
1300     NewTreeNode:=DefineTreeView.Items.AddObject(nil,NewTemplate.Name,NewTemplate);
1301     // add in DefineTree
1302     DefineTree.Add(NewTemplate);
1303   end;
1304   // add children to TreeView
1305   AddChilds(NewTreeNode);
1306   // show and select
1307   SetNodeImages(NewTreeNode,true);
1308   NewTreeNode.Selected:=true;
1309   ShowSelectedValues;
1310 end;
1311 
FindUniqueNamenull1312 function TCodeToolsDefinesEditor.FindUniqueName: string;
1313 var i: integer;
1314 begin
1315   i:=1;
1316   while (DefineTree.FindDefineTemplateByName(lisCodeToolsDefsNewNode+IntToStr(i
1317     ), false)<>nil)
1318   do inc(i);
1319   Result:=lisCodeToolsDefsNewNode+IntToStr(i);
1320 end;
1321 
TCodeToolsDefinesEditor.ConsistencyChecknull1322 function TCodeToolsDefinesEditor.ConsistencyCheck: integer;
1323 
CheckNodenull1324   function CheckNode(ATreeNode: TTreeNode): integer;
1325   var ADefNode, DummyDefNode: TDefineTemplate;
1326   begin
1327     if ATreeNode=nil then exit(0);
1328     ADefNode:=TDefineTemplate(ATreeNode.Data);
1329     //debugln(' CheckNode "',ATreeNode.Text,'" "',ADefNode.Name,'"');
1330     if ADefNode=nil then begin
1331       Result:=-1;  exit;
1332     end;
1333     if (ATreeNode.GetPrevSibling<>nil)
1334     and (TDefineTemplate(ATreeNode.GetPrevSibling.Data)<>ADefNode.Prior) then
1335     begin
1336       Result:=-2;  exit;
1337     end;
1338     if (ATreeNode.GetNextSibling<>nil)
1339     and (TDefineTemplate(ATreeNode.GetNextSibling.Data)<>ADefNode.Next) then
1340     begin
1341       DbgOut(' ERROR: ',ATreeNode.GetNextSibling.Text,' ');
1342       if ADefNode.Next<>nil then DbgOut('ADefNode.Next=',ADefNode.Next.Name,' ')
1343       else DbgOut('ADefNode.Next=nil ');
1344       DummyDefNode:=TDefineTemplate(ATreeNode.GetNextSibling.Data);
1345       if DummyDefNode<>nil then
1346         DebugLn('ATreeNode.GetNextSibling.Next=',DummyDefNode.Name)
1347       else
1348         DebugLn('ATreeNode.GetNextSibling.Next=nil');
1349       Result:=-3;  exit;
1350     end;
1351     if (ATreeNode.GetFirstChild<>nil)
1352     and (TDefineTemplate(ATreeNode.GetFirstChild.Data)<>ADefNode.FirstChild)
1353     then begin
1354       Result:=-4;  exit;
1355     end;
1356     Result:=CheckNode(ATreeNode.GetFirstChild);
1357     if Result<0 then exit;
1358     Result:=CheckNode(ATreeNode.GetNextSibling);
1359     if Result<0 then exit;
1360   end;
1361 
1362 begin
1363   DefineTreeView.ConsistencyCheck;
1364   DefineTree.ConsistencyCheck;
1365   Result:=CheckNode(DefineTreeView.Items.GetFirstNode);
1366   if Result<0 then begin
1367     dec(Result,300000);
1368     exit;
1369   end;
1370   Result:=0;
1371 end;
1372 
1373 procedure TCodeToolsDefinesEditor.SetValuesEditable(AValue: boolean);
1374 begin
1375   SelectedItemGroupBox.Enabled:=true;
1376   TypeLabel.Enabled:=true;
1377   NameLabel.Enabled:=AValue;
1378   NameEdit.Enabled:=AValue;
1379   DescriptionLabel.Enabled:=AValue;
1380   DescriptionEdit.Enabled:=AValue;
1381   VariableLabel.Enabled:=AValue;
1382   VariableEdit.Enabled:=AValue;
1383   ValueAsTextSynEdit.ReadOnly:=not AValue;
1384   ValueAsFilePathsSynEdit.ReadOnly:=not AValue;
1385   MoveFilePathUpBitBtn.Enabled:=AValue;
1386   MoveFilePathDownBitBtn.Enabled:=AValue;
1387   DeleteFilePathBitBtn.Enabled:=AValue;
1388   InsertFilePathBitBtn.Enabled:=AValue;
1389 end;
1390 
1391 procedure TCodeToolsDefinesEditor.SetOptions(ACodeToolBoss: TCodeToolManager);
1392 begin
1393   FLastSelectedNode:=nil;
1394   FBoss:=ACodeToolBoss;
1395   FDefineTree.Assign(ACodeToolBoss.DefineTree);
1396   RebuildDefineTreeView(DefineTreeView,DefineTree.RootTemplate);
1397   ShowSelectedValues;
1398 end;
1399 
1400 constructor TCodeToolsDefinesEditor.Create(TheOwner: TComponent);
1401 begin
1402   inherited Create(TheOwner);
1403 
1404   IDEDialogLayoutList.ApplyLayout(Self,500,460);
1405 
1406   Caption:=lisCodeToolsDefsCodeToolsDefinesEditor;
1407 
1408   CreateComponents;
1409   MainSplitter.SetSplitterPosition(
1410          Max(20,Min(ClientHeight-100,CodeToolsOpts.DefinesEditMainSplitterTop)));
1411 
1412   FDefineTree:=TDefineTree.Create;
1413 
1414   EditorOpts.GetSynEditSettings(ValueAsTextSynEdit);
1415   ValueAsTextSynEdit.Gutter.Visible:=false;
1416   EditorOpts.GetSynEditSettings(ValueAsFilePathsSynEdit);
1417   ValueAsFilePathsSynEdit.Gutter.Visible:=false;
1418 end;
1419 
1420 destructor TCodeToolsDefinesEditor.Destroy;
1421 begin
1422   FDefineTree.Free;
1423   inherited Destroy;
1424 end;
1425 
1426 end.
1427 
1428