IDE: added refactoring tool show abstract methods

git-svn-id: trunk@13212 -
This commit is contained in:
mattias 2007-12-07 23:16:21 +00:00
parent 65148452ac
commit b27b9bb629
15 changed files with 743 additions and 111 deletions

3
.gitattributes vendored
View File

@ -1792,6 +1792,9 @@ ide/Makefile.fpc svneol=native#text/plain
ide/aboutfrm.lfm svneol=native#text/plain ide/aboutfrm.lfm svneol=native#text/plain
ide/aboutfrm.lrs svneol=native#text/pascal ide/aboutfrm.lrs svneol=native#text/pascal
ide/aboutfrm.pas svneol=native#text/pascal ide/aboutfrm.pas svneol=native#text/pascal
ide/abstractsmethodsdlg.lfm svneol=native#text/plain
ide/abstractsmethodsdlg.lrs svneol=native#text/plain
ide/abstractsmethodsdlg.pas svneol=native#text/plain
ide/addtoprojectdlg.lfm svneol=native#text/plain ide/addtoprojectdlg.lfm svneol=native#text/plain
ide/addtoprojectdlg.lrs svneol=native#text/plain ide/addtoprojectdlg.lrs svneol=native#text/plain
ide/addtoprojectdlg.pas svneol=native#text/pascal ide/addtoprojectdlg.pas svneol=native#text/pascal

View File

