Initial version of missing properties fixer.

git-svn-id: trunk@23801 -
This commit is contained in:
juha 2010-02-27 15:02:32 +00:00
parent 611903515a
commit 722da95ece
3 changed files with 1319 additions and 0 deletions

2
.gitattributes vendored
View File

@ -2211,6 +2211,8 @@ converter/convertdelphi.pas svneol=native#text/plain
converter/convertsettings.lfm svneol=native#text/plain
converter/convertsettings.pas svneol=native#text/plain
converter/lazxmlforms.pas svneol=native#text/plain
converter/missingpropertiesdlg.lfm svneol=native#text/plain
converter/missingpropertiesdlg.pas svneol=native#text/plain
converter/missingunits.lfm svneol=native#text/plain
converter/missingunits.pas svneol=native#text/plain
debian/README.Debian svneol=native#text/plain

View File

@ -0,0 +1,741 @@
object FixLFMDialog: TFixLFMDialog
Left = 337
Height = 580
Top = 150
Width = 749
ActiveControl = LFMSynEdit
Caption = 'Repair LFM file'
ClientHeight = 580
ClientWidth = 749
OnCreate = CheckLFMDialogCreate
LCLVersion = '0.9.29'
object NoteLabel: TLabel
Left = 0
Height = 16
Top = 0
Width = 749
Align = alTop
Caption = 'NoteLabel'
ParentColor = False
WordWrap = True
end
object LFMGroupBox: TGroupBox
Left = 0
Height = 412
Top = 16
Width = 408
Align = alLeft
Caption = 'LFM file'
ClientHeight = 390
ClientWidth = 398
TabOrder = 0
inline LFMSynEdit: TSynEdit
Left = 0
Height = 390
Top = 0
Width = 398
Align = alClient
Font.Height = -15
Font.Name = 'courier'
Font.Pitch = fpFixed
Font.Quality = fqNonAntialiased
ParentColor = False
ParentFont = False
TabOrder = 0
Gutter.Width = 59
Gutter.MouseActions = <
item
Shift = []
ShiftMask = []
Button = mbLeft
ClickCount = ccAny
ClickDir = cdDown
Command = 13
MoveCaret = False
Option = 0
Priority = 0
end
item
Shift = []
ShiftMask = []
Button = mbRight
ClickCount = ccSingle
ClickDir = cdUp
Command = 12
MoveCaret = False
Option = 0
Priority = 0
end>
Highlighter = SynLFMSyn1
Keystrokes = <
item
Command = ecUp
ShortCut = 38
end
item
Command = ecSelUp
ShortCut = 8230
end
item
Command = ecScrollUp
ShortCut = 16422
end
item
Command = ecDown
ShortCut = 40
end
item
Command = ecSelDown
ShortCut = 8232
end
item
Command = ecScrollDown
ShortCut = 16424
end
item
Command = ecLeft
ShortCut = 37
end
item
Command = ecSelLeft
ShortCut = 8229
end
item
Command = ecWordLeft
ShortCut = 16421
end
item
Command = ecSelWordLeft
ShortCut = 24613
end
item
Command = ecRight
ShortCut = 39
end
item
Command = ecSelRight
ShortCut = 8231
end
item
Command = ecWordRight
ShortCut = 16423
end
item
Command = ecSelWordRight
ShortCut = 24615
end
item
Command = ecPageDown
ShortCut = 34
end
item
Command = ecSelPageDown
ShortCut = 8226
end
item
Command = ecPageBottom
ShortCut = 16418
end
item
Command = ecSelPageBottom
ShortCut = 24610
end
item
Command = ecPageUp
ShortCut = 33
end
item
Command = ecSelPageUp
ShortCut = 8225
end
item
Command = ecPageTop
ShortCut = 16417
end
item
Command = ecSelPageTop
ShortCut = 24609
end
item
Command = ecLineStart
ShortCut = 36
end
item
Command = ecSelLineStart
ShortCut = 8228
end
item
Command = ecEditorTop
ShortCut = 16420
end
item
Command = ecSelEditorTop
ShortCut = 24612
end
item
Command = ecLineEnd
ShortCut = 35
end
item
Command = ecSelLineEnd
ShortCut = 8227
end
item
Command = ecEditorBottom
ShortCut = 16419
end
item
Command = ecSelEditorBottom
ShortCut = 24611
end
item
Command = ecToggleMode
ShortCut = 45
end
item
Command = ecCopy
ShortCut = 16429
end
item
Command = ecPaste
ShortCut = 8237
end
item
Command = ecDeleteChar
ShortCut = 46
end
item
Command = ecCut
ShortCut = 8238
end
item
Command = ecDeleteLastChar
ShortCut = 8
end
item
Command = ecDeleteLastChar
ShortCut = 8200
end
item
Command = ecDeleteLastWord
ShortCut = 16392
end
item
Command = ecUndo
ShortCut = 32776
end
item
Command = ecRedo
ShortCut = 40968
end
item
Command = ecLineBreak
ShortCut = 13
end
item
Command = ecSelectAll
ShortCut = 16449
end
item
Command = ecCopy
ShortCut = 16451
end
item
Command = ecBlockIndent
ShortCut = 24649
end
item
Command = ecLineBreak
ShortCut = 16461
end
item
Command = ecInsertLine
ShortCut = 16462
end
item
Command = ecDeleteWord
ShortCut = 16468
end
item
Command = ecBlockUnindent
ShortCut = 24661
end
item
Command = ecPaste
ShortCut = 16470
end
item
Command = ecCut
ShortCut = 16472
end
item
Command = ecDeleteLine
ShortCut = 16473
end
item
Command = ecDeleteEOL
ShortCut = 24665
end
item
Command = ecUndo
ShortCut = 16474
end
item
Command = ecRedo
ShortCut = 24666
end
item
Command = ecGotoMarker0
ShortCut = 16432
end
item
Command = ecGotoMarker1
ShortCut = 16433
end
item
Command = ecGotoMarker2
ShortCut = 16434
end
item
Command = ecGotoMarker3
ShortCut = 16435
end
item
Command = ecGotoMarker4
ShortCut = 16436
end
item
Command = ecGotoMarker5
ShortCut = 16437
end
item
Command = ecGotoMarker6
ShortCut = 16438
end
item
Command = ecGotoMarker7
ShortCut = 16439
end
item
Command = ecGotoMarker8
ShortCut = 16440
end
item
Command = ecGotoMarker9
ShortCut = 16441
end
item
Command = ecSetMarker0
ShortCut = 24624
end
item
Command = ecSetMarker1
ShortCut = 24625
end
item
Command = ecSetMarker2
ShortCut = 24626
end
item
Command = ecSetMarker3
ShortCut = 24627
end
item
Command = ecSetMarker4
ShortCut = 24628
end
item
Command = ecSetMarker5
ShortCut = 24629
end
item
Command = ecSetMarker6
ShortCut = 24630
end
item
Command = ecSetMarker7
ShortCut = 24631
end
item
Command = ecSetMarker8
ShortCut = 24632
end
item
Command = ecSetMarker9
ShortCut = 24633
end
item
Command = ecNormalSelect
ShortCut = 24654
end
item
Command = ecColumnSelect
ShortCut = 24643
end
item
Command = ecLineSelect
ShortCut = 24652
end
item
Command = ecTab
ShortCut = 9
end
item
Command = ecShiftTab
ShortCut = 8201
end
item
Command = ecMatchBracket
ShortCut = 24642
end>
MouseActions = <
item
Shift = []
ShiftMask = [ssShift, ssAlt]
Button = mbLeft
ClickCount = ccSingle
ClickDir = cdDown
Command = 1
MoveCaret = True
Option = 0
Priority = 0
end
item
Shift = [ssShift]
ShiftMask = [ssShift, ssAlt]
Button = mbLeft
ClickCount = ccSingle
ClickDir = cdDown
Command = 1
MoveCaret = True
Option = 1
Priority = 0
end
item
Shift = [ssAlt]
ShiftMask = [ssShift, ssAlt]
Button = mbLeft
ClickCount = ccSingle
ClickDir = cdDown
Command = 3
MoveCaret = True
Option = 0
Priority = 0
end
item
Shift = [ssShift, ssAlt]
ShiftMask = [ssShift, ssAlt]
Button = mbLeft
ClickCount = ccSingle
ClickDir = cdDown
Command = 3
MoveCaret = True
Option = 1
Priority = 0
end
item
Shift = []
ShiftMask = []
Button = mbRight
ClickCount = ccSingle
ClickDir = cdUp
Command = 12
MoveCaret = False
Option = 0
Priority = 0
end
item
Shift = []
ShiftMask = []
Button = mbLeft
ClickCount = ccDouble
ClickDir = cdDown
Command = 6
MoveCaret = True
Option = 0
Priority = 0
end
item
Shift = []
ShiftMask = []
Button = mbLeft
ClickCount = ccTriple
ClickDir = cdDown
Command = 7
MoveCaret = True
Option = 0
Priority = 0
end
item
Shift = []
ShiftMask = []
Button = mbLeft
ClickCount = ccQuad
ClickDir = cdDown
Command = 8
MoveCaret = True
Option = 0
Priority = 0
end
item
Shift = []
ShiftMask = []
Button = mbMiddle
ClickCount = ccSingle
ClickDir = cdDown
Command = 10
MoveCaret = True
Option = 0
Priority = 0
end
item
Shift = [ssCtrl]
ShiftMask = [ssShift, ssAlt, ssCtrl]
Button = mbLeft
ClickCount = ccSingle
ClickDir = cdUp
Command = 11
MoveCaret = False
Option = 0
Priority = 0
end>
MouseSelActions = <
item
Shift = []
ShiftMask = []
Button = mbLeft
ClickCount = ccSingle
ClickDir = cdDown
Command = 9
MoveCaret = False
Option = 0
Priority = 0
end>
Lines.Strings = (
'LFMSynEdit'
)
BracketHighlightStyle = sbhsBoth
OnSpecialLineMarkup = LFMSynEditSpecialLineMarkup
inline TSynGutterPartList
object TSynGutterMarks
Width = 23
end
object TSynGutterLineNumber
Width = 19
MouseActions = <>
MarkupInfo.Background = clBtnFace
MarkupInfo.Foreground = clNone
DigitCount = 2
ShowOnlyLineNumbersMultiplesOf = 1
ZeroStart = False
LeadingZeros = False
end
object TSynGutterChanges
Width = 4
ModifiedColor = 59900
SavedColor = clGreen
end
object TSynGutterSeparator
Width = 2
end
object TSynGutterCodeFolding
MouseActions = <
item
Shift = []
ShiftMask = []
Button = mbRight
ClickCount = ccSingle
ClickDir = cdUp
Command = 16
MoveCaret = False
Option = 0
Priority = 0
end
item
Shift = []
ShiftMask = [ssShift]
Button = mbMiddle
ClickCount = ccAny
ClickDir = cdDown
Command = 14
MoveCaret = False
Option = 0
Priority = 0
end
item
Shift = [ssShift]
ShiftMask = [ssShift]
Button = mbMiddle
ClickCount = ccAny
ClickDir = cdDown
Command = 14
MoveCaret = False
Option = 1
Priority = 0
end
item
Shift = []
ShiftMask = []
Button = mbLeft
ClickCount = ccAny
ClickDir = cdDown
Command = 0
MoveCaret = False
Option = 0
Priority = 0
end>
MarkupInfo.Background = clNone
MarkupInfo.Foreground = clGray
MouseActionsExpanded = <
item
Shift = []
ShiftMask = []
Button = mbLeft
ClickCount = ccAny
ClickDir = cdDown
Command = 14
MoveCaret = False
Option = 0
Priority = 0
end>
MouseActionsCollapsed = <
item
Shift = [ssCtrl]
ShiftMask = [ssCtrl]
Button = mbLeft
ClickCount = ccAny
ClickDir = cdDown
Command = 15
MoveCaret = False
Option = 0
Priority = 0
end
item
Shift = []
ShiftMask = [ssCtrl]
Button = mbLeft
ClickCount = ccAny
ClickDir = cdDown
Command = 15
MoveCaret = False
Option = 1
Priority = 0
end>
end
end
end
end
object ErrorsGroupBox: TGroupBox
Left = 0
Height = 104
Top = 428
Width = 749
Align = alBottom
Caption = 'Errors'
ClientHeight = 82
ClientWidth = 739
TabOrder = 1
object ErrorsListBox: TListBox
Left = 0
Height = 82
Top = 0
Width = 739
Align = alClient
ItemHeight = 0
OnClick = ErrorsListBoxClick
TabOrder = 0
end
end
object BtnPanel: TPanel
Left = 0
Height = 48
Top = 532
Width = 749
Align = alBottom
AutoSize = True
BevelOuter = bvNone
ClientHeight = 48
ClientWidth = 749
TabOrder = 2
object CancelButton: TBitBtn
Left = 662
Height = 36
Top = 6
Width = 81
Align = alRight
AutoSize = True
BorderSpacing.Around = 6
Cancel = True
Caption = 'Cancel'
Kind = bkCancel
ModalResult = 2
NumGlyphs = 0
TabOrder = 0
end
object RemoveAllButton: TBitBtn
Left = 6
Height = 25
Top = 6
Width = 175
AutoSize = True
BorderSpacing.Around = 6
Caption = 'Remove all invalid properties'
NumGlyphs = 0
OnClick = RemoveAllButtonClick
TabOrder = 1
end
object ReplaceAllButton: TBitBtn
AnchorSideLeft.Control = RemoveAllButton
AnchorSideLeft.Side = asrBottom
Left = 192
Height = 25
Top = 6
Width = 137
AutoSize = True
BorderSpacing.Left = 11
Caption = 'Replace all properties'
OnClick = ReplaceAllButtonClick
TabOrder = 2
Visible = False
end
end
object PropertyReplaceGroupBox: TGroupBox
Left = 413
Height = 412
Top = 16
Width = 336
Align = alClient
Caption = 'Properties to replace'
ClientHeight = 390
ClientWidth = 326
TabOrder = 3
object PropertyReplaceGrid: TStringGrid
Left = 0
Height = 390
Top = 0
Width = 326
Align = alClient
ColCount = 3
Columns = <
item
Title.Caption = 'Delphi Property'
end
item
Title.Caption = 'New Property'
end>
TabOrder = 0
end
end
object Splitter1: TSplitter
Left = 408
Height = 412
Top = 16
Width = 5
end
object SynLFMSyn1: TSynLFMSyn
DefaultFilter = 'Lazarus Form Files (*.lfm)|*.lfm'
Enabled = False
left = 129
top = 104
end
end

