1 {
2 *****************************************************************************
3 See the file COPYING.modifiedLGPL.txt, included in this distribution,
4 for details about the license.
5 *****************************************************************************
6
7 Author: Mattias Gaertner
8
9 Abstract:
10 Defines a converter and tools to modify a Text. The Text can be a file,
11 a string or a TStrings.
12 Packages can register extra tools, which the IDE user can then be put
13 together to define a series of changes. For example several Find&Replace
14 tools can be added and then executed automatically.
15 For an extensive example, see the package in components/h2pas/.
16 }
17 unit IDETextConverter;
18
19 {$mode objfpc}{$H+}
20
21 interface
22
23 uses
24 Classes, SysUtils, TypInfo,
25 // LCL
26 LCLProc,
27 // LazUtils
28 UITypes, FileUtil, LazFileUtils, LazUTF8, LazLoggerBase,
29 // IdeIntf
30 SrcEditorIntf, PropEdits, ObjInspStrConsts;
31
32 type
33 TCustomTextConverterTool = class;
34
35 TTextConverterType = (
36 tctSource,
37 tctFile,
38 tctStrings,
39 tctCodeBuffer // TCodeBuffer
40 );
41
42 { TIDETextConverter
43 A component to hold a Text and tools to change the Text.
44 For example to do several find and replace operations on the text.
45 The Text can be a file, a string, TStrings or a TCodeBuffer.
46 The Text is converted on the fly, whenever someone reads/write one of the
47 formats.
48 The tools are decendants of TCustomTextConverterTool. }
49
50 TIDETextConverter = class(TComponent)
51 private
52 FFilename: string;
53 FSource: string;
54 FCodeBuffer: Pointer;
55 FStrings: TStrings;
56 FCurrentType: TTextConverterType;
57 FFileIsTemporary: boolean;
58 FStringsIsTemporary: Boolean;
59 procedure CreateTempFilename;
GetCodeBuffernull60 function GetCodeBuffer: Pointer;
GetFilenamenull61 function GetFilename: string;
GetSourcenull62 function GetSource: string;
GetStringsnull63 function GetStrings: TStrings;
64 procedure ResetStrings;
65 procedure ResetFile;
66 procedure ConvertToFile(const NewFilename: string);
67 procedure SetCodeBuffer(const AValue: Pointer);
68 procedure SetFilename(const AValue: string);
69 procedure SetSource(const AValue: string);
70 procedure SetStrings(const AValue: TStrings);
71 procedure SetCurrentType(const AValue: TTextConverterType);
72 procedure SetFileIsTemporary(const AValue: boolean);
73 procedure SetStringsIsTemporary(const AValue: Boolean);
74 protected
GetTempFilenamenull75 function GetTempFilename: string; virtual;
76 public
77 constructor Create(TheOwner: TComponent); override;
78 destructor Destroy; override;
79 procedure Clear;
80 procedure CheckType(aTextType: TTextConverterType);
SupportsTypenull81 function SupportsType(aTextType: TTextConverterType): boolean; virtual;
Executenull82 function Execute(ToolList: TComponent; out ErrorTool: TComponent): TModalResult;// run the tools
LoadFromFilenull83 function LoadFromFile(const AFilename: string;
84 UseIDECache: Boolean = true;
85 UpdateFromDisk: Boolean = true;
86 Revert: Boolean = false
87 ): Boolean; virtual;
88 procedure InitWithFilename(const AFilename: string);
89 procedure InitWithSource(const ASource: string);
90 procedure InitWithStrings(const aStrings: TStrings);
91 procedure InitWithCodeBuffers(const aBuffer: Pointer);
92 property CurrentType: TTextConverterType read FCurrentType write SetCurrentType;
93 property Source: string read GetSource write SetSource;
94 property CodeBuffer: Pointer read GetCodeBuffer write SetCodeBuffer;
95 property Filename: string read GetFilename write SetFilename;
96 property Strings: TStrings read GetStrings write SetStrings;
97 property FileIsTemporary: boolean read FFileIsTemporary write SetFileIsTemporary;
98 property StringsIsTemporary: Boolean read FStringsIsTemporary write SetStringsIsTemporary;
99 end;
100
101 { TCustomTextConverterTool
102 An abstract component to change a Text (TIDETextConverter). }
103
104 TCustomTextConverterTool = class(TComponent)
105 private
106 FCaption: string;
107 FDescription: string;
108 FEnabled: boolean;
109 FErrorColumn: integer;
110 FErrorFilename: string;
111 FErrorLine: integer;
112 FErrorMsg: string;
113 FErrorTopLine: integer;
IsCaptionStorednull114 function IsCaptionStored: boolean;
115 procedure SetCaption(const AValue: string);
116 procedure SetDescription(const AValue: string);
117 public
ClassDescriptionnull118 class function ClassDescription: string; virtual; abstract;//the first line should be a short title
FirstLineOfClassDescriptionnull119 class function FirstLineOfClassDescription: string;
120 constructor Create(TheOwner: TComponent); override;
Executenull121 function Execute(aText: TIDETextConverter): TModalResult; virtual; abstract;
122 procedure Assign(Source: TPersistent); override;
123 procedure ClearError; virtual;
124 procedure AssignError(Source: TCustomTextConverterTool);
125 procedure AssignCodeToolBossError;
126 property ErrorMsg: string read FErrorMsg write FErrorMsg;
127 property ErrorLine: integer read FErrorLine write FErrorLine;
128 property ErrorColumn: integer read FErrorColumn write FErrorColumn;
129 property ErrorTopLine: integer read FErrorTopLine write FErrorTopLine;
130 property ErrorFilename: string read FErrorFilename write FErrorFilename;
131 published
132 property Caption: string read FCaption write SetCaption stored IsCaptionStored;
133 property Description: string read FDescription write SetDescription;
134 property Enabled: boolean read FEnabled write FEnabled default True;
135 end;
136 TCustomTextConverterToolClass = class of TCustomTextConverterTool;
137
138 { TCustomTextReplaceTool
139 A tool to do a 'find and replace' in a text. }
140
141 TTextReplaceToolOption = (
142 trtMatchCase, // search case sensitive
143 trtWholeWord, // search at word boundaries
144 trtRegExpr, // use regular expressions for find and replace
145 trtMultiLine // ignore type of line endings in pattern (e.g. #10 = #13#10)
146 //TODO trtSearchInReplacement,// when replaced, continue search at start of replacement, instead of end of replacement
147 //TODO trtReplaceUntilNotFound// restart replace until pattern not found
148 );
149 TTextReplaceToolOptions = set of TTextReplaceToolOption;
150
151 TCustomTextReplaceTool = class(TCustomTextConverterTool)
152 private
153 FOptions: TTextReplaceToolOptions;
154 FReplaceWith: string;
155 FSearchFor: string;
156 procedure SetOptions(const AValue: TTextReplaceToolOptions);
157 procedure SetReplaceWith(const AValue: string);
158 procedure SetSearchFor(const AValue: string);
159 public
ClassDescriptionnull160 class function ClassDescription: string; override;
Executenull161 function Execute(aText: TIDETextConverter): TModalResult; override;
162 procedure Assign(Source: TPersistent); override;
163 property SearchFor: string read FSearchFor write SetSearchFor;
164 property ReplaceWith: string read FReplaceWith write SetReplaceWith;
165 property Options: TTextReplaceToolOptions read FOptions write SetOptions;
166 end;
167
168 { TTextReplaceTool }
169
170 TTextReplaceTool = class(TCustomTextReplaceTool)
171 published
172 property SearchFor;
173 property ReplaceWith;
174 property Options;
175 end;
176
177 { TTextConverterToolClasses
178 A list to hold the registered TCustomTextConverterToolClass(es) }
179
180 TTextConverterToolClasses = class
181 private
182 FItems: TFPList;// list of TCustomTextConverterToolClass
GetCountnull183 function GetCount: integer;
GetItemsnull184 function GetItems(Index: integer): TCustomTextConverterToolClass;
185 public
186 constructor Create;
187 destructor Destroy; override;
188 procedure RegisterClass(AClass: TCustomTextConverterToolClass);
189 procedure UnregisterClass(AClass: TCustomTextConverterToolClass);
FindByNamenull190 function FindByName(const aClassName: string): TCustomTextConverterToolClass;
FindByFirstLineOfClassDescriptionnull191 function FindByFirstLineOfClassDescription(const Line: string
192 ): TCustomTextConverterToolClass;
193 procedure FindClass(Reader: TReader; const aClassName: string;
194 var ComponentClass: TComponentClass);
195 property Items[Index: integer]: TCustomTextConverterToolClass read GetItems; default;
196 property Count: integer read GetCount;
197
SupportsTypenull198 function SupportsType(aTextType: TTextConverterType): boolean; virtual; abstract;
GetTempFilenamenull199 function GetTempFilename: string; virtual; abstract;
LoadFromFilenull200 function LoadFromFile(Converter: TIDETextConverter; const AFilename: string;
201 UpdateFromDisk, Revert: Boolean): Boolean; virtual; abstract;
SaveCodeBufferToFilenull202 function SaveCodeBufferToFile(Converter: TIDETextConverter;
203 const AFilename: string): Boolean; virtual; abstract;
GetCodeBufferSourcenull204 function GetCodeBufferSource(Converter: TIDETextConverter;
205 out Source: string): boolean; virtual; abstract;
CreateCodeBuffernull206 function CreateCodeBuffer(Converter: TIDETextConverter;
207 const Filename, NewSource: string;
208 out CodeBuffer: Pointer): boolean; virtual; abstract;
LoadCodeBufferFromFilenull209 function LoadCodeBufferFromFile(Converter: TIDETextConverter;
210 const Filename: string;
211 UpdateFromDisk, Revert: Boolean;
212 out CodeBuffer: Pointer): boolean; virtual; abstract;
213 procedure AssignCodeToolBossError(Target: TCustomTextConverterTool); virtual;
214 end;
215
216 var
217 TextConverterToolClasses: TTextConverterToolClasses = nil;// set by the IDE
218
219 procedure ClearTextConverterToolList(List: TComponent);
220 procedure CopyTextConverterToolList(Src, Dest: TComponent;
221 ClearDest: boolean = true);
222
223 procedure MakeToolNameUnique(List: TComponent;
224 NewTool: TCustomTextConverterTool);
225 procedure MakeToolCaptionUnique(List: TComponent;
226 NewTool: TCustomTextConverterTool);
227 procedure MakeToolCaptionAndNameUnique(List: TComponent;
228 NewTool: TCustomTextConverterTool);
AddNewTextConverterToolnull229 function AddNewTextConverterTool(List: TComponent;
230 NewClass: TCustomTextConverterToolClass): TCustomTextConverterTool;
231
232
233 implementation
234
235
236 procedure MakeToolNameUnique(List: TComponent;
237 NewTool: TCustomTextConverterTool);
238 var
239 NewName: String;
240
241 procedure MakeValidIdentifier;
242 var
243 i: Integer;
244 begin
245 for i:=length(NewName) downto 1 do
246 if not (NewName[i] in ['0'..'9','_','a'..'z','A'..'Z']) then
247 System.Delete(NewName,i,1);
248 if (NewName<>'') and (NewName[1] in ['0'..'9']) then
249 NewName:='_'+NewName;
250 end;
251
NameIsUniquenull252 function NameIsUnique: Boolean;
253 var
254 i: Integer;
255 CurTool: TCustomTextConverterTool;
256 begin
257 MakeValidIdentifier;
258 if NewName='' then exit(false);
259 for i:=0 to List.ComponentCount-1 do begin
260 CurTool:=TCustomTextConverterTool(List.Components[i]);
261 if CurTool=NewTool then continue;
262 if CompareText(CurTool.Name,NewName)=0 then exit(false);
263 end;
264 Result:=true;
265 NewTool.Name:=NewName;
266 end;
267
268 begin
269 NewName:=NewTool.Name;
270 if NameIsUnique then exit;
271 NewName:=NewTool.FirstLineOfClassDescription;
272 if NewName='' then NewName:=NewTool.ClassName;
273 while not NameIsUnique do
274 NewName:=CreateNextIdentifier(NewName);
275 end;
276
277 procedure MakeToolCaptionUnique(List: TComponent;
278 NewTool: TCustomTextConverterTool);
279 var
280 NewCaption: String;
281
CaptionIsUniquenull282 function CaptionIsUnique: Boolean;
283 var
284 i: Integer;
285 CurTool: TCustomTextConverterTool;
286 begin
287 if NewCaption='' then exit(false);
288 for i:=0 to List.ComponentCount-1 do begin
289 CurTool:=TCustomTextConverterTool(List.Components[i]);
290 if CurTool=NewTool then continue;
291 if CompareText(CurTool.Caption,NewCaption)=0 then exit(false);
292 end;
293 Result:=true;
294 NewTool.Caption:=NewCaption;
295 end;
296
297 begin
298 NewCaption:=NewTool.Caption;
299 if CaptionIsUnique then exit;
300 NewCaption:=NewTool.FirstLineOfClassDescription;
301 if NewCaption='' then NewCaption:=NewTool.ClassName;
302 while not CaptionIsUnique do
303 NewCaption:=CreateNextIdentifier(NewCaption);
304 end;
305
306 procedure MakeToolCaptionAndNameUnique(List: TComponent;
307 NewTool: TCustomTextConverterTool);
308 begin
309 MakeToolNameUnique(List,NewTool);
310 MakeToolCaptionUnique(List,NewTool);
311 end;
312
AddNewTextConverterToolnull313 function AddNewTextConverterTool(List: TComponent;
314 NewClass: TCustomTextConverterToolClass): TCustomTextConverterTool;
315 begin
316 Result:=NewClass.Create(List);
317 MakeToolCaptionAndNameUnique(List,Result);
318 if Result.Caption='' then RaiseGDBException('');
319 end;
320
321 procedure ClearTextConverterToolList(List: TComponent);
322 begin
323 if List=nil then exit;
324 while List.ComponentCount>0 do
325 List.Components[List.ComponentCount-1].Free;
326 end;
327
328 procedure CopyTextConverterToolList(Src, Dest: TComponent; ClearDest: boolean);
329 var
330 i: Integer;
331 SrcTool: TCustomTextConverterTool;
332 NewTool: TCustomTextConverterTool;
333 begin
334 if ClearDest then
335 ClearTextConverterToolList(Dest);
336 for i:=0 to Src.ComponentCount-1 do begin
337 SrcTool:=Src.Components[i] as TCustomTextConverterTool;
338 NewTool:=TCustomTextConverterToolClass(SrcTool.ClassType).Create(Dest);
339 NewTool.Assign(SrcTool);
340 NewTool.Name:=SrcTool.Name;
341 end;
342 end;
343
344 { TIDETextConverter }
345
346 procedure TIDETextConverter.SetFilename(const AValue: string);
347 begin
348 ConvertToFile(AValue);
349 end;
350
TIDETextConverter.GetFilenamenull351 function TIDETextConverter.GetFilename: string;
352 begin
353 CurrentType:=tctFile;
354 Result:=FFilename;
355 end;
356
TIDETextConverter.GetSourcenull357 function TIDETextConverter.GetSource: string;
358 begin
359 CurrentType:=tctSource;
360 Result:=FSource;
361 end;
362
TIDETextConverter.GetStringsnull363 function TIDETextConverter.GetStrings: TStrings;
364 begin
365 CurrentType:=tctStrings;
366 Result:=FStrings;
367 end;
368
369 procedure TIDETextConverter.ResetStrings;
370 begin
371 if StringsIsTemporary then
372 FStrings.Free;
373 FStrings:=nil;
374 FStringsIsTemporary:=false;
375 end;
376
377 procedure TIDETextConverter.ResetFile;
378 begin
379 if FileIsTemporary then begin
380 DeleteFileUTF8(FFilename);
381 // do not change FFileIsTemporary, so that File > Source > File sequences
382 // keep the file temporary.
383 end;
384 end;
385
386 procedure TIDETextConverter.SetSource(const AValue: string);
387 begin
388 FCurrentType:=tctSource;
389 ResetStrings;
390 ResetFile;
391 FSource:=AValue;
392 end;
393
394 procedure TIDETextConverter.SetStrings(const AValue: TStrings);
395 begin
396 FCurrentType:=tctStrings;
397 ResetFile;
398 ResetStrings;
399 FStrings:=AValue;
400 end;
401
402 procedure TIDETextConverter.SetCurrentType(const AValue: TTextConverterType);
403 var
404 fs: TFileStream;
405 begin
406 if FCurrentType=AValue then exit;
407 CheckType(AValue);
408 //DebugLn(['TIDETextConverter.SetCurrentType ',ord(FCurrentType),' ',ord(AValue)]);
409 case AValue of
410 tctSource:
411 // convert to Source
412 begin
413 FSource:='';
414 case FCurrentType of
415 tctStrings:
416 if FStrings<>nil then begin
417 FSource:=FStrings.Text;
418 ResetStrings;
419 end;
420 tctFile:
421 if FileExistsUTF8(FFilename) then begin
422 fs:=TFileStream.Create(FFilename,fmOpenRead);
423 try
424 SetLength(FSource,fs.Size);
425 fs.Read(FSource[1],length(FSource));
426 finally
427 fs.Free;
428 end;
429 ResetFile;
430 end;
431 tctCodeBuffer:
432 begin
433 TextConverterToolClasses.GetCodeBufferSource(Self,FSource);
434 FCodeBuffer:=nil;
435 end;
436 end;
437 end;
438
439 tctStrings:
440 // convert to TStrings
441 begin
442 if FStrings<>nil then
443 RaiseGDBException('TTextConverterText.SetCurrentType FStrings<>nil');
444 FStrings:=TStringList.Create;
445 fStringsIsTemporary:=true;
446 case FCurrentType of
447 tctSource:
448 begin
449 FStrings.Text:=FSource;
450 FSource:='';
451 end;
452 tctFile:
453 if FileExistsUTF8(FFilename) then begin
454 FStrings.LoadFromFile(FFilename);
455 ResetFile;
456 end;
457 tctCodeBuffer:
458 begin
459 TextConverterToolClasses.GetCodeBufferSource(Self,FSource);
460 FStrings.Text:=FSource;
461 FSource:='';
462 FCodeBuffer:=nil;
463 end;
464 end;
465 end;
466
467 tctFile:
468 // convert to File
469 begin
470 // keep old Filename, so that a Filename, Source, Filename combination
471 // uses the same Filename
472 if FFilename='' then
473 CreateTempFilename;
474 case FCurrentType of
475 tctSource:
476 begin
477 fs:=TFileStream.Create(FFilename,fmCreate);
478 try
479 if FSource<>'' then begin
480 fs.Write(FSource[1],length(FSource));
481 FSource:='';
482 end;
483 finally
484 fs.Free;
485 end;
486 end;
487 tctStrings:
488 if FStrings<>nil then begin
489 FStrings.LoadFromFile(FFilename);
490 ResetStrings;
491 end;
492 tctCodeBuffer:
493 begin
494 TextConverterToolClasses.SaveCodeBufferToFile(Self,FFilename);
495 FCodeBuffer:=nil;
496 end;
497 end;
498 end;
499
500 tctCodeBuffer:
501 // convert to CodeBuffer
502 begin
503 // keep old Filename, so that a Filename, Source, Filename combination
504 // uses the same Filename
505 if FFilename='' then
506 CreateTempFilename;
507 case FCurrentType of
508 tctSource:
509 begin
510 TextConverterToolClasses.CreateCodeBuffer(Self,FFilename,FSource,
511 FCodeBuffer);
512 FSource:='';
513 end;
514 tctStrings:
515 begin
516 TextConverterToolClasses.CreateCodeBuffer(Self,FFilename,
517 FStrings.Text,FCodeBuffer);
518 ResetStrings;
519 end;
520 tctFile:
521 begin
522 TextConverterToolClasses.LoadCodeBufferFromFile(Self,FFilename,
523 true,true,FCodeBuffer);
524 ResetFile;
525 end;
526 end;
527 end;
528 end;
529 FCurrentType:=AValue;
530 end;
531
532 procedure TIDETextConverter.SetFileIsTemporary(const AValue: boolean);
533 begin
534 if FFileIsTemporary=AValue then exit;
535 FFileIsTemporary:=AValue;
536 end;
537
538 procedure TIDETextConverter.ConvertToFile(const NewFilename: string);
539 var
540 fs: TFileStream;
541 TrimmedFilename: String;
542 begin
543 TrimmedFilename:=TrimFilename(NewFilename);
544 case CurrentType of
545 tctFile:
546 if (FFilename<>'') and (FFilename<>TrimmedFilename)
547 and (FileExistsUTF8(FFilename)) then
548 RenameFileUTF8(FFilename,TrimmedFilename);
549 tctSource:
550 begin
551 fs:=TFileStream.Create(TrimmedFilename,fmCreate);
552 try
553 if FSource<>'' then
554 fs.Write(FSource[1],length(FSource));
555 finally
556 fs.Free;
557 end;
558 end;
559 tctStrings:
560 begin
561 FStrings.SaveToFile(TrimmedFilename);
562 ResetStrings;
563 end;
564 tctCodeBuffer:
565 begin
566 TextConverterToolClasses.SaveCodeBufferToFile(Self,NewFilename);
567 FCodeBuffer:=nil;
568 end;
569 end;
570 FCurrentType:=tctFile;
571 FFilename:=TrimmedFilename;
572 end;
573
574 procedure TIDETextConverter.SetCodeBuffer(const AValue: Pointer);
575 begin
576 CheckType(tctCodeBuffer);
577 FCurrentType:=tctCodeBuffer;
578 ResetStrings;
579 FCodeBuffer:=AValue;
580 end;
581
582 procedure TIDETextConverter.CreateTempFilename;
583 begin
584 FFilename:=GetTempFilename;
585 FFileIsTemporary:=true;
586 end;
587
TIDETextConverter.GetCodeBuffernull588 function TIDETextConverter.GetCodeBuffer: Pointer;
589 begin
590 CurrentType:=tctCodeBuffer;
591 Result:=FCodeBuffer;
592 end;
593
594 procedure TIDETextConverter.SetStringsIsTemporary(const AValue: Boolean);
595 begin
596 if FStringsIsTemporary=AValue then exit;
597 FStringsIsTemporary:=AValue;
598 end;
599
GetTempFilenamenull600 function TIDETextConverter.GetTempFilename: string;
601 begin
602 if TextConverterToolClasses<>nil then
603 Result:=TextConverterToolClasses.GetTempFilename
604 else
605 Result:='';
606 if Result='' then
607 Result:='temp.txt';
608 end;
609
610 constructor TIDETextConverter.Create(TheOwner: TComponent);
611 begin
612 inherited Create(TheOwner);
613 FCurrentType:=tctSource;
614 end;
615
616 destructor TIDETextConverter.Destroy;
617 begin
618 ResetFile;
619 ResetStrings;
620 inherited Destroy;
621 end;
622
623 procedure TIDETextConverter.Clear;
624 begin
625 FFilename:='';
626 FSource:='';
627 FCodeBuffer:=nil;
628 ResetStrings;
629 FCurrentType:=tctSource;
630 end;
631
632 procedure TIDETextConverter.CheckType(aTextType: TTextConverterType);
633
634 procedure RaiseNotSupported;
635 begin
636 raise Exception.Create('TIDETextConverter.CheckType:'
637 +' type not supported '+GetEnumName(TypeInfo(TTextConverterType),ord(aTextType)));
638 end;
639
640 begin
641 if not SupportsType(aTextType) then RaiseNotSupported;
642 end;
643
TIDETextConverter.SupportsTypenull644 function TIDETextConverter.SupportsType(aTextType: TTextConverterType): boolean;
645 begin
646 Result:=(aTextType in [tctSource,tctFile,tctStrings])
647 or ((TextConverterToolClasses<>nil)
648 and (TextConverterToolClasses.SupportsType(aTextType)));
649 end;
650
TIDETextConverter.Executenull651 function TIDETextConverter.Execute(ToolList: TComponent;
652 out ErrorTool: TComponent): TModalResult;
653 var
654 i: Integer;
655 Tool: TCustomTextConverterTool;
656 CurResult: TModalResult;
657 begin
658 Result:=mrOk;
659 ErrorTool:=nil;
660 for i:=0 to ToolList.ComponentCount-1 do begin
661 if ToolList.Components[i] is TCustomTextConverterTool then begin
662 Tool:=TCustomTextConverterTool(ToolList.Components[i]);
663 if Tool.Enabled then begin
664 Tool.ClearError;
665 CurResult:=Tool.Execute(Self);
666 if CurResult=mrIgnore then
667 Result:=mrOk
668 else if CurResult<>mrOk then begin
669 ErrorTool:=Tool;
670 exit(mrAbort);
671 end;
672 end;
673 end;
674 end;
675 end;
676
TIDETextConverter.LoadFromFilenull677 function TIDETextConverter.LoadFromFile(const AFilename: string;
678 UseIDECache: Boolean; UpdateFromDisk: Boolean; Revert: Boolean): Boolean;
679 var
680 fs: TFileStream;
681 begin
682 if UseIDECache and (TextConverterToolClasses<>nil) then begin
683 //DebugLn(['TIDETextConverter.LoadFromFile using IDE cache']);
684 Result:=TextConverterToolClasses.LoadFromFile(Self,AFilename,
685 UpdateFromDisk,Revert);
686 end else begin
687 //DebugLn(['TIDETextConverter.LoadFromFile loading directly CurrentType=',ord(CurrentType),' FFilename="',FFilename,'"']);
688 Result:=false;
689 try
690 case CurrentType of
691 tctSource:
692 begin
693 fs:=TFileStream.Create(AFilename,fmOpenRead);
694 try
695 SetLength(FSource,fs.Size);
696 if fSource<>'' then
697 fs.Read(fSource[1],length(fSource));
698 finally
699 fs.Free;
700 end;
701 end;
702 tctFile:
703 CopyFile(AFilename,FFilename);
704 tctStrings:
705 FStrings.LoadFromFile(FFilename)
706 end;
707 Result:=true;
708 except
709 end;
710 end;
711 end;
712
713 procedure TIDETextConverter.InitWithFilename(const AFilename: string);
714 begin
715 Clear;
716 FCurrentType:=tctFile;
717 FFilename:=AFilename;
718 end;
719
720 procedure TIDETextConverter.InitWithSource(const ASource: string);
721 begin
722 Clear;
723 FCurrentType:=tctSource;
724 FSource:=ASource;
725 end;
726
727 procedure TIDETextConverter.InitWithStrings(const aStrings: TStrings);
728 begin
729 Clear;
730 FCurrentType:=tctStrings;
731 FStrings:=aStrings;
732 end;
733
734 procedure TIDETextConverter.InitWithCodeBuffers(const aBuffer: Pointer);
735 begin
736 CheckType(tctCodeBuffer);
737 Clear;
738 FCurrentType:=tctCodeBuffer;
739 FCodeBuffer:=aBuffer;
740 end;
741
742 { TCustomTextConverterTool }
743
744 procedure TCustomTextConverterTool.SetCaption(const AValue: string);
745 begin
746 if FCaption=AValue then exit;
747 FCaption:=AValue;
748 end;
749
IsCaptionStorednull750 function TCustomTextConverterTool.IsCaptionStored: boolean;
751 begin
752 Result:=Caption<>FirstLineOfClassDescription;
753 end;
754
755 procedure TCustomTextConverterTool.SetDescription(const AValue: string);
756 begin
757 if FDescription=AValue then exit;
758 FDescription:=AValue;
759 end;
760
761 constructor TCustomTextConverterTool.Create(TheOwner: TComponent);
762 begin
763 inherited Create(TheOwner);
764 Enabled:=true;
765 Caption:=FirstLineOfClassDescription;
766 end;
767
768 procedure TCustomTextConverterTool.Assign(Source: TPersistent);
769 var
770 Src: TCustomTextConverterTool;
771 begin
772 if Source is TCustomTextConverterTool then begin
773 Src:=TCustomTextConverterTool(Source);
774 Caption:=Src.Caption;
775 Description:=Src.Description;
776 end else
777 inherited Assign(Source);
778 end;
779
780 procedure TCustomTextConverterTool.ClearError;
781 begin
782 FErrorMsg:='';
783 FErrorLine:=0;
784 FErrorColumn:=0;
785 FErrorTopLine:=0;
786 FErrorFilename:='';
787 end;
788
789 procedure TCustomTextConverterTool.AssignError(Source: TCustomTextConverterTool);
790 begin
791 FErrorMsg:=Source.ErrorMsg;
792 FErrorLine:=Source.ErrorLine;
793 FErrorColumn:=Source.ErrorColumn;
794 FErrorTopLine:=Source.ErrorTopLine;
795 FErrorFilename:=Source.ErrorFilename;
796 end;
797
798 procedure TCustomTextConverterTool.AssignCodeToolBossError;
799 begin
800 if Assigned(TextConverterToolClasses) then
801 TextConverterToolClasses.AssignCodeToolBossError(Self)
802 else
803 ClearError;
804 end;
805
TCustomTextConverterTool.FirstLineOfClassDescriptionnull806 class function TCustomTextConverterTool.FirstLineOfClassDescription: string;
807 var
808 p: Integer;
809 begin
810 Result:=ClassDescription;
811 p:=1;
812 while (p<=length(Result)) do begin
813 if Result[p] in [#10,#13] then begin
814 Result:=copy(Result,1,p-1);
815 exit;
816 end;
817 inc(p);
818 end;
819 end;
820
821 { TCustomTextReplaceTool }
822
823 procedure TCustomTextReplaceTool.SetOptions(const AValue: TTextReplaceToolOptions);
824 begin
825 if FOptions=AValue then exit;
826 FOptions:=AValue;
827 end;
828
829 procedure TCustomTextReplaceTool.SetReplaceWith(const AValue: string);
830 begin
831 if FReplaceWith=AValue then exit;
832 FReplaceWith:=AValue;
833 end;
834
835 procedure TCustomTextReplaceTool.SetSearchFor(const AValue: string);
836 begin
837 if FSearchFor=AValue then exit;
838 FSearchFor:=AValue;
839 end;
840
TCustomTextReplaceTool.Executenull841 function TCustomTextReplaceTool.Execute(aText: TIDETextConverter): TModalResult;
842 var
843 Source: String;
844 Flags: TSrcEditSearchOptions;
845 Prompt: Boolean;
846 begin
847 //DebugLn(['TCustomTextReplaceTool.Execute ',dbgsName(Self),' aText=',dbgsName(aText),' SearchFor="',dbgstr(SearchFor),'"']);
848 Result:=mrCancel;
849 if aText=nil then exit;
850 if SearchFor='' then exit(mrOk);
851 Source:=aText.Source;
852 Flags:=[sesoReplace,sesoReplaceAll];
853 if trtMatchCase in Options then Include(Flags,sesoMatchCase);
854 if trtWholeWord in Options then Include(Flags,sesoWholeWord);
855 if trtRegExpr in Options then Include(Flags,sesoRegExpr);
856 if trtMultiLine in Options then Include(Flags,sesoMultiLine);
857 Prompt:=false;
858 Result:=IDESearchInText('',Source,SearchFor,ReplaceWith,Flags,Prompt,nil);
859 if Result=mrOk then
860 aText.Source:=Source;
861 //DebugLn(['TCustomTextReplaceTool.Execute END Result=',Result=mrOk]);
862 end;
863
864 procedure TCustomTextReplaceTool.Assign(Source: TPersistent);
865 var
866 Src: TCustomTextReplaceTool;
867 begin
868 if Source is TCustomTextReplaceTool then begin
869 Src:=TCustomTextReplaceTool(Source);
870 SearchFor:=Src.SearchFor;
871 ReplaceWith:=Src.ReplaceWith;
872 Options:=Src.Options;
873 end;
874 inherited Assign(Source);
875 end;
876
TCustomTextReplaceTool.ClassDescriptionnull877 class function TCustomTextReplaceTool.ClassDescription: string;
878 begin
879 Result := itcsSearchAndReplace;
880 end;
881
882 { TTextConverterToolClasses }
883
TTextConverterToolClasses.GetCountnull884 function TTextConverterToolClasses.GetCount: integer;
885 begin
886 if Self<>nil then
887 Result:=FItems.Count
888 else
889 Result:=0;
890 end;
891
TTextConverterToolClasses.GetItemsnull892 function TTextConverterToolClasses.GetItems(Index: integer
893 ): TCustomTextConverterToolClass;
894 begin
895 Result:=TCustomTextConverterToolClass(FItems[Index]);
896 end;
897
898 constructor TTextConverterToolClasses.Create;
899 begin
900 FItems:=TFPList.Create;
901 end;
902
903 destructor TTextConverterToolClasses.Destroy;
904 begin
905 FItems.Clear;
906 FreeAndNil(FItems);
907 inherited Destroy;
908 end;
909
910 procedure TTextConverterToolClasses.RegisterClass(
911 AClass: TCustomTextConverterToolClass);
912 begin
913 if Self=nil then exit;
914 if FItems.IndexOf(AClass)<0 then
915 FItems.Add(AClass);
916 end;
917
918 procedure TTextConverterToolClasses.UnregisterClass(
919 AClass: TCustomTextConverterToolClass);
920 begin
921 if Self=nil then exit;
922 FItems.Remove(AClass);
923 end;
924
TTextConverterToolClasses.FindByNamenull925 function TTextConverterToolClasses.FindByName(const aClassName: string
926 ): TCustomTextConverterToolClass;
927 var
928 i: Integer;
929 begin
930 if Self<>nil then
931 for i:=0 to FItems.Count-1 do begin
932 Result:=Items[i];
933 if CompareText(Result.ClassName,aClassName)=0 then exit;
934 end;
935 Result:=nil;
936 end;
937
FindByFirstLineOfClassDescriptionnull938 function TTextConverterToolClasses.FindByFirstLineOfClassDescription(
939 const Line: string): TCustomTextConverterToolClass;
940 var
941 i: Integer;
942 begin
943 if Self<>nil then
944 for i:=0 to FItems.Count-1 do begin
945 Result:=Items[i];
946 if Result.FirstLineOfClassDescription=Line then exit;
947 end;
948 Result:=nil;
949 end;
950
951 procedure TTextConverterToolClasses.FindClass(Reader: TReader;
952 const aClassName: string; var ComponentClass: TComponentClass);
953 begin
954 if Reader=nil then ;
955 ComponentClass:=FindByName(aClassName);
956 end;
957
958 procedure TTextConverterToolClasses.AssignCodeToolBossError(
959 Target: TCustomTextConverterTool);
960 begin
961 Target.ErrorMsg:='';
962 Target.ErrorLine:=-1;
963 Target.ErrorColumn:=-1;
964 Target.ErrorTopLine:=-1;
965 Target.ErrorFilename:='';
966 end;
967
968 initialization
969 RegisterPropertyEditor(TypeInfo(AnsiString),
970 TCustomTextReplaceTool, 'SearchFor', TStringMultilinePropertyEditor);
971 RegisterPropertyEditor(TypeInfo(AnsiString),
972 TCustomTextReplaceTool, 'ReplaceWith', TStringMultilinePropertyEditor);
973
974 end.
975
976