{ Installs anchor docking manager in the Lazarus IDE.

  Copyright (C) 2010 Mattias Gaertner mattias@freepascal.org

  This library is free software; you can redistribute it and/or modify it
  under the terms of the GNU Library General Public License as published by
  the Free Software Foundation; either version 2 of the License, or (at your
  option) any later version with the following modification:

  As a special exception, the copyright holders of this library give you
  permission to link this library with independent modules to produce an
  executable, regardless of the license terms of these independent modules,and
  to copy and distribute the resulting executable under terms of your choice,
  provided that you also meet, for each linked independent module, the terms
  and conditions of the license of that module. An independent module is a
  module which is not derived from or based on this library. If you modify
  this library, you may extend this exception to your version of the library,
  but you are not obligated to do so. If you do not wish to do so, delete this
  exception statement from your version.

  This program is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  for more details.

  You should have received a copy of the GNU Library General Public License
  along with this library; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

  ToDo:
    - save settings after options dialog
    - close source editor and show again
    - show anchor editor => too small
    - qt: focus on close page
    - gtk2: focus on cancel completion box
    - gtk2: focus on execute completion box
    - gtk2: restore fails for mainidebar
}
unit RegisterAnchorDocking;

{$mode objfpc}{$H+}

interface

uses
  Math, Classes, SysUtils, LCLProc, Forms, Controls, FileUtil, Dialogs,
  LazConfigStorage, XMLCfg, XMLPropStorage, StdCtrls, LCLIntf,
  BaseIDEIntf, ProjectIntf, MacroIntf, IDEDialogs, MenuIntf, LazIDEIntf,
  IDEWindowIntf, IDEOptionsIntf,
  AnchorDockStr, AnchorDocking, AnchorDockOptionsDlg;

const
  DefaultConfigFileName = 'anchordocklayout.xml';
var
  mnuAnchorDockSection: TIDEMenuSection;
    mnuADSaveLayoutAsDefault: TIDEMenuCommand;
    mnuADSaveLayoutToFile: TIDEMenuCommand;
    mnuADLoadLayoutFromFile: TIDEMenuCommand;

type

  { TIDEAnchorDockMaster }

  TIDEAnchorDockMaster = class(TIDEDockMaster)
  private
    FChangeStamp: int64;
    FEnabled: boolean;
    FModified: boolean;
    FUserLayoutLoaded: boolean;
    procedure DockMasterCreateControl(Sender: TObject; aName: string;
      var AControl: TControl; DoDisableAutoSizing: boolean);
    procedure GetDefaultBounds(AForm: TCustomForm; out Creator: TIDEWindowCreator;
      out NewBounds: TRect; out DockSiblingName: string; out DockAlign: TAlign);
    procedure SetEnabled(const AValue: boolean);
    procedure SetModified(const AValue: boolean);
    procedure SetUserLayoutLoaded(const AValue: boolean);
  public
    constructor Create;
    destructor Destroy; override;
    procedure MakeIDEWindowDockSite(AForm: TCustomForm; ASides: TDockSides = [alBottom]); override;
    procedure MakeIDEWindowDockable(AControl: TWinControl); override;
    function AddableInWindowMenu(AForm: TCustomForm): boolean; override;
    function GetDefaultLayoutFilename: string;
    procedure LoadDefaultLayout;
    procedure LoadUserLayout;
    procedure SaveUserLayout;
    procedure LoadLayoutFromFile(Filename: string);
    procedure SaveLayoutToFile(Filename: string);
    procedure ShowForm(AForm: TCustomForm; BringToFront: boolean); override;
    procedure CloseAll; override;
    procedure OnIDERestoreWindows(Sender: TObject);
    function OnProjectClose(Sender: TObject; AProject: TLazProject): TModalResult;
    procedure LoadLayoutFromFileClicked(Sender: TObject);
    procedure SaveLayoutToFileClicked(Sender: TObject);
    procedure SaveLayoutAsDefaultClicked(Sender: TObject);
    property UserLayoutLoaded: boolean read FUserLayoutLoaded write SetUserLayoutLoaded;
    property Enabled: boolean read FEnabled write SetEnabled;
    procedure IncreaseChangeStamp;
    property ChangeStamp: int64 read FChangeStamp;
    property Modified: boolean read FModified write SetModified;
  end;

  { TAnchorDockIDEFrame }

  TAnchorDockIDEFrame = class(TAbstractIDEOptionsEditor)
    EnableCheckBox: TCheckBox;
    NoteLabel: TLabel;
  public
    OptionsFrame: TAnchorDockOptionsFrame;
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
    function GetTitle: String; override;
    procedure Setup(ADialog: TAbstractOptionsEditorDialog); override;
    procedure ReadSettings(AOptions: TAbstractIDEOptions); override;
    procedure WriteSettings(AOptions: TAbstractIDEOptions); override;
    class function SupportedOptionsClass: TAbstractIDEOptionsClass; override;
  end;