@ -1485,12 +1485,11 @@ begin
ReadRawNextPascalAtom(ProcText,p,AtomStart,NestedComments); ReadRawNextPascalAtom(ProcText,p,AtomStart,NestedComments);
if AtomStart>length(ProcText) then exit; if AtomStart>length(ProcText) then exit;
if ProcText[AtomStart] in ['[','('] then begin if ProcText[AtomStart] in ['[','('] then begin
if not ReadTilPascalBracketClose(ProcText,AtomStart,NestedComments) then if not ReadTilPascalBracketClose(ProcText,p,NestedComments) then
exit; exit;
p:=AtomStart;
end else if ProcText[AtomStart]=';' then begin end else if ProcText[AtomStart]=';' then begin
ReadRawNextPascalAtom(ProcText,p,AtomStart,NestedComments); ReadRawNextPascalAtom(ProcText,p,AtomStart,NestedComments);
Result:=p; Result:=AtomStart;
exit; exit;
end; end;
end; end;
@ -1515,10 +1514,9 @@ begin
break; break;
end; end;
if ProcText[AtomStart] in ['[','('] then begin if ProcText[AtomStart] in ['[','('] then begin
if not ReadTilPascalBracketClose(ProcText,AtomStart,NestedComments) if not ReadTilPascalBracketClose(ProcText,Result,NestedComments)
then then
exit(-1); exit(-1);
Result:=AtomStart;
end; end;
end; end;
SpecifierEndPosition:=Result; SpecifierEndPosition:=Result;
@ -1527,10 +1525,9 @@ begin
ReadRawNextPascalAtom(ProcText,SpecifierEndPosition,AtomStart,NestedComments); ReadRawNextPascalAtom(ProcText,SpecifierEndPosition,AtomStart,NestedComments);
if AtomStart>length(ProcText) then exit; if AtomStart>length(ProcText) then exit;
if ProcText[AtomStart] in ['[','('] then begin if ProcText[AtomStart] in ['[','('] then begin
if not ReadTilPascalBracketClose(ProcText,AtomStart,NestedComments) if not ReadTilPascalBracketClose(ProcText,SpecifierEndPosition,NestedComments)
then then
exit(-1); exit(-1);
SpecifierEndPosition:=AtomStart;
end; end;
end; end;
if WithSpaceBehindSemicolon and (SpecifierEndPosition<=length(ProcText)) then if WithSpaceBehindSemicolon and (SpecifierEndPosition<=length(ProcText)) then
@ -1538,6 +1535,7 @@ begin
SpecifierEndPosition:=FindLineEndOrCodeAfterPosition(ProcText, SpecifierEndPosition:=FindLineEndOrCodeAfterPosition(ProcText,
SpecifierEndPosition+1,0,NestedComments); SpecifierEndPosition+1,0,NestedComments);
end; end;
//DebugLn(['SearchProcSpecifier ',copy(ProcText,Result,SpecifierEndPosition-Result)]);
end; end;
function RemoveProcSpecifier(const ProcText, Specifier: string; function RemoveProcSpecifier(const ProcText, Specifier: string;
@ -1815,15 +1813,18 @@ begin
AtomStart:=Position; AtomStart:=Position;
while Position<=Len do begin while Position<=Len do begin
ReadRawNextPascalAtom(Source,Position,AtomStart,NestedComments); ReadRawNextPascalAtom(Source,Position,AtomStart,NestedComments);
//DebugLn(['ReadTilPascalBracketClose ',copy(Source,AtomStart,Position-AtomStart)]);
if Position>Len then if Position>Len then
exit; // CloseBracket not found exit; // CloseBracket not found
case Source[Position] of case Source[AtomStart] of
'{','(','[': '{','(','[':
if not ReadTilPascalBracketClose(Source,Position) then exit; begin
if not ReadTilPascalBracketClose(Source,AtomStart) then exit;
Position:=AtomStart;
end;
'}',')',']': '}',')',']':
if Source[Position]=CloseBracket then begin if Source[AtomStart]=CloseBracket then begin
// CloseBracket found // CloseBracket found
inc(Position);
Result:=true; Result:=true;
exit; exit;
end else begin end else begin

View File

@ -121,7 +121,7 @@ type
FirstInsert: TCodeTreeNodeExtension; // list of insert requests FirstInsert: TCodeTreeNodeExtension; // list of insert requests
FOnGetNewVariableLocation: TOnGetNewVariableLocation; FOnGetNewVariableLocation: TOnGetNewVariableLocation;
FSetPropertyVariablename: string; FSetPropertyVariablename: string;
JumpToProcName: string; FJumpToProcName: string;
NewClassSectionIndent: array[TPascalClassSection] of integer; NewClassSectionIndent: array[TPascalClassSection] of integer;
NewClassSectionInsertPos: array[TPascalClassSection] of integer; NewClassSectionInsertPos: array[TPascalClassSection] of integer;
fFullTopLvlName: string;// used by OnTopLvlIdentifierFound fFullTopLvlName: string;// used by OnTopLvlIdentifierFound
@ -142,6 +142,9 @@ type
function InsertMissingClassSemicolons: boolean; function InsertMissingClassSemicolons: boolean;
function InsertAllNewUnitsToMainUsesSection: boolean; function InsertAllNewUnitsToMainUsesSection: boolean;
function CreateMissingProcBodies: boolean; function CreateMissingProcBodies: boolean;
function ApplyChangesAndJumpToFirstNewProc(CleanPos: integer;
OldTopLine: integer;
out NewPos: TCodeXYPosition; out NewTopLine: integer): boolean;
function NodeExtIsVariable(ANodeExt: TCodeTreeNodeExtension): boolean; function NodeExtIsVariable(ANodeExt: TCodeTreeNodeExtension): boolean;
function NodeExtHasVisibilty(ANodeExt: TCodeTreeNodeExtension; function NodeExtHasVisibilty(ANodeExt: TCodeTreeNodeExtension;
Visibility: TPascalClassSection): boolean; Visibility: TPascalClassSection): boolean;
@ -157,7 +160,7 @@ type
var NewPos: TCodeXYPosition; var NewTopLine: integer; var NewPos: TCodeXYPosition; var NewTopLine: integer;
SourceChangeCache: TSourceChangeCache): boolean; SourceChangeCache: TSourceChangeCache): boolean;
procedure AdjustCursor(OldCodePos: TCodePosition; OldTopLine: integer; procedure AdjustCursor(OldCodePos: TCodePosition; OldTopLine: integer;
var NewPos: TCodeXYPosition; var NewTopLine: integer); out NewPos: TCodeXYPosition; out NewTopLine: integer);
function AddVariable(CursorNode: TCodeTreeNode; function AddVariable(CursorNode: TCodeTreeNode;
CleanCursorPos,OldTopLine: integer; CleanCursorPos,OldTopLine: integer;
const VariableName, NewType: string; const VariableName, NewType: string;
@ -187,8 +190,10 @@ type
out NewPos: TCodeXYPosition; out NewTopLine: integer; out NewPos: TCodeXYPosition; out NewTopLine: integer;
SourceChangeCache: TSourceChangeCache): boolean; SourceChangeCache: TSourceChangeCache): boolean;
function AddMethods(CursorPos: TCodeXYPosition;// position in class declaration function AddMethods(CursorPos: TCodeXYPosition;// position in class declaration
OldTopLine: integer;
ListOfPCodeXYPosition: TFPList; ListOfPCodeXYPosition: TFPList;
const VirtualToOverride: boolean; const VirtualToOverride: boolean;
out NewPos: TCodeXYPosition; out NewTopLine: integer;
SourceChangeCache: TSourceChangeCache): boolean; SourceChangeCache: TSourceChangeCache): boolean;
function AddPublishedVariable(const UpperClassName,VarName, VarType: string; function AddPublishedVariable(const UpperClassName,VarName, VarType: string;
SourceChangeCache: TSourceChangeCache): boolean; override; SourceChangeCache: TSourceChangeCache): boolean; override;
@ -314,7 +319,7 @@ begin
FCompletingStartNode:=FCompletingStartNode.NextBrother; FCompletingStartNode:=FCompletingStartNode.NextBrother;
if FCompletingStartNode<>nil then if FCompletingStartNode<>nil then
FCompletingStartNode:=FCompletingStartNode.FirstChild; FCompletingStartNode:=FCompletingStartNode.FirstChild;
JumpToProcName:=''; FJumpToProcName:='';
end; end;
procedure TCodeCompletionCodeTool.SetCodeCompleteSrcChgCache( procedure TCodeCompletionCodeTool.SetCodeCompleteSrcChgCache(
@ -826,7 +831,7 @@ begin
end; end;
procedure TCodeCompletionCodeTool.AdjustCursor(OldCodePos: TCodePosition; procedure TCodeCompletionCodeTool.AdjustCursor(OldCodePos: TCodePosition;
OldTopLine: integer; var NewPos: TCodeXYPosition; var NewTopLine: integer); OldTopLine: integer; out NewPos: TCodeXYPosition; out NewTopLine: integer);
begin begin
OldCodePos.Code.AdjustPosition(OldCodePos.P); OldCodePos.Code.AdjustPosition(OldCodePos.P);
NewPos.Code:=OldCodePos.Code; NewPos.Code:=OldCodePos.Code;
@ -4648,13 +4653,13 @@ var
ProcCode,Indent,ANodeExt.ExtTxt3=''); ProcCode,Indent,ANodeExt.ExtTxt3='');
ASourceChangeCache.Replace(gtEmptyLine,gtEmptyLine,InsertPos,InsertPos, ASourceChangeCache.Replace(gtEmptyLine,gtEmptyLine,InsertPos,InsertPos,
ProcCode); ProcCode);
if JumpToProcName='' then begin if FJumpToProcName='' then begin
// remember one proc body to jump to after the completion // remember one proc body to jump to after the completion
JumpToProcName:=ANodeExt.Txt; FJumpToProcName:=ANodeExt.Txt;
if System.Pos('.',JumpToProcName)<1 then if System.Pos('.',FJumpToProcName)<1 then
JumpToProcName:=UpperCaseStr(TheClassName)+'.'+JumpToProcName; FJumpToProcName:=UpperCaseStr(TheClassName)+'.'+FJumpToProcName;
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
DebugLn('CreateMissingProcBodies JumpToProcName="',JumpToProcName,'"'); DebugLn('CreateMissingProcBodies FJumpToProcName="',FJumpToProcName,'"');
{$ENDIF} {$ENDIF}
end; end;
end; end;
@ -5019,6 +5024,73 @@ begin
end; end;
end; end;
function TCodeCompletionCodeTool.ApplyChangesAndJumpToFirstNewProc(
CleanPos: integer; OldTopLine: integer;
out NewPos: TCodeXYPosition; out NewTopLine: integer): boolean;
var
OldCodeXYPos: TCodeXYPosition;
OldCodePos: TCodePosition;
CursorNode: TCodeTreeNode;
CurClassName: String;
ANode: TCodeTreeNode;
ProcNode: TCodeTreeNode;
begin
Result:=false;
CurClassName:=ExtractClassName(FCodeCompleteClassNode,false);
// apply the changes and jump to first new proc body
if not CleanPosToCodePos(CleanPos,OldCodePos) then
RaiseException('TCodeCompletionCodeTool.CompleteCode Internal Error CleanPosToCodePos');
if not CleanPosToCaret(CleanPos,OldCodeXYPos) then
RaiseException('TCodeCompletionCodeTool.CompleteCode Internal Error CleanPosToCaret');
if not ASourceChangeCache.Apply then
RaiseException(ctsUnableToApplyChanges);
if FJumpToProcName<>'' then begin
{$IFDEF CTDEBUG}
DebugLn('TCodeCompletionCodeTool.ApplyChangesAndJumpToFirstNewProc Jump to new proc body ... "',FJumpToProcName,'"');
{$ENDIF}
// there was a new proc body
// -> find it and jump to
// reparse code
BuildTreeAndGetCleanPos(trAll,OldCodeXYPos,CleanPos,[]);
// find CodeTreeNode at cursor
CursorNode:=FindDeepestNodeAtPos(CleanPos,true);
// due to insertions in front of the class, the cursor position could
// have changed
while (CursorNode<>nil) do begin
if (CursorNode.Desc=ctnTypeSection)
or ((CursorNode.Parent<>nil) and (CursorNode.Parent.Desc=ctnTypeSection))
then break;
CursorNode:=CursorNode.Parent;
end;
FCodeCompleteClassNode:=FindClassNode(CursorNode,CurClassName,true,false);
if FCodeCompleteClassNode=nil then
RaiseException('oops, I lost your class');
ANode:=FCodeCompleteClassNode.GetNodeOfTypes(
[ctnTypeDefinition,ctnGenericType]);
if ANode=nil then
RaiseException(ctsClassNodeWithoutParentNode);
if (ANode.Parent<>nil) and (ANode.Parent.Desc=ctnTypeSection) then
ANode:=ANode.Parent;
ProcNode:=FindProcNode(ANode,FJumpToProcName,
[phpInUpperCase,phpIgnoreForwards]);
if ProcNode=nil then
RaiseException(ctsNewProcBodyNotFound);
Result:=FindJumpPointInProcNode(ProcNode,NewPos,NewTopLine);
end else begin
{$IFDEF CTDEBUG}
DebugLn('TCodeCompletionCodeTool.ApplyChangesAndJumpToFirstNewProc Adjust Cursor ... ');
{$ENDIF}
// there was no new proc body
// -> adjust cursor
AdjustCursor(OldCodePos,OldTopLine,NewPos,NewTopLine);
Result:=true;
end;
end;
function TCodeCompletionCodeTool.CompleteCode(CursorPos: TCodeXYPosition; function TCodeCompletionCodeTool.CompleteCode(CursorPos: TCodeXYPosition;
OldTopLine: integer; out NewPos: TCodeXYPosition; out NewTopLine: integer; OldTopLine: integer; out NewPos: TCodeXYPosition; out NewTopLine: integer;
SourceChangeCache: TSourceChangeCache): boolean; SourceChangeCache: TSourceChangeCache): boolean;
@ -5028,9 +5100,6 @@ var CleanCursorPos, Indent, insertPos: integer;
OldCleanCursorPos: LongInt; OldCleanCursorPos: LongInt;
procedure CompleteClass; procedure CompleteClass;
var
OldCodePos: TCodePosition;
CurClassName: String;
begin begin
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
DebugLn('TCodeCompletionCodeTool.CompleteCode In-a-class ',NodeDescriptionAsString(AClassNode.Desc)); DebugLn('TCodeCompletionCodeTool.CompleteCode In-a-class ',NodeDescriptionAsString(AClassNode.Desc));
@ -5042,7 +5111,6 @@ var CleanCursorPos, Indent, insertPos: integer;
DebugLn('TCodeCompletionCodeTool.CompleteCode C ',dbgs(CleanCursorPos),', |',copy(Src,CleanCursorPos,8)); DebugLn('TCodeCompletionCodeTool.CompleteCode C ',dbgs(CleanCursorPos),', |',copy(Src,CleanCursorPos,8));
{$ENDIF} {$ENDIF}
CodeCompleteClassNode:=AClassNode; CodeCompleteClassNode:=AClassNode;
CurClassName:=ExtractClassName(AClassNode,false);
try try
// go through all properties and procs // go through all properties and procs
// insert read + write prop specifiers // insert read + write prop specifiers
@ -5082,55 +5150,8 @@ var CleanCursorPos, Indent, insertPos: integer;
DebugLn('TCodeCompletionCodeTool.CompleteCode Apply ... '); DebugLn('TCodeCompletionCodeTool.CompleteCode Apply ... ');
{$ENDIF} {$ENDIF}
// apply the changes and jump to first new proc body // apply the changes and jump to first new proc body
if not CleanPosToCodePos(CleanCursorPos,OldCodePos) then Result:=ApplyChangesAndJumpToFirstNewProc(CleanCursorPos,OldTopLine,
RaiseException('TCodeCompletionCodeTool.CompleteCode Internal Error CleanPosToCodePos'); NewPos,NewTopLine);
if not SourceChangeCache.Apply then
RaiseException(ctsUnableToApplyChanges);
if JumpToProcName<>'' then begin
{$IFDEF CTDEBUG}
DebugLn('TCodeCompletionCodeTool.CompleteCode Jump to new proc body ... "',JumpToProcName,'"');
{$ENDIF}
// there was a new proc body
// -> find it and jump to
// reparse code
BuildTreeAndGetCleanPos(trAll,CursorPos,CleanCursorPos,[]);
// find CodeTreeNode at cursor
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
// due to insertions in front of the class, the cursor position could
// have changed
while (CursorNode<>nil) do begin
if (CursorNode.Desc=ctnTypeSection)
or ((CursorNode.Parent<>nil) and (CursorNode.Parent.Desc=ctnTypeSection))
then break;
CursorNode:=CursorNode.Parent;
end;
FCodeCompleteClassNode:=
FindClassNode(CursorNode,CurClassName,true,false);
if FCodeCompleteClassNode=nil then
RaiseException('oops, I lost your class');
ANode:=FCodeCompleteClassNode.GetNodeOfTypes(
[ctnTypeDefinition,ctnGenericType]);
if ANode=nil then
RaiseException(ctsClassNodeWithoutParentNode);
if (ANode.Parent<>nil) and (ANode.Parent.Desc=ctnTypeSection) then
ANode:=ANode.Parent;
ProcNode:=FindProcNode(ANode,JumpToProcName,
[phpInUpperCase,phpIgnoreForwards]);
if ProcNode=nil then
RaiseException(ctsNewProcBodyNotFound);
Result:=FindJumpPointInProcNode(ProcNode,NewPos,NewTopLine);
end else begin
{$IFDEF CTDEBUG}
DebugLn('TCodeCompletionCodeTool.CompleteCode Adjust Cursor ... ');
{$ENDIF}
// there was no new proc body
// -> adjust cursor
AdjustCursor(OldCodePos,OldTopLine,NewPos,NewTopLine);
Result:=true;
end;
finally finally
FreeClassInsertionList; FreeClassInsertionList;
end; end;
@ -5629,8 +5650,10 @@ begin
end; end;
function TCodeCompletionCodeTool.AddMethods(CursorPos: TCodeXYPosition; function TCodeCompletionCodeTool.AddMethods(CursorPos: TCodeXYPosition;
OldTopLine: integer;
ListOfPCodeXYPosition: TFPList; ListOfPCodeXYPosition: TFPList;
const VirtualToOverride: boolean; const VirtualToOverride: boolean;
out NewPos: TCodeXYPosition; out NewTopLine: integer;
SourceChangeCache: TSourceChangeCache): boolean; SourceChangeCache: TSourceChangeCache): boolean;
var var
CleanCursorPos: integer; CleanCursorPos: integer;
@ -5651,6 +5674,7 @@ var
NewClassPart: TNewClassPart; NewClassPart: TNewClassPart;
Beautifier: TBeautifyCodeOptions; Beautifier: TBeautifyCodeOptions;
ProcCode: String; ProcCode: String;
CurClassName: String;
begin begin
Result:=false; Result:=false;
if (ListOfPCodeXYPosition=nil) or (ListOfPCodeXYPosition.Count=0) then if (ListOfPCodeXYPosition=nil) or (ListOfPCodeXYPosition.Count=0) then
@ -5659,6 +5683,7 @@ begin
if (SourceChangeCache=nil) then if (SourceChangeCache=nil) then
RaiseException('need a SourceChangeCache'); RaiseException('need a SourceChangeCache');
CodeCompleteSrcChgCache:=SourceChangeCache;
Beautifier:=SourceChangeCache.BeautifyCodeOptions; Beautifier:=SourceChangeCache.BeautifyCodeOptions;
NewMethods:=TAVLTree.Create(@CompareCodeTreeNodeExt); NewMethods:=TAVLTree.Create(@CompareCodeTreeNodeExt);
try try
@ -5676,10 +5701,10 @@ begin
// parse unit // parse unit
NewCodeTool.BuildTreeAndGetCleanPos(trAll,CodeXYPos,CleanCursorPos,[]); NewCodeTool.BuildTreeAndGetCleanPos(trAll,CodeXYPos,CleanCursorPos,[]);
// find node at position // find node at position
ProcNode:=FindDeepestExpandedNodeAtPos(CleanCursorPos,true); ProcNode:=NewCodeTool.FindDeepestExpandedNodeAtPos(CleanCursorPos,true);
if (ProcNode.Desc<>ctnProcedure) if (ProcNode.Desc<>ctnProcedure)
or (ProcNode.Parent=nil) then begin or (ProcNode.Parent=nil) then begin
MoveCursorToNodeStart(ProcNode); NewCodeTool.MoveCursorToNodeStart(ProcNode);
RaiseException('TCodeCompletionCodeTool.AddMethods source position not a procedure'); RaiseException('TCodeCompletionCodeTool.AddMethods source position not a procedure');
end; end;
// find visibility // find visibility
@ -5699,7 +5724,7 @@ begin
if VirtualStartPos>=1 then begin if VirtualStartPos>=1 then begin
// replace virtual with override // replace virtual with override
FullProcCode:=copy(FullProcCode,1,VirtualStartPos-1) FullProcCode:=copy(FullProcCode,1,VirtualStartPos-1)
+'override' +'override;'
+copy(FullProcCode,VirtualEndPos,length(FullProcCode)); +copy(FullProcCode,VirtualEndPos,length(FullProcCode));
end; end;
// remove abstract // remove abstract
@ -5707,14 +5732,13 @@ begin
NewCodeTool.Scanner.NestedComments); NewCodeTool.Scanner.NestedComments);
end; end;
ProcCode:=ExtractProcHead(ProcNode,[phpWithStart, ProcCode:=NewCodeTool.ExtractProcHead(ProcNode,[phpWithStart,
phpAddClassname,phpWithVarModifiers,phpWithParameterNames, phpWithoutClassName,phpWithVarModifiers,phpWithParameterNames,
phpWithResultType,phpWithCallingSpecs]); phpWithResultType,phpWithCallingSpecs]);
ProcCode:=ProcCode+Beautifier.LineEnd ProcCode:=ProcCode+Beautifier.LineEnd
+'begin'+Beautifier.LineEnd +'begin'+Beautifier.LineEnd
+GetIndentStr(Beautifier.Indent)+Beautifier.LineEnd +GetIndentStr(Beautifier.Indent)+Beautifier.LineEnd
+'end;'; +'end;';
ProcCode:=Beautifier.BeautifyProc(ProcCode,0,false);
// add method data // add method data
NodeExt:=NodeExtMemManager.NewNode; NodeExt:=NodeExtMemManager.NewNode;
@ -5727,16 +5751,18 @@ begin
DebugLn(['TCodeCompletionCodeTool.AddMethods ',i,' CleanProcTxt=',CleanProcCode,' FullProcTxt=',FullProcCode]); DebugLn(['TCodeCompletionCodeTool.AddMethods ',i,' CleanProcTxt=',CleanProcCode,' FullProcTxt=',FullProcCode]);
end; end;
BuildTreeAndGetCleanPos(trAll,CursorPos, CleanCursorPos,[]); BuildTreeAndGetCleanPos(trAll,CursorPos,CleanCursorPos,[]);
// find node at position // find node at position
CursorNode:=FindDeepestExpandedNodeAtPos(CleanCursorPos,true); CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
// if cursor is on type node, find class node // if cursor is on type node, find class node
if CursorNode.Desc=ctnTypeDefinition then if CursorNode.Desc=ctnTypeDefinition then
CursorNode:=CursorNode.FirstChild CursorNode:=CursorNode.FirstChild
else if CursorNode.Desc=ctnGenericType then else if CursorNode.Desc=ctnGenericType then
CursorNode:=CursorNode.LastChild; CursorNode:=CursorNode.LastChild
else
CursorNode:=CursorNode.GetNodeOfTypes([ctnClass,ctnClassInterface]);
if (CursorNode=nil) or (CursorNode.Desc<>ctnClass) then begin if (CursorNode=nil) or (CursorNode.Desc<>ctnClass) then begin
DebugLn(['TIdentCompletionTool.AddMethods cursor not in a class']); DebugLn(['TIdentCompletionTool.AddMethods cursor not in a class']);
exit; exit;
@ -5744,6 +5770,7 @@ begin
CodeCompleteSrcChgCache:=SourceChangeCache; CodeCompleteSrcChgCache:=SourceChangeCache;
CodeCompleteClassNode:=CursorNode; CodeCompleteClassNode:=CursorNode;
CurClassName:=ExtractClassName(CursorNode,false);
// add methods // add methods
AVLNode:=NewMethods.FindLowest; AVLNode:=NewMethods.FindLowest;
@ -5762,6 +5789,8 @@ begin
else NewClassPart:=ncpPublicProcs; else NewClassPart:=ncpPublicProcs;
end; end;
// change classname
ProcCode:=Beautifier.AddClassAndNameToProc(ProcCode,CurClassName,ProcName);
AddClassInsertion(CleanProcCode,FullProcCode,ProcName,NewClassPart,nil, AddClassInsertion(CleanProcCode,FullProcCode,ProcName,NewClassPart,nil,
ProcCode); ProcCode);
@ -5775,11 +5804,12 @@ begin
if not CreateMissingProcBodies then exit; if not CreateMissingProcBodies then exit;
// apply changes // apply changes
if not SourceChangeCache.Apply then if not ApplyChangesAndJumpToFirstNewProc(CleanCursorPos,OldTopLine,
RaiseException(ctsUnableToApplyChanges); NewPos,NewTopLine) then exit;
Result:=true; Result:=true;
finally finally
FreeClassInsertionList;
NodeExtMemManager.DisposeAVLTree(NewMethods); NodeExtMemManager.DisposeAVLTree(NewMethods);
end; end;
end; end;

