unit FPCodTmp; { Code Templates } interface uses Objects,Drivers,Dialogs, WUtils,WViews,WEditor, FPViews; type PCodeTemplate = ^TCodeTemplate; TCodeTemplate = object(TObject) constructor Init(const AShortCut: string; AText: PUnsortedStringCollection); function GetShortCut: string; procedure GetText(AList: PUnsortedStringCollection); procedure SetShortCut(const AShortCut: string); procedure SetText(AList: PUnsortedStringCollection); procedure GetParams(var AShortCut: string; Lines: PUnsortedStringCollection); procedure SetParams(const AShortCut: string; Lines: PUnsortedStringCollection); constructor Load(var S: TStream); procedure Store(var S: TStream); destructor Done; virtual; private ShortCut: PString; Text: PUnsortedStringCollection; end; PCodeTemplateCollection = ^TCodeTemplateCollection; TCodeTemplateCollection = object(TSortedCollection) function Compare(Key1, Key2: Pointer): sw_Integer; virtual; function SearchByShortCut(const ShortCut: string): PCodeTemplate; virtual; function LookUp(const S: string; AcceptMulti: boolean; var Idx: sw_integer): string; virtual; end; PCodeTemplateListBox = ^TCodeTemplateListBox; TCodeTemplateListBox = object(TAdvancedListBox) function GetText(Item,MaxLen: Sw_Integer): String; virtual; end; PCodeTemplateDialog = ^TCodeTemplateDialog; TCodeTemplateDialog = object(TCenterDialog) constructor Init(const ATitle: string; ATemplate: PCodeTemplate); function Execute: Word; virtual; private Template : PCodeTemplate; ShortcutIL : PInputLine; CodeMemo : PFPCodeMemo; end; PCodeTemplatesDialog = ^TCodeTemplatesDialog; TCodeTemplatesDialog = object(TCenterDialog) SelMode: boolean; constructor Init(ASelMode: boolean;const AShortCut : string); function Execute: Word; virtual; procedure HandleEvent(var Event: TEvent); virtual; function GetSelectedShortCut: string; private CodeTemplatesLB : PCodeTemplateListBox; TemplateViewer : PFPCodeMemo; StartIdx : sw_integer; procedure Add; procedure Edit; procedure Delete; procedure Update; end; const CodeTemplates : PCodeTemplateCollection = nil; function FPTranslateCodeTemplate(var Shortcut: string; ALines: PUnsortedStringCollection): boolean; procedure InitCodeTemplates; function LoadCodeTemplates(var S: TStream): boolean; function StoreCodeTemplates(var S: TStream): boolean; procedure DoneCodeTemplates; procedure RegisterCodeTemplates; implementation uses Views,App,Validate, {$ifdef FVISION} FVConsts, {$else} Commands, {$endif} FPConst,FPString; {$ifndef NOOBJREG} const RCodeTemplate: TStreamRec = ( ObjType: 14501; VmtLink: Ofs(TypeOf(TCodeTemplate)^); Load: @TCodeTemplate.Load; Store: @TCodeTemplate.Store ); RCodeTemplateCollection: TStreamRec = ( ObjType: 14502; VmtLink: Ofs(TypeOf(TCodeTemplateCollection)^); Load: @TCodeTemplateCollection.Load; Store: @TCodeTemplateCollection.Store ); {$endif} constructor TCodeTemplate.Init(const AShortCut: string; AText: PUnsortedStringCollection); procedure CopyIt(P: PString); {$ifndef FPC}far;{$endif} begin Text^.Insert(NewStr(GetStr(P))); end; begin inherited Init; ShortCut:=NewStr(AShortCut); SetText(AText); end; function TCodeTemplate.GetShortCut: string; begin GetShortCut:=GetStr(ShortCut); end; procedure TCodeTemplate.GetText(AList: PUnsortedStringCollection); procedure CopyIt(P: PString); {$ifndef FPC}far;{$endif} begin AList^.Insert(NewStr(GetStr(P))); end; begin if Assigned(AList) and Assigned(Text) then Text^.ForEach(@CopyIt); end; procedure TCodeTemplate.SetShortCut(const AShortCut: string); begin if Assigned(ShortCut) then DisposeStr(ShortCut); ShortCut:=NewStr(AShortCut); end; procedure TCodeTemplate.SetText(AList: PUnsortedStringCollection); begin if Assigned(Text) then Dispose(Text, Done); New(Text, CreateFrom(AList)); end; procedure TCodeTemplate.GetParams(var AShortCut: string; Lines: PUnsortedStringCollection); begin AShortCut:=GetShortCut; GetText(Lines); end; procedure TCodeTemplate.SetParams(const AShortCut: string; Lines: PUnsortedStringCollection); begin SetShortCut(AShortCut); SetText(Lines); end; constructor TCodeTemplate.Load(var S: TStream); begin ShortCut:=S.ReadStr; New(Text, Load(S)); end; procedure TCodeTemplate.Store(var S: TStream); begin S.WriteStr(ShortCut); Text^.Store(S); end; destructor TCodeTemplate.Done; begin if Assigned(ShortCut) then DisposeStr(ShortCut); ShortCut:=nil; if Assigned(Text) then Dispose(Text, Done); Text:=nil; inherited Done; end; function TCodeTemplateCollection.Compare(Key1, Key2: Pointer): sw_Integer; var K1: PCodeTemplate absolute Key1; K2: PCodeTemplate absolute Key2; R: Sw_integer; S1,S2: string; begin S1:=UpCaseStr(K1^.GetShortCut); S2:=UpCaseStr(K2^.GetShortCut); if S1S2 then R:=1 else R:=0; Compare:=R; end; function TCodeTemplateCollection.SearchByShortCut(const ShortCut: string): PCodeTemplate; var T: TCodeTemplate; Index: sw_integer; P: PCodeTemplate; begin T.Init(ShortCut,nil); if Search(@T,Index)=false then P:=nil else P:=At(Index); T.Done; SearchByShortCut:=P; end; function TCodeTemplateCollection.LookUp(const S: string; AcceptMulti: boolean; var Idx: sw_integer): string; var OLI,ORI,Left,Right,Mid: sw_integer; MidP: PCodeTemplate; MidS: string; FoundS: string; UpS : string; begin Idx:=-1; FoundS:=''; Left:=0; Right:=Count-1; UpS:=UpCaseStr(S); while Left<=Right do begin OLI:=Left; ORI:=Right; Mid:=Left+(Right-Left) div 2; MidP:=At(Mid); MidS:=UpCaseStr(MidP^.GetShortCut); if copy(MidS,1,length(UpS))=UpS then begin if (Idx<>-1) and (Idx<>Mid) and not AcceptMulti then begin { several solutions possible, return nothing } Idx:=-1; FoundS:=''; break; end else if Idx=-1 then begin Idx:=Mid; FoundS:=MidP^.GetShortCut; end; end; if UpS-1) and (Idx-1 then begin P:=CodeTemplates^.At(Idx); ShortCut:=CompleteName; end; end; OK:=Assigned(P); if OK then P^.GetText(ALines); end; FPTranslateCodeTemplate:=OK; end; procedure InitCodeTemplates; begin if Assigned(CodeTemplates) then Exit; New(CodeTemplates, Init(10,10)); end; function LoadCodeTemplates(var S: TStream): boolean; var C: PCodeTemplateCollection; OK: boolean; begin New(C, Load(S)); OK:=Assigned(C) and (S.Status=stOk); if OK then begin if Assigned(CodeTemplates) then Dispose(CodeTemplates, Done); CodeTemplates:=C; end else if Assigned(C) then Dispose(C, Done); LoadCodeTemplates:=OK; end; function StoreCodeTemplates(var S: TStream): boolean; var OK: boolean; begin OK:=Assigned(CodeTemplates); if OK then begin CodeTemplates^.Store(S); OK:=OK and (S.Status=stOK); end; StoreCodeTemplates:=OK; end; procedure DoneCodeTemplates; begin if Assigned(CodeTemplates) then Dispose(CodeTemplates, Done); CodeTemplates:=nil; end; function TCodeTemplateListBox.GetText(Item,MaxLen: Sw_Integer): String; var P: PCodeTemplate; begin P:=List^.At(Item); GetText:=P^.GetShortCut; end; constructor TCodeTemplateDialog.Init(const ATitle: string; ATemplate: PCodeTemplate); var R,R2,R3: TRect; begin R.Assign(0,0,52,15); inherited Init(R,ATitle); Template:=ATemplate; 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+46; New(ShortCutIL, Init(R, 128)); Insert(ShortcutIL); ShortCutIL^.SetValidator(New(PFilterValidator,Init(NumberChars+AlphaChars))); R2.Copy(R); R2.Move(-1,-1); Insert(New(PLabel, Init(R2, label_codetemplate_shortcut, ShortcutIL))); R.Move(0,3); R.B.Y:=R.A.Y+8; New(CodeMemo, Init(R, nil,nil,nil{,4096 does not compile !! })); Insert(CodeMemo); R2.Copy(R); R2.Move(-1,-1); R2.B.Y:=R2.A.Y+1; Insert(New(PLabel, Init(R2, label_codetemplate_content, CodeMemo))); InsertButtons(@Self); ShortcutIL^.Select; end; function TCodeTemplateDialog.Execute: Word; var R: word; S: string; L: PUnsortedStringCollection; begin New(L, Init(10,10)); S:=Template^.GetShortCut; Template^.GetText(L); ShortcutIL^.SetData(S); CodeMemo^.SetContent(L); R:=inherited Execute; if R=cmOK then begin L^.FreeAll; ShortcutIL^.GetData(S); CodeMemo^.GetContent(L); Template^.SetShortcut(S); Template^.SetText(L); end; Execute:=R; end; constructor TCodeTemplatesDialog.Init(ASelMode: boolean;const AShortCut : string); function B2I(B: boolean; I1,I2: longint): longint; begin if B then B2I:=I1 else B2I:=I2; end; var R,R2,R3: TRect; SB: PScrollBar; begin R.Assign(0,0,46,20); inherited Init(R,'Code Templates'); HelpCtx:=hcCodeTemplateOptions; SelMode:=ASelMode; GetExtent(R); R.Grow(-3,-2); Inc(R.A.Y); R.B.Y:=R.A.Y+10; 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(CodeTemplatesLB, Init(R,1,SB)); Insert(CodeTemplatesLB); if AShortCut<>'' then begin If assigned(CodeTemplates) then CodeTemplates^.Lookup(AShortCut,true,StartIdx) else StartIdx:=-1; end; R2.Copy(R); R2.Move(0,-1); R2.B.Y:=R2.A.Y+1; Dec(R2.A.X); Insert(New(PLabel, Init(R2, label_codetemplate_templates, CodeTemplatesLB))); GetExtent(R); R.Grow(-2,-2); Inc(R.A.Y,12); R2.Copy(R); R2.Move(1,0); R2.A.X:=R2.B.X-1; New(SB, Init(R2)); Insert(SB); New(TemplateViewer, Init(R,nil,SB,nil{,4096 does not compile })); with TemplateViewer^ do begin ReadOnly:=true; AlwaysShowScrollBars:=true; end; Insert(TemplateViewer); 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, B2I(SelMode,bfDefault,bfNormal)))); R.Move(0,2); Insert(New(PButton, Init(R, button_Edit, cmEditItem, B2I(SelMode,bfNormal,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 TCodeTemplatesDialog.Update; var C: PUnsortedStringCollection; begin if CodeTemplatesLB^.Range=0 then C:=nil else C:=PCodeTemplate(CodeTemplatesLB^.GetFocusedItem)^.Text; TemplateViewer^.SetContent(C); ReDraw; end; function TCodeTemplatesDialog.GetSelectedShortCut: string; var S: string; begin if CodeTemplatesLB^.Range=0 then S:='' else S:=GetStr(PCodeTemplate(CodeTemplatesLB^.GetFocusedItem)^.ShortCut); GetSelectedShortCut:=S; end; procedure TCodeTemplatesDialog.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(CodeTemplatesLB) then Message(@Self,evCommand,cmEditItem,nil); cmListFocusChanged : if Event.InfoPtr=pointer(CodeTemplatesLB) then Message(@Self,evBroadcast,cmUpdate,nil); cmUpdate : Update; 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 TCodeTemplatesDialog.Execute: Word; var R: word; P: PCodeTemplate; C: PCodeTemplateCollection; L: PUnsortedStringCollection; I: integer; begin New(C, Init(10,20)); if Assigned(CodeTemplates) then for I:=0 to CodeTemplates^.Count-1 do begin P:=CodeTemplates^.At(I); New(L, Init(10,50)); P^.GetText(L); C^.Insert(New(PCodeTemplate, Init(P^.GetShortCut,L))); Dispose(L, Done); end; CodeTemplatesLB^.NewList(C); if StartIdx<>-1 then CodeTemplatesLB^.SetFocusedItem(CodeTemplates^.At(StartIdx)); Update; R:=inherited Execute; if R=cmOK then begin if Assigned(CodeTemplates) then Dispose(CodeTemplates, Done); CodeTemplates:=C; end else Dispose(C, Done); Execute:=R; end; procedure TCodeTemplatesDialog.Add; var P,P2: PCodeTemplate; IC: boolean; S: string; L: PUnsortedStringCollection; Cmd: word; CanExit: boolean; begin New(L, Init(10,10)); IC:=CodeTemplatesLB^.Range=0; if IC=false then begin P:=CodeTemplatesLB^.List^.At(CodeTemplatesLB^.Focused); P^.GetParams(S,L); end else begin S:=''; end; New(P, Init(S,L)); repeat Cmd:=Application^.ExecuteDialog(New(PCodeTemplateDialog, Init(dialog_newtemplate,P)), nil); CanExit:=(Cmd<>cmOK); if CanExit=false then begin P2:=PCodeTemplateCollection(CodeTemplatesLB^.List)^.SearchByShortCut(P^.GetShortCut); CanExit:=(Assigned(P2)=false); if CanExit=false then begin ClearFormatParams; AddFormatParamStr(P^.GetShortCut); ErrorBox(msg_codetemplate_alreadyinlist,@FormatParams); end; end; until CanExit; if Cmd=cmOK then begin CodeTemplatesLB^.List^.Insert(P); CodeTemplatesLB^.SetRange(CodeTemplatesLB^.List^.Count); CodeTemplatesLB^.SetFocusedItem(P); Update; end else Dispose(P, Done); Dispose(L, Done); end; procedure TCodeTemplatesDialog.Edit; var P,O,P2: PCodeTemplate; I: sw_integer; S: string; L: PUnsortedStringCollection; Cmd: word; CanExit: boolean; begin if CodeTemplatesLB^.Range=0 then Exit; New(L, Init(10,10)); I:=CodeTemplatesLB^.Focused; O:=CodeTemplatesLB^.List^.At(I); O^.GetParams(S,L); P:=New(PCodeTemplate, Init(S, L)); repeat Cmd:=Application^.ExecuteDialog(New(PCodeTemplateDialog, Init(dialog_modifytemplate,P)), nil); CanExit:=(Cmd<>cmOK); if CanExit=false then begin P2:=PCodeTemplateCollection(CodeTemplatesLB^.List)^.SearchByShortCut(P^.GetShortCut); CanExit:=(Assigned(P2)=false) or (CodeTemplatesLB^.List^.IndexOf(P2)=I); if CanExit=false then begin ClearFormatParams; AddFormatParamStr(P^.GetShortCut); ErrorBox(msg_codetemplate_alreadyinlist,@FormatParams); end; end; until CanExit; if Cmd=cmOK then begin with CodeTemplatesLB^ do begin List^.AtFree(I); O:=nil; List^.Insert(P); SetFocusedItem(P); end; Update; end; Dispose(L, Done); end; procedure TCodeTemplatesDialog.Delete; begin if CodeTemplatesLB^.Range=0 then Exit; CodeTemplatesLB^.List^.AtFree(CodeTemplatesLB^.Focused); CodeTemplatesLB^.SetRange(CodeTemplatesLB^.List^.Count); Update; end; procedure RegisterCodeTemplates; begin {$ifndef NOOBJREG} RegisterType(RCodeTemplate); RegisterType(RCodeTemplateCollection); {$endif} end; END.