var
  IDEAnchorDockMaster: TIDEAnchorDockMaster = nil;
  AnchorDockOptionsID: integer = 1000;

procedure Register;

implementation

procedure Register;
begin
  if not (IDEDockMaster is TIDEAnchorDockMaster) then exit;

  LazarusIDE.AddHandlerOnIDERestoreWindows(@IDEAnchorDockMaster.OnIDERestoreWindows);
  LazarusIDE.AddHandlerOnProjectClose(@IDEAnchorDockMaster.OnProjectClose);

  // add menu section
  mnuAnchorDockSection:=RegisterIDEMenuSection(mnuEnvironment,'AnchorDocking');
  mnuADSaveLayoutAsDefault:=RegisterIDEMenuCommand(mnuAnchorDockSection,
    'ADSaveLayoutAsDefault', adrsSaveWindowLayoutAsDefault,
    @IDEAnchorDockMaster.SaveLayoutAsDefaultClicked);
  mnuADSaveLayoutToFile:=RegisterIDEMenuCommand(mnuAnchorDockSection,
    'ADSaveLayoutToFile', adrsSaveWindowLayoutToFile,
    @IDEAnchorDockMaster.SaveLayoutToFileClicked);
  mnuADLoadLayoutFromFile:=RegisterIDEMenuCommand(mnuAnchorDockSection,
    'ADLoadLayoutFromFile', adrsLoadWindowLayoutFromFile,
    @IDEAnchorDockMaster.LoadLayoutFromFileClicked);

  // add options frame
  {$R *.lfm}
  AnchorDockOptionsID:=RegisterIDEOptionsEditor(GroupEnvironment,TAnchorDockIDEFrame,
                                                AnchorDockOptionsID)^.Index;
end;

{ TIDEAnchorDockMaster }

procedure TIDEAnchorDockMaster.DockMasterCreateControl(Sender: TObject;
  aName: string; var AControl: TControl; DoDisableAutoSizing: boolean);
begin
  //debugln(['TIDEAnchorDockMaster.DockMasterCreateControl CtrlName="',dbgstr(AName),'"']);
  AControl:=IDEWindowCreators.GetForm(aName,true,DoDisableAutoSizing);
  //debugln(['TIDEAnchorDockMaster.DockMasterCreateControl Result=',DbgSName(AControl)]);
end;

procedure TIDEAnchorDockMaster.GetDefaultBounds(AForm: TCustomForm; out
  Creator: TIDEWindowCreator; out NewBounds: TRect; out
  DockSiblingName: string; out DockAlign: TAlign);
var
  AControl: TControl;
begin
  NewBounds:=Rect(0,0,0,0);
  DockSiblingName:='';
  DockAlign:=alNone;

  // get the embedded control
  AControl:=DockMaster.GetControl(AForm);
  if not (AControl is TCustomForm) then exit;
  AForm:=TCustomForm(AControl);

  Creator:=IDEWindowCreators.FindWithName(AForm.Name);
  if Creator=nil then exit;
  if Creator.OnGetLayout<>nil then
    Creator.OnGetLayout(Self,AForm.Name,NewBounds,DockSiblingName,DockAlign)
  else begin
    Creator.GetDefaultBounds(AForm,NewBounds);
    DockSiblingName:=Creator.DockSibling;
    DockAlign:=Creator.DockAlign;
  end;
  NewBounds.Left:=Min(10000,Max(-10000,NewBounds.Left));
  NewBounds.Top:=Min(10000,Max(-10000,NewBounds.Top));
  NewBounds.Right:=Max(NewBounds.Left+100,NewBounds.Right);
  NewBounds.Bottom:=Max(NewBounds.Top+100,NewBounds.Bottom);
