mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-07-18 09:05:55 +02:00
476 lines
16 KiB
ObjectPascal
476 lines
16 KiB
ObjectPascal
{
|
|
*****************************************************************************
|
|
See the file COPYING.modifiedLGPL.txt, included in this distribution,
|
|
for details about the license.
|
|
*****************************************************************************
|
|
|
|
Authors: Maciej Izak
|
|
Michael W. Vogel
|
|
|
|
This is the access to one SourceEditor window. There can be more then just one
|
|
(that list is SourceEditorWindows).
|
|
Each SourceEditor window can hold a lot of units, forms etc. available per
|
|
SourceEditorWindowInterface in PageControlList.
|
|
|
|
}
|
|
|
|
unit DockedSourceEditorWindow;
|
|
|
|
{$mode objfpc}{$H+}
|
|
{$modeswitch advancedrecords}
|
|
{$modeswitch typehelpers}
|
|
|
|
{ $define DEBUGDOCKEDFORMEDITOR}
|
|
|
|
interface
|
|
|
|
uses
|
|
// RTL
|
|
Classes, SysUtils, fgl,
|
|
// LCL
|
|
Forms, Controls, LCLProc,
|
|
// IDEIntf
|
|
SrcEditorIntf, LazIDEIntf, FormEditingIntf, ExtendedNotebook,
|
|
// DockedFormEditor
|
|
DockedSourceEditorPageControls, DockedDesignForm, DockedModulePageControl,
|
|
DockedOptionsIDE, DockedTools;
|
|
|
|
type
|
|
|
|
{ TSourceEditorWindow }
|
|
|
|
TSourceEditorWindow = class
|
|
private
|
|
FActiveDesignForm: TDesignForm;
|
|
FLastActiveSourceEditor: TSourceEditorInterface;
|
|
FLastTopParent: TControl;
|
|
FNotebookPageChanged: TNotifyEvent;
|
|
FPageControlList: TSourceEditorPageControls;
|
|
FSourceEditorNotebook: TExtendedNotebook;
|
|
FSourceEditorWindowInterface: TSourceEditorWindowInterface;
|
|
function GetActiveEditor: TSourceEditorInterface;
|
|
procedure HookIntoOnPageChanged;
|
|
procedure SetActiveDesignForm(const AValue: TDesignForm);
|
|
procedure SourceEditorPageChanged(Sender: TObject);
|
|
procedure UpdateEditorPageCaption(Sender: TObject);
|
|
public
|
|
constructor Create(ASourceEditorWindowInterface: TSourceEditorWindowInterface);
|
|
destructor Destroy; override;
|
|
procedure AddPageCtrl(ASourceEditor: TSourceEditorInterface; APageControl: TModulePageControl);
|
|
procedure AdjustPageControl;
|
|
function FindModulePageControl(ASourceEditor: TSourceEditorInterface): TModulePageControl;
|
|
procedure RemoveActiveDesignForm;
|
|
procedure RemovePageCtrl(ASourceEditor: TSourceEditorInterface);
|
|
public
|
|
property ActiveDesignForm: TDesignForm read FActiveDesignForm write SetActiveDesignForm;
|
|
property ActiveEditor: TSourceEditorInterface read GetActiveEditor;
|
|
property LastActiveSourceEditor: TSourceEditorInterface read FLastActiveSourceEditor write FLastActiveSourceEditor;
|
|
property LastTopParent: TControl read FLastTopParent write FLastTopParent;
|
|
property PageControlList: TSourceEditorPageControls read FPageControlList;
|
|
property SourceEditorWindowInterface: TSourceEditorWindowInterface read FSourceEditorWindowInterface;
|
|
end;
|
|
|
|
{ TSourceEditorWindows }
|
|
|
|
TSourceEditorWindows = class(specialize TFPGList<TSourceEditorWindow>)
|
|
private
|
|
FLastActiveSourceEditorWindow: TSourceEditorWindowInterface;
|
|
function GetLastActiveModulePageControl: TModulePageControl;
|
|
function GetLastActiveSourceEditor: TSourceEditorInterface;
|
|
function GetWindowInterface(ASrcEditor: TSourceEditorWindow): TSourceEditorWindowInterface;
|
|
function GetSourceEditorWindow(AWindowInterface: TSourceEditorWindowInterface): TSourceEditorWindow;
|
|
procedure SetLastActiveSourceEditor(AValue: TSourceEditorInterface);
|
|
public
|
|
constructor CreateNew;
|
|
destructor Destroy; override;
|
|
function Contains(AWindowInterface: TSourceEditorWindowInterface): Boolean;
|
|
function Contains(ASrcEditor: TSourceEditorWindow): Boolean;
|
|
procedure DeleteItem(Index: Integer);
|
|
function FindDesignForm(AModulePageCtrl: TModulePageControl): TDesignForm;
|
|
function FindModulePageControl(ASrcEditor: TSourceEditorInterface): TModulePageControl;
|
|
function IndexOf(AWindowInterface: TSourceEditorWindowInterface): Integer; overload;
|
|
function LastSourceEditorNotFound: Boolean;
|
|
procedure RefreshActivePageControls;
|
|
procedure RefreshAllPageControls;
|
|
procedure Remove(AWindowInterface: TSourceEditorWindowInterface); overload;
|
|
procedure ShowCodeTabSkipCurrent(CurrentPageCtrl: TModulePageControl; ADesignForm: TDesignForm);
|
|
public
|
|
property LastActiveSourceEditorWindow: TSourceEditorWindowInterface read FLastActiveSourceEditorWindow write FLastActiveSourceEditorWindow;
|
|
property LastActiveSourceEditor: TSourceEditorInterface read GetLastActiveSourceEditor write SetLastActiveSourceEditor;
|
|
property LastActiveModulePageControl: TModulePageControl read GetLastActiveModulePageControl;
|
|
property WindowInterface[ASrcEditor: TSourceEditorWindow]: TSourceEditorWindowInterface read GetWindowInterface;
|
|
property SourceEditorWindow[AWindowInterface: TSourceEditorWindowInterface]: TSourceEditorWindow read GetSourceEditorWindow;
|
|
end;
|
|
|
|
var
|
|
SourceEditorWindows: TSourceEditorWindows;
|
|
|
|
implementation
|
|
|
|
{ TSourceEditorWindow }
|
|
|
|
procedure TSourceEditorWindow.HookIntoOnPageChanged;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to FSourceEditorWindowInterface.ControlCount - 1 do
|
|
if FSourceEditorWindowInterface.Controls[i] is TExtendedNotebook then
|
|
begin
|
|
FSourceEditorNotebook := TExtendedNotebook(FSourceEditorWindowInterface.Controls[i]);
|
|
Break;
|
|
end;
|
|
if not Assigned(FSourceEditorNotebook) then Exit;
|
|
FNotebookPageChanged := FSourceEditorNotebook.OnChange;
|
|
FSourceEditorNotebook.OnChange := @SourceEditorPageChanged;
|
|
end;
|
|
|
|
function TSourceEditorWindow.GetActiveEditor: TSourceEditorInterface;
|
|
begin
|
|
Result := FSourceEditorWindowInterface.ActiveEditor;
|
|
end;
|
|
|
|
procedure TSourceEditorWindow.SetActiveDesignForm(const AValue: TDesignForm);
|
|
var
|
|
LPageCtrl: TModulePageControl;
|
|
begin
|
|
if FActiveDesignForm = AValue then Exit;
|
|
if FActiveDesignForm <> nil then
|
|
// don't hide now if soon form will be hidden (for example on the IDE start)
|
|
if not FActiveDesignForm.Hiding then
|
|
FActiveDesignForm.HideWindow;
|
|
FActiveDesignForm := AValue;
|
|
|
|
LPageCtrl := FindModulePageControl(ActiveEditor);
|
|
// important when we want back to tab where was oppened form
|
|
if (AValue <> nil) then
|
|
LazarusIDE.DoShowDesignerFormOfSrc(ActiveEditor);
|
|
|
|
if LPageCtrl = nil then Exit;
|
|
LPageCtrl.DesignForm := AValue;
|
|
end;
|
|
|
|
procedure TSourceEditorWindow.SourceEditorPageChanged(Sender: TObject);
|
|
var
|
|
LPageCtrl: TModulePageControl;
|
|
begin
|
|
{$IFDEF DEBUGDOCKEDFORMEDITOR} DebugLn('TSourceEditorWindow.SourceEditorPageChanged SourceEditorWindow[' + FSourceEditorWindowInterface.Caption + ']'); {$ENDIF}
|
|
FNotebookPageChanged(Sender);
|
|
LPageCtrl := FindModulePageControl(ActiveEditor);
|
|
if not Assigned(LPageCtrl) then Exit;
|
|
if LPageCtrl.DesignerPageActive then
|
|
begin
|
|
LPageCtrl.AdjustPage;
|
|
{$IF DEFINED(LCLGtk2)}
|
|
LPageCtrl.DesignerSetFocusAsync;
|
|
{$ELSE}
|
|
LPageCtrl.DesignerSetFocus;
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorWindow.UpdateEditorPageCaption(Sender: TObject);
|
|
var
|
|
LSourceEditor: TSourceEditorInterface;
|
|
LSourceEditorWindow: TSourceEditorWindowInterface;
|
|
begin
|
|
// if a unit is cloned to undocked empty source editor window, the ModulePageControl
|
|
// is not created, the only workaround I found is, to activate the new created
|
|
// source editor in this window
|
|
if not (Sender is TSourceEditorInterface) then Exit;
|
|
if SourceEditorManagerIntf.ActiveSourceWindow = nil then Exit;
|
|
LSourceEditor := TSourceEditorInterface(Sender);
|
|
{$IFDEF DEBUGDOCKEDFORMEDITOR} DebugLn('TSourceEditorWindow.UpdateEditorPageCaption [' + SourceEditorWindowCaption(LSourceEditor) + ']'); {$ENDIF}
|
|
LSourceEditorWindow := SourceEditorWindow(LSourceEditor);
|
|
if not Assigned(LSourceEditorWindow)
|
|
or (SourceEditorManagerIntf.ActiveSourceWindow = LSourceEditorWindow)
|
|
or (SourceEditorWindows.LastActiveSourceEditorWindow = LSourceEditorWindow)
|
|
then
|
|
Exit;
|
|
LSourceEditorWindow.ActiveEditor := LSourceEditor;
|
|
end;
|
|
|
|
constructor TSourceEditorWindow.Create(ASourceEditorWindowInterface: TSourceEditorWindowInterface);
|
|
begin
|
|
FLastActiveSourceEditor := nil;
|
|
FSourceEditorWindowInterface := ASourceEditorWindowInterface;
|
|
FPageControlList := TSourceEditorPageControls.Create;
|
|
FSourceEditorNotebook := nil;
|
|
HookIntoOnPageChanged;
|
|
FSourceEditorWindowInterface.AddUpdateEditorPageCaptionHandler(@UpdateEditorPageCaption);
|
|
end;
|
|
|
|
destructor TSourceEditorWindow.Destroy;
|
|
begin
|
|
if Assigned(FSourceEditorNotebook) then
|
|
FSourceEditorNotebook.OnChange := FNotebookPageChanged;
|
|
FPageControlList.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TSourceEditorWindow.AddPageCtrl(ASourceEditor: TSourceEditorInterface; APageControl: TModulePageControl);
|
|
begin
|
|
FPageControlList.Add(ASourceEditor, APageControl);
|
|
end;
|
|
|
|
procedure TSourceEditorWindow.AdjustPageControl;
|
|
var
|
|
LPageCtrl: TModulePageControl;
|
|
begin
|
|
LPageCtrl := FindModulePageControl(ActiveEditor);
|
|
if LPageCtrl <> nil then
|
|
LPageCtrl.AdjustPage;
|
|
end;
|
|
|
|
function TSourceEditorWindow.FindModulePageControl(ASourceEditor: TSourceEditorInterface): TModulePageControl;
|
|
var
|
|
LParent: TWinControl;
|
|
begin
|
|
if ASourceEditor = nil then
|
|
Exit(nil);
|
|
LParent := ASourceEditor.EditorControl.Parent;
|
|
while LParent <> nil do
|
|
begin
|
|
if LParent is TModulePageControl then
|
|
Exit(TModulePageControl(LParent));
|
|
LParent := LParent.Parent;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TSourceEditorWindow.RemoveActiveDesignForm;
|
|
begin
|
|
FActiveDesignForm := nil;
|
|
end;
|
|
|
|
procedure TSourceEditorWindow.RemovePageCtrl(ASourceEditor: TSourceEditorInterface);
|
|
begin
|
|
FPageControlList.Remove(ASourceEditor);
|
|
if LastActiveSourceEditor = ASourceEditor then
|
|
LastActiveSourceEditor := nil;
|
|
end;
|
|
|
|
{ TSourceEditorWindows }
|
|
|
|
function TSourceEditorWindows.GetWindowInterface(ASrcEditor: TSourceEditorWindow): TSourceEditorWindowInterface;
|
|
var
|
|
LIndex: Integer;
|
|
begin
|
|
LIndex := IndexOf(ASrcEditor);
|
|
if LIndex >= 0 then
|
|
Result := Items[LIndex].SourceEditorWindowInterface
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TSourceEditorWindows.GetLastActiveModulePageControl: TModulePageControl;
|
|
begin
|
|
Result := FindModulePageControl(LastActiveSourceEditor);
|
|
end;
|
|
|
|
function TSourceEditorWindows.GetLastActiveSourceEditor: TSourceEditorInterface;
|
|
var
|
|
LSourceEditorWindow: TSourceEditorWindow;
|
|
begin
|
|
Result := nil;
|
|
if not Assigned(LastActiveSourceEditorWindow) then Exit;
|
|
LSourceEditorWindow := SourceEditorWindow[LastActiveSourceEditorWindow];
|
|
if not Assigned(LSourceEditorWindow) then Exit;
|
|
Result := LSourceEditorWindow.LastActiveSourceEditor;
|
|
end;
|
|
|
|
function TSourceEditorWindows.GetSourceEditorWindow(AWindowInterface: TSourceEditorWindowInterface): TSourceEditorWindow;
|
|
var
|
|
LIndex: Integer;
|
|
begin
|
|
LIndex := IndexOf(AWindowInterface);
|
|
if LIndex >= 0 then
|
|
Result := Items[LIndex]
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TSourceEditorWindows.SetLastActiveSourceEditor(AValue: TSourceEditorInterface);
|
|
var
|
|
LSourceEditorWindow: TSourceEditorWindow;
|
|
begin
|
|
if not Assigned(LastActiveSourceEditorWindow) then Exit;
|
|
LSourceEditorWindow := SourceEditorWindow[LastActiveSourceEditorWindow];
|
|
if not Assigned(LSourceEditorWindow) then Exit;
|
|
LSourceEditorWindow.LastActiveSourceEditor := AValue;
|
|
end;
|
|
|
|
constructor TSourceEditorWindows.CreateNew;
|
|
begin
|
|
inherited Create;
|
|
FLastActiveSourceEditorWindow := nil;
|
|
end;
|
|
|
|
destructor TSourceEditorWindows.Destroy;
|
|
begin
|
|
while Count > 0 do
|
|
DeleteItem(0);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TSourceEditorWindows.Contains(AWindowInterface: TSourceEditorWindowInterface): Boolean;
|
|
begin
|
|
Result := IndexOf(AWindowInterface) >= 0;
|
|
end;
|
|
|
|
function TSourceEditorWindows.Contains(ASrcEditor: TSourceEditorWindow): Boolean;
|
|
begin
|
|
Result := IndexOf(ASrcEditor) >= 0;
|
|
end;
|
|
|
|
procedure TSourceEditorWindows.DeleteItem(Index: Integer);
|
|
var
|
|
LSourceEditorWindow: TSourceEditorWindow;
|
|
begin
|
|
LSourceEditorWindow := Items[Index];
|
|
LSourceEditorWindow.Free;
|
|
Delete(Index);
|
|
end;
|
|
|
|
function TSourceEditorWindows.FindDesignForm(AModulePageCtrl: TModulePageControl): TDesignForm;
|
|
var
|
|
LSourceEditorWindow: TSourceEditorWindow;
|
|
LSourceEditorInterface: TSourceEditorInterface;
|
|
begin
|
|
Result := nil;
|
|
if AModulePageCtrl = nil then Exit;
|
|
for LSourceEditorWindow in Self do
|
|
begin
|
|
if AModulePageCtrl.Owner = LSourceEditorWindow.SourceEditorWindowInterface then
|
|
begin
|
|
LSourceEditorInterface := LSourceEditorWindow.ActiveEditor;
|
|
if LSourceEditorInterface = nil then Exit;
|
|
Result := DesignForms.Find(LSourceEditorInterface.GetDesigner(True));
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditorWindows.FindModulePageControl(ASrcEditor: TSourceEditorInterface): TModulePageControl;
|
|
var
|
|
LSourceEditorWindow: TSourceEditorWindow;
|
|
begin
|
|
Result := nil;
|
|
for LSourceEditorWindow in Self do
|
|
if LSourceEditorWindow.PageControlList.Contains(ASrcEditor) then
|
|
Exit(LSourceEditorWindow.PageControlList.PageControl[ASrcEditor]);
|
|
end;
|
|
|
|
function TSourceEditorWindows.IndexOf(AWindowInterface: TSourceEditorWindowInterface): Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := -1;
|
|
for i := 0 to Count - 1 do
|
|
if Items[i].SourceEditorWindowInterface = AWindowInterface then
|
|
Exit(i);
|
|
end;
|
|
|
|
function TSourceEditorWindows.LastSourceEditorNotFound: Boolean;
|
|
var
|
|
i: Integer;
|
|
LSourceEditorPageControl: TSourceEditorPageControl;
|
|
LSourceEditorWindow: TSourceEditorWindow;
|
|
begin
|
|
if (LastActiveSourceEditorWindow = nil) or (LastActiveSourceEditor = nil) then
|
|
Exit(False);
|
|
|
|
LSourceEditorWindow := SourceEditorWindow[LastActiveSourceEditorWindow];
|
|
for LSourceEditorPageControl in LSourceEditorWindow.PageControlList do
|
|
begin
|
|
Result := True;
|
|
for i := 0 to LastActiveSourceEditorWindow.Count - 1 do
|
|
if LSourceEditorPageControl.SourceEditor = LastActiveSourceEditorWindow.Items[i] then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
if Result then
|
|
begin
|
|
// after moving code editor into other window, sometimes IDE switch to other tab
|
|
// this line prevent this.
|
|
LSourceEditorWindow.LastActiveSourceEditor := LSourceEditorPageControl.SourceEditor;
|
|
Exit;
|
|
end;
|
|
end;
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TSourceEditorWindows.RefreshActivePageControls;
|
|
var
|
|
LWindow: TSourceEditorWindow;
|
|
LPageCtrl: TModulePageControl;
|
|
begin
|
|
for LWindow in Self do
|
|
begin
|
|
LPageCtrl := LWindow.FindModulePageControl(LWindow.ActiveEditor);
|
|
// for example LPageCtrl is nil when we clone module to new window
|
|
if (LPageCtrl = nil) or (csDestroying in LWindow.SourceEditorWindowInterface.ComponentState) then
|
|
Continue;
|
|
if (LWindow.ActiveEditor = nil)
|
|
or (LWindow.ActiveEditor.GetDesigner(True) <> nil)
|
|
then
|
|
LPageCtrl.RemoveDesignPages
|
|
else
|
|
if Assigned(LPageCtrl.DesignForm) then
|
|
begin
|
|
LPageCtrl.CreateTabSheetDesigner;
|
|
if not (LPageCtrl.DesignForm.Form is TNonControlProxyDesignerForm) then
|
|
LPageCtrl.CreateTabSheetAnchors;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorWindows.RefreshAllPageControls;
|
|
var
|
|
LWindow: TSourceEditorWindow;
|
|
LSourceEditorPageControl: TSourceEditorPageControl;
|
|
begin
|
|
for LWindow in SourceEditorWindows do
|
|
for LSourceEditorPageControl in LWindow.PageControlList do
|
|
begin
|
|
LSourceEditorPageControl.PageControl.TabPosition := DockedOptions.TabPosition;
|
|
LSourceEditorPageControl.PageControl.RefreshResizer;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorWindows.Remove(AWindowInterface: TSourceEditorWindowInterface);
|
|
var
|
|
LIndex: Integer;
|
|
begin
|
|
LIndex := IndexOf(AWindowInterface);
|
|
if LIndex < 0 then Exit;
|
|
DeleteItem(LIndex);
|
|
if LastActiveSourceEditorWindow = AWindowInterface then
|
|
LastActiveSourceEditorWindow := nil;
|
|
end;
|
|
|
|
procedure TSourceEditorWindows.ShowCodeTabSkipCurrent(CurrentPageCtrl: TModulePageControl; ADesignForm: TDesignForm);
|
|
var
|
|
LSourceEditorWindow: TSourceEditorWindow;
|
|
LSourceEditorPageControl: TSourceEditorPageControl;
|
|
begin
|
|
for LSourceEditorWindow in Self do
|
|
for LSourceEditorPageControl in LSourceEditorWindow.PageControlList do
|
|
if LSourceEditorPageControl.PageControl = CurrentPageCtrl then
|
|
begin
|
|
LSourceEditorPageControl.PageControl.DesignForm := ADesignForm;
|
|
LSourceEditorPageControl.PageControl.InitPage;
|
|
end else
|
|
if LSourceEditorPageControl.PageControl.DesignForm = ADesignForm then
|
|
LSourceEditorPageControl.PageControl.ShowCode;
|
|
end;
|
|
|
|
initialization
|
|
SourceEditorWindows := TSourceEditorWindows.CreateNew;
|
|
|
|
finalization
|
|
SourceEditorWindows.Free;
|
|
|
|
end.
|
|
|