View File

@ -0,0 +1,576 @@
{ $Id$ }
{
/***************************************************************************
checklfmdlg.pas
---------------
***************************************************************************/
***************************************************************************
* *
* 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. *
* *
***************************************************************************
}
unit MissingPropertiesDlg;
{$mode objfpc}{$H+}
interface
uses
// FCL+LCL
Classes, SysUtils, Math, TypInfo, LCLProc, Forms, Controls, LResources,
Graphics, Dialogs, Buttons, StdCtrls,
// components
SynHighlighterLFM, SynEdit, BasicCodeTools, CodeCache, CodeToolManager,
SynEditMiscClasses, LFMTrees,
// IDE
PropEdits, IDEDialogs, ComponentReg, PackageIntf, IDEWindowIntf,
CustomFormEditor, LazarusIDEStrConsts, OutputFilter, IDEProcs, IDEOptionDefs,
EditorOptions, ExtCtrls, Grids, JITForms, PropEditUtils;
type
{ TLfmFixer }
TLfmFixer = class
private
fPascalBuffer: TCodeBuffer;
fLfmBuffer: TCodeBuffer;
fOnOutput: TOnAddFilteredLine;
fRootMustBeClassInIntf: boolean;
fObjectsMustExists: boolean;
fLfmTree: TLFMTree;
procedure WriteUnitError(Code: TCodeBuffer; x, Y: integer;
const ErrorMessage: string);
procedure WriteCodeToolsError;
procedure WriteLFMErrors;
function FixMissingComponentClasses: TModalResult;
function CheckUnit: boolean;
function ShowRepairLFMWizard: TModalResult;
public
constructor Create(APascalBuffer, ALfmBuffer: TCodeBuffer;
const AOnOutput: TOnAddFilteredLine);
destructor Destroy; override;
function Repair: TModalResult;
public
property PascalBuffer: TCodeBuffer read fPascalBuffer;
property LfmBuffer: TCodeBuffer read fLfmBuffer;
property OnOutput: TOnAddFilteredLine read fOnOutput;
property RootMustBeClassInIntf: boolean read fRootMustBeClassInIntf
write fRootMustBeClassInIntf;
property ObjectsMustExists: boolean read fObjectsMustExists
write fObjectsMustExists;
end;
{ TFixLFMDialog }
TFixLFMDialog = class(TForm)
ReplaceAllButton: TBitBtn;
CancelButton: TBitBtn;
ErrorsGroupBox: TGroupBox;
ErrorsListBox: TListBox;
PropertyReplaceGroupBox: TGroupBox;
NoteLabel: TLabel;
LFMGroupBox: TGroupBox;
LFMSynEdit: TSynEdit;
BtnPanel: TPanel;
RemoveAllButton: TBitBtn;
Splitter1: TSplitter;
PropertyReplaceGrid: TStringGrid;
SynLFMSyn1: TSynLFMSyn;
procedure ErrorsListBoxClick(Sender: TObject);
procedure LFMSynEditSpecialLineMarkup(Sender: TObject; Line: integer;
var Special: boolean; AMarkup: TSynSelectedColor);
procedure RemoveAllButtonClick(Sender: TObject);
procedure CheckLFMDialogCREATE(Sender: TObject);
procedure ReplaceAllButtonClick(Sender: TObject);
private
fLFMSource: TCodeBuffer;
fLFMTree: TLFMTree;
procedure SetLFMSource(const AValue: TCodeBuffer);
procedure SetLFMTree(const AValue: TLFMTree);
procedure SetupComponents;
function FindListBoxError: TLFMError;
procedure JumpToError(LFMError: TLFMError);
procedure FindNiceNodeBounds(LFMNode: TLFMTreeNode;
var StartPos, EndPos: integer);
procedure AddReplacement(LFMChangeList: TList; StartPos, EndPos: integer;
const NewText: string);
function ApplyReplacements(LFMChangeList: TList): boolean;
public
procedure LoadLFM;
procedure FillErrorsListBox;
function AutomaticFixIsPossible: boolean;
property LFMTree: TLFMTree read fLFMTree write SetLFMTree;
property LFMSource: TCodeBuffer read fLFMSource write SetLFMSource;
end;
implementation
{$R *.lfm}
type
TLFMChangeEntry = class
public
StartPos, EndPos: integer;
NewText: string;
end;
{ TLfmFixer }
constructor TLfmFixer.Create(APascalBuffer, ALfmBuffer: TCodeBuffer;
const AOnOutput: TOnAddFilteredLine);
begin
fPascalBuffer:=APascalBuffer;
fLfmBuffer:=ALfmBuffer;
fOnOutput:=AOnOutput;
fRootMustBeClassInIntf:=true;
fObjectsMustExists:=true;
end;
destructor TLfmFixer.Destroy;
begin
inherited Destroy;
end;
function TLfmFixer.Repair: TModalResult;
begin
Result:=mrCancel;
if not CheckUnit then begin
exit;
end;
if CodeToolBoss.CheckLFM(fPascalBuffer,fLfmBuffer,fLfmTree,
fRootMustBeClassInIntf,fObjectsMustExists)
then begin
Result:=mrOk;
exit;
end;
Result:=FixMissingComponentClasses;
if Result in [mrAbort,mrOk] then begin
exit;
end;
WriteLFMErrors;
Result:=ShowRepairLFMWizard;
end;
procedure TLfmFixer.WriteUnitError(Code: TCodeBuffer; x, Y: integer;
const ErrorMessage: string);
var
Dir: String;
Filename: String;
Msg: String;
begin
if not Assigned(fOnOutput) then exit;
if Code=nil then
Code:=fPascalBuffer;
Dir:=ExtractFilePath(Code.Filename);
Filename:=ExtractFilename(Code.Filename);
Msg:=Filename
+'('+IntToStr(Y)+','+IntToStr(X)+')'
+' Error: '
+ErrorMessage;
fOnOutput(Msg,Dir,-1,nil);
end;
procedure TLfmFixer.WriteCodeToolsError;
begin
WriteUnitError(CodeToolBoss.ErrorCode,CodeToolBoss.ErrorColumn,
CodeToolBoss.ErrorLine,CodeToolBoss.ErrorMessage);
end;
procedure TLfmFixer.WriteLFMErrors;
var
CurError: TLFMError;
Dir: String;
Msg: String;
Filename: String;
begin
if not Assigned(fOnOutput) then exit;
CurError:=fLfmTree.FirstError;
Dir:=ExtractFilePath(fLfmBuffer.Filename);
Filename:=ExtractFilename(fLfmBuffer.Filename);
while CurError<>nil do begin
Msg:=Filename
+'('+IntToStr(CurError.Caret.Y)+','+IntToStr(CurError.Caret.X)+')'
+' Error: '
+CurError.ErrorMessage;
fOnOutput(Msg,Dir,-1,nil);
CurError:=CurError.NextError;
end;
end;
function TLfmFixer.FixMissingComponentClasses: TModalResult;
// returns true, if after adding units to uses section all errors are fixed
var
CurError: TLFMError;
MissingObjectTypes: TStringList;
TypeName: String;
RegComp: TRegisteredComponent;
i: Integer;
begin
Result:=mrCancel;
MissingObjectTypes:=TStringList.Create;
try
// collect all missing object types
CurError:=fLfmTree.FirstError;
while CurError<>nil do begin
if CurError.IsMissingObjectType then begin
TypeName:=(CurError.Node as TLFMObjectNode).TypeName;
if MissingObjectTypes.IndexOf(TypeName)<0 then
MissingObjectTypes.Add(TypeName);
end;
CurError:=CurError.NextError;
end;
// FixMissingComponentClasses Missing object types in unit.
// keep all object types with a registered component class
for i:=MissingObjectTypes.Count-1 downto 0 do begin
RegComp:=IDEComponentPalette.FindComponent(MissingObjectTypes[i]);
if (RegComp=nil) or (RegComp.GetUnitName='') then
MissingObjectTypes.Delete(i);
end;
if MissingObjectTypes.Count=0 then exit;
//FixMissingComponentClasses Missing object types, but luckily found in IDE.
// there are missing object types with registered component classes
Result:=PackageEditingInterface.AddUnitDependenciesForComponentClasses(
fPascalBuffer.Filename,MissingObjectTypes);
if Result<>mrOk then begin
exit;
end;
// check LFM again
if CodeToolBoss.CheckLFM(fPascalBuffer,fLfmBuffer,fLfmTree,
fRootMustBeClassInIntf,fObjectsMustExists)
then begin
Result:=mrOk;
end else begin
Result:=mrCancel;
end;
finally
MissingObjectTypes.Free;
end;
end;
function TLfmFixer.CheckUnit: boolean;
var
NewCode: TCodeBuffer;
NewX, NewY, NewTopLine: integer;
ErrorMsg: string;
MissingUnits: TStrings;
s: String;
begin
Result:=false;
// check syntax
if not CodeToolBoss.CheckSyntax(fPascalBuffer,NewCode,NewX,NewY,NewTopLine,ErrorMsg)
then begin
WriteUnitError(NewCode,NewX,NewY,ErrorMsg);
exit;
end;
// check used units
MissingUnits:=nil;
try
if not CodeToolBoss.FindMissingUnits(fPascalBuffer,MissingUnits,false,
false)
then begin
WriteCodeToolsError;
exit;
end;
if (MissingUnits<>nil) and (MissingUnits.Count>0) then begin
s:=StringListToText(MissingUnits,',');
WriteUnitError(fPascalBuffer,1,1,'Units not found: '+s);
exit;
end;
finally
MissingUnits.Free;
end;
if NewTopLine=0 then ;
Result:=true;
end;
function TLfmFixer.ShowRepairLFMWizard: TModalResult;
var
FixLFMDialog: TFixLFMDialog;
begin
Result:=mrCancel;
FixLFMDialog:=TFixLFMDialog.Create(nil);
FixLFMDialog.LFMTree:=fLfmTree;
FixLFMDialog.LFMSource:=fLfmBuffer;
FixLFMDialog.LoadLFM;
Result:=FixLFMDialog.ShowModal;
FixLFMDialog.Free;
end;
{ TFixLFMDialog }
procedure TFixLFMDialog.ReplaceAllButtonClick(Sender: TObject);
begin
;
end;
procedure TFixLFMDialog.RemoveAllButtonClick(Sender: TObject);
var
CurError: TLFMError;
DeleteNode: TLFMTreeNode;
StartPos, EndPos: integer;
Replacements: TList;
i: integer;
begin
Replacements:=TList.Create;
try
// automatically delete each error location
CurError:=LFMTree.LastError;
while CurError<>nil do begin
DeleteNode:=CurError.FindContextNode;
if (DeleteNode<>nil) and (DeleteNode.Parent<>nil) then begin
FindNiceNodeBounds(DeleteNode,StartPos,EndPos);
AddReplacement(Replacements,StartPos,EndPos,'');
end;
CurError:=CurError.PrevError;
end;
if ApplyReplacements(Replacements) then
ModalResult:=mrOk;
finally
for i := 0 to Replacements.Count - 1 do
TObject(Replacements[i]).Free;
Replacements.Free;
end;
end;
procedure TFixLFMDialog.ErrorsListBoxClick(Sender: TObject);
begin
JumpToError(FindListBoxError);
end;
procedure TFixLFMDialog.LFMSynEditSpecialLineMarkup(Sender: TObject;
Line: integer; var Special: boolean; AMarkup: TSynSelectedColor);
var
CurError: TLFMError;
begin
CurError:=LFMTree.FindErrorAtLine(Line);
if CurError = nil then Exit;
Special := True;
EditorOpts.SetMarkupColor(SynLFMSyn1, ahaErrorLine, AMarkup);
end;
procedure TFixLFMDialog.CheckLFMDialogCREATE(Sender: TObject);
begin
Caption:=lisFixLFMFile;
Position:=poScreenCenter;
IDEDialogLayoutList.ApplyLayout(Self,600,400);
SetupComponents;
end;
procedure TFixLFMDialog.SetLFMSource(const AValue: TCodeBuffer);
begin
if fLFMSource=AValue then exit;
fLFMSource:=AValue;
end;
procedure TFixLFMDialog.SetLFMTree(const AValue: TLFMTree);
begin
if fLFMTree=AValue then exit;
fLFMTree:=AValue;
RemoveAllButton.Enabled:=AutomaticFixIsPossible;
end;
procedure TFixLFMDialog.SetupComponents;
const // Will be moved to LazarusIDEStrConsts
lisReplaceAllProperties = 'Replace all properties';
begin
NoteLabel.Caption:=lisTheLFMLazarusFormFileContainsInvalidPropertiesThis;
ErrorsGroupBox.Caption:=lisErrors;
LFMGroupBox.Caption:=lisLFMFile;
RemoveAllButton.Caption:=lisRemoveAllInvalidProperties;
RemoveAllButton.LoadGlyphFromLazarusResource('laz_delete');
ReplaceAllButton.Caption:=lisReplaceAllProperties;
ReplaceAllButton.LoadGlyphFromLazarusResource('laz_refresh');
EditorOpts.GetHighlighterSettings(SynLFMSyn1);
EditorOpts.GetSynEditSettings(LFMSynEdit);
end;
function TFixLFMDialog.FindListBoxError: TLFMError;
var
i: Integer;
begin
Result:=nil;
i:=ErrorsListBox.ItemIndex;
if (i<0) or (i>=ErrorsListBox.Items.Count) then exit;
Result:=LFMTree.FirstError;
while Result<>nil do begin
if i=0 then exit;
Result:=Result.NextError;
dec(i);
end;
end;
procedure TFixLFMDialog.JumpToError(LFMError: TLFMError);
begin
if LFMError=nil then exit;
LFMSynEdit.CaretXY:=LFMError.Caret;
end;
procedure TFixLFMDialog.FindNiceNodeBounds(LFMNode: TLFMTreeNode;
var StartPos, EndPos: integer);
var
Src: String;
begin
Src:=LFMSource.Source;
StartPos:=FindLineEndOrCodeInFrontOfPosition(Src,LFMNode.StartPos,1,false,true);
EndPos:=FindLineEndOrCodeInFrontOfPosition(Src,LFMNode.EndPos,1,false,true);
EndPos:=FindLineEndOrCodeAfterPosition(Src,EndPos,length(Src),false);
end;
procedure TFixLFMDialog.AddReplacement(LFMChangeList: TList;
StartPos, EndPos: integer; const NewText: string);
var
Entry: TLFMChangeEntry;
NewEntry: TLFMChangeEntry;
i: Integer;
begin
if StartPos>EndPos then
RaiseException('TCheckLFMDialog.AddReplaceMent StartPos>EndPos');
// check for intersection
for i:=0 to LFMChangeList.Count-1 do begin
Entry:=TLFMChangeEntry(LFMChangeList[i]);
if ((Entry.StartPos<EndPos) and (Entry.EndPos>StartPos)) then begin
// New and Entry intersects
if (Entry.NewText='') and (NewText='') then begin
// both are deletes => combine
StartPos:=Min(StartPos,Entry.StartPos);
EndPos:=Max(EndPos,Entry.EndPos);
end else begin
// not allowed
RaiseException('TCheckLFMDialog.AddReplaceMent invalid Intersection');
end;
end;
end;
// combine deletions
if NewText='' then begin
for i:=LFMChangeList.Count-1 downto 0 do begin
Entry:=TLFMChangeEntry(LFMChangeList[i]);
if ((Entry.StartPos<EndPos) and (Entry.EndPos>StartPos)) then begin
// New and Entry intersects
// -> remove Entry
LFMChangeList.Delete(i);
Entry.Free;
end;
end;
end;
// insert new entry
NewEntry:=TLFMChangeEntry.Create;
NewEntry.NewText:=NewText;
NewEntry.StartPos:=StartPos;
NewEntry.EndPos:=EndPos;
if LFMChangeList.Count=0 then begin
LFMChangeList.Add(NewEntry);
end else begin
for i:=0 to LFMChangeList.Count-1 do begin
Entry:=TLFMChangeEntry(LFMChangeList[i]);
if EndPos<=Entry.StartPos then begin
// insert in front
LFMChangeList.Insert(i,NewEntry);
break;
end else if i=LFMChangeList.Count-1 then begin
// insert behind
LFMChangeList.Add(NewEntry);
break;
end;
end;
end;
end;
function TFixLFMDialog.ApplyReplacements(LFMChangeList: TList): boolean;
var
i: Integer;
Entry: TLFMChangeEntry;
begin
Result:=false;
for i:=LFMChangeList.Count-1 downto 0 do begin
Entry:=TLFMChangeEntry(LFMChangeList[i]);
// DebugLn('TCheckLFMDialog.ApplyReplacements A ',IntToStr(i),' ',
// IntToStr(Entry.StartPos),',',IntToStr(Entry.EndPos),
// ' "',copy(LFMSource.Source,Entry.StartPos,Entry.EndPos-Entry.StartPos),'" -> "',Entry.NewText,'"');
LFMSource.Replace(Entry.StartPos,Entry.EndPos-Entry.StartPos,Entry.NewText);
end;
//writeln(LFMSource.Source);
Result:=true;
end;
procedure TFixLFMDialog.LoadLFM;
begin
LFMSynEdit.Lines.Text:=LFMSource.Source;
FillErrorsListBox;
end;
procedure TFixLFMDialog.FillErrorsListBox;
var
CurError: TLFMError;
Filename: String;
Msg: String;
begin
ErrorsListBox.Items.BeginUpdate;
ErrorsListBox.Items.Clear;
if LFMTree<>nil then begin
Filename:=ExtractFileName(LFMSource.Filename);
CurError:=LFMTree.FirstError;
while CurError<>nil do begin
Msg:=Filename
+'('+IntToStr(CurError.Caret.Y)+','+IntToStr(CurError.Caret.X)+')'
+' Error: '
+CurError.ErrorMessage;
ErrorsListBox.Items.Add(Msg);
CurError:=CurError.NextError;
end;
end;
ErrorsListBox.Items.EndUpdate;
end;
function TFixLFMDialog.AutomaticFixIsPossible: boolean;
var
CurError: TLFMError;
begin
Result:=true;
CurError:=LFMTree.FirstError;
while CurError<>nil do begin
if CurError.ErrorType in [lfmeNoError,lfmeIdentifierNotFound,
lfmeObjectNameMissing,lfmeObjectIncompatible,lfmePropertyNameMissing,
lfmePropertyHasNoSubProperties,lfmeIdentifierNotPublished]
then begin
// these things can be fixed automatically
end else begin
// these not
Result:=false;
exit;
end;
CurError:=CurError.NextError;
end;
end;
end.