end;

procedure TIDEAnchorDockMaster.SetEnabled(const AValue: boolean);
begin
  if FEnabled=AValue then exit;
  FEnabled:=AValue;
  IncreaseChangeStamp;
end;

procedure TIDEAnchorDockMaster.SetModified(const AValue: boolean);
begin
  if FModified=AValue then exit;
  FModified:=AValue;
end;

procedure TIDEAnchorDockMaster.SetUserLayoutLoaded(const AValue: boolean);
begin
  if FUserLayoutLoaded=AValue then exit;
  FUserLayoutLoaded:=AValue;
end;

constructor TIDEAnchorDockMaster.Create;
begin
  inherited Create;
  fEnabled:=true;
  IDEAnchorDockMaster:=Self;
  DockMaster.OnCreateControl:=@DockMasterCreateControl;
  DockMaster.OnShowOptions:=@ShowAnchorDockOptions;
end;

destructor TIDEAnchorDockMaster.Destroy;
begin
  IDEAnchorDockMaster:=nil;
  if IDEDockMaster=Self then
    IDEDockMaster:=Self;
  inherited Destroy;
end;

procedure TIDEAnchorDockMaster.MakeIDEWindowDockSite(AForm: TCustomForm;
  ASides: TDockSides);
var
  aManager: TAnchorDockManager;
begin
  debugln(['TIDEAnchorDockMaster.MakeIDEWindowDockSite ',DbgSName(AForm)]);
  if ASides=[] then ;
  DockMaster.MakeDockSite(AForm,[akBottom],admrpChild);
  if AForm.DockManager is TAnchorDockManager then begin
    aManager:=TAnchorDockManager(AForm.DockManager);
    aManager.PreferredSiteSizeAsSiteMinimum:=false;
  end;
end;

procedure TIDEAnchorDockMaster.MakeIDEWindowDockable(AControl: TWinControl);
begin
  debugln(['TIDEAnchorDockMaster.MakeIDEWindowDockable ',DbgSName(AControl)]);
  DockMaster.MakeDockable(AControl,false);
end;

function TIDEAnchorDockMaster.AddableInWindowMenu(AForm: TCustomForm): boolean;
begin
  Result:=false;
  if AForm is TAnchorDockHostSite then exit;
  if (DockMaster.FindControl(AForm.Name)=nil) and (AForm.Parent<>nil) then exit;
  Result:=true;
end;

function TIDEAnchorDockMaster.GetDefaultLayoutFilename: string;
begin
  Result:=AppendPathDelim(LazarusIDE.GetPrimaryConfigPath)+DefaultConfigFileName;
end;

procedure TIDEAnchorDockMaster.LoadDefaultLayout;
var
  BaseDir: String;
  Filename: String;
begin
  BaseDir:='$PkgDir(AnchorDockingDsgn)';
  IDEMacros.SubstituteMacros(BaseDir);
  if (BaseDir<>'') and DirectoryExistsUTF8(BaseDir) then begin
    Filename:=AppendPathDelim(BaseDir)+'ADLayoutDefault.xml';
    if FileExistsUTF8(Filename) then
      LoadLayoutFromFile(Filename);
  end;
end;

procedure TIDEAnchorDockMaster.LoadUserLayout;
var
  Filename: String;
  Config: TConfigStorage;
begin
  Filename:=DefaultConfigFileName;
  try
    debugln(['TIDEAnchorDockMaster.LoadUserLayout ',Filename]);
    Config:=GetIDEConfigStorage(Filename,true);
    try
      if not DockMaster.ConfigIsEmpty(Config) then begin
        // loading last layout
        debugln(['TIDEAnchorDockMaster.LoadUserLayout restoring ...']);
        DockMaster.LoadSettingsFromConfig(Config);
        DockMaster.LoadLayoutFromConfig(Config,true);
        UserLayoutLoaded:=true;
      end else begin
        debugln(['TIDEAnchorDockMaster.LoadUserLayout loading default layout ...']);
        LoadDefaultLayout;
      end;
    finally
      Config.Free;
    end;
  except
    on E: Exception do begin
      DebugLn(['TIDEAnchorDockMaster.LoadUserLayout loading ',Filename,' failed: ',E.Message]);
    end;
  end;
end;

