finshed Make Resourcestring dialog and implemented TToggleBox

git-svn-id: trunk@3905 -
This commit is contained in:
mattias 2003-03-09 17:44:12 +00:00
parent a0262292bf
commit b25b6d4dc1
8 changed files with 429 additions and 33 deletions

View File

@ -105,6 +105,11 @@ function TrimCodeSpace(const ACode: string): string;
function CodeIsOnlySpace(const ACode: string; FromPos, ToPos: integer): boolean;
function StringToPascalConst(const s: string): string;
// string constants
function SplitStringConstant(const StringConstant: string;
FirstLineLength, OtherLineLengths, Indent: integer;
const NewLine: string): string;
// other useful stuff
procedure RaiseCatchableException(const Msg: string);
@ -214,7 +219,9 @@ implementation
var
IsIDChar, // ['a'..'z','A'..'Z','0'..'9','_']
IsIDStartChar, // ['a'..'z','A'..'Z','_']
IsSpaceChar
IsSpaceChar,
IsNumberChar,
IsHexNumberChar
: array[char] of boolean;
function Min(i1, i2: integer): integer;
@ -2096,6 +2103,263 @@ begin
Convert(Result);
end;
function SplitStringConstant(const StringConstant: string;
FirstLineLength, OtherLineLengths, Indent: integer;
const NewLine: string): string;
{ Split long string constants
If possible it tries to split on word boundaries.
Examples:
1.
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',15,20,6
becomes: |'ABCDEFGHIJKLM'|
| +'NOPQRSTUVWX'|
| +'YZ'|
Result:
'ABCDEFGHIJKLM'#13#10 +'NOPQRSTUVWX'#13#10 +'YZ'
2.
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',5,20,6
}
const
// string constant character types:
stctStart = 'S'; // ' start char
stctEnd = 'E'; // ' end char
stctWordStart = 'W'; // word char after non word char
stctQuotation1 = 'Q'; // first ' of a double ''
stctQuotation2 = 'M'; // second ' of a double ''
stctChar = 'C'; // normal character
stctHash = '#'; // hash
stctHashNumber = '0'; // hash number
stctLineEnd10 = #10; // hash number is 10
stctLineEnd13 = #13; // hash number is 13
stctJunk = 'j'; // junk
var
SrcLen: Integer;
Src: String;
CurLineMax: Integer;
ParsedSrc: string;
ParsedLen: integer;
SplitPos: integer;
procedure ParseSrc;
var
APos: Integer;
NumberStart: Integer;
Number: Integer;
begin
SetLength(ParsedSrc,CurLineMax+1);
APos:=1;
ParsedLen:=CurLineMax+1;
if ParsedLen>SrcLen then ParsedLen:=SrcLen;
while APos<=ParsedLen do begin
if Src[APos]='''' then begin
ParsedSrc[APos]:=stctStart;
inc(APos);
while APos<=ParsedLen do begin
if (Src[APos]='''') then begin
inc(APos);
if (APos<=ParsedLen) and (Src[APos]='''') then begin
// double ''
ParsedSrc[APos-1]:=stctQuotation1;
ParsedSrc[APos]:=stctQuotation2;
inc(APos);
end else begin
// end of string
ParsedSrc[APos-1]:=stctEnd;
break;
end;
end else begin
// normal char
if (Src[APos] in ['A'..'Z','a'..'z'])
and (APos>1)
and (ParsedSrc[APos-1]=stctChar)
and (not (Src[APos-1] in ['A'..'Z','a'..'z'])) then
ParsedSrc[APos]:=stctWordStart
else
ParsedSrc[APos]:=stctChar;
inc(APos);
end;
end;
end else if Src[APos]='#' then begin
ParsedSrc[APos]:=stctHash;
inc(APos);
NumberStart:=APos;
if (APos<=ParsedLen) then begin
// parse character number
if IsNumberChar[Src[APos]] then begin
// parse decimal number
while (APos<=ParsedLen) and IsNumberChar[Src[APos]] do begin
ParsedSrc[APos]:=stctHashNumber;
inc(APos);
end;
end else if Src[APos]='$' then begin
// parse hex number
while (APos<=ParsedLen) and IsHexNumberChar[Src[APos]] do begin
ParsedSrc[APos]:=stctHashNumber;
inc(APos);
end;
end;
Number:=StrToIntDef(copy(Src,NumberStart,APos-NumberStart),-1);
if (Number=10) or (Number=13) then begin
while NumberStart<APos do begin
ParsedSrc[NumberStart]:=chr(Number);
inc(NumberStart);
end;
end;
end;
end else begin
// junk
ParsedSrc[APos]:=stctJunk;
inc(APos);
end;
end;
end;
function SearchCharLeftToRight(c: char): integer;
begin
Result:=1;
while (Result<=ParsedLen) and (ParsedSrc[Result]<>c) do
inc(Result);
if Result>ParsedLen then Result:=-1;
end;
function SearchDiffCharLeftToRight(StartPos: integer): integer;
begin
Result:=StartPos+1;
while (Result<=ParsedLen) and (ParsedSrc[Result]=ParsedSrc[StartPos]) do
inc(Result);
end;
procedure SplitAtNewLineCharConstant;
var
HashPos: Integer;
NewSplitPos: Integer;
begin
if SplitPos>0 then exit;
// check if there is a newline character constant
HashPos:=SearchCharLeftToRight(stctLineEnd10)-1;
if (HashPos<1) then begin
HashPos:=SearchCharLeftToRight(stctLineEnd13)-1;
if HashPos<1 then exit;
end;
NewSplitPos:=SearchDiffCharLeftToRight(HashPos+1);
if NewSplitPos>CurLineMax then exit;
// check if this is a double new line char const #13#10
if (NewSplitPos<ParsedLen) and (ParsedSrc[NewSplitPos]=stctHash)
and (ParsedSrc[NewSplitPos+1] in [stctLineEnd10,stctLineEnd13])
and (ParsedSrc[NewSplitPos+1]<>ParsedSrc[NewSplitPos-1])
then begin
NewSplitPos:=SearchDiffCharLeftToRight(NewSplitPos+1);
if NewSplitPos>CurLineMax then exit;
end;
SplitPos:=NewSplitPos;
end;
procedure SplitBetweenConstants;
var
APos: Integer;
begin
if SplitPos>0 then exit;
APos:=CurLineMax;
while (APos>=2) do begin
if (ParsedSrc[APos] in [stctHash,stctStart]) then begin
SplitPos:=APos;
exit;
end;
dec(APos);
end;
end;
procedure SplitAtWordBoundary;
var
APos: Integer;
begin
if SplitPos>0 then exit;
APos:=CurLineMax-1;
while (APos>2) and (APos>(CurLineMax shr 1)) do begin
if (ParsedSrc[APos]=stctWordStart) then begin
SplitPos:=APos;
exit;
end;
dec(APos);
end;
end;
procedure SplitDefault;
begin
if SplitPos>0 then exit;
SplitPos:=CurLineMax;
while (SplitPos>1) do begin
if (ParsedSrc[SplitPos]
in [stctStart,stctWordStart,stctChar,stctHash,stctJunk])
then
break;
dec(SplitPos);
end;
end;
procedure Split;
var
CurIndent: Integer;
begin
// move left split side from Src to Result
//writeln('Split: SplitPos=',SplitPos,' ',copy(Src,SplitPos-5,6));
Result:=Result+copy(Src,1,SplitPos-1);
Src:=copy(Src,SplitPos,length(Src)-SplitPos+1);
if ParsedSrc[SplitPos] in [stctWordStart,stctChar] then begin
// line break in string constant
// -> add ' to end of last line and to start of next
Result:=Result+'''';
Src:=''''+Src;
end;
SrcLen:=length(Src);
// calculate indent size for next line
CurLineMax:=OtherLineLengths;
CurIndent:=Indent;
if CurIndent>(CurLineMax-10) then
CurIndent:=CurLineMax-10;
if CurIndent<0 then CurIndent:=0;
// add indent spaces to Result
Result:=Result+NewLine+GetIndentStr(CurIndent)+'+';
// calculate next maximum line length
CurLineMax:=CurLineMax-CurIndent-1;
end;
begin
Result:='';
if FirstLineLength<5 then FirstLineLength:=5;
if OtherLineLengths<5 then OtherLineLengths:=5;
Src:=StringConstant;
SrcLen:=length(Src);
CurLineMax:=FirstLineLength;
//writeln('SplitStringConstant FirstLineLength=',FirstLineLength,
//' OtherLineLengths=',OtherLineLengths,' Indent=',Indent,' ');
repeat
//writeln('SrcLen=',SrcLen,' CurMaxLine=',CurLineMax);
//writeln('Src="',Src,'"');
//writeln('Result="',Result,'"');
if SrcLen<=CurLineMax then begin
// line fits
Result:=Result+Src;
break;
end;
// split line -> search nice split position
ParseSrc;
SplitPos:=0;
SplitAtNewLineCharConstant;
SplitBetweenConstants;
SplitAtWordBoundary;
SplitDefault;
Split;
until false;
//writeln('END Result="',Result,'"');
//writeln('SplitStringConstant END---------------------------------');
end;
procedure RaiseCatchableException(const Msg: string);
begin
{ Raises an exception.
@ -2218,6 +2482,8 @@ begin
IsIDChar[c]:=(c in ['a'..'z','A'..'Z','0'..'9','_']);
IsIDStartChar[c]:=(c in ['a'..'z','A'..'Z','_']);
IsSpaceChar[c]:=c in [#0..#32];
IsNumberChar[c]:=c in ['0'..'9'];
IsHexNumberChar[c]:=c in ['0'..'9','A'..'Z','a'..'z'];
end;
end;

View File

@ -251,6 +251,10 @@ type
StartCode: TCodeBuffer; StartX, StartY: integer;
EndCode: TCodeBuffer; EndX, EndY: integer;
var FormatStringConstant, FormatParameters: string): boolean;
function AddResourcestring(SectionCode: TCodeBuffer;
SectionX, SectionY: integer;
const NewIdentifier, NewValue: string;
InsertAlphabetically: boolean): boolean;
// expressions
function GetStringConstBounds(Code: TCodeBuffer; X,Y: integer;
@ -921,6 +925,28 @@ begin
end;
end;
function TCodeToolManager.AddResourcestring(SectionCode: TCodeBuffer; SectionX,
SectionY: integer; const NewIdentifier, NewValue: string;
InsertAlphabetically: boolean): boolean;
var
CursorPos: TCodeXYPosition;
begin
Result:=false;
{$IFDEF CTDEBUG}
writeln('TCodeToolManager.AddResourcestring A ',SectionCode.Filename,' x=',Sectionx,' y=',Sectiony);
{$ENDIF}
if not InitCurCodeTool(SectionCode) then exit;
CursorPos.X:=SectionX;
CursorPos.Y:=SectionY;
CursorPos.Code:=SectionCode;
try
Result:=FCurCodeTool.AddResourcestring(CursorPos, NewIdentifier, NewValue,
InsertAlphabetically,SourceChangeCache);
except
on e: Exception do HandleException(e);
end;
end;
function TCodeToolManager.GetStringConstBounds(Code: TCodeBuffer; X, Y: integer;
var StartCode: TCodeBuffer; var StartX, StartY: integer;
var EndCode: TCodeBuffer; var EndX, EndY: integer;

View File

@ -81,7 +81,7 @@ type
CurAtomType, LastAtomType: TAtomType;
CurPos, AtomStart, AtomEnd, SrcLen, CurIndent: integer;
Src, UpperSrc: string;
procedure AddAtom(var s:string; NewAtom: string);
procedure AddAtom(var CurCode: string; NewAtom: string);
procedure ReadNextAtom;
public
LineLength: integer;
@ -825,38 +825,54 @@ begin
PrivatVariablePrefix:='f';
end;
procedure TBeautifyCodeOptions.AddAtom(var s:string; NewAtom: string);
procedure TBeautifyCodeOptions.AddAtom(var CurCode: string; NewAtom: string);
var
RestLineLen, LastLineEndInAtom: integer;
begin
if NewAtom='' then exit;
//writeln('[TBeautifyCodeOptions.AddAtom] NewAtom=',NewAtom,' s="',s,'"');
// beautify identifier
if IsIdentStartChar[NewAtom[1]] then begin
if WordIsKeyWord.DoItCaseInsensitive(NewAtom) then
NewAtom:=BeautifyWord(NewAtom,KeyWordPolicy)
else
NewAtom:=BeautifyWord(NewAtom,IdentifierPolicy);
end;
// split long string constants
if NewAtom[1] in ['''','#'] then
NewAtom:=SplitStringConstant(NewAtom,LineLength-CurLineLen,LineLength,
Indent+GetLineIndent(CurCode,LastSrcLineStart),
LineEnd);
// find last line end in atom
LastLineEndInAtom:=length(NewAtom);
while (LastLineEndInAtom>=1) and (not (NewAtom[LastLineEndInAtom] in [#10,#13]))
do dec(LastLineEndInAtom);
while (LastLineEndInAtom>=1)
and (not (NewAtom[LastLineEndInAtom] in [#10,#13]))
do
dec(LastLineEndInAtom);
// start new line if necessary
if (LastLineEndInAtom<1) and (CurLineLen+length(NewAtom)>LineLength)
and (LastSplitPos>1) then begin
// new atom does not fit into the line and there is a split position
// -> split line
//writeln('[TBeautifyCodeOptions.AddAtom] NEW LINE CurLineLen=',CurLineLen,' NewAtom=',NewAtom,' "',copy(s,LastSplitPos,5));
RestLineLen:=length(s)-LastSplitPos+1;
s:=copy(s,1,LastSplitPos-1)+LineEnd
+GetIndentStr(CurIndent+Indent+GetLineIndent(s,LastSrcLineStart))
+copy(s,LastSplitPos,RestLineLen)+NewAtom;
CurLineLen:=length(s)-LastSplitPos-length(LineEnd)+1;
RestLineLen:=length(CurCode)-LastSplitPos+1;
CurCode:=copy(CurCode,1,LastSplitPos-1)+LineEnd
+GetIndentStr(Indent+GetLineIndent(CurCode,LastSrcLineStart))
+copy(CurCode,LastSplitPos,RestLineLen)+NewAtom;
CurLineLen:=length(CurCode)-LastSplitPos-length(LineEnd)+1;
LastSplitPos:=-1;
end else begin
s:=s+NewAtom;
CurCode:=CurCode+NewAtom;
if LastLineEndInAtom<1 then begin
inc(CurLineLen,length(NewAtom));
end else begin
// there is a line end in the code
CurLineLen:=length(NewAtom)-LastLineEndInAtom;
LastSrcLineStart:=length(s)+1-CurLineLen;
LastSrcLineStart:=length(CurCode)+1-CurLineLen;
end;
end;
end;

View File

@ -175,6 +175,9 @@ type
function StringConstToFormatString(
const StartCursorPos, EndCursorPos: TCodeXYPosition;
var FormatStringConstant,FormatParameters: string): boolean;
function AddResourcestring(SectionPos: TCodeXYPosition;
const NewIdentifier, NewValue: string; InsertAlphabetically: boolean;
SourceChangeCache: TSourceChangeCache): boolean;
end;
@ -1637,6 +1640,75 @@ begin
Result:=FormatStringConstant<>'';
end;
function TStandardCodeTool.AddResourcestring(SectionPos: TCodeXYPosition;
const NewIdentifier, NewValue: string; InsertAlphabetically: boolean;
SourceChangeCache: TSourceChangeCache): boolean;
var
CleanSectionPos: integer;
ANode, SectionNode: TCodeTreeNode;
Indent: Integer;
InsertPos: Integer;
InsertSrc: String;
begin
Result:=false;
//writeln('TStandardCodeTool.AddResourcestring A ',NewIdentifier,'=',NewValue);
if (NewIdentifier='') or (length(NewIdentifier)>255) then exit;
if SourceChangeCache=nil then exit;
SourceChangeCache.MainScanner:=Scanner;
// parse source and find clean positions
BuildTreeAndGetCleanPos(trAll,SectionPos,CleanSectionPos,[]);
// find resource string section
SectionNode:=FindDeepestNodeAtPos(CleanSectionPos,true);
if (SectionNode=nil) then exit;
SectionNode:=SectionNode.GetNodeOfType(ctnResStrSection);
if SectionNode=nil then exit;
//writeln('TStandardCodeTool.AddResourcestring B SectionChilds=',SectionNode.FirstChild<>nil,' InsertAlphabetically=',InsertAlphabetically);
// find insert position
if SectionNode.FirstChild=nil then begin
// no resourcestring in this section yet -> append as first child
Indent:=GetLineIndent(Src,SectionNode.StartPos)
+SourceChangeCache.BeautifyCodeOptions.Indent;
InsertPos:=SectionNode.StartPos+length('RESOURCESTRING');
end else begin
// search insert position
if InsertAlphabetically then begin
// insert new identifier alphabetically
ANode:=SectionNode.FirstChild;
while (ANode<>nil) do begin
if (ANode.Desc=ctnConstDefinition)
and (CompareIdentifiers(@Src[ANode.StartPos],PChar(NewIdentifier))<0)
then
break;
ANode:=ANode.NextBrother;
end;
if ANode=nil then begin
// append new identifier as last
Indent:=GetLineIndent(Src,SectionNode.LastChild.StartPos);
InsertPos:=FindLineEndOrCodeAfterPosition(SectionNode.LastChild.EndPos);
end else begin
// insert in front of node
Indent:=GetLineIndent(Src,ANode.StartPos);
InsertPos:=FindLineEndOrCodeInFrontOfPosition(ANode.StartPos);
end;
end else begin
// append new identifier
Indent:=GetLineIndent(Src,SectionNode.LastChild.StartPos);
InsertPos:=FindLineEndOrCodeAfterPosition(SectionNode.LastChild.EndPos);
end;
end;
//writeln('TStandardCodeTool.AddResourcestring C Indent=',Indent,' InsertPos=',InsertPos,' ',copy(Src,InsertPos-9,8),'|',copy(Src,InsertPos,8));
// insert
InsertSrc:=SourceChangeCache.BeautifyCodeOptions.BeautifyStatement(
NewIdentifier+' = '+NewValue+';',Indent);
//writeln('TStandardCodeTool.AddResourcestring D "',InsertSrc,'"');
SourceChangeCache.Replace(gtNewLine,gtNewLine,InsertPos,InsertPos,InsertSrc);
SourceChangeCache.Apply;
Result:=true;
//writeln('TStandardCodeTool.AddResourcestring END ',Result);
end;
function TStandardCodeTool.FindPublishedVariable(const UpperClassName,
UpperVarName: string): TCodeTreeNode;
var ClassNode, SectionNode: TCodeTreeNode;

View File

@ -110,17 +110,18 @@ type
procedure SetSource(NewCode: TCodeBuffer;
const NewStartPos, NewEndPos: TPoint);
function ResourceStringExists(const Identifier: string): boolean;
function GetNewSource: string;
procedure GetNewSource(var NewSource, ResourceStringValue: string);
end;
function ShowMakeResStrDialog(
const StartPos, EndPos: TPoint; Code: TCodeBuffer;
Positions: TCodeXYPositions;
var NewIdentifier: string;
var NewIdentifier, NewIdentifierValue: string;
var NewSourceLines: string;
var ResourcestringSection: integer;
var ResStrSectionCode: TCodeBuffer;
var ResStrSectionXY: TPoint;
var InsertPolicy: TResourcestringInsertPolicy): TModalResult;
implementation
@ -130,12 +131,15 @@ uses
function ShowMakeResStrDialog(
const StartPos, EndPos: TPoint; Code: TCodeBuffer;
Positions: TCodeXYPositions;
var NewIdentifier: string;
var NewIdentifier, NewIdentifierValue: string;
var NewSourceLines: string;
var ResourcestringSection: integer;
var ResStrSectionCode: TCodeBuffer;
var ResStrSectionXY: TPoint;
var InsertPolicy: TResourcestringInsertPolicy): TModalResult;
var
MakeResStrDialog: TMakeResStrDialog;
Section: PCodeXYPosition;
ResourcestringSectionID: Integer;
begin
MakeResStrDialog:=TMakeResStrDialog.Create(Application);
MakeResStrDialog.SetSource(Code,StartPos,EndPos);
@ -160,12 +164,15 @@ begin
if Result=mrOk then begin
// return results
NewIdentifier:=MakeResStrDialog.GetIdentifier;
ResourcestringSection:=MakeResStrDialog.ResStrSectionComboBox.ItemIndex;
NewSourceLines:=MakeResStrDialog.GetNewSource;
ResourcestringSectionID:=MakeResStrDialog.ResStrSectionComboBox.ItemIndex;
MakeResStrDialog.GetNewSource(NewSourceLines,NewIdentifierValue);
if MakeResStrDialog.InsertAlphabeticallyResStrRadioButton.Checked then
InsertPolicy:=rsipAlphabetically
else
InsertPolicy:=rsipAppend;
Section:=CodeToolBoss.Positions[ResourcestringSectionID];
ResStrSectionCode:=Section^.Code;
ResStrSectionXY:=Point(Section^.X,Section^.Y);
end;
// save settings and clean up
@ -568,8 +575,11 @@ begin
end;
procedure TMakeResStrDialog.UpdateSourcePreview;
var
NewSource, NewValue: string;
begin
SrcPreviewSynEdit.Text:=GetNewSource;
GetNewSource(NewSource,NewValue);
SrcPreviewSynEdit.Text:=NewSource;
end;
function TMakeResStrDialog.GetIdentifier: string;
@ -616,11 +626,11 @@ begin
CodeXY^.Code,CodeXY^.X,CodeXY^.Y,Identifier);
end;
function TMakeResStrDialog.GetNewSource: string;
procedure TMakeResStrDialog.GetNewSource(var NewSource,
ResourceStringValue: string);
var
FormatStringConstant: string;
FormatParameters: string;
NewSource: String;
LeftSide: String;
LastLine: string;
NewString: String;
@ -642,9 +652,9 @@ begin
NewSource:=LeftSide+NewString+RightSide;
with CodeToolBoss.SourceChangeCache.BeautifyCodeOptions do
NewSource:=BeautifyStatement(NewSource,Indent);
NewSource:=BeautifyStatement(NewSource,0);
Result:=NewSource;
ResourceStringValue:=FormatStringConstant;
end;

View File

@ -31,9 +31,9 @@ begin
// this is done in the overriden methods
end;
constructor TButtonControl.Create(AOwner: TComponent);
constructor TButtonControl.Create(TheOwner: TComponent);
begin
inherited Create(AOwner);
inherited Create(TheOwner);
ControlStyle:=ControlStyle-csMultiClicks-[csAcceptsControls];
end;

View File

@ -75,14 +75,14 @@ end;
{------------------------------------------------------------------------------
Method: TCustomCheckBox.Create
Params: AOwner: the owner of the class
Params: TheOwner: the owner of the class
Returns: Nothing
Constructor for custom checkbox.
------------------------------------------------------------------------------}
constructor TCustomCheckBox.Create(AOwner : TComponent);
constructor TCustomCheckBox.Create(TheOwner : TComponent);
begin
Inherited Create(AOwner);
Inherited Create(TheOwner);
FState := cbUnchecked;
FAllowGrayed := True;
Height:=20;
@ -185,6 +185,9 @@ begin
end;
{
$Log$
Revision 1.10 2003/03/09 17:44:12 mattias
finshed Make Resourcestring dialog and implemented TToggleBox
Revision 1.9 2002/10/09 10:22:54 lazarus
MG: fixed client origin coordinates

View File

@ -614,7 +614,7 @@ type
property Checked: Boolean read GetChecked write SetChecked stored IsCheckedStored default False;
property ClicksDisabled: Boolean read FClicksDisabled write FClicksDisabled;
public
constructor Create(AOwner: TComponent); override;
constructor Create(TheOwner: TComponent); override;
end;
@ -643,7 +643,7 @@ type
property AllowGrayed: Boolean read FAllowGrayed write FAllowGrayed;
property State: TCheckBoxState read GetState write SetState;
public
constructor Create(AOwner: TComponent); override;
constructor Create(TheOwner: TComponent); override;
published
property TabOrder;
property TabStop;
@ -769,7 +769,7 @@ type
TToggleBox = class(TCustomCheckBox)
private
public
constructor Create(AOwner: TComponent); override;
constructor Create(TheOwner: TComponent); override;
published
property AllowGrayed;
property Anchors;
@ -1394,6 +1394,9 @@ end.
{ =============================================================================
$Log$
Revision 1.78 2003/03/09 17:44:12 mattias
finshed Make Resourcestring dialog and implemented TToggleBox
Revision 1.77 2003/03/08 21:51:57 mattias
make resource string dialog nearly complete