1 {
2 /***************************************************************************
3                               CodeExplOpts.pas
4                              -------------------
5 
6  ***************************************************************************/
7 
8  ***************************************************************************
9  *                                                                         *
10  *   This source is free software; you can redistribute it and/or modify   *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  *   This code is distributed in the hope that it will be useful, but      *
16  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
18  *   General Public License for more details.                              *
19  *                                                                         *
20  *   A copy of the GNU General Public License is available on the World    *
21  *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
22  *   obtain it by writing to the Free Software Foundation,                 *
23  *   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.   *
24  *                                                                         *
25  ***************************************************************************
26 
27   Abstract:
28     Dialog for the options of the code explorer.
29 }
30 unit CodeExplOpts;
31 
32 {$mode objfpc}{$H+}
33 
34 interface
35 
36 uses
37   // RTL + FCL
38   Classes, SysUtils, Laz_AVL_Tree,
39   // LCL
40   LCLProc, Forms, Controls, Graphics, Dialogs, Buttons,
41   // CodeTools
42   BasicCodeTools, FileProcs,
43   // LazUtils
44   AvgLvlTree, Laz2_XMLCfg, LazFileUtils, LazFileCache,
45   // IDEIntf
46   IDEOptionsIntf, IDEOptEditorIntf,
47   // IDE
48   LazConf, IDEProcs, LazarusIDEStrConsts;
49 
50 type
51   { TCodeExplorerOptions }
52 
53   TCodeExplorerPage = (
54     cepNone,
55     cepCode,
56     cepDirectives
57     );
58 
59   TCodeExplorerRefresh = (
60     cerManual,  // only via refresh button
61     cerSwitchEditorPage,// everytime the source editor switches to another page
62     cerOnIdle // on idle
63     );
64 
65   TCodeExplorerMode = (
66     cemCategory, // Category - Delphi like
67     cemSource    // Follows Source Code
68   );
69 
70   TCodeExplorerCategory = (
71     cecNone,
72     cecUses,
73     cecTypes,
74     cecVariables,
75     cecConstants,
76     cecProperties,
77     cecProcedures,
78     cecCodeObserver,
79     cecSurrounding
80     );
81   TCodeExplorerCategories = set of TCodeExplorerCategory;
82 
83   TCEObserverCategory = (
84     cefcLongProcs,    // procedures with many lines of code
85     cefcLongParamLists, // procedures with many parameters
86     cefcEmptyProcs,  // procs without code (can contain comments)
87     cefcNestedProcs, // procs with a lot of nested sub procs
88     cefcUnnamedConsts, // numbers, strings in statements
89     cefcEmptyBlocks,   // empty begin..end block (not even a comment)
90     cefcWrongIndentation, // possible missing lines or begin blocks
91     cefcPublishedPropWithoutDefault, // published properties without default specifier
92     cefcUnsortedClassVisibility, // public,private,protected,published keywords are not sorted
93     cefcEmptyClassSections, // empty public,private,protected,published section
94     cefcUnsortedClassMembers, // member of a public,private,protected,published section is not sorted alphabetically
95     cefcToDos  // todo comment
96     );
97   TCEObserverCategories = set of TCEObserverCategory;
98 
99   TCEObserverCategoryGroup = (ocgComplexity, ocgEmpty, ocgStyle, ocgOther);
100 
101 const
102   FirstCodeExplorerCategory = cecUses;
103   DefaultCodeExplorerCategories = [cecUses,
104                cecTypes,cecVariables,cecConstants,cecProcedures];
105   cefcAll = [low(TCEObserverCategory)..high(TCEObserverCategory)];
106   DefaultCodeExplorerPage = cepCode;
107   DefaultCodeObserverCategories = [
108     cefcLongProcs,
109     cefcEmptyProcs,
110     cefcUnnamedConsts,
111     cefcEmptyBlocks,
112     cefcWrongIndentation,
113     cefcPublishedPropWithoutDefault,
114     cefcToDos
115     ];
116   DefaultCOLongProcLineCount = 50;
117   DefaultCOLongParamListCount = 6;
118   DefaultCONestedProcCount = 3;
119   DefaultCOureCharConst = false;
120   DefaultCOIgnoreConstants: array[1..2] of ansistring // Note: keep this asciiz
121     = (
122     '0',
123     '1'
124     );
125   DefaultCOIgnoreConstInFuncs: array[1..15] of ansistring // Note: keep this asciiz
126     = (
127     'Assert',
128     'Debug',
129     'DebugLn',
130     'DbgOut',
131     'write',
132     'writeln',
133     'Format',
134     'FormatBuf',
135     'StrFmt',
136     'StrLFmt',
137     'FmtStr',
138     'FloatToStrF',
139     'FloatToStr',
140     'CurrToStrF',
141     'FormatDateTime'
142     );
143 
144 type
145 
146   TCodeExplorerOptions = class(TAbstractIDEEnvironmentOptions)
147   private
148     FCategories: TCodeExplorerCategories;
149     FChangeStep: integer;
150     FObserveCharConst: boolean;
151     FCOIgnoreConstInFuncs: TStringToStringTree;
152     FLongParamListCount: integer;
153     FLongProcLineCount: integer;
154     FNestedProcCount: integer;
155     FObserverCategories: TCEObserverCategories;
156     FFollowCursor: boolean;
157     FMode : TCodeExplorerMode;
158     FObserverIgnoreConstants: TAvlTree;// tree of AnsiString
159     FOptionsFilename: string;
160     FPage: TCodeExplorerPage;
161     FRefresh: TCodeExplorerRefresh;
162     FSavedChangeStep: integer;
GetModifiednull163     function GetModified: boolean;
164     procedure SetCategories(const AValue: TCodeExplorerCategories);
165     procedure SetFollowCursor(const AValue: boolean);
166     procedure SetLongParamListCount(const AValue: integer);
167     procedure SetLongProcLineCount(const AValue: integer);
168     procedure SetMode(const AValue: TCodeExplorerMode);
169     procedure SetModified(AValue: boolean);
170     procedure SetNestedProcCount(const AValue: integer);
171     procedure SetObserveCharConst(const AValue: boolean);
172     procedure SetObserverCategories(const AValue: TCEObserverCategories);
173     procedure SetPage(AValue: TCodeExplorerPage);
174     procedure SetRefresh(const AValue: TCodeExplorerRefresh);
175   public
GetGroupCaptionnull176     class function GetGroupCaption:string; override;
GetInstancenull177     class function GetInstance: TAbstractIDEOptions; override;
178     procedure DoAfterWrite(Restore: boolean); override;
179   public
180     constructor Create;
181     destructor Destroy; override;
182     procedure Clear;
183     procedure Assign(Source: TPersistent); override;
184     procedure Load;
185     procedure Save;
186     procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string);
187     procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string);
188     procedure IncreaseChangeStep;
189     property Modified: boolean read GetModified write SetModified;
190   public
191     // observer: ignore constants
CreateListOfCOIgnoreConstantsnull192     function CreateListOfCOIgnoreConstants: TStrings;
193     procedure SetListOf_COIgnoreConstants(List: TStrings; Add: boolean);
COIgnoreConstantnull194     function COIgnoreConstant(p: PChar): boolean;// test if atom is in COIgnoreConstants
COIgnoreConstants_AreDefaultnull195     function COIgnoreConstants_AreDefault(Exactly: boolean): boolean; // true if COIgnoreConstants contain/are default values
COIgnoreConstant_IsDefaultnull196     function COIgnoreConstant_IsDefault(const Atom: string): boolean; // true if Atom is in default values
197     procedure Add_COIgnoreConstant(const Atom: string);
198     procedure Clear_COIgnoreConstants;
199     procedure LoadDefaults_COIgnoreConstants;
200   public
201     // observer: ignore constants in functions
CreateListOfCOIgnoreConstInFuncsnull202     function CreateListOfCOIgnoreConstInFuncs: TStrings;
203     procedure SetListOf_COIgnoreConstInFuncs(List: TStrings; Add: boolean);
COIgnoreConstInFuncnull204     function COIgnoreConstInFunc(const Func: string): boolean;// test if function is in COIgnoreConstInFuncs
205     function COIgnoreConstInFuncs_AreDefault(Exactly: boolean): boolean; // true if COIgnoreConstInFuncs contain/are default values
COIgnoreConstInFuncs_IsDefaultnull206     function COIgnoreConstInFuncs_IsDefault(const Func: string): boolean; // true if Atom is in default values
207     procedure Add_COIgnoreConstInFuncs(const Func: string);
208     procedure Clear_COIgnoreConstInFuncs;
209     procedure LoadDefaults_COIgnoreConstInFuncs;
210   public
211     property Refresh: TCodeExplorerRefresh read FRefresh write SetRefresh default cerSwitchEditorPage;
212     property Mode: TCodeExplorerMode read FMode write SetMode default cemCategory;
213     property OptionsFilename: string read FOptionsFilename write FOptionsFilename;
214     property FollowCursor: boolean read FFollowCursor write SetFollowCursor default true;
215     property Categories: TCodeExplorerCategories read FCategories write SetCategories default DefaultCodeExplorerCategories;
216     property Page: TCodeExplorerPage read FPage write SetPage default DefaultCodeExplorerPage;
217     property ChangeStep: integer read FChangeStep write FChangeStep;
218   public
219     // Observer
220     property ObserveCharConst: boolean read FObserveCharConst write SetObserveCharConst default DefaultCOureCharConst;
221     property ObserverCategories: TCEObserverCategories read FObserverCategories write SetObserverCategories default DefaultCodeObserverCategories;
222     property ObserverIgnoreConstants: TAvlTree read FObserverIgnoreConstants;
223     property COIgnoreConstInFuncs: TStringToStringTree read FCOIgnoreConstInFuncs;
224     property LongParamListCount: integer read FLongParamListCount write SetLongParamListCount default DefaultCOLongParamListCount;
225     property LongProcLineCount: integer read FLongProcLineCount write SetLongProcLineCount default DefaultCOLongProcLineCount;
226     property NestedProcCount: integer read FNestedProcCount write SetNestedProcCount default DefaultCONestedProcCount;
227   end;
228 
229 const
230   CodeExplorerVersion = 1;
231 
232   cerDefault = cerSwitchEditorPage;
233 
234   CodeExplorerPageNames: array[TCodeExplorerPage] of string = (
235     '?',
236     'Code',
237     'Directives'
238     );
239   CodeExplorerRefreshNames: array[TCodeExplorerRefresh] of string = (
240     'Manual',
241     'SwitchEditorPage',
242     'OnIdle'
243     );
244   CodeExplorerModeNames: array[TCodeExplorerMode] of string = (
245     'Category',
246     'Source'
247     );
248   CodeExplorerCategoryNames: array[TCodeExplorerCategory] of string = (
249     '?',
250     'Uses',
251     'Types',
252     'Variables',
253     'Constants',
254     'Properties',
255     'Procedures',
256     'CodeObserver',
257     'Surrounding'
258     );
259   CodeObserverCategoryNames: array[TCEObserverCategory] of string = (
260     'LongProcs',
261     'LongParamLists',
262     'EmptyProcs',
263     'NestedProcs',
264     'UnnamedConsts',
265     'EmptyBlocks',
266     'WrongIndentation',
267     'PublishedPropWithoutDefault',
268     'UnsortedClassVisibility',
269     'EmptyClassSections',
270     'UnsortedClassMembers',
271     'ToDos'
272     );
273 
274 var
275   CodeExplorerOptions: TCodeExplorerOptions = nil; // set by the IDE
276 
CodeExplorerPageNameToEnumnull277 function CodeExplorerPageNameToEnum(const s: string): TCodeExplorerPage;
CodeExplorerRefreshNameToEnumnull278 function CodeExplorerRefreshNameToEnum(const s: string): TCodeExplorerRefresh;
CodeExplorerModeNameToEnumnull279 function CodeExplorerModeNameToEnum(const s: string): TCodeExplorerMode;
CodeExplorerCategoryNameToEnumnull280 function CodeExplorerCategoryNameToEnum(const s: string): TCodeExplorerCategory;
CodeExplorerLocalizedStringnull281 function CodeExplorerLocalizedString(const c: TCodeExplorerCategory): string;
CodeObserverCatNameToEnumnull282 function CodeObserverCatNameToEnum(const s: string): TCEObserverCategory;
CodeExplorerLocalizedStringnull283 function CodeExplorerLocalizedString(const c: TCEObserverCategory): string;
dbgsnull284 function dbgs(c: TCodeExplorerCategory): string; overload;
285 
286 implementation
287 
CodeExplorerPageNameToEnumnull288 function CodeExplorerPageNameToEnum(const s: string): TCodeExplorerPage;
289 begin
290   for Result:=Low(TCodeExplorerPage) to High(TCodeExplorerPage) do
291     if SysUtils.CompareText(CodeExplorerPageNames[Result],s)=0 then exit;
292   Result:=DefaultCodeExplorerPage;
293 end;
294 
CodeExplorerRefreshNameToEnumnull295 function CodeExplorerRefreshNameToEnum(const s: string): TCodeExplorerRefresh;
296 begin
297   for Result:=Low(TCodeExplorerRefresh) to High(TCodeExplorerRefresh) do
298     if SysUtils.CompareText(CodeExplorerRefreshNames[Result],s)=0 then exit;
299   Result:=cerDefault;
300 end;
301 
CodeExplorerModeNameToEnumnull302 function CodeExplorerModeNameToEnum(const s: string): TCodeExplorerMode;
303 begin
304   for Result:=Low(TCodeExplorerMode) to High(TCodeExplorerMode) do
305     if SysUtils.CompareText(CodeExplorerModeNames[Result],s)=0 then exit;
306   Result:=cemCategory;
307 end;
308 
CodeExplorerCategoryNameToEnumnull309 function CodeExplorerCategoryNameToEnum(const s: string): TCodeExplorerCategory;
310 begin
311   for Result:=FirstCodeExplorerCategory to High(TCodeExplorerCategory) do
312     if SysUtils.CompareText(CodeExplorerCategoryNames[Result],s)=0 then exit;
313   Result:=cecTypes;
314 end;
315 
CodeExplorerLocalizedStringnull316 function CodeExplorerLocalizedString(const c: TCodeExplorerCategory): string;
317 begin
318   case c of
319   cecUses: Result:=lisCEUses;
320   cecTypes: Result:=lisCETypes;
321   cecVariables: Result:=lisCEVariables;
322   cecConstants: Result:=lisCEConstants;
323   cecProcedures: Result:=lisCEProcedures;
324   cecProperties: Result:=lisCEProperties;
325   cecCodeObserver: Result:=lisCodeObserver;
326   cecSurrounding: Result:=lisCESurrounding;
327   else Result:='?';
328   end;
329 end;
330 
CodeObserverCatNameToEnumnull331 function CodeObserverCatNameToEnum(const s: string): TCEObserverCategory;
332 begin
333   for Result:=low(TCEObserverCategory) to High(TCEObserverCategory) do
334     if SysUtils.CompareText(CodeObserverCategoryNames[Result],s)=0 then exit;
335   Result:=cefcLongProcs;
336 end;
337 
CodeExplorerLocalizedStringnull338 function CodeExplorerLocalizedString(const c: TCEObserverCategory): string;
339 begin
340   case c of
341   cefcLongProcs: Result:=lisCELongProcedures;
342   cefcLongParamLists: Result:=lisCEManyParameters;
343   cefcEmptyProcs: Result:=lisCEEmptyProcedures;
344   cefcNestedProcs: Result:=lisCEManyNestedProcedures;
345   cefcUnnamedConsts: Result:=lisCEUnnamedConstants;
346   cefcEmptyBlocks: Result:=lisCEEmptyBlocks;
347   cefcWrongIndentation: Result:=lisCEWrongIndentation;
348   cefcPublishedPropWithoutDefault: Result:=lisCEPublishedPropertyWithoutDefault;
349   cefcUnsortedClassVisibility: Result:=lisCEUnsortedVisibility;
350   cefcEmptyClassSections: Result:=lisCEEmptyClassSections;
351   cefcUnsortedClassMembers: Result:=lisCEUnsortedMembers;
352   cefcToDos: Result:=lisCEToDos;
353   else Result:='?';
354   end;
355 end;
356 
dbgsnull357 function dbgs(c: TCodeExplorerCategory): string;
358 begin
359   Result:=CodeExplorerCategoryNames[c];
360 end;
361 
362 { TCodeExplorerOptions }
363 
364 procedure TCodeExplorerOptions.SetRefresh(const AValue: TCodeExplorerRefresh);
365 begin
366   if FRefresh=AValue then exit;
367   FRefresh:=AValue;
368   IncreaseChangeStep;
369 end;
370 
371 procedure TCodeExplorerOptions.SetMode(const AValue: TCodeExplorerMode);
372 begin
373   if FMode=AValue then exit;
374   FMode:=AValue;
375   IncreaseChangeStep;
376 end;
377 
378 procedure TCodeExplorerOptions.SetModified(AValue: boolean);
379 begin
380   if AValue then
381     IncreaseChangeStep
382   else
383     FSavedChangeStep:=FChangeStep;
384 end;
385 
386 procedure TCodeExplorerOptions.SetNestedProcCount(const AValue: integer);
387 begin
388   if FNestedProcCount=AValue then exit;
389   FNestedProcCount:=AValue;
390   IncreaseChangeStep;
391 end;
392 
393 procedure TCodeExplorerOptions.SetObserveCharConst(const AValue: boolean);
394 begin
395   if FObserveCharConst=AValue then exit;
396   FObserveCharConst:=AValue;
397   IncreaseChangeStep;
398 end;
399 
400 procedure TCodeExplorerOptions.SetObserverCategories(
401   const AValue: TCEObserverCategories);
402 begin
403   if FObserverCategories=AValue then exit;
404   FObserverCategories:=AValue;
405   IncreaseChangeStep;
406 end;
407 
408 procedure TCodeExplorerOptions.SetPage(AValue: TCodeExplorerPage);
409 begin
410   if FPage=AValue then Exit;
411   FPage:=AValue;
412   IncreaseChangeStep;
413 end;
414 
415 procedure TCodeExplorerOptions.SetFollowCursor(const AValue: boolean);
416 begin
417   if FFollowCursor=AValue then exit;
418   FFollowCursor:=AValue;
419   IncreaseChangeStep;
420 end;
421 
422 procedure TCodeExplorerOptions.SetLongParamListCount(const AValue: integer);
423 begin
424   if FLongParamListCount=AValue then exit;
425   FLongParamListCount:=AValue;
426   IncreaseChangeStep;
427 end;
428 
429 procedure TCodeExplorerOptions.SetLongProcLineCount(const AValue: integer);
430 begin
431   if FLongProcLineCount=AValue then exit;
432   FLongProcLineCount:=AValue;
433   IncreaseChangeStep;
434 end;
435 
436 procedure TCodeExplorerOptions.SetCategories(
437   const AValue: TCodeExplorerCategories);
438 begin
439   if FCategories=AValue then exit;
440   FCategories:=AValue;
441   IncreaseChangeStep;
442 end;
443 
TCodeExplorerOptions.GetModifiednull444 function TCodeExplorerOptions.GetModified: boolean;
445 begin
446   Result:=FSavedChangeStep<>FChangeStep;
447 end;
448 
449 constructor TCodeExplorerOptions.Create;
450 begin
451   FOptionsFilename:=AppendPathDelim(GetPrimaryConfigPath)+'codeexploreroptions.xml';
452   FObserverIgnoreConstants:=TAvlTree.Create(TListSortCompare(@CompareAtom));
453   FCOIgnoreConstInFuncs:=TStringToStringTree.Create(false);
454   Clear;
455   LoadDefaults_COIgnoreConstants;
456   LoadDefaults_COIgnoreConstInFuncs;
457 end;
458 
459 destructor TCodeExplorerOptions.Destroy;
460 begin
461   Clear_COIgnoreConstants;
462   FreeAndNil(FObserverIgnoreConstants);
463   FreeAndNil(FCOIgnoreConstInFuncs);
464   inherited Destroy;
465 end;
466 
TCodeExplorerOptions.GetGroupCaptionnull467 class function TCodeExplorerOptions.GetGroupCaption: string;
468 begin
469   Result := dlgGroupCodeExplorer;
470 end;
471 
TCodeExplorerOptions.GetInstancenull472 class function TCodeExplorerOptions.GetInstance: TAbstractIDEOptions;
473 begin
474   Result := CodeExplorerOptions;
475 end;
476 
477 procedure TCodeExplorerOptions.DoAfterWrite(Restore: boolean);
478 begin
479   if not Restore then
480     Save;
481 end;
482 
483 procedure TCodeExplorerOptions.Clear;
484 begin
485   IncreaseChangeStep;
486   FMode:=cemCategory;
487   FRefresh:=cerDefault;
488   FFollowCursor:=true;
489   FPage:=DefaultCodeExplorerPage;
490   FCategories:=DefaultCodeExplorerCategories;
491   FObserverCategories:=DefaultCodeObserverCategories;
492   FLongProcLineCount:=DefaultCOLongProcLineCount;
493   FLongParamListCount:=DefaultCOLongParamListCount;
494   FNestedProcCount:=DefaultCONestedProcCount;
495   FObserveCharConst:=DefaultCOureCharConst;
496   Clear_COIgnoreConstants;
497   Clear_COIgnoreConstInFuncs;
498 end;
499 
500 procedure TCodeExplorerOptions.Assign(Source: TPersistent);
501 var
502   Src: TCodeExplorerOptions;
503   List: TStrings;
504 begin
505   if Source is TCodeExplorerOptions then begin
506     IncreaseChangeStep;
507     Src:=TCodeExplorerOptions(Source);
508     FRefresh:=Src.Refresh;
509     FMode:=Src.Mode;
510     FFollowCursor:=Src.FollowCursor;
511     FPage:=Src.Page;
512     FCategories:=Src.Categories;
513     FObserverCategories:=Src.ObserverCategories;
514     FLongProcLineCount:=Src.LongProcLineCount;
515     FLongParamListCount:=Src.LongParamListCount;
516     FNestedProcCount:=Src.NestedProcCount;
517     FObserveCharConst:=Src.ObserveCharConst;
518     List:=Src.CreateListOfCOIgnoreConstants;
519     try
520       SetListOf_COIgnoreConstants(List,false);
521     finally
522       List.Free;
523     end;
524     List:=Src.CreateListOfCOIgnoreConstInFuncs;
525     try
526       SetListOf_COIgnoreConstInFuncs(List,false);
527     finally
528       List.Free;
529     end;
530   end else
531     inherited Assign(Source);
532 end;
533 
534 procedure TCodeExplorerOptions.Load;
535 var
536   XMLConfig: TXMLConfig;
537   //FileVersion: integer;
538 begin
539   if not FileExistsUTF8(FOptionsFilename) then
540   begin
541     Clear;
542     LoadDefaults_COIgnoreConstants;
543     LoadDefaults_COIgnoreConstInFuncs;
544     Exit;
545   end;
546   try
547     XMLConfig:=TXMLConfig.Create(FOptionsFilename);
548     //FileVersion:=XMLConfig.GetValue('CodeExplorer/Version/Value',0);
549     LoadFromXMLConfig(XMLConfig,'CodeExplorer/');
550     XMLConfig.Free;
551   except
552     on E: Exception do begin
553       DebugLn('[TCodeExplorerOptions.Load]  error reading "',FOptionsFilename,'" ',E.Message);
554     end;
555   end;
556 end;
557 
558 procedure TCodeExplorerOptions.Save;
559 var
560   XMLConfig: TXMLConfig;
561 begin
562   if FileExistsCached(FOptionsFilename) and not Modified then exit;
563   try
564     InvalidateFileStateCache;
565     XMLConfig:=TXMLConfig.CreateClean(FOptionsFilename);
566     XMLConfig.SetDeleteValue('CodeExplorer/Version/Value',
567       CodeExplorerVersion,0);
568     SaveToXMLConfig(XMLConfig,'CodeExplorer/');
569     XMLConfig.Flush;
570     XMLConfig.Free;
571     Modified:=false;
572   except
573     on E: Exception do begin
574       DebugLn('[TCodeExplorerOptions.Save]  error writing "',FOptionsFilename,'" ',E.Message);
575     end;
576   end;
577 end;
578 
579 procedure TCodeExplorerOptions.LoadFromXMLConfig(XMLConfig: TXMLConfig;
580   const Path: string);
581 var
582   c: TCodeExplorerCategory;
583   f: TCEObserverCategory;
584   CurPath: String;
585   List: TStringList;
586 begin
587   IncreaseChangeStep;
588   Clear;
589   FRefresh:=CodeExplorerRefreshNameToEnum(
590                                    XMLConfig.GetValue(Path+'Refresh/Value',''));
591   FMode:=CodeExplorerModeNameToEnum(
592                                    XMLConfig.GetValue(Path+'Mode/Value',''));
593   FFollowCursor:=XMLConfig.GetValue(Path+'FollowCursor',true);
594   FPage:=CodeExplorerPageNameToEnum(XMLConfig.GetValue(Path+'Page/Value',''));
595 
596   FCategories:=[];
597   for c:=FirstCodeExplorerCategory to high(TCodeExplorerCategory) do
598     if XMLConfig.GetValue(Path+'Categories/'+CodeExplorerCategoryNames[c],
599       c in DefaultCodeExplorerCategories) then
600         Include(FCategories,c);
601   FObserverCategories:=[];
602   for f:=low(TCEObserverCategory) to high(TCEObserverCategory) do
603   begin
604     CurPath:=Path+'CodeObserver/'+CodeObserverCategoryNames[f]+'/';
605     if XMLConfig.GetValue(CurPath+'Show',f in DefaultCodeObserverCategories)
606     then
607       Include(FObserverCategories,f);
608     case f of
609     cefcLongProcs:
610       FLongProcLineCount:=XMLConfig.GetValue(CurPath+'LineCount/Value',
611                                                  DefaultCOLongProcLineCount);
612     cefcLongParamLists:
613       FLongParamListCount:=XMLConfig.GetValue(CurPath+'Count/Value',
614                                                  DefaultCOLongParamListCount);
615     cefcNestedProcs:
616       FNestedProcCount:=XMLConfig.GetValue(CurPath+'Count/Value',
617                                                  DefaultCONestedProcCount);
618     cefcUnnamedConsts:
619       begin
620         FObserveCharConst:=XMLConfig.GetValue(CurPath+'CharConsts/Value',
621                                                  DefaultCOureCharConst);
622         // load standard ObserverIgnoreConstants
623         if XMLConfig.GetValue(CurPath+'Ignore/ContainsDefaults',true) then
624           LoadDefaults_COIgnoreConstants;
625         // load custom ObserverIgnoreConstants
626         List:=TStringList.Create;
627         try
628           LoadStringList(XMLConfig,List,CurPath+'Ignore/');
629           SetListOf_COIgnoreConstants(List,true);
630         finally
631           List.Free;
632         end;
633         // load standard COIgnoreConstInFuncs
634         if XMLConfig.GetValue(CurPath+'IgnoreInFuncs/ContainsDefaults',true) then
635           LoadDefaults_COIgnoreConstInFuncs;
636         // load custom COIgnoreConstInFuncs
637         List:=TStringList.Create;
638         try
639           LoadStringList(XMLConfig,List,CurPath+'IgnoreFuncs/');
640           SetListOf_COIgnoreConstInFuncs(List,true);
641         finally
642           List.Free;
643         end;
644       end;
645     end;
646   end;
647 end;
648 
649 procedure TCodeExplorerOptions.SaveToXMLConfig(XMLConfig: TXMLConfig;
650   const Path: string);
651 var
652   c: TCodeExplorerCategory;
653   f: TCEObserverCategory;
654   CurPath: String;
655   List: TStrings;
656   ContainsDefaults: Boolean;
657   i: Integer;
658 begin
659   XMLConfig.SetDeleteValue(Path+'Refresh/Value',
660                            CodeExplorerRefreshNames[FRefresh],
661                            CodeExplorerRefreshNames[cerDefault]);
662   XMLConfig.SetDeleteValue(Path+'Mode/Value',
663                            CodeExplorerModeNames[FMode],
664                            CodeExplorerModeNames[cemCategory]);
665   XMLConfig.SetDeleteValue(Path+'FollowCursor',FFollowCursor,true);
666   XMLConfig.SetDeleteValue(Path+'Page/Value',CodeExplorerPageNames[FPage],
667                            CodeExplorerPageNames[DefaultCodeExplorerPage]);
668 
669   for c:=FirstCodeExplorerCategory to high(TCodeExplorerCategory) do
670     XMLConfig.SetDeleteValue(Path+'Categories/'+CodeExplorerCategoryNames[c],
671       c in FCategories,c in DefaultCodeExplorerCategories);
672   for f:=low(TCEObserverCategory) to high(TCEObserverCategory) do
673   begin
674     CurPath:=Path+'CodeObserver/'+CodeObserverCategoryNames[f]+'/';
675     XMLConfig.SetDeleteValue(CurPath+'Show',
676       f in FObserverCategories,f in DefaultCodeObserverCategories);
677     case f of
678     cefcLongProcs:
679       XMLConfig.SetDeleteValue(CurPath+'LineCount/Value',
680                            FLongProcLineCount,DefaultCOLongProcLineCount);
681     cefcLongParamLists:
682       XMLConfig.SetDeleteValue(CurPath+'Count/Value',
683                            FLongParamListCount,DefaultCOLongParamListCount);
684     cefcNestedProcs:
685       XMLConfig.SetDeleteValue(CurPath+'Count/Value',
686                            FNestedProcCount,DefaultCONestedProcCount);
687     cefcUnnamedConsts:
688       begin
689         XMLConfig.SetDeleteValue(CurPath+'CharConsts/Value',
690                            FObserveCharConst,DefaultCOureCharConst);
691         // save standard ObserverIgnoreConstants
692         ContainsDefaults:=COIgnoreConstants_AreDefault(false);
693         XMLConfig.SetDeleteValue(CurPath+'Ignore/ContainsDefaults',
694            ContainsDefaults,true);
695         // save ObserverIgnoreConstants
696         List:=CreateListOfCOIgnoreConstants;
697         try
698           for i:=List.Count-1 downto 0 do
699             if COIgnoreConstant_IsDefault(List[i]) then
700               List.Delete(i);
701           SaveStringList(XMLConfig,List,CurPath+'Ignore/');
702         finally
703           List.Free;
704         end;
705         // save standard COIgnoreConstInFuncs
706         ContainsDefaults:=COIgnoreConstInFuncs_AreDefault(false);
707         XMLConfig.SetDeleteValue(CurPath+'IgnoreInFuncs/ContainsDefaults',
708            ContainsDefaults,true);
709         // save COIgnoreConstInFuncs
710         List:=CreateListOfCOIgnoreConstInFuncs;
711         try
712           for i:=List.Count-1 downto 0 do
713             if COIgnoreConstInFuncs_IsDefault(List[i]) then
714               List.Delete(i);
715           SaveStringList(XMLConfig,List,CurPath+'IgnoreInFuncs/');
716         finally
717           List.Free;
718         end;
719       end;
720     end;
721   end;
722 end;
723 
724 procedure TCodeExplorerOptions.IncreaseChangeStep;
725 begin
726   if FChangeStep=high(integer) then
727     FChangeStep:=low(integer)
728   else
729     inc(FChangeStep);
730 end;
731 
CreateListOfCOIgnoreConstantsnull732 function TCodeExplorerOptions.CreateListOfCOIgnoreConstants: TStrings;
733 var
734   AVLNode: TAvlTreeNode;
735   s: String;
736 begin
737   Result:=TStringList.Create;
738   AVLNode:=ObserverIgnoreConstants.FindLowest;
739   while AVLNode<>nil do begin
740     s:=GetAtomString(PChar(AVLNode.Data),false);
741     if s<>'' then
742       Result.Add(s);
743     AVLNode:=ObserverIgnoreConstants.FindSuccessor(AVLNode);
744   end;
745 end;
746 
747 procedure TCodeExplorerOptions.Clear_COIgnoreConstants;
748 var
749   AVLNode: TAvlTreeNode;
750   s: String;
751 begin
752   if FObserverIgnoreConstants.Count=0 then exit;
753   IncreaseChangeStep;
754   s:='';
755   AVLNode:=FObserverIgnoreConstants.FindLowest;
756   while AVLNode<>nil do begin
757     // decrease reference counter
758     Pointer(s):=AVLNode.Data;
759     s:='';
760     AVLNode:=FObserverIgnoreConstants.FindSuccessor(AVLNode);
761   end;
762   if s='' then ; // omit fpc note
763   FObserverIgnoreConstants.Clear;
764 end;
765 
766 procedure TCodeExplorerOptions.SetListOf_COIgnoreConstants(List: TStrings;
767   Add: boolean);
768 var
769   i: Integer;
770 begin
771   IncreaseChangeStep;
772   if not Add then
773     Clear_COIgnoreConstants;
774   for i:=0 to List.Count-1 do
775     Add_COIgnoreConstant(List[i]);
776 end;
777 
778 procedure TCodeExplorerOptions.LoadDefaults_COIgnoreConstants;
779 var
780   i: Integer;
781 begin
782   if COIgnoreConstants_AreDefault(true) then exit;
783   IncreaseChangeStep;
784   Clear_COIgnoreConstants;
785   for i:=low(DefaultCOIgnoreConstants) to high(DefaultCOIgnoreConstants) do
786     Add_COIgnoreConstant(DefaultCOIgnoreConstants[i]);
787 end;
788 
TCodeExplorerOptions.CreateListOfCOIgnoreConstInFuncsnull789 function TCodeExplorerOptions.CreateListOfCOIgnoreConstInFuncs: TStrings;
790 var
791   AVLNode: TAvlTreeNode;
792   s: String;
793 begin
794   Result:=TStringList.Create;
795   AVLNode:=COIgnoreConstInFuncs.Tree.FindLowest;
796   while AVLNode<>nil do begin
797     s:=PStringToStringItem(AVLNode.Data)^.Name;
798     if s<>'' then
799       Result.Add(s);
800     AVLNode:=COIgnoreConstInFuncs.Tree.FindSuccessor(AVLNode);
801   end;
802 end;
803 
804 procedure TCodeExplorerOptions.SetListOf_COIgnoreConstInFuncs(List: TStrings;
805   Add: boolean);
806 var
807   i: Integer;
808 begin
809   IncreaseChangeStep;
810   if not Add then
811     Clear_COIgnoreConstInFuncs;
812   for i:=0 to List.Count-1 do
813     Add_COIgnoreConstInFuncs(List[i]);
814 end;
815 
COIgnoreConstInFuncnull816 function TCodeExplorerOptions.COIgnoreConstInFunc(const Func: string): boolean;
817 begin
818   Result:=FCOIgnoreConstInFuncs.Contains(Func);
819 end;
820 
COIgnoreConstInFuncs_AreDefaultnull821 function TCodeExplorerOptions.COIgnoreConstInFuncs_AreDefault(Exactly: boolean
822   ): boolean;
823 const
824   DefCount = high(DefaultCOIgnoreConstInFuncs)-Low(DefaultCOIgnoreConstInFuncs)+1;
825 var
826   i: Integer;
827 begin
828   if Exactly and (FCOIgnoreConstInFuncs.Count=DefCount) then
829     exit(false);
830   if FCOIgnoreConstInFuncs.Count<DefCount then exit(false);
831   for i:=low(DefaultCOIgnoreConstInFuncs) to high(DefaultCOIgnoreConstInFuncs) do
832     if not COIgnoreConstInFunc(DefaultCOIgnoreConstInFuncs[i]) then
833       exit(false);
834   Result:=true;
835 end;
836 
TCodeExplorerOptions.COIgnoreConstInFuncs_IsDefaultnull837 function TCodeExplorerOptions.COIgnoreConstInFuncs_IsDefault(const Func: string
838   ): boolean;
839 var
840   i: Integer;
841 begin
842   for i:=low(DefaultCOIgnoreConstants) to high(DefaultCOIgnoreConstants) do
843     if SysUtils.CompareText(Func,DefaultCOIgnoreConstants[i])=0 then
844       exit(true);
845   Result:=false;
846 end;
847 
848 procedure TCodeExplorerOptions.Add_COIgnoreConstInFuncs(const Func: string);
849 begin
850   if Func='' then exit;
851   if COIgnoreConstInFunc(Func) then exit;
852   IncreaseChangeStep;
853   FCOIgnoreConstInFuncs.Values[Func]:='';
854 end;
855 
856 procedure TCodeExplorerOptions.Clear_COIgnoreConstInFuncs;
857 begin
858   if FCOIgnoreConstInFuncs.Count=0 then exit;
859   IncreaseChangeStep;
860   FCOIgnoreConstInFuncs.Clear;
861 end;
862 
863 procedure TCodeExplorerOptions.LoadDefaults_COIgnoreConstInFuncs;
864 var
865   i: Integer;
866 begin
867   if COIgnoreConstInFuncs_AreDefault(true) then exit;
868   IncreaseChangeStep;
869   Clear_COIgnoreConstInFuncs;
870   for i:=low(DefaultCOIgnoreConstInFuncs) to high(DefaultCOIgnoreConstInFuncs) do
871     Add_COIgnoreConstInFuncs(DefaultCOIgnoreConstInFuncs[i]);
872 end;
873 
TCodeExplorerOptions.COIgnoreConstantnull874 function TCodeExplorerOptions.COIgnoreConstant(p: PChar): boolean;
875 begin
876   Result:=FObserverIgnoreConstants.Find(p)<>nil;
877 end;
878 
879 procedure TCodeExplorerOptions.Add_COIgnoreConstant(const Atom: string);
880 var
881   s: String;
882 begin
883   if Atom='' then exit;
884   if COIgnoreConstant(PChar(Atom)) then exit;
885   IncreaseChangeStep;
886   s:=Atom;
887   FObserverIgnoreConstants.Add(Pointer(s));
888   Pointer(s):=nil;
889 end;
890 
TCodeExplorerOptions.COIgnoreConstants_AreDefaultnull891 function TCodeExplorerOptions.COIgnoreConstants_AreDefault(Exactly: boolean
892   ): boolean;
893 const
894   DefCount = high(DefaultCOIgnoreConstants)-Low(DefaultCOIgnoreConstants)+1;
895 var
896   i: Integer;
897 begin
898   if Exactly and (FObserverIgnoreConstants.Count=DefCount) then
899     exit(false);
900   if FObserverIgnoreConstants.Count<DefCount then exit(false);
901   for i:=low(DefaultCOIgnoreConstants) to high(DefaultCOIgnoreConstants) do
902     if not COIgnoreConstant(PChar(DefaultCOIgnoreConstants[i])) then
903       exit(false);
904   Result:=true;
905 end;
906 
COIgnoreConstant_IsDefaultnull907 function TCodeExplorerOptions.COIgnoreConstant_IsDefault(const Atom: string
908   ): boolean;
909 var
910   i: Integer;
911 begin
912   for i:=low(DefaultCOIgnoreConstants) to high(DefaultCOIgnoreConstants) do
913     if CompareAtom(PChar(Atom),PChar(DefaultCOIgnoreConstants[i]),false)=0 then
914       exit(true);
915   Result:=false;
916 end;
917 
918 initialization
919   RegisterIDEOptionsGroup(GroupCodeExplorer, TCodeExplorerOptions);
920 end.
921 
922