procedure TIDEAnchorDockMaster.SaveUserLayout;
var
  Filename: String;
  Config: TConfigStorage;
begin
  Filename:=DefaultConfigFileName;
  try
    debugln(['TIDEAnchorDockMaster.SaveDefaultLayout ',Filename]);
    Config:=GetIDEConfigStorage(Filename,false);
    try
      DockMaster.SaveSettingsToConfig(Config);
      DockMaster.SaveLayoutToConfig(Config);
    finally
      Config.Free;
    end;
  except
    on E: Exception do begin
      DebugLn(['TIDEAnchorDockMaster.SaveDefaultLayout saving ',Filename,' failed: ',E.Message]);
    end;
  end;
end;

procedure TIDEAnchorDockMaster.LoadLayoutFromFile(Filename: string);
var
  XMLConfig: TXMLConfig;
  Config: TXMLConfigStorage;
begin
  //debugln(['TIDEAnchorDockMaster.LoadLayoutFromFile ',Filename]);
  XMLConfig:=TXMLConfig.Create(nil);
  try
    XMLConfig.Filename:=Filename;
    Config:=TXMLConfigStorage.Create(XMLConfig);
    try
      DockMaster.LoadLayoutFromConfig(Config,true);
    finally
      Config.Free;
    end;
    XMLConfig.Flush;
  finally
    XMLConfig.Free;
  end;
end;

procedure TIDEAnchorDockMaster.SaveLayoutToFile(Filename: string);
var
  XMLConfig: TXMLConfig;
  Config: TXMLConfigStorage;
begin
  XMLConfig:=TXMLConfig.Create(nil);
  try
    XMLConfig.StartEmpty:=true;
    XMLConfig.Filename:=Filename;
    Config:=TXMLConfigStorage.Create(XMLConfig);
    try
      DockMaster.SaveLayoutToConfig(Config);
    finally
      Config.Free;
    end;
    XMLConfig.Flush;
  finally
    XMLConfig.Free;
  end;
end;

procedure TIDEAnchorDockMaster.ShowForm(AForm: TCustomForm;
  BringToFront: boolean);
var
  Parent: TCustomForm;
  Creator: TIDEWindowCreator;
  NewBounds: TRect;
  DockSiblingName: string;
  DockAlign: TAlign;
  DockSibling: TCustomForm;
  NewDockSite: TCustomForm;
  Site: TAnchorDockHostSite;
  AControl: TControl;
  NeedPlacing: Boolean;
  SiteForm: TCustomForm;
  OldActiveControl: TWinControl;
