Converter: New setting for interactive / automatic replacement of used units. Refactoring.

git-svn-id: trunk@26126 -
This commit is contained in:
juha 2010-06-15 08:24:29 +00:00
parent 60b1d16bc6
commit 47e48c80c5
4 changed files with 165 additions and 128 deletions

View File

@ -34,7 +34,7 @@ interface
uses
// LCL+FCL
Classes, SysUtils, LCLProc, Forms, Controls, Dialogs, LResources,
FileUtil, contnrs, IniFiles,
FileUtil, contnrs, IniFiles, AVL_Tree,
// codetools
CodeToolManager, DefineTemplates, CodeAtom, CodeCache, LinkScanner,
FileProcs, CodeToolsStructs,
@ -706,16 +706,39 @@ end;
function TConvertDelphiUnit.FixMissingUnits: TModalResult;
var
UnitUpdater: TStringMapUpdater;
ConvTool: TConvDelphiCodeTool;
UnitNames: TStringList;
procedure RenameOrRemoveUnit(AOldName, ANewName: string);
var
x: Integer;
begin
if (ANewName<>'') and not UnitNames.Find(ANewName, x) then begin
fUnitsToRename[AOldName]:=ANewName;
IDEMessagesWindow.AddMsg(Format(
'Replaced unit "%s" with "%s" in uses section.',[AOldName, ANewName]),'',-1);
end
else begin
fUnitsToRemove.Append(AOldName);
IDEMessagesWindow.AddMsg(Format(
'Removed used unit "%s" in uses section.',[AOldName]),'',-1);
end;
end;
var
UnitUpdater: TStringMapUpdater;
MapToEdit: TStringToStringTree;
Node: TAVLTreeNode;
Item: PStringToStringTreeItem;
ConvTool: TConvDelphiCodeTool;
CTResult: Boolean;
i, x: Integer;
i: Integer;
UnitN, s: string;
begin
Result:=mrOk;
UnitUpdater:=TStringMapUpdater.Create(fSettings.ReplaceUnits);
ConvTool:=TConvDelphiCodeTool.Create(fPascalBuffer);
if not fSettings.AutoReplaceUnits then
MapToEdit:=TStringToStringTree.Create(false);
UnitNames:=nil; // Will be created in ConvTool.UsesSectionsToUnitnames.
fMissingUnits:=nil; // Will be created in CodeToolBoss.FindMissingUnits.
try
@ -732,20 +755,26 @@ begin
// no missing units -> good
if (fMissingUnits=nil) or (fMissingUnits.Count=0) then exit;
// Remove or replace units defined in settings.
// Find replacements for missing units from settings.
for i:=fMissingUnits.Count-1 downto 0 do begin
UnitN:=fMissingUnits[i];
if UnitUpdater.FindReplacement(UnitN, s) then begin
if (s<>'') and not UnitNames.Find(s, x) then begin
fUnitsToRename[UnitN]:=s;
IDEMessagesWindow.AddMsg(Format(
'Replaced unit "%s" with "%s" in uses section.',[UnitN, s]),'',-1);
end
else begin
fUnitsToRemove.Append(UnitN);
IDEMessagesWindow.AddMsg(Format(
'Removed used unit "%s" in uses section.',[UnitN]),'',-1);
end;
if fSettings.AutoReplaceUnits then
RenameOrRemoveUnit(UnitN, s) // Automatic rename / remove.
else
MapToEdit[UnitN]:=s; // Add for interactive editing.
end;
end;
if not fSettings.AutoReplaceUnits then begin
// Edit, then remove or replace units.
Result:=EditMap(MapToEdit, 'Units to rename or remove.');
if Result<>mrOK then exit;
// Iterate the map and rename / remove.
Node:=MapToEdit.Tree.FindLowest;
while Node<>nil do begin
Item:=PStringToStringTreeItem(Node.Data);
RenameOrRemoveUnit(Item^.Name, Item^.Value);
Node:=MapToEdit.Tree.FindSuccessor(Node);
end;
end;
// Remove and rename missing units. More of them may be added later.
@ -779,6 +808,8 @@ begin
IDEMessagesWindow.AddMsg(MissingUnitToMsg(fMissingUnits[i]),'',-1);
Application.ProcessMessages;
finally
if not fSettings.AutoReplaceUnits then
MapToEdit.Free;
fMissingUnits.Free;
UnitNames.Free;
ConvTool.Free;