View File

@ -442,9 +442,11 @@ type
function CompleteCode(Code: TCodeBuffer; X,Y,TopLine: integer; function CompleteCode(Code: TCodeBuffer; X,Y,TopLine: integer;
out NewCode: TCodeBuffer; out NewCode: TCodeBuffer;
out NewX, NewY, NewTopLine: integer): boolean; out NewX, NewY, NewTopLine: integer): boolean;
function AddMethods(Code: TCodeBuffer; X,Y: integer; function AddMethods(Code: TCodeBuffer; X,Y, TopLine: integer;
ListOfPCodeXYPosition: TFPList; ListOfPCodeXYPosition: TFPList;
const VirtualToOverride: boolean): boolean; const VirtualToOverride: boolean;
out NewCode: TCodeBuffer;
out NewX, NewY, NewTopLine: integer): boolean;
function FindRedefinitions(Code: TCodeBuffer; function FindRedefinitions(Code: TCodeBuffer;
out TreeOfCodeTreeNodeExt: TAVLTree; WithEnums: boolean): boolean; out TreeOfCodeTreeNodeExt: TAVLTree; WithEnums: boolean): boolean;
function RemoveRedefinitions(Code: TCodeBuffer; function RemoveRedefinitions(Code: TCodeBuffer;
@ -3002,11 +3004,11 @@ begin
end; end;
end; end;
function TCodeToolManager.AddMethods(Code: TCodeBuffer; X, Y: integer; function TCodeToolManager.AddMethods(Code: TCodeBuffer; X, Y, TopLine: integer;
ListOfPCodeXYPosition: TFPList; const VirtualToOverride: boolean ListOfPCodeXYPosition: TFPList; const VirtualToOverride: boolean;
): boolean; out NewCode: TCodeBuffer; out NewX, NewY, NewTopLine: integer): boolean;
var var
CursorPos: TCodeXYPosition; CursorPos, NewPos: TCodeXYPosition;
begin begin
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
DebugLn('TCodeToolManager.AddMethods A ',Code.Filename); DebugLn('TCodeToolManager.AddMethods A ',Code.Filename);
@ -3017,8 +3019,11 @@ begin
CursorPos.Y:=Y; CursorPos.Y:=Y;
CursorPos.Code:=Code; CursorPos.Code:=Code;
try try
Result:=FCurCodeTool.AddMethods(CursorPos,ListOfPCodeXYPosition, Result:=FCurCodeTool.AddMethods(CursorPos,TopLine,ListOfPCodeXYPosition,
VirtualToOverride,SourceChangeCache); VirtualToOverride,NewPos,NewTopLine,SourceChangeCache);
NewCode:=NewPos.Code;
NewX:=NewPos.X;
NewY:=NewPos.Y;
except except
on e: Exception do Result:=HandleException(e); on e: Exception do Result:=HandleException(e);
end; end;

View File

@ -1052,7 +1052,7 @@ end;
procedure TCTDirectoryCachePool.IncreaseTimeStamp; procedure TCTDirectoryCachePool.IncreaseTimeStamp;
begin begin
DebugLn(['TCTDirectoryCachePool.IncreaseTimeStamp ']); //DebugLn(['TCTDirectoryCachePool.IncreaseTimeStamp ']);
if FTimeStamp<>High(FTimeStamp) then if FTimeStamp<>High(FTimeStamp) then
inc(FTimeStamp) inc(FTimeStamp)
else else

View File

@ -42,6 +42,8 @@ var
ListOfPCodeXYPosition: TFPList; ListOfPCodeXYPosition: TFPList;
i: Integer; i: Integer;
CodeXYPos: TCodeXYPosition; CodeXYPos: TCodeXYPosition;
NewCode: TCodeBuffer;
NewX, NewY, NewTopLine: integer;
begin begin
if (ParamCount>=1) and (Paramcount<>3) then begin if (ParamCount>=1) and (Paramcount<>3) then begin
writeln('Usage:'); writeln('Usage:');
@ -59,7 +61,6 @@ begin
Filename:=GetCurrentDir+'/scanexamples/abstractclass1.pas'; Filename:=GetCurrentDir+'/scanexamples/abstractclass1.pas';
X:=3; X:=3;
Y:=18; Y:=18;
if (ParamCount>=3) then begin if (ParamCount>=3) then begin
Filename:=ExpandFileName(ParamStr(1)); Filename:=ExpandFileName(ParamStr(1));
X:=StrToInt(ParamStr(2)); X:=StrToInt(ParamStr(2));
@ -85,9 +86,10 @@ begin
writeln('FindAbstractMethods failed: ',CodeToolBoss.ErrorMessage); writeln('FindAbstractMethods failed: ',CodeToolBoss.ErrorMessage);
end; end;
if CodeToolBoss.AddMethods(Code,X,Y,ListOfPCodeXYPosition,true) if CodeToolBoss.AddMethods(Code,X,Y,1,ListOfPCodeXYPosition,true,
NewCode,NewX,NewY,NewTopLine)
then begin then begin
writeln('AddMethods succeeded: '); writeln('AddMethods succeeded: ',NewCode.Filename,' (',NewY,',',NewX,') ');
writeln(Code.Source); writeln(Code.Source);
end else begin end else begin
writeln('AddMethods failed: ',CodeToolBoss.ErrorMessage); writeln('AddMethods failed: ',CodeToolBoss.ErrorMessage);

View File

@ -8,7 +8,7 @@ uses
Classes, SysUtils; Classes, SysUtils;
type type
TAbstractClass = class TAbstractClass = class(TStrings)
public public
procedure Increase; virtual; abstract; procedure Increase; virtual; abstract;
procedure Decrease; virtual; abstract; procedure Decrease; virtual; abstract;

View File

@ -759,7 +759,7 @@ type
IgnoreJumpCentered: boolean): boolean; IgnoreJumpCentered: boolean): boolean;
function JumpToCleanPos(NewCleanPos, NewTopLineCleanPos, function JumpToCleanPos(NewCleanPos, NewTopLineCleanPos,
NewBottomLineCleanPos: integer; NewBottomLineCleanPos: integer;
var NewPos: TCodeXYPosition; var NewTopLine: integer; out NewPos: TCodeXYPosition; out NewTopLine: integer;
IgnoreJumpCentered: boolean): boolean; IgnoreJumpCentered: boolean): boolean;
function NodeIsForwardDeclaration(Node: TCodeTreeNode): boolean; function NodeIsForwardDeclaration(Node: TCodeTreeNode): boolean;
@ -3918,8 +3918,8 @@ begin
end; end;
function TFindDeclarationTool.JumpToCleanPos(NewCleanPos, NewTopLineCleanPos, function TFindDeclarationTool.JumpToCleanPos(NewCleanPos, NewTopLineCleanPos,
NewBottomLineCleanPos: integer; var NewPos: TCodeXYPosition; NewBottomLineCleanPos: integer; out NewPos: TCodeXYPosition;
var NewTopLine: integer; IgnoreJumpCentered: boolean): boolean; out NewTopLine: integer; IgnoreJumpCentered: boolean): boolean;
var var
CenteredTopLine: integer; CenteredTopLine: integer;
NewTopLinePos: TCodeXYPosition; NewTopLinePos: TCodeXYPosition;