begin
  //debugln(['TIDEAnchorDockMaster.ShowForm START ',DbgSName(AForm),' BringToFront=',BringToFront,' IsSite=',DockMaster.IsSite(AForm),' IsCustomSite=',DockMaster.IsCustomSite(AForm)]);
  try
    AForm.DisableAlign;

    NeedPlacing:=not AForm.IsVisible;
    if DockMaster.GetSite(AForm)=nil then begin
      // this form was not yet docked
      // => make it dockable
      DockMaster.MakeDockable(AForm,false);
      NeedPlacing:=true;
    end;
    AControl:=DockMaster.GetControl(AForm);

    if not Aform.IsVisible then debugln(['TIDEAnchorDockMaster.ShowForm AControl=',DbgSName(AControl),' NeedPlacing=',NeedPlacing,' Floating=',DockMaster.IsFloating(AForm)]);

    if (AControl<>nil) and NeedPlacing and DockMaster.IsFloating(AForm) then begin
      // this form is not yet on the screen and is not yet docked
      debugln(['TIDEAnchorDockMaster.ShowForm placing ',DbgSName(AControl),' ...']);

      // ToDo: use the restore layout

      // place it at a default position and/or dock it
      GetDefaultBounds(AForm,Creator,NewBounds,DockSiblingName,DockAlign);
      if Creator<>nil then begin
        SiteForm:=GetParentForm(AForm);
        SiteForm.BoundsRect:=NewBounds;
        SiteForm.UndockWidth:=NewBounds.Right-NewBounds.Left;
        SiteForm.UndockHeight:=NewBounds.Bottom-NewBounds.Top;
        debugln(['TIDEAnchorDockMaster.ShowForm creator for ',DbgSName(AControl),' found: Left=',Creator.Left,' Top=',Creator.Top,' Right=',Creator.Right,' Bottom=',Creator.Bottom,' DockSiblingName=',DockSiblingName,' DockAlign=',dbgs(DockAlign),' ',dbgs(SiteForm.BoundsRect)]);
        Site:=DockMaster.GetAnchorSite(SiteForm);
        if (Site<>nil) and (DockSiblingName<>'') then begin
          DockSibling:=Screen.FindForm(DockSiblingName);
          debugln(['TIDEAnchorDockMaster.ShowForm DockSiblingName="',DockSiblingName,'" DockSibling=',DbgSName(DockSibling)]);
          if DockSibling<>nil then begin
            NewDockSite:=DockMaster.GetSite(DockSibling);
            if NewDockSite<>nil then begin
              debugln(['TIDEAnchorDockMaster.ShowForm NewDockSite=',DbgSName(NewDockSite),'="',NewDockSite.Caption,'"']);
              DockMaster.ManualDock(Site,NewDockSite,DockAlign);
              debugln(['TIDEAnchorDockMaster.ShowForm after docking: ',DbgSName(AControl),' Floating=',DockMaster.IsFloating(AControl)]);
            end;
          end;
        end;
      end;
    end;

  finally
    OldActiveControl:=AForm.ActiveControl;
    if not AForm.IsVisible then debugln(['TIDEAnchorDockMaster.ShowForm MakeVisible ',DbgSName(AForm),' ',dbgs(AForm.BoundsRect),' Floating=',DockMaster.IsFloating(AForm)]);
    DockMaster.MakeVisible(AForm,BringToFront);
    AForm.EnableAlign;

    if BringToFront then begin
      if (OldActiveControl=nil)
      or (not OldActiveControl.HandleAllocated)
      or (FindControl(GetFocus)<>OldActiveControl) then begin
        Parent:=GetParentForm(AForm);
        Parent.ShowOnTop;
        if (OldActiveControl<>nil) and OldActiveControl.CanFocus then
        begin
          Parent.ActiveControl:=OldActiveControl;
          Parent.SetFocus;
        end;
        //debugln(['TIDEAnchorDockMaster.ShowForm AForm.ActiveControl=',dbgsname(AForm.ActiveControl),' ',DbgSName(Parent.ActiveControl),' ',DbgSName(FindControl(GetFocus))]);
      end;
    end;
  end;
  //debugln(['TIDEAnchorDockMaster.ShowForm END ',DbgSName(AForm),' ',dbgs(AForm.BoundsRect),' ',DbgSName(FindControl(GetFocus))]);
end;

procedure TIDEAnchorDockMaster.CloseAll;
begin
  DockMaster.CloseAll;
end;

function TIDEAnchorDockMaster.OnProjectClose(Sender: TObject;
  AProject: TLazProject): TModalResult;
begin
  Result:=mrOk;
  if AProject=nil then exit;
  // do not auto save user layout, the restore is not yet stable
  //SaveUserLayout;
end;

procedure TIDEAnchorDockMaster.OnIDERestoreWindows(Sender: TObject);
begin
  LoadUserLayout;
end;

procedure TIDEAnchorDockMaster.LoadLayoutFromFileClicked(Sender: TObject);
var
  Dlg: TOpenDialog;
  Filename: String;
