diff --git a/components/codetools/codecompletiontool.pas b/components/codetools/codecompletiontool.pas index c360b3e17e..28ed0e0b9d 100644 --- a/components/codetools/codecompletiontool.pas +++ b/components/codetools/codecompletiontool.pas @@ -39,8 +39,8 @@ ToDo: -add code for index properties (TList, TFPList, array of, Pointer array) TList: - property Items[Index: integer]: AType accesstlist; - -> creates + property Items[Index: integer]: AType; + -> creates via dialog property Items[Index: integer]: Type2 read GetItems write SetItems; private FItems: TList; private function GetItems(Index: integer): Type2; @@ -108,7 +108,7 @@ type const VariableName: string; var VariableType: string; IsMethod: boolean; NewLocation: TNewVarLocation ): boolean; - + { TCodeCompletionCodeTool } TCodeCompletionCodeTool = class(TMethodJumpingCodeTool) @@ -188,6 +188,15 @@ type SourceChangeCache: TSourceChangeCache): boolean; function AddPublishedVariable(const UpperClassName,VarName, VarType: string; SourceChangeCache: TSourceChangeCache): boolean; override; + function GetRedefinitionNodeText(Node: TCodeTreeNode): string; + function FindRedefinitions(out TreeOfCodeTreeNodeExt: TAVLTree; + WithEnums: boolean): boolean; + function RemoveRedefinitions(TreeOfCodeTreeNodeExt: TAVLTree; + SourceChangeCache: TSourceChangeCache): boolean; + function FindAliasDefinitions(out TreeOfCodeTreeNodeExt: TAVLTree; + OnlyWrongType: boolean): boolean; + function FixAliasDefinitions(TreeOfCodeTreeNodeExt: TAVLTree; + SourceChangeCache: TSourceChangeCache): boolean; // custom class completion function InitClassCompletion(const UpperClassName: string; @@ -1102,6 +1111,307 @@ begin Result:=true; end; +function TCodeCompletionCodeTool.GetRedefinitionNodeText(Node: TCodeTreeNode + ): string; +begin + case Node.Desc of + ctnProcedure: + Result:=ExtractProcHead(Node,[phpInUpperCase,phpWithoutSemicolon]); + ctnVarDefinition,ctnConstDefinition,ctnTypeDefinition,ctnEnumIdentifier: + Result:=ExtractDefinitionName(Node); + else + Result:=''; + end; +end; + +function TCodeCompletionCodeTool.FindRedefinitions( + out TreeOfCodeTreeNodeExt: TAVLTree; WithEnums: boolean): boolean; +var + AllNodes: TAVLTree; + + procedure AddRedefinition(Redefinition, Definition: TCodeTreeNode; + const NodeText: string); + var + NodeExt: TCodeTreeNodeExtension; + begin + DebugLn(['AddRedefinition ',NodeText,' Redefined=',CleanPosToStr(Redefinition.StartPos),' Definition=',CleanPosToStr(Definition.StartPos)]); + if TreeOfCodeTreeNodeExt=nil then + TreeOfCodeTreeNodeExt:=TAVLTree.Create(@CompareCodeTreeNodeExt); + NodeExt:=NodeExtMemManager.NewNode; + NodeExt.Node:=Redefinition; + NodeExt.Data:=Definition; + NodeExt.Txt:=NodeText; + TreeOfCodeTreeNodeExt.Add(NodeExt); + end; + + procedure AddDefinition(Node: TCodeTreeNode; const NodeText: string); + var + NodeExt: TCodeTreeNodeExtension; + begin + NodeExt:=NodeExtMemManager.NewNode; + NodeExt.Node:=Node; + NodeExt.Txt:=NodeText; + AllNodes.Add(NodeExt); + end; + +var + Node: TCodeTreeNode; + NodeText: String; + AVLNode: TAVLTreeNode; +begin + Result:=false; + TreeOfCodeTreeNodeExt:=nil; + BuildTree(true); + + AllNodes:=TAVLTree.Create(@CompareCodeTreeNodeExt); + try + Node:=Tree.Root; + while Node<>nil do begin + case Node.Desc of + ctnImplementation, ctnInitialization, ctnFinalization, + ctnBeginBlock, ctnAsmBlock: + // skip implementation + break; + ctnVarDefinition, ctnTypeDefinition, ctnConstDefinition, ctnProcedure, + ctnEnumIdentifier: + begin + NodeText:=GetRedefinitionNodeText(Node); + AVLNode:=FindCodeTreeNodeExtAVLNode(AllNodes,NodeText); + if AVLNode<>nil then begin + AddRedefinition(Node,TCodeTreeNodeExtension(AVLNode.Data).Node,NodeText); + end else begin + AddDefinition(Node,NodeText); + end; + if WithEnums + and (Node.FirstChild<>nil) + and (Node.FirstChild.Desc=ctnEnumerationType) then + Node:=Node.FirstChild + else + Node:=Node.NextSkipChilds; + end; + else + Node:=Node.Next; + end; + end; + finally + AllNodes.FreeAndClear; + AllNodes.Free; + end; + Result:=true; +end; + +function TCodeCompletionCodeTool.RemoveRedefinitions( + TreeOfCodeTreeNodeExt: TAVLTree; + SourceChangeCache: TSourceChangeCache): boolean; +var + AVLNode: TAVLTreeNode; + NodesToDo: TAVLTree; + Node: TCodeTreeNode; + StartNode: TCodeTreeNode; + EndNode: TCodeTreeNode; + IsListStart: Boolean; + IsListEnd: Boolean; + StartPos: LongInt; + EndPos: LongInt; +begin + Result:=false; + if SourceChangeCache=nil then exit; + if (TreeOfCodeTreeNodeExt=nil) or (TreeOfCodeTreeNodeExt.Count=0) then exit; + SourceChangeCache.MainScanner:=Scanner; + + NodesToDo:=TAVLTree.Create; + try + // put the nodes to remove into the NodesToDo + AVLNode:=TreeOfCodeTreeNodeExt.FindLowest; + while AVLNode<>nil do begin + NodesToDo.Add(TCodeTreeNodeExtension(AVLNode.Data).Node); + AVLNode:=TreeOfCodeTreeNodeExt.FindSuccessor(AVLNode); + end; + + // delete all redefinitions + while NodesToDo.Count>0 do begin + // find a block of redefinitions + StartNode:=TCodeTreeNode(NodesToDo.Root.Data); + EndNode:=StartNode; + while (StartNode.PriorBrother<>nil) + and (NodesToDo.Find(StartNode.PriorBrother)<>nil) do + StartNode:=StartNode.PriorBrother; + while (EndNode.NextBrother<>nil) + and (NodesToDo.Find(EndNode.NextBrother)<>nil) do + EndNode:=EndNode.NextBrother; + + // check if a whole section is deleted + if (StartNode.PriorBrother=nil) and (EndNode.PriorBrother=nil) + and (StartNode.Parent<>nil) + and (StartNode.Parent.Desc in AllDefinitionSections) then begin + StartNode:=StartNode.Parent; + EndNode:=StartNode; + end; + + // compute nice code positions to delete + StartPos:=FindLineEndOrCodeInFrontOfPosition(StartNode.StartPos); + EndPos:=FindLineEndOrCodeAfterPosition(EndNode.EndPos); + + // check list of definitions + if EndNode.Desc in AllIdentifierDefinitions then begin + // check list definition. For example: + // delete, delete: char; -> delete whole + // a,delete, delete: char; -> a: char; + // delete,delete,c: char; -> c: char; + // a,delete,delete,c: char; -> a,c:char; + IsListStart:=(StartNode.PriorBrother<>nil) + and (StartNode.PriorBrother.FirstChild<>nil); + IsListEnd:=(EndNode.FirstChild<>nil); + if IsListStart and IsListEnd then begin + // case 1: delete, delete: char; -> delete whole + end else begin + // case 2-4: keep type + // get start position of first deleting identifier + StartPos:=StartNode.StartPos; + // get end position of last deleting identifier + EndPos:=EndNode.StartPos+GetIdentLen(@Src[EndNode.StartPos]); + if IsListEnd then begin + // case 2: a,delete, delete: char; -> a: char; + // delete comma in front of start too + MoveCursorToCleanPos(StartNode.PriorBrother.StartPos); + ReadNextAtom; // read identifier + ReadNextAtom; // read comma + StartPos:=CurPos.StartPos; + end else begin + // case 3,4 + // delete comma behind end too + MoveCursorToCleanPos(EndNode.StartPos); + ReadNextAtom; // read identifier + ReadNextAtom; // read comma + EndPos:=CurPos.StartPos; + end; + end; + end; + + // replace + DebugLn(['TCodeCompletionCodeTool.RemoveRedefinitions deleting:']); + debugln('"',copy(Src,StartPos,EndPos-StartPos),'"'); + + if not SourceChangeCache.Replace(gtNone,gtNone,StartPos,EndPos,'') then + exit; + + // remove nodes from NodesToDo + Node:=StartNode; + repeat + NodesToDo.Remove(Node); + if Node=EndNode then break; + Node:=Node.Next; + until false; + end; + finally + NodesToDo.Free; + end; + + Result:=SourceChangeCache.Apply; +end; + +function TCodeCompletionCodeTool.FindAliasDefinitions(out + TreeOfCodeTreeNodeExt: TAVLTree; OnlyWrongType: boolean): boolean; +var + NodeExt: TCodeTreeNodeExtension; + AllNodes: TAVLTree; + Node: TCodeTreeNode; + NodeText: String; + AVLNode: TAVLTreeNode; + ReferingNode: TCodeTreeNode; + ReferingNodeText: String; + WrongType: Boolean; +begin + Result:=false; + TreeOfCodeTreeNodeExt:=nil; + BuildTree(true); + + AllNodes:=TAVLTree.Create(@CompareCodeTreeNodeExt); + try + Node:=Tree.Root; + while Node<>nil do begin + case Node.Desc of + ctnImplementation, ctnInitialization, ctnFinalization, + ctnBeginBlock, ctnAsmBlock: + // skip implementation + break; + ctnTypeDefinition, ctnConstDefinition: + begin + if OnlyWrongType then begin + // remember the definition + NodeText:=GetRedefinitionNodeText(Node); + AVLNode:=FindCodeTreeNodeExtAVLNode(AllNodes,NodeText); + if AVLNode=nil then begin + // add new node + NodeExt:=NodeExtMemManager.NewNode; + NodeExt.Node:=Node; + NodeExt.Txt:=NodeText; + AllNodes.Add(NodeExt); + end else begin + // update node + NodeExt:=TCodeTreeNodeExtension(AVLNode.Data); + NodeExt.Node:=Node; + end; + end; + + // check if definition is an alias + // Example: const A = B; + if (Node.Parent<>nil) + and (Node.Parent.Desc in [ctnConstSection,ctnTypeSection]) + and (Node.FirstChild<>nil) + and (Node.FirstChild.Desc=ctnIdentifier) then begin + // this is a const or type alias + DebugLn(['TCodeCompletionCodeTool.FindAliasDefinitions Alias: ',ExtractNode(Node,[])]); + WrongType:=false; + ReferingNode:=nil; + if OnlyWrongType then begin + ReferingNodeText:=GetIdentifier(@Src[Node.FirstChild.StartPos]); + AVLNode:=FindCodeTreeNodeExtAVLNode(AllNodes,ReferingNodeText); + if (AVLNode<>nil) then begin + NodeExt:=TCodeTreeNodeExtension(AVLNode.Data); + ReferingNode:=NodeExt.Node; + if ReferingNode.Desc<>Node.Desc then begin + // this alias has wrong type + WrongType:=true; + DebugLn(['TCodeCompletionCodeTool.FindAliasDefinitions Wrong: ',ReferingNode.DescAsString,'<>',Node.DescAsString]); + end; + end; + end; + if (not WrongType) or OnlyWrongType then begin + // add alias + if TreeOfCodeTreeNodeExt=nil then + TreeOfCodeTreeNodeExt:=TAVLTree.Create(@CompareCodeTreeNodeExt); + NodeExt:=NodeExtMemManager.NewNode; + NodeExt.Node:=Node; + NodeExt.Txt:=GetRedefinitionNodeText(Node); + NodeExt.Data:=ReferingNode; + TreeOfCodeTreeNodeExt.Add(NodeExt); + end; + end; + + Node:=Node.NextSkipChilds; + end; + ctnProcedure: + Node:=Node.NextSkipChilds; + else + Node:=Node.Next; + end; + end; + finally + AllNodes.FreeAndClear; + AllNodes.Free; + end; + Result:=true; +end; + +function TCodeCompletionCodeTool.FixAliasDefinitions( + TreeOfCodeTreeNodeExt: TAVLTree; SourceChangeCache: TSourceChangeCache + ): boolean; +begin + Result:=false; + +end; + function TCodeCompletionCodeTool.InitClassCompletion( const UpperClassName: string; SourceChangeCache: TSourceChangeCache): boolean; @@ -1829,7 +2139,7 @@ begin Indent:=GetLineIndent(Src,InsertNode.StartPos); if InsertBehind then begin // insert behind InsertNode - InsertPos:=FindFirstLineEndAfterInCode(InsertNode.EndPos); + InsertPos:=FindLineEndOrCodeAfterPosition(InsertNode.EndPos); end else begin // insert in front of InsertNode InsertPos:=InsertNode.StartPos; @@ -1838,7 +2148,7 @@ begin // insert as first variable/proc Indent:=GetLineIndent(Src,ClassSectionNode.StartPos) +ASourceChangeCache.BeautifyCodeOptions.Indent; - InsertPos:=FindFirstLineEndAfterInCode(ClassSectionNode.StartPos); + InsertPos:=FindLineEndOrCodeAfterPosition(ClassSectionNode.StartPos); end; end; CurCode:=ANodeExt.ExtTxt1; diff --git a/components/codetools/codetoolmanager.pas b/components/codetools/codetoolmanager.pas index 3e1a40add5..fede54bc7b 100644 --- a/components/codetools/codetoolmanager.pas +++ b/components/codetools/codetoolmanager.pas @@ -406,6 +406,18 @@ type function CompleteCode(Code: TCodeBuffer; X,Y,TopLine: integer; out NewCode: TCodeBuffer; out NewX, NewY, NewTopLine: integer): boolean; + function FindRedefinitions(Code: TCodeBuffer; + out TreeOfCodeTreeNodeExt: TAVLTree; + WithEnums: boolean): boolean; + function RemoveRedefinitions(Code: TCodeBuffer; + TreeOfCodeTreeNodeExt: TAVLTree): boolean; + function RemoveAllRedefinitions(Code: TCodeBuffer): boolean; + function FindAliasDefinitions(Code: TCodeBuffer; + out TreeOfCodeTreeNodeExt: TAVLTree; + OnlyWrongType: boolean): boolean; + function FixAliasDefinitions(Code: TCodeBuffer; + TreeOfCodeTreeNodeExt: TAVLTree): boolean; + function FixAllAliasDefinitions(Code: TCodeBuffer): boolean; // custom class completion function InitClassCompletion(Code: TCodeBuffer; @@ -2699,6 +2711,127 @@ begin end; end; +function TCodeToolManager.FindRedefinitions(Code: TCodeBuffer; out + TreeOfCodeTreeNodeExt: TAVLTree; WithEnums: boolean): boolean; +begin + {$IFDEF CTDEBUG} + DebugLn('TCodeToolManager.FindRedefinitions A ',Code.Filename); + {$ENDIF} + Result:=false; + TreeOfCodeTreeNodeExt:=nil; + if not InitCurCodeTool(Code) then exit; + try + Result:=FCurCodeTool.FindRedefinitions(TreeOfCodeTreeNodeExt,WithEnums); + except + on e: Exception do Result:=HandleException(e); + end; +end; + +function TCodeToolManager.RemoveRedefinitions(Code: TCodeBuffer; + TreeOfCodeTreeNodeExt: TAVLTree): boolean; +begin + {$IFDEF CTDEBUG} + DebugLn('TCodeToolManager.RemoveRedefinitions A ',Code.Filename); + {$ENDIF} + Result:=false; + if not InitCurCodeTool(Code) then exit; + try + Result:=FCurCodeTool.RemoveRedefinitions(TreeOfCodeTreeNodeExt, + SourceChangeCache); + except + on e: Exception do Result:=HandleException(e); + end; +end; + +function TCodeToolManager.RemoveAllRedefinitions(Code: TCodeBuffer): boolean; +var + TreeOfCodeTreeNodeExt: TAVLTree; +begin + {$IFDEF CTDEBUG} + DebugLn('TCodeToolManager.RemoveAllRedefinitions A ',Code.Filename); + {$ENDIF} + Result:=false; + TreeOfCodeTreeNodeExt:=nil; + try + TreeOfCodeTreeNodeExt:=nil; + if not InitCurCodeTool(Code) then exit; + try + Result:=FCurCodeTool.FindRedefinitions(TreeOfCodeTreeNodeExt,false); + if not Result then exit; + Result:=FCurCodeTool.RemoveRedefinitions(TreeOfCodeTreeNodeExt, + SourceChangeCache); + except + on e: Exception do Result:=HandleException(e); + end; + finally + if TreeOfCodeTreeNodeExt<>nil then begin + TreeOfCodeTreeNodeExt.FreeAndClear; + TreeOfCodeTreeNodeExt.Free; + end; + end; +end; + +function TCodeToolManager.FindAliasDefinitions(Code: TCodeBuffer; out + TreeOfCodeTreeNodeExt: TAVLTree; OnlyWrongType: boolean): boolean; +begin + {$IFDEF CTDEBUG} + DebugLn('TCodeToolManager.FindAliasDefinitions A ',Code.Filename); + {$ENDIF} + Result:=false; + TreeOfCodeTreeNodeExt:=nil; + if not InitCurCodeTool(Code) then exit; + try + Result:=FCurCodeTool.FindAliasDefinitions(TreeOfCodeTreeNodeExt, + OnlyWrongType); + except + on e: Exception do Result:=HandleException(e); + end; +end; + +function TCodeToolManager.FixAliasDefinitions(Code: TCodeBuffer; + TreeOfCodeTreeNodeExt: TAVLTree): boolean; +begin + {$IFDEF CTDEBUG} + DebugLn('TCodeToolManager.FixAliasDefinitions A ',Code.Filename); + {$ENDIF} + Result:=false; + if not InitCurCodeTool(Code) then exit; + try + Result:=FCurCodeTool.FixAliasDefinitions(TreeOfCodeTreeNodeExt, + SourceChangeCache); + except + on e: Exception do Result:=HandleException(e); + end; +end; + +function TCodeToolManager.FixAllAliasDefinitions(Code: TCodeBuffer): boolean; +var + TreeOfCodeTreeNodeExt: TAVLTree; +begin + {$IFDEF CTDEBUG} + DebugLn('TCodeToolManager.FixAllAliasDefinitions A ',Code.Filename); + {$ENDIF} + Result:=false; + TreeOfCodeTreeNodeExt:=nil; + try + TreeOfCodeTreeNodeExt:=nil; + if not InitCurCodeTool(Code) then exit; + try + Result:=FCurCodeTool.FindAliasDefinitions(TreeOfCodeTreeNodeExt,true); + if not Result then exit; + Result:=FCurCodeTool.FixAliasDefinitions(TreeOfCodeTreeNodeExt, + SourceChangeCache); + except + on e: Exception do Result:=HandleException(e); + end; + finally + if TreeOfCodeTreeNodeExt<>nil then begin + TreeOfCodeTreeNodeExt.FreeAndClear; + TreeOfCodeTreeNodeExt.Free; + end; + end; +end; + function TCodeToolManager.InitClassCompletion(Code: TCodeBuffer; const UpperClassName: string; out CodeTool: TCodeTool): boolean; begin diff --git a/components/codetools/codetree.pas b/components/codetools/codetree.pas index 21f0601f70..9737d56278 100644 --- a/components/codetools/codetree.pas +++ b/components/codetools/codetree.pas @@ -238,6 +238,9 @@ type procedure WriteDebugReport(WithChilds: boolean); end; + + { TCodeTreeNodeExtension } + TCodeTreeNodeExtension = class public Node: TCodeTreeNode; @@ -249,12 +252,13 @@ type Next: TCodeTreeNodeExtension; procedure Clear; constructor Create; - destructor Destroy; override; function ConsistencyCheck: integer; // 0 = ok procedure WriteDebugReport; end; - // memory system for TCodeTreeNode(s) + + { TCodeTreeNodeMemManager - memory system for TCodeTreeNode(s) } + TCodeTreeNodeMemManager = class(TCodeToolMemManager) protected procedure FreeFirstItem; override; @@ -263,7 +267,9 @@ type function NewNode: TCodeTreeNode; end; - // memory system for TCodeTreeNodeExtension(s) + + { TCodeTreeNodeExtMemManager - memory system for TCodeTreeNodeExtension(s) } + TCodeTreeNodeExtMemManager = class(TCodeToolMemManager) protected procedure FreeFirstItem; override; @@ -783,11 +789,6 @@ begin Position:=-1; end; -destructor TCodeTreeNodeExtension.Destroy; -begin - inherited Destroy; -end; - function TCodeTreeNodeExtension.ConsistencyCheck: integer; // 0 = ok begin diff --git a/components/codetools/customcodetool.pas b/components/codetools/customcodetool.pas index bd3aada482..8be1a0b3e7 100644 --- a/components/codetools/customcodetool.pas +++ b/components/codetools/customcodetool.pas @@ -204,7 +204,6 @@ type function FindLineEndOrCodeInFrontOfPosition(StartPos: integer): integer; function FindLineEndOrCodeInFrontOfPosition(StartPos: integer; StopAtDirectives: boolean): integer; - function FindFirstLineEndAfterInCode(StartPos: integer): integer; function UpdateNeeded(OnlyInterfaceNeeded: boolean): boolean; procedure BeginParsing(DeleteNodes, OnlyInterfaceNeeded: boolean); virtual; @@ -1805,7 +1804,7 @@ var NewPos: integer; begin if Src='' then RaiseSrcEmpty; - NewPos:=PtrInt(ACleanPos)-PtrInt(@Src[1])+1; + NewPos:=PtrInt(PtrUInt(ACleanPos))-PtrInt(PtrUInt(@Src[1]))+1; if (NewPos<1) or (NewPos>SrcLen) then RaiseNotInSrc; MoveCursorToCleanPos(NewPos); @@ -1852,7 +1851,7 @@ var NewPos: integer; begin Result:=false; if Src='' then exit; - NewPos:=PtrInt(ACleanPos)-PtrInt(@Src[1])+1; + NewPos:=PtrInt(PtrUInt(ACleanPos))-PtrInt(PtrUInt(@Src[1]))+1; if (NewPos<1) or (NewPos>SrcLen) then exit; Result:=true; end; @@ -2282,23 +2281,6 @@ begin StartPos,LinkStart,Scanner.NestedComments,StopAtDirectives); end; -function TCustomCodeTool.FindFirstLineEndAfterInCode(StartPos: integer - ): integer; -{ Searches a line end or code break in the cleaned source after StartPos. - It will skip any line ends in comments. -} -var - LinkIndex, LinkEnd: integer; -begin - LinkIndex:=Scanner.LinkIndexAtCleanPos(StartPos); - LinkEnd:=Scanner.LinkCleanedEndPos(LinkIndex); - if LinkEnd>StartPos then - Result:=BasicCodeTools.FindFirstLineEndAfterInCode(Src, - StartPos,LinkEnd-1,Scanner.NestedComments) - else - Result:=StartPos; -end; - procedure TCustomCodeTool.ClearIgnoreErrorAfter; begin IgnoreErrorAfter:=CodePosition(0,nil); @@ -2555,7 +2537,7 @@ var NewPos: integer; begin Result:=false; if Src='' then exit; - NewPos:=PtrInt(p)-PtrInt(@Src[1])+1; + NewPos:=PtrInt(PtrUInt(p))-PtrInt(PtrUInt(@Src[1]))+1; if (NewPos<1) or (NewPos>length(Src)) then exit; Result:=true; end; @@ -2583,7 +2565,7 @@ var NewPos: integer; begin if Src='' then RaiseSrcEmpty; - NewPos:=PtrInt(APos)-PtrInt(@Src[1])+1; + NewPos:=PtrInt(PtrUInt(APos))-PtrInt(PtrUInt(@Src[1]))+1; if (NewPos<1) or (NewPos>length(Src)) then RaiseNotInSrc; MoveCursorToPos(NewPos); diff --git a/components/codetools/laz_dom.pas b/components/codetools/laz_dom.pas index 4c782035f8..e68fd97c57 100644 --- a/components/codetools/laz_dom.pas +++ b/components/codetools/laz_dom.pas @@ -1025,8 +1025,6 @@ var child: TDOMNode; begin Result := nil; - if index < 0 then - exit; child := node.FirstChild; while Assigned(child) do begin diff --git a/components/codetools/stdcodetools.pas b/components/codetools/stdcodetools.pas index 5ddcd58115..2d3c394f46 100644 --- a/components/codetools/stdcodetools.pas +++ b/components/codetools/stdcodetools.pas @@ -1463,7 +1463,7 @@ begin if OldPosition.StartPos>0 then begin OldPosition.StartPos:=FindLineEndOrCodeInFrontOfPosition( OldPosition.StartPos); - OldPosition.EndPos:=FindFirstLineEndAfterInCode(OldPosition.EndPos); + OldPosition.EndPos:=FindLineEndOrCodeAfterPosition(OldPosition.EndPos); if not SourceChangeCache.Replace(gtNone,gtNone, OldPosition.StartPos,OldPosition.EndPos,'') then exit; end; @@ -2172,7 +2172,7 @@ begin end else begin // it exists -> replace it FromPos:=FindLineEndOrCodeInFrontOfPosition(OldPosition.StartPos); - ToPos:=FindFirstLineEndAfterInCode(OldPosition.EndPos); + ToPos:=FindLineEndOrCodeAfterPosition(OldPosition.EndPos); SourceChangeCache.MainScanner:=Scanner; SourceChangeCache.Replace(gtNewLine,gtNewLine,FromPos,ToPos, SourceChangeCache.BeautifyCodeOptions.BeautifyStatement( @@ -2191,7 +2191,7 @@ begin if FindCreateFormStatement(-1,'*',UpperVarName,Position)=-1 then exit; FromPos:=FindLineEndOrCodeInFrontOfPosition(Position.StartPos); - ToPos:=FindFirstLineEndAfterInCode(Position.EndPos); + ToPos:=FindLineEndOrCodeAfterPosition(Position.EndPos); SourceChangeCache.MainScanner:=Scanner; SourceChangeCache.Replace(gtNone,gtNone,FromPos,ToPos,''); Result:=SourceChangeCache.Apply; @@ -2226,7 +2226,7 @@ begin end else begin // replace FromPos:=FindLineEndOrCodeInFrontOfPosition(OldPosition.StartPos); - ToPos:=FindFirstLineEndAfterInCode(OldPosition.EndPos); + ToPos:=FindLineEndOrCodeAfterPosition(OldPosition.EndPos); SourceChangeCache.MainScanner:=Scanner; SourceChangeCache.Replace(gtNewLine,gtNewLine,FromPos,ToPos, SourceChangeCache.BeautifyCodeOptions.BeautifyStatement( @@ -2296,7 +2296,7 @@ begin StatementPos.StartPos:= FindLineEndOrCodeInFrontOfPosition(StatementPos.StartPos); if InsertPos < 1 then InsertPos:= StatementPos.StartPos; - StatementPos.EndPos:= FindFirstLineEndAfterInCode(StatementPos.EndPos); + StatementPos.EndPos:= FindLineEndOrCodeAfterPosition(StatementPos.EndPos); SourceChangeCache.Replace(gtNone,gtNone, StatementPos.StartPos, StatementPos.EndPos, ''); until false; @@ -2454,7 +2454,7 @@ begin if StringConstStartPos=0 then ; // -> delete whole line FromPos:=FindLineEndOrCodeInFrontOfPosition(StartPos); - ToPos:=FindFirstLineEndAfterInCode(EndPos); + ToPos:=FindLineEndOrCodeAfterPosition(EndPos); SourceChangeCache.MainScanner:=Scanner; if not SourceChangeCache.Replace(gtNone,gtNone,FromPos,ToPos,'') then exit; if not SourceChangeCache.Apply then exit; @@ -3825,7 +3825,7 @@ begin NearestNode:=CursorTool.FindNearestIdentifierNode(CursorPos,IdentTree); if NearestNode=nil then exit; // convert node to cleanpos - NearestCleanPos:=PtrInt(NearestNode.Data)-PtrInt(@SectionTool.Src[1])+1; + NearestCleanPos:=PtrUInt(NearestNode.Data)-PtrUInt(@SectionTool.Src[1])+1; // convert cleanpos to caret CleanPosToCaret(NearestCleanPos,NearestPos); finally @@ -4046,7 +4046,7 @@ begin // variable definition has the form 'VarName: VarType;' // -> delete whole line FromPos:=FindLineEndOrCodeInFrontOfPosition(VarNode.StartPos); - ToPos:=FindFirstLineEndAfterInCode(VarNode.EndPos); + ToPos:=FindLineEndOrCodeAfterPosition(VarNode.EndPos); end else begin // variable definition has the form 'VarName, NextVarName: VarType;' // -> delete only 'VarName, ' @@ -4233,7 +4233,7 @@ var PropInfo:=PPropInfo(PByte(@TypeData^.UnitName)+Length(TypeData^.UnitName)+1); // read property count CurCount:=PWord(PropInfo)^; - inc(PtrInt(PropInfo),SizeOf(Word)); + inc(PtrUInt(PropInfo),SizeOf(Word)); //debugln(' UnitName=',TypeData^.UnitName,' Type=',TypeInfo^.Name,' CurPropCount=',dbgs(CurCount)); // read properties while CurCount>0 do begin diff --git a/components/h2pas/h2pasconvert.pas b/components/h2pas/h2pasconvert.pas index e58be771a3..ddb127d34b 100644 --- a/components/h2pas/h2pasconvert.pas +++ b/components/h2pas/h2pasconvert.pas @@ -26,7 +26,7 @@ uses Classes, SysUtils, LCLProc, LResources, LazConfigStorage, XMLPropStorage, Forms, Controls, Dialogs, FileUtil, FileProcs, AvgLvlTree, // CodeTools - KeywordFuncLists, BasicCodeTools, + KeywordFuncLists, BasicCodeTools, CodeCache, CodeToolManager, // IDEIntf TextTools, IDEExternToolIntf, IDEDialogs, LazIDEIntf, SrcEditorIntf, IDEMsgIntf, IDETextConverter; @@ -41,6 +41,7 @@ type function Execute(aText: TIDETextConverter): TModalResult; override; end; + { TRemoveEmptyCMacrosTool - Remove empty C macros} TRemoveEmptyCMacrosTool = class(TCustomTextConverterTool) @@ -49,6 +50,7 @@ type function Execute(aText: TIDETextConverter): TModalResult; override; end; + { TReplaceEdgedBracketPairWithStar - Replace [] with * } TReplaceEdgedBracketPairWithStar = class(TCustomTextReplaceTool) @@ -57,6 +59,7 @@ type constructor Create(TheOwner: TComponent); override; end; + { TReplace0PointerWithNULL - Replace macro values 0 pointer like (char *)0 with NULL } @@ -65,6 +68,7 @@ type class function ClassDescription: string; override; function Execute(aText: TIDETextConverter): TModalResult; override; end; + { TReplaceUnitFilenameWithUnitName - Replace "unit filename;" with "unit name;" } @@ -75,6 +79,7 @@ type constructor Create(TheOwner: TComponent); override; end; + { TRemoveSystemTypes - Remove type redefinitons like PLongint } @@ -84,6 +89,7 @@ type function Execute(aText: TIDETextConverter): TModalResult; override; end; + { TRemoveRedefinedPointerTypes - Remove redefined pointer types } TRemoveRedefinedPointerTypes = class(TCustomTextConverterTool) @@ -92,6 +98,7 @@ type function Execute(aText: TIDETextConverter): TModalResult; override; end; + { TRemoveEmptyTypeVarConstSections - Remove empty type/var/const sections } TRemoveEmptyTypeVarConstSections = class(TCustomTextConverterTool) @@ -100,6 +107,7 @@ type function Execute(aText: TIDETextConverter): TModalResult; override; end; + { TReplaceImplicitTypes - Search implicit types in parameters and add types for them For example: @@ -142,6 +150,7 @@ type function Execute(aText: TIDETextConverter): TModalResult; override; function CodeToIdentifier(const Code: string): string; end; + { TFixArrayOfParameterType - Replace "array of )" with "array of const)" } @@ -151,8 +160,33 @@ type function Execute(aText: TIDETextConverter): TModalResult; override; end; + + { TRemoveRedefinitionsInUnit + Removes redefinitions of types, variables, constants and resourcestrings } + + TRemoveRedefinitionsInUnit = class(TCustomTextConverterTool) + public + class function ClassDescription: string; override; + function Execute(aText: TIDETextConverter): TModalResult; override; + end; + + + { TFixAliasDefinitionsInUnit + NOT COMPLETE YET + + Checks all alias definitions of the form + const LeftSide = RightSide; + looks up RightSide in the unit and if RightSide is a type or var, changes + the section accordingly } + + TFixAliasDefinitionsInUnit = class(TCustomTextConverterTool) + public + class function ClassDescription: string; override; + function Execute(aText: TIDETextConverter): TModalResult; override; + end; + + { Proposal: - - A tool to collect the content of several units into one - A tool to remove redefinitions - A tool to fix "constant A=B;" to type A=B; or functions - A tool to reorder a unit to fix forward definitions @@ -605,13 +639,14 @@ end; function TH2PasFile.IsEqual(AFile: TH2PasFile): boolean; begin Result:=(CompareFilenames(Filename,AFile.Filename)=0) - and (Enabled=AFile.Enabled); + and (Enabled=AFile.Enabled) + and (Merge=AFile.Merge); end; procedure TH2PasFile.Load(Config: TConfigStorage); begin FEnabled:=Config.GetValue('Enabled/Value',true); - FMerge:=Config.GetValue('Merge/Value',false); + FMerge:=Config.GetValue('Merge/Value',true); FFilename:=Config.GetValue('Filename/Value',''); if Project<>nil then FFilename:=Project.NormalizeFilename(FFilename); @@ -1353,6 +1388,9 @@ begin AddNewTextConverterTool(FPostH2PasTools,TRemoveEmptyTypeVarConstSections); AddNewTextConverterTool(FPostH2PasTools,TReplaceImplicitTypes); AddNewTextConverterTool(FPostH2PasTools,TFixArrayOfParameterType); + // the above tools fixed the syntax + // now improve the declarations + AddNewTextConverterTool(FPostH2PasTools,TRemoveRedefinitionsInUnit); end; function TH2PasProject.SearchIncludedCHeaderFile(aFile: TH2PasFile; @@ -1787,7 +1825,7 @@ begin CheckedFiles:=TFPList.Create; AddIncludedByFiles(IncludedByFiles,CurFile); if IncludedByFiles.Count>1 then begin - // this merged file is included by more than unit + // this merged file is included by more than one unit Warning:=Warning +'Warning: the file "'+Project.ShortenFilename(CurFile.Filename)+'"'#13 +'will be merged into multiple files:'#13; @@ -3085,4 +3123,53 @@ begin inherited Destroy; end; +{ TRemoveRedefinitionsInUnit } + +class function TRemoveRedefinitionsInUnit.ClassDescription: string; +begin + Result:='Remove redefinitions in pascal unit'; +end; + +function TRemoveRedefinitionsInUnit.Execute(aText: TIDETextConverter + ): TModalResult; +begin + Result:=mrCancel; + if (not FilenameIsPascalUnit(aText.Filename)) then begin + DebugLn(['TRemoveRedefinitionsInUnit.Execute file is not pascal: ',aText.Filename]); + exit(mrOk);// ignore + end; + if not CodeToolBoss.RemoveAllRedefinitions(TCodeBuffer(aText.CodeBuffer)) then begin + DebugLn(['TRemoveRedefinitionsInUnit.Execute RemoveAllRedefinitions failed ',CodeToolBoss.ErrorMessage]); + exit; + end; + Result:=mrOk; +end; + +{ TFixAliasDefinitionsInUnit } + +class function TFixAliasDefinitionsInUnit.ClassDescription: string; +begin + Result:='Fixes section type of alias definitions in pascal unit'#13 + +'Checks all alias definitions of the form'#13 + +'const LeftSide = RightSide;'#13 + +'looks up RightSide in the unit and if RightSide is a type or var, changes' + +' the section accordingly'; +end; + +function TFixAliasDefinitionsInUnit.Execute(aText: TIDETextConverter + ): TModalResult; +begin + Result:=mrCancel; + if (not FilenameIsPascalUnit(aText.Filename)) then begin + DebugLn(['TRemoveRedefinitionsInUnit.Execute file is not pascal: ',aText.Filename]); + exit(mrOk);// ignore + end; + // ToDo: finish codetools FixAllAliasDefinitions + if not CodeToolBoss.FixAllAliasDefinitions(TCodeBuffer(aText.CodeBuffer)) then begin + DebugLn(['TRemoveRedefinitionsInUnit.Execute FixAllAliasDefinitions failed ',CodeToolBoss.ErrorMessage]); + exit; + end; + Result:=mrOk; +end; + end. diff --git a/components/h2pas/h2pasdlg.pas b/components/h2pas/h2pasdlg.pas index 798006a46d..59e69e109d 100644 --- a/components/h2pas/h2pasdlg.pas +++ b/components/h2pas/h2pasdlg.pas @@ -218,6 +218,7 @@ begin TextConverterToolClasses.RegisterClass(TRemoveEmptyTypeVarConstSections); TextConverterToolClasses.RegisterClass(TReplaceImplicitTypes); TextConverterToolClasses.RegisterClass(TFixArrayOfParameterType); + TextConverterToolClasses.RegisterClass(TRemoveRedefinitionsInUnit); end; { TH2PasDialog } diff --git a/components/synedit/syneditregexsearch.pas b/components/synedit/syneditregexsearch.pas index 33aa6aab50..bba7339335 100644 --- a/components/synedit/syneditregexsearch.pas +++ b/components/synedit/syneditregexsearch.pas @@ -120,7 +120,7 @@ end; function TSynEditRegexSearch.GetLength(aIndex: integer): integer; begin - Result := PtrInt( fLengths[ aIndex ] ); + Result := PtrInt(PtrUInt( fLengths[ aIndex ] )); end; function TSynEditRegexSearch.GetPattern: string; @@ -130,7 +130,7 @@ end; function TSynEditRegexSearch.GetResult(aIndex: integer): integer; begin - Result := PtrInt( fPositions[ aIndex ] ); + Result := PtrInt( PtrUint(fPositions[ aIndex ]) ); end; function TSynEditRegexSearch.GetResultCount: integer; diff --git a/debugger/debugger.pp b/debugger/debugger.pp index c1196b7707..dc489a62d8 100644 --- a/debugger/debugger.pp +++ b/debugger/debugger.pp @@ -3067,7 +3067,7 @@ function TBaseCallStack.GetStackEntry(const AIndex: Integer): TCallStackEntry; var idx: PtrInt; begin - idx := PtrInt(FEntryIndex[AIndex]); + idx := PtrInt(PtrUInt(FEntryIndex[AIndex])); if idx = -1 then begin // not created yet diff --git a/ide/sourceeditprocs.pas b/ide/sourceeditprocs.pas index f3323569e2..b5211f1fe3 100644 --- a/ide/sourceeditprocs.pas +++ b/ide/sourceeditprocs.pas @@ -48,8 +48,20 @@ type TLazTextConverterToolClasses = class(TTextConverterToolClasses) protected function GetTempFilename: string; override; + function SupportsType(aTextType: TTextConverterType): boolean; override; function LoadFromFile(Converter: TIDETextConverter; const AFilename: string; UpdateFromDisk, Revert: Boolean): Boolean; override; + function SaveCodeBufferToFile(Converter: TIDETextConverter; + const AFilename: string): Boolean; override; + function GetCodeBufferSource(Converter: TIDETextConverter; + out Source: string): boolean; override; + function CreateCodeBuffer(Converter: TIDETextConverter; + const Filename, NewSource: string; + out CodeBuffer: Pointer): boolean; override; + function LoadCodeBufferFromFile(Converter: TIDETextConverter; + const Filename: string; + UpdateFromDisk, Revert: Boolean; + out CodeBuffer: Pointer): boolean; override; end; procedure SetupTextConverters; @@ -599,6 +611,7 @@ function TLazTextConverterToolClasses.LoadFromFile( var TheFilename: String; CodeBuf: TCodeBuffer; + TargetCodeBuffer: TCodeBuffer; begin TheFilename:=CleanAndExpandFilename(AFilename); CodeBuf:=CodeToolBoss.FindFile(TheFilename); @@ -622,10 +635,59 @@ begin Result:=SaveStringToFile(Converter.Filename,CodeBuf.Source,[])=mrOk; tctStrings: CodeBuf.AssignTo(Converter.Strings,true); + tctCodeBuffer: + begin + if Converter.CodeBuffer=nil then + Converter.CodeBuffer:=CodeBuf + else begin + TargetCodeBuffer:=(TObject(Converter.CodeBuffer) as TCodeBuffer); + if TargetCodeBuffer<>CodeBuf then + TargetCodeBuffer.Source:=CodeBuf.Source; + end; + end; end; end; end; +function TLazTextConverterToolClasses.SaveCodeBufferToFile( + Converter: TIDETextConverter; const AFilename: string): Boolean; +begin + Result:=(TObject(Converter.CodeBuffer) as TCodeBuffer).SaveToFile(AFilename); +end; + +function TLazTextConverterToolClasses.GetCodeBufferSource( + Converter: TIDETextConverter; out Source: string): boolean; +begin + Result:=true; + Source:=(TObject(Converter.CodeBuffer) as TCodeBuffer).Source; +end; + +function TLazTextConverterToolClasses.CreateCodeBuffer( + Converter: TIDETextConverter; const Filename, NewSource: string; out + CodeBuffer: Pointer): boolean; +begin + CodeBuffer:=CodeToolBoss.CreateFile(Filename); + if CodeBuffer<>nil then begin + TCodeBuffer(CodeBuffer).Source:=NewSource; + Result:=true; + end else + Result:=false; +end; + +function TLazTextConverterToolClasses.LoadCodeBufferFromFile( + Converter: TIDETextConverter; const Filename: string; + UpdateFromDisk, Revert: Boolean; out CodeBuffer: Pointer): boolean; +begin + CodeBuffer:=CodeToolBoss.LoadFile(Filename,UpdateFromDisk,Revert); + Result:=CodeBuffer<>nil; +end; + +function TLazTextConverterToolClasses.SupportsType(aTextType: TTextConverterType + ): boolean; +begin + Result:=true; +end; + initialization REException:=ERegExpr; REMatchesFunction:=@SynREMatches; diff --git a/ideintf/idetextconverter.pas b/ideintf/idetextconverter.pas index 831fcecf7a..65c283cb32 100644 --- a/ideintf/idetextconverter.pas +++ b/ideintf/idetextconverter.pas @@ -27,7 +27,7 @@ unit IDETextConverter; interface uses - Classes, SysUtils, LCLProc, Controls, Forms, FileUtil, SrcEditorIntf, + Classes, SysUtils, TypInfo, LCLProc, Controls, Forms, FileUtil, SrcEditorIntf, PropEdits; type @@ -36,13 +36,14 @@ type TTextConverterType = ( tctSource, tctFile, - tctStrings + tctStrings, + tctCodeBuffer // TCodeBuffer ); { TIDETextConverter A component to hold a Text and tools to change the Text. For example to do several find and replace operations on the text. - The Text can be a file, a string or TStrings. + The Text can be a file, a string, TStrings or a TCodeBuffer. The Text is converted on the fly, whenever someone reads/write one of the formats. The tools are decendants of TCustomTextConverterTool. } @@ -51,16 +52,20 @@ type private FFilename: string; FSource: string; + FCodeBuffer: Pointer; FStrings: TStrings; FCurrentType: TTextConverterType; FFileIsTemporary: boolean; FStringsIsTemporary: Boolean; procedure CreateTempFilename; + function GetCodeBuffer: Pointer; function GetFilename: string; function GetSource: string; function GetStrings: TStrings; - procedure RemoveStrings; - procedure SaveToFile(const NewFilename: string); + procedure ResetStrings; + procedure ResetFile; + procedure ConvertToFile(const NewFilename: string); + procedure SetCodeBuffer(const AValue: Pointer); procedure SetFilename(const AValue: string); procedure SetSource(const AValue: string); procedure SetStrings(const AValue: TStrings); @@ -73,6 +78,8 @@ type constructor Create(TheOwner: TComponent); override; destructor Destroy; override; procedure Clear; + procedure CheckType(aTextType: TTextConverterType); + function SupportsType(aTextType: TTextConverterType): boolean; virtual; function Execute(ToolList: TComponent): TModalResult;// run the tools function LoadFromFile(const AFilename: string; UseIDECache: Boolean = true; @@ -82,8 +89,10 @@ type procedure InitWithFilename(const AFilename: string); procedure InitWithSource(const ASource: string); procedure InitWithStrings(const aStrings: TStrings); + procedure InitWithCodeBuffers(const aBuffer: Pointer); property CurrentType: TTextConverterType read FCurrentType write SetCurrentType; property Source: string read GetSource write SetSource; + property CodeBuffer: Pointer read GetCodeBuffer write SetCodeBuffer; property Filename: string read GetFilename write SetFilename; property Strings: TStrings read GetStrings write SetStrings; property FileIsTemporary: boolean read FFileIsTemporary write SetFileIsTemporary; @@ -98,6 +107,7 @@ type FCaption: string; FDescription: string; FEnabled: boolean; + function IsCaptionStored: boolean; procedure SetCaption(const AValue: string); procedure SetDescription(const AValue: string); public @@ -107,7 +117,7 @@ type function Execute(aText: TIDETextConverter): TModalResult; virtual; abstract; procedure Assign(Source: TPersistent); override; published - property Caption: string read FCaption write SetCaption; + property Caption: string read FCaption write SetCaption stored IsCaptionStored; property Description: string read FDescription write SetDescription; property Enabled: boolean read FEnabled write FEnabled default True; end; @@ -172,9 +182,22 @@ type var ComponentClass: TComponentClass); property Items[Index: integer]: TCustomTextConverterToolClass read GetItems; default; property Count: integer read GetCount; + + function SupportsType(aTextType: TTextConverterType): boolean; virtual; abstract; function GetTempFilename: string; virtual; abstract; function LoadFromFile(Converter: TIDETextConverter; const AFilename: string; UpdateFromDisk, Revert: Boolean): Boolean; virtual; abstract; + function SaveCodeBufferToFile(Converter: TIDETextConverter; + const AFilename: string): Boolean; virtual; abstract; + function GetCodeBufferSource(Converter: TIDETextConverter; + out Source: string): boolean; virtual; abstract; + function CreateCodeBuffer(Converter: TIDETextConverter; + const Filename, NewSource: string; + out CodeBuffer: Pointer): boolean; virtual; abstract; + function LoadCodeBufferFromFile(Converter: TIDETextConverter; + const Filename: string; + UpdateFromDisk, Revert: Boolean; + out CodeBuffer: Pointer): boolean; virtual; abstract; end; var @@ -309,7 +332,7 @@ end; procedure TIDETextConverter.SetFilename(const AValue: string); begin - SaveToFile(AValue); + ConvertToFile(AValue); end; function TIDETextConverter.GetFilename: string; @@ -330,7 +353,7 @@ begin Result:=FStrings; end; -procedure TIDETextConverter.RemoveStrings; +procedure TIDETextConverter.ResetStrings; begin if StringsIsTemporary then FStrings.Free; @@ -338,20 +361,29 @@ begin FStringsIsTemporary:=false; end; +procedure TIDETextConverter.ResetFile; +begin + if FileIsTemporary then begin + DeleteFile(FFilename); + // do not change FFileIsTemporary, so that File > Source > File sequences + // keep the file temporary. + end; +end; + procedure TIDETextConverter.SetSource(const AValue: string); begin FCurrentType:=tctSource; - RemoveStrings; + ResetStrings; + ResetFile; FSource:=AValue; end; procedure TIDETextConverter.SetStrings(const AValue: TStrings); begin FCurrentType:=tctStrings; - if (AValue<>FStrings) and StringsIsTemporary then - FreeAndNil(FStrings); + ResetFile; + ResetStrings; FStrings:=AValue; - FStringsIsTemporary:=false; end; procedure TIDETextConverter.SetCurrentType(const AValue: TTextConverterType); @@ -359,6 +391,7 @@ var fs: TFileStream; begin if FCurrentType=AValue then exit; + CheckType(AValue); //DebugLn(['TIDETextConverter.SetCurrentType ',ord(FCurrentType),' ',ord(AValue)]); case AValue of tctSource: @@ -369,7 +402,7 @@ begin tctStrings: if FStrings<>nil then begin FSource:=FStrings.Text; - RemoveStrings; + ResetStrings; end; tctFile: if FileExists(FFilename) then begin @@ -380,12 +413,16 @@ begin finally fs.Free; end; - if FileIsTemporary then begin - DeleteFile(FFilename); - end; + ResetFile; + end; + tctCodeBuffer: + begin + TextConverterToolClasses.GetCodeBufferSource(Self,FSource); + FCodeBuffer:=nil; end; end; end; + tctStrings: // convert to TStrings begin @@ -402,12 +439,18 @@ begin tctFile: if FileExists(FFilename) then begin FStrings.LoadFromFile(FFilename); - if FileIsTemporary then begin - DeleteFile(FFilename); - end; + ResetFile; + end; + tctCodeBuffer: + begin + TextConverterToolClasses.GetCodeBufferSource(Self,FSource); + FStrings.Text:=FSource; + FSource:=''; + FCodeBuffer:=nil; end; end; end; + tctFile: // convert to File begin @@ -431,7 +474,41 @@ begin tctStrings: if FStrings<>nil then begin FStrings.SaveToFile(FFilename); - RemoveStrings; + ResetStrings; + end; + tctCodeBuffer: + begin + TextConverterToolClasses.SaveCodeBufferToFile(Self,FFilename); + FCodeBuffer:=nil; + end; + end; + end; + + tctCodeBuffer: + // convert to CodeBuffer + begin + // keep old Filename, so that a Filename, Source, Filename combination + // uses the same Filename + if FFilename='' then + CreateTempFilename; + case FCurrentType of + tctSource: + begin + TextConverterToolClasses.CreateCodeBuffer(Self,FFilename,FSource, + FCodeBuffer); + FSource:=''; + end; + tctStrings: + begin + TextConverterToolClasses.CreateCodeBuffer(Self,FFilename, + FStrings.Text,FCodeBuffer); + ResetStrings; + end; + tctFile: + begin + TextConverterToolClasses.LoadCodeBufferFromFile(Self,FFilename, + true,true,FCodeBuffer); + ResetFile; end; end; end; @@ -445,7 +522,7 @@ begin FFileIsTemporary:=AValue; end; -procedure TIDETextConverter.SaveToFile(const NewFilename: string); +procedure TIDETextConverter.ConvertToFile(const NewFilename: string); var fs: TFileStream; TrimmedFilename: String; @@ -469,19 +546,38 @@ begin tctStrings: begin fStrings.SaveToFile(TrimmedFilename); - RemoveStrings; + ResetStrings; + end; + tctCodeBuffer: + begin + TextConverterToolClasses.SaveCodeBufferToFile(Self,NewFilename); + FCodeBuffer:=nil; end; end; FCurrentType:=tctFile; FFilename:=TrimmedFilename; end; +procedure TIDETextConverter.SetCodeBuffer(const AValue: Pointer); +begin + CheckType(tctCodeBuffer); + FCurrentType:=tctCodeBuffer; + ResetStrings; + FCodeBuffer:=AValue; +end; + procedure TIDETextConverter.CreateTempFilename; begin FFilename:=GetTempFilename; FFileIsTemporary:=true; end; +function TIDETextConverter.GetCodeBuffer: Pointer; +begin + CurrentType:=tctCodeBuffer; + Result:=FCodeBuffer; +end; + procedure TIDETextConverter.SetStringsIsTemporary(const AValue: Boolean); begin if FStringsIsTemporary=AValue then exit; @@ -504,7 +600,8 @@ end; destructor TIDETextConverter.Destroy; begin - RemoveStrings; + ResetFile; + ResetStrings; inherited Destroy; end; @@ -512,10 +609,31 @@ procedure TIDETextConverter.Clear; begin FFilename:=''; FSource:=''; - RemoveStrings; + FCodeBuffer:=nil; + ResetStrings; FCurrentType:=tctSource; end; +procedure TIDETextConverter.CheckType(aTextType: TTextConverterType); + + procedure RaiseNotSupported; + begin + raise Exception.Create('TIDETextConverter.CheckType:' + +' type not supported '+GetEnumName(TypeInfo(TTextConverterType),ord(aTextType))); + end; + +begin + if not SupportsType(aTextType) then RaiseNotSupported; +end; + +function TIDETextConverter.SupportsType(aTextType: TTextConverterType + ): boolean; +begin + Result:=(aTextType in [tctSource,tctFile,tctStrings]) + or ((TextConverterToolClasses<>nil) + and (TextConverterToolClasses.SupportsType(aTextType))); +end; + function TIDETextConverter.Execute(ToolList: TComponent): TModalResult; var i: Integer; @@ -594,6 +712,14 @@ begin FStrings:=aStrings; end; +procedure TIDETextConverter.InitWithCodeBuffers(const aBuffer: Pointer); +begin + CheckType(tctCodeBuffer); + Clear; + FCurrentType:=tctCodeBuffer; + FCodeBuffer:=aBuffer; +end; + { TCustomTextConverterTool } procedure TCustomTextConverterTool.SetCaption(const AValue: string); @@ -602,6 +728,11 @@ begin FCaption:=AValue; end; +function TCustomTextConverterTool.IsCaptionStored: boolean; +begin + Result:=Caption<>FirstLineOfClassDescription; +end; + procedure TCustomTextConverterTool.SetDescription(const AValue: string); begin if FDescription=AValue then exit; diff --git a/lcl/interfaces/gtk/gtkcallback.inc b/lcl/interfaces/gtk/gtkcallback.inc index 37bc6b99b0..8f052abff7 100644 --- a/lcl/interfaces/gtk/gtkcallback.inc +++ b/lcl/interfaces/gtk/gtkcallback.inc @@ -813,6 +813,7 @@ begin EventTrace('killfocusCB', data); {$ENDIF} if (Widget=nil) or (Event=nil) then ; + //DebugLn('GTKKillFocusCB ',DbgSName(TObject(Data)),' ',GetWidgetDebugReport(Widget)); {$IFDEF VerboseFocus} write('GTKillFocusCB Widget=',DbgS(Widget),' Event^.theIn=',Event^.theIn); LCLObject:=TObject(data); @@ -862,6 +863,7 @@ begin {$IFDEF EventTrace} EventTrace('killfocusCBAfter', data); {$ENDIF} + //DebugLn('GTKKillFocusCBAfter ',DbgSName(TObject(Data)),' ',GetWidgetDebugReport(Widget)); {$IFDEF VerboseFocus} write('GTKillFocusCBAfter Widget=',DbgS(Widget),' Event^.theIn=',Event^.theIn); LCLObject:=TObject(data); diff --git a/lcl/interfaces/gtk/gtkproc.inc b/lcl/interfaces/gtk/gtkproc.inc index a19a2ed97c..16bf4faba2 100644 --- a/lcl/interfaces/gtk/gtkproc.inc +++ b/lcl/interfaces/gtk/gtkproc.inc @@ -515,7 +515,7 @@ begin then begin p:=nil; gdk_window_get_user_data(AWindow,p); - if GtkWidgetIsA(PGTKWidget(p),GTKAPIWidget_GetType) then begin + if GtkWidgetIsA(PGTKWidget(p),gtk_widget_get_type) then begin Widget:=PGTKWidget(p); Result:=Result+''; end else begin diff --git a/lcl/interfaces/gtk2/gtk2object.inc b/lcl/interfaces/gtk2/gtk2object.inc index 1024fb1d99..a8d311f2ba 100644 --- a/lcl/interfaces/gtk2/gtk2object.inc +++ b/lcl/interfaces/gtk2/gtk2object.inc @@ -418,6 +418,7 @@ procedure TGTK2WidgetSet.SetCallbackEx(const AMsg: LongInt; procedure ConnectFocusEvents(const AnObject: PGTKObject); begin + //DebugLn(['ConnectFocusEvents ',GetWidgetDebugReport(PGtkWidget(AnObject))]); ConnectSenderSignal(AnObject, 'focus-in-event', @gtk2FocusCB); ConnectSenderSignalAfter(AnObject, 'focus-in-event', @gtk2FocusCBAfter); ConnectSenderSignal(AnObject, 'focus-out-event', @gtk2KillFocusCB); @@ -460,12 +461,7 @@ begin case AMsg of LM_FOCUS : begin - if (ALCLObject is TCustomComboBox) then begin - ConnectFocusEvents(PgtkObject(PgtkCombo(gObject)^.entry)); - ConnectFocusEvents(PgtkObject(PgtkCombo(gObject)^.list)); - end else begin - ConnectFocusEvents(gCore); - end; + ConnectFocusEvents(gCore); end; LM_CHAR, diff --git a/lcl/interfaces/gtk2/gtk2wsstdctrls.pp b/lcl/interfaces/gtk2/gtk2wsstdctrls.pp index 7466906895..745ef76f95 100644 --- a/lcl/interfaces/gtk2/gtk2wsstdctrls.pp +++ b/lcl/interfaces/gtk2/gtk2wsstdctrls.pp @@ -42,7 +42,8 @@ uses type - { !!! Both are used: TGtkComboBoxEntry and TGtkComboBox, but not the old TGtkCombo !!! } + { !!! Both are used: TGtkComboBoxEntry (with entry) and TGtkComboBox (without entry), + but not the old TGtkCombo !!! } PGtkComboBoxPrivate = ^TGtkComboBoxPrivate; TGtkComboBoxPrivate = record @@ -95,7 +96,8 @@ type end; { TGtk2WSCustomComboBox } - { !!! Both are used: TGtkComboBoxEntry and TGtkComboBox, but not the old TGtkCombo !!! } + { !!! Both are used: TGtkComboBoxEntry (with entry) and TGtkComboBox (without entry), + but not the old TGtkCombo !!! } TGtk2WSCustomComboBox = class(TGtkWSCustomComboBox) private @@ -900,7 +902,8 @@ begin Gtk2WidgetSet.SetCallbackDirect(LM_MBUTTONUP, InputObject, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEWHEEL, InputObject, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_PAINT, InputObject, AWinControl); - + Gtk2WidgetSet.SetCallbackDirect(LM_FOCUS, InputObject, AWinControl); + // And now the same for the Button in the combo if AButton<>nil then begin Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEENTER, AButton, AWinControl); @@ -915,6 +918,7 @@ begin Gtk2WidgetSet.SetCallbackDirect(LM_MBUTTONUP, AButton, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_MOUSEWHEEL, AButton, AWinControl); Gtk2WidgetSet.SetCallbackDirect(LM_PAINT, AButton, AWinControl); + Gtk2WidgetSet.SetCallbackDirect(LM_FOCUS, AButton, AWinControl); end; // if we are a GtkComboBoxEntry @@ -924,7 +928,7 @@ begin if APrivate^.popup_widget<>nil then begin g_signal_connect(APrivate^.popup_widget, 'show', TGCallback(@GtkPopupShowCB), AWidgetInfo); - g_signal_connect(APrivate^.popup_widget, 'hide', TGCallback(@GtkPopupHideCB), AWidgetInfo); + g_signal_connect_after(APrivate^.popup_widget, 'hide', TGCallback(@GtkPopupHideCB), AWidgetInfo); end; //g_signal_connect(ComboWidget, 'popup-shown', TGCallback(@GtkPopupShowCB), AWidgetInfo); g_object_set_data(G_OBJECT(AWidget), 'Menu', APrivate^.popup_widget);