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, Controls, Forms,
27 // LazUtils
28 FileUtil, LazFileUtils, LazUTF8, LazUTF8Classes, 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:=TFileStreamUTF8.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 if FStrings is TStringListUTF8 then
455 FStrings.LoadFromFile(FFilename)
456 else
457 FStrings.LoadFromFile(UTF8ToSys(FFilename));
458 ResetFile;
459 end;
460 tctCodeBuffer:
461 begin
462 TextConverterToolClasses.GetCodeBufferSource(Self,FSource);
463 FStrings.Text:=FSource;
464 FSource:='';
465 FCodeBuffer:=nil;
466 end;
467 end;
468 end;
469
470 tctFile:
471 // convert to File
472 begin
473 // keep old Filename, so that a Filename, Source, Filename combination
474 // uses the same Filename
475 if FFilename='' then
476 CreateTempFilename;
477 case FCurrentType of
478 tctSource:
479 begin
480 fs:=TFileStreamUTF8.Create(FFilename,fmCreate);
481 try
482 if FSource<>'' then begin
483 fs.Write(FSource[1],length(FSource));
484 FSource:='';
485 end;
486 finally
487 fs.Free;
488 end;
489 end;
490 tctStrings:
491 if FStrings<>nil then begin
492 if FStrings is TStringListUTF8 then
493 FStrings.LoadFromFile(FFilename)
494 else
495 FStrings.LoadFromFile(UTF8ToSys(FFilename));
496 ResetStrings;
497 end;
498 tctCodeBuffer:
499 begin
500 TextConverterToolClasses.SaveCodeBufferToFile(Self,FFilename);
501 FCodeBuffer:=nil;
502 end;
503 end;
504 end;
505
506 tctCodeBuffer:
507 // convert to CodeBuffer
508 begin
509 // keep old Filename, so that a Filename, Source, Filename combination
510 // uses the same Filename
511 if FFilename='' then
512 CreateTempFilename;
513 case FCurrentType of
514 tctSource:
515 begin
516 TextConverterToolClasses.CreateCodeBuffer(Self,FFilename,FSource,
517 FCodeBuffer);
518 FSource:='';
519 end;
520 tctStrings:
521 begin
522 TextConverterToolClasses.CreateCodeBuffer(Self,FFilename,
523 FStrings.Text,FCodeBuffer);
524 ResetStrings;
525 end;
526 tctFile:
527 begin
528 TextConverterToolClasses.LoadCodeBufferFromFile(Self,FFilename,
529 true,true,FCodeBuffer);
530 ResetFile;
531 end;
532 end;
533 end;
534 end;
535 FCurrentType:=AValue;
536 end;
537
538 procedure TIDETextConverter.SetFileIsTemporary(const AValue: boolean);
539 begin
540 if FFileIsTemporary=AValue then exit;
541 FFileIsTemporary:=AValue;
542 end;
543
544 procedure TIDETextConverter.ConvertToFile(const NewFilename: string);
545 var
546 fs: TFileStream;
547 TrimmedFilename: String;
548 begin
549 TrimmedFilename:=TrimFilename(NewFilename);
550 case CurrentType of
551 tctFile:
552 if (FFilename<>'') and (FFilename<>TrimmedFilename)
553 and (FileExistsUTF8(FFilename)) then
554 RenameFileUTF8(FFilename,TrimmedFilename);
555 tctSource:
556 begin
557 fs:=TFileStreamUTF8.Create(TrimmedFilename,fmCreate);
558 try
559 if FSource<>'' then
560 fs.Write(FSource[1],length(FSource));
561 finally
562 fs.Free;
563 end;
564 end;
565 tctStrings:
566 begin
567 if FStrings is TStringListUTF8 then
568 FStrings.SaveToFile(TrimmedFilename)
569 else
570 FStrings.SaveToFile(UTF8ToSys(TrimmedFilename));
571 ResetStrings;
572 end;
573 tctCodeBuffer:
574 begin
575 TextConverterToolClasses.SaveCodeBufferToFile(Self,NewFilename);
576 FCodeBuffer:=nil;
577 end;
578 end;
579 FCurrentType:=tctFile;
580 FFilename:=TrimmedFilename;
581 end;
582
583 procedure TIDETextConverter.SetCodeBuffer(const AValue: Pointer);
584 begin
585 CheckType(tctCodeBuffer);
586 FCurrentType:=tctCodeBuffer;
587 ResetStrings;
588 FCodeBuffer:=AValue;
589 end;
590
591 procedure TIDETextConverter.CreateTempFilename;
592 begin
593 FFilename:=GetTempFilename;
594 FFileIsTemporary:=true;
595 end;
596
TIDETextConverter.GetCodeBuffernull597 function TIDETextConverter.GetCodeBuffer: Pointer;
598 begin
599 CurrentType:=tctCodeBuffer;
600 Result:=FCodeBuffer;
601 end;
602
603 procedure TIDETextConverter.SetStringsIsTemporary(const AValue: Boolean);
604 begin
605 if FStringsIsTemporary=AValue then exit;
606 FStringsIsTemporary:=AValue;
607 end;
608
GetTempFilenamenull609 function TIDETextConverter.GetTempFilename: string;
610 begin
611 if TextConverterToolClasses<>nil then
612 Result:=TextConverterToolClasses.GetTempFilename
613 else
614 Result:='';
615 if Result='' then
616 Result:='temp.txt';
617 end;
618
619 constructor TIDETextConverter.Create(TheOwner: TComponent);
620 begin
621 inherited Create(TheOwner);
622 FCurrentType:=tctSource;
623 end;
624
625 destructor TIDETextConverter.Destroy;
626 begin
627 ResetFile;
628 ResetStrings;
629 inherited Destroy;
630 end;
631
632 procedure TIDETextConverter.Clear;
633 begin
634 FFilename:='';
635 FSource:='';
636 FCodeBuffer:=nil;
637 ResetStrings;
638 FCurrentType:=tctSource;
639 end;
640
641 procedure TIDETextConverter.CheckType(aTextType: TTextConverterType);
642
643 procedure RaiseNotSupported;
644 begin
645 raise Exception.Create('TIDETextConverter.CheckType:'
646 +' type not supported '+GetEnumName(TypeInfo(TTextConverterType),ord(aTextType)));
647 end;
648
649 begin
650 if not SupportsType(aTextType) then RaiseNotSupported;
651 end;
652
TIDETextConverter.SupportsTypenull653 function TIDETextConverter.SupportsType(aTextType: TTextConverterType
654 ): boolean;
655 begin
656 Result:=(aTextType in [tctSource,tctFile,tctStrings])
657 or ((TextConverterToolClasses<>nil)
658 and (TextConverterToolClasses.SupportsType(aTextType)));
659 end;
660
TIDETextConverter.Executenull661 function TIDETextConverter.Execute(ToolList: TComponent;
662 out ErrorTool: TComponent): TModalResult;
663 var
664 i: Integer;
665 Tool: TCustomTextConverterTool;
666 CurResult: TModalResult;
667 begin
668 Result:=mrOk;
669 ErrorTool:=nil;
670 for i:=0 to ToolList.ComponentCount-1 do begin
671 if ToolList.Components[i] is TCustomTextConverterTool then begin
672 Tool:=TCustomTextConverterTool(ToolList.Components[i]);
673 if Tool.Enabled then begin
674 Tool.ClearError;
675 CurResult:=Tool.Execute(Self);
676 if CurResult=mrIgnore then
677 Result:=mrOk
678 else if CurResult<>mrOk then begin
679 ErrorTool:=Tool;
680 exit(mrAbort);
681 end;
682 end;
683 end;
684 end;
685 end;
686
TIDETextConverter.LoadFromFilenull687 function TIDETextConverter.LoadFromFile(const AFilename: string;
688 UseIDECache: Boolean; UpdateFromDisk: Boolean; Revert: Boolean): Boolean;
689 var
690 fs: TFileStream;
691 begin
692 if UseIDECache and (TextConverterToolClasses<>nil) then begin
693 //DebugLn(['TIDETextConverter.LoadFromFile using IDE cache']);
694 Result:=TextConverterToolClasses.LoadFromFile(Self,AFilename,
695 UpdateFromDisk,Revert);
696 end else begin
697 //DebugLn(['TIDETextConverter.LoadFromFile loading directly CurrentType=',ord(CurrentType),' FFilename="',FFilename,'"']);
698 Result:=false;
699 try
700 case CurrentType of
701 tctSource:
702 begin
703 fs:=TFileStreamUTF8.Create(AFilename,fmOpenRead);
704 try
705 SetLength(FSource,fs.Size);
706 if fSource<>'' then
707 fs.Read(fSource[1],length(fSource));
708 finally
709 fs.Free;
710 end;
711 end;
712 tctFile:
713 CopyFile(AFilename,FFilename);
714 tctStrings:
715 if FStrings is TStringListUTF8 then
716 FStrings.LoadFromFile(FFilename)
717 else
718 FStrings.LoadFromFile(UTF8ToSys(FFilename));
719 end;
720 Result:=true;
721 except
722 end;
723 end;
724 end;
725
726 procedure TIDETextConverter.InitWithFilename(const AFilename: string);
727 begin
728 Clear;
729 FCurrentType:=tctFile;
730 FFilename:=AFilename;
731 end;
732
733 procedure TIDETextConverter.InitWithSource(const ASource: string);
734 begin
735 Clear;
736 FCurrentType:=tctSource;
737 FSource:=ASource;
738 end;
739
740 procedure TIDETextConverter.InitWithStrings(const aStrings: TStrings);
741 begin
742 Clear;
743 FCurrentType:=tctStrings;
744 FStrings:=aStrings;
745 end;
746
747 procedure TIDETextConverter.InitWithCodeBuffers(const aBuffer: Pointer);
748 begin
749 CheckType(tctCodeBuffer);
750 Clear;
751 FCurrentType:=tctCodeBuffer;
752 FCodeBuffer:=aBuffer;
753 end;
754
755 { TCustomTextConverterTool }
756
757 procedure TCustomTextConverterTool.SetCaption(const AValue: string);
758 begin
759 if FCaption=AValue then exit;
760 FCaption:=AValue;
761 end;
762
IsCaptionStorednull763 function TCustomTextConverterTool.IsCaptionStored: boolean;
764 begin
765 Result:=Caption<>FirstLineOfClassDescription;
766 end;
767
768 procedure TCustomTextConverterTool.SetDescription(const AValue: string);
769 begin
770 if FDescription=AValue then exit;
771 FDescription:=AValue;
772 end;
773
774 constructor TCustomTextConverterTool.Create(TheOwner: TComponent);
775 begin
776 inherited Create(TheOwner);
777 Enabled:=true;
778 Caption:=FirstLineOfClassDescription;
779 end;
780
781 procedure TCustomTextConverterTool.Assign(Source: TPersistent);
782 var
783 Src: TCustomTextConverterTool;
784 begin
785 if Source is TCustomTextConverterTool then begin
786 Src:=TCustomTextConverterTool(Source);
787 Caption:=Src.Caption;
788 Description:=Src.Description;
789 end else
790 inherited Assign(Source);
791 end;
792
793 procedure TCustomTextConverterTool.ClearError;
794 begin
795 FErrorMsg:='';
796 FErrorLine:=0;
797 FErrorColumn:=0;
798 FErrorTopLine:=0;
799 FErrorFilename:='';
800 end;
801
802 procedure TCustomTextConverterTool.AssignError(Source: TCustomTextConverterTool);
803 begin
804 FErrorMsg:=Source.ErrorMsg;
805 FErrorLine:=Source.ErrorLine;
806 FErrorColumn:=Source.ErrorColumn;
807 FErrorTopLine:=Source.ErrorTopLine;
808 FErrorFilename:=Source.ErrorFilename;
809 end;
810
811 procedure TCustomTextConverterTool.AssignCodeToolBossError;
812 begin
813 if Assigned(TextConverterToolClasses) then
814 TextConverterToolClasses.AssignCodeToolBossError(Self)
815 else
816 ClearError;
817 end;
818
TCustomTextConverterTool.FirstLineOfClassDescriptionnull819 class function TCustomTextConverterTool.FirstLineOfClassDescription: string;
820 var
821 p: Integer;
822 begin
823 Result:=ClassDescription;
824 p:=1;
825 while (p<=length(Result)) do begin
826 if Result[p] in [#10,#13] then begin
827 Result:=copy(Result,1,p-1);
828 exit;
829 end;
830 inc(p);
831 end;
832 end;
833
834 { TCustomTextReplaceTool }
835
836 procedure TCustomTextReplaceTool.SetOptions(
837 const AValue: TTextReplaceToolOptions);
838 begin
839 if FOptions=AValue then exit;
840 FOptions:=AValue;
841 end;
842
843 procedure TCustomTextReplaceTool.SetReplaceWith(const AValue: string);
844 begin
845 if FReplaceWith=AValue then exit;
846 FReplaceWith:=AValue;
847 end;
848
849 procedure TCustomTextReplaceTool.SetSearchFor(const AValue: string);
850 begin
851 if FSearchFor=AValue then exit;
852 FSearchFor:=AValue;
853 end;
854
TCustomTextReplaceTool.Executenull855 function TCustomTextReplaceTool.Execute(aText: TIDETextConverter
856 ): TModalResult;
857 var
858 Source: String;
859 Flags: TSrcEditSearchOptions;
860 Prompt: Boolean;
861 begin
862 //DebugLn(['TCustomTextReplaceTool.Execute ',dbgsName(Self),' aText=',dbgsName(aText),' SearchFor="',dbgstr(SearchFor),'"']);
863 Result:=mrCancel;
864 if aText=nil then exit;
865 if SearchFor='' then exit(mrOk);
866 Source:=aText.Source;
867 Flags:=[sesoReplace,sesoReplaceAll];
868 if trtMatchCase in Options then Include(Flags,sesoMatchCase);
869 if trtWholeWord in Options then Include(Flags,sesoWholeWord);
870 if trtRegExpr in Options then Include(Flags,sesoRegExpr);
871 if trtMultiLine in Options then Include(Flags,sesoMultiLine);
872 Prompt:=false;
873 Result:=IDESearchInText('',Source,SearchFor,ReplaceWith,Flags,Prompt,nil);
874 if Result=mrOk then
875 aText.Source:=Source;
876 //DebugLn(['TCustomTextReplaceTool.Execute END Result=',Result=mrOk]);
877 end;
878
879 procedure TCustomTextReplaceTool.Assign(Source: TPersistent);
880 var
881 Src: TCustomTextReplaceTool;
882 begin
883 if Source is TCustomTextReplaceTool then begin
884 Src:=TCustomTextReplaceTool(Source);
885 SearchFor:=Src.SearchFor;
886 ReplaceWith:=Src.ReplaceWith;
887 Options:=Src.Options;
888 end;
889 inherited Assign(Source);
890 end;
891
TCustomTextReplaceTool.ClassDescriptionnull892 class function TCustomTextReplaceTool.ClassDescription: string;
893 begin
894 Result := itcsSearchAndReplace;
895 end;
896
897 { TTextConverterToolClasses }
898
TTextConverterToolClasses.GetCountnull899 function TTextConverterToolClasses.GetCount: integer;
900 begin
901 if Self<>nil then
902 Result:=FItems.Count
903 else
904 Result:=0;
905 end;
906
TTextConverterToolClasses.GetItemsnull907 function TTextConverterToolClasses.GetItems(Index: integer
908 ): TCustomTextConverterToolClass;
909 begin
910 Result:=TCustomTextConverterToolClass(FItems[Index]);
911 end;
912
913 constructor TTextConverterToolClasses.Create;
914 begin
915 FItems:=TFPList.Create;
916 end;
917
918 destructor TTextConverterToolClasses.Destroy;
919 begin
920 FItems.Clear;
921 FreeAndNil(FItems);
922 inherited Destroy;
923 end;
924
925 procedure TTextConverterToolClasses.RegisterClass(
926 AClass: TCustomTextConverterToolClass);
927 begin
928 if Self=nil then exit;
929 if FItems.IndexOf(AClass)<0 then
930 FItems.Add(AClass);
931 end;
932
933 procedure TTextConverterToolClasses.UnregisterClass(
934 AClass: TCustomTextConverterToolClass);
935 begin
936 if Self=nil then exit;
937 FItems.Remove(AClass);
938 end;
939
TTextConverterToolClasses.FindByNamenull940 function TTextConverterToolClasses.FindByName(const aClassName: string
941 ): TCustomTextConverterToolClass;
942 var
943 i: Integer;
944 begin
945 if Self<>nil then
946 for i:=0 to FItems.Count-1 do begin
947 Result:=Items[i];
948 if CompareText(Result.ClassName,aClassName)=0 then exit;
949 end;
950 Result:=nil;
951 end;
952
FindByFirstLineOfClassDescriptionnull953 function TTextConverterToolClasses.FindByFirstLineOfClassDescription(
954 const Line: string): TCustomTextConverterToolClass;
955 var
956 i: Integer;
957 begin
958 if Self<>nil then
959 for i:=0 to FItems.Count-1 do begin
960 Result:=Items[i];
961 if Result.FirstLineOfClassDescription=Line then exit;
962 end;
963 Result:=nil;
964 end;
965
966 procedure TTextConverterToolClasses.FindClass(Reader: TReader;
967 const aClassName: string; var ComponentClass: TComponentClass);
968 begin
969 if Reader=nil then ;
970 ComponentClass:=FindByName(aClassName);
971 end;
972
973 procedure TTextConverterToolClasses.AssignCodeToolBossError(
974 Target: TCustomTextConverterTool);
975 begin
976 Target.ErrorMsg:='';
977 Target.ErrorLine:=-1;
978 Target.ErrorColumn:=-1;
979 Target.ErrorTopLine:=-1;
980 Target.ErrorFilename:='';
981 end;
982
983 initialization
984 RegisterPropertyEditor(TypeInfo(AnsiString),
985 TCustomTextReplaceTool, 'SearchFor', TStringMultilinePropertyEditor);
986 RegisterPropertyEditor(TypeInfo(AnsiString),
987 TCustomTextReplaceTool, 'ReplaceWith', TStringMultilinePropertyEditor);
988
989 end.
990
991