begin
  Dlg:=TOpenDialog.Create(nil);
  try
    InitIDEFileDialog(Dlg);
    Dlg.Title:=adrsLoadWindowLayoutFromFileXml;
    Dlg.Options:=Dlg.Options+[ofFileMustExist];
    Dlg.Filter:=adrsAnchorDockingLayout+'|*.xml|'+adrsAllFiles+'|'+GetAllFilesMask;
    if Dlg.Execute then begin
      Filename:=CleanAndExpandFilename(Dlg.FileName);
      try
        LoadLayoutFromFile(Filename);
      except
        on E: Exception do begin
          IDEMessageDialog(adrsError,
            Format(adrsErrorLoadingWindowLayoutFromFile, [Filename, #13, E.Message]),
            mtError,[mbCancel]);
        end;
      end;
    end;
    StoreIDEFileDialog(Dlg);
  finally
    Dlg.Free;
  end;
end;

procedure TIDEAnchorDockMaster.SaveLayoutToFileClicked(Sender: TObject);
var
  Dlg: TSaveDialog;
  Filename: String;
begin
  Dlg:=TSaveDialog.Create(nil);
  try
    InitIDEFileDialog(Dlg);
    Dlg.Title:=adrsSaveWindowLayoutToFileXml;
    Dlg.Options:=Dlg.Options+[ofPathMustExist,ofNoReadOnlyReturn,ofOverwritePrompt];
    Dlg.Filter:=adrsAnchorDockingLayout+'|*.xml|'+adrsAllFiles+'|'+GetAllFilesMask;
    if Dlg.Execute then begin
      Filename:=CleanAndExpandFilename(Dlg.FileName);
      if ExtractFileExt(Filename)='' then
        Filename:=Filename+'.xml';
      try
        SaveLayoutToFile(Filename);
      except
        on E: Exception do begin
          IDEMessageDialog(adrsError,
            Format(adrsErrorWritingWindowLayoutToFile, [Filename, #13, E.Message]),
            mtError,[mbCancel]);
        end;
      end;
    end;
    StoreIDEFileDialog(Dlg);
  finally
    Dlg.Free;
  end;
end;

procedure TIDEAnchorDockMaster.SaveLayoutAsDefaultClicked(Sender: TObject);
begin
  SaveUserLayout;
end;

procedure TIDEAnchorDockMaster.IncreaseChangeStamp;
begin
  if FChangeStamp<High(FChangeStamp) then
    inc(FChangeStamp)
  else
    FChangeStamp:=low(FChangeStamp);
end;

{ TAnchorDockIDEFrame }

constructor TAnchorDockIDEFrame.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);

  OptionsFrame:=TAnchorDockOptionsFrame.Create(Self);
  with OptionsFrame do begin
    Name:='OptionsFrame';
  end;
end;

destructor TAnchorDockIDEFrame.Destroy;
begin
  inherited Destroy;
end;

function TAnchorDockIDEFrame.GetTitle: String;
begin
  Result:='Docking / Anchordocking';
end;

procedure TAnchorDockIDEFrame.Setup(ADialog: TAbstractOptionsEditorDialog);
begin
  if ADialog=nil then ;
  if IDEDockMaster=IDEAnchorDockMaster then begin
    NoteLabel.Visible:=false;
    EnableCheckBox.AnchorParallel(akTop,6,Self);
    OptionsFrame.Align:=alBottom;
    OptionsFrame.AnchorToNeighbour(akTop,6,EnableCheckBox);
    OptionsFrame.Parent:=Self;
    EnableCheckBox.Caption:=adrsDockingEnabledRequiresARestartOfTheIDE;
  end else begin
    NoteLabel.Visible:=true;
    NoteLabel.Caption:=Format(adrsToUseAnchordockingYouMustFirstUninstall, [
      DbgSName(IDEDockMaster)]);
    NoteLabel.Hint:=Format(
      adrsThereIsAnotherDockMasterInstalledOnlyOneDockingPac, [DbgSName(
      IDEDockMaster)]);
    EnableCheckBox.Visible:=false;
    OptionsFrame.Parent:=nil;
  end;
end;

procedure TAnchorDockIDEFrame.ReadSettings(AOptions: TAbstractIDEOptions);
begin
  if not (AOptions is SupportedOptionsClass) then exit;
  EnableCheckBox.Checked:=IDEAnchorDockMaster.Enabled;
  OptionsFrame.Master:=DockMaster;
end;

procedure TAnchorDockIDEFrame.WriteSettings(AOptions: TAbstractIDEOptions);
begin
  if not (AOptions is SupportedOptionsClass) then exit;
  IDEAnchorDockMaster.Enabled:=EnableCheckBox.Checked;
  OptionsFrame.SaveToMaster;

end;

class function TAnchorDockIDEFrame.
  SupportedOptionsClass: TAbstractIDEOptionsClass;
begin
  Result:=IDEEditorGroups.GetByIndex(GroupEnvironment)^.GroupClass;
end;

initialization
  // create the dockmaster in the initialization section, so that it is ready
  // when the Register procedures of the packages are called.
  if IDEDockMaster<>nil then begin
    debugln('WARNING: there is already another IDEDockMaster installed.');
    TIDEAnchorDockMaster.Create;
  end else
    IDEDockMaster:=TIDEAnchorDockMaster.Create;

finalization
  FreeAndNil(IDEAnchorDockMaster);

end.