View File

@ -1461,7 +1461,8 @@ begin
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers G'); DebugLn('TIdentCompletionTool.GatherIdentifiers G');
{$ENDIF} {$ENDIF}
GatherUsefulIdentifiers(IdentStartPos,GatherContext,BeautifyCodeOptions); GatherUsefulIdentifiers(IdentStartPos,CreateFindContext(Self,CursorNode),
BeautifyCodeOptions);
// check for incomplete context // check for incomplete context
@ -1682,16 +1683,18 @@ begin
// find node at position // find node at position
CursorNode:=FindDeepestExpandedNodeAtPos(CleanCursorPos,true); CursorNode:=FindDeepestExpandedNodeAtPos(CleanCursorPos,true);
// if cursor is on type node, find class node // if cursor is on type node, find class node
if CursorNode.Desc=ctnTypeDefinition then if CursorNode.Desc=ctnTypeDefinition then
CursorNode:=CursorNode.FirstChild CursorNode:=CursorNode.FirstChild
else if CursorNode.Desc=ctnGenericType then else if CursorNode.Desc=ctnGenericType then
CursorNode:=CursorNode.LastChild; CursorNode:=CursorNode.LastChild
else
CursorNode:=CursorNode.GetNodeOfTypes([ctnClass,ctnClassInterface]);
if (CursorNode=nil) or (CursorNode.Desc<>ctnClass) if (CursorNode=nil) or (CursorNode.Desc<>ctnClass)
or ((CursorNode.SubDesc and ctnsForwardDeclaration)>0) then begin or ((CursorNode.SubDesc and ctnsForwardDeclaration)>0) then begin
DebugLn(['TIdentCompletionTool.FindAbstractMethods cursor not in a class']); MoveCursorToNodeStart(CursorNode);
exit; RaiseException('TIdentCompletionTool.FindAbstractMethods cursor is not in a class');
end; end;
ClassNode:=CursorNode; ClassNode:=CursorNode;

