{$mode objfpc} {$h+} unit pgEditor; interface uses SysUtils,Classes,gdk,fpgtk,gtk,fpgtkext,dom,xmlread,xmlwrite; Type TTagType = (ttBold,ttItalic,ttUnderline,ttParagraph,ttVariable,ttRemark, ttNumberedList,ttUnnumberedList,ttListItem,ttTable,ttRow, ttCell,TTHeader,ttPre,ttCode,ttLink,ttFile); TNodeTreeItem = Class(TFPGtkTreeItem) Private FNode : TDomElement; Public Constructor Create (ANode : TDomElement); virtual; Property Node : TDomElement Read Fnode; Procedure CheckSubTree; end; TModuleTreeItem = Class(TNodeTreeItem); TTopicTreeItem = Class(TNodeTreeItem); TPackageTreeItem = Class(TNodeTreeItem); TNodeSelectEvent = Procedure (Sender : TObject; Node : TDomElement) Of Object; TPackageEditor = Class(TFPGtkVPaned) Private FCurrentPackage, FCurrentElement, FCurrentModule, FCurrentTopic : TDomElement; FOnSelectElement, FOnSelectPackage, FOnSelectTopic, FOnSelectionChanged, // FOnDeSelectElement, FOnSelectModule : TNodeSelectEvent; FDescriptionNode : TDomNode; FModuleTree : TFPGtkScrollTree; FElementTree : TFPGtkScrollTree; FModuleNode : TNodeTreeItem; FModified : Boolean; PTMenu, PMMenu : TFPgtkMenu; PMNode : TNodeTreeItem; FTRenameMenu, FTDeleteMenu, FRenameMenu, FDeleteMenu : TFPgtkMenuItem; Procedure MenuRenameClick(Sender : TFPGtkObject; Data : Pointer); Procedure MenuDeleteClick(Sender : TFPGtkObject; Data : Pointer); Function PopupModuleMenu(Sender:TFPgtkWidget; Event:PGdkEventButton; data:pointer): boolean; Function PopupTopicMenu(Sender:TFPgtkWidget; Event:PGdkEventButton; data:pointer): boolean; Procedure SelectTopic(Sender : TFPGtkObject; Data : Pointer); Procedure SelectModule(Sender : TFPGtkObject; Data : Pointer); Procedure SelectPackage(Sender : TFPGtkObject; Data : Pointer); Procedure SelectElement(Sender : TFPGtkObject; Data : Pointer); // Procedure DeSelectElement(Sender : TFPGtkWidget; Data : Pointer); // Procedure DoSelectionChanged(Sender : TFPGtkWidget; Data : Pointer); Procedure ShowModuleElements(Module : TDomElement); Procedure SetCurrentModule(Value : TDomElement); Procedure SetCurrentPackage(Value : TDomElement); Function FindPackageNode(P : TDomElement) : TNodeTreeItem; Function FindModuleNodeInNode(M : TDomElement; N : TNodeTreeItem) : TNodeTreeItem; Function FindTopicNodeInNode(M : TDomElement; N : TNodeTreeItem) : TNodeTreeItem; Function FindElementNode(E : TDomElement; N : TNodeTreeItem) : TNodeTreeItem; Procedure SetCurrentElement(E : TDomElement); Procedure SetCurrentTopic(T : TDomElement); Function CreateElementNode(E : TDomelement) : TNodeTreeItem; Procedure DeletePackage(N : TNodeTreeItem); Procedure DeleteModule(N : TNodeTreeItem); Procedure DeleteTopic(N : TNodeTreeItem); Procedure DeleteElement(N : TNodeTreeItem); Procedure RenamePackage(N : TNodeTreeItem); Procedure RenameModule(N : TNodeTreeItem); Procedure RenameTopic(N : TNodeTreeItem); Procedure RenameElement(N : TNodeTreeItem); Function GetSelectedNode : TNodeTreeItem; Procedure GetNameData(Sender : TFPGtkWindow;Data : Pointer; Action : Integer;Initiator : TFPGtkObject); Function NewName(ATitle : String;Var AName : String) : Boolean; Procedure ClearElements; Public Constructor Create; Procedure SetDescriptionNode (Value : TDomNode); Procedure Refresh; Procedure AddElement(E : TDomElement); Procedure DeletePackage(P : TDomElement); Procedure DeleteModule(M : TDomElement); Procedure DeleteElement(E : TDomElement); Procedure DeleteTopic(T : TDomElement); Procedure RenamePackage(P : TDomElement); Procedure RenameModule(M : TDomElement); Procedure RenameElement(E : TDomElement); Procedure RenameTopic(T : TDomElement); Property ModuleTree : TFPGtkScrollTree Read FModuleTree; Property ElementTree : TFPGtkScrollTree Read FElementTree; Property DescriptionNode : TDomNode Read FDescriptionNode Write SetDescriptionNode; Property OnSelectModule : TNodeSelectEvent Read FOnSelectModule Write FOnSelectmodule; Property OnSelectTopic : TNodeSelectEvent Read FOnSelectTopic Write FOnSelectTopic; Property OnSelectPackage : TNodeSelectEvent Read FOnSelectPackage Write FOnSelectPackage; // Property OnDeSelectElement : TNodeSelectEvent Read FOnDeSelectElement Write FOnDeSelectElement; Property OnSelectElement : TNodeSelectEvent Read FOnSelectElement Write FOnSelectElement; // Property OnSelectionChanged : TNodeSelectEvent Read FOnSelectionChanged Write FOnSelectionChanged; Property CurrentPackage : TDomElement Read FCurrentPackage Write SetCurrentPackage; Property CurrentModule : TDomElement Read FCurrentModule Write SetCurrentModule; Property CurrentTopic : TDomElement Read FCurrentTopic Write SetCurrentTopic; Property CurrentElement: TDomElement Read FCurrentElement Write SetCurrentElement; Property Modified : Boolean Read FModified Write FModified; end; TElementEditor = Class(TFPGtkVBox) Private FExampleNode, FShortNode, FDescrNode, FErrorsNode, FSeeAlsoNode, Felement : TDomElement; FLabel : TFPGtkLabel; FShortEntry : TFPGtkEntry; FDescrMemo, FErrorsMemo, FSeeAlsoMemo : TFPGtkScrollText; FExample : TFPGtkEntry; FCurrentEditable : TFPGtkEditable; FModified : Boolean; Procedure GetNodes; Procedure SetElement (Value : TDomElement); Function CurrentEditable : TFPGtkEditable; Function OnEditableFocusIn(Sender : TFPGtkWidget; Event : PGDKEventFocus;Data : Pointer) : Boolean; Function GetCurrentSelection : String; Procedure OnTextModified(Sender : TFPGtkObject; Data : Pointer); Public Procedure Refresh; Constructor Create; Function TestSave(S : String) : Boolean; Function CurrentXML : String; Function Save : Boolean; Procedure DeleteElement; Procedure InsertTag (tagName : String); Procedure InsertTag (TagType : TTagType); Procedure InsertLink(LinkTarget,LinkText : String); Procedure InsertTable(Cols,Rows : Integer; UseHeader : Boolean); Property Element : TDomElement Read FElement Write SetElement; Property CurrentSelection : String Read GetCurrentSelection; Property Modified : Boolean Read FModified Write FModified; end; TEditorPage = Class(TFPGtkHPaned) Private FChangingSelection : Boolean; FFileNameLabel : TFpGtkLabel; FDocument : TXMLDocument; FPackages : TPackageEditor; FElement : TElementEditor; FFileNAme : String; Procedure ElementSelected(Sender : TObject; Node : TDomElement) ; Procedure TopicSelected(Sender : TObject; Node : TDomElement) ; Procedure ModuleSelected(Sender : TObject; Node : TDomElement) ; Procedure PackageSelected(Sender : TObject; Node : TDomElement) ; // Procedure SelectionChanged(Sender : TFPgtkWidget; Node : TDomElement) ; // Procedure ElementDeSelected(Sender : TObject; Node : TDomElement) ; Function GetCurrentSelection : String; Function GetCurrentPackage : TDomElement; Function GetCurrentModule : TDomElement; Function GetCurrentTopic : TDomElement; Function GetCurrentElement : TDomElement; Procedure SetCurrentModule(Value : TDomElement); Procedure SetCurrentTopic(Value : TDomElement); Procedure SetCurrentPackage(Value : TDomElement); Procedure SetCurrentElement(Value : TDomElement); Procedure SetModified(Value : Boolean); Function GetModified : Boolean; Function MakeBackup(FN : String) : Boolean; Public Constructor Create; Function FirstPackage : TDomElement; Function FirstModule(APackage : TDomElement) : TDomElement; Procedure DisplayDocument; Procedure ClearDocument; Procedure LoadFromFile(FN : String); Procedure LoadFromStream(S : TStream); Procedure SaveToFile(FN : String); Procedure SetFileName(FN : String); Procedure InsertTag(TagType : TTagType); Procedure InsertLink(LinkTarget,LinkText : String); Procedure InsertTable(Cols,Rows : Integer; UseHeader : Boolean); Procedure NewPackage(APackageName : String); Procedure NewModule(AModuleName : String); Procedure NewTopic(ATopicName : String); Procedure NewElement(AElementName : String); Procedure GetElementList(List : TStrings); Property FileName : String Read FFileName; Property CurrentSelection : String Read GetCurrentSelection; Property CurrentPackage : TDomElement Read GetCurrentPackage Write SetCurrentPackage; Property CurrentModule : TDomElement Read GetCurrentModule Write SetCurrentModule; Property CurrentTopic : TDomElement Read GetCurrentTopic Write SetCurrentTopic; Property CurrentElement : TDomElement Read GetCurrentElement Write SetCurrentElement; Property FileNameLabel : TFPgtkLabel Read FFileNameLabel Write FFileNameLabel; Property Modified : Boolean Read GetModified Write SetModified; end; Const TagNames : Array[TTagType] of string = ('b','i','u','p','var','remark', 'ol','ul','li','table','tr', 'td','th','pre','code','link','file' ); implementation uses fpdemsg,frmnewnode,fpdeopts; { --------------------------------------------------------------------- TElementEditor ---------------------------------------------------------------------} Constructor TElementEditor.Create; Var F1,F2 : TFPGtkVPaned; V : TFPgtkVBox; L : TFpGtkLabel; begin Inherited Create; FLabel:=TFPgtkLabel.Create(SNoElement); PackStart(FLabel,False,False,0); L:=TFPGtkLabel.Create(SShortDescription); // Short V:=TFPGtkVBox.Create; FShortEntry:=TFPGtkEntry.Create; FShortEntry.ConnectFocusInEvent(@OnEditableFocusIn,Nil); FShortEntry.ConnectChanged(@OnTextModified,Nil); V.PackStart(L,False,False,0); V.PackStart(FShortEntry,True,true,0); PackStart(V,false,false,0); // Errors L:=TFPGtkLabel.Create(SErrors); V:=TFPGtkVBox.Create; FErrorsMemo:=TFPGtkScrollText.Create; FErrorsMemo.TheText.ConnectFocusInEvent(@OnEditableFocusIn,Nil); FErrorsMemo.TheText.ConnectChanged(@OnTextModified,Nil); FErrorsMemo.setusize(400,50); V.PackStart(L,False,False,0); V.PackStart(FErrorsMemo,True,true,0); F2:=TFPGtkVPaned.Create; F2.Pack1(V,True,True); // See Also V:=TFPGtkVBox.Create; L:=TFPGtkLabel.Create(SSeeAlso); FSeeAlsoMemo:=TFPGtkScrollText.Create; // FSeeAlsoMemo.TheText.ConnectEnterNotify(@OnEnterEditable,Nil); FSeeAlsoMemo.TheText.ConnectFocusInEvent(@OnEditableFocusIn,Nil); FSeeAlsoMemo.TheText.ConnectChanged(@OnTextModified,Nil); FSeeAlsoMemo.setusize(400,50); V.PackStart(L,False,False,0); V.PackStart(FSeeAlsoMemo,True,true,0); F2.Pack2(V,False,True); // Descr L:=TFPGtkLabel.Create(SDescription); V:=TFPGtkVBox.Create; FDescrMemo:=TFPGtkScrollText.Create; // FDescrMemo.TheText.ConnectEnterNotify(@OnEnterEditable,Nil); FDescrMemo.TheText.ConnectFocusInEvent(@OnEditableFocusIn,Nil); FDescrMemo.TheText.ConnectChanged(@OnTextModified,Nil); FDescrMemo.setusize(400,150); V.PackStart(L,False,False,0); V.PackStart(FDescrMemo,True,true,0); F1:=TFPGtkVPaned.Create; F1.Pack1(V,True,True); F1.Pack2(F2,False,True); PackStart(F1,true,true,0); // Example V:=TFPGtkVBox.Create; L:=TFPGtkLabel.Create(SCodeExample); FExample:=TFPGtkEntry.Create; FExample.ConnectFocusInEvent(@OnEditableFocusIn,Nil); FExample.ConnectChanged(@OnTextModified,Nil); V.PackStart(L,False,False,0); V.PackStart(FExample,True,true,0); PackStart(V,false,false,0); end; Procedure TElementEditor.SetElement (Value : TDomElement); begin // Writeln('Setelement'); If (Value<>FElement) then If not Modified or Save then begin { If (Value=Nil) then Writeln('Setelement called with Nil') else Writeln('Setelement : ',Value['name']);} FElement:=Value; // Writeln('Setelement : Refreshing'); Refresh; // Writeln('SetElement : Refreshed'); end; end; Procedure TElementEditor.DeleteElement; begin FElement:=Nil; Refresh; end; Procedure TElementEditor.Refresh; Var S : TSTringStream; Function NodeToString(E : TDomElement) : String; Var N : TDomNode; begin If (E=Nil) then Result:='' else begin S.Seek(0,soFromBeginning); S.Size:=0; N:=E.FirstChild; While Assigned(N) do begin WriteXml(N,S); N:=N.NextSibling; end; Result:=S.Datastring; end; end; Function RemoveLineFeeds(S : String) : String; Var I : Integer; begin Result:=S; For I:=1 to Length(Result) do If Result[i] in [#10,#13] then Result[i]:=' '; end; begin GetNodes; If Assigned(Felement) then FLabel.Text:=Format(SDataForElement,[FElement['name']]) else FLabel.Text:=SNoElement; S:=TStringStream.Create(''); Try FShortEntry.Text:=RemoveLineFeeds(NodeToString(FShortNode)); FDescrMemo.Text:=NodeToString(FDescrNode); FErrorsMemo.Text:=NodeToString(FErrorsNode); FSeeAlsoMemo.Text:=NodeToString(FSeeAlsoNode); If FExampleNode=Nil then FExample.Text:='' else FExample.Text:=FExampleNode['file']; FModified:=False; Finally S.Free; end; end; Function TElementeditor.TestSave(S : String) : Boolean; Const Head = ''; Tail = ''; SErrorSaving = 'There is an error in the documentation nodes:'+LineEnding+ '%s'+LineEnding+ 'Please correct it first and try saving again.'; Var D : TXMLDocument; SS : TStringStream; begin // Writeln('In testsave'); Result:=Length(S)=0; If Not Result then begin SS:=TStringStream.Create(Head+S+Tail); Try Try ReadXmlFile(D,SS); Result:=True; except On E : Exception do MessageDlg(SErrorSaving,[E.Message],mtError,[mbOK],0) end; finally D.Free; SS.Free; end; end; end; Function TElementEditor.CurrentXML : String; Function GetNodeString(NodeName,Value : String) : String; begin Result:=''; If (Value<>'') Then Result:=Format('<%s>%s',[NodeName,Value,NodeName]) else If Not SkipEmptyNodes then result:='<'+NodeName+'/>'; end; Var S : String; begin // Writeln('In currentxml'); Result:=''; If Not Assigned(FElement) then Exit; Result:=GetNodeString('short',Trim(FShortEntry.Text)); Result:=Result+GetNodeString('descr',trim(FDescrMemo.Text)); Result:=Result+GetNodeString('errors',trim(FErrorsMemo.Text)); Result:=Result+GetNodeString('seealso',trim(FSeeAlsoMemo.Text)); S:=Trim(FExample.Text); If (S<>'') then Result:=Result+''; // Writeln('Currentxml : ',Result); end; Function TElementEditor.Save : Boolean; Var SS : TStringStream; S : String; N,NN : TDomNode; begin Result:=False; S:=CurrentXML; If TestSave(S) then begin // Writeln('Saving data'); SS:=TStringStream.Create(S); Try // Free child nodes. N:=FElement.FirstChild; While N<>Nil do begin NN:=N.NextSibling; If not ((N is TDomElement) and (N.NodeName='element')) then FElement.RemoveChild(N); N:=NN; end; // Read them again from stream. SS.Seek(0,soFromBeginning); ReadXMLFragment(FElement,SS); FModified:=False; Result:=True; // Writeln('Data saved'); Finally SS.Free; end; end; end; Procedure TElementEditor.InsertTag (tagName : String); Var PB,PE : Integer; begin If Assigned(CurrentEditable) then With CurrentEditable do begin PB:=SelectionStart; PE:=SelectionEnd; InsertText('',PE); InsertText('<'+TagName+'>',PB); SelectionStart:=PB+Length(TagName)+2; FModified:=True; end; end; Procedure TElementEditor.InsertTag(TagType : TTagType); begin InsertTag(TagNames[TagTYpe]); end; Procedure TElementEditor.InsertLink(LinkTarget,LinkText : String); begin If CurrentEditable<>Nil then With CurrentEditable do begin If (LinkText<>'') then Selection:=''+LinkText+'' else Selection:=''; end; end; Procedure TElementEditor.InsertTable(Cols,Rows : Integer; UseHeader : Boolean); Var I,J : Integer; R,T : String; begin If (CurrentEditable=FDescrMemo.TheText) or (CurrentEditable=FErrorsMemo.TheText) then begin R:=''; For I:=1 to Cols do R:=R+''; R:=R+''+lineEnding; T:=''; If UseHeader then begin Dec(Rows); T:=''; For I:=1 to Cols do T:=T+''; T:=T+''+lineEnding; end; For I:=1 to rows do T:=T+R; T:=LineEnding+''+LineEnding+T+'
'+LineEnding; With CurrentEditable do Selection:=t; end; end; Procedure TElementEditor.GetNodes; Var Node : TDomNode; S : String; begin FShortNode:=Nil; FDescrNode:=Nil; FErrorsNode:=Nil; FSeeAlsoNode:=Nil; FExampleNode:=Nil; If Assigned(FElement) then begin Node:=FElement.FirstChild; While Assigned(Node) do begin If (Node.NodeType=ELEMENT_NODE) then begin S:=Node.NodeName; If S='short' then FShortNode:=TDomElement(Node) else if S='descr' then FDescrNode:=TDomElement(Node) else if S='errors' then FErrorsNode:=TDomElement(Node) else if S='seealso' then FSeeAlsoNode:=TDomElement(Node) else if S='example' then FExampleNode:=TDomElement(Node); end; Node:=Node.NextSibling; end; end; end; Function TElementEditor.CurrentEditable : TFPGtkEditable; begin Result:=FCurrentEditable; end; Function TElementEditor.OnEditableFocusIn(Sender : TFPGtkWidget; Event : PGDKEventFocus;Data : Pointer) : Boolean; begin FCurrentEditable:=Sender as TFPGtkEditable; Result:=False; end; Procedure TElementEditor.OnTextModified(Sender : TFPGtkObject; Data : Pointer); begin FModified:=True; end; Function TElementEditor.GetCurrentSelection : String; begin If CurrentEditable=Nil then begin // Writeln('No current editable'); Result:='' end else Result:=CurrentEditable.Selection; end; { --------------------------------------------------------------------- TNodeTreeItem ---------------------------------------------------------------------} Constructor TNodeTreeItem.Create (ANode : TDomElement); begin Inherited Create; FNode:=Anode; Text:=ANode['name']; end; Procedure TNodeTreeItem.CheckSubTree; begin If (SubTree=Nil) then SubTree:=TFPgtkTree.Create; end; { --------------------------------------------------------------------- TPackageEditor ---------------------------------------------------------------------} Constructor TPackageEditor.Create; begin Inherited; FModuleTree:=TFPGtkScrollTree.Create; FElementTree:=TFPGtkScrollTree.Create; // FelementTree.Tree.ConnectSelectionChanged(@DoSelectionChanged,Nil); PMMenu:=TFPgtkMenu.Create; FRenameMenu:=NewMenuItem(SMenuRename,'','',@MenuRenameClick,Nil); FDeleteMenu:=NewMenuItem(SMenuDelete,'','',@MenuDeleteClick,Nil); PMMenu.Append(FRenameMenu); PMMenu.Append(FDeleteMenu); Add1(FModuleTree); Add2(FElementTree); PTMenu:=TFPgtkMenu.Create; FTRenameMenu:=NewMenuItem(SMenuRename,'','',@MenuRenameClick,Nil); FTDeleteMenu:=NewMenuItem(SMenuDelete,'','',@MenuDeleteClick,Nil); PTMenu.Append(FTRenameMenu); PTMenu.Append(FTDeleteMenu); end; function TPackageEditor.PopupModuleMenu(Sender:TFPgtkWidget; Event:PGdkEventButton; data:pointer): boolean; begin PMNode:=Sender as TNodeTreeItem; Result:=(event^.thetype=GDK_BUTTON_PRESS) and (event^.button=3); If Result then PMMenu.Popup(3); end; function TPackageEditor.PopupTopicMenu(Sender:TFPgtkWidget; Event:PGdkEventButton; data:pointer): boolean; begin PMNode:=Sender as TNodeTreeItem; Result:=(event^.thetype=GDK_BUTTON_PRESS) and (event^.button=3); If Result then PTMenu.Popup(3); end; Procedure TPackageEditor.SetDescriptionNode (Value : TDomNode); begin FDescriptionNode:=Value; Refresh; end; {Procedure TPackageEditor.DoSelectionChanged(Sender : TFPGtkWidget; Data : Pointer); Var N : TNodeTreeItem; E : TDomElement; begin // Writeln('In doselectionchanged'); If Assigned(FOnSelectionChanged) Then begin // Writeln('Getting selected node'); N:=GetSelectedNode; If N<>Nil then E:=N.Node else E:=Nil; FOnSelectionChanged(Sender,E); end; end; } Procedure TPackageEditor.SelectModule(Sender : TFPGtkObject; Data : Pointer); Var W : TFPGtkWidget; begin FCurrentElement:=Nil; FCurrentTopic:=Nil; FCurrentModule:=TDomElement(Data); FCurrentPackage:=FCurrentModule.ParentNode as TDomElement; ShowModuleElements(FCurrentModule); If Assigned(FOnSelectModule) then FOnSelectModule(Self,FCurrentModule); end; Procedure TPackageEditor.SelectPackage(Sender : TFPGtkObject; Data : Pointer); begin FCurrentElement:=Nil; FCurrentModule:=Nil; FCurrentTopic:=Nil; FCurrentPackage:=TDomElement(Data); If Assigned(FOnSelectPackage) then FOnSelectPackage(Self,FCurrentPackage); end; Procedure TPackageEditor.SelectTopic(Sender : TFPGtkObject; Data : Pointer); Var P : TDomElement; begin FCurrentTopic:=TDomElement(Data); P:=FCurrentTopic.ParentNode as TDomElement; if P.NodeName='module' then CurrentModule:=P else if P.NodeName='topic' then CurrentPackage:=P.ParentNode as TDomElement else if P.NodeName='package' then CurrentPackage:=p else Raise Exception.CreateFmt(SErrUnknownDomElement,[P.NodeName]); If Assigned(FOnSelectTopic) then FOnSelectPackage(Self,FCurrentTopic); end; Function TPackageEditor.GetSelectedNode : TNodeTreeItem; Var G : TFPgtkGroup; begin G:=TFPgtkGroup.Create; try FModuleTree.Tree.GetSelection(G); If G.Count>0 then try Result:=TObject(G[0]) as TNodeTreeItem; except Result:=Nil; end else Result:=Nil; finally G.Free; end; // Writeln('Getselectednode done'); end; Procedure TPackageEditor.MenuRenameClick(Sender : TFPGtkObject; Data : Pointer); Var N : TNodeTreeItem; E : TDomElement; begin N:=PMNode; If (N<>Nil) then If N.Node.NodeName='package' then RenamePackage(N) Else if N.Node.NodeName='module' then RenameModule(N) Else if N.Node.NodeName='topic' then RenameTopic(N) else if N.Node.NodeName='element' then RenameElement(N) end; Procedure TPackageEditor.MenuDeleteClick(Sender : TFPGtkObject; Data : Pointer); Var N : TNodeTreeItem; E : TDomElement; begin N:=PMNode; If (N<>Nil) then If N.Node.NodeName='package' then DeletePackage(N) Else if N.Node.NodeName='module' then DeleteModule(N) Else if N.Node.NodeName='topic' then DeleteTopic(N) else if N.Node.NodeName='element' then DeleteElement(N); end; Procedure TPackageEditor.DeletePackage(N : TNodeTreeItem); begin If (Not ConfirmDelete) or (MessageDlg(SDeletePackage,[N.Node['name']],mtConfirmation,mbYesNo,0)=mrYes) then begin N.Node.ParentNode.RemoveChild(N.Node); Refresh; FModified:=True; end; end; Procedure TPackageEditor.DeleteModule(N : TNodeTreeItem); begin If (Not ConfirmDelete) or (MessageDlg(SDeleteModule,[N.Node['name']],mtConfirmation,mbYesNo,0)=mrYes) then begin N.Node.ParentNode.RemoveChild(N.Node); Refresh; FModified:=True; end; end; Procedure TPackageEditor.DeleteTopic(N : TNodeTreeItem); begin If (Not ConfirmDelete) or (MessageDlg(SDeleteTopic,[N.Node['name']],mtConfirmation,mbYesNo,0)=mrYes) then begin N.Node.ParentNode.RemoveChild(N.Node); Refresh; FModified:=True; end; end; Procedure TPackageEditor.GetNameData(Sender : TFPGtkWindow;Data : Pointer; Action : Integer;Initiator : TFPGtkObject); type PString = ^AnsiString; begin With (Sender as TNewNodeForm) do PString(Data)^:=FENodeName.Text; end; Function TPackageEditor.NewName(ATitle : String;Var AName : String) : Boolean; Var S : String; begin With TNewNodeForm.Create do begin Title:=ATitle; FENodeName.Text:=AName; Result:=Execute(Nil,@S,@GetNameData)=drOK; If Result Then AName:=S; end; end; Procedure TPackageEditor.RenamePackage(N : TNodeTreeItem); Var S : String; begin S:=N.Node['name']; If NewName(SRenamePackage,S) then begin N.Node['name']:=S; N.Text:=S; FModified:=True; end; end; Procedure TPackageEditor.RenameModule(N : TNodeTreeItem); Var S : String; begin S:=N.Node['name']; If NewName(SRenameModule,S) then begin N.Node['name']:=S; N.Text:=S; FModified:=True; end; end; Procedure TPackageEditor.RenameTopic(N : TNodeTreeItem); Var S : String; begin S:=N.Node['name']; If NewName(SRenameTopic,S) then begin N.Node['name']:=S; N.Text:=S; FModified:=True; end; end; Procedure TPackageEditor.RenameElement(N : TNodeTreeItem); Var S : String; begin S:=N.Node['name']; If NewName(SRenameElement,S) then begin N.Node['name']:=S; N.Text:=S; FModified:=True; end; end; Procedure TPackageEditor.SelectElement (Sender : TFPGtkObject; Data : Pointer); begin FCurrentElement:=TDomElement(Data); If Assigned(FOnSelectElement) then FOnSelectElement(Self,FCurrentElement); end; { Procedure TPackageEditor.DeSelectElement(Sender : TFPGtkWidget; Data : Pointer); Var M : TDomElement; begin // Writeln('In Deselectelement'); M:=TDomElement(Data); If Assigned(FOnDeSelectElement) then FOnDeSelectElement(Self,M); end; } Function TPackageEditor.CreateElementNode(E : TDomelement) : TNodeTreeItem; begin Result:=TNodeTreeItem.Create(E); Result.ConnectSelect(@SelectElement,E); if (E.NodeName='element') then Result.ConnectButtonPressEvent(@PopupModuleMenu,Nil); // Result.ConnectDeselect(@DeselectElement,E); end; Procedure TPackageEditor.DeleteElement(N : TNodeTreeItem); Var Reposition : Boolean; Index : Integer; begin Reposition:=(N.Node=CurrentElement); With (FModuleNode.Subtree as TFPgtkTree) do begin Index:=ChildPosition(N); Remove(N); FModified:=True; If Reposition then SelectItem(Index); end; end; Procedure TPackageEditor.DeleteElement(E : TDomElement); Var N : TNodeTreeItem; begin N:=FindElementNode(E,Nil); If (N<>Nil) then DeleteElement(N); end; Procedure TPackageEditor.DeletePackage(P : TDomElement); Var N : TNodeTreeItem; begin N:=FindPackageNode(P); If N<>NIl then DeletePackage(N); end; Procedure TPackageEditor.DeleteModule(M : TDomElement); Var N : TNodeTreeItem; begin N:=FindModuleNodeInNode(M,Nil); If N<>NIl then DeleteModule(N); end; Procedure TPackageEditor.DeleteTopic(T : TDomElement); Var N : TNodeTreeItem; begin N:=FindTopicNodeInNode(T,Nil); If N<>NIl then DeleteTopic(N); end; Procedure TPackageEditor.RenamePackage(P : TDomElement); Var N : TNodeTreeItem; begin N:=FindPackageNode(P); If N<>NIl then RenamePackage(N); end; Procedure TPackageEditor.RenameModule(M : TDomElement); Var N : TNodeTreeItem; begin N:=FindModuleNodeInNode(M,Nil); If N<>NIl then RenameModule(N); end; Procedure TPackageEditor.RenameTopic(T : TDomElement); Var N : TNodeTreeItem; begin N:=FindTopicNodeInNode(T,Nil); If N<>NIl then RenameTopic(N); end; Procedure TPackageEditor.RenameElement(E : TDomElement); Var N : TNodeTreeItem; begin N:=FindElementNode(E,Nil); If N<>NIl then RenameElement(N); end; Procedure TPackageEditor.ClearElements; begin FElementTree.Tree.ClearItems(0,-1); end; Procedure TPackageEditor.ShowModuleElements(Module : TDomElement); Var Node : TDomNode; ETreeNode : TNodeTreeItem; S : TStringList; I : Integer; begin ClearElements; If Assigned(Module) then begin FModuleNode:=CreateElementNode(Module); FElementTree.Tree.Append(FModuleNode); FModuleNode.Show; FModuleNode.SubTree:=TFPGtkTree.Create; S:=TStringList.Create; Try S.Sorted:=True; Node:=Module.FirstChild; While Assigned(Node) do begin If (Node.NodeType=ELEMENT_NODE) and (Node.NodeName='element') then begin ETreeNode:=CreateElementNode(TDomElement(Node)); S.AddObject(TDomElement(Node)['name'],ETreeNode); end; Node:=Node.NextSibling; end; For I:=0 to S.Count-1 do begin ETreeNode:=TNodeTreeItem(S.Objects[i]); (FModuleNode.SubTree as TFPgtKTree).Append(ETreeNode); //ETreeNode.Show; end; Finally S.Free; end; FModuleNode.Expand; // NOT (!!) FModuleNode.Select; this cannot be undone... FElementTree.Tree.SelectChild(FModuleNode); end; FelementTree.Tree.SelectionMode:=GTK_SELECTION_BROWSE; end; Procedure TPackageEditor.Refresh; Procedure DoTopicNode(Node : TDomElement;Parent : TNodeTreeItem); Var TTreeNode : TTopicTreeItem; SubNode : TDomNode; begin TTreeNode:=TTopicTreeItem.Create(TDomElement(Node)); TTreeNode.ConnectSelect(@SelectTopic,Node); TTreeNode.ConnectButtonPressEvent(@PopupTopicMenu,Nil); Parent.CheckSubtree; TFPGtkTree(Parent.SubTree).Append(TTreeNode); TTreeNode.Show; SubNode:=Node.FirstChild; While (SubNode<>Nil) do begin If (SubNode.NodeType=ELEMENT_NODE) and (SubNode.NodeName='topic') then DoTopicNode(SubNode as TDomElement,TtreeNode); SubNode:=SubNode.NextSibling; end; end; var Node,SubNode,SSnode : TDomNode; FTreeNode : TPackageTreeItem; MTreeNode: TModuleTreeItem; begin FModuleTree.Tree.ClearItems(0,-1); If Assigned(FDescriptionNode) then begin Node:=FDescriptionNode.FirstChild; While Assigned(Node) do begin If (Node.NodeType=ELEMENT_NODE) and (Node.NodeName='package') then begin FTreeNode:=TPackageTreeItem.Create(TDomElement(Node)); FTreeNode.ConnectSelect(@Selectpackage,Node); FTreeNode.ConnectButtonPressEvent(@PopupModuleMenu,Nil); FModuleTree.Tree.Append(FTreeNode); FTreeNode.Show; SubNode:=Node.FirstChild; While Assigned(SubNode) do begin If (SubNode.NodeType=ELEMENT_NODE) and (SubNode.NodeName='module') then begin MTreeNode:=TModuleTreeItem.Create(TDomElement(SubNode)); MtreeNode.ConnectSelect(@SelectModule,SubNode); MTreeNode.ConnectButtonPressEvent(@PopupModuleMenu,Nil); FTreeNode.CheckSubtree; TFPGtkTree(FTreeNode.SubTree).Append(MTreeNode); //MTreeNode.Show; SSNode:=SubNode.FirstChild; While (SSNode<>Nil) do begin if (SSNode.NodeType=ELEMENT_NODE) and (SSNode.NodeName='topic') then DoTopicNode(SSNode as TDomElement,MTreeNode); SSNode:=SSNode.NextSibling; end; end else if (SubNode.NodeType=ELEMENT_NODE) and (SubNode.NodeName='topic') then begin DoTopicNode(SubNode as TDomElement,FTreeNode); end; SubNode:=SubNode.NextSibling; end; end; Node:=Node.NextSibling; end; end; CurrentModule:=Nil; FModified:=False; end; Function TPackageEditor.FindPackageNode(P : TDomElement) : TNodeTreeItem; Var N : TNodeTreeItem; G : TFPgtkWidgetGroup; I : Integer; begin Result:=Nil; G:=FModuleTree.Tree.Children; I:=0; While (Result=Nil) and (INil) then SN:=N else SN:=FindPackageNode(M.ParentNode as TDomElement); If Assigned(SN) and Assigned(SN.SubTree) Then begin G:=(SN.SubTree as TFpGtkTree).Children; I:=0; While (Result=Nil) and (INil) then SN:=N else begin E:=M.ParentNode as TDomElement; PN:=(E.NodeName); if PN='module' then SN:=FindModuleNodeInNode(E,FindPackageNode(E.ParentNode as TDomElement)) else if PN='topic' then // Assumes that we can only nest 2 deep inside package node. SN:=FindTopicNodeInNode(E,FindPackageNode(E.ParentNode as TDomElement)) else if (PN='package') then SN:=FindPackageNode(E); end; If Assigned(SN) and Assigned(SN.SubTree) Then begin G:=(SN.SubTree as TFpGtkTree).Children; I:=0; While (Result=Nil) and (INil) then SN:=N else SN:=FModuleNode; // FindModuleNodeInNode(E.ParentNode as TDomElement,Nil); If E.NodeName='module' then Result:=FModuleNode else If Assigned(SN) and Assigned(SN.SubTree) Then begin G:=(SN.SubTree as TFpGtkTree).Children; I:=0; While (Result=Nil) and (IFCurrentElement) then begin If Assigned(FCurrentElement) then begin N:=FindElementNode(FCurrentElement,Nil); If Assigned(N) then N.Deselect; end; CurrentModule:=E.ParentNode as TDomElement; N:=FindElementNode(E,Nil); if Assigned(N) then With (FModuleNode.Subtree as TFPgtkTree) do SelectChild(N); end; end; Procedure TPackageEditor.SetCurrentModule(Value : TDomElement); Var N1,N2 : TNodeTreeItem; begin If (FCurrentModule<>Value) then begin FCurrentModule:=Value; If Assigned(Value) then begin FCurrentPackage:=Value.ParentNode as TDomElement; N1:=FindPackageNode(FCurrentPackage); N1.Expand; N2:=FindModuleNodeInNode(FCurrentModule,N1); (N1.SubTree as TFPgtkTree).SelectChild(N2); end Else ClearElements; end; end; Procedure TPackageEditor.SetCurrentTopic(T : TDomElement); Var N : TDomElement; PI,NI : TNodeTreeItem; begin If (FCurrentTopic<>T) then begin FCurrentElement:=Nil; FCurrentTopic:=T; If Assigned(T) then begin // Writeln('clearing current element'); If (CurrentElement<>Nil) then CurrentElement:=Nil; // Writeln('checking parent node'); N:=T.ParentNode as TDomElement; If N.NodeName='topic' then begin // Writeln('Parent is topic'); N:=N.ParentNode as TDomElement; PI:=FindTopicNodeInNode(N,Nil); end; if N.NodeName='module' then begin // Writeln('Parent is module'); CurrentModule:=N; N:=N.ParentNode as TDomElement; PI:=FindModuleNodeInNode(N,Nil); end else if N.NodeName='package' then begin // Writeln('Parent is package ?'); CurrentModule:=Nil; CurrentPackage:=N; PI:=FindPackageNode(N) end { else Writeln('Unknown parent node')} ; NI:=FindTopicNodeInNode(T,PI); If Assigned(PI) then begin // Writeln('Expanding parent node'); PI.Expand; If Assigned(PI.Subtree) and Assigned(NI) then begin // Writeln('Selecting subnode'); (PI.SubTree as TFPgtkTree).SelectChild(NI); end; end; end; end; end; Procedure TPackageEditor.SetCurrentPackage(Value : TDomElement); Var N : TNodeTreeItem; begin FCurrentPackage:=Value; N:=FindPackageNode(Value); N.Expand; N.Select; end; { --------------------------------------------------------------------- TPageEditor ---------------------------------------------------------------------} Constructor TEditorPage.Create; begin Inherited Create; FPackages:=TPackageEditor.Create; FElement:=TElementEditor.Create; // Fpackages.OnSelectionChanged:=@SelectionChanged; FPackages.OnSelectElement:=@ElementSelected; FPackages.OnSelectModule:=@ModuleSelected; FPackages.OnSelectPackage:=@PackageSelected; FPackages.OnSelectTopic:=@TopicSelected; // FPackages.OnDeselectElement:=@ElementDeSelected; Add1(FPackages); Add2(FElement); end; Procedure TEditorPage.ClearDocument; begin if (FDocument<>nil) then begin FDocument.Free; FDocument:=Nil; end; end; Procedure TEditorPage.LoadFromFile(FN : String); Var F : TFileStream; begin ClearDocument; F:=TFileStream.Create(FN,fmOpenRead); Try SetFileName(FN); ReadXMLFile(FDocument,F); DisplayDocument; finally F.Free; end; end; Procedure TEditorPage.LoadFromStream(S : TStream); begin ClearDocument; ReadXMLFile(FDocument,S); SetFileName(SNewDocument); DisplayDocument; end; Procedure TEditorPage.SetFileName(FN : String); begin FFileName:=FN; FFileNameLabel.Text:=ChangeFileExt(ExtractFileName(FN),''); end; Function TEditorPage.MakeBackup(FN : String) : Boolean; Var BN : String; begin Result:=Not CreateBackup; If not Result then begin BN:=ChangeFileExt(FN,BackupExtension); Result:=RenameFile(FN,BN); end; end; Procedure TEditorPage.SaveToFile(FN : String); begin If FElement.Modified then FElement.Save; If (not FileExists(FN)) or MakeBackup(FN) then begin WriteXMLFile(FDocument,FN); if (FN<>FFileName) then SetFileName(FN); end; end; Procedure TEditorPage.DisplayDocument; begin FPackages.DescriptionNode:=FDocument.DocumentElement; end; { Procedure TEditorPage.SelectionChanged(Sender : TFPgtkWidget; Node : TDomElement) ; //Procedure TEditorPage.SelectionChanged(Sender : TObject; Node : TDomElement) ; Var OldNode : TDomElement; begin If Not FChangingSelection then begin FChangingSelection:=True; Try OldNode:=FElement.Element; If (OldNode<>Node) then begin FElement.Element:=Node; { if the switch didn't succeed, it means that something went wrong when saving the old node, so we reselect the old node. } If FElement.Element<>Node then begin FPackages.CurrentElement:=OldNode; end; end; Finally FChangingSelection:=False; end; end; end; } Procedure TEditorPage.ElementSelected(Sender : TObject; Node : TDomElement) ; Var OldNode : TDomElement; begin // Writeln('In ElementSelected'); OldNode:=FElement.Element; If OldNode<>Node then begin FElement.Element:=Node; { if the switch didn't succeed, it means that something went wrong when saving the old node, so we reselect the old node. } { If FElement.Element<>Node then FPackages.CurrentElement:=OldNode; } end; end; Procedure TEditorPage.PackageSelected(Sender : TObject; Node : TDomElement) ; begin ElementSelected(Sender,Node); end; Procedure TEditorPage.ModuleSelected(Sender : TObject; Node : TDomElement) ; begin ElementSelected(Sender,Node); end; Procedure TEditorPage.TopicSelected(Sender : TObject; Node : TDomElement) ; begin ElementSelected(Sender,Node); end; { Procedure TEditorPage.ElementDeselected(Sender : TObject; Node : TDomElement) ; begin With FElement do If Modified then Save; end; } Procedure TEditorPage.InsertTag(TagType : TTagType); begin FElement.InsertTag(TagType) end; Procedure TEditorPage.InsertLink(LinkTarget,LinkText : String); begin FElement.InsertLink(LinkTarget,LinkText); end; Procedure TEditorPage.InsertTable(Cols,Rows : Integer; UseHeader : Boolean); begin Felement.InsertTable(Cols,Rows,UseHeader); end; Function TEditorPage.GetCurrentSelection : String; begin Result:=FElement.CurrentSelection; end; Procedure TEditorPage.NewPackage(APackageName : String); Var P : TDomElement; begin P:=FDocument.CreateElement('package'); P['name']:=APAckageName; FDocument.DocumentElement.AppendChild(P); FPackages.Refresh; FPackages.FModified:=True; CurrentPackage:=P; end; Function TEditorPage.FirstPackage : TDomElement; Var N : TDomNode; begin N:=FDocument.DocumentElement.FirstChild; While (N<>Nil) and Not ((N.NodeType=ELEMENT_NODE) and (N.NodeName='package')) do N:=N.NextSibling; Result:=TDomElement(N); end; Function TEditorPage.FirstModule(APackage : TDomElement) : TDomElement; Var N : TDomNode; begin N:=APAckage.FirstChild; While (N<>Nil) and Not ((N.NodeType=ELEMENT_NODE) and (N.NodeName='module')) do N:=N.NextSibling; Result:=TDomElement(N); end; Procedure TEditorPage.NewModule(AModuleName : String); Var M,P : TDomElement; begin If CurrentPackage<>Nil then P:=CurrentPackage else P:=FirstPackage; If (P=Nil) then Raise Exception.CreateFmt(SErrNoPackageForModule,[AModuleName]); M:=FDocument.CreateElement('module'); M['name']:=AModuleName; P.AppendChild(M); FPackages.Refresh; FPackages.FModified:=True; CurrentModule:=M; end; Procedure TEditorPage.NewTopic(ATopicName : String); Var T,M,P : TDomElement; begin { If currently a topic is selected, make a subtopic, or a sibling topic. If no topic is selected, then make a topic under the current module or package. A menu to move topics up/down is needed... } if (CurrentTopic<>Nil) then begin M:=CurrentTopic.ParentNode as TDomElement; If M.NodeName='module' then P:=M else if M.NodeName='topic' then P:=M else P:=CurrentTopic; // Writeln('Parent topic is ',P.NodeName) end else if (CurrentModule<>Nil) then P:=CurrentModule else if (CurrentPackage<>Nil) then P:=CurrentPackage else P:=FirstPackage; If (P=Nil) then Raise Exception.CreateFmt(SErrNoNodeForTopic,[ATopicName]); // Writeln('Parent node : ',P.NodeName); T:=FDocument.CreateElement('topic'); T['name']:=ATopicName; P.AppendChild(T); // Writeln('Refreshing tree'); FPackages.Refresh; FPackages.FModified:=True; // Writeln('Setting current topic'); CurrentTopic:=T; end; Procedure TEditorPage.NewElement(AElementName : String); Var P,E,M : TDomElement; N : TDomNode; begin If CurrentModule<>Nil then M:=CurrentModule else begin P:=FirstPackage; If P<>Nil then M:=FirstModule(P) else M:=Nil; If M<>Nil then CurrentModule:=M; end; If (M=Nil) then Raise Exception.CreateFmt(SErrNoModuleForElement,[AElementName]); E:=FDocument.CreateElement('element'); E['name']:=AElementName; M.AppendChild(E); FPackages.AddElement(E); end; Function TEditorPage.GetCurrentPackage : TDomElement; begin Result:=FPackages.CurrentPackage; end; Function TEditorPage.GetCurrentModule : TDomElement; begin Result:=FPackages.CurrentModule; end; Function TEditorPage.GetCurrentTopic : TDomElement; begin Result:=FPackages.CurrentTopic; end; Function TEditorPage.GetCurrentElement : TDomElement; begin Result:=FElement.Element; end; Procedure TEditorPage.SetCurrentElement(Value : TDomElement); begin FPackages.CurrentElement:=Value; end; Procedure TEditorPage.SetCurrentModule(Value : TDomElement); begin FPackages.CurrentModule:=Value; end; Procedure TEditorPage.SetCurrentTopic(Value : TDomElement); begin FPackages.CurrentTopic:=Value; end; Procedure TEditorPage.SetCurrentPackage(Value : TDomElement); begin FPackages.CurrentPackage:=Value; end; Procedure TEditorPage.SetModified(Value : Boolean); begin end; Function TEditorPage.GetModified : Boolean; begin Result:=FPackages.Modified or FElement.Modified; end; Procedure TEditorPage.GetElementList(List : TStrings); Var N : TDOmNode; begin With List do begin Clear; If Assigned(CurrentModule) then begin N:=Currentmodule.FirstChild; While (N<>Nil) do begin If (N is TDomElement) and (N.NodeName='element') then Add(TDomElement(N)['name']); N:=N.NextSibling; end; end; end; end; end.