View File

@ -53,6 +53,7 @@ type
fBackupFiles: boolean;
fTarget: TConvertTarget;
fSameDFMFile: boolean;
fAutoReplaceUnits: boolean;
fAutoRemoveProperties: boolean;
// Delphi units mapped to Lazarus units, will be replaced or removed.
fReplaceUnits: TStringToStringTree;
@ -90,6 +91,7 @@ type
property BackupFiles: boolean read fBackupFiles;
property Target: TConvertTarget read fTarget;
property SameDFMFile: boolean read fSameDFMFile;
property AutoReplaceUnits: boolean read fAutoReplaceUnits;
property AutoRemoveProperties: boolean read fAutoRemoveProperties;
property ReplaceUnits: TStringToStringTree read fReplaceUnits;
property ReplaceTypes: TStringToStringTree read fReplaceTypes;
@ -199,6 +201,7 @@ begin
fBackupFiles :=fConfigStorage.GetValue('BackupFiles', true);
fTarget:=TConvertTarget(fConfigStorage.GetValue('ConvertTarget', 0));
fSameDFMFile :=fConfigStorage.GetValue('SameDFMFile', false);
fAutoReplaceUnits :=fConfigStorage.GetValue('AutoReplaceUnits', false);
fAutoRemoveProperties :=fConfigStorage.GetValue('AutoRemoveProperties', false);
LoadStringToStringTree(fConfigStorage, 'ReplaceUnits', fReplaceUnits);
LoadStringToStringTree(fConfigStorage, 'ReplaceTypes', fReplaceTypes);
@ -206,17 +209,26 @@ begin
// Add default values for string maps if ConfigStorage doesn't have them.
// Map Delphi units to Lazarus units.
TheMap:=fReplaceUnits;
MapReplacement('Windows', 'LCLIntf, LCLType, LMessages');
MapReplacement('Mask', 'MaskEdit');
MapReplacement('Variants', '');
MapReplacement('ShellApi', '');
MapReplacement('pngImage', '');
MapReplacement('Jpeg', '');
MapReplacement('gifimage', '');
MapReplacement('^Q(.+)', '$1'); // Kylix unit names.
MapReplacement('^Tnt(.+)', '$1'); // Tnt* third party components.
MapReplacement('Windows', 'LCLIntf, LCLType, LMessages');
MapReplacement('Mask', 'MaskEdit');
MapReplacement('Variants', '');
MapReplacement('ShellApi', '');
MapReplacement('pngImage', '');
MapReplacement('Jpeg', '');
MapReplacement('gifimage', '');
MapReplacement('^Q(.+)', '$1'); // Kylix unit names.
// Tnt* third party components.
MapReplacement('TntLXStringGrids', 'Grids');
MapReplacement('TntLXCombos', '');
MapReplacement('TntLXDataSet', '');
MapReplacement('TntLXVarArrayDataSet','');
MapReplacement('TntLXLookupCtrls', '');
MapReplacement('^TntLX(.+)', '$1');
MapReplacement('^Tnt([^L][^X].+)', '$1');
// Map Delphi types to LCL types.
// LXComCtrls, LXDBGrids,
// Map Delphi types to LCL types.
TheMap:=fReplaceTypes;
MapReplacement('TFlowPanel', 'TPanel');
MapReplacement('TGridPanel', 'TPanel');
@ -228,8 +240,11 @@ begin
MapReplacement('TDBRichEdit', 'TDBMemo');
MapReplacement('TApplicationEvents','TApplicationProperties');
MapReplacement('TPNGObject', 'TPortableNetworkGraphic');
// DevExpress components.
MapReplacement('TCxEdit', 'TEdit');
MapReplacement('^TTnt(.+)', 'T$1');
// Tnt* third party components.
MapReplacement('^TTnt(.+)LX$', 'T$1');
MapReplacement('^TTnt(.+[^L][^X])$','T$1');
end;
destructor TConvertSettings.Destroy;
@ -238,6 +253,7 @@ begin
fConfigStorage.SetDeleteValue('BackupFiles', fBackupFiles, true);
fConfigStorage.SetDeleteValue('ConvertTarget', integer(fTarget), 0);
fConfigStorage.SetDeleteValue('SameDFMFile', fSameDFMFile, false);
fConfigStorage.SetDeleteValue('AutoReplaceUnits', fAutoReplaceUnits, false);
fConfigStorage.SetDeleteValue('AutoRemoveProperties', fAutoRemoveProperties, false);
SaveStringToStringTree(fConfigStorage, 'ReplaceUnits', fReplaceUnits);
SaveStringToStringTree(fConfigStorage, 'ReplaceTypes', fReplaceTypes);
@ -258,16 +274,18 @@ begin
Caption:=fTitle;
ProjectPathEdit.Text:=fMainPath;
// Settings --> UI. Loaded from ConfigSettings earlier.
BackupCheckBox.Checked :=fBackupFiles;
TargetRadioGroup.ItemIndex :=integer(fTarget);
SameDFMCheckBox.Checked :=fSameDFMFile;
AutoRemovePropCheckBox.Checked :=fAutoRemoveProperties;
BackupCheckBox.Checked :=fBackupFiles;
TargetRadioGroup.ItemIndex :=integer(fTarget);
SameDFMCheckBox.Checked :=fSameDFMFile;
AutoReplaceUnitsCheckBox.Checked :=fAutoReplaceUnits;
AutoRemovePropCheckBox.Checked :=fAutoRemoveProperties;
Result:=ShowModal; // Let the user change settings in a form.
if Result=mrOK then begin
// UI --> Settings. Will be saved to ConfigSettings later.
fBackupFiles :=BackupCheckBox.Checked;
fTarget :=TConvertTarget(TargetRadioGroup.ItemIndex);
fSameDFMFile :=SameDFMCheckBox.Checked;
fAutoReplaceUnits :=AutoReplaceUnitsCheckBox.Checked;
fAutoRemoveProperties:=AutoRemovePropCheckBox.Checked;
end;
finally
@ -422,44 +440,18 @@ begin
end;
procedure TConvertSettingsForm.UnitReplacementsButtonClick(Sender: TObject);
var
RNForm: TReplaceNamesForm;
GridUpdater: TGridUpdater;
begin
RNForm:=TReplaceNamesForm.Create(nil);
GridUpdater:=TGridUpdater.Create(fSettings.ReplaceUnits, RNForm.Grid);
try
RNForm.Caption:=lisConvUnitsToReplace;
GridUpdater.MapToGrid;
if RNForm.ShowModal=mrOK then
GridUpdater.GridToMap;
finally
GridUpdater.Free;
RNForm.Free;
end;
EditMap(fSettings.ReplaceUnits, lisConvUnitsToReplace);
end;
procedure TConvertSettingsForm.TypeReplacementsButtonClick(Sender: TObject);
var
RNForm: TReplaceNamesForm;
GridUpdater: TGridUpdater;
begin
RNForm:=TReplaceNamesForm.Create(nil);
GridUpdater:=TGridUpdater.Create(fSettings.ReplaceTypes, RNForm.Grid);
try
RNForm.Caption:=lisConvTypesToReplace;
GridUpdater.MapToGrid;
if RNForm.ShowModal=mrOK then
GridUpdater.GridToMap;
finally
GridUpdater.Free;
RNForm.Free;
end;
EditMap(fSettings.ReplaceTypes, lisConvTypesToReplace);
end;
procedure TConvertSettingsForm.MethodReplacementsButtonClick(Sender: TObject);
begin
;
end;

