mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-15 16:02:40 +02:00
380 lines
12 KiB
ObjectPascal
380 lines
12 KiB
ObjectPascal
{
|
|
***************************************************************************
|
|
* *
|
|
* This source is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This code is distributed in the hope that it will be useful, but *
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
* General Public License for more details. *
|
|
* *
|
|
* A copy of the GNU General Public License is available on the World *
|
|
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
|
|
* obtain it by writing to the Free Software Foundation, *
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
* *
|
|
***************************************************************************
|
|
|
|
Author: Mattias Gaertner
|
|
|
|
Abstract:
|
|
Dialog and functions to change encodings (e.g. UTF-8) of projects and
|
|
packages.
|
|
}
|
|
unit ChgEncodingDlg;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, LCLProc, FileProcs, Forms, Controls, Graphics,
|
|
Dialogs, LConvEncoding, ExtCtrls, StdCtrls, ComCtrls,
|
|
IDEWindowIntf, SynRegExpr, SrcEditorIntf,
|
|
CodeCache, CodeToolsStructs, CodeToolManager, AVL_Tree,
|
|
// IDE
|
|
IDEProcs, CodeBrowser, PackageDefs, PackageSystem, Project,
|
|
LazarusIDEStrConsts, Buttons, IDEContextHelpEdit;
|
|
|
|
type
|
|
|
|
{ TChgEncodingDialog }
|
|
|
|
TChgEncodingDialog = class(TForm)
|
|
ApplyButton: TBitBtn;
|
|
HelpButton: TBitBtn;
|
|
BtnPanel: TPanel;
|
|
CloseButton: TBitBtn;
|
|
NewEncodingComboBox: TComboBox;
|
|
FileFilterCombobox: TComboBox;
|
|
NewEncodingLabel: TLabel;
|
|
PreviewButton: TBitBtn;
|
|
PreviewListView: TListView;
|
|
PreviewGroupBox: TGroupBox;
|
|
OwnerComboBox: TComboBox;
|
|
ScopeGroupBox: TGroupBox;
|
|
RegExprCheckBox: TCheckBox;
|
|
FileFilterLabel: TLabel;
|
|
NonUTF8FilesCheckBox: TCheckBox;
|
|
UTF8FilesCheckBox: TCheckBox;
|
|
FilesGroupBox: TGroupBox;
|
|
procedure ApplyButtonClick(Sender: TObject);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure HelpButtonClick(Sender: TObject);
|
|
procedure PreviewButtonClick(Sender: TObject);
|
|
private
|
|
procedure GetFiles(out Tree: TFilenameToStringTree);
|
|
procedure UpdatePreview;
|
|
public
|
|
end;
|
|
|
|
function ShowConvertEncodingDlg: TModalResult;
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
function ShowConvertEncodingDlg: TModalResult;
|
|
var
|
|
ChgEncodingDialog: TChgEncodingDialog;
|
|
begin
|
|
ChgEncodingDialog:=TChgEncodingDialog.Create(nil);
|
|
Result:=ChgEncodingDialog.ShowModal;
|
|
ChgEncodingDialog.Free;
|
|
end;
|
|
|
|
{ TChgEncodingDialog }
|
|
|
|
procedure TChgEncodingDialog.FormCreate(Sender: TObject);
|
|
var
|
|
List: TStringList;
|
|
Encoding: string;
|
|
i: Integer;
|
|
begin
|
|
IDEDialogLayoutList.ApplyLayout(Self);
|
|
|
|
Caption:=lisConvertEncoding;
|
|
|
|
ScopeGroupBox.Caption:=lisConvertProjectOrPackage;
|
|
NewEncodingLabel.Caption:=lisNewEncoding;
|
|
FilesGroupBox.Caption:=lisFileFilter;
|
|
UTF8FilesCheckBox.Caption:=lisFilesInASCIIOrUTF8Encoding;
|
|
NonUTF8FilesCheckBox.Caption:=lisFilesNotInASCIINorUTF8Encoding;
|
|
FileFilterLabel.Caption:=lisFilter;
|
|
RegExprCheckBox.Caption:=lisRegularExpression;
|
|
|
|
PreviewButton.Caption:=lisUpdatePreview;
|
|
CloseButton.Caption:=lisMenuClose;
|
|
ApplyButton.Caption:=lisConvert;
|
|
HelpButton.Caption:=dlgGroupHelp;
|
|
PreviewButton.LoadGlyphFromLazarusResource('laz_refresh');
|
|
CloseButton.LoadGlyphFromLazarusResource('btn_close');
|
|
ApplyButton.LoadGlyphFromLazarusResource('btn_ok');
|
|
HelpButton.LoadGlyphFromLazarusResource('btn_help');
|
|
|
|
PreviewGroupBox.Caption:=dlgWRDPreview;
|
|
PreviewListView.Column[0].Caption:=dlgEnvFiles;
|
|
PreviewListView.Column[0].Width:=350;
|
|
PreviewListView.Column[1].Caption:=uemEncoding;
|
|
|
|
// get possible encodings
|
|
List:=TStringList.Create;
|
|
GetSupportedEncodings(List);
|
|
for i:=List.Count-1 downto 0 do begin
|
|
Encoding:=List[i];
|
|
if (Encoding='') or (SysUtils.CompareText(Encoding,EncodingAnsi)=0) then
|
|
List.Delete(i);
|
|
end;
|
|
List.Sort;
|
|
NewEncodingComboBox.Items.Assign(List);
|
|
List.Free;
|
|
NewEncodingComboBox.Text:='UTF-8';
|
|
|
|
// get possible filters
|
|
List:=TStringList.Create;
|
|
List.Add('*.pas;*.pp;*.p;*.inc;*.lpr;*.lfm;*.lrs;*.txt');
|
|
List.Sort;
|
|
FileFilterCombobox.Items.Assign(List);
|
|
List.Free;
|
|
FileFilterCombobox.Text:=FileFilterCombobox.Items[0];
|
|
|
|
// get possible projects and packages
|
|
List:=TStringList.Create;
|
|
for i:=0 to PackageGraph.Count-1 do
|
|
if (List.IndexOf(PackageGraph[i].Name)<0)
|
|
and (not PackageGraph[i].ReadOnly)
|
|
and (not PackageGraph[i].IsVirtual)
|
|
then
|
|
List.Add(PackageGraph[i].Name);
|
|
List.Sort;
|
|
if not Project1.IsVirtual then
|
|
List.Insert(0,dlgEnvProject);
|
|
OwnerComboBox.Items.Assign(List);
|
|
List.Free;
|
|
if OwnerComboBox.Items.Count>0 then
|
|
OwnerComboBox.Text:=OwnerComboBox.Items[0]
|
|
else
|
|
OwnerComboBox.Text:='';
|
|
end;
|
|
|
|
procedure TChgEncodingDialog.ApplyButtonClick(Sender: TObject);
|
|
var
|
|
Buf: TCodeBuffer;
|
|
SrcEdit: TSourceEditorInterface;
|
|
NewEncoding: String;
|
|
OldEncoding: String;
|
|
Files: TFilenameToStringTree;
|
|
Node: TAVLTreeNode;
|
|
Item: PStringToStringTreeItem;
|
|
Filename: String;
|
|
Encoding: String;
|
|
HasChanged: boolean;
|
|
li: TListItem;
|
|
begin
|
|
GetFiles(Files);
|
|
if Files=nil then exit;
|
|
try
|
|
NewEncoding:=NormalizeEncoding(NewEncodingComboBox.Text);
|
|
|
|
PreviewListView.BeginUpdate;
|
|
PreviewListView.Items.Clear;
|
|
Node:=Files.Tree.FindLowest;
|
|
while Node<>nil do begin
|
|
Item:=PStringToStringTreeItem(Node.Data);
|
|
Filename:=Item^.Name;
|
|
Encoding:=Item^.Value;
|
|
DebugLn(['TChgEncodingDialog.ApplyButtonClick Filename=',Filename,' Encoding=',Encoding]);
|
|
Buf:=CodeToolBoss.LoadFile(Filename,true,false);
|
|
if not Buf.ReadOnly then begin
|
|
OldEncoding:=Buf.DiskEncoding;
|
|
SrcEdit:=SourceEditorManagerIntf.SourceEditorIntfWithFilename(Filename);
|
|
HasChanged:=true;
|
|
if SrcEdit<>nil then begin
|
|
DebugLn(['TChgEncodingDialog.ApplyButtonClick changing in source editor: ',Filename]);
|
|
Buf.DiskEncoding:=NewEncoding;
|
|
SrcEdit.Modified:=true;
|
|
end else begin
|
|
DebugLn(['TChgEncodingDialog.ApplyButtonClick changing on disk: ',Filename]);
|
|
Buf:=CodeToolBoss.LoadFile(Filename,true,false);
|
|
Buf.DiskEncoding:=NewEncoding;
|
|
HasChanged:=Buf.Save;
|
|
if not HasChanged then
|
|
Buf.DiskEncoding:=OldEncoding;
|
|
end;
|
|
end;
|
|
if not HasChanged then begin
|
|
li:=PreviewListView.Items.Add;
|
|
li.Caption:=Filename;
|
|
li.SubItems.Add(Encoding);
|
|
end;
|
|
Node:=Files.Tree.FindSuccessor(Node);
|
|
end;
|
|
PreviewListView.EndUpdate;
|
|
PreviewGroupBox.Caption:='Number of files failed to convert: '+IntToStr(PreviewListView.Items.Count);
|
|
finally
|
|
Files.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TChgEncodingDialog.FormDestroy(Sender: TObject);
|
|
begin
|
|
IDEDialogLayoutList.SaveLayout(Self);
|
|
end;
|
|
|
|
procedure TChgEncodingDialog.HelpButtonClick(Sender: TObject);
|
|
begin
|
|
ShowContextHelpForIDE(Self);
|
|
end;
|
|
|
|
procedure TChgEncodingDialog.PreviewButtonClick(Sender: TObject);
|
|
begin
|
|
UpdatePreview;
|
|
end;
|
|
|
|
procedure TChgEncodingDialog.GetFiles(out Tree: TFilenameToStringTree);
|
|
var
|
|
AProject: TProject;
|
|
SearchPath: String;
|
|
APackage: TLazPackage;
|
|
Dir: String;
|
|
FileInfo: TSearchRec;
|
|
CurFilename: String;
|
|
Buf: TCodeBuffer;
|
|
NewEncoding: String;
|
|
IncludeFilterRegExpr: TRegExpr;
|
|
CurOwner: TObject;
|
|
Expr: String;
|
|
ok: Boolean;
|
|
p: Integer;
|
|
CurEncoding: String;
|
|
begin
|
|
Tree:=nil;
|
|
|
|
// check owner
|
|
if OwnerComboBox.Text=dlgEnvProject then
|
|
CurOwner:=Project1
|
|
else
|
|
CurOwner:=PackageGraph.FindAPackageWithName(OwnerComboBox.Text,nil);
|
|
if CurOwner=nil then begin
|
|
DebugLn(['TChgEncodingDialog.UpdatePreview package not found: ',OwnerComboBox.Text]);
|
|
exit;
|
|
end;
|
|
|
|
// find search paths
|
|
if CurOwner is TProject then begin
|
|
AProject:=TProject(CurOwner);
|
|
SearchPath:=AProject.SourceDirectories.CreateSearchPathFromAllFiles;
|
|
SearchPath:=MergeSearchPaths(SearchPath,AProject.CompilerOptions.GetIncludePath(false));
|
|
end else begin
|
|
APackage:=TLazPackage(CurOwner);
|
|
SearchPath:=APackage.SourceDirectories.CreateSearchPathFromAllFiles;
|
|
SearchPath:=MergeSearchPaths(SearchPath,APackage.CompilerOptions.GetIncludePath(false));
|
|
end;
|
|
|
|
// find files
|
|
IncludeFilterRegExpr:=TRegExpr.Create;
|
|
Expr:=FileFilterCombobox.Text;
|
|
if not RegExprCheckBox.Checked then
|
|
Expr:=SimpleSyntaxToRegExpr(Expr);
|
|
ok:=false;
|
|
try
|
|
IncludeFilterRegExpr.Expression:=Expr;
|
|
ok:=true;
|
|
except
|
|
on E: Exception do begin
|
|
DebugLn('Invalid Include File Expression ',Expr,' ',E.Message);
|
|
MessageDlg('Error in regular expression',
|
|
E.Message,mtError,[mbCancel],0);
|
|
end;
|
|
end;
|
|
if not ok then exit;
|
|
|
|
NewEncoding:=NormalizeEncoding(NewEncodingComboBox.Text);
|
|
Tree:=TFilenameToStringTree.Create(FilenamesCaseSensitive);
|
|
p:=1;
|
|
repeat
|
|
Dir:=GetNextDirectoryInSearchPath(SearchPath,p);
|
|
if p>length(SearchPath) then break;
|
|
Dir:=AppendPathDelim(Dir);
|
|
DebugLn(['TChgEncodingDialog.GetFiles Dir=',Dir]);
|
|
if FindFirstUTF8(Dir+FileMask,faAnyFile,FileInfo)=0 then begin
|
|
repeat
|
|
// check if special file
|
|
//DebugLn(['TChgEncodingDialog.GetFiles ',FileInfo.Name,' ... ']);
|
|
if (FileInfo.Name='.') or (FileInfo.Name='..') or (FileInfo.Name='') then
|
|
continue;
|
|
CurFilename:=Dir+FileInfo.Name;
|
|
if Tree.Contains(CurFilename) then continue;
|
|
if not IncludeFilterRegExpr.Exec(CurFilename) then begin
|
|
DebugLn(['TChgEncodingDialog.GetFiles not matching filter: ',CurFilename]);
|
|
continue;
|
|
end;
|
|
if not FileIsTextCached(CurFilename) then begin
|
|
DebugLn(['TChgEncodingDialog.GetFiles not a text file: ',CurFilename]);
|
|
continue;
|
|
end;
|
|
|
|
if (FileInfo.Attr and faDirectory)>0 then begin
|
|
// skip directory
|
|
end else begin
|
|
Buf:=CodeToolBoss.LoadFile(CurFilename,true,false);
|
|
if Buf<>nil then begin
|
|
//DebugLn(['TChgEncodingDialog.GetFiles Filename=',CurFilename,' Encoding=',NormalizeEncoding(Buf.DiskEncoding)]);
|
|
CurEncoding:=NormalizeEncoding(Buf.DiskEncoding);
|
|
if CurEncoding=NewEncoding then continue;
|
|
if (CurEncoding=EncodingUTF8) and (not UTF8FilesCheckBox.Checked) then
|
|
continue;
|
|
if (CurEncoding<>EncodingUTF8)
|
|
and (not NonUTF8FilesCheckBox.Checked) then
|
|
continue;
|
|
Tree[CurFilename]:=Buf.DiskEncoding;
|
|
end else begin
|
|
DebugLn(['TChgEncodingDialog.UpdatePreview read error: ',CurFilename]);
|
|
end;
|
|
end;
|
|
until FindNextUTF8(FileInfo)<>0;
|
|
end;
|
|
FindCloseUTF8(FileInfo);
|
|
until false;
|
|
end;
|
|
|
|
procedure TChgEncodingDialog.UpdatePreview;
|
|
var
|
|
Files: TFilenameToStringTree;
|
|
Node: TAVLTreeNode;
|
|
Item: PStringToStringTreeItem;
|
|
Filename: String;
|
|
Encoding: String;
|
|
li: TListItem;
|
|
begin
|
|
GetFiles(Files);
|
|
if Files=nil then exit;
|
|
try
|
|
PreviewListView.BeginUpdate;
|
|
PreviewListView.Items.Clear;
|
|
Node:=Files.Tree.FindLowest;
|
|
while Node<>nil do begin
|
|
Item:=PStringToStringTreeItem(Node.Data);
|
|
Filename:=Item^.Name;
|
|
Encoding:=Item^.Value;
|
|
DebugLn(['TChgEncodingDialog.UpdatePreview Filename=',Filename,' Encoding=',Encoding]);
|
|
li:=PreviewListView.Items.Add;
|
|
li.Caption:=Filename;
|
|
li.SubItems.Add(Encoding);
|
|
Node:=Files.Tree.FindSuccessor(Node);
|
|
end;
|
|
PreviewListView.EndUpdate;
|
|
PreviewGroupBox.Caption:=Format(lisNumberOfFilesToConvert, [IntToStr(
|
|
PreviewListView.Items.Count)]);
|
|
finally
|
|
Files.Free;
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|