View File

@ -63,7 +63,7 @@ type
var NewPos: TCodeXYPosition; var NewTopLine: integer; var NewPos: TCodeXYPosition; var NewTopLine: integer;
var RevertableJump: boolean): boolean; var RevertableJump: boolean): boolean;
function FindJumpPointInProcNode(ProcNode: TCodeTreeNode; function FindJumpPointInProcNode(ProcNode: TCodeTreeNode;
var NewPos: TCodeXYPosition; var NewTopLine: integer): boolean; out NewPos: TCodeXYPosition; out NewTopLine: integer): boolean;
function GatherProcNodes(StartNode: TCodeTreeNode; function GatherProcNodes(StartNode: TCodeTreeNode;
Attr: TProcHeadAttributes; const UpperClassName: string): TAVLTree; Attr: TProcHeadAttributes; const UpperClassName: string): TAVLTree;
function FindFirstDifferenceNode(SearchForNodes, SearchInNodes: TAVLTree; function FindFirstDifferenceNode(SearchForNodes, SearchInNodes: TAVLTree;
@ -678,7 +678,7 @@ begin
end; end;
function TMethodJumpingCodeTool.FindJumpPointInProcNode(ProcNode: TCodeTreeNode; function TMethodJumpingCodeTool.FindJumpPointInProcNode(ProcNode: TCodeTreeNode;
var NewPos: TCodeXYPosition; var NewTopLine: integer): boolean; out NewPos: TCodeXYPosition; out NewTopLine: integer): boolean;
var DestNode: TCodeTreeNode; var DestNode: TCodeTreeNode;
i, NewCleanPos: integer; i, NewCleanPos: integer;
begin begin

129
ide/abstractsmethodsdlg.lfm Normal file
View File

@ -0,0 +1,129 @@
object AbstractMethodsDialog: TAbstractMethodsDialog
Left = 350
Height = 344
Top = 291
Width = 581
HorzScrollBar.Page = 580
VertScrollBar.Page = 343
ActiveControl = MethodsCheckListBox
Caption = 'AbstractMethodsDialog'
ClientHeight = 344
ClientWidth = 581
OnCreate = FormCreate
OnDestroy = FormDestroy
object NoteLabel: TLabel
Height = 20
Width = 581
Align = alTop
Caption = 'NoteLabel'
ParentColor = False
WordWrap = True
end
object MethodsGroupBox: TGroupBox
Height = 274
Top = 20
Width = 581
Align = alClient
Caption = 'MethodsGroupBox'
ClientHeight = 255
ClientWidth = 577
TabOrder = 0
object MethodsCheckListBox: TCheckListBox
AnchorSideBottom.Control = SelectAllButton
Height = 214
Width = 577
Align = alTop
Anchors = [akTop, akLeft, akRight, akBottom]
OnClickCheck = MethodsCheckListBoxClickCheck
TabOrder = 0
TopIndex = -1
end
object SelectAllButton: TButton
AnchorSideLeft.Control = MethodsGroupBox
AnchorSideBottom.Control = MethodsGroupBox
AnchorSideBottom.Side = asrBottom
Left = 6
Height = 29
Top = 220
Width = 110
Anchors = [akLeft, akBottom]
AutoSize = True
BorderSpacing.Around = 6
Caption = 'SelectAllButton'
OnClick = SelectAllButtonClick
TabOrder = 1
end
object SelectNoneButton: TButton
AnchorSideLeft.Control = SelectAllButton
AnchorSideLeft.Side = asrBottom
AnchorSideBottom.Control = MethodsGroupBox
AnchorSideBottom.Side = asrBottom
Left = 122
Height = 29
Top = 220
Width = 129
Anchors = [akLeft, akBottom]
AutoSize = True
BorderSpacing.Around = 6
Caption = 'SelectNoneButton'
OnClick = SelectNoneButtonClick
TabOrder = 2
end
end
object BtnPanel: TPanel
Height = 50
Top = 294
Width = 581
Align = alBottom
BevelOuter = bvNone
ClientHeight = 50
ClientWidth = 581
TabOrder = 1
object CancelBitBtn: TBitBtn
Left = 497
Height = 38
Top = 6
Width = 78
Align = alRight
AutoSize = True
BorderSpacing.Around = 6
Cancel = True
Caption = 'Cancel'
Kind = bkCancel
ModalResult = 2
NumGlyphs = 0
TabOrder = 0
end
object AddFirstBitBtn: TBitBtn
Left = 339
Height = 38
Top = 6
Width = 59
Align = alRight
AutoSize = True
BorderSpacing.Around = 6
Caption = '&Yes'
Default = True
Kind = bkYes
ModalResult = 6
NumGlyphs = 0
OnClick = AddFirstBitBtnClick
TabOrder = 1
end
object AddAllBitBtn: TBitBtn
Left = 404
Height = 38
Top = 6
Width = 87
Align = alRight
AutoSize = True
BorderSpacing.Around = 6
Caption = 'Yes to &All'
Kind = bkYesToAll
ModalResult = 10
NumGlyphs = 0
OnClick = AddAllBitBtnClick
TabOrder = 2
end
end
end

View File

@ -0,0 +1,43 @@
{ This is an automatically generated lazarus resource file }
LazarusResources.Add('TAbstractMethodsDialog','FORMDATA',[
'TPF0'#22'TAbstractMethodsDialog'#21'AbstractMethodsDialog'#4'Left'#3'^'#1#6
+'Height'#3'X'#1#3'Top'#3'#'#1#5'Width'#3'E'#2#18'HorzScrollBar.Page'#3'D'#2
+#18'VertScrollBar.Page'#3'W'#1#13'ActiveControl'#7#19'MethodsCheckListBox'#7
+'Caption'#6#21'AbstractMethodsDialog'#12'ClientHeight'#3'X'#1#11'ClientWidth'
+#3'E'#2#8'OnCreate'#7#10'FormCreate'#9'OnDestroy'#7#11'FormDestroy'#0#6'TLab'
+'el'#9'NoteLabel'#6'Height'#2#20#5'Width'#3'E'#2#5'Align'#7#5'alTop'#7'Capti'
+'on'#6#9'NoteLabel'#11'ParentColor'#8#8'WordWrap'#9#0#0#9'TGroupBox'#15'Meth'
+'odsGroupBox'#6'Height'#3#18#1#3'Top'#2#20#5'Width'#3'E'#2#5'Align'#7#8'alCl'
+'ient'#7'Caption'#6#15'MethodsGroupBox'#12'ClientHeight'#3#255#0#11'ClientWi'
+'dth'#3'A'#2#8'TabOrder'#2#0#0#13'TCheckListBox'#19'MethodsCheckListBox'#24
+'AnchorSideBottom.Control'#7#15'SelectAllButton'#6'Height'#3#214#0#5'Width'#3
+'A'#2#5'Align'#7#5'alTop'#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#8'akBo'
+'ttom'#0#12'OnClickCheck'#7#29'MethodsCheckListBoxClickCheck'#8'TabOrder'#2#0
+#8'TopIndex'#2#255#0#0#7'TButton'#15'SelectAllButton'#22'AnchorSideLeft.Cont'
+'rol'#7#15'MethodsGroupBox'#24'AnchorSideBottom.Control'#7#15'MethodsGroupBo'
+'x'#21'AnchorSideBottom.Side'#7#9'asrBottom'#4'Left'#2#6#6'Height'#2#29#3'To'
+'p'#3#220#0#5'Width'#2'n'#7'Anchors'#11#6'akLeft'#8'akBottom'#0#8'AutoSize'#9
+#20'BorderSpacing.Around'#2#6#7'Caption'#6#15'SelectAllButton'#7'OnClick'#7
+#20'SelectAllButtonClick'#8'TabOrder'#2#1#0#0#7'TButton'#16'SelectNoneButton'
+#22'AnchorSideLeft.Control'#7#15'SelectAllButton'#19'AnchorSideLeft.Side'#7#9
+'asrBottom'#24'AnchorSideBottom.Control'#7#15'MethodsGroupBox'#21'AnchorSide'
+'Bottom.Side'#7#9'asrBottom'#4'Left'#2'z'#6'Height'#2#29#3'Top'#3#220#0#5'Wi'
+'dth'#3#129#0#7'Anchors'#11#6'akLeft'#8'akBottom'#0#8'AutoSize'#9#20'BorderS'
+'pacing.Around'#2#6#7'Caption'#6#16'SelectNoneButton'#7'OnClick'#7#21'Select'
+'NoneButtonClick'#8'TabOrder'#2#2#0#0#0#6'TPanel'#8'BtnPanel'#6'Height'#2'2'
+#3'Top'#3'&'#1#5'Width'#3'E'#2#5'Align'#7#8'alBottom'#10'BevelOuter'#7#6'bvN'
+'one'#12'ClientHeight'#2'2'#11'ClientWidth'#3'E'#2#8'TabOrder'#2#1#0#7'TBitB'
+'tn'#12'CancelBitBtn'#4'Left'#3#241#1#6'Height'#2'&'#3'Top'#2#6#5'Width'#2'N'
+#5'Align'#7#7'alRight'#8'AutoSize'#9#20'BorderSpacing.Around'#2#6#6'Cancel'#9
+#7'Caption'#6#6'Cancel'#4'Kind'#7#8'bkCancel'#11'ModalResult'#2#2#9'NumGlyph'
+'s'#2#0#8'TabOrder'#2#0#0#0#7'TBitBtn'#14'AddFirstBitBtn'#4'Left'#3'S'#1#6'H'
+'eight'#2'&'#3'Top'#2#6#5'Width'#2';'#5'Align'#7#7'alRight'#8'AutoSize'#9#20
+'BorderSpacing.Around'#2#6#7'Caption'#6#4'&Yes'#7'Default'#9#4'Kind'#7#5'bkY'
+'es'#11'ModalResult'#2#6#9'NumGlyphs'#2#0#7'OnClick'#7#19'AddFirstBitBtnClic'
+'k'#8'TabOrder'#2#1#0#0#7'TBitBtn'#12'AddAllBitBtn'#4'Left'#3#148#1#6'Height'
+#2'&'#3'Top'#2#6#5'Width'#2'W'#5'Align'#7#7'alRight'#8'AutoSize'#9#20'Border'
+'Spacing.Around'#2#6#7'Caption'#6#11'Yes to &All'#4'Kind'#7#10'bkYesToAll'#11
+'ModalResult'#2#10#9'NumGlyphs'#2#0#7'OnClick'#7#17'AddAllBitBtnClick'#8'Tab'
+'Order'#2#2#0#0#0#0
]);

397
ide/abstractsmethodsdlg.pas Normal file
View File

@ -0,0 +1,397 @@
{
***************************************************************************
* *
* 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:
A dialog showing the abstract methods of the current class
(at cursor in source editor).
With the ability to implement them automatically by adding empty method
stubs.
}
unit AbstractsMethodsDlg;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LCLProc, LResources, Forms, Controls, Graphics, Dialogs,
CheckLst, StdCtrls, ExtCtrls, Buttons,
CodeAtom, CodeTree, PascalParserTool, CodeCache, CodeToolManager,
LazIDEIntf, SrcEditorIntf;
type
{ TAbstractMethodDlgItem }
TAbstractMethodDlgItem = class
public
CodeXYPos: TCodeXYPosition;
ProcHead: string;
BelongsToStartClass: boolean;
end;
{ TAbstractMethodsDialog }
TAbstractMethodsDialog = class(TForm)
AddAllBitBtn: TBitBtn;
NoteLabel: TLabel;
SelectNoneButton: TButton;
SelectAllButton: TButton;
CancelBitBtn: TBitBtn;
AddFirstBitBtn: TBitBtn;
MethodsCheckListBox: TCheckListBox;
MethodsGroupBox: TGroupBox;
BtnPanel: TPanel;
procedure AddAllBitBtnClick(Sender: TObject);
procedure AddFirstBitBtnClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure MethodsCheckListBoxClickCheck(Sender: TObject);
procedure SelectAllButtonClick(Sender: TObject);
procedure SelectNoneButtonClick(Sender: TObject);
private
CodePos: TCodeXYPosition;
TopLine: integer;
FItems: TFPList;// list of TAbstractMethodDlgItem
FCheckingSelection: boolean;
procedure ClearItems;
procedure UpdateButtons;
function CheckSelection: boolean;
function AddOverrides(OnlyFirst: boolean): boolean;
public
NewCode: TCodeBuffer;
NewX,NewY,NewTopLine: integer;
procedure Init(aListOfPCodeXYPosition: TFPList; aCode: TCodeBuffer;
const aCaret: TPoint; aTopLine: integer);
end;
function ShowAbstractMethodsDialog: TModalResult;
implementation
function ShowAbstractMethodsDialog: TModalResult;
var
AbstractMethodsDialog: TAbstractMethodsDialog;
SrcEdit: TSourceEditorInterface;
Code: TCodeBuffer;
Caret: TPoint;
ErrMsg: String;
ListOfPCodeXYPosition: TFPList;
begin
Result:=mrCancel;
ListOfPCodeXYPosition:=nil;
try
// init codetools
ErrMsg:='IDE is busy';
if not LazarusIDE.BeginCodeTools then exit;
// get cursor position
ErrMsg:='Cursor is not in a class declaration';
SrcEdit:=SourceEditorWindow.ActiveEditor;
if SrcEdit=nil then exit;
Code:=TCodeBuffer(SrcEdit.CodeToolsBuffer);
if Code=nil then exit;
Caret:=SrcEdit.CursorTextXY;
// check cursor is in a class
if not CodeToolBoss.FindAbstractMethods(Code,Caret.X,Caret.Y,
ListOfPCodeXYPosition,false) then
begin
if CodeToolBoss.ErrorMessage<>'' then begin
ErrMsg:='';
LazarusIDE.DoJumpToCodeToolBossError;
end;
exit;
end;
// check if there are abstract methods left to override
if (ListOfPCodeXYPosition=nil) or (ListOfPCodeXYPosition.Count=0) then begin
ErrMsg:='';
MessageDlg('No abstract methods found',
'There are no abstract methods left to override.'
,mtConfirmation,[mbOk],0);
Result:=mrOk;
exit;
end;
ErrMsg:='';
AbstractMethodsDialog:=TAbstractMethodsDialog.Create(nil);
AbstractMethodsDialog.Init(ListOfPCodeXYPosition,Code,Caret,SrcEdit.TopLine);
Result:=AbstractMethodsDialog.ShowModal;
AbstractMethodsDialog.Free;
finally
CodeToolBoss.FreeListOfPCodeXYPosition(ListOfPCodeXYPosition);
if ErrMsg<>'' then begin
MessageDlg('Error','Unable to show abstract methods of the current class, because'#13
+ErrMsg,mtError,[mbCancel],0);
end;
end;
end;
{ TAbstractMethodsDialog }
procedure TAbstractMethodsDialog.FormCreate(Sender: TObject);
begin
FItems:=TFPList.Create;
AddFirstBitBtn.Caption:='Override first selected';
AddAllBitBtn.Caption:='Override all selected';
CancelBitBtn.Caption:='Cancel';
SelectNoneButton.Caption:='Select none';
SelectAllButton.Caption:='Select all';
MethodsGroupBox.Caption:='Abstract methods - not overriden';
end;
procedure TAbstractMethodsDialog.AddFirstBitBtnClick(Sender: TObject);
begin
if not AddOverrides(true) then exit;
ModalResult:=mrOk;
end;
procedure TAbstractMethodsDialog.AddAllBitBtnClick(Sender: TObject);
begin
if not AddOverrides(false) then exit;
ModalResult:=mrOk;
end;
procedure TAbstractMethodsDialog.FormDestroy(Sender: TObject);
begin
ClearItems;
end;
procedure TAbstractMethodsDialog.MethodsCheckListBoxClickCheck(Sender: TObject);
begin
CheckSelection;
UpdateButtons;
end;
procedure TAbstractMethodsDialog.SelectAllButtonClick(Sender: TObject);
var
i: Integer;
begin
for i:=0 to FItems.Count-1 do
MethodsCheckListBox.Checked[i]:=
not TAbstractMethodDlgItem(FItems[i]).BelongsToStartClass;
end;
procedure TAbstractMethodsDialog.SelectNoneButtonClick(Sender: TObject);
var
i: Integer;
begin
for i:=0 to FItems.Count-1 do
MethodsCheckListBox.Checked[i]:=false;
end;
procedure TAbstractMethodsDialog.ClearItems;
var
i: Integer;
begin
if FItems=nil then exit;
for i:=0 to FItems.Count-1 do
TObject(FItems[i]).Free;
FreeAndNil(FItems);
end;
procedure TAbstractMethodsDialog.UpdateButtons;
var
i: Integer;
begin
i:=MethodsCheckListBox.Items.Count-1;
while (i>=0) and (not MethodsCheckListBox.Checked[i]) do dec(i);
AddFirstBitBtn.Enabled:=i>=0;
AddAllBitBtn.Enabled:=AddFirstBitBtn.Enabled;
end;
function TAbstractMethodsDialog.CheckSelection: boolean;
var
i: Integer;
Item: TAbstractMethodDlgItem;
begin
Result:=true;
if FCheckingSelection then exit;
FCheckingSelection:=true;
try
for i:=0 to FItems.Count-1 do begin
Item:=TAbstractMethodDlgItem(FItems[i]);
if MethodsCheckListBox.Checked[i] and Item.BelongsToStartClass then begin
if Result then begin
MessageDlg('Impossible',
'This method can not be overriden because it is defined in the current class',
mtError,[mbCancel],0);
Result:=false;
end;
MethodsCheckListBox.Checked[i]:=false;
end;
end;
finally
FCheckingSelection:=false;
end;
end;
function TAbstractMethodsDialog.AddOverrides(OnlyFirst: boolean): boolean;
var
i: Integer;
NewList: TFPList;
Item: TAbstractMethodDlgItem;
begin
Result:=false;
if not CheckSelection then exit;
NewList:=nil;
try
for i:=0 to FItems.Count-1 do begin
if not MethodsCheckListBox.Checked[i] then continue;
Item:=TAbstractMethodDlgItem(FItems[i]);
AddCodePosition(NewList,Item.CodeXYPos);
DebugLn(['TAbstractMethodsDialog.AddOverrides ',Item.CodeXYPos.Code.Filename,' ',Item.CodeXYPos.X,',',Item.CodeXYPos.Y]);
if OnlyFirst then break;
end;
//DebugLn(['TAbstractMethodsDialog.AddOverrides ',CodePos.Code.Filename,' ',CodePos.X,',',CodePos.Y]);
if not CodeToolBoss.AddMethods(CodePos.Code,CodePos.X,CodePos.Y,TopLine,
NewList,true,NewCode,NewX,NewY,NewTopLine)
then begin
LazarusIDE.DoJumpToCodeToolBossError;
exit;
end;
LazarusIDE.DoOpenFileAndJumpToPos(NewCode.Filename,Point(NewX,NewY),
NewTopLine,-1,[]);
finally
CodeToolBoss.FreeListOfPCodeXYPosition(NewList);
end;
Result:=true;
end;
procedure TAbstractMethodsDialog.Init(aListOfPCodeXYPosition: TFPList;
aCode: TCodeBuffer; const aCaret: TPoint; aTopLine: integer);
var
i: Integer;
CodeXYPos: TCodeXYPosition;
CurTool: TCodeTool;
ListOfPCodeXYPosition: TFPList;
Tool: TCodeTool;
CleanPos: integer;
ClassNode: TCodeTreeNode;
CurNode: TCodeTreeNode;
ProcNode: TCodeTreeNode;
NewItem: TAbstractMethodDlgItem;
StartClassName: String;
BelongsToStartClassCnt: Integer;
NoteStr: String;
begin
ListOfPCodeXYPosition:=aListOfPCodeXYPosition;
if ListOfPCodeXYPosition=nil then begin
DebugLn(['TAbstractMethodsDialog.Init ListOfPCodeXYPosition=nil']);
exit;
end;
CodePos.Code:=aCode;
CodePos.X:=aCaret.X;
CodePos.Y:=aCaret.Y;
TopLine:=aTopLine;
// get Tool and ClassNode
Tool:=CodeToolBoss.GetCodeToolForSource(CodePos.Code,true,false) as TCodeTool;
if Tool.CaretToCleanPos(CodePos,CleanPos)<>0 then begin
DebugLn(['TAbstractMethodsDialog.Init invalid ',CodePos.Code.Filename,' ',CodePos.X,',',CodePos.Y]);
exit;
end;
ClassNode:=Tool.FindDeepestNodeAtPos(CleanPos,false);
if ClassNode=nil then begin
DebugLn(['TAbstractMethodsDialog.Init no node at cursor ',CodePos.Code.Filename,' ',CodePos.X,',',CodePos.Y]);
exit;
end;
if ClassNode.Desc=ctnTypeDefinition then
ClassNode:=ClassNode.FirstChild
else if ClassNode.Desc=ctnGenericType then
ClassNode:=ClassNode.LastChild
else
ClassNode:=ClassNode.GetNodeOfTypes([ctnClass,ctnClassInterface]);
if (ClassNode=nil) or (not (ClassNode.Desc in [ctnClass,ctnClassInterface]))
then begin
DebugLn(['TAbstractMethodsDialog.Init no class node at cursor ',CodePos.Code.Filename,' ',CodePos.X,',',CodePos.Y]);
exit;
end;
StartClassName:=Tool.ExtractClassName(ClassNode,false);
BelongsToStartClassCnt:=0;
// create items
for i:=0 to ListOfPCodeXYPosition.Count-1 do begin
CodeXYPos:=PCodeXYPosition(ListOfPCodeXYPosition[i])^;
CurTool:=CodeToolBoss.GetCodeToolForSource(CodeXYPos.Code,true,false) as TCodeTool;
if CurTool.CaretToCleanPos(CodeXYPos,CleanPos)<>0 then begin
DebugLn(['TAbstractMethodsDialog.Init skipping ',CodeXYPos.Code.Filename,' ',CodeXYPos.X,',',CodeXYPos.Y]);
continue;
end;
CurNode:=CurTool.FindDeepestNodeAtPos(CleanPos,false);
if CurNode=nil then begin
DebugLn(['TAbstractMethodsDialog.Init no node at ',CodeXYPos.Code.Filename,' ',CodeXYPos.X,',',CodeXYPos.Y]);
continue;
end;
if CurNode.Desc<>ctnProcedure then begin
DebugLn(['TAbstractMethodsDialog.Init no proc node at ',CodeXYPos.Code.Filename,' ',CodeXYPos.X,',',CodeXYPos.Y]);
continue;
end;
ProcNode:=CurNode;
NewItem:=TAbstractMethodDlgItem.Create;
NewItem.CodeXYPos:=CodeXYPos;
NewItem.ProcHead:=CurTool.ExtractProcHead(ProcNode,[phpAddClassname,
phpWithStart,phpWithParameterNames,phpWithVarModifiers,
phpWithDefaultValues,phpWithResultType,
phpWithOfObject,phpWithCallingSpecs]);
NewItem.BelongsToStartClass:=ProcNode.HasAsParent(ClassNode);
inc(BelongsToStartClassCnt);
FItems.Add(NewItem);
end;
MethodsCheckListBox.Clear;
for i:=0 to FItems.Count-1 do begin
NewItem:=TAbstractMethodDlgItem(FItems[i]);
MethodsCheckListBox.Items.Add(NewItem.ProcHead);
MethodsCheckListBox.Checked[i]:=not NewItem.BelongsToStartClass;
end;
// caption
Caption:='Abstract methods of '+ClassName;
// note
NoteStr:='';
if BelongsToStartClassCnt>0 then begin
NoteStr:=StartClassName+' is an abstract class, it has '
+IntToStr(BelongsToStartClassCnt)+' abstract methods.'#13;
end;
NoteStr:=NoteStr+'There are '+IntToStr(FItems.Count-BelongsToStartClassCnt)
+' abstract methods to override.'#13
+'Select the methods for which stubs should be created:';
NoteLabel.Caption:=NoteStr;
UpdateButtons;
end;
initialization
{$I abstractsmethodsdlg.lrs}
end.

View File

@ -129,7 +129,7 @@ uses
BuildLazDialog, MiscOptions, InputHistory, UnitDependencies, ClipBoardHistory, BuildLazDialog, MiscOptions, InputHistory, UnitDependencies, ClipBoardHistory,
ProcessList, InitialSetupDlgs, NewDialog, MakeResStrDlg, ToDoList, ProcessList, InitialSetupDlgs, NewDialog, MakeResStrDlg, ToDoList,
DialogProcs, FindReplaceDialog, FindInFilesDlg, CodeExplorer, BuildFileDlg, DialogProcs, FindReplaceDialog, FindInFilesDlg, CodeExplorer, BuildFileDlg,
ProcedureList, ExtractProcDlg, FindRenameIdentifier, ProcedureList, ExtractProcDlg, FindRenameIdentifier, AbstractsMethodsDlg,
CleanDirDlg, CodeContextForm, AboutFrm, BuildManager, CleanDirDlg, CodeContextForm, AboutFrm, BuildManager,
// main ide // main ide
MainBar, MainIntf, MainBase; MainBar, MainIntf, MainBase;
@ -835,6 +835,7 @@ type
procedure DoFindDeclarationAtCursor; procedure DoFindDeclarationAtCursor;
procedure DoFindDeclarationAtCaret(const LogCaretXY: TPoint); procedure DoFindDeclarationAtCaret(const LogCaretXY: TPoint);
function DoFindRenameIdentifier(Rename: boolean): TModalResult; function DoFindRenameIdentifier(Rename: boolean): TModalResult;
function DoShowAbstractMethods: TModalResult;
function DoInitIdentCompletion(JumpToError: boolean): boolean; function DoInitIdentCompletion(JumpToError: boolean): boolean;
function DoShowCodeContext(JumpToError: boolean): boolean; function DoShowCodeContext(JumpToError: boolean): boolean;
procedure DoCompleteCodeAtCursor; procedure DoCompleteCodeAtCursor;
@ -2565,6 +2566,9 @@ begin
ecRenameIdentifier: ecRenameIdentifier:
DoFindRenameIdentifier(true); DoFindRenameIdentifier(true);
ecShowAbstractMethods:
DoShowAbstractMethods;
ecFindBlockOtherEnd: ecFindBlockOtherEnd:
DoGoToPascalBlockOtherEnd; DoGoToPascalBlockOtherEnd;
@ -11531,6 +11535,11 @@ begin
end; end;
end; end;
function TMainIDE.DoShowAbstractMethods: TModalResult;
begin
Result:=ShowAbstractMethodsDialog;
end;
{------------------------------------------------------------------------------- {-------------------------------------------------------------------------------
function TMainIDE.DoInitIdentCompletion(JumpToError: boolean): boolean; function TMainIDE.DoInitIdentCompletion(JumpToError: boolean): boolean;
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}

View File

@ -417,7 +417,7 @@ type
procedure InvertAssignmentMenuItemClick(Sender: TObject); procedure InvertAssignmentMenuItemClick(Sender: TObject);
procedure FindIdentifierReferencesMenuItemClick(Sender: TObject); procedure FindIdentifierReferencesMenuItemClick(Sender: TObject);
procedure RenameIdentifierMenuItemClick(Sender: TObject); procedure RenameIdentifierMenuItemClick(Sender: TObject);
//procedure ShowAbstractMethodsMenuItemClick(Sender: TObject); procedure ShowAbstractMethodsMenuItemClick(Sender: TObject);
procedure RunToClicked(Sender: TObject); procedure RunToClicked(Sender: TObject);
procedure ViewCallStackClick(Sender: TObject); procedure ViewCallStackClick(Sender: TObject);
procedure AddWatchAtCursor(Sender: TObject); procedure AddWatchAtCursor(Sender: TObject);
@ -833,6 +833,7 @@ var
SrcEditMenuFindIdentifierReferences: TIDEMenuCommand; SrcEditMenuFindIdentifierReferences: TIDEMenuCommand;
SrcEditMenuExtractProc: TIDEMenuCommand; SrcEditMenuExtractProc: TIDEMenuCommand;
SrcEditMenuInvertAssignment: TIDEMenuCommand; SrcEditMenuInvertAssignment: TIDEMenuCommand;
SrcEditMenuShowAbstractMethods: TIDEMenuCommand;
SrcEditMenuInsertTodo: TIDEMenuCommand; SrcEditMenuInsertTodo: TIDEMenuCommand;
SrcEditMenuMoveEditorLeft: TIDEMenuCommand; SrcEditMenuMoveEditorLeft: TIDEMenuCommand;
SrcEditMenuMoveEditorRight: TIDEMenuCommand; SrcEditMenuMoveEditorRight: TIDEMenuCommand;
@ -979,6 +980,8 @@ begin
'ExtractProc',uemExtractProc); 'ExtractProc',uemExtractProc);
SrcEditMenuInvertAssignment:=RegisterIDEMenuCommand(AParent, SrcEditMenuInvertAssignment:=RegisterIDEMenuCommand(AParent,
'InvertAssignment',uemInvertAssignment); 'InvertAssignment',uemInvertAssignment);
SrcEditMenuShowAbstractMethods:=RegisterIDEMenuCommand(AParent,
'ShowAbstractMethods',srkmecShowAbstractMethods);
SrcEditMenuInsertTodo:=RegisterIDEMenuCommand(SourceEditorMenuRoot, SrcEditMenuInsertTodo:=RegisterIDEMenuCommand(SourceEditorMenuRoot,
'InsertTodo',uemInsertTodo, nil, nil, nil, 'item_todo'); 'InsertTodo',uemInsertTodo, nil, nil, nil, 'item_todo');
@ -3868,6 +3871,7 @@ begin
SrcEditMenuRenameIdentifier.Enabled:= SrcEditMenuRenameIdentifier.Enabled:=
IsValidIdent(ASrcEdit.GetWordAtCurrentCaret) IsValidIdent(ASrcEdit.GetWordAtCurrentCaret)
and (not ASrcEdit.ReadOnly); and (not ASrcEdit.ReadOnly);
SrcEditMenuShowAbstractMethods.Enabled:=not ASrcEdit.ReadOnly;
end else begin end else begin
// user clicked on gutter // user clicked on gutter
SourceEditorMarks.GetMarksForLine(EditorComp,EditorComp.CaretY, SourceEditorMarks.GetMarksForLine(EditorComp,EditorComp.CaretY,
@ -4022,6 +4026,7 @@ begin
SrcEditMenuFindIdentifierReferences.OnClick:= SrcEditMenuFindIdentifierReferences.OnClick:=
@FindIdentifierReferencesMenuItemClick; @FindIdentifierReferencesMenuItemClick;
SrcEditMenuRenameIdentifier.OnClick:=@RenameIdentifierMenuItemClick; SrcEditMenuRenameIdentifier.OnClick:=@RenameIdentifierMenuItemClick;
SrcEditMenuShowAbstractMethods.OnClick:=@ShowAbstractMethodsMenuItemClick;
SrcEditMenuReadOnly.OnClick:=@ReadOnlyClicked; SrcEditMenuReadOnly.OnClick:=@ReadOnlyClicked;
SrcEditMenuShowLineNumbers.OnClick:=@ToggleLineNumbersClicked; SrcEditMenuShowLineNumbers.OnClick:=@ToggleLineNumbersClicked;
@ -5112,6 +5117,11 @@ begin
MainIDEInterface.DoCommand(ecRenameIdentifier); MainIDEInterface.DoCommand(ecRenameIdentifier);
end; end;
procedure TSourceNotebook.ShowAbstractMethodsMenuItemClick(Sender: TObject);
begin
MainIDEInterface.DoCommand(ecShowAbstractMethods);
end;
procedure TSourceNotebook.RunToClicked(Sender: TObject); procedure TSourceNotebook.RunToClicked(Sender: TObject);
var var
ASrcEdit: TSourceEditor; ASrcEdit: TSourceEditor;