View File

@ -257,9 +257,6 @@ var
TypeReplacements: TStringToStringTree;
// List of TLFMChangeEntry objects.
ChgEntryRepl: TObjectList;
// Updater moves data between grid and map.
PropUpdater: TGridUpdater;
TypeUpdater: TGridUpdater;
OldIdent, NewIdent: string;
StartPos, EndPos: integer;
begin
@ -267,12 +264,10 @@ begin
ChgEntryRepl:=TObjectList.Create;
PropReplacements:=TStringToStringTree.Create(false);
TypeReplacements:=TStringToStringTree.Create(false);
PropUpdater:=TGridUpdater.Create(PropReplacements, fPropReplaceGrid);
TypeUpdater:=TGridUpdater.Create(TypeReplacements, fTypeReplaceGrid);
try
// Collect (maybe edited) properties from StringGrid to map.
PropUpdater.GridToMap;
TypeUpdater.GridToMap(false);
FromGridToMap(PropReplacements, fPropReplaceGrid);
FromGridToMap(TypeReplacements, fTypeReplaceGrid, false);
// Replace each missing property / type or delete it if no replacement.
CurError:=fLFMTree.LastError;
while CurError<>nil do begin
@ -316,8 +311,6 @@ begin
TLFMObjectNode(fLFMTree.Root).TypeName, TypeReplacements, false) then
Result:=mrCancel;
finally
TypeUpdater.Free;
PropUpdater.Free;
TypeReplacements.Free;
PropReplacements.Free;
ChgEntryRepl.Free;
@ -341,12 +334,12 @@ begin
while CurError<>nil do begin
if CurError.IsMissingObjectType then begin
OldIdent:=(CurError.Node as TLFMObjectNode).TypeName;
TypeUpdater.AddUniqueToGrid(OldIdent); // Add a unique type only once.
TypeUpdater.AddUnique(OldIdent); // Add a unique type only once.
fHasMissingObjectTypes:=true;
end
else begin
OldIdent:=CurError.Node.GetIdentifier;
PropUpdater.AddUniqueToGrid(OldIdent); // Add a unique property only once.
PropUpdater.AddUnique(OldIdent); // Add a unique property only once.
end;
CurError:=CurError.NextError;
end;

View File

@ -17,9 +17,9 @@ type
private
fStringMap: TStringToStringTree;
fMapNames: TStringList; // Names (keys) in fStringMap.
fSeenName: TStringList;
fSeenNames: TStringList;
public
constructor Create(AStringMap: TStringToStringTree);
constructor Create(AStringsMap: TStringToStringTree);
destructor Destroy; override;
function FindReplacement(AIdent: string; out AReplacement: string): boolean;
end;
@ -31,11 +31,9 @@ type
fGrid: TStringGrid;
GridEndInd: Integer;
public
constructor Create(AStringMap: TStringToStringTree; AGrid: TStringGrid);
constructor Create(AStringsMap: TStringToStringTree; AGrid: TStringGrid);
destructor Destroy; override;
procedure AddUniqueToGrid(AOldIdent: string);
procedure MapToGrid;
procedure GridToMap(AllowEmptyValues: boolean = true);
procedure AddUnique(AOldIdent: string);
end;
{ TReplaceNamesForm }
@ -67,23 +65,88 @@ var
ReplaceNamesForm: TReplaceNamesForm;
function FromMapToGrid(AMap: TStringToStringTree; AGrid: TStringGrid): boolean;
function FromGridToMap(AMap: TStringToStringTree; AGrid: TStringGrid;
AllowEmptyValues: boolean = true): boolean;
function EditMap(AMap: TStringToStringTree; ATitle: string): TModalResult;
implementation
{$R *.lfm}
function FromMapToGrid(AMap: TStringToStringTree; AGrid: TStringGrid): boolean;
// Copy strings from Map to Grid.
var
OldIdent, NewIdent: string;
List: TStringList;
i: Integer;
begin
List:=TStringList.Create;
try
AGrid.BeginUpdate;
AMap.GetNames(List);
for i:=0 to List.Count-1 do begin
OldIdent:=List[i];
NewIdent:=AMap[OldIdent];
if AGrid.RowCount<i+2 then
AGrid.RowCount:=i+2; // Leave one empty row to the end.
AGrid.Cells[0,i]:=OldIdent;
AGrid.Cells[1,i]:=NewIdent;
end;
AGrid.EndUpdate;
finally
List.Free;
end;
end;
function FromGridToMap(AMap: TStringToStringTree; AGrid: TStringGrid;
AllowEmptyValues: boolean = true): boolean;
var
OldIdent, NewIdent: string;
i: Integer;
begin
AMap.Clear;
// Collect (maybe edited) properties from StringGrid to fStringMap.
for i:=1 to AGrid.RowCount-1 do begin // Skip the fixed row.
OldIdent:=AGrid.Cells[0,i];
NewIdent:=AGrid.Cells[1,i];
if OldIdent<>'' then begin
if AllowEmptyValues or (NewIdent<>'') then
AMap[OldIdent]:=NewIdent;
end;
end;
end;
function EditMap(AMap: TStringToStringTree; ATitle: string): TModalResult;
var
RNForm: TReplaceNamesForm;
begin
RNForm:=TReplaceNamesForm.Create(nil);
try
RNForm.Caption:=ATitle;
FromMapToGrid(AMap, RNForm.Grid);
Result:=RNForm.ShowModal;
if Result=mrOK then
FromGridToMap(AMap, RNForm.Grid);
finally
RNForm.Free;
end;
end;
{ TStringMapUpdater }
constructor TStringMapUpdater.Create(AStringMap: TStringToStringTree);
constructor TStringMapUpdater.Create(AStringsMap: TStringToStringTree);
begin
fStringMap:=AStringMap;
fStringMap:=AStringsMap;
fMapNames:=TStringList.Create;
fStringMap.GetNames(fMapNames);
fSeenName:=TStringList.Create;
fSeenNames:=TStringList.Create;
end;
destructor TStringMapUpdater.Destroy;
begin
fSeenName.Free;
fSeenNames.Free;
fMapNames.Free;
inherited Destroy;
end;
@ -126,9 +189,9 @@ end;
{ TGridUpdater }
constructor TGridUpdater.Create(AStringMap: TStringToStringTree; AGrid: TStringGrid);
constructor TGridUpdater.Create(AStringsMap: TStringToStringTree; AGrid: TStringGrid);
begin
inherited Create(AStringMap);
inherited Create(AStringsMap);
fGrid:=AGrid;
GridEndInd:=1;
end;
@ -138,56 +201,14 @@ begin
inherited Destroy;
end;
procedure TGridUpdater.MapToGrid;
var
OldIdent, NewIdent: string;
List: TStringList;
i: Integer;
begin
// Copy properties from NameReplacements to StringGrid.
List:=TStringList.Create;
try
fGrid.BeginUpdate;
fStringMap.GetNames(List);
for i:=0 to List.Count-1 do begin
OldIdent:=List[i];
NewIdent:=fStringMap[OldIdent];
if fGrid.RowCount<i+2 then
fGrid.RowCount:=i+2; // Leave one empty row to the end.
fGrid.Cells[0,i]:=OldIdent;
fGrid.Cells[1,i]:=NewIdent;
end;
fGrid.EndUpdate;
finally
List.Free;
end;
end;
procedure TGridUpdater.GridToMap(AllowEmptyValues: boolean);
var
OldIdent, NewIdent: string;
i: Integer;
begin
fStringMap.Clear;
// Collect (maybe edited) properties from StringGrid to NameReplacements.
for i:=1 to fGrid.RowCount-1 do begin // Skip the fixed row.
OldIdent:=fGrid.Cells[0,i];
NewIdent:=fGrid.Cells[1,i];
if OldIdent<>'' then begin
if AllowEmptyValues or (NewIdent<>'') then
fStringMap[OldIdent]:=NewIdent;
end;
end;
end;
procedure TGridUpdater.AddUniqueToGrid(AOldIdent: string);
// Add a new Delphi -> Lazarus mapping to grid.
procedure TGridUpdater.AddUnique(AOldIdent: string);
// Add a new Delphi -> Lazarus mapping to the grid.
var
NewIdent: string;
begin
// Add only one instance of each property name.
if fSeenName.IndexOf(AOldIdent)<0 then begin
fSeenName.Append(AOldIdent);
if fSeenNames.IndexOf(AOldIdent)<0 then begin
fSeenNames.Append(AOldIdent);
FindReplacement(AOldIdent, NewIdent);
if fGrid.RowCount<GridEndInd+1 then
fGrid.RowCount:=GridEndInd+1;