{ This file is part of the Free Pascal Integrated Development Environment Copyright (c) 1998 by Berczi Gabor Tool support for the IDE See the file COPYING.FPC, included in this distribution, for details about the copyright. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} {$I globdir.inc} unit FPTools; {$ifdef cpullvm} {$modeswitch nestedprocvars} {$endif} interface uses Objects,Drivers,Views,Dialogs,Validate, BrowCol, WEditor,WViews, FPViews; const MsgFilterSign = 'BI#PIP#OK'#0; type TCaptureTarget = (capNone,capMessageWindow,capEditWindow,capNoSwap); PTool = ^TTool; TTool = object(TObject) constructor Init(const ATitle, AProgramPath, ACommandLine: string; AHotKey: word); function GetTitle: string; virtual; procedure GetParams(var ATitle, AProgramPath, ACommandLine: string; var AHotKey: word); virtual; procedure SetParams(const ATitle, AProgramPath, ACommandLine: string; const AHotKey: word); virtual; destructor Done; virtual; private Title : PString; ProgramPath : PString; CommandLine : PString; HotKey : word; end; PToolCollection = ^TToolCollection; TToolCollection = object(TCollection) function At(Index: sw_Integer): PTool; end; PToolListBox = ^TToolListBox; TToolListBox = object(TAdvancedListBox) function GetText(Item,MaxLen: Sw_Integer): String; virtual; end; PToolParamValidator = ^TToolParamValidator; TToolParamValidator = object(TValidator) function IsValid(const S: string): Boolean; virtual; procedure Error; virtual; private ErrorPos: integer; end; PToolItemDialog = ^TToolItemDialog; TToolItemDialog = object(TCenterDialog) constructor Init(ATool: PTool); function Execute: Word; virtual; private Tool : PTool; TitleIL : PEditorInputLine; ProgramIL: PEditorInputLine; ParamIL : PEditorInputLine; HotKeyRB : PRadioButtons; end; PToolsDialog = ^TToolsDialog; TToolsDialog = object(TCenterDialog) constructor Init; function Execute: Word; virtual; procedure HandleEvent(var Event: TEvent); virtual; private ToolsLB : PToolListBox; procedure Add; procedure Edit; procedure Delete; end; PToolMessage = ^TToolMessage; TToolMessage = object(TMessageItem) constructor Init(AModule: PString; ALine: string; ARow, ACol: sw_integer); function GetText(MaxLen: Sw_integer): string; virtual; end; PToolMessageListBox = ^TToolMessageListBox; TToolMessageListBox = object(TMessageListBox) procedure NewList(AList: PCollection); virtual; procedure Clear; virtual; procedure Update; virtual; function GetPalette: PPalette; virtual; constructor Load(var S: TStream); procedure Store(var S: TStream); destructor Done; virtual; end; PMessagesWindow = ^TMessagesWindow; TMessagesWindow = object(TFPWindow) constructor Init; procedure Update; virtual; procedure HandleEvent(var Event: TEvent); virtual; function GetPalette: PPalette; virtual; constructor Load(var S: TStream); procedure Store(var S: TStream); destructor Done; virtual; procedure FocusItem(i : sw_integer); procedure SizeLimits(var Min, Max: TPoint); virtual; private MsgLB : PToolMessageListBox; end; procedure InitTools; function GetToolCount: sw_integer; function GetToolName(Idx: sw_integer): string; function AddTool(Title, ProgramPath, Params: string; HotKey: word): sw_integer; procedure GetToolParams(Idx: sw_integer; var Title, ProgramPath, Params: string; var HotKey: word); procedure SetToolParams(Idx: sw_integer; Title, ProgramPath, Params: string; HotKey: word); procedure DoneTools; function GetHotKeyName(Key: word): string; function ParseToolParams(var Params: string; CheckOnly: boolean): integer; procedure InitToolProcessing; function ProcessMessageFile(const MsgFileName: string): boolean; procedure AddToolCommand(Command: string); procedure AddToolMessage(ModuleName, Text: string; Row, Col: longint); procedure ClearToolMessages; procedure DoneToolMessages; procedure UpdateToolMessages; procedure InitToolTempFiles; procedure DoneToolTempFiles; const ToolFilter : string[128] = ''; ToolOutput : string[128] = ''; CaptureToolTo : TCaptureTarget = capNone; ToolMessages : PCollection = nil; ToolModuleNames: PStoreCollection = nil; MessagesWindow : PMessagesWindow = nil; LastToolMessageFocused : PToolMessage = nil; LongestTool : sw_integer = 0; procedure RegisterFPTools; {$ifdef DEBUG} Procedure FpToolsDebugMessage(AFileName, AText : string; ALine, APos : string;nrline,nrpos:sw_word); {$endif DEBUG} implementation uses Dos, FVConsts, App,MsgBox, WConsts,WUtils,WINI, FPConst,FPVars,FPUtils; {$ifndef NOOBJREG} const RToolMessageListBox: TStreamRec = ( ObjType: 1600; VmtLink: Ofs(TypeOf(TToolMessageListBox)^); Load: @TToolMessageListBox.Load; Store: @TToolMessageListBox.Store ); RMessagesWindow: TStreamRec = ( ObjType: 1601; VmtLink: Ofs(TypeOf(TMessagesWindow)^); Load: @TMessagesWindow.Load; Store: @TMessagesWindow.Store ); {$endif} {$ifdef useresstrings} resourcestring {$else} const {$endif} dialog_tools = 'Tools'; dialog_modifynewtool = 'Modify/New Tool'; dialog_programarguments = 'Program Arguments'; dialog_messages = 'Messages'; msg_errorparsingparametersatpos = ^C'Error parsing parameters line at line position %d.'; msg_cantinstallmoretools = ^C'Can''t install more tools...'; msg_requiredparametermissingin = 'Required parameter missing in [%s]'; msg_requiredpropertymissingin = 'Required property missing in [%s]'; msg_unknowntypein = 'Unknown type in [%s]'; msg_propertymissingin = '%s property missing in [%s]'; msg_invaliditemsin = 'Invalid number of items in [%s]'; label_tools_programtitles = '~P~rogram titles'; label_toolprop_title = '~T~itle'; label_toolprop_programpath = 'Program ~p~ath'; label_toolprop_commandline = 'Command ~l~ine'; label_enterprogramargument = '~E~nter program argument'; { standard button texts } button_OK = 'O~K~'; button_Cancel = 'Cancel'; button_New = '~N~ew'; button_Edit = '~E~dit'; button_Delete = '~D~elete'; type THotKeyDef = record Name : string[12]; KeyCode : word; end; const HotKeys : array[0..11] of THotKeyDef = ( (Name : '~U~nassigned' ; KeyCode : kbNoKey ), (Name : 'Shift+F~2~' ; KeyCode : kbShiftF2 ), (Name : 'Shift+F~3~' ; KeyCode : kbShiftF3 ), (Name : 'Shift+F~4~' ; KeyCode : kbShiftF4 ), (Name : 'Shift+F~5~' ; KeyCode : kbShiftF5 ), (Name : 'Shift+F~6~' ; KeyCode : kbShiftF6 ), (Name : 'Shift+F~7~' ; KeyCode : kbShiftF7 ), (Name : 'Shift+F~8~' ; KeyCode : kbShiftF8 ), (Name : 'Shift+F~9~' ; KeyCode : kbShiftF9 ), (Name : 'Shift+F1~0~' ; KeyCode : kbShiftF10), (Name : 'Shift+F1~1~' ; KeyCode : kbShiftF11), (Name : 'Shift+~F~12' ; KeyCode : kbShiftF12)); Tools : PToolCollection = nil; AbortTool : boolean = false; ToolTempFiles: PUnsortedStringCollection = nil; function GetHotKeyCount: integer; begin GetHotKeyCount:=ord(High(HotKeys))-ord(Low(HotKeys))+1; end; function GetHotKeyNameByIdx(Idx: integer): string; begin GetHotKeyNameByIdx:=HotKeys[Idx].Name; end; function HotKeyToIdx(Key: word): integer; var Count,I: integer; Found: boolean; begin Count:=GetHotKeyCount; Found:=false; I:=0; while (Inil then DisposeStr(Title); Title:=nil; if ProgramPath<>nil then DisposeStr(ProgramPath); ProgramPath:=nil; if CommandLine<>nil then DisposeStr(CommandLine); CommandLine:=nil; Title:=NewStr(ATitle); ProgramPath:=NewStr(AProgramPath); CommandLine:=NewStr(ACommandLine); HotKey:=AHotKey; end; destructor TTool.Done; begin inherited Done; if Title<>nil then DisposeStr(Title); if ProgramPath<>nil then DisposeStr(ProgramPath); if CommandLine<>nil then DisposeStr(CommandLine); end; function TToolCollection.At(Index: sw_Integer): PTool; begin At:=inherited At(Index); end; function TToolListBox.GetText(Item,MaxLen: sw_integer): String; var S: string; P: PTool; begin P:=List^.At(Item); S:=P^.GetTitle; GetText:=copy(S,1,MaxLen); end; procedure InitTools; begin if Tools<>nil then DoneTools; New(Tools, Init(10,20)); end; function GetToolCount: sw_integer; var Count: integer; begin if Tools=nil then Count:=0 else Count:=Tools^.Count; GetToolCount:=Count; end; function GetToolName(Idx: sw_integer): string; var S1,S2: string; W: word; begin GetToolParams(Idx,S1,S2,S2,W); GetToolName:=KillTilde(S1); end; function AddTool(Title, ProgramPath, Params: string; HotKey: word): sw_integer; var P: PTool; begin if Tools=nil then InitTools; New(P, Init(Title,ProgramPath,Params,HotKey)); Tools^.Insert(P); AddTool:=Tools^.IndexOf(P); end; procedure GetToolParams(Idx: sw_integer; var Title, ProgramPath, Params: string; var HotKey: word); var P: PTool; begin P:=Tools^.At(Idx); P^.GetParams(Title,ProgramPath,Params,HotKey); end; procedure SetToolParams(Idx: sw_integer; Title, ProgramPath, Params: string; HotKey: word); var P: PTool; begin P:=Tools^.At(Idx); P^.GetParams(Title,ProgramPath,Params,HotKey); end; procedure DoneTools; begin if Tools<>nil then Dispose(Tools, Done); Tools:=nil; end; procedure TToolParamValidator.Error; begin MsgParms[1].Long:=ErrorPos; ErrorBox(msg_errorparsingparametersatpos,@MsgParms); end; function TToolParamValidator.IsValid(const S: string): Boolean; var P: string; begin P:=S; ErrorPos:=ParseToolParams(P,true); IsValid:=ErrorPos=0; end; constructor TToolItemDialog.Init(ATool: PTool); var R,R2,R3: TRect; Items: PSItem; I,KeyCount: sw_integer; begin KeyCount:=GetHotKeyCount; R.Assign(0,0,60,Max(3+KeyCount,12)); inherited Init(R,dialog_modifynewtool); Tool:=ATool; GetExtent(R); R.Grow(-3,-2); R3.Copy(R); Inc(R.A.Y); R.B.Y:=R.A.Y+1; R.B.X:=R.A.X+36; New(TitleIL, Init(R, 128)); Insert(TitleIL); R2.Copy(R); R2.Move(-1,-1); Insert(New(PLabel, Init(R2, label_toolprop_title, TitleIL))); R.Move(0,3); New(ProgramIL, Init(R, 128)); Insert(ProgramIL); R2.Copy(R); R2.Move(-1,-1); Insert(New(PLabel, Init(R2, label_toolprop_programpath, ProgramIL))); R.Move(0,3); New(ParamIL, Init(R, 128)); Insert(ParamIL); ParamIL^.SetValidator(New(PToolParamValidator, Init)); R2.Copy(R); R2.Move(-1,-1); Insert(New(PLabel, Init(R2, label_toolprop_commandline, ParamIL))); R.Copy(R3); Inc(R.A.X,38); R.B.Y:=R.A.Y+KeyCount; Items:=nil; for I:=KeyCount-1 downto 0 do Items:=NewSItem(GetHotKeyNameByIdx(I), Items); New(HotKeyRB, Init(R, Items)); Insert(HotKeyRB); InsertButtons(@Self); TitleIL^.Select; end; function TToolItemDialog.Execute: Word; var R: word; S1,S2,S3: string; W: word; L: longint; begin Tool^.GetParams(S1,S2,S3,W); TitleIL^.SetData(S1); ProgramIL^.SetData(S2); ParamIL^.SetData(S3); L:=HotKeyToIdx(W); if L=-1 then L:=255; HotKeyRB^.SetData(L); R:=inherited Execute; if R=cmOK then begin TitleIL^.GetData(S1); ProgramIL^.GetData(S2); ParamIL^.GetData(S3); HotKeyRB^.GetData(L); W:=IdxToHotKey(L); Tool^.SetParams(S1,S2,S3,W); end; Execute:=R; end; constructor TToolsDialog.Init; var R,R2,R3: TRect; SB: PScrollBar; begin R.Assign(0,0,46,16); inherited Init(R,dialog_tools); HelpCtx:=hcTools; GetExtent(R); R.Grow(-3,-2); Inc(R.A.Y); R3.Copy(R); Dec(R.B.X,12); R2.Copy(R); R2.Move(1,0); R2.A.X:=R2.B.X-1; New(SB, Init(R2)); Insert(SB); New(ToolsLB, Init(R,1,SB)); Insert(ToolsLB); R2.Copy(R); R2.Move(0,-1); R2.B.Y:=R2.A.Y+1; Dec(R2.A.X); Insert(New(PLabel, Init(R2, label_tools_programtitles, ToolsLB))); R.Copy(R3); R.A.X:=R.B.X-10; R.B.Y:=R.A.Y+2; Insert(New(PButton, Init(R, button_OK, cmOK, bfNormal))); R.Move(0,2); Insert(New(PButton, Init(R, button_Edit, cmEditItem, bfDefault))); R.Move(0,2); Insert(New(PButton, Init(R, button_New, cmAddItem, bfNormal))); R.Move(0,2); Insert(New(PButton, Init(R, button_Delete, cmDeleteItem, bfNormal))); R.Move(0,2); Insert(New(PButton, Init(R, button_Cancel, cmCancel, bfNormal))); SelectNext(false); end; procedure TToolsDialog.HandleEvent(var Event: TEvent); var DontClear: boolean; begin case Event.What of evKeyDown : begin DontClear:=false; case Event.KeyCode of kbIns : Message(@Self,evCommand,cmAddItem,nil); kbDel : Message(@Self,evCommand,cmDeleteItem,nil); else DontClear:=true; end; if DontClear=false then ClearEvent(Event); end; evBroadcast : case Event.Command of cmListItemSelected : if Event.InfoPtr=pointer(ToolsLB) then Message(@Self,evCommand,cmEditItem,nil); end; evCommand : begin DontClear:=false; case Event.Command of cmAddItem : Add; cmDeleteItem : Delete; cmEditItem : Edit; else DontClear:=true; end; if DontClear=false then ClearEvent(Event); end; end; inherited HandleEvent(Event); end; function TToolsDialog.Execute: Word; var R: word; C: PToolCollection; I: integer; S1,S2,S3: string; W: word; begin New(C, Init(10,20)); if Tools<>nil then for I:=0 to Tools^.Count-1 do begin Tools^.At(I)^.GetParams(S1,S2,S3,W); C^.Insert(New(PTool, Init(S1,S2,S3,W))); end; ToolsLB^.NewList(C); R:=inherited Execute; if R=cmOK then begin if Tools<>nil then Dispose(Tools, Done); Tools:=C; Message(Application,evBroadcast,cmUpdateTools,nil); end else Dispose(C, Done); Execute:=R; end; procedure TToolsDialog.Add; var P: PTool; IC: boolean; S1,S2,S3: string; W: word; begin if ToolsLB^.Range>=MaxToolCount then begin InformationBox(msg_cantinstallmoretools,nil); Exit; end; IC:=ToolsLB^.Range=0; if IC=false then begin P:=ToolsLB^.List^.At(ToolsLB^.Focused); P^.GetParams(S1,S2,S3,W); end else begin S1:=''; S2:=''; S3:=''; W:=0; end; New(P, Init(S1,S2,S3,W)); if Application^.ExecuteDialog(New(PToolItemDialog, Init(P)), nil)=cmOK then begin ToolsLB^.List^.Insert(P); ToolsLB^.SetRange(ToolsLB^.List^.Count); ReDraw; end else Dispose(P, Done); end; procedure TToolsDialog.Edit; var P: PTool; begin if ToolsLB^.Range=0 then Exit; P:=ToolsLB^.List^.At(ToolsLB^.Focused); Application^.ExecuteDialog(New(PToolItemDialog, Init(P)), nil); ReDraw; end; procedure TToolsDialog.Delete; begin if ToolsLB^.Range=0 then Exit; ToolsLB^.List^.AtFree(ToolsLB^.Focused); ToolsLB^.SetRange(ToolsLB^.List^.Count); ReDraw; end; (*procedure ReplaceStr(var S: string; const What,NewS: string); var I : integer; begin repeat I:=Pos(What,S); if I>0 then begin Delete(S,I,length(What)); Insert(NewS,S,I); end; until I=0; end; procedure ReplaceStrI(var S: string; What: string; const NewS: string); var I : integer; UpcaseS: string; begin UpcaseS:=UpcaseStr(S); What:=UpcaseStr(What); repeat I:=Pos(What,UpcaseS); if I>0 then begin Delete(S,I,length(What)); Insert(NewS,S,I); end; until I=0; end;*) function GetCoordEntry(F: PINIFile; Section, Entry: string; var P: TPoint): boolean; var OK: boolean; S: string; Px: integer; begin S:=F^.GetEntry(Section,Entry,''); S:=Trim(S); OK:=(S<>'') and (S[1]='(') and (S[length(S)]=')'); if OK then S:=copy(S,2,length(S)-2); Px:=Pos(',',S); OK:=OK and (Px>0); if OK then P.X:=StrToInt(copy(S,1,Px-1)); OK:=OK and (LastStrToIntResult=0); if OK then P.Y:=StrToInt(copy(S,Px+1,High(S))); OK:=OK and (LastStrToIntResult=0); GetCoordEntry:=OK; end; function ExecutePromptDialog(const FileName: string; var Params: string): boolean; const MaxViews = 20; MaxViewNameLen = 40; MaxValueLen = 80; secMain = 'MAIN'; { Main section entries } tmeTitle = 'TITLE'; tmeCommandLine = 'COMMANDLINE'; tmeSize = 'SIZE'; tmeDefaultView = 'DEFAULT'; { View section entries } tieType = 'TYPE'; tieOrigin = 'ORIGIN'; tieSize = 'SIZE'; {*} tieDefault = 'DEFAULT'; tieValue = 'VALUE'; { Additional CheckBox view section entries } tieName = 'NAME'; tieOnParm = 'ON'; tieOffParm = 'OFF'; { Additional CheckBox view section entries } tieItem = 'ITEM'; tieParam = 'PARAM'; { Additional InputLine view section entries } tieMaxLen = 'MAXLEN'; { Additional Label view section entries } tieLink = 'LINK'; tieText = 'TEXT'; { Additional Memo view section entries } tieFileName = 'FILENAME'; { View types } vtCheckBox = 1; vtRadioButton = 2; vtInputLine = 3; vtMemo = 4; vtLabel = 127; vtsCheckBox = 'CHECKBOX'; vtsRadioButton = 'RADIOBUTTON'; vtsInputLine = 'INPUTLINE'; vtsLabel = 'LABEL'; vtsMemo = 'MEMO'; var Title : string; DSize : TPoint; CmdLine : string; ViewCount : Sw_integer; ViewNames : array[0..MaxViews-1] of string[MaxViewNameLen]; ViewTypes : array[0..MaxViews-1] of byte; ViewBounds : array[0..MaxViews-1] of TRect; ViewPtrs : array[0..MaxViews-1] of PView; ViewValues : array[0..MaxViews-1] of string[MaxValueLen]; ViewItemCount: array[0..MaxViews-1] of sw_integer; function BuildPromptDialogInfo(F: PINIFile): boolean; var OK: boolean; _IS: PINISection; procedure ProcessSection(Sec: PINISection); var P1,P2: TPoint; Typ: string; Count: sw_integer; begin if (OK=false) or ( (UpcaseStr(Sec^.GetName)=secMain) or (UpcaseStr(Sec^.GetName)=UpcaseStr(MainSectionName)) ) then Exit; ViewItemCount[ViewCount]:=0; OK:=(Sec^.SearchEntry(tieType)<>nil) and (Sec^.SearchEntry(tieOrigin)<>nil) and (Sec^.SearchEntry(tieSize)<>nil); if OK=false then begin ErrorBox(FormatStrStr(msg_requiredparametermissingin,Sec^.GetName),nil); Exit; end; Typ:=UpcaseStr(Trim(F^.GetEntry(Sec^.GetName,tieType,''))); if Typ=vtsCheckBox then ViewTypes[ViewCount]:=vtCheckBox else if Typ=vtsRadioButton then ViewTypes[ViewCount]:=vtRadioButton else if Typ=vtsInputLine then ViewTypes[ViewCount]:=vtInputLine else if Typ=vtsLabel then ViewTypes[ViewCount]:=vtLabel else if Typ=vtsMemo then ViewTypes[ViewCount]:=vtMemo else begin OK:=false; ErrorBox(FormatStrStr(msg_unknowntypein,Sec^.GetName),nil); Exit; end; ViewNames[ViewCount]:=Sec^.GetName; GetCoordEntry(F,Sec^.GetName,tieOrigin,P1); GetCoordEntry(F,Sec^.GetName,tieSize,P2); ViewBounds[ViewCount].Assign(P1.X,P1.Y,P1.X+P2.X,P1.Y+P2.Y); { allow conversion of $EDNAME for instance in default values PM } Typ:=F^.GetEntry(Sec^.GetName,tieValue,''); ParseToolParams(Typ,true); ViewValues[ViewCount]:=Typ; case ViewTypes[ViewCount] of vtLabel : begin OK:=OK and (Sec^.SearchEntry(tieLink)<>nil) and (Sec^.SearchEntry(tieText)<>nil); if OK=false then begin ErrorBox(FormatStrStr(msg_requiredpropertymissingin,Sec^.GetName),nil); Exit; end; end; vtInputLine : ; vtMemo : ; vtCheckBox : begin OK:=OK and (Sec^.SearchEntry(tieName)<>nil); if Typ='' then Typ:=tieOffParm; if F^.GetEntry(Sec^.GetName,tieDefault,'')<>'' then begin Typ:=F^.GetEntry(Sec^.GetName,tieDefault,''); end; Typ:=UpcaseStr(Trim(Typ)); if Typ=tieOnParm then Typ:='1' else if Typ=tieOffParm then Typ:='0' else if (Typ<>'0') and (Typ<>'1') then Ok:=false; ViewValues[ViewCount]:=Typ; if OK=false then begin ErrorBox(FormatStrStr2(msg_propertymissingin,tieName,Sec^.GetName),nil); Exit; end; end; vtRadioButton: begin Count:=0; while Sec^.SearchEntry(tieItem+IntToStr(Count+1))<>nil do Inc(Count); ViewItemCount[ViewCount]:=Count; OK:=Count>0; if OK=false then begin ErrorBox(FormatStrStr(msg_invaliditemsin,Sec^.GetName),nil); Exit; end; end; end; if OK then Inc(ViewCount); end; begin BuildPromptDialogInfo:=false; _IS:=F^.SearchSection(secMain); OK:=_IS<>nil; if OK then OK:=(_IS^.SearchEntry(tmeTitle)<>nil) and (_IS^.SearchEntry(tmeSize)<>nil) and (_IS^.SearchEntry(tmeCommandLine)<>nil); if OK then begin Title:=F^.GetEntry(secMain,tmeTitle,''); OK:=OK and GetCoordEntry(F,secMain,tmeSize,DSize); CmdLine:=F^.GetEntry(secMain,tmeCommandLine,''); OK:=OK and (CmdLine<>''); end; if OK=false then begin ErrorBox(FormatStrStr(msg_requiredpropertymissingin,_IS^.GetName),nil); Exit; end; if OK then begin ViewCount:=0; F^.ForEachSection(TCallbackProcParam(@ProcessSection)); end; BuildPromptDialogInfo:=OK; end; function SearchViewByName(Name: string): integer; var I,Idx: Sw_integer; begin Idx:=-1; Name:=UpcaseStr(Name); for I:=0 to ViewCount-1 do if UpcaseStr(ViewNames[I])=Name then begin Idx:=I; Break; end; SearchViewByName:=Idx; end; function GetParamValueStr(F: PINIFile; Idx: integer): string; var S: string; Entry: string[20]; begin S:='???'; case ViewTypes[Idx] of vtLabel : S:=''; vtMemo : begin S:=F^.GetEntry(ViewNames[Idx],tieFileName,''); if S='' then S:=GenTempFileName; ToolTempFiles^.InsertStr(S); if PFPMemo(ViewPtrs[Idx])^.SaveToFile(S)=false then ErrorBox(FormatStrStr(msg_errorsavingfile,S),nil); end; vtInputLine : S:=PInputLine(ViewPtrs[Idx])^.Data^; vtCheckBox : with PCheckBoxes(ViewPtrs[Idx])^ do begin if Mark(0) then Entry:=tieOnParm else Entry:=tieOffParm; S:=F^.GetEntry(ViewNames[Idx],Entry,''); end; vtRadioButton : with PRadioButtons(ViewPtrs[Idx])^ do begin Entry:=tieParam+IntToStr(Value+1); S:=F^.GetEntry(ViewNames[Idx],Entry,''); end; end; GetParamValueStr:=S; end; function ExtractPromptDialogParams(F: PINIFile; var Params: string): boolean; function ReplacePart(StartP,EndP: integer; const S: string): integer; begin Params:=copy(Params,1,StartP-1)+S+copy(Params,EndP+1,255); ReplacePart:=length(S)-(EndP-StartP+1); end; var OptName: string; OK: boolean; C: char; OptStart: integer; InOpt: boolean; I,Idx: integer; S: string; begin Params:=CmdLine; I:=1; InOpt:=false; OK:=true; while OK and (I<=length(Params)) do begin C:=Params[I]; if C='%' then begin InOpt:=not InOpt; if InOpt then begin OptName:=''; OptStart:=I; end else begin OptName:=UpcaseStr(OptName); Idx:=SearchViewByName(OptName); OK:=Idx<>-1; if OK then begin S:=GetParamValueStr(F,Idx); if (S='') and (Params[I+1]=' ') then Inc(I); I:=I+ReplacePart(OptStart,I,S); end; end; end else if InOpt then OptName:=OptName+C; Inc(I); end; ExtractPromptDialogParams:=OK; end; function ExecPromptDialog(F: PINIFile): boolean; var R: TRect; PromptDialog: PCenterDialog; Re: integer; OK: boolean; I,J,MaxLen: integer; Memo: PFPMemo; IL: PEditorInputLine; CB: PCheckBoxes; RB: PRadioButtons; LV: PLabel; SI: PSItem; S: string; P: PView; begin OK:=true; R.Assign(0,0,DSize.X,DSize.Y); New(PromptDialog, Init(R, Title)); with PromptDialog^ do begin for I:=0 to ViewCount-1 do begin case ViewTypes[I] of vtLabel : begin S:=F^.GetEntry(ViewNames[I],tieLink,''); J:=SearchViewByName(S); if J=-1 then P:=nil else P:=ViewPtrs[J]; S:=F^.GetEntry(ViewNames[I],tieText,''); New(LV, Init(ViewBounds[I], S, P)); ViewPtrs[I]:=LV; end; vtInputLine : begin MaxLen:=F^.GetIntEntry(ViewNames[I],tieMaxLen,80); New(IL, Init(ViewBounds[I], MaxLen)); IL^.Data^:=ViewValues[I]; ViewPtrs[I]:=IL; end; vtMemo : begin { MaxLen:=F^.GetIntEntry(ViewNames[I],tieMaxLen,80);} New(Memo, Init(ViewBounds[I],nil,nil,nil)); if ViewValues[I]<>'' then begin Memo^.AddLine(ViewValues[I]); Memo^.TextEnd; end; ViewPtrs[I]:=Memo; end; vtCheckBox : begin New(CB, Init(ViewBounds[I], NewSItem( F^.GetEntry(ViewNames[I],tieName,''), nil))); if StrToInt(ViewValues[I])=1 then CB^.Press(0); ViewPtrs[I]:=CB; end; vtRadioButton : begin SI:=nil; for J:=ViewItemCount[I] downto 1 do SI:=NewSItem(F^.GetEntry(ViewNames[I],tieItem+IntToStr(J),''),SI); New(RB, Init(ViewBounds[I], SI)); RB^.Press(StrToInt(ViewValues[I])); ViewPtrs[I]:=RB; end; end; Insert(ViewPtrs[I]); end; end; InsertButtons(PromptDialog); S:=F^.GetEntry(secMain,tmeDefaultView,''); if S<>'' then begin S:=UpcaseStr(S); I:=0; while (IS) do Inc(I); if UpcaseStr(ViewNames[I])=S then ViewPtrs[I]^.Select; end; Re:=Desktop^.ExecView(PromptDialog); OK:=OK and (Re=cmOK); AbortTool:=(Re<>cmOK); if OK then OK:=ExtractPromptDialogParams(F,Params); if PromptDialog<>nil then Dispose(PromptDialog, Done); ExecPromptDialog:=OK; end; var OK: boolean; F: PINIFile; Fn : string; begin Fn:=LocateFile(FileName); if Fn='' then Fn:=FileName; if not ExistsFile(Fn) then ErrorBox('Can''t read '+Fn,nil) else begin New(F, Init(Fn)); OK:=F<>nil; if OK then begin OK:=BuildPromptDialogInfo(F); if OK then OK:=ExecPromptDialog(F); end; if F<>nil then Dispose(F, Done); end; ExecutePromptDialog:=OK; end; function ParseToolParams(var Params: string; CheckOnly: boolean): integer; var Err: integer; W: PSourceWindow; procedure ParseParams(Pass: sw_integer); var I: sw_integer; function IsAlpha(Ch: char): boolean; begin IsAlpha:=(Upcase(Ch) in['A'..'Z','_','$']); end; function ReplacePart(StartP,EndP: integer; const S: string): integer; begin Params:=copy(Params,1,StartP-1)+S+copy(Params,EndP+1,255); ReplacePart:=length(S)-(EndP-StartP+1); end; function Consume(Ch: char): boolean; var OK: boolean; begin OK:=Params[I]=Ch; if OK then Inc(I); Consume:=OK; end; function ReadTill(var S: string; C: char): boolean; var Found: boolean; begin Found:=false; S:=''; while (I<=length(Params)) and (Found=false) do begin Found:=Params[I]=C; if Found=false then begin S:=S+Params[I]; Inc(I); end; end; ReadTill:=Found; end; var C,PrevC: char; WordS: string; LastWordStart: sw_integer; L: longint; S: string; D: DirStr; N: NameStr; E: ExtStr; begin I:=1; WordS:=''; LastWordStart:=I; PrevC:=' '; while (I<=length(Params)+1) and (Err=0) do begin if I<=length(Params) then C:=Params[I]; if (I<=length(Params)) and IsAlpha(C) then begin if (I=1) or (IsAlpha(PrevC)=false) then begin WordS:=''; LastWordStart:=I; end; { if IsAlpha(C) then ForceConcat:=false;} WordS:=WordS+C; end else begin WordS:=UpcaseStr(Trim(WordS)); if WordS<>'' then if (WordS='$CAP') then begin if (Pass=0) then if (Params[I]=' ') and (I<=High(Params)) then Params[I]:='_'; end else if (WordS='$CAP_MSG') then begin if (Pass=2) then if Consume('(')=false then Err:=I else if ReadTill(S,')')=false then Err:=I else begin Consume(')'); I:=I+ReplacePart(LastWordStart,I-1,'')-1; ToolFilter:=S; CaptureToolTo:=capMessageWindow; end; end else if (WordS='$CAP_EDIT') then begin if (Pass=3) then begin if Consume('(')=false then I:=I+ReplacePart(LastWordStart,I-1,'')-1 else if ReadTill(S,')')=false then Err:=I else begin Consume(')'); I:=I+ReplacePart(LastWordStart,I-1,'')-1; ToolOutput:=S; end; CaptureToolTo:=capEditWindow; end; end else if (WordS='$COL') then begin if (Pass=1) then begin if W=nil then L:=0 else L:=W^.Editor^.CurPos.X+1; I:=I+ReplacePart(LastWordStart,I-1,IntToStr(L))-1; end; end else if (WordS='$CONFIG') then begin if (Pass=1) then I:=I+ReplacePart(LastWordStart,I-1,IniFileName)-1; end else if (WordS='$DIR') then begin if (Pass=2) then if Consume('(')=false then Err:=I else if ReadTill(S,')')=false then Err:=I else begin Consume(')'); FSplit(S,D,N,E); L:=Pos(':',D);if L>0 then Delete(D,1,L); I:=I+ReplacePart(LastWordStart,I-1,D)-1; end; end else if (WordS='$DRIVE') then begin if (Pass=2) then if Consume('(')=false then Err:=I else if ReadTill(S,')')=false then Err:=I else begin Consume(')'); FSplit(S,D,N,E); L:=Pos(':',D); D:=copy(D,1,L); I:=I+ReplacePart(LastWordStart,I-1,D)-1; end; end else if (WordS='$EDNAME') then begin if (Pass=1) then begin if W=nil then S:='' else S:=W^.Editor^.FileName; I:=I+ReplacePart(LastWordStart,I-1,S)-1; end; end else if (WordS='$EXENAME') then begin if (Pass=1) then I:=I+ReplacePart(LastWordStart,I-1,EXEFile)-1; end else if (WordS='$EXT') then begin if (Pass=2) then if Consume('(')=false then Err:=I else if ReadTill(S,')')=false then Err:=I else begin Consume(')'); FSplit(S,D,N,E); E:=copy(E,2,High(E)); I:=I+ReplacePart(LastWordStart,I-1,E)-1; end; end else if (WordS='$LINE') then begin if (Pass=1) then begin if W=nil then L:=0 else L:=W^.Editor^.CurPos.Y+1; I:=I+ReplacePart(LastWordStart,I-1,IntToStr(L))-1; end; end else if (WordS='$NAME') then begin if (Pass=2) then if Consume('(')=false then Err:=I else if ReadTill(S,')')=false then Err:=I else begin Consume(')'); FSplit(S,D,N,E); I:=I+ReplacePart(LastWordStart,I-1,N)-1; end; end else if (WordS='$NAMEEXT') then begin if (Pass=2) then if Consume('(')=false then Err:=I else if ReadTill(S,')')=false then Err:=I else begin Consume(')'); FSplit(S,D,N,E); I:=I+ReplacePart(LastWordStart,I-1,N+E)-1; end; end else if (WordS='$NOSWAP') then begin if (Pass=1) then begin I:=I+ReplacePart(LastWordStart,I-1,'')-1; CaptureToolTo:=capNoSwap; end; end else if (WordS='$DRIVE') then begin if (Pass=2) then if Consume('(')=false then Err:=I else if ReadTill(S,')')=false then Err:=I else begin Consume(')'); FSplit(S,D,N,E); L:=Pos(':',D); if L=0 then L:=-1; D:=copy(D,1,L+1); I:=I+ReplacePart(LastWordStart,I-1,D)-1; end; end else if (WordS='$PROMPT') then begin if (Pass=3) then if Params[I]='(' then begin if Consume('(')=false then Err:=I else if ReadTill(S,')')=false then Err:=I else begin Consume(')'); if S='' then Err:=I-1 else if CheckOnly=false then if ExecutePromptDialog(S,S)=false then Err:=I else I:=I+ReplacePart(LastWordStart,I-1,S)-1; end; end else { just prompt for parms } begin I:=I+ReplacePart(LastWordStart,I-1,'')-1; if CheckOnly=false then begin S:=copy(Params,I+1,High(Params)); if InputBox(dialog_programarguments, label_enterprogramargument, S,High(Params)-I+1)=cmOK then begin ReplacePart(LastWordStart,255,S); I:=255; end else Err:=-1; end; end; end else if (WordS='$SAVE') then begin if (Pass=0) then if (Params[I]=' ') and (I<=High(Params)) then Params[I]:='_'; end else if (WordS='$SAVE_ALL') then begin if (Pass=2) then begin I:=I+ReplacePart(LastWordStart,I-1,'')-1; Message(Application,evCommand,cmSaveAll,nil); end; end else if (WordS='$SAVE_CUR') then begin if (Pass=2) then begin I:=I+ReplacePart(LastWordStart,I-1,'')-1; Message(W,evCommand,cmSave,nil); end; end else if (WordS='$SAVE_PROMPT') then begin if (Pass=2) then begin I:=I+ReplacePart(LastWordStart,I-1,'')-1; if W<>nil then if W^.Editor^.SaveAsk(true)=false then Err:=-1; end; end else if (WordS='$WRITEMSG') then begin if (Pass=2) then if Consume('(')=false then Err:=I else if ReadTill(S,')')=false then Err:=I else begin Consume(')'); I:=I+ReplacePart(LastWordStart,I-1,'')-1; if CheckOnly=false then WriteToolMessagesToFile(S); end; end else if copy(WordS,1,1)='$' then Err:=LastWordStart; WordS:=''; end; PrevC:=C; Inc(I); end; end; var Pass: sw_integer; begin W:=FirstEditorWindow; Err:=0; AbortTool:=false; for Pass:=0 to 3 do begin ParseParams(Pass); if Err<>0 then Break; end; if AbortTool then Err:=-1; ParseToolParams:=Err; end; procedure InitToolProcessing; begin AbortTool:=false; CaptureToolTo:=capNone; ToolFilter:=''; ToolOutput:=''; end; function ProcessMessageFile(const MsgFileName: string): boolean; var OK,Done: boolean; S: PBufStream; C: char; Sign: array[1..10] of char; InFileName,InReference: boolean; AddChar: boolean; FileName,Line: string; Row,Col: longint; procedure AddLine; begin Row:=ord(Line[1])+ord(Line[2]) shl 8; Col:=ord(Line[3])+ord(Line[4]) shl 8; AddToolMessage(FileName,copy(Line,5,High(Line)),Row,Col); end; begin New(S, Init(MsgFileName, stOpenRead, 4096)); OK:=(S<>nil) and (S^.Status=stOK); if OK then S^.Read(Sign,SizeOf(Sign)); OK:=OK and (Sign=MsgFilterSign); Done:=false; InFileName:=false; InReference:=false; FileName:=''; Line:=''; while OK and (Done=false) do begin S^.Read(C,SizeOf(C)); OK:=(S^.Status=stOK); AddChar:=false; if OK then case C of #0 : if InFileName then begin InFileName:=false end else if InReference then begin if (length(Line)>4) then begin AddLine; InReference:=false; end else AddChar:=true; end else begin InFileName:=true; FileName:=''; end; #1 : if InReference then AddChar:=true else begin InReference:=true; Line:=''; end; #127 : if InReference then AddChar:=true else Done:=true; else AddChar:=true; end; if AddChar then if InFileName then FileName:=FileName+C else if InReference then Line:=Line+C; end; if S<>nil then Dispose(S, Done); ProcessMessageFile:=OK; end; procedure InitToolTempFiles; begin if not Assigned(ToolTempFiles) then New(ToolTempFiles, Init(10,10)); end; procedure DoneToolTempFiles; procedure DeleteIt(P: PString); begin DeleteFile(GetStr(P)); end; begin if not Assigned(ToolTempFiles) then Exit; {$ifndef DEBUG} ToolTempFiles^.ForEach(TCallbackProcParam(@DeleteIt)); {$endif ndef DEBUG} Dispose(ToolTempFiles, Done); ToolTempFiles:=nil; end; constructor TToolMessage.Init(AModule: PString; ALine: string; ARow, ACol: sw_integer); begin inherited Init(0,ALine,AModule,ARow,ACol); if LongestTool0) and (P<>nil) then begin Idx:=List^.IndexOf(P); if Idx>=0 then begin FocusItem(Idx); DrawView; end; end; DrawView; end; procedure TToolMessageListBox.NewList(AList: PCollection); begin if (List=ToolMessages) or (ToolMessages=nil) then begin List:=nil; SetRange(0); end; inherited NewList(AList); end; procedure TToolMessageListBox.Clear; begin ClearToolMessages; Update; Message(Application,evBroadcast,cmClearLineHighlights,@Self); end; function TToolMessageListBox.GetPalette: PPalette; const P: string[length(CBrowserListBox)] = CBrowserListBox; begin GetPalette:=@P; end; constructor TToolMessageListBox.Load(var S: TStream); begin inherited Load(S); end; procedure TToolMessageListBox.Store(var S: TStream); var OL: PCollection; begin OL:=List; New(List, Init(1,1)); inherited Store(S); Dispose(List, Done); List:=OL; end; destructor TToolMessageListBox.Done; begin HScrollBar:=nil; VScrollBar:=nil; if List=ToolMessages then begin List:=nil; SetRange(0); end; inherited Done; end; constructor TMessagesWindow.Init; var R: TRect; HSB,VSB: PScrollBar; begin Desktop^.GetExtent(R); R.A.Y:=R.B.Y-7; inherited Init(R,dialog_messages,SearchFreeWindowNo); HelpCtx:=hcMessagesWindow; HSB:=StandardScrollBar(sbHorizontal+sbHandleKeyboard); Insert(HSB); VSB:=StandardScrollBar(sbVertical+sbHandleKeyboard); Insert(VSB); VSB^.SetStep(R.B.Y-R.A.Y-2,1); HSB^.SetStep(R.B.X-R.A.X-2,1); GetExtent(R); R.Grow(-1,-1); New(MsgLB, Init(R, HSB, VSB)); Insert(MsgLB); Update; MessagesWindow:=@Self; end; procedure TMessagesWindow.Update; begin MsgLB^.Update; end; procedure TMessagesWindow.FocusItem(i : sw_integer); begin MsgLB^.FocusItem(i); end; procedure TMessagesWindow.HandleEvent(var Event: TEvent); begin case Event.What of evBroadcast : case Event.Command of cmListFocusChanged : if Event.InfoPtr=MsgLB then begin LastToolMessageFocused:=MsgLB^.List^.At(MsgLB^.Focused); Message(Application,evBroadcast,cmClearLineHighlights,@Self); end; end; end; inherited HandleEvent(Event); end; procedure TMessagesWindow.SizeLimits(var Min, Max: TPoint); begin inherited SizeLimits(Min,Max); Min.X:=20; Min.Y:=4; end; function TMessagesWindow.GetPalette: PPalette; const S: string[length(CBrowserWindow)] = CBrowserWindow; begin GetPalette:=@S; end; constructor TMessagesWindow.Load(var S: TStream); begin inherited Load(S); GetSubViewPtr(S,MsgLB); Update; MessagesWindow:=@Self; end; procedure TMessagesWindow.Store(var S: TStream); begin inherited Store(S); PutSubViewPtr(S,MsgLB); end; destructor TMessagesWindow.Done; begin MessagesWindow:=nil; inherited Done; end; procedure RegisterFPTools; begin {$ifndef NOOBJREG} RegisterType(RToolMessageListBox); RegisterType(RMessagesWindow); {$endif} end; {$ifdef DEBUG} Procedure FpToolsDebugMessage(AFileName, AText : string; ALine, APos :string ;nrline,nrpos:sw_word); begin AddToolMessage(AFileName,AText,nrline,nrPos); UpdateToolMessages; end; begin DebugMessageS:=@FpToolsDebugMessage; {$endif DEBUG} END.