1 {
2  ***************************************************************************
3  *                                                                         *
4  *   This source is free software; you can redistribute it and/or modify   *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This code is distributed in the hope that it will be useful, but      *
10  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
12  *   General Public License for more details.                              *
13  *                                                                         *
14  *   A copy of the GNU General Public License is available on the World    *
15  *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
16  *   obtain it by writing to the Free Software Foundation,                 *
17  *   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.   *
18  *                                                                         *
19  ***************************************************************************
20 
21   Author: Mattias Gaertner
22 
23   Abstract:
24     Editor dialog to edit nodes of Help for IDE windows (controls).
25 }
26 {%RunCommand bb$MakeExe($(EdFile))}
27 unit IDEContextHelpEdit;
28 
29 {$mode objfpc}{$H+}
30 
31 interface
32 
33 uses
34   Classes, SysUtils, LCLProc, Forms, Controls, Graphics, Dialogs,
35   Buttons, ButtonPanel, StdCtrls, ComCtrls,
36   // codetools
37   CodeToolManager, CodeCache,
38   // IDEIntf
39   PropEdits, LazIDEIntf, IDEWindowIntf, IDEDialogs,
40   // IDE
41   IDEWindowHelp, LazarusIDEStrConsts, ExtCtrls;
42 
43 type
44 
45   { TOpenIDEFileOnIdle }
46 
47   TOpenIDEFileOnIdle = class(TComponent)
48   protected
49     procedure Notification(AComponent: TComponent; Operation: TOperation);
50       override;
51   public
52     Filename: string;
53     X, Y: integer;
54     CloseDialogs: TFPList; // list of modal TCustomForm to cancel
55     CancelDialogs: TFPList; // list of modal TCustomForm tried to cancel
56     Ending: boolean;
57     constructor Create(AOwner: TComponent); override;
58     procedure Run;
59     destructor Destroy; override;
60     procedure OnIdle(Sender: TObject; var {%H-}Done: Boolean);
61   end;
62 
63 
64   { TContextHelpEditorDlg }
65 
66   TContextHelpEditorDlg = class(TForm)
67     ButtonPanel: TButtonPanel;
68     FullPathEdit: TEdit;
69     NodeIsRootCheckBox: TCheckBox;
70     OpenDeclarationBitBtn: TBitBtn;
71     TestButton: TButton;
72     CreateHelpNodeForControlButton: TButton;
73     NodeNameEdit: TEdit;
74     NodePathEdit: TEdit;
75     NodeHasHelpCheckBox: TCheckBox;
76     HelpNodePropertiesGroupBox: TGroupBox;
77     NodePathLabel: TLabel;
78     NodeNameLabel: TLabel;
79     NodesGroupBox: TGroupBox;
80     ControlsTreeView: TTreeView;
81     HelpNodesTreeView: TTreeView;
82     Splitter1: TSplitter;
83     WindowControlsGroupBox: TGroupBox;
84     procedure ControlsTreeViewShowHint(Sender: TObject; HintInfo: PHintInfo);
85     procedure CreateHelpNodeForControlButtonClick(Sender: TObject);
86     procedure FormClose(Sender: TObject; var {%H-}CloseAction: TCloseAction);
87     procedure FormCreate(Sender: TObject);
88     procedure FormDestroy(Sender: TObject);
89     procedure HelpNodesTreeViewSelectionChanged(Sender: TObject);
90     procedure NodeHasHelpCheckBoxEditingDone(Sender: TObject);
91     procedure NodeIsRootCheckBoxEditingDone(Sender: TObject);
92     procedure NodeNameEditEditingDone(Sender: TObject);
93     procedure NodePathEditEditingDone(Sender: TObject);
94     procedure OkBitBtnClick(Sender: TObject);
95     procedure OpenDeclarationBitBtnClick(Sender: TObject);
96     procedure OpenDeclarationBitBtnShowHint(Sender: TObject; HintInfo: PHintInfo);
97     procedure TestButtonClick(Sender: TObject);
98   private
99     FIDEWindow: TCustomForm;
100     FInvoker: TObject;
101     FWorkingHelpNodes: TIWHelpTree;
102     fLoading: boolean;
103     procedure SetIDEWindow(const AValue: TCustomForm);
104     procedure SetInvoker(const AValue: TObject);
105     procedure UpdateWindowControlsGroupBoxCaption;
106     procedure FillControlsTreeView;
107     procedure FillHelpNodesTreeView;
108     procedure UpdateHelpNodePropertiesGroupBox;
109     procedure SelectHelpNode(AControl: TControl);
110     procedure SelectControlNode(AControl: TControl);
FindHelpTreeNodenull111     function FindHelpTreeNode(HelpNode: TIWHelpNode): TTreeNode;
FindControlTreeNodenull112     function FindControlTreeNode(AControl: TControl): TTreeNode;
GetCurrentControlnull113     function GetCurrentControl: TControl;
GetCurrentHelpNodenull114     function GetCurrentHelpNode: TIWHelpNode;
115     procedure SaveHelpNodeProperties;
GetHintForControlnull116     function GetHintForControl(AControl: TControl): string;
117   public
118     property Invoker: TObject read FInvoker write SetInvoker;
119     property IDEWindow: TCustomForm read FIDEWindow write SetIDEWindow;
120     property WorkingHelpNodes: TIWHelpTree read FWorkingHelpNodes;
121   end;
122 
123 var
124   ContextHelpEditorDlg: TContextHelpEditorDlg = nil;
125 
ShowContextHelpEditornull126 function ShowContextHelpEditor(Sender: TObject): TModalResult;
127 
FindDeclarationOfIDEControlnull128 function FindDeclarationOfIDEControl(AControl: TControl; out Filename: string;
129                                      out X, Y: integer): boolean;
130 
131 implementation
132 
133 {$R *.lfm}
134 
ShowContextHelpEditornull135 function ShowContextHelpEditor(Sender: TObject): TModalResult;
136 begin
137   // make sure there is only one editor at a time
138   if ContextHelpEditorDlg<>nil then exit;
139 
140   ContextHelpEditorDlg:=TContextHelpEditorDlg.Create(nil);
141   try
142     ContextHelpEditorDlg.Invoker:=Sender;
143     Result:=ContextHelpEditorDlg.ShowModal;
144   finally
145     ContextHelpEditorDlg.Free;
146     ContextHelpEditorDlg:=nil;
147   end;
148 end;
149 
FindDeclarationOfIDEControlnull150 function FindDeclarationOfIDEControl(AControl: TControl; out Filename: string;
151   out X, Y: integer): boolean;
152 var
153   UnitControl: TControl;
154   FormFilename: String;
155   Code: TCodeBuffer;
156   TopLine: integer;
157   NewCode: TCodeBuffer;
158   Path: String;
159   AComponent: TComponent;
160 begin
161   Result:=false;
162   Filename:='';
163   Y:=0;
164   X:=0;
165   if AControl=nil then exit;
166   UnitControl:=AControl;
167   while (UnitControl<>nil) do begin
168     if (UnitControl is TFrame) or (UnitControl is TCustomForm) then break;
169     UnitControl:=UnitControl.Parent;
170   end;
171   if UnitControl=nil then begin
172     debugln(['FindDeclarationOfIDEControl control '+DbgSName(AControl)+' is not on a form/frame']);
173     exit;
174   end;
175   //debugln(['FindDeclarationOfIDEControl UnitControl=',DbgSName(UnitControl),' Unitname=',UnitControl.UnitName]);
176   FormFilename:=LazarusIDE.FindUnitFile(GetClassUnitName(UnitControl.ClassType),LazarusIDE);
177   //debugln(['FindDeclarationOfIDEControl FormFilename=',FormFilename]);
178   if FormFilename='' then begin
179     debugln(['FindDeclarationOfIDEControl UnitControl=',DbgSName(UnitControl),' Unitname=',GetClassUnitName(UnitControl.ClassType),': unit source not found']);
180     exit;
181   end;
182   Code:=CodeToolBoss.LoadFile(FormFilename,true,false);
183   if Code=nil then begin
184     debugln(['FindDeclarationOfIDEControl unable to open file: '+FormFilename]);
185     exit;
186   end;
187 
188   Path:='';
189   AComponent:=AControl;
190   while (AComponent<>nil) and (AComponent<>UnitControl) do begin
191     Path:='.'+AComponent.Name+Path;
192     AComponent:=AComponent.Owner;
193   end;
194   Path:=UnitControl.ClassName+Path;
195   if not CodeToolBoss.FindDeclarationOfPropertyPath(Code,Path,NewCode,X,Y,TopLine)
196   then begin
197     debugln(['FindDeclarationOfIDEControl path ',Path,' not found in unit ',Code.Filename]);
198     exit;
199   end;
200   Filename:=NewCode.Filename;
201   // success
202   Result:=true;
203 end;
204 
205 { TContextHelpEditorDlg }
206 
207 procedure TContextHelpEditorDlg.FormClose(Sender: TObject;
208   var CloseAction: TCloseAction);
209 begin
210   IDEDialogLayoutList.SaveLayout(Self);
211 end;
212 
213 procedure TContextHelpEditorDlg.CreateHelpNodeForControlButtonClick(
214   Sender: TObject);
215 var
216   AControl: TControl;
217 begin
218   AControl:=GetCurrentControl;
219   if AControl=nil then exit;
220   WorkingHelpNodes.FindNodeForControl(AControl,true);
221   FillHelpNodesTreeView;
222   SelectHelpNode(AControl);
223   SelectControlNode(AControl);
224 end;
225 
226 procedure TContextHelpEditorDlg.ControlsTreeViewShowHint(Sender: TObject;
227   HintInfo: PHintInfo);
228 var
229   Node: TTreeNode;
230 begin
231   Node:=ControlsTreeView.GetNodeAt(HintInfo^.CursorPos.X,HintInfo^.CursorPos.Y);
232   if Node=nil then exit;
233   HintInfo^.HintStr:=GetHintForControl(TControl(Node.Data));
234 end;
235 
236 procedure TContextHelpEditorDlg.FormCreate(Sender: TObject);
237 begin
238   Caption:=lisEditContextHelp;
239 
240   TestButton.Caption:=dlgCCOTest;
241   CreateHelpNodeForControlButton.Caption:=lisCreateHelpNode;
242   OpenDeclarationBitBtn.Caption:=lisDlgOpen;
243   OpenDeclarationBitBtn.OnShowHint:=@OpenDeclarationBitBtnShowHint;
244   NodeHasHelpCheckBox.Caption:=lisHasHelp;
245   NodeIsRootCheckBox.Caption:=lisCEIsARootControl;
246   NodePathLabel.Caption:=lisPath;
247   NodeNameLabel.Caption:=lisName;
248   NodesGroupBox.Caption:=lisHelpEntries;
249 
250   ButtonPanel.OKButton.OnClick:=@OkBitBtnClick;
251 
252   IDEDialogLayoutList.ApplyLayout(Self, 600, 450);
253 
254   LoadIDEWindowHelp;
255   FWorkingHelpNodes:=TIWHelpTree.Create;
256   FWorkingHelpNodes.Assign(IDEWindowHelpNodes);
257   FillHelpNodesTreeView;
258 end;
259 
260 procedure TContextHelpEditorDlg.FormDestroy(Sender: TObject);
261 begin
262   FreeAndNil(FWorkingHelpNodes);
263 end;
264 
265 procedure TContextHelpEditorDlg.HelpNodesTreeViewSelectionChanged(
266   Sender: TObject);
267 begin
268   UpdateHelpNodePropertiesGroupBox;
269 end;
270 
271 procedure TContextHelpEditorDlg.NodeHasHelpCheckBoxEditingDone(Sender: TObject);
272 begin
273   SaveHelpNodeProperties;
274 end;
275 
276 procedure TContextHelpEditorDlg.NodeIsRootCheckBoxEditingDone(Sender: TObject);
277 begin
278   SaveHelpNodeProperties;
279 end;
280 
281 procedure TContextHelpEditorDlg.NodeNameEditEditingDone(Sender: TObject);
282 begin
283   SaveHelpNodeProperties;
284 end;
285 
286 procedure TContextHelpEditorDlg.NodePathEditEditingDone(Sender: TObject);
287 begin
288   SaveHelpNodeProperties;
289 end;
290 
291 procedure TContextHelpEditorDlg.OkBitBtnClick(Sender: TObject);
292 begin
293   WorkingHelpNodes.DeleteLeavesWithoutHelp;
294   IDEWindowHelpNodes.Assign(WorkingHelpNodes);
295   SaveIDEWindowHelp;
296   ModalResult:=mrOk;
297 end;
298 
299 procedure TContextHelpEditorDlg.OpenDeclarationBitBtnClick(Sender: TObject);
300 var
301   AControl: TControl;
302   Closer: TOpenIDEFileOnIdle;
303   Filename: string;
304   X: integer;
305   Y: integer;
306 begin
307   AControl:=GetCurrentControl;
308   if AControl=nil then begin
309     IDEMessageDialog('Error','Please select a control first',mtError,[mbCancel]);
310     exit;
311   end;
312   if not FindDeclarationOfIDEControl(AControl,Filename,X,Y) then begin
313     IDEMessageDialog('Error','No declaration found for '+DbgSName(AControl),mtError,[mbCancel]);
314     exit;
315   end;
316   if IDEMessageDialog('Close dialogs?','This will close all currently open modal forms and open the file '+Filename+' in the editor.',
317     mtConfirmation,[mbOk,mbCancel])<>mrOk then exit;
318   Closer:=TOpenIDEFileOnIdle.Create(LazarusIDE.OwningComponent);
319   Closer.Filename:=Filename;
320   Closer.X:=X;
321   Closer.Y:=Y;
322   Closer.Run;
323 end;
324 
325 procedure TContextHelpEditorDlg.OpenDeclarationBitBtnShowHint(Sender: TObject;
326   HintInfo: PHintInfo);
327 begin
328   HintInfo^.HintStr:='Open declaration '+GetHintForControl(GetCurrentControl);
329 end;
330 
331 procedure TContextHelpEditorDlg.TestButtonClick(Sender: TObject);
332 var
333   AControl: TControl;
334 begin
335   AControl:=GetCurrentControl;
336   if AControl=nil then exit;
337   WorkingHelpNodes.InvokeHelp(AControl);
338 end;
339 
340 procedure TContextHelpEditorDlg.SetInvoker(const AValue: TObject);
341 var
342   AControl: TControl;
343 begin
344   if FInvoker=AValue then exit;
345   FInvoker:=AValue;
346   //DebugLn('TContextHelpEditorDlg.SetInvoker Invoker=',dbgsName(Invoker));
347   if Invoker is TControl then begin
348     AControl:=TControl(Invoker);
349     IDEWindow:=GetParentForm(AControl);
350     //DebugLn('TContextHelpEditorDlg.SetInvoker IDEWindow=',dbgsName(IDEWindow));
351     WorkingHelpNodes.FindNodeForControl(AControl,true);
352     FillHelpNodesTreeView;
353     SelectHelpNode(AControl);
354     SelectControlNode(AControl);
355   end;
356 end;
357 
358 procedure TContextHelpEditorDlg.UpdateWindowControlsGroupBoxCaption;
359 begin
360   if IDEWindow<>nil then begin
361     WindowControlsGroupBox.Caption:=dbgsName(IDEWindow);
362     WindowControlsGroupBox.Enabled:=true;
363   end else begin
364     WindowControlsGroupBox.Caption:=lisNoIDEWindowSelected;
365     WindowControlsGroupBox.Enabled:=false;
366   end;
367 end;
368 
369 procedure TContextHelpEditorDlg.FillControlsTreeView;
370 
371   procedure Add(AControl: TControl; ParentNode: TTreeNode);
372   var
373     i: Integer;
374     NewNode: TTreeNode;
375   begin
376     NewNode:=ControlsTreeView.Items.AddChildObject(ParentNode,
377                                                    dbgsName(AControl),AControl);
378     if AControl is TWinControl then begin
379       for i:=0 to TWinControl(AControl).ControlCount-1 do
380         Add(TWinControl(AControl).Controls[i],NewNode);
381     end;
382     NewNode.Expanded:=true;
383   end;
384 
385 begin
386   ControlsTreeView.BeginUpdate;
387   ControlsTreeView.Items.Clear;
388   if IDEWindow<>nil then
389     Add(IDEWindow,nil);
390   ControlsTreeView.EndUpdate;
391 end;
392 
393 procedure TContextHelpEditorDlg.FillHelpNodesTreeView;
394 
395   procedure Add(HelpNode: TIWHelpNode; ParentNode: TTreeNode);
396   var
397     i: Integer;
398     NewNode: TTreeNode;
399   begin
400     NewNode:=HelpNodesTreeView.Items.AddChildObject(ParentNode,
401                                                    HelpNode.Name,HelpNode);
402     for i:=0 to HelpNode.Count-1 do
403       Add(HelpNode[i],NewNode);
404     NewNode.Expanded:=true;
405   end;
406 
407 begin
408   HelpNodesTreeView.BeginUpdate;
409   HelpNodesTreeView.Items.Clear;
410   Add(WorkingHelpNodes.Root,nil);
411   HelpNodesTreeView.EndUpdate;
412 end;
413 
414 procedure TContextHelpEditorDlg.UpdateHelpNodePropertiesGroupBox;
415 var
416   HelpNode: TIWHelpNode;
417 begin
418   if (csDestroying in ComponentState) then exit;
419   HelpNode:=GetCurrentHelpNode;
420   fLoading:=true;
421   try
422     if HelpNode<>nil then begin
423       HelpNodePropertiesGroupBox.Caption:=HelpNode.Name;
424       NodeNameEdit.Text:=HelpNode.Name;
425       NodePathEdit.Text:=HelpNode.Path;
426       NodeHasHelpCheckBox.Checked:=HelpNode.HasHelp;
427       NodeIsRootCheckBox.Checked:=HelpNode.IsRoot;
428       HelpNodePropertiesGroupBox.Enabled:=true;
429       FullPathEdit.Text:=HelpNode.GetFullPath;
430     end else begin
431       HelpNodePropertiesGroupBox.Caption:=lisNoNodeSelected;
432       HelpNodePropertiesGroupBox.Enabled:=false;
433     end;
434   finally
435     fLoading:=false;
436   end;
437 end;
438 
439 procedure TContextHelpEditorDlg.SelectHelpNode(AControl: TControl);
440 var
441   Node: TTreeNode;
442 begin
443   Node:=FindHelpTreeNode(WorkingHelpNodes.FindNodeForControl(AControl));
444   HelpNodesTreeView.Selected:=Node;
445   //DebugLn('TContextHelpEditorDlg.SelectHelpNode Node=',dbgs(Node),' AControl=',dbgsName(AControl),' ',dbgs(HelpNodesTreeView.Selected));
446 end;
447 
448 procedure TContextHelpEditorDlg.SelectControlNode(AControl: TControl);
449 var
450   Node: TTreeNode;
451 begin
452   Node:=FindControlTreeNode(AControl);
453   ControlsTreeView.Selected:=Node;
454 end;
455 
FindHelpTreeNodenull456 function TContextHelpEditorDlg.FindHelpTreeNode(HelpNode: TIWHelpNode): TTreeNode;
457 
Findnull458   function Find(HNode: TIWHelpNode): TTreeNode;
459   var
460     ParentTreeNode: TTreeNode;
461   begin
462     if HNode=nil then exit(nil);
463     if HNode.Parent=nil then begin
464       Result:=HelpNodesTreeView.Items.FindTopLvlNode(HNode.Name);
465     end else begin
466       ParentTreeNode:=Find(HNode.Parent);
467       if ParentTreeNode=nil then
468         Result:=nil
469       else
470         Result:=ParentTreeNode.FindNode(HNode.Name);
471     end;
472   end;
473 
474 begin
475   Result:=Find(HelpNode);
476 end;
477 
TContextHelpEditorDlg.FindControlTreeNodenull478 function TContextHelpEditorDlg.FindControlTreeNode(AControl: TControl): TTreeNode;
479 
Findnull480   function Find(TheControl: TControl): TTreeNode;
481   var
482     ParentTreeNode: TTreeNode;
483   begin
484     if TheControl=nil then exit(nil);
485     if TheControl.Parent=nil then begin
486       Result:=ControlsTreeView.Items.FindTopLvlNode(dbgsName(TheControl));
487     end else begin
488       ParentTreeNode:=Find(TheControl.Parent);
489       if ParentTreeNode=nil then
490         Result:=nil
491       else
492         Result:=ParentTreeNode.FindNode(dbgsName(TheControl));
493     end;
494   end;
495 
496 begin
497   Result:=Find(AControl);
498 end;
499 
GetCurrentControlnull500 function TContextHelpEditorDlg.GetCurrentControl: TControl;
501 var
502   Node: TTreeNode;
503 begin
504   Node:=ControlsTreeView.Selected;
505   if Node=nil then exit(nil);
506   Result:=TControl(Node.Data);
507 end;
508 
TContextHelpEditorDlg.GetCurrentHelpNodenull509 function TContextHelpEditorDlg.GetCurrentHelpNode: TIWHelpNode;
510 var
511   Node: TTreeNode;
512 begin
513   Node:=HelpNodesTreeView.Selected;
514   if Node=nil then exit(nil);
515   Result:=TIWHelpNode(Node.Data);
516 end;
517 
518 procedure TContextHelpEditorDlg.SaveHelpNodeProperties;
519 var
520   HelpNode: TIWHelpNode;
521 begin
522   if fLoading then exit;
523   HelpNode:=GetCurrentHelpNode;
524   if HelpNode=nil then exit;
525   HelpNode.Name:=NodeNameEdit.Text;
526   HelpNode.Path:=NodePathEdit.Text;
527   HelpNode.HasHelp:=NodeHasHelpCheckBox.Checked;
528   HelpNode.IsRoot:=NodeIsRootCheckBox.Checked;
529   FullPathEdit.Text:=HelpNode.GetFullPath;
530 end;
531 
GetHintForControlnull532 function TContextHelpEditorDlg.GetHintForControl(AControl: TControl): string;
533 var
534   X: integer;
535   Y: integer;
536   Filename: string;
537 begin
538   if not FindDeclarationOfIDEControl(AControl,Filename,X,Y) then
539     Result:='';
540   Result:=DbgSName(AControl)+': '+Filename+'('+IntToStr(Y)+','+IntToStr(X)+')';
541 end;
542 
543 procedure TContextHelpEditorDlg.SetIDEWindow(const AValue: TCustomForm);
544 begin
545   if FIDEWindow=AValue then exit;
546   FIDEWindow:=AValue;
547   UpdateWindowControlsGroupBoxCaption;
548   FillControlsTreeView;
549 end;
550 
551 { TOpenIDEFileOnIdle }
552 
553 procedure TOpenIDEFileOnIdle.Notification(AComponent: TComponent;
554   Operation: TOperation);
555 begin
556   inherited Notification(AComponent, Operation);
557   if Operation=opRemove then begin
558     CloseDialogs.Remove(AComponent);
559     CancelDialogs.Remove(AComponent);
560   end;
561 end;
562 
563 constructor TOpenIDEFileOnIdle.Create(AOwner: TComponent);
564 begin
565   inherited Create(AOwner);
566   CloseDialogs:=TFPList.Create;
567   CancelDialogs:=TFPList.Create;
568 end;
569 
570 procedure TOpenIDEFileOnIdle.Run;
571 var
572   i: Integer;
573   Form: TCustomForm;
574 begin
575   for i:=0 to Screen.CustomFormCount-1 do begin
576     Form:=Screen.CustomForms[i];
577     if (CloseDialogs.IndexOf(Form)<0) and (fsModal in Form.FormState) then
578     begin
579       FreeNotification(Form);
580       CloseDialogs.Add(Form);
581     end;
582   end;
583   Application.AddOnIdleHandler(@OnIdle);
584 end;
585 
586 destructor TOpenIDEFileOnIdle.Destroy;
587 begin
588   Application.RemoveOnIdleHandler(@OnIdle);
589   inherited Destroy;
590   FreeAndNil(CloseDialogs);
591   FreeAndNil(CancelDialogs);
592 end;
593 
594 procedure TOpenIDEFileOnIdle.OnIdle(Sender: TObject; var Done: Boolean);
595 var
596   i: Integer;
597   Form: TCustomForm;
598 begin
599   if Ending then exit;
600 
601   { For example:
602     User press ok:
603     - cancel the context help dialog
604     - cancel the options dialog
605     - a question is asked
606   }
607 
608   // remove pending forms that are no longer modal
609   for i:=CloseDialogs.Count-1 downto 0 do begin
610     Form:=TCustomForm(CloseDialogs[i]);
611     if not (fsModal in Form.FormState) then
612       CloseDialogs.Delete(i);
613   end;
614   Form:=Screen.GetCurrentModalForm;
615   debugln(['TOpenIDEFileOnIdle.OnIdle Modal=',DbgSName(Form)]);
616   // check if complete
617   if CloseDialogs.Count=0 then begin
618     debugln(['TOpenIDEFileOnIdle.OnIdle no more closing ...']);
619     Ending:=true;
620     if Form=nil then begin
621       // no more modal forms open
622       debugln(['TOpenIDEFileOnIdle.OnIdle opening ...']);
623       LazarusIDE.DoOpenFileAndJumpToPos(Filename,Point(X,Y),-1,-1,-1,[ofDoNotLoadResource]);
624     end;
625     Free;
626   end
627   else begin
628     // close a modal dialog
629     if CancelDialogs.IndexOf(Form)>=0 then begin
630       // this form was already cancelled, but is still there on idle
631       // => user cancelled or something went wrong
632       debugln(['TOpenIDEFileOnIdle.OnIdle closing failed']);
633       Ending:=true;
634       Free;
635     end else if CloseDialogs.IndexOf(Form)>=0 then begin
636       // close modal dialog
637       debugln(['TOpenIDEFileOnIdle.OnIdle closing ',DbgSName(Form)]);
638       CancelDialogs.Add(Form);
639       CloseDialogs.Remove(Form);
640       Form.ModalResult:=mrCancel;
641     end;
642   end;
643 end;
644 
645 end.
646 
647