MG: codecompletion now checks for filebreaks, savefile now checks for filedate

git-svn-id: trunk@1828 -
This commit is contained in:
lazarus 2002-08-07 09:55:31 +00:00
parent c775c0e5d4
commit 0e368232da
18 changed files with 421 additions and 130 deletions

View File

@ -129,13 +129,13 @@ function FindFirstNonSpaceCharInLine(const Source: string;
Position: integer): integer;
function GetLineIndent(const Source: string; Position: integer): integer;
function FindLineEndOrCodeInFrontOfPosition(const Source: string;
Position: integer; NestedComments: boolean): integer;
Position, MinPosition: integer; NestedComments: boolean): integer;
function FindLineEndOrCodeAfterPosition(const Source: string;
Position: integer; NestedComments: boolean): integer;
Position, MaxPosition: integer; NestedComments: boolean): integer;
function FindFirstLineEndInFrontOfInCode(const Source: string;
Position: integer; NestedComments: boolean): integer;
Position, MinPosition: integer; NestedComments: boolean): integer;
function FindFirstLineEndAfterInCode(const Source: string;
Position: integer; NestedComments: boolean): integer;
Position, MaxPosition: integer; NestedComments: boolean): integer;
function ReplacementNeedsLineEnd(const Source: string;
FromPos, ToPos, NewLength, MaxLineLength: integer): boolean;
function CountNeededLineEndsToAddForward(const Src: string;
@ -1159,7 +1159,7 @@ begin
end;
function FindLineEndOrCodeAfterPosition(const Source: string;
Position: integer; NestedComments: boolean): integer;
Position, MaxPosition: integer; NestedComments: boolean): integer;
{ search forward for a line end or code
ignore line ends in comments
Result is Position of Start of Line End
@ -1214,6 +1214,7 @@ var SrcLen: integer;
begin
SrcLen:=length(Source);
if SrcLen>MaxPosition then SrcLen:=MaxPosition;
Result:=Position;
if Result=0 then exit;
while (Result<=SrcLen) do begin
@ -1234,7 +1235,7 @@ begin
end;
function FindLineEndOrCodeInFrontOfPosition(const Source: string;
Position: integer; NestedComments: boolean): integer;
Position, MinPosition: integer; NestedComments: boolean): integer;
{ search backward for a line end or code
ignore line ends in comments or at the end of comment lines
(comment lines are lines without code and at least one comment)
@ -1264,61 +1265,74 @@ function FindLineEndOrCodeInFrontOfPosition(const Source: string;
2: comment */ |
3: a:=1;
}
procedure ReadComment(var P: integer);
var SrcStart: integer;
function ReadComment(var P: integer): boolean;
// false if compiler directive
var OldP: integer;
begin
OldP:=P;
case Source[P] of
'}':
begin
dec(P);
while (P>=1) and (Source[P]<>'{') do begin
while (P>=SrcStart) and (Source[P]<>'{') do begin
if NestedComments and (Source[P] in ['}',')']) then
ReadComment(P)
else
dec(P);
end;
Result:=not ((P>=SrcStart) and (Source[P+1]='$'));
dec(P);
end;
')':
begin
dec(P);
if (P>=1) and (Source[P]='*') then begin
if (P>=SrcStart) and (Source[P]='*') then begin
dec(P);
while (P>1)
while (P>SrcStart)
and ((Source[P-1]<>'(') or (Source[P]<>'*')) do begin
if NestedComments and (Source[P] in ['}',')']) then
ReadComment(P)
else
dec(P);
end;
Result:=not ((P>=SrcStart) and (Source[P+1]='$'));
dec(P,2);
end;
end else
Result:=true;
end;
else
Result:=true;
end;
if not Result then P:=OldP+1;
end;
var TestPos: integer;
OnlySpace: boolean;
begin
if Position<=1 then begin
Result:=1;
SrcStart:=MinPosition;
if SrcStart<1 then SrcStart:=1;
if Position<=SrcStart then begin
Result:=SrcStart;
exit;
end;
Result:=Position-1;
if Result>length(Source) then Result:=length(Source);
while (Result>0) do begin
while (Result>=SrcStart) do begin
case Source[Result] of
'}',')':
ReadComment(Result);
if not ReadComment(Result) then exit;
#10,#13:
begin
// line end in code found
if (Result>1) and (Source[Result-1] in [#10,#13])
if (Result>SrcStart) and (Source[Result-1] in [#10,#13])
and (Source[Result]<>Source[Result-1]) then dec(Result);
// test if it is a comment line (a line without code and at least one
// comment)
TestPos:=Result-1;
OnlySpace:=true;
while (TestPos>1) do begin
while (TestPos>SrcStart) do begin
if (Source[TestPos]='/') and (Source[TestPos-1]='/') then begin
// this is a comment line end -> search further
dec(TestPos);
@ -1347,10 +1361,11 @@ begin
end;
end;
end;
if Result<SrcStart then Result:=SrcStart;
end;
function FindFirstLineEndAfterInCode(const Source: string;
Position: integer; NestedComments: boolean): integer;
Position, MaxPosition: integer; NestedComments: boolean): integer;
{ search forward for a line end
ignore line ends in comments
Result is Position of Start of Line End
@ -1405,6 +1420,7 @@ var SrcLen: integer;
begin
SrcLen:=length(Source);
if SrcLen>MaxPosition then SrcLen:=MaxPosition;
Result:=Position;
while (Result<=SrcLen) do begin
case Source[Result] of
@ -1419,18 +1435,21 @@ begin
end;
function FindFirstLineEndInFrontOfInCode(const Source: string;
Position: integer; NestedComments: boolean): integer;
Position, MinPosition: integer; NestedComments: boolean): integer;
{ search backward for a line end
ignore line ends in comments
Result will be at the Start of the Line End
}
var
SrcStart: integer;
procedure ReadComment(var P: integer);
begin
case Source[P] of
'}':
begin
dec(P);
while (P>=1) and (Source[P]<>'{') do begin
while (P>=SrcStart) and (Source[P]<>'{') do begin
if NestedComments and (Source[P] in ['}',')']) then
ReadComment(P)
else
@ -1441,9 +1460,9 @@ function FindFirstLineEndInFrontOfInCode(const Source: string;
')':
begin
dec(P);
if (P>=1) and (Source[P]='*') then begin
if (P>=SrcStart) and (Source[P]='*') then begin
dec(P);
while (P>1)
while (P>SrcStart)
and ((Source[P-1]<>'(') or (Source[P]<>'*')) do begin
if NestedComments and (Source[P] in ['}',')']) then
ReadComment(P)
@ -1459,17 +1478,19 @@ function FindFirstLineEndInFrontOfInCode(const Source: string;
var TestPos: integer;
begin
Result:=Position;
while (Result>0) do begin
SrcStart:=MinPosition;
if SrcStart<1 then SrcStart:=1;
while (Result>=SrcStart) do begin
case Source[Result] of
'}',')':
ReadComment(Result);
#10,#13:
begin
// test if it is a '//' comment
if (Result>1) and (Source[Result-1] in [#10,#13])
if (Result>SrcStart) and (Source[Result-1] in [#10,#13])
and (Source[Result]<>Source[Result-1]) then dec(Result);
TestPos:=Result-1;
while (TestPos>1) do begin
while (TestPos>SrcStart) do begin
if (Source[TestPos]='/') and (Source[TestPos-1]='/') then begin
// this is a comment line end -> search further
break;

View File

@ -25,7 +25,6 @@
TCodeBuffer is an descendent of TSourceLog and manages a single file.
ToDo:
}
unit CodeCache;
@ -113,7 +112,8 @@ type
FGlobalWriteLockIsSet: boolean;
FGlobalWriteLockStep: integer;
function OnScannerGetSource(Sender: TObject; Code: pointer): TSourceLog;
function OnScannerLoadSource(Sender: TObject; const AFilename: string): pointer;
function OnScannerLoadSource(Sender: TObject; const AFilename: string;
OnlyIfExists: boolean): pointer;
function OnScannerGetFileName(Sender: TObject; Code: pointer): string;
function OnScannerCheckFileOnDisk(Code: pointer): boolean;
procedure OnScannerIncludeCode(ParentCode, IncludeCode: pointer);
@ -379,9 +379,12 @@ begin
end;
function TCodeCache.OnScannerLoadSource(Sender: TObject;
const AFilename: string): pointer;
const AFilename: string; OnlyIfExists: boolean): pointer;
begin
Result:=LoadFile(AFilename);
if OnlyIfExists and (not FileExists(AFilename)) then
Result:=FindFile(AFilename)
else
Result:=LoadFile(AFilename);
if Result<>nil then
OnScannerCheckFileOnDisk(Result);
end;

View File

@ -915,14 +915,12 @@ begin
if InsertNode<>nil then begin
// insert after InsertNode
Indent:=GetLineIndent(Src,InsertNode.StartPos);
InsertPos:=FindFirstLineEndAfterInCode(Src,InsertNode.EndPos,
Scanner.NestedComments);
InsertPos:=FindFirstLineEndAfterInCode(InsertNode.EndPos);
end else begin
// insert as first variable/proc
Indent:=GetLineIndent(Src,ClassSectionNode.StartPos)
+ASourceChangeCache.BeautifyCodeOptions.Indent;
InsertPos:=FindFirstLineEndAfterInCode(Src,ClassSectionNode.StartPos,
Scanner.NestedComments);
InsertPos:=FindFirstLineEndAfterInCode(ClassSectionNode.StartPos);
end;
end;
CurCode:=ANodeExt.ExtTxt1;
@ -1251,8 +1249,8 @@ var
or (ImplementationNode.LastChild.Desc<>ctnBeginBlock) then
InsertPos:=ImplementationNode.EndPos
else begin
InsertPos:=FindLineEndOrCodeInFrontOfPosition(Src,
ImplementationNode.LastChild.StartPos,Scanner.NestedComments);
InsertPos:=FindLineEndOrCodeInFrontOfPosition(
ImplementationNode.LastChild.StartPos);
end;
end else begin
// class is not in interface section
@ -1386,8 +1384,7 @@ begin
// set default insert position
Indent:=GetLineIndent(Src,LastExistingProcBody.StartPos);
InsertPos:=FindLineEndOrCodeAfterPosition(Src,
LastExistingProcBody.EndPos,Scanner.NestedComments);
InsertPos:=FindLineEndOrCodeAfterPosition(LastExistingProcBody.EndPos);
// check for all defined class methods (MissingNode), if there is a body
MissingNode:=ClassProcs.FindHighest;
@ -1415,12 +1412,10 @@ begin
Indent:=GetLineIndent(Src,ANode.StartPos);
if cmp>0 then begin
// insert behind ExistingNode
InsertPos:=FindLineEndOrCodeAfterPosition(Src,
ANode.EndPos,Scanner.NestedComments);
InsertPos:=FindLineEndOrCodeAfterPosition(ANode.EndPos);
end else begin
// insert in front of ExistingNode
InsertPos:=FindLineEndOrCodeInFrontOfPosition(Src,
ANode.StartPos,Scanner.NestedComments);
InsertPos:=FindLineEndOrCodeInFrontOfPosition(ANode.StartPos);
end;
end;
@ -1451,16 +1446,14 @@ begin
// see above (note 1) for ANodeExt2.Data
ANode:=TCodeTreeNodeExtension(ANodeExt2.Data).Node;
Indent:=GetLineIndent(Src,ANode.StartPos);
InsertPos:=FindLineEndOrCodeAfterPosition(Src,
ANode.EndPos,Scanner.NestedComments);
InsertPos:=FindLineEndOrCodeAfterPosition(ANode.EndPos);
end else if NextAVLNode<>nil then begin
// there is a NextAVLNode behind -> insert in front of body
ANodeExt2:=TCodeTreeNodeExtension(NextAVLNode.Data);
// see above (note 1) for ANodeExt2.Data
ANode:=TCodeTreeNodeExtension(ANodeExt2.Data).Node;
Indent:=GetLineIndent(Src,ANode.StartPos);
InsertPos:=FindLineEndOrCodeInFrontOfPosition(Src,
ANode.StartPos,Scanner.NestedComments);
InsertPos:=FindLineEndOrCodeInFrontOfPosition(ANode.StartPos);
end;
end;
end;
@ -1609,12 +1602,11 @@ var CleanCursorPos, Indent, insertPos: integer;
if (ImplementationNode.LastChild=nil)
or (ImplementationNode.LastChild.Desc<>ctnBeginBlock) then
// insert at end of code
InsertPos:=FindLineEndOrCodeInFrontOfPosition(Src,
ImplementationNode.EndPos,Scanner.NestedComments)
InsertPos:=FindLineEndOrCodeInFrontOfPosition(ImplementationNode.EndPos)
else begin
// insert in front of main program begin..end.
InsertPos:=FindLineEndOrCodeInFrontOfPosition(Src,
ImplementationNode.LastChild.StartPos,Scanner.NestedComments);
InsertPos:=FindLineEndOrCodeInFrontOfPosition(
ImplementationNode.LastChild.StartPos);
end;
// build nice proc

View File

@ -114,6 +114,9 @@ type
var Caret:TCodeXYPosition; var NewTopLine: integer): boolean; // true=ok, false=invalid CleanPos
procedure GetLineInfo(ACleanPos: integer;
var ALineStart, ALineEnd, AFirstAtomStart, ALastAtomEnd: integer);
function FindLineEndOrCodeAfterPosition(StartPos: integer): integer;
function FindLineEndOrCodeInFrontOfPosition(StartPos: integer): integer;
function FindFirstLineEndAfterInCode(StartPos: integer): integer;
function UpdateNeeded(OnlyInterfaceNeeded: boolean): boolean;
procedure BeginParsing(DeleteNodes, OnlyInterfaceNeeded: boolean); virtual;
@ -1591,6 +1594,56 @@ begin
end;
end;
function TCustomCodeTool.FindLineEndOrCodeAfterPosition(StartPos: integer
): integer;
{ Searches a nice position in the cleaned source after StartPos.
It will skip any space or comments (not directives) till next
line end or compiler directive or code or include file end.
}
var
LinkIndex, LinkEnd: integer;
begin
LinkIndex:=Scanner.LinkIndexAtCleanPos(StartPos);
LinkEnd:=Scanner.LinkCleanedEndPos(LinkIndex);
if LinkEnd>StartPos then
Result:=BasicCodeTools.FindLineEndOrCodeAfterPosition(Src,
StartPos,LinkEnd-1,Scanner.NestedComments)
else
Result:=StartPos;
end;
function TCustomCodeTool.FindLineEndOrCodeInFrontOfPosition(StartPos: integer
): integer;
{ Searches a nice position in the cleaned source in front of StartPos.
It will skip any space or comments (not directives) till next
line end or compiler directive or code or include file end.
}
var
LinkIndex, LinkStart: integer;
begin
LinkIndex:=Scanner.LinkIndexAtCleanPos(StartPos);
LinkStart:=Scanner.Links[LinkIndex].CleanedPos;
Result:=BasicCodeTools.FindLineEndOrCodeInFrontOfPosition(Src,
StartPos,LinkStart,Scanner.NestedComments);
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;
function TCustomCodeTool.UpdateNeeded(OnlyInterfaceNeeded: boolean): boolean;
begin
{$IFDEF CTDEBUG}

View File

@ -840,7 +840,8 @@ function TFindDeclarationTool.FindUnitSource(const AnUnitName,
{$IFDEF ShowTriedFiles}
writeln('TFindDeclarationTool.FindUnitSource.LoadFile ',AFilename);
{$ENDIF}
NewCode:=TCodeBuffer(Scanner.OnLoadSource(Self,ExpandFilename(AFilename)));
NewCode:=TCodeBuffer(Scanner.OnLoadSource(
Self,ExpandFilename(AFilename),true));
Result:=NewCode<>nil;
end;
@ -974,7 +975,7 @@ begin
if AnUnitInFilename<>'' then begin
// unitname in 'filename'
if FilenameIsAbsolute(AnUnitInFilename) then begin
Result:=TCodeBuffer(Scanner.OnLoadSource(Self,AnUnitInFilename));
Result:=TCodeBuffer(Scanner.OnLoadSource(Self,AnUnitInFilename,true));
end else begin
// search AnUnitInFilename in searchpath
Result:=SearchFileInPath(UnitSrcSearchPath,AnUnitInFilename);

View File

@ -54,8 +54,8 @@ type
//----------------------------------------------------------------------------
TOnGetSource = function(Sender: TObject; Code: Pointer): TSourceLog
of object;
TOnLoadSource = function(Sender: TObject; const AFilename: string): pointer
of object;
TOnLoadSource = function(Sender: TObject; const AFilename: string;
OnlyIfExists: boolean): pointer of object;
TOnGetSourceStatus = procedure(Sender: TObject; Code: Pointer;
var ReadOnly: boolean) of object;
TOnDeleteSource = procedure(Sender: TObject; Code: Pointer; Pos, Len: integer)
@ -249,8 +249,10 @@ type
function LinkIndexAtCleanPos(ACleanPos: integer): integer;
function LinkIndexAtCursorPos(ACursorPos: integer; ACode: Pointer): integer;
function LinkSize(Index: integer): integer;
function LinkCleanedEndPos(Index: integer): integer;
function FindFirstSiblingLink(LinkIndex: integer): integer;
function FindParentLink(LinkIndex: integer): integer;
//function FindFirstLinkIndexOfCodeInCleanPos
function CleanedSrc: string;
function CursorToCleanPos(ACursorPos: integer; ACode: pointer;
@ -259,7 +261,7 @@ type
// 1=CursorPos beyond scanned code
function CleanedPosToCursor(ACleanedPos: integer; var ACursorPos: integer;
var ACode: Pointer): boolean;
function WholeRangeIsWritable(CleanStartPos, CleanEndPos: integer): boolean;
procedure FindCodeInRange(CleanStartPos, CleanEndPos: integer;
UniqueSortedCodeList: TList);
@ -531,15 +533,21 @@ begin
Result:=CleanedLen-Links[Index].CleanedPos;
end;
function TLinkScanner.FindFirstSiblingLink(LinkIndex: integer): integer;
{ find link of the start of the code
e.g. The resulting link SrcPos is always 1
if LinkIndex is in the main code, the result will be 0
if LinkIndex is in an include file, the result will be the first link of
the include file. If the include file is included multiple times, it is
treated as if they are different files.
function TLinkScanner.LinkCleanedEndPos(Index: integer): integer;
begin
Result:=Links[Index].CleanedPos+LinkSize(Index);
end;
ToDo: if include file include itself, directly or indirectly
function TLinkScanner.FindFirstSiblingLink(LinkIndex: integer): integer;
{ find link at the start of the code
e.g. The resulting link SrcPos is always 1
if LinkIndex is in the main code, the result will be 0
if LinkIndex is in an include file, the result will be the first link of
the include file. If the include file is included multiple times, it is
treated as if they are different files.
ToDo: if include file includes itself, directly or indirectly
}
var
LastIndex: integer;
@ -1893,14 +1901,13 @@ begin
if Path<>'' then Path:=ExpandFilename(Path);
FileNameOnly:=ExtractFilename(AFilename);
Result:=nil;
if FileExists(Path+FileNameOnly) then
Result:=FOnLoadSource(Self,Path+FileNameOnly);
Result:=FOnLoadSource(Self,Path+FileNameOnly,true);
FileNameOnly:=lowercase(FileNameOnly);
if (Result=nil) and (FileExists(Path+FileNameOnly)) then
Result:=FOnLoadSource(Self,Path+FileNameOnly);
if (Result=nil) then
Result:=FOnLoadSource(Self,Path+FileNameOnly,true);
FileNameOnly:=UpperCaseStr(FileNameOnly);
if (Result=nil) and (FileExists(Path+FileNameOnly)) then
Result:=FOnLoadSource(Self,Path+FileNameOnly);
if (Result=nil) then
Result:=FOnLoadSource(Self,Path+FileNameOnly,true);
end;
function TLinkScanner.SearchIncludeFile(const AFilename: string;
@ -1956,11 +1963,11 @@ begin
if Result then exit;
end else begin
// main source has relative filename (= virtual)
NewCode:=FOnLoadSource(Self,AFilename);
NewCode:=FOnLoadSource(Self,AFilename,true);
if NewCode=nil then
NewCode:=FOnLoadSource(Self,lowercase(AFilename));
NewCode:=FOnLoadSource(Self,lowercase(AFilename),true);
if NewCode=nil then
NewCode:=FOnLoadSource(Self,UpperCaseStr(AFilename));
NewCode:=FOnLoadSource(Self,UpperCaseStr(AFilename),true);
Result:=(NewCode<>nil);
if Result then exit;
end;

View File

@ -835,8 +835,7 @@ begin
// if there is a comment in front of the top position, it probably belongs
// to the destination code
// -> adjust the topline position, so that the comment is visible
NewTopLineCleanPos:=FindLineEndOrCodeInFrontOfPosition(Src,
NewTopLineCleanPos,Scanner.NestedComments);
NewTopLineCleanPos:=FindLineEndOrCodeInFrontOfPosition(NewTopLineCleanPos);
if (NewTopLineCleanPos>=1) and (Src[NewTopLineCleanPos] in [#13,#10])
then begin
inc(NewTopLineCleanPos);

View File

@ -128,10 +128,10 @@ begin
InsertAtom.StartPos:=ResourceCode.SourceLength+1;
InsertAtom.EndPos:=ResourceCode.SourceLength+1;
end;
InsertAtom.StartPos:=FindLineEndOrCodeInFrontOfPosition(Src,
InsertAtom.StartPos,false)+1;
InsertAtom.EndPos:=FindLineEndOrCodeAfterPosition(Src,
InsertAtom.EndPos,false);
InsertAtom.StartPos:=BasicCodeTools.FindLineEndOrCodeInFrontOfPosition(Src,
InsertAtom.StartPos,1,false)+1;
InsertAtom.EndPos:=BasicCodeTools.FindLineEndOrCodeAfterPosition(Src,
InsertAtom.EndPos,SrcLen,false);
NewResData:=ResourceData;
i:=length(NewResData);
while (i>1) and (NewResData[i] in [' ',#10,#13]) do
@ -164,7 +164,8 @@ begin
Result:=true;
OldAtom:=FindLazarusResource(ResourceCode,ResourceName);
if (OldAtom.StartPos<1) then exit;
OldAtom.EndPos:=FindLineEndOrCodeAfterPosition(Src,OldAtom.EndPos,false);
OldAtom.EndPos:=BasicCodeTools.FindLineEndOrCodeAfterPosition(Src,
OldAtom.EndPos,SrcLen,false);
ResourceCode.Delete(OldAtom.StartPos,OldAtom.EndPos);
end;

View File

@ -649,10 +649,9 @@ begin
SourceChangeCache.MainScanner:=Scanner;
OldPosition:=FindLazarusResourceInBuffer(ResourceCode,ResourceName);
if OldPosition.StartPos>0 then begin
OldPosition.StartPos:=FindLineEndOrCodeInFrontOfPosition(Src,
OldPosition.StartPos,Scanner.NestedComments);
OldPosition.EndPos:=FindFirstLineEndAfterInCode(Src,OldPosition.EndPos,
Scanner.NestedComments);
OldPosition.StartPos:=FindLineEndOrCodeInFrontOfPosition(
OldPosition.StartPos);
OldPosition.EndPos:=FindFirstLineEndAfterInCode(OldPosition.EndPos);
if not SourceChangeCache.Replace(gtNone,gtNone,
OldPosition.StartPos,OldPosition.EndPos,'') then exit;
end;
@ -798,16 +797,13 @@ begin
if FromPos<1 then exit;
SourceChangeCache.MainScanner:=Scanner;
Indent:=GetLineIndent(Src,FromPos);
FromPos:=FindLineEndOrCodeInFrontOfPosition(Src,FromPos,
Scanner.NestedComments);
FromPos:=FindLineEndOrCodeInFrontOfPosition(FromPos);
SourceChangeCache.Replace(gtNewLine,gtNewLine,FromPos,FromPos,
SourceChangeCache.BeautifyCodeOptions.BeautifyStatement(
'Application.CreateForm('+AClassName+','+AVarName+');',Indent));
end else begin
FromPos:=FindLineEndOrCodeInFrontOfPosition(Src,OldPosition.StartPos,
Scanner.NestedComments);
ToPos:=FindFirstLineEndAfterInCode(Src,OldPosition.EndPos,
Scanner.NestedComments);
FromPos:=FindLineEndOrCodeInFrontOfPosition(OldPosition.StartPos);
ToPos:=FindFirstLineEndAfterInCode(OldPosition.EndPos);
SourceChangeCache.MainScanner:=Scanner;
SourceChangeCache.Replace(gtNewLine,gtNewLine,FromPos,ToPos,
SourceChangeCache.BeautifyCodeOptions.BeautifyStatement(
@ -824,10 +820,8 @@ begin
Result:=false;
if FindCreateFormStatement(-1,'*',UpperVarName,Position)=-1 then
exit;
FromPos:=FindLineEndOrCodeInFrontOfPosition(Src,Position.StartPos,
Scanner.NestedComments);
ToPos:=FindFirstLineEndAfterInCode(Src,Position.EndPos,
Scanner.NestedComments);
FromPos:=FindLineEndOrCodeInFrontOfPosition(Position.StartPos);
ToPos:=FindFirstLineEndAfterInCode(Position.EndPos);
SourceChangeCache.MainScanner:=Scanner;
SourceChangeCache.Replace(gtNone,gtNone,FromPos,ToPos,'');
Result:=SourceChangeCache.Apply;
@ -889,11 +883,10 @@ begin
if FindCreateFormStatement(Position,'*','*',StatementPos)=-1 then
break;
Position:=StatementPos.EndPos;
StatementPos.StartPos:=FindLineEndOrCodeInFrontOfPosition(Src,
StatementPos.StartPos,Scanner.NestedComments);
StatementPos.StartPos:=FindLineEndOrCodeInFrontOfPosition(
StatementPos.StartPos);
InsertPos:=StatementPos.StartPos;
StatementPos.EndPos:=FindFirstLineEndAfterInCode(Src,
StatementPos.EndPos,Scanner.NestedComments);
StatementPos.EndPos:=FindFirstLineEndAfterInCode(StatementPos.EndPos);
SourceChangeCache.Replace(gtNone,gtNone,
StatementPos.StartPos,StatementPos.EndPos,'');
until false;
@ -984,8 +977,7 @@ begin
Indent:=GetLineIndent(Src,SectionNode.StartPos)
+SourceChangeCache.BeautifyCodeOptions.Indent;
end;
InsertPos:=FindLineEndOrCodeInFrontOfPosition(Src,SectionNode.EndPos,
Scanner.NestedComments);
InsertPos:=FindLineEndOrCodeInFrontOfPosition(SectionNode.EndPos);
SourceChangeCache.Replace(gtNewLine,gtNewLine,InsertPos,InsertPos,
SourceChangeCache.BeautifyCodeOptions.BeautifyStatement(
VarName+':'+VarType+';',Indent)
@ -1018,10 +1010,8 @@ begin
if VarNode.FirstChild<>nil then begin
// variable definition has the form 'VarName: VarType;'
// -> delete whole line
FromPos:=FindLineEndOrCodeInFrontOfPosition(Src,VarNode.StartPos,
Scanner.NestedComments);
ToPos:=FindFirstLineEndAfterInCode(Src,VarNode.EndPos,
Scanner.NestedComments);
FromPos:=FindLineEndOrCodeInFrontOfPosition(VarNode.StartPos);
ToPos:=FindFirstLineEndAfterInCode(VarNode.EndPos);
end else begin
// variable definition has the form 'VarName, NextVarName: VarType;'
// -> delete only 'VarName, '

View File

@ -3695,7 +3695,7 @@ begin
// if nothing modified then a simple Save can be skipped
if ([sfSaveToTestDir,sfSaveAs]*Flags=[])
and (not ActiveUnitInfo.Modified) then begin
and (not ActiveUnitInfo.NeedsSaveToDisk) then begin
Result:=mrOk;
exit;
end;
@ -5253,10 +5253,11 @@ begin
Project1.GetUnitsChangedOnDisk(AnUnitList);
if AnUnitList=nil then exit;
Result:=ShowDiskDiffsDialog(AnUnitList);
if Result in [mrYesToAll] then begin
for i:=0 to AnUnitList.Count-1 do begin
CurUnit:=TUnitInfo(AnUnitList[i]);
writeln('AAA1 REVERTING ',CurUnit.Filename);
if Result in [mrYesToAll] then
Result:=mrOk;
for i:=0 to AnUnitList.Count-1 do begin
CurUnit:=TUnitInfo(AnUnitList[i]);
if Result in [mrYesToAll] then begin
if CurUnit.EditorIndex>=0 then begin
Result:=DoOpenEditorFile('',CurUnit.EditorIndex,[ofRevert]);
end else if CurUnit.IsMainUnit then begin
@ -5264,6 +5265,8 @@ writeln('AAA1 REVERTING ',CurUnit.Filename);
end else
Result:=mrIgnore;
if Result=mrAbort then exit;
end else begin
CurUnit.IgnoreCurrentFileDateOnDisk;
end;
Result:=mrOk;
end;
@ -6858,6 +6861,9 @@ end.
{ =============================================================================
$Log$
Revision 1.336 2002/08/07 09:55:26 lazarus
MG: codecompletion now checks for filebreaks, savefile now checks for filedate
Revision 1.335 2002/08/05 08:56:54 lazarus
MG: TMenuItems can now be enabled and disabled

View File

@ -79,8 +79,9 @@ type
fFormName: string; // classname is always T<FormName>
// this attribute contains the formname even if the unit is not loaded
fHasResources: boolean; // source has resource file
FIgnoreFileDateOnDiskValid: boolean;
FIgnoreFileDateOnDisk: longint;
fIsPartOfProject: boolean;
fLastCheckedFileAge: longint;
fLoaded: Boolean; // loaded in the source editor
fModified: boolean;
fOnFileBackup: TOnFileBackup;
@ -134,8 +135,10 @@ type
procedure IncreaseAutoRevertLock;
procedure DecreaseAutoRevertLock;
function IsAutoRevertLocked: boolean;
function ChangedOnDisk: boolean;
function ChangedOnDisk(CompareOnlyLoadSaveTime: boolean): boolean;
procedure IgnoreCurrentFileDateOnDisk;
function ShortFilename: string;
function NeedsSaveToDisk: boolean;
{ Properties }
property Breakpoints: TProjectBreakPointList
@ -423,8 +426,10 @@ begin
,MB_ABORTRETRYIGNORE);
if Result=mrAbort then exit;
if Result=mrIgnore then Result:=mrOk;
end else
end else begin
Result:=mrOk;
FIgnoreFileDateOnDiskValid:=true;
end;
until Result<>mrRetry;
Result:=mrOk;
end;
@ -476,6 +481,7 @@ begin
exit;
end else begin
Source:=NewSource;
FIgnoreFileDateOnDiskValid:=true;
Result:=mrOk;
end;
until Result<>mrRetry;
@ -503,6 +509,7 @@ begin
fForm := nil;
fFormName := '';
fHasResources := false;
FIgnoreFileDateOnDiskValid:=false;
fIsPartOfProject := false;
Loaded := false;
fModified := false;
@ -679,12 +686,22 @@ begin
Result:=fAutoRevertLockCount>0;
end;
function TUnitInfo.ChangedOnDisk: boolean;
function TUnitInfo.ChangedOnDisk(CompareOnlyLoadSaveTime: boolean): boolean;
begin
Result:=(Source<>nil) and (Source.FileOnDiskHasChanged)
and (fLastCheckedFileAge<>Source.FileDateOnDisk);
if Result then
fLastCheckedFileAge:=Source.FileDateOnDisk;
Result:=(Source<>nil) and (Source.FileOnDiskHasChanged);
if Result
and (not CompareOnlyLoadSaveTime)
and FIgnoreFileDateOnDiskValid
and (FIgnoreFileDateOnDisk=Source.FileDateOnDisk) then
Result:=false;
end;
procedure TUnitInfo.IgnoreCurrentFileDateOnDisk;
begin
if Source<>nil then begin
FIgnoreFileDateOnDiskValid:=true;
FIgnoreFileDateOnDisk:=Source.FileDateOnDisk;
end
end;
function TUnitInfo.ShortFilename: string;
@ -696,12 +713,19 @@ begin
end;
end;
function TUnitInfo.NeedsSaveToDisk: boolean;
begin
Result:=IsVirtual or Modified or ChangedOnDisk(true)
or (not FileExists(Filename));
end;
procedure TUnitInfo.SetSource(ABuffer: TCodeBuffer);
begin
if fSource=ABuffer then exit;
if (fSource<>nil) and IsAutoRevertLocked then
fSource.UnlockAutoDiskRevert;
fSource:=ABuffer;
FIgnoreFileDateOnDiskValid:=false;
if (fSource<>nil) then begin
if IsAutoRevertLocked then
fSource.LockAutoDiskRevert;
@ -1657,7 +1681,7 @@ begin
AnUnitList:=nil;
AnUnitInfo:=fFirstAutoRevertLockedUnit;
while (AnUnitInfo<>nil) do begin
if AnUnitInfo.ChangedOnDisk then begin
if AnUnitInfo.ChangedOnDisk(false) then begin
if AnUnitList=nil then
AnUnitList:=TList.Create;
AnUnitList.Add(AnUnitInfo);
@ -1852,6 +1876,9 @@ end.
{
$Log$
Revision 1.71 2002/08/07 09:55:28 lazarus
MG: codecompletion now checks for filebreaks, savefile now checks for filedate
Revision 1.70 2002/08/01 14:10:30 lazarus
MG: started file access monitoring for loaded files

View File

@ -1,3 +1,4 @@
// included by menus.pp
{******************************************************************************
TMainMenu
******************************************************************************
@ -15,6 +16,21 @@
* *
*****************************************************************************
}
{------------------------------------------------------------------------------
Method: TMainMenu.ItemChanged
Params: none
Returns: Nothing
Called whenever
------------------------------------------------------------------------------}
procedure TMainMenu.ItemChanged;
begin
{MenuChanged(nil, nil, False);
if FWindowHandle <> 0 then
SendMessage(FWindowHandle, CM_MENUCHANGED, 0, 0);}
end;
{------------------------------------------------------------------------------
Method: TMainMenu.Create
Params: AOwner: the owner of the class
@ -28,10 +44,14 @@ begin
FCompStyle := csMainMenu;
end;
// included by menus.pp
{ =============================================================================
$Log$
Revision 1.4 2002/08/07 09:55:30 lazarus
MG: codecompletion now checks for filebreaks, savefile now checks for filedate
Revision 1.3 2002/05/10 06:05:53 lazarus
MG: changed license to LGPL

View File

@ -17,6 +17,10 @@
* *
*****************************************************************************
}
const
SMenuNotFound = 'Sub-menu is not in menu';
SMenuIndexError = 'Menu index out of range';
SMenuItemIsNil = 'MenuItem is nil';
{------------------------------------------------------------------------------
Method: TMenuItem.Add
@ -92,8 +96,19 @@ end;
Description of the procedure for the class.
------------------------------------------------------------------------------}
procedure TMenuItem.Delete(Index: Integer);
var
Cur: TMenuItem;
begin
//TODO: Complete
if (Index < 0) or (FItems = nil) or (Index >= GetCount) then
raise EMenuError.Create(SMenuIndexError);
Cur := TMenuItem(FItems[Index]);
if Cur=nil then
raise EMenuError.Create(SMenuItemIsNil);
FItems.Delete(Index);
Cur.FParent := nil;
Cur.FOnChange := nil;
DestroyHandle;
MenuChanged(Count = 0);
end;
{------------------------------------------------------------------------------
@ -107,6 +122,7 @@ destructor TMenuItem.Destroy;
var
i : integer;
begin
DestroyHandle;
if assigned (FItems) then begin
i := FItems.Count-1;
while i>=0 do begin
@ -196,6 +212,17 @@ begin
Result := TMenuItem(FItems[Index]);
end;
{------------------------------------------------------------------------------
function TMenuItem.GetMenuIndex: Integer;
Get position of this menuitem in its menu
------------------------------------------------------------------------------}
function TMenuItem.GetMenuIndex: Integer;
begin
Result := -1;
if FParent <> nil then Result := FParent.IndexOf(Self);
end;
{------------------------------------------------------------------------------
Function: TMenuItem.GetParent
Params: none
@ -298,12 +325,30 @@ begin
if not HandleAllocated then CreateHandle;
end;
{------------------------------------------------------------------------------
procedure TMenuItem.DestroyHandle;
Free the Handle
------------------------------------------------------------------------------}
procedure TMenuItem.DestroyHandle;
var i: integer;
begin
if not HandleAllocated then exit;
if assigned (FItems) then begin
i := FItems.Count-1;
while i>=0 do begin
TMenuItem(FItems[i]).DestroyHandle;
dec(i);
end;
InterfaceObject.IntSendMessage3(LM_DESTROY, Self, nil);
end;
end;
{------------------------------------------------------------------------------
Method: TMenuItem.HasParent
Params:
Returns: True - the item has a parent responsible for streaming
------------------------------------------------------------------------------}
function TMenuItem.HasParent : Boolean;
begin
@ -333,12 +378,11 @@ begin
Item.GroupIndex := TMenuItem(FItems[Index - 1]).GroupIndex;
VerifyGroupIndex(Index, Item.GroupIndex);
// check if we are the main menu
// mainmenuitems have csMenu style
// if FMenu <> nil then Item.FCompStyle := csMenu;
Item.FParent := Self;
Item.FOnChange := @SubItemChanged;
FItems.Insert(Index, Item);
if HandleAllocated then Item.HandleNeeded;
MenuChanged(FItems.Count = 1);
end;
@ -367,20 +411,34 @@ var
Source: TMenuItem;
begin
if (Parent = nil) and (Owner is TMenu) then
Source := nil else
Source := nil
else
Source := Self;
if Assigned(FOnChange) then FOnChange(Self, Source, Rebuild);
end;
{------------------------------------------------------------------------------
Method: TMenuItem.Remove
Params: Item:
Returns: Nothing
procedure TMenuItem.SetChildOrder(Child: TComponent; Order: Integer);
Reposition the MenuItem
------------------------------------------------------------------------------}
procedure TMenuItem.SetChildOrder(Child: TComponent; Order: Integer);
begin
(Child as TMenuItem).MenuIndex := Order;
end;
{------------------------------------------------------------------------------
procedure TMenuItem.Remove(Item: TMenuItem);
------------------------------------------------------------------------------}
procedure TMenuItem.Remove(Item: TMenuItem);
var
I: Integer;
begin
// ToDo
I := IndexOf(Item);
if I<0 then raise EMenuError.Create(SMenuNotFound);
Delete(I);
end;
{------------------------------------------------------------------------------
@ -447,14 +505,57 @@ begin
end;
end;
{------------------------------------------------------------------------------
procedure TMenuItem.SetMenuIndex(const AValue: Integer);
Reposition the MenuItem
------------------------------------------------------------------------------}
procedure TMenuItem.SetMenuIndex(AValue: Integer);
var
OldParent: TMenuItem;
ParentCount: Integer;
begin
if FParent <> nil then
begin
ParentCount := FParent.Count;
if AValue < 0 then AValue := 0;
if AValue >= ParentCount then AValue := ParentCount - 1;
if AValue <> MenuIndex then
begin
OldParent := FParent;
OldParent.Remove(Self);
OldParent.Insert(AValue, Self);
end;
end;
end;
{------------------------------------------------------------------------------
procedure TMenuItem.SetRadioItem(const AValue: Boolean);
Sets the 'RadioItem' property of the group of menuitems with the same
GroupIndex. If RadioItem is true only one menuitem is checked at a time.
------------------------------------------------------------------------------}
procedure TMenuItem.SetRadioItem(const AValue: Boolean);
var
i: integer;
Item: TMenuItem;
begin
if FRadioItem <> AValue then
begin
FRadioItem := AValue;
if FChecked and FRadioItem then
TurnSiblingsOff;
MenuChanged(True);
if (GroupIndex<>0) and (FParent<>nil) then begin
for I := 0 to FParent.Count - 1 do begin
Item := FParent[I];
if (Item <> Self)
and (Item.GroupIndex = GroupIndex) then
Item.FRadioItem:=FRadioItem;
end;
end;
if (FParent <> nil) and not (csReading in ComponentState)
and (HandleAllocated) then
RadioMenuItemGroup(Handle,FRadioItem);
end;
end;
@ -576,12 +677,31 @@ begin
InterfaceObject.IntSendMessage3(LM_SETSHORTCUT, Self, @Msg);
end;
{------------------------------------------------------------------------------
procedure TMenuItem.SubItemChanged(Sender: TObject; Source: TMenuItem;
Rebuild: Boolean);
Is Called whenever one of the childs has changed.
------------------------------------------------------------------------------}
procedure TMenuItem.SubItemChanged(Sender: TObject; Source: TMenuItem;
Rebuild: Boolean);
begin
if Rebuild and HandleAllocated then
; // RebuildHandle;
if Parent <> nil then
Parent.SubItemChanged(Self, Source, False)
else if Owner is TMainMenu then
TMainMenu(Owner).ItemChanged;
end;
{------------------------------------------------------------------------------
Method: TMenuItem.TurnSiblingsOff
Params: none
Returns: Nothing
Unchecks all siblings.
In contrary to Delphi this will not use SetChecked, because this is up to the
interface. This procedure just sets the private variables.
------------------------------------------------------------------------------}
procedure TMenuItem.TurnSiblingsOff;
var
@ -627,6 +747,9 @@ end;
{ =============================================================================
$Log$
Revision 1.19 2002/08/07 09:55:30 lazarus
MG: codecompletion now checks for filebreaks, savefile now checks for filedate
Revision 1.18 2002/08/06 20:05:19 lazarus
MG: added actnlist.pp
@ -709,6 +832,9 @@ end;
$Log$
Revision 1.19 2002/08/07 09:55:30 lazarus
MG: codecompletion now checks for filebreaks, savefile now checks for filedate
Revision 1.18 2002/08/06 20:05:19 lazarus
MG: added actnlist.pp

View File

@ -453,6 +453,11 @@ begin
Result := InterfaceObject.PostMessage(hWnd, Msg, wParam, lParam);
end;
function RadioMenuItemGroup(hMenu: HMENU; bRadio: Boolean): Boolean;
begin
Result := InterfaceObject.RadioMenuItemGroup(hMenu,bRadio);
end;
function RealizePalette(DC: HDC): Cardinal;
begin
Result := InterfaceObject.RealizePalette(DC);
@ -1099,6 +1104,9 @@ end;
{ =============================================================================
$Log$
Revision 1.35 2002/08/07 09:55:30 lazarus
MG: codecompletion now checks for filebreaks, savefile now checks for filedate
Revision 1.34 2002/08/05 10:45:03 lazarus
MG: TMenuItem.Caption can now be set after creation

View File

@ -142,6 +142,7 @@ function Polyline(DC: HDC; Points: PPoint; NumPts: Integer): boolean; {$IFDEF IF
function PostMessage(hWnd: HWND; Msg: Cardinal; wParam: LongInt; lParam: LongInt): Boolean; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
//function PtInRect --> independent
function RadioMenuItemGroup(hMenu: HMENU; bRadio: Boolean): Boolean; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
function RealizePalette(DC: HDC): Cardinal; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
function Rectangle(DC: HDC; X1, Y1, X2, Y2: Integer): Boolean; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
function RectVisible(dc : hdc; ARect: TRect) : Boolean; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
@ -271,6 +272,9 @@ function UnionRect(var DestRect: TRect; const SrcRect1, SrcRect2: TRect): Boolea
{ =============================================================================
$Log$
Revision 1.30 2002/08/07 09:55:30 lazarus
MG: codecompletion now checks for filebreaks, savefile now checks for filedate
Revision 1.29 2002/08/05 10:45:03 lazarus
MG: TMenuItem.Caption can now be set after creation

View File

@ -3664,9 +3664,22 @@ begin
Result := True;
end;
{------------------------------------------------------------------------------
Function: RadioMenuItemGroup
Params: hMenu: HMENU; bRadio: Boolean
Returns: Nothing
Change the group of menuitems to 'radio' or to checked.
------------------------------------------------------------------------------}
function TgtkObject.RadioMenuItemGroup(hMenu: HMENU; bRadio: Boolean): Boolean;
begin
// ToDo
Result := false;
end;
{------------------------------------------------------------------------------
Function: RealizePalette
Params: none
Params: DC: HDC
Returns: Nothing
@ -3680,7 +3693,7 @@ end;
{------------------------------------------------------------------------------
Function: Rectangle
Params: none
Params: DC: HDC; X1, Y1, X2, Y2: Integer
Returns: Nothing
The Rectangle function draws a rectangle. The rectangle is outlined by using
@ -4838,6 +4851,9 @@ end;
{ =============================================================================
$Log$
Revision 1.87 2002/08/07 09:55:30 lazarus
MG: codecompletion now checks for filebreaks, savefile now checks for filedate
Revision 1.86 2002/08/05 10:45:06 lazarus
MG: TMenuItem.Caption can now be set after creation

View File

@ -114,6 +114,7 @@ function Polygon(DC: HDC; Points: PPoint; NumPts: Integer; Winding: boolean): bo
function Polyline(DC: HDC; Points: PPoint; NumPts: Integer): boolean; override;
function PostMessage(hWnd: HWND; Msg: Cardinal; wParam: LongInt; lParam: LongInt): Boolean; override;
function RadioMenuItemGroup(hMenu: HMENU; bRadio: Boolean): Boolean; override;
function RealizePalette(DC: HDC): Cardinal; override;
function Rectangle(DC: HDC; X1, Y1, X2, Y2: Integer): Boolean; override;
function RectVisible(dc : hdc; ARect: TRect) : Boolean; override;
@ -158,6 +159,9 @@ Function WindowFromPoint(Point : TPoint) : HWND; override;
{ =============================================================================
$Log$
Revision 1.34 2002/08/07 09:55:31 lazarus
MG: codecompletion now checks for filebreaks, savefile now checks for filedate
Revision 1.33 2002/08/05 10:45:08 lazarus
MG: TMenuItem.Caption can now be set after creation

View File

@ -115,6 +115,7 @@ type
FOnClick: TNotifyEvent;
function GetCount: Integer;
function GetItem(Index: Integer): TMenuItem;
function GetMenuIndex: Integer;
function GetParent: TMenuItem;
function IsCaptionStored: boolean;
function IsCheckedStored: boolean;
@ -125,13 +126,17 @@ type
procedure SetChecked(AValue: Boolean);
procedure SetDefault(AValue: Boolean);
procedure SetEnabled(AValue: Boolean);
procedure SetMenuIndex(AValue: Integer);
procedure SetRadioItem(const AValue: Boolean);
procedure ShortcutChanged(const OldValue, Value : TShortcut);
procedure SubItemChanged(Sender: TObject; Source: TMenuItem;
Rebuild: Boolean);
procedure TurnSiblingsOff;
procedure VerifyGroupIndex(Position: Integer; Value: Byte);
protected
property ActionLink: TMenuActionLink read FActionLink write FActionLink;
procedure CreateHandle; virtual;
procedure DestroyHandle; virtual;
procedure DoClicked(var msg); message LM_ACTIVATE; //'activate';
function GetHandle: HMenu;
Procedure SetImageIndex(value : Integer);
@ -139,6 +144,7 @@ type
procedure SetShortCut(AValue : TShortCut);
procedure SetVisible(AValue: Boolean);
procedure MenuChanged(Rebuild : Boolean);
procedure SetChildOrder(Child: TComponent; Order: Integer); override;
procedure SetParentComponent(AValue : TComponent); override;
procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
public
@ -157,8 +163,10 @@ type
property Count: Integer read GetCount;
property Handle: HMenu read GetHandle write FHandle;
property Items[Index: Integer]: TMenuItem read GetItem; default;
property MenuIndex: Integer read GetMenuIndex write SetMenuIndex;
property Parent: TMenuItem read GetParent;
published
//property Bitmap: TBitmap read GetBitmap write SetBitmap;
property Caption: String read FCaption write SetCaption stored IsCaptionStored;
property Checked: Boolean read FChecked write SetChecked stored IsCheckedStored default False;
property Default: Boolean read FDefault write SetDefault default False;
@ -198,6 +206,8 @@ type
end;
TMainMenu = class(TMenu)
protected
procedure ItemChanged;
public
constructor Create(AOwner: TComponent); override;
published
@ -401,6 +411,9 @@ end.
{
$Log$
Revision 1.18 2002/08/07 09:55:30 lazarus
MG: codecompletion now checks for filebreaks, savefile now checks for filedate
Revision 1.17 2002/08/06 20:05:38 lazarus
MG: added stored funcitons