Code Search for Developers
 
 
  

JvDockControlForm.pas from pyscripter at Krugle


Show JvDockControlForm.pas syntax highlighted

{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.

The Original Code is: JvDockControlForm.pas, released on 2003-12-31.

The Initial Developer of the Original Code is luxiaoban.
Portions created by luxiaoban are Copyright (C) 2002,2003 luxiaoban.
All Rights Reserved.

Contributor(s):
  2005-02-08 - Warren Postma - TJvDockServer.CustomPanel.

Last Modified: 2005-02-08

You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.sourceforge.net

Known Issues:
-----------------------------------------------------------------------------}
// $Id: JvDockControlForm.pas 10674 2006-06-09 07:15:52Z obones $

{ Changes:

  2005-02-08 WP: Added TJvDockServer.CustomDock panel (new property),
  and new event TJvDockServer.OnCustomPanel to get
  a custom parent control (such as the form's center area) for the
  CustomPanel. Previously you could only dock at the edges. Created a
  splitter object (to avoid possible access violations) but the splitter
  control is hidden and never used for this custom panel.  Several
  changes were made  to the VID dock style also to make this custom
  panel more useful,allowing an "tabbed MDI" style application.
}

unit JvDockControlForm;

{$I jvcl.inc}

interface

uses
  {$IFDEF USEJVCL}
  {$IFDEF UNITVERSIONING}
  JclUnitVersioning,
  {$ENDIF UNITVERSIONING}
  {$ENDIF USEJVCL}
  Windows, Messages, Classes, Graphics, Controls, Forms, Menus,
  ExtCtrls, ComCtrls,
  {$IFDEF USEJVCL}
  JvComponentBase, JvAppStorage,
  {$ENDIF USEJVCL}
  JvDockTree, JvDockSupportClass, JvDockSupportControl, JvDockAdvTree;

const
  JvDockPositionCount = 5;

  JvDockState_Unknown = 0;
  JvDockState_Docking = 1;
  JvDockState_Floating = 2;

type
  TJvDockSplitterSize = 0..32767;

  TJvDockBaseControl = class;
  TJvDockServer = class;
  TJvDockClient = class;
  TJvDockConjoinPanel = class;
  TJvDockTabPageControl = class;
  TJvDockConjoinHostForm = class;
  TJvDockTabHostForm = class;

  TJvDockSplitter = class(TJvDockCustomPanelSplitter)
  private
    FDockServer: TJvDockServer;
    function GetSplitterIndex: Integer;
  protected
    function FindControl: TControl; override;
    property DockServer: TJvDockServer read FDockServer write FDockServer;
  public
    constructor Create(AOwner: TComponent); override;
    property SplitterIndex: Integer read GetSplitterIndex;
  end;

  TJvDockSetDockPanelSizeFrom = (sdfDockPanel, sdfClient);

  TJvDockPanel = class(TJvDockCustomPanel)
  private
    FDockServer: TJvDockServer;
    FCustomFlag: Boolean; // Set only if custom area! {NEW}
    function GetPanelIndex: Integer;
    procedure SetDockServer(ADockServer: TJvDockServer);
  protected
    function CreateDockManager: IDockManager; override;
    procedure AddDockServer(ADockServer: TJvDockServer); virtual;
    procedure RemoveDockServer(ADockServer: TJvDockServer); virtual;
    procedure ReloadDockedControl(const AControlName: string;
      var AControl: TControl); override;
    procedure CustomStartDock(var Source: TJvDockDragDockObject); override;
    procedure CustomGetSiteInfo(Source: TJvDockDragDockObject; Client: TControl; var InfluenceRect: TRect;
      MousePos: TPoint; var CanDock: Boolean); override;
    procedure CustomDockOver(Source: TJvDockDragDockObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean); override;
    procedure CustomPositionDockRect(Source: TJvDockDragDockObject; X, Y: Integer); override;
    procedure CustomDockDrop(Source: TJvDockDragDockObject; X, Y: Integer); override;
    procedure CustomEndDock(Target: TObject; X, Y: Integer); override;
    function CustomUnDock(Source: TJvDockDragDockObject; NewTarget: TWinControl; Client: TControl): Boolean; override;
    function DoUnDock(NewTarget: TWinControl; Client: TControl): Boolean; override;
    procedure Resize; override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure DockDrop(Source: TDragDockObject; X, Y: Integer); override;

    procedure ShowDockPanel(MakeVisible: Boolean; Client: TControl;
      PanelSizeFrom: TJvDockSetDockPanelSizeFrom = sdfClient); virtual;
    procedure ResetPosition;
    // GetDockedControls:  NEW! -WPostma.
    // base class doesn't have this capability.
    // see TJvDockAdvPanel for override that implements this!
    procedure GetDockedControls(WinControls: TList); virtual;

    property PanelIndex: Integer read GetPanelIndex;
    property DockServer: TJvDockServer read FDockServer write SetDockServer;
    property CustomFlag: Boolean read FCustomFlag write FCustomFlag; // Set only if custom area! {NEW}
  end;

  TJvDockAdvPanel = class(TJvDockPanel)
  private
    procedure CMUnDockClient(var Msg: TCMUnDockClient); message CM_UNDOCKCLIENT;
  protected
    procedure CustomDockDrop(Source: TJvDockDragDockObject; X, Y: Integer); override;
    function CustomUnDock(Source: TJvDockDragDockObject; NewTarget: TWinControl; Client: TControl): Boolean; override;
    function DoUnDock(NewTarget: TWinControl; Client: TControl): Boolean; override;
  public
    procedure GetDockedControls(WinControls: TList); override;
    procedure DockDrop(Source: TDragDockObject; X, Y: Integer); override;
  end;

  TJvDockPanelClass = class of TJvDockPanel;
  TJvDockSplitterClass = class of TJvDockSplitter;
  TJvDockConjoinPanelClass = class of TJvDockConjoinPanel;
  TJvDockTabClass = class of TJvDockTabPageControl;

  { Maintained by a TJvDockServer; TJvDockServer ensures that FDockServer is
    assigned. FSplitter may be nil }
  TJvDockSplitterStyle = class(TPersistent)
  private
    FSplitter: TJvDockSplitter;
    FDockServer: TJvDockServer;
    FColor: TColor;
    FCursor: TCursor;
    FParentColor: Boolean;
    FResizeStyle: TResizeStyle;
    FSize: TJvDockSplitterSize;
    FMinSize: TJvDockSplitterSize;
    procedure SetColor(const Value: TColor);
    procedure SetCursor(const Value: TCursor);
    procedure SetParentColor(const Value: Boolean);
    procedure SetResizeStyle(const Value: TResizeStyle);
    procedure SetSize(const Value: TJvDockSplitterSize);
    procedure SetMinSize(const Value: TJvDockSplitterSize);
  protected
    procedure AssignTo(Dest: TPersistent); override;
    procedure AssignToSplitter(Dest: TJvDockSplitter);
    procedure SetSplitterStyle;
    property Splitter: TJvDockSplitter read FSplitter write FSplitter;
  public
    constructor Create(ASplitter: TJvDockSplitter; ACursor: TCursor); virtual;
    procedure Assign(Source: TPersistent); override;
  published
    property Color: TColor read FColor write SetColor default clBtnFace;
    property Cursor: TCursor read FCursor write SetCursor;
    property ParentColor: Boolean read FParentColor write SetParentColor default True;
    property ResizeStyle: TResizeStyle read FResizeStyle write SetResizeStyle default rsPattern;
    property Size: TJvDockSplitterSize read FSize write SetSize default 3;
    property MinSize: TJvDockSplitterSize read FMinSize write SetMinSize default 30;
  end;

  TJvDockBasicStyle = class;

  TJvDockBasicStyle = class(TJvDockObservableStyle)
  private
    FDockPanelClass: TJvDockPanelClass;
    FDockSplitterClass: TJvDockSplitterClass;
    FConjoinPanelClass: TJvDockConjoinPanelClass;
    FTabDockClass: TJvDockTabClass;
    FDockPanelTreeClass: TJvDockTreeClass;
    FDockPanelZoneClass: TJvDockZoneClass;
    FConjoinPanelTreeClass: TJvDockTreeClass;
    FConjoinPanelZoneClass: TJvDockZoneClass;
    FDockBaseControls: TList;
    function GetDockBaseControlCount: Integer;
    function GetDockBaseControl(Index: Integer): TJvDockBaseControl;
  protected
    procedure FormStartDock(DockClient: TJvDockClient; var Source: TJvDockDragDockObject); virtual;
    procedure FormGetSiteInfo(Source: TJvDockDragDockObject; DockClient: TJvDockClient; Client: TControl;
      var InfluenceRect: TRect; MousePos: TPoint; var CanDock: Boolean); virtual;
    procedure FormDockOver(DockClient: TJvDockClient; Source: TJvDockDragDockObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean); virtual;
    procedure FormPositionDockRect(DockClient: TJvDockClient; Source: TJvDockDragDockObject); virtual;
    procedure FormDockDrop(DockClient: TJvDockClient; Source: TJvDockDragDockObject; X, Y: Integer); virtual;
    procedure FormEndDock(DockClient: TJvDockClient; Target: TObject; X, Y: Integer); virtual;
    function FormUnDock(DockClient: TJvDockClient; NewTarget: TWinControl; Client: TControl): Boolean; virtual;
    procedure FormGetDockEdge(DockClient: TJvDockClient; Source: TJvDockDragDockObject;
      MousePos: TPoint; var DropAlign: TAlign); virtual;

    procedure SetDockBaseControl(IsCreate: Boolean; DockBaseControl: TJvDockBaseControl); virtual;
    function DockServerWindowProc(DockServer: TJvDockServer; var Msg: TMessage): Boolean; virtual;
    function DockClientWindowProc(DockClient: TJvDockClient; var Msg: TMessage): Boolean; virtual;
    procedure AddDockBaseControl(ADockBaseControl: TJvDockBaseControl); virtual;
    procedure RemoveDockBaseControl(ADockBaseControl: TJvDockBaseControl); virtual;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    function CanSetEnableDocked(ADockBaseControl: TJvDockBaseControl): Boolean; virtual;
    function CanSetLeftDocked(ADockBaseControl: TJvDockBaseControl): Boolean; virtual;
    function CanSetRightDocked(ADockBaseControl: TJvDockBaseControl): Boolean; virtual;
    function CanSetTopDocked(ADockBaseControl: TJvDockBaseControl): Boolean; virtual;
    function CanSetBottomDocked(ADockBaseControl: TJvDockBaseControl): Boolean; virtual;
    function CanSetEachOtherDocked(ADockBaseControl: TJvDockBaseControl): Boolean; virtual;
    {$IFNDEF USEJVCL}
    function GetControlName: string; virtual;
    function GetDockStyleVersion: string; virtual;
    {$ENDIF !USEJVCL}

    procedure ResetCursor(Source: TJvDockDragDockObject); virtual;

    function GetDockState(DockClient: TJvDockClient): Integer; virtual;

    procedure DoShowDockForm(DockWindow: TWinControl); virtual;
    procedure DoHideDockForm(DockWindow: TWinControl); virtual;

    procedure ShowDockForm(ADockClient: TJvDockClient); virtual;
    procedure HideDockForm(ADockClient: TJvDockClient); virtual;
    function GetDockFormVisible(ADockClient: TJvDockClient): Boolean; virtual;

    property DockBaseControlCount: Integer read GetDockBaseControlCount;
    property DockBaseControl[Index: Integer]: TJvDockBaseControl read GetDockBaseControl;

    procedure RestoreClient(DockClient: TJvDockClient); virtual;
    {$IFNDEF USEJVCL}
    property Version: string read GetDockStyleVersion;
    property ControlName: string read GetControlName;
    {$ENDIF !USEJVCL}
    property DockPanelClass: TJvDockPanelClass read FDockPanelClass write FDockPanelClass;
    property DockSplitterClass: TJvDockSplitterClass read FDockSplitterClass write FDockSplitterClass;
    property ConjoinPanelClass: TJvDockConjoinPanelClass read FConjoinPanelClass write FConjoinPanelClass;
    property TabDockClass: TJvDockTabClass read FTabDockClass write FTabDockClass;
    property DockPanelTreeClass: TJvDockTreeClass read FDockPanelTreeClass write FDockPanelTreeClass;
    property DockPanelZoneClass: TJvDockZoneClass read FDockPanelZoneClass write FDockPanelZoneClass;
    property ConjoinPanelTreeClass: TJvDockTreeClass read FConjoinPanelTreeClass write FConjoinPanelTreeClass;
    property ConjoinPanelZoneClass: TJvDockZoneClass read FConjoinPanelZoneClass write FConjoinPanelZoneClass;
  end;

  TJvDockAdvStyle = class(TJvDockBasicStyle)
  protected
    function DockClientWindowProc(DockClient: TJvDockClient; var Msg: TMessage): Boolean; override;
  end;

  {$IFDEF USEJVCL}
  TJvDockBaseControl = class(TJvComponent)
  {$ELSE}
  TJvDockBaseControl = class(TComponent)
  {$ENDIF USEJVCL}
  private
    FEnableDock: Boolean;
    FLeftDock: Boolean; { Can the parent form be docked into the Left dock? }
    FTopDock: Boolean; { Can the parent form be docked into the Top dock? }
    FRightDock: Boolean; { Can the parent form be docked into the Right dock? }
    FBottomDock: Boolean; { Can the parent form be docked into the Bottom dock? }
    FCustomDock: Boolean; {NEW!  Can the parent form be docked into the Custom (center window) dock area? }
    FEachOtherDock: Boolean;
    FDockStyle: TJvDockBasicStyle;
    FOldOnClose: TCloseEvent;
    FOldOnCreate: TNotifyEvent;
    FParentForm: TForm;
    FOldWindowProc: TWndMethod;
    procedure SetDockStyle(ADockStyle: TJvDockBasicStyle);
  protected
    procedure SetParentComponent(Value: TComponent); override;

    function CanSetEnableDocked: Boolean; virtual;
    function CanSetLeftDocked: Boolean; virtual;
    function CanSetRightDocked: Boolean; virtual;
    function CanSetTopDocked: Boolean; virtual;
    function CanSetBottomDocked: Boolean; virtual;
    function CanSetEachOtherDocked: Boolean; virtual;

    procedure DoFormOnClose(Sender: TObject; var Action: TCloseAction); virtual;
    procedure DoFormOnCreate(Sender: TObject); virtual;

    procedure SetBottomDock(const Value: Boolean); virtual;
    procedure SetEachOtherDock(const Value: Boolean); virtual;
    procedure SetEnableDock(const Value: Boolean); virtual;
    procedure SetLeftDock(const Value: Boolean); virtual;
    procedure SetRightDock(const Value: Boolean); virtual;
    procedure SetTopDock(const Value: Boolean); virtual;

    procedure AddDockStyle(ADockStyle: TJvDockBasicStyle); virtual;
    procedure RemoveDockStyle(ADockStyle: TJvDockBasicStyle); virtual;

    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure WindowProc(var Msg: TMessage); virtual;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    {$IFNDEF USEJVCL}
    function GetDockStyleVersion: string; virtual;
    {$ENDIF !USEJVCL}
    { Owner of this component }
    property ParentForm: TForm read FParentForm;
    property EnableDock: Boolean read FEnableDock write SetEnableDock default True;
    property LeftDock: Boolean read FLeftDock write SetLeftDock default True;
    property TopDock: Boolean read FTopDock write SetTopDock default True;
    property RightDock: Boolean read FRightDock write SetRightDock default True;
    property BottomDock: Boolean read FBottomDock write SetBottomDock default True;
    property EachOtherDock: Boolean read FEachOtherDock write SetEachOtherDock default True;
    property CustomDock: Boolean read FCustomDock write FCustomDock default True; {NEW!}
    property DockStyle: TJvDockBasicStyle read FDockStyle write SetDockStyle;
    {$IFNDEF USEJVCL}
    property Version: string read GetDockStyleVersion;
    {$ENDIF !USEJVCL}
  end;

  TJvDockCustomPanelEvent = procedure(Sender: TJvDockServer;
    var AParent: TWinControl; var Align: TAlign) of object; {NEW!}
  TJvDockCheckDockableEvent = procedure(DockClient: TJvDockClient; DockForm: TForm;
    DockServer: TJvDockServer; DockPanel: TJvDockPanel; var CanDock: Boolean) of object; {NEW!}
  TJvDockTabHostFormCreatedEvent = procedure(DockClient: TJvDockClient;
    TabHost: TJvDockTabHostForm) of object;

  TJvDockGetClientAlignSizeEvent = procedure(Align: TAlign; var Value: Integer) of object;
  TJvDockFinishSetDockPanelSizeEvent = procedure(DockPanel: TJvDockPanel) of object;

  {

    TJvDockServer is the Creator of 4 panels and 4 splitters that are placed on
    the form that contains the TJvDockServer. The type of the panels and splitters
    is determined by the DockStyle.

    o  TJvDockServer maintains the panels and splitters. If the dock server is
       destroyed then the panels and splitters are destroyed.
    o  If the DockStyle is changed then the panels+splitters are destroyed and
       recreated.
    o  If DockStyle is set to nil then the panels+splitters are nil.
  }

  TJvDockPosition = (dpLeft, dpRight, dpTop, dpBottom, dpCustom); {dpCustom NEW!}

  TJvDockServer = class(TJvDockBaseControl)
  private
    FDockPanelClass: TJvDockPanelClass;
    FDockPanels: array [TJvDockPosition] of TJvDockPanel;
    FDockSplitterClass: TJvDockSplitterClass;
    FSplitters: array [TJvDockPosition] of TJvDockSplitter;
    FSplitterStyles: array [TJvDockPosition] of TJvDockSplitterStyle;
    FOnCustomPanel: TJvDockCustomPanelEvent; // Self, AParent, Align
    FOnGetClientAlignSize: TJvDockGetClientAlignSizeEvent;
    FOnFinishSetDockPanelSize: TJvDockFinishSetDockPanelSizeEvent;
    FAutoFocusDockedForm: Boolean;
    procedure CreateDockPanelAndSplitter;
    procedure DestroyDockPanelAndSplitter;
    procedure CreateSplitterStyle;
    procedure DestroySplitterStyle;
    procedure SetSplitterStyles;
    procedure DoGetClientAlignControl(Align: TAlign; var Value: Integer);
    function GetDockPanel(DockPosition: TJvDockPosition): TJvDockPanel;
    function GetDockPanelIndex(const Index: Integer): TJvDockPanel;
    function GetDockPanelWithAlign(Index: TAlign): TJvDockPanel;
    function GetDockSplitterWithAlign(Index: TAlign): TJvDockSplitter;
    function GetSplitter(DockPosition: TJvDockPosition): TJvDockSplitter;
    function GetSplitterIndex(const Index: Integer): TJvDockSplitter;
    function GetSplitterStyle(DockPosition: TJvDockPosition): TJvDockSplitterStyle;
    function GetSplitterStyleIndex(const Index: Integer): TJvDockSplitterStyle;
    procedure SetSplitterStyle(DockPosition: TJvDockPosition; ASplitterStyle: TJvDockSplitterStyle);
    procedure SetSplitterStyleIndex(const Index: Integer; ASplitterStyle: TJvDockSplitterStyle);
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure DoFinishSetDockPanelSize(DockPanel: TJvDockPanel);
    procedure DoFloatDockClients(DockPanel: TJvDockPanel);
    procedure SetBottomDock(const Value: Boolean); override;
    procedure SetEnableDock(const Value: Boolean); override;
    procedure SetLeftDock(const Value: Boolean); override;
    procedure SetRightDock(const Value: Boolean); override;
    procedure SetTopDock(const Value: Boolean); override;

    procedure AddDockStyle(ADockStyle: TJvDockBasicStyle); override;
    procedure RemoveDockStyle(ADockStyle: TJvDockBasicStyle); override;

    procedure WMActivate(var Msg: TWMActivate);
    procedure WindowProc(var Msg: TMessage); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    function GetClientAlignControl(Align: TAlign): Integer;

    property DockPanel[DockPosition: TJvDockPosition]: TJvDockPanel read GetDockPanel;
    property Splitter[DockPosition: TJvDockPosition]: TJvDockSplitter read GetSplitter;
    property SplitterStyle[DockPosition: TJvDockPosition]: TJvDockSplitterStyle read GetSplitterStyle write
      SetSplitterStyle;

    property LeftDockPanel: TJvDockPanel index 0 read GetDockPanelIndex;
    property RightDockPanel: TJvDockPanel index 1 read GetDockPanelIndex;
    property TopDockPanel: TJvDockPanel index 2 read GetDockPanelIndex;
    property BottomDockPanel: TJvDockPanel index 3 read GetDockPanelIndex;
    property CustomDockPanel: TJvDockPanel index 4 read GetDockPanelIndex;

    property LeftSplitter: TJvDockSplitter index 0 read GetSplitterIndex;
    property RightSplitter: TJvDockSplitter index 1 read GetSplitterIndex;
    property TopSplitter: TJvDockSplitter index 2 read GetSplitterIndex;
    property BottomSplitter: TJvDockSplitter index 3 read GetSplitterIndex;

    property DockPanelWithAlign[Index: TAlign]: TJvDockPanel read GetDockPanelWithAlign;
    property DockSplitterWithAlign[Index: TAlign]: TJvDockSplitter read GetDockSplitterWithAlign;
    {$IFNDEF USEJVCL}
    property Version: string read GetDockStyleVersion;
    {$ENDIF !USEJVCL}
  published
    property LeftSplitterStyle: TJvDockSplitterStyle index 0 read GetSplitterStyleIndex write SetSplitterStyleIndex;
    property RightSplitterStyle: TJvDockSplitterStyle index 1 read GetSplitterStyleIndex write SetSplitterStyleIndex;
    property TopSplitterStyle: TJvDockSplitterStyle index 2 read GetSplitterStyleIndex write SetSplitterStyleIndex;
    property BottomSplitterStyle: TJvDockSplitterStyle index 3 read GetSplitterStyleIndex write SetSplitterStyleIndex;
    property AutoFocusDockedForm: Boolean read FAutoFocusDockedForm write FAutoFocusDockedForm default True;
    property EnableDock;
    property LeftDock;
    property TopDock;
    property RightDock;
    property BottomDock;
    property DockStyle;
    property CustomDock;
    property OnGetClientAlignSize: TJvDockGetClientAlignSizeEvent read FOnGetClientAlignSize
      write FOnGetClientAlignSize;
    property OnFinishSetDockPanelSize: TJvDockFinishSetDockPanelSizeEvent read FOnFinishSetDockPanelSize
      write FOnFinishSetDockPanelSize;
    property OnCustomPanel: TJvDockCustomPanelEvent read FOnCustomPanel write FOnCustomPanel; {NEW!}
  end;

  TJvDockMouseStation = (msFloat, msConjoin, msTabPage);

  TJvDockNCButtonEvent = procedure(DockClient: TJvDockClient; Button: TMouseButton;
    X, Y: Smallint; HitTest: Longint; MouseStation: TJvDockMouseStation) of object;
  TJvDockNCButtonDownEvent = TJvDockNCButtonEvent;
  TJvDockNCButtonUpEvent = TJvDockNCButtonEvent;
  TJvDockNCButtonDblClkEvent = TJvDockNCButtonEvent;
  TJvDockNCMouseMoveEvent = procedure(DockClient: TJvDockClient;
    X, Y: Smallint; HitTest: Longint; MouseStation: TJvDockMouseStation) of object;
  TJvDockPaintDockEvent = procedure(Canvas: TCanvas;
    Control: TControl; const ARect: TRect) of object;
  TJvDockPaintDockGrabberEvent = TJvDockPaintDockEvent;
  TJvDockPaintDockSplitterEvent = TJvDockPaintDockEvent;
  TJvDockFormHintEvent = procedure(HTFlag: Integer; var HintStr: string; var CanShow: Boolean) of object;

  TJvDockClient = class(TJvDockBaseControl)
  private
    FConjoinPanelClass: TJvDockConjoinPanelClass;
    FTabDockClass: TJvDockTabClass;
    FParentVisible: Boolean;
    FNCPopupMenu: TPopupMenu;
    FDirectDrag: Boolean;
    FShowHint: Boolean;
    FCanFloat: Boolean;
    FDockLevel: Integer;
    FEnableCloseButton: Boolean;
    FOnNCButtonDown: TJvDockNCButtonDownEvent;
    FOnNCButtonUp: TJvDockNCButtonUpEvent;
    FOnNCMouseMove: TJvDockNCMouseMoveEvent;
    FOnNCButtonDblClk: TJvDockNCButtonDblClkEvent;
    FOnPaintDockGrabber: TJvDockPaintDockGrabberEvent;
    FOnPaintDockSplitter: TJvDockPaintDockSplitterEvent;
    FOnFormShowHint: TJvDockFormHintEvent;
    FOnFormShow: TNotifyEvent;
    FOnFormHide: TNotifyEvent;
    FOnCheckIsDockable: TJvDockCheckDockableEvent; {NEW!}
    FOnTabHostFormCreated: TJvDockTabHostFormCreatedEvent; {NEW!}
    FCurrentDockSite: TWinControl;
    FLastDockSite: TWinControl;
    FUnDockLeft: Integer;
    FUnDockTop: Integer;
    FVSPaneWidth: Integer;
    procedure SetParentVisible(const Value: Boolean);
    function GetLRDockWidth: Integer;
    function GetTBDockHeight: Integer;
    procedure SetLRDockWidth(const Value: Integer);
    procedure SetTBDockHeight(const Value: Integer);
    procedure SetNCPopupMenu(Value: TPopupMenu);
    procedure WMNCLButtonDown(var Msg: TWMNCHitMessage);
    procedure WMNCLButtonUp(var Msg: TWMNCHitMessage);
    procedure WMNCLButtonDblClk(var Msg: TWMNCHitMessage);
    procedure WMNCMButtonDown(var Msg: TWMNCHitMessage);
    procedure WMNCMButtonUp(var Msg: TWMNCHitMessage);
    procedure WMNCMButtonDblClk(var Msg: TWMNCHitMessage);
    procedure WMNCRButtonDown(var Msg: TWMNCHitMessage);
    procedure WMNCRButtonUp(var Msg: TWMNCHitMessage);
    procedure WMNCRButtonDblClk(var Msg: TWMNCHitMessage);
    procedure WMNCMouseMove(var Msg: TWMNCHitMessage);
    procedure CMVisibleChanged(var Msg: TMessage);
    procedure SetCurrentDockSite(const Value: TWinControl);
    procedure SetLastDockSite(ALastDockSite: TWinControl);
    procedure SetVSPaneWidth(const Value: Integer);
    procedure SetUnDockLeft(const Value: Integer);
    procedure SetUnDockTop(const Value: Integer);
    function GetDockState: Integer;
    procedure SetCanFloat(const Value: Boolean);
    procedure SetDockLevel(const Value: Integer);
    procedure SetEnableCloseButton(const Value: Boolean);
  protected
    procedure DoMenuPopup(X, Y: Integer); virtual;
    procedure Deactivate; virtual;
    procedure Activate; virtual;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure DoFloatDockClients(PanelAlign: TAlign);
    procedure DoFloatDockEachOther;
    procedure SetBottomDock(const Value: Boolean); override;
    procedure SetEachOtherDock(const Value: Boolean); override;
    procedure SetEnableDock(const Value: Boolean); override;
    procedure SetLeftDock(const Value: Boolean); override;
    procedure SetRightDock(const Value: Boolean); override;
    procedure SetTopDock(const Value: Boolean); override;
    procedure DoFormOnClose(Sender: TObject; var Action: TCloseAction); override;
    procedure AddDockStyle(ADockStyle: TJvDockBasicStyle); override;
    procedure RemoveDockStyle(ADockStyle: TJvDockBasicStyle); override;
    procedure WMSize(var Msg: TWMSize);
    procedure WMActivate(var Msg: TWMActivate);
    procedure WindowProc(var Msg: TMessage); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure FormStartDock(var Source: TJvDockDragDockObject); virtual;
    procedure FormPositionDockRect(Source: TJvDockDragDockObject); virtual;
    procedure FormDockOver(Source: TJvDockDragDockObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean); virtual;
    procedure FormDockDrop(Source: TJvDockDragDockObject; X, Y: Integer); virtual;
    procedure FormEndDock(Target: TObject; X, Y: Integer); virtual;
    function FormUnDock(NewTarget: TWinControl; Client: TControl): Boolean; virtual;
    procedure FormGetSiteInfo(Source: TJvDockDragDockObject;
      Client: TControl; var InfluenceRect: TRect; MousePos: TPoint;
      var CanDock: Boolean); virtual;
    procedure FormGetDockEdge(Source: TJvDockDragDockObject; MousePos: TPoint; var DropAlign: TAlign); virtual;
    procedure Assign(Source: TPersistent); override;
    procedure MakeShowEvent;
    procedure MakeHideEvent;
    function CreateConjoinPanelClass(ConjoinHost: TForm): TJvDockConjoinPanel;
    function CreateTabDockClass(TabHost: TForm): TJvDockTabPageControl;
    function CreateConjoinHostAndDockControl(Control1, Control2: TControl;
      DockType: TAlign): TJvDockConjoinHostForm; virtual;
    function CreateTabHostAndDockControl(Control1, Control2: TControl): TJvDockTabHostForm; virtual;

    function FindTabHostForm: TForm;
    // return nil if not found, otherwise, get currently docked parent tabhost form if there is one.

    procedure DoNCButtonDown(Msg: TWMNCHitMessage; Button: TMouseButton;
      MouseStation: TJvDockMouseStation); virtual;
    procedure DoNCButtonUp(Msg: TWMNCHitMessage; Button: TMouseButton;
      MouseStation: TJvDockMouseStation); virtual;
    procedure DoNCMouseMove(Msg: TWMNCHitMessage;
      MouseStation: TJvDockMouseStation); virtual;
    procedure DoNCButtonDblClk(Msg: TWMNCHitMessage; Button: TMouseButton;
      MouseStation: TJvDockMouseStation); virtual;

    procedure DoPaintDockGrabber(Canvas: TCanvas;
      Control: TControl; const ARect: TRect);
    procedure DoPaintDockSplitter(Canvas: TCanvas;
      Control: TControl; const ARect: TRect);
    procedure DoFormShowHint(HTFlag: Integer; var HintStr: string; var CanShow: Boolean);
    procedure ShowParentForm;
    procedure HideParentForm;
    procedure RestoreChild;
    property VSPaneWidth: Integer read FVSPaneWidth write SetVSPaneWidth;
    property ParentVisible: Boolean read FParentVisible write SetParentVisible;
    { (rb) not used? }
    property CurrentDockSite: TWinControl read FCurrentDockSite write SetCurrentDockSite;
    property LastDockSite: TWinControl read FLastDockSite write SetLastDockSite;
    property UnDockLeft: Integer read FUnDockLeft write SetUnDockLeft;
    property UnDockTop: Integer read FUnDockTop write SetUnDockTop;
    property DockState: Integer read GetDockState;
  published
    property LRDockWidth: Integer read GetLRDockWidth write SetLRDockWidth default 100;
    property TBDockHeight: Integer read GetTBDockHeight write SetTBDockHeight default 100;
    property NCPopupMenu: TPopupMenu read FNCPopupMenu write SetNCPopupMenu;
    property DirectDrag: Boolean read FDirectDrag write FDirectDrag;
    property ShowHint: Boolean read FShowHint write FShowHint default True;
    property CanFloat: Boolean read FCanFloat write SetCanFloat default True;
    { Not implemented; intention: only forms with the same DockLevel could be docked together }
    property DockLevel: Integer read FDockLevel write SetDockLevel default 0;
    property EnableCloseButton: Boolean read FEnableCloseButton write SetEnableCloseButton default True;
    property EnableDock;
    property LeftDock;
    property TopDock;
    property RightDock;
    property BottomDock;
    property EachOtherDock;
    property DockStyle;
    property CustomDock;
    property OnFormShow: TNotifyEvent read FOnFormShow write FOnFormShow;
    property OnFormHide: TNotifyEvent read FOnFormHide write FOnFormHide;
    property OnCheckIsDockable: TJvDockCheckDockableEvent read FOnCheckIsDockable write FOnCheckIsDockable; {NEW!}
    property OnTabHostFormCreated: TJvDockTabHostFormCreatedEvent read FOnTabHostFormCreated
      write FOnTabHostFormCreated; {NEW!}
    property OnNCButtonDown: TJvDockNCButtonDownEvent read FOnNCButtonDown write FOnNCButtonDown;
    property OnNCButtonUp: TJvDockNCButtonUpEvent read FOnNCButtonUp write FOnNCButtonUp;
    property OnNCMouseMove: TJvDockNCMouseMoveEvent read FOnNCMouseMove write FOnNCMouseMove;
    property OnNCButtonDblClk: TJvDockNCButtonDblClkEvent read FOnNCButtonDblClk write FOnNCButtonDblClk;
    property OnPaintDockGrabber: TJvDockPaintDockGrabberEvent read FOnPaintDockGrabber write FOnPaintDockGrabber;
    property OnPaintDockSplitter: TJvDockPaintDockSplitterEvent read FOnPaintDockSplitter write FOnPaintDockSplitter;
    property OnFormShowHint: TJvDockFormHintEvent read FOnFormShowHint write FOnFormShowHint;
  end;

  { Maintained by a TJvDockConjoinHostForm; That is (always) the owner, ie.
    that is assumed on multiple places in the code) }
  TJvDockConjoinPanel = class(TJvDockCustomPanel)
  private
    function GetDockClient: TJvDockClient;
    function GetParentForm: TJvDockConjoinHostForm;
    procedure CMUnDockClient(var Msg: TCMUnDockClient); message CM_UNDOCKCLIENT;
  protected
    function CreateDockManager: IDockManager; override;
    procedure ReloadDockedControl(const AControlName: string; var AControl: TControl); override;
    procedure CustomStartDock(var Source: TJvDockDragDockObject); override;
    procedure CustomGetSiteInfo(Source: TJvDockDragDockObject;
      Client: TControl; var InfluenceRect: TRect; MousePos: TPoint;
      var CanDock: Boolean); override;
    procedure CustomDockOver(Source: TJvDockDragDockObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean); override;
    procedure CustomPositionDockRect(Source: TJvDockDragDockObject; X, Y: Integer); override;
    procedure CustomDockDrop(Source: TJvDockDragDockObject; X, Y: Integer); override;
    procedure CustomEndDock(Target: TObject; X, Y: Integer); override;
    function CustomUnDock(Source: TJvDockDragDockObject; NewTarget: TWinControl;
      Client: TControl): Boolean; override;
    procedure DoDockOver(Source: TDragDockObject; X, Y: Integer; State: TDragState;
      var Accept: Boolean); override;
    procedure GetSiteInfo(Client: TControl; var InfluenceRect: TRect;
      MousePos: TPoint; var CanDock: Boolean); override;
    function DoUnDock(NewTarget: TWinControl; Client: TControl): Boolean; override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure DockDrop(Source: TDragDockObject; X, Y: Integer); override;
    { DockClient of the Owner }
    property DockClient: TJvDockClient read GetDockClient;
    { ParentForm is the Owner }
    property ParentForm: TJvDockConjoinHostForm read GetParentForm;
  end;

  TJvDockAdvConjoinPanel = class(TJvDockConjoinPanel)
  private
    procedure CMUnDockClient(var Msg: TCMUnDockClient); message CM_UNDOCKCLIENT;
  protected
    procedure CustomDockDrop(Source: TJvDockDragDockObject; X, Y: Integer); override;
    function CustomUnDock(Source: TJvDockDragDockObject; NewTarget: TWinControl;
      Client: TControl): Boolean; override;
    function DoUnDock(NewTarget: TWinControl; Client: TControl): Boolean; override;
  public
    procedure DockDrop(Source: TDragDockObject; X, Y: Integer); override;
  end;

  { Maintained by a TJvDockTabHostForm; That is (always) the owner, ie.
    that is assumed on multiple places in the code) }
  TJvDockTabPageControl = class(TJvDockPageControl)
  private
    FVersion: Integer;
    FStyleLink: TJvDockStyleLink;
    function GetParentForm: TJvDockTabHostForm;
    procedure DockStyleChanged(Sender: TObject);
    function GetDockStyle: TJvDockObservableStyle;
  protected
    procedure AdjustClientRect(var Rect: TRect); override;
    procedure ReloadDockedControl(const AControlName: string;
      var AControl: TControl); override;
    procedure CustomStartDock(var Source: TJvDockDragDockObject); override;
    procedure CustomGetSiteInfo(Source: TJvDockDragDockObject; Client: TControl;
      var InfluenceRect: TRect; MousePos: TPoint; var CanDock: Boolean); override;
    procedure CustomDockOver(Source: TJvDockDragDockObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean); override;
    procedure CustomPositionDockRect(Source: TJvDockDragDockObject; X, Y: Integer); override;
    procedure CustomDockDrop(Source: TJvDockDragDockObject; X, Y: Integer); override;
    procedure CustomEndDock(Target: TObject; X, Y: Integer); override;
    function CustomUnDock(Source: TJvDockDragDockObject; NewTarget: TWinControl;
      Client: TControl): Boolean; override;
    procedure CustomGetDockEdge(Source: TJvDockDragDockObject; MousePos: TPoint;
      var DropAlign: TAlign); override;
    function DoUnDock(NewTarget: TWinControl; Client: TControl): Boolean; override;

    procedure SyncWithStyle; virtual;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure AfterConstruction; override;
    procedure DockDrop(Source: TDragDockObject; X, Y: Integer); override;
    procedure LoadFromStream(Stream: TStream); virtual;
    procedure SaveToStream(Stream: TStream); virtual;
    { ParentForm is the Owner }
    property ParentForm: TJvDockTabHostForm read GetParentForm;
    property TabPosition;
    property DockStyle: TJvDockObservableStyle read GetDockStyle;
  end;

  TJvDockAdvTabPageControl = class(TJvDockTabPageControl)
  private
    procedure CMUnDockClient(var Msg: TCMUnDockClient); message CM_UNDOCKCLIENT;
  protected
    procedure CustomDockDrop(Source: TJvDockDragDockObject; X, Y: Integer); override;
    function CustomUnDock(Source: TJvDockDragDockObject; NewTarget: TWinControl;
      Client: TControl): Boolean; override;
    function DoUnDock(NewTarget: TWinControl; Client: TControl): Boolean; override;
  public
    destructor Destroy; override;
    procedure DockDrop(Source: TDragDockObject; X, Y: Integer); override;
  end;

  { A TJvDockableForm is a base class for TJvDockConjoinHostForm
     and TJvDockTabHostForm which are the base classes for the two kinds of
     docked-views possible for handling multiple controls docked to the same
     dock site. }
  TJvDockableForm = class(TForm)
  private
    FDockClient: TJvDockClient;
    FDockableControl: TWinControl;
    FUnDockControl: TControl;
    FFloatingChild: TControl;
    function GetDockableControl: TWinControl;
    procedure SetDockableControl(const Value: TWinControl);
    procedure SetUnDockControl(const Value: TControl);
  protected
    procedure DoClose(var Action: TCloseAction); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    { Fixed DockClient owned by the component }
    property DockClient: TJvDockClient read FDockClient;
    { Either a TJvDockTabPageControl or a TJvDockConjoinPanel, assigned on
      construction of the dockable form }
    property DockableControl: TWinControl read GetDockableControl write SetDockableControl;
    { ?? Probably needs notification }
    property UnDockControl: TControl read FUnDockControl write SetUnDockControl;
    { ?? Probably needs notification }
    property FloatingChild: TControl read FFloatingChild;
  end;

  TJvDockConjoinHostForm = class(TJvDockableForm)
  private
    FPanel: TJvDockConjoinPanel;
  protected
    procedure DoClose(var Action: TCloseAction); override;
  public
    constructor Create(AOwner: TComponent); override;
    property DockClient;
    { Constructed in TJvDockClient.CreateConjoinPanelClass }
    property Panel: TJvDockConjoinPanel read FPanel write FPanel;
  end;

  TJvDockTabHostForm = class(TJvDockableForm)
  private
    FPageControl: TJvDockTabPageControl;
  public
    constructor Create(AOwner: TComponent); override;
    procedure ShowDockedControl(AControl:TWinControl); virtual; // If aControl is docked in PageControl, change PageControl to that page. NEW! WPostma.
    procedure UpdateCaption(AControl:TWinControl); virtual; // update tab host's tabs and title bar when page caption changes.

    function GetActiveDockForm: TForm;
    property DockClient;
    { Constructed in TJvDockClient.CreateTabDockClass }
    property PageControl: TJvDockTabPageControl read FPageControl write FPageControl;
  end;

  TJvGlobalDockManager = class(TJvDockManager)
  private
    FDockServers: TList;
    FDockClients: TList;
    FDockableForms: TList;
    function GetDockClient(const Index: Integer): TJvDockClient;
    function GetDockClientCount: Integer;
    function GetDockServer(const Index: Integer): TJvDockServer;
    function GetDockServerCount: Integer;
    function GetDockableForm(const Index: Integer): TJvDockableForm;
    function GetDockableFormCount: Integer;
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure RegisterDockServer(ADockServer: TJvDockServer);
    procedure RegisterDockClient(ADockClient: TJvDockClient);
    procedure RegisterDockableForm(ADockableForm: TJvDockableForm);
    procedure UnRegisterDockServer(ADockServer: TJvDockServer);
    procedure UnRegisterDockClient(ADockClient: TJvDockClient);
    procedure UnRegisterDockableForm(ADockableForm: TJvDockableForm);
    function FindDockServerForm(const AName: string): TControl;
    function FindDockClientForm(const AName: string): TControl;
    function FindDockControlForm(const AName: string): TControl;

    property DockServer[const Index: Integer]: TJvDockServer read GetDockServer;
    property DockClient[const Index: Integer]: TJvDockClient read GetDockClient;
    property DockableForm[const Index: Integer]: TJvDockableForm read GetDockableForm;
    property DockServerCount: Integer read GetDockServerCount;
    property DockClientCount: Integer read GetDockClientCount;
    property DockableFormCount: Integer read GetDockableFormCount;
  end;

var
  DefaultDockPanelClass: TJvDockPanelClass = TJvDockPanel;
  DefaultDockSplitterClass: TJvDockSplitterClass = TJvDockSplitter;
  DefaultConjoinPanelClass: TJvDockConjoinPanelClass = TJvDockConjoinPanel;
  DefaultTabDockClass: TJvDockTabClass = TJvDockTabPageControl;
  DefaultDockZoneClass: TJvDockZoneClass = TJvDockZone;
  DefaultDockTreeClass: TJvDockTreeClass = TJvDockTree;

procedure ShowDockForm(DockWindow: TWinControl);
procedure HideDockForm(DockWindow: TWinControl);
procedure MakeDockClientEvent(Host: TControl; Visible: Boolean);
function GetFormVisible(DockWindow: TWinControl): Boolean;
procedure SetDockPageControlPopupMenu(Value: TPopupMenu);
procedure SetDockPageControlHotTrack(Value: Boolean);
procedure SetTabDockHostBorderStyle(Value: TFormBorderStyle);
procedure SetConjoinDockHostBorderStyle(Value: TFormBorderStyle);

{$IFDEF USEJVCL}
// Save Layout to JvAppStorage:
procedure SaveDockTreeToAppStorage(AppStorage: TJvCustomAppStorage; AppStoragePath: string = '');
// Load Layout from JvAppStorage:
procedure LoadDockTreeFromAppStorage(AppStorage: TJvCustomAppStorage; AppStoragePath: string = '');
{$ENDIF USEJVCL}

procedure SaveDockTreeToFile(FileName: string);
procedure LoadDockTreeFromFile(FileName: string);
procedure SaveDockTreeToReg(ARootKey: DWORD; RegPatch: string);
procedure LoadDockTreeFromReg(ARootKey: DWORD; RegPatch: string);

function FindDockBaseControl(Client: TControl): TJvDockBaseControl;
function FindDockClient(Client: TControl): TJvDockClient;
function FindDockServer(Client: TControl): TJvDockServer;

function IsDockable(Sender: TWinControl; Client: TControl;
  DropCtl: TControl = nil; DockAlign: TAlign = alNone): Boolean;
function ComputeDockingRect(AControl: TControl;
  var DockRect: TRect; MousePos: TPoint): TAlign;

{ Undocks AControl from Sender; Sender is used to calculate the rectangle in
  which AControl is displayed when it starts floating. }
procedure DoFloat(Sender, AControl: TControl);
procedure SetDockSite(Control: TWinControl; SiteValue: Boolean);
procedure DoFloatForm(DockForm: TControl);
procedure FreeAllDockableForm;
procedure DoFloatAllForm;

function GetClientAlignControlArea(AControl: TWinControl; Align: TAlign; Exclude: TControl = nil): Integer;
procedure ResetDockClient(Control: TControl; NewTarget: TControl); overload;
procedure ResetDockClient(DockClient: TJvDockClient; NewTarget: TControl); overload;
procedure ReshowAllVisibleWindow;

{ Quick way to do tabbed docking programmatically - Added by Warren }
function ManualTabDock(DockSite: TWinControl; Form1, Form2: TForm): TJvDockTabHostForm;
{ Must create the initial tab dock with two pages, using ManualTabDock,
  then you can add more pages with this:}
procedure ManualTabDockAddPage(TabHost: TJvDockTabHostForm; AForm: TForm);
function ManualConjoinDock(DockSite: TWinControl; Form1, Form2: TForm): TJvDockConjoinHostForm;

function DockStateStr(DockState: Integer): string; {return string for a dock state}

{$IFDEF USEJVCL}
{$IFDEF UNITVERSIONING}
const
  UnitVersioning: TUnitVersionInfo = (
    RCSfile: '$URL: https://svn.sourceforge.net:443/svnroot/jvcl/trunk/jvcl/run/JvDockControlForm.pas $';
    Revision: '$Revision: 10674 $';
    Date: '$Date: 2006-06-09 00:15:52 -0700 (Fri, 09 Jun 2006) $';
    LogPath: 'JVCL\run'
    );
{$ENDIF UNITVERSIONING}
{$ENDIF USEJVCL}

implementation

uses
  SysUtils,
  {$IFDEF USEJVCL}
  JvAppRegistryStorage, JvAppIniStorage, JvTypes,
  {$ELSE}
  IniFiles, Registry,
  {$ENDIF USEJVCL}
  JvDockSupportProc, JvDockGlobals, JvDockInfo, JvDockVSNetStyle;

{$R JvDockableForm.dfm}
{$R JvDockConjoinHost.dfm}
{$R JvDockTabHost.dfm}

type
  TControlAccessProtected = class(TControl);
  TWinControlAccessProtected = class(TWinControl);

  
{$IFNDEF USEJVCL}
const
  cDefaultFormName = '_JVFORM_';
  cDefaultNameSuffix = '_JVDOCK_';
{$ENDIF !USEJVCL}

var
  DockPageControlPopupMenu: TPopupMenu = nil;
  DockPageControlHotTrack: Boolean = False;
  TabDockHostBorderStyle: TFormBorderStyle = bsSizeToolWin;
  ConjoinDockHostBorderStyle: TFormBorderStyle = bsSizeToolWin;
  IsWinXP: Boolean;

//=== Local procedures =======================================================

procedure UpdateCaption(Source: TWinControl; Exclude: TControl);
var
  I: Integer;
  Host: TJvDockableForm;
begin
  if (Source <> nil) and (Source.Parent is TJvDockableForm) then
  begin
    Host := TJvDockableForm(Source.Parent);
    Host.Caption := '';

    for I := 0 to Source.DockClientCount - 1 do
      if Source.DockClients[I].Visible and (Source.DockClients[I] <> Exclude) then
        Host.Caption := Host.Caption + TCustomForm(Source.DockClients[I]).Caption + RsDockStringSplitter;

    if Host.HostDockSite is TJvDockTabPageControl then
      with TJvDockTabPageControl(Host.HostDockSite) do
        if (ActivePage <> nil) and (ActivePage.Controls[0] = Source) then
          ActivePage.Caption := Host.Caption;
    UpdateCaption(Host.HostDockSite, nil);
  end;
end;

function GetActiveControl(AForm: TCustomForm): TWinControl;
var
  AControl: TWinControl;
begin
  Result := nil;
  AControl := AForm.ActiveControl;
  while AControl <> nil do
  begin
    if AControl.HostDockSite <> nil then
    begin
      Result := AControl;
      Break;
    end;
    AControl := AControl.Parent;
  end;
end;

function GetHostDockParent(AControl: TWinControl): TWinControl;
begin
  Result := nil;
  while AControl <> nil do
  begin
    if AControl.HostDockSite <> nil then
    begin
      Result := AControl.HostDockSite;
      Break;
    end;
    AControl := AControl.Parent;
  end;
end;

//=== Global procedures ======================================================

function ComputeDockingRect(AControl: TControl; var DockRect: TRect; MousePos: TPoint): TAlign;
var
  DockTopRect, DockLeftRect, DockBottomRect, DockRightRect, DockCenterRect: TRect;
begin
  Result := alNone;

  if AControl = nil then
    Exit;
  with AControl do
  begin
    DockLeftRect.TopLeft := Point(0, 0);
    DockLeftRect.BottomRight := Point(ClientWidth div 5, ClientHeight);

    DockTopRect.TopLeft := Point(ClientWidth div 5, 0);
    DockTopRect.BottomRight := Point(ClientWidth div 5 * 4, ClientHeight div 5);

    DockRightRect.TopLeft := Point(ClientWidth div 5 * 4, 0);
    DockRightRect.BottomRight := Point(ClientWidth, ClientHeight);

    DockBottomRect.TopLeft := Point(ClientWidth div 5, ClientHeight div 5 * 4);
    DockBottomRect.BottomRight := Point(ClientWidth div 5 * 4, ClientHeight);

    DockCenterRect.TopLeft := Point(ClientWidth div 5, ClientHeight div 5);
    DockCenterRect.BottomRight := Point(ClientWidth div 5 * 4, ClientHeight div 5 * 4);

    if PtInRect(DockLeftRect, MousePos) then
    begin
      Result := alLeft;
      DockRect := DockLeftRect;
      DockRect.Right := ClientWidth div 2;
    end
    else
    if PtInRect(DockTopRect, MousePos) then
    begin
      Result := alTop;
      DockRect := DockTopRect;
      DockRect.Left := 0;
      DockRect.Right := ClientWidth;
      DockRect.Bottom := ClientHeight div 2;
    end
    else
    if PtInRect(DockRightRect, MousePos) then
    begin
      Result := alRight;
      DockRect := DockRightRect;
      DockRect.Left := ClientWidth div 2;
    end
    else
    if PtInRect(DockBottomRect, MousePos) then
    begin
      Result := alBottom;
      DockRect := DockBottomRect;
      DockRect.Left := 0;
      DockRect.Right := ClientWidth;
      DockRect.Top := ClientHeight div 2;
    end
    else
    if PtInRect(DockCenterRect, MousePos) then
    begin
      Result := alClient;
      DockRect := DockCenterRect;
    end;
    if Result = alNone then
      Exit;

    DockRect.TopLeft := ClientToScreen(DockRect.TopLeft);
    DockRect.BottomRight := ClientToScreen(DockRect.BottomRight);
  end;
end;

function DockStateStr(DockState: Integer): string;
begin
  // (rom) XML strings do not localize
  case DockState of
    JvDockState_Unknown:
      Result := 'Unknown';
    JvDockState_Docking:
      Result := 'Docking';
    JvDockState_Floating:
      Result := 'Floating';
  else
    Result := IntToStr(DockState);
  end;
end;

procedure DoFloat(Sender, AControl: TControl);
var
  ARect: TRect;
  CH, BW: Integer;
begin
  BW := JvDockGetSysBorderWidth;
  CH := JvDockGetSysCaptionHeight;

  ARect.TopLeft := Sender.ClientToScreen(Point(-(BW + 3), -(CH + BW + 1)));
  ARect.BottomRight := Sender.ClientToScreen(
    Point(Sender.UndockWidth - (BW + 3), Sender.UndockHeight - (BW + CH + 1)));
  AControl.ManualFloat(ARect);
  if (AControl.Left <> ARect.Left) or (AControl.Top <> ARect.Top) then
  begin
    AControl.Left := ARect.Left;
    AControl.Top := ARect.Top;
  end;
end;

procedure DoFloatAllForm;
var
  I: Integer;
  TempList: TList;
begin
  TempList := TList.Create;
  try
    for I := 0 to Screen.CustomFormCount - 1 do
      if not (Screen.CustomForms[I] is TJvDockableForm) and
        (Assigned(FinddockClient(Screen.CustomForms[I])) or
         Assigned(FinddockServer(Screen.CustomForms[I]))) then
        TempList.Add(Screen.CustomForms[I]);

    for I := 0 to TempList.Count - 1 do
      DoFloatForm(TempList[I]);
  finally
    TempList.Free;
  end;
  FreeAllDockableForm;
end;

procedure DoFloatForm(DockForm: TControl);
var
  I: TAlign;
  J: Integer;
  ADockServer: TJvDockServer;
  //  ARect: TRect;
  Channel: TJvDockVSChannel;
begin
  if DockForm is TJvDockableForm then
  begin
    with TJvDockableForm(DockForm).DockableControl do
    begin
      for J := DockClientCount - 1 downto 0 do
        DoFloatForm(DockClients[J]);

      DockForm.ManualDock(nil);
    end;
  end
  else
  begin
    ADockServer := FindDockServer(DockForm);
    if ADockServer <> nil then
    begin
      // (rom) better use a Count or introduce one
      // (p3) this is due to the fact that DockPanel returns a dockpanel based on the indices 0 to 3
      //  DockPanelWithAlign uses the TAlign enumeration, however
      for I := alTop to alRight do
        if Assigned(ADockServer.DockPanelWithAlign[I]) then
        begin
          for J := ADockServer.DockPanelWithAlign[I].DockClientCount - 1 downto 0 do
            DoFloatForm(ADockServer.DockPanelWithAlign[I].DockClients[J]);
          if ADockServer.DockPanelWithAlign[I] is TJvDockVSNETPanel then
            with TJvDockVSNETPanel(ADockServer.DockPanelWithAlign[I]).VSChannel do
            begin
              RemoveAllBlock;
              HidePopupPanel(ActiveDockForm);
            end;
        end;
    end
    else
    begin
      if DockForm.HostDockSite <> nil then
      begin
        if (DockForm.HostDockSite.Parent is TJvDockableForm) and
          (DockForm.HostDockSite.DockClientCount <= 2) then
          PostMessage(DockForm.HostDockSite.Parent.Handle, WM_CLOSE, 0, 0);
      end;
      //      else
      //        ARect := DockForm.BoundsRect;

      Channel := RetrieveChannel(DockForm.HostDockSite);
      if Assigned(Channel) then
      begin
        Channel.RemoveDockControl(TWinControl(DockForm));
        DockForm.Dock(nil, Bounds(DockForm.Left, DockForm.Top, DockForm.UndockWidth, DockForm.UndockHeight));
      end
      else
        DockForm.ManualDock(nil);
    end;
  end;
end;

function FindDockBaseControl(Client: TControl): TJvDockBaseControl;
var
  I: Integer;
begin
  Result := nil;
  if Client <> nil then
    for I := 0 to Client.ComponentCount - 1 do
      if Client.Components[I] is TJvDockBaseControl then
      begin
        Result := TJvDockBaseControl(Client.Components[I]);
        Break;
      end;
end;

function FindDockClient(Client: TControl): TJvDockClient;
var
  ADockControl: TJvDockBaseControl;
begin
  ADockControl := FindDockBaseControl(Client);
  if ADockControl is TJvDockClient then
    Result := TJvDockClient(ADockControl)
  else
    Result := nil;
end;

function FindDockServer(Client: TControl): TJvDockServer;
var
  ADockControl: TJvDockBaseControl;
begin
  ADockControl := FindDockBaseControl(Client);
  if ADockControl is TJvDockServer then
    Result := TJvDockServer(ADockControl)
  else
    Result := nil;
end;

procedure FreeAllDockableForm;
var
  I: Integer;
begin
  Assert(JvGlobalDockManager <> nil);
  for I := JvGlobalDockManager.DockableFormCount - 1 downto 0 do
    if JvGlobalDockManager.DockableForm[I].DockableControl.DockClientCount = 0 then
      JvGlobalDockManager.DockableForm[I].Free;
end;

function GetClientAlignControlArea(AControl: TWinControl; Align: TAlign; Exclude: TControl): Integer;
var
  I: Integer;
begin
  Result := 0;
  for I := 0 to AControl.ControlCount - 1 do
    if (AControl.Controls[I].Align = Align) and AControl.Controls[I].Visible and
      (AControl.Controls[I] <> Exclude) and
      not ((AControl.Controls[I] is TJvDockSplitter) or (AControl.Controls[I] is TJvDockPanel)) then
      if Align in [alLeft, alRight] then
        Inc(Result, AControl.Controls[I].Width)
      else
        Inc(Result, AControl.Controls[I].Height);
end;

function GetFormVisible(DockWindow: TWinControl): Boolean;
var
  ADockClient: TJvDockClient;
begin
  Result := True;
  ADockClient := FindDockClient(DockWindow);
  if ADockClient <> nil then
    Result := ADockClient.DockStyle.GetDockFormVisible(ADockClient);
end;

procedure HideDockForm(DockWindow: TWinControl);
var
  ADockClient: TJvDockClient;
begin
  // delegate to style
  ADockClient := FindDockClient(DockWindow);
  if Assigned(ADockClient) and Assigned(ADockClient.DockStyle) then
    ADockClient.DockStyle.DoHideDockForm(DockWindow);
end;

procedure TJvDockBasicStyle.DoHideDockForm(DockWindow: TWinControl);

  procedure HideDockChild(DockWindow: TWinControl);
  var
    I: Integer;
    DockClient: TJvDockClient;
  begin
    if DockWindow = nil then
      Exit;
    if (DockWindow is TJvDockableForm) and (DockWindow.Visible) then
      with TJvDockableForm(DockWindow).DockableControl do
        for I := 0 to DockClientCount - 1 do
          HideDockChild(TWinControl(DockClients[I]));
    DockClient := FindDockClient(DockWindow);
    if (DockWindow is TForm) and (TForm(DockWindow).FormStyle <> fsMDIChild) and
      (DockClient.DockStyle <> nil) then
      DockClient.DockStyle.HideDockForm(DockClient);
  end;

  procedure HideDockParent(DockWindow: TWinControl);
  var
    Host: TWinControl;
    DockClient: TJvDockClient;
  begin
    if (DockWindow <> nil) and (DockWindow.HostDockSite <> nil) then
    begin
      Host := DockWindow.HostDockSite;
      if Host.VisibleDockClientCount = 0 then
        if Host is TJvDockPanel then
          TJvDockPanel(Host).ShowDockPanel(False, nil)
        else
        begin
          if Host.Parent <> nil then
          begin
            DockClient := FindDockClient(Host.Parent);
            if (DockClient <> nil) and (DockClient.DockStyle <> nil) then
              DockClient.DockStyle.HideDockForm(DockClient);
            HideDockParent(Host.Parent);
          end;
        end;
    end;
  end;

begin
  HideDockChild(DockWindow);
  HideDockParent(DockWindow);
  if (DockWindow.HostDockSite is TJvDockCustomControl) then
    TJvDockCustomControl(DockWindow.HostDockSite).UpdateCaption(DockWindow);
end;

function IsDockable(Sender: TWinControl; Client: TControl; DropCtl: TControl = nil;
  DockAlign: TAlign = alNone): Boolean;
var
  I: Integer;
  ADockClient: TJvDockClient;
  SenderDockStyle, ClientDockStyle: TJvDockBasicStyle;
  SenderStyleName, ClientStyleName: string;
  SenderDocPanel: TJvDockPanel;
  //s:String;
  // (rom) disabled unused
  //label
  // JudgeRelation;
begin
  ADockClient := FindDockClient(Client);
  Result := False;
  if (ADockClient <> nil) and (ADockClient.EnableDock) then
  begin
    if Sender is TJvDockPanel then
    begin
      SenderDocPanel := TJvDockPanel(Sender);
      with SenderDocPanel do
      begin
        {$IFDEF JVDOCK_DEBUG}
        if CustomFlag and (not ADockClient.CustomDock) then
        begin
          OutputDebugString('IsDockable() - Debugging Dock-to-custom-panel problem.');
          ADockClient.CustomDock := True; // BUG WORKAROUND. WPostma.
        end;
        {$ENDIF JVDOCK_DEBUG}
        Result := DockServer.EnableDock and
          (((Align = alLeft) and DockServer.LeftDock and (ADockClient.LeftDock)) or
          ((Align = alTop) and DockServer.TopDock and (ADockClient.TopDock)) or
          ((Align = alRight) and DockServer.RightDock and (ADockClient.RightDock)) or
          ((Align = alBottom) and DockServer.BottomDock and (ADockClient.BottomDock)) or
          ((CustomFlag) and Assigned(DockServer.CustomDockPanel) and (ADockClient.CustomDock))
          );

          //{$IFDEF JVDOCK_DEBUG}
          // XXXXXX very noisy during drag operations:
          //if Result then begin
          //    if Assigned(DropCtl) then
          //        s := DropCtl.Name
          //   else
          //        s := 'nil';
          //    OutputDebugString(PChar( 'JvDockControlForm.pas IsDockable: '+Sender.Name+ ': Dockable. DropCtl='+s ));
          //end;
          //{$ENDIF JVDOCK_DEBUG}
        SenderDockStyle := DockServer.DockStyle;
      end;
    end
    else
    begin
      if (Sender <> nil) and (Sender.Parent is TJvDockableForm) then
        with TJvDockableForm(Sender.Parent).DockableControl do
          for I := 0 to DockClientCount - 1 do
            if DockClients[I] = Client then
              Exit;
      Result := ADockClient.EachOtherDock;
      if Sender <> nil then
        ADockClient := FindDockClient(Sender.Parent);
      if ADockClient <> nil then
        Result := Result and ADockClient.EachOtherDock;

      if ADockClient <> nil then
        SenderDockStyle := ADockClient.DockStyle
      else
        Exit;
    end;

    ADockClient := FindDockClient(Client);
    if ADockClient <> nil then
      ClientDockStyle := ADockClient.DockStyle
    else
      Exit;

    if SenderDockStyle = nil then
      SenderStyleName := ''
    else
      SenderStyleName := SenderDockStyle.ClassName;

    if ClientDockStyle = nil then
      ClientStyleName := ''
    else
      ClientStyleName := ClientDockStyle.ClassName;

    Result := Result and (SenderStyleName = ClientStyleName);

    //JudgeRelation:
  end;
end;

{$IFDEF USEJVCL}

procedure LoadDockTreeFromAppStorage(AppStorage: TJvCustomAppStorage; AppStoragePath: string = '');
var
  JvDockInfoTree: TJvDockInfoTree;
  Form: TForm;
begin
  AppStorage.BeginUpdate;
  try
    HideAllPopupPanel(nil); {This is in JvDockVSNetStyle.pas }

    Form := TForm.CreateNew(nil);
    // What does this form do, and why is it created only during the loading of the app storage?
    Form.BorderStyle := bsNone;
    Form.BoundsRect := Rect(0, 0, 0, 0);
    Form.Visible := True;
    Form.Name := {NOTRANSLATE} 'LoadDockTreeFromAppStorage_Form';

    JvDockInfoTree := TJvDockInfoTree.Create(TJvDockInfoZone);

    JvDockLockWindow(nil);
    try
      JvDockInfoTree.AppStorage := AppStorage;
      JvDockInfoTree.AppStoragePath := AppStoragePath;
      try
        JvGlobalDockIsLoading := True;
        JvDockInfoTree.ReadInfoFromAppStorage;
      finally
        JvGlobalDockIsLoading := False;
      end;
    finally
//      Form.Release;
      Form.Free;
      JvDockUnLockWindow;
      JvDockInfoTree.Free;
    end;
    ReshowAllVisibleWindow;
  finally
    AppStorage.EndUpdate;
  end;
end;

procedure LoadDockTreeFromFile(FileName: string);
var
  JvAppStorage: TJvAppIniFileStorage;
begin
  JvAppStorage := TJvAppIniFileStorage.Create(nil);
  try
    JvAppStorage.Location := flCustom;
    JvAppStorage.FileName := FileName;
    JvAppStorage.Reload;
    LoadDockTreeFromAppStorage(JvAppStorage);
  finally
    JvAppStorage.Free;
  end;
end;

procedure LoadDockTreeFromReg(ARootKey: DWORD; RegPatch: string);
var
  JvAppStorage: TJvAppRegistryStorage;
begin
  JvAppStorage := TJvAppRegistryStorage.Create(nil);
  try
    // (p3) this seems dangerous but it's the same method as used by TJvAppRegistryStorage
    JvAppStorage.RegRoot := TJvRegKey(HKEY_CLASSES_ROOT + ARootKey);
    JvAppStorage.Path := RegPatch;
    LoadDockTreeFromAppStorage(JvAppStorage);
  finally
    JvAppStorage.Free;
  end;
end;

{$ELSE}

procedure LoadDockTreeFromFile(FileName: string);
var
  JvDockInfoTree: TJvDockInfoTree;
  Form: TForm;
  MemFile: TMemIniFile;
begin
  HideAllPopupPanel(nil);

  Form := TForm.CreateNew(nil);
  Form.BorderStyle := bsNone;
  Form.BoundsRect := Rect(0, 0, 0, 0);
  Form.Visible := True;
  Form.Name := cDefaultFormName;

  JvDockInfoTree := TJvDockInfoTree.Create(TJvDockInfoZone);

  MemFile := TMemIniFile.Create(FileName);
  JvDockLockWindow(nil);
  try
    JvDockInfoTree.DockInfoIni := MemFile;
    JvGlobalDockIsLoading := True;
    JvDockInfoTree.ReadInfoFromIni;
    JvGlobalDockIsLoading := False;
  finally
//    Form.Release;
    Form.Free;
    JvDockUnLockWindow;
    JvDockInfoTree.Free;
    MemFile.Free;
  end;
  ReshowAllVisibleWindow;
end;

procedure LoadDockTreeFromReg(ARootKey: DWORD; RegPatch: string);
var
  JvDockInfoTree: TJvDockInfoTree;
  Form: TForm;
begin
  HideAllPopupPanel(nil);

  Form := TForm.CreateNew(nil);
  Form.BorderStyle := bsNone;
  Form.BoundsRect := Rect(0, 0, 0, 0);
  Form.Visible := True;
  Form.Name := cDefaultFormName;

  JvDockInfoTree := TJvDockInfoTree.Create(TJvDockInfoZone);

  JvDockLockWindow(nil);
  try
    JvDockInfoTree.DockInfoReg := TRegistry.Create;
    try
      JvGlobalDockIsLoading := True;
      JvDockInfoTree.DockInfoReg.RootKey := ARootKey;
      JvDockInfoTree.ReadInfoFromReg(RegPatch);
    finally
      JvDockInfoTree.DockInfoReg.Free;
      JvGlobalDockIsLoading := False;
    end;
  finally
    JvDockUnLockWindow;
    JvDockInfoTree.Free;
//    Form.Release;
    Form.Free;
  end;
  ReshowAllVisibleWindow;
end;

{$ENDIF USEJVCL}

procedure MakeDockClientEvent(Host: TControl; Visible: Boolean);
var
  I: Integer;
  DC: TJvDockClient;
begin
  DC := FindDockClient(Host);
  if DC <> nil then
  begin
    if Visible then
      DC.MakeShowEvent
    else
      DC.MakeHideEvent;
    if (Host is TJvDockableForm) and Host.Visible then
      with TJvDockableForm(Host).DockableControl do
        for I := 0 to DockClientCount - 1 do
          MakeDockClientEvent(DockClients[I], Visible);
  end;
end;

{ Quick way to do conjoined docking programmatically - Added by Warren }

function ManualConjoinDock(DockSite: TWinControl; Form1, Form2: TForm): TJvDockConjoinHostForm;
var
  ConjoinHost: TJvDockConjoinHostForm;
  DockClient1, DockCLient2: TJvDockClient;
begin
  Form1.Show;
  Form2.Show;
  DockClient1 := FindDockClient(Form1);
  Assert(Assigned(DockClient1));
  DockClient2 := FindDockClient(Form2);
  Assert(Assigned(DockClient2));
  ConjoinHost := DockClient1.CreateConjoinHostAndDockControl(DockClient1.ParentForm, Form2, alTop);
  ShowDockForm(Form2);
  ConjoinHost.ManualDock(DockSite);
  Result := ConjoinHost;
end;

{ Quick way to do tabbed docking programmatically - Added by Warren }

function ManualTabDock(DockSite: TWinControl; Form1, Form2: TForm): TJvDockTabHostForm;
var
  TabHost: TJvDockTabHostForm;
// wasVisible1,wasVisible2:Boolean;
  DockClient1, DockCLient2: TJvDockClient;
  ScreenPos: TRect;
begin
  //Form1.Show;
  //Form2.Show;

  DockClient1 := FindDockClient(Form1);
  //wasVisible1 := Form1.Visible;
  Form1.Hide;
  Assert(Assigned(DockClient1));
  if DockClient1.DockState = JvDockState_Docking then
  begin
    ScreenPos := Application.MainForm.ClientRect; // Just making it float temporarily.
    Form1.ManualFloat(ScreenPos);
  end;
  DockClient2 := FindDockClient(Form2);
  //wasVisible2 := Form2.Visible;
  Form2.Hide;

  Assert(Assigned(DockClient2));
  if DockClient2.DockState = JvDockState_Docking then
  begin
    ScreenPos := Application.MainForm.ClientRect; // Just making it float temporarily.
    Form2.ManualFloat(ScreenPos);
  end;

  TabHost := DockClient1.CreateTabHostAndDockControl(Form1, Form2);
    {DockClient1.ParentForm, DockClient2.ParentForm}
  TabHost.Hide;

  TabHost.ManualDock(DockSite);
  if not Form1.Visible then
    Form1.Show;
  if not Form2.Visible then
    Form2.Show;

  TabHost.Show;
  ShowDockForm(Form2);
  Result := TabHost;
end;

{ Must create the initial tab dock with two pages, using ManualTabDock,
  then you can add more pages with this:}

procedure ManualTabDockAddPage(TabHost: TJvDockTabHostForm; AForm: TForm);
begin
  Assert(Assigned(TabHost));
  Assert(Assigned(TabHost.PageControl));
  //AForm.Show;
  AForm.ManualDock(TabHost.PageControl);
  AForm.Show;
end;

procedure ResetDockClient(DockClient: TJvDockClient; NewTarget: TControl);
var
  Pt: TPoint;
begin
  if (DockClient <> nil) and not (csDestroying in DockClient.ParentForm.ComponentState) then
  begin
    if not ((DockClient.ParentForm.HostDockSite is TJvDockPanel) and (NewTarget is TJvDockPanel)) then
    begin
      if (DockClient.LastDockSite is TJvDockPanel) and (NewTarget is TJvDockPanel) and
        (DockClient.LastDockSite <> NewTarget) then
        with TJvDockPanel(DockClient.LastDockSite) do
          if UseDockManager and (JvDockManager <> nil) then
            JvDockManager.RemoveControl(DockClient.ParentForm);

      if DockClient.ParentForm.HostDockSite is TJvDockPanel then
        DockClient.LastDockSite := DockClient.ParentForm.HostDockSite
      else
        DockClient.LastDockSite := nil;

      if DockClient.ParentForm.HostDockSite = nil then
      begin
        DockClient.UnDockLeft := DockClient.ParentForm.BoundsRect.TopLeft.X;
        DockClient.UnDockTop := DockClient.ParentForm.BoundsRect.TopLeft.Y;
      end
      else
      begin
        Pt := DockClient.ParentForm.BoundsRect.TopLeft;
        Pt := DockClient.ParentForm.HostDockSite.ClientToScreen(Pt);
        DockClient.UnDockLeft := Pt.X;
        DockClient.UnDockTop := Pt.Y;
      end;
    end;
  end;
end;

procedure ResetDockClient(Control: TControl; NewTarget: TControl);
begin
  ResetDockClient(FindDockClient(Control), NewTarget);
end;

procedure ReshowAllVisibleWindow;
var
  I: Integer;
begin
  if IsWinXP then
    for I := 0 to Screen.FormCount - 1 do
      if Screen.Forms[I].Visible then
        Windows.ShowWindow(Screen.Forms[I].Handle, SW_SHOW)
      else
        Windows.ShowWindow(Screen.Forms[I].Handle, SW_HIDE);
end;

{$IFDEF USEJVCL}

 // Save Layout to JvAppStorage:
 //
 // Uses Global VCL object Screens to go through all forms, and save layout for
 // all the forms. Use any JvCustomAppStorage descendant to store to, such
 // as registry, ini files, etc.

procedure SaveDockTreeToAppStorage(AppStorage: TJvCustomAppStorage; AppStoragePath: string = '');
var
  JvDockInfoTree: TJvDockInfoTree;
  I: Integer;
begin
  AppStorage.BeginUpdate;
  try
    HideAllPopupPanel(nil); {This is in JvDockVSNetStyle.pas }
    JvDockInfoTree := TJvDockInfoTree.Create(TJvDockInfoZone);
    try
      for I := 0 to Screen.CustomFormCount - 1 do
        if (Screen.CustomForms[I].Parent = nil) and
          ((FindDockClient(Screen.CustomForms[I]) <> nil) or
           (FindDockServer(Screen.CustomForms[I]) <> nil)) then
        begin
          {$IFDEF JVDOCK_DEBUG}
          OutputDebugString(PChar('SaveDockTreeToAppStorage : Form ' + Screen.CustomForms[I].Name));
          {$ENDIF JVDOCK_DEBUG}
          JvDockInfoTree.CreateZoneAndAddInfoFromApp(Screen.CustomForms[I]);
        end;

      JvDockInfoTree.AppStorage := AppStorage;
      JvDockInfoTree.AppStoragePath := AppStoragePath;
      JvDockInfoTree.WriteInfoToAppStorage;
    finally
      JvDockInfoTree.Free;
    end;
  finally
    AppStorage.EndUpdate;
  end;
end;

procedure SaveDockTreeToFile(FileName: string);
var
  JvAppStorage: TJvAppIniFileStorage;
begin
  JvAppStorage := TJvAppIniFileStorage.Create(nil);
  try
    JvAppStorage.Location := flCustom;
    JvAppStorage.FileName := FileName;
    JvAppStorage.Reload;
    SaveDockTreeToAppStorage(JvAppStorage);
  finally
    JvAppStorage.Flush;
    JvAppStorage.Free;
  end;
end;

procedure SaveDockTreeToReg(ARootKey: DWORD; RegPatch: string);
var
  JvAppStorage: TJvAppRegistryStorage;
begin
  JvAppStorage := TJvAppRegistryStorage.Create(nil);
  try
    // (p3) this seems dangerous but it's the same method as used by TJvAppRegistryStorage
    JvAppStorage.RegRoot := TJvRegKey(HKEY_CLASSES_ROOT + ARootKey);
    JvAppStorage.Path := RegPatch;
    SaveDockTreeToAppStorage(JvAppStorage);
  finally
    JvAppStorage.Free;
  end;
end;

{$ELSE}

procedure SaveDockTreeToFile(FileName: string);
var
  JvDockInfoTree: TJvDockInfoTree;
  I: Integer;
  MemFile: TMemIniFile;
begin
  HideAllPopupPanel(nil);
  MemFile := TMemIniFile.Create(FileName);
  try
    JvDockInfoTree := TJvDockInfoTree.Create(TJvDockInfoZone);
    try
      for I := 0 to Screen.CustomFormCount - 1 do
        if (Screen.CustomForms[I].Parent = nil) and
          ((FindDockClient(Screen.CustomForms[I]) <> nil) or
           (FindDockServer(Screen.CustomForms[I]) <> nil)) then
          JvDockInfoTree.CreateZoneAndAddInfoFromApp(Screen.CustomForms[I]);

      JvDockInfoTree.DockInfoIni := MemFile;
      JvDockInfoTree.WriteInfoToIni;
      MemFile.UpdateFile;
    finally
      JvDockInfoTree.Free;
    end;
  finally
    MemFile.Free;
  end;
end;

procedure SaveDockTreeToReg(ARootKey: DWORD; RegPatch: string);
var
  I: Integer;
  JvDockInfoTree: TJvDockInfoTree;
begin
  HideAllPopupPanel(nil);

  JvDockInfoTree := TJvDockInfoTree.Create(TJvDockInfoZone);
  try
    for I := 0 to Screen.CustomFormCount - 1 do
      if (Screen.CustomForms[I].Parent = nil) and
        (FindDockClient(Screen.CustomForms[I]) <> nil) then
        JvDockInfoTree.CreateZoneAndAddInfoFromApp(Screen.CustomForms[I]);

    for I := 0 to Screen.CustomFormCount - 1 do
      if (Screen.CustomForms[I].Parent = nil) and
        (FindDockServer(Screen.CustomForms[I]) <> nil) then
        JvDockInfoTree.CreateZoneAndAddInfoFromApp(Screen.CustomForms[I]);

    JvDockInfoTree.DockInfoReg := TRegistry.Create;
    try
      JvDockInfoTree.DockInfoReg.RootKey := ARootKey;
      JvDockInfoTree.WriteInfoToReg(RegPatch);
    finally
      JvDockInfoTree.DockInfoReg.Free;
    end;
  finally
    JvDockInfoTree.Free;
  end;
end;

{$ENDIF USEJVCL}

procedure SetConjoinDockHostBorderStyle(Value: TFormBorderStyle);
var
  I: Integer;
begin
  ConjoinDockHostBorderStyle := Value;
  for I := 0 to Screen.FormCount - 1 do
    if (Screen.CustomForms[I] is TJvDockConjoinHostForm) and (Screen.CustomForms[I].HostDockSite = nil) then
      TJvDockConjoinHostForm(Screen.CustomForms[I]).BorderStyle := Value;
end;

procedure SetDockPageControlHotTrack(Value: Boolean);
var
  I: Integer;
begin
  DockPageControlHotTrack := Value;
  for I := 0 to Screen.FormCount - 1 do
    if Screen.CustomForms[I] is TJvDockTabHostForm then
      TJvDockTabHostForm(Screen.CustomForms[I]).PageControl.HotTrack := Value;
end;

procedure SetDockPageControlPopupMenu(Value: TPopupMenu);
var
  I: Integer;
begin
  DockPageControlPopupMenu := Value;
  for I := 0 to Screen.FormCount - 1 do
    if Screen.CustomForms[I] is TJvDockTabHostForm then
      TJvDockTabHostForm(Screen.CustomForms[I]).PageControl.PopupMenu := Value;
end;

procedure SetDockSite(Control: TWinControl; SiteValue: Boolean);
begin
  TWinControlAccessProtected(Control).DockSite := SiteValue;
  if (not (csDesigning in Control.ComponentState)) and (JvGlobalDockManager <> nil) then
    JvGlobalDockManager.RegisterDockSite(Control, SiteValue);
end;

procedure SetTabDockHostBorderStyle(Value: TFormBorderStyle);
var
  I: Integer;
begin
  TabDockHostBorderStyle := Value;
  for I := 0 to Screen.FormCount - 1 do
    if (Screen.CustomForms[I] is TJvDockTabHostForm) and (Screen.CustomForms[I].HostDockSite = nil) then
      TJvDockTabHostForm(Screen.CustomForms[I]).BorderStyle := Value;
end;

procedure ShowDockForm(DockWindow: TWinControl);
var
  ADockClient: TJvDockClient;
begin
  // delegate to style
  ADockClient := FindDockClient(DockWindow);
  if Assigned(ADockClient) and Assigned(ADockClient.DockStyle) then
    ADockClient.DockStyle.DoShowDockForm(DockWindow);
end;

procedure TJvDockBasicStyle.DoShowDockForm(DockWindow: TWinControl);

  procedure ShowClient(Client, DockParent: TWinControl);
  var
    ADockClient: TJvDockClient;
    ADockServer: TJvDockServer;
    I: Integer;
  begin
    if (DockParent is TJvDockableForm) and (Client <> nil) then
    begin
      with TJvDockableForm(DockParent).DockableControl do
        for I := 0 to DockClientCount - 1 do
          if DockClients[I] <> Client then
            MakeDockClientEvent(DockClients[I], True);
      if Client.HostDockSite is TJvDockCustomControl then
        TJvDockCustomControl(Client.HostDockSite).UpdateCaption(nil);
    end
    else
    begin
      ADockClient := FindDockClient(DockParent);
      if (ADockClient <> nil) and (ADockClient.DockStyle <> nil) then
      begin
        ADockClient.DockStyle.ShowDockForm(ADockClient);
        ADockServer := FindDockServer(GetParentForm(DockParent));
        if (not Assigned(ADockServer) or ADockServer.AutoFocusDockedForm) and
          DockParent.CanFocus then
          DockParent.SetFocus;
      end;
    end;
    if DockParent.Parent = nil then
      SetForegroundWindow(DockParent.Handle);
  end;

  function ShowDockPanel(Client: TWinControl): TWinControl;
  begin
    Result := Client;
    if Assigned(Client) and (Client.HostDockSite is TJvDockPanel) then
    begin
      ShowClient(nil, Client);
      TJvDockPanel(Client.HostDockSite).ShowDockPanel(True, Client, sdfDockPanel);
      Result := nil;
    end;
  end;

  function ShowTabDockHost(Client: TWinControl): TWinControl;
  var
    I: Integer;
  begin
    Result := Client;
    if Assigned(Client) and (Client.HostDockSite is TJvDockTabPageControl) then
    begin
      ShowClient(nil, Client);

      with TJvDockTabPageControl(Client.HostDockSite) do
        for I := 0 to Count - 1 do
          if Pages[I].Controls[0] = Client then
          begin
            Pages[I].Show;
            Break;
          end;
      if (Client.HostDockSite <> nil) and not (Client.HostDockSite is TJvDockPanel) then
      begin
        Result := Client.HostDockSite.Parent;
        ShowClient(Client, Result);
        if (Result <> nil) and (Result.HostDockSite is TJvDockTabPageControl) then
          { (rb) never called AFAICS }
          Result := ShowTabDockHost(Result)
        else
          ShowClient(nil, Result);
      end;
    end;
  end;

  function ShowConjoinDockHost(Client: TWinControl): TWinControl;
  begin
    Result := Client;
    if Assigned(Client) and Assigned(Client.HostDockSite) and not (Client.HostDockSite is TJvDockPanel) then
    begin
      ShowClient(nil, Client);
      if Client.HostDockSite.Parent <> nil then
      begin
        Result := Client.HostDockSite.Parent;
        ShowClient(Client, Result);
        if (Result <> nil) and (Result.HostDockSite is TJvDockConjoinPanel) then
          { (rb) never called AFAICS }
          Result := ShowConjoinDockHost(Result)
        else
          ShowClient(nil, Result);
      end;
    end;
  end;

begin
  repeat
    { Show single floating window }
    if Assigned(DockWindow) and (DockWindow.HostDockSite = nil) then
      ShowClient(nil, DockWindow);
    DockWindow := ShowTabDockHost(DockWindow);
    DockWindow := ShowConjoinDockHost(DockWindow);
    { Show docked window }
    DockWindow := ShowDockPanel(DockWindow);
  until (DockWindow = nil) or (DockWindow.Parent = nil);
end;

//=== { TJvDockableForm } ====================================================

constructor TJvDockableForm.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  DragKind := dkDock;
  FDockClient := TJvDockClient.Create(Self);
  JvGlobalDockManager.RegisterDockableForm(Self);
  FFloatingChild := nil;
  TBDockHeight := FDockClient.TBDockHeight;
  LRDockWidth := FDockClient.LRDockWidth;
end;

destructor TJvDockableForm.Destroy;
begin
  if JvGlobalDockManager <> nil then
    JvGlobalDockManager.UnRegisterDockableForm(Self);
  { Now handled in destroy of DockClient via TJvDockClient.SetLastDockSite }
  //if DockClient.LastDockSite is TJvDockPanel then
  //  if Assigned(TJvDockPanel(DockClient.LastDockSite).JvDockManager) then
  //    TJvDockPanel(DockClient.LastDockSite).JvDockManager.RemoveControl(Self);
  inherited Destroy;
  // (rom) better comment this
  FFloatingChild := nil;
end;

procedure TJvDockableForm.DoClose(var Action: TCloseAction);
var
  I: Integer;
begin
  if DockableControl.DockClientCount = 1 then
  begin
    FFloatingChild := DockableControl.DockClients[0];

    if HostDockSite <> nil then
      FFloatingChild.Visible := False;

    DoFloat(Self, DockableControl.DockClients[0]);
    Action := caFree;
  end
  else
  if DockableControl.DockClientCount = 0 then
    Action := caFree
  else
  begin
    Action := caHide;
    if (FUnDockControl <> nil) and (DockableControl.DockClientCount = 2) then
      for I := 0 to DockableControl.DockClientCount - 1 do
        if FUnDockControl = DockableControl.DockClients[I] then
        begin
          Action := caNone;
          Break;
        end;
  end;
  if (HostDockSite is TJvDockPanel) and (HostDockSite.VisibleDockClientCount = 1) and
    (FFloatingChild = nil) then
    TJvDockPanel(HostDockSite).ShowDockPanel(False, Self);

  inherited DoClose(Action);
  FUnDockControl := nil;
end;

function TJvDockableForm.GetDockableControl: TWinControl;
begin
  Result := FDockableControl;
end;

procedure TJvDockableForm.SetDockableControl(const Value: TWinControl);
begin
  FDockableControl := Value;
end;

procedure TJvDockableForm.SetUnDockControl(const Value: TControl);
begin
  FUnDockControl := Value;
end;

//=== { TJvDockAdvConjoinPanel } =============================================

procedure TJvDockAdvConjoinPanel.CMUnDockClient(var Msg: TCMUnDockClient);
begin
  inherited;
end;

procedure TJvDockAdvConjoinPanel.CustomDockDrop(Source: TJvDockDragDockObject;
  X, Y: Integer);
begin
  if not JvGlobalDockIsLoading then
    ResetDockClient(Source.Control, Source.TargetControl);
  inherited CustomDockDrop(Source, X, Y);
end;

function TJvDockAdvConjoinPanel.CustomUnDock(Source: TJvDockDragDockObject;
  NewTarget: TWinControl; Client: TControl): Boolean;
begin
  if not JvGlobalDockIsLoading then
    ResetDockClient(Source.Control, NewTarget);
  Result := inherited CustomUnDock(Source, NewTarget, Client);
end;

procedure TJvDockAdvConjoinPanel.DockDrop(Source: TDragDockObject;
  X, Y: Integer);
begin
  if not JvGlobalDockIsLoading then
    ResetDockClient(Source.Control, TControl(Source.DragTarget));
  inherited DockDrop(Source, X, Y);
end;

function TJvDockAdvConjoinPanel.DoUnDock(NewTarget: TWinControl;
  Client: TControl): Boolean;
begin
  if not JvGlobalDockIsLoading then
    ResetDockClient(Client, NewTarget);
  Result := inherited DoUnDock(NewTarget, Client);
end;

//=== { TJvDockAdvPanel } ====================================================

procedure TJvDockAdvPanel.CMUnDockClient(var Msg: TCMUnDockClient);
var
  DockClient: TJvDockClient;
begin
  if JvGlobalDockIsLoading then
    Exit;
  with Msg do
  begin
    Result := 0;
    if UseDockManager and (JvDockManager <> nil) then
    begin
      DockClient := FindDockClient(Client);
      if (NewTarget <> nil) or
        ((Client <> nil) and (csDestroying in Client.ComponentState)) then
      begin
        if DockClient <> nil then
          DockClient.LastDockSite := nil;
        JvDockManager.RemoveControl(Client);
      end
      else
      begin
        if DockClient <> nil then
          DockClient.LastDockSite := Self;
        JvDockManager.HideControl(Client);
      end;
    end;
  end;
end;

procedure TJvDockAdvPanel.CustomDockDrop(Source: TJvDockDragDockObject;
  X, Y: Integer);
begin
  if not JvGlobalDockIsLoading then
    ResetDockClient(Source.Control, Source.TargetControl);
  inherited CustomDockDrop(Source, X, Y);
end;

function TJvDockAdvPanel.CustomUnDock(Source: TJvDockDragDockObject;
  NewTarget: TWinControl; Client: TControl): Boolean;
begin
  if not JvGlobalDockIsLoading then
    ResetDockClient(Source.Control, NewTarget);
  Result := inherited CustomUnDock(Source, NewTarget, Client)
end;

procedure TJvDockAdvPanel.DockDrop(Source: TDragDockObject; X, Y: Integer);
begin
  if not JvGlobalDockIsLoading then
    ResetDockClient(Source.Control, TControl(Source.DragTarget));
  inherited DockDrop(Source, X, Y);
end;

function TJvDockAdvPanel.DoUnDock(NewTarget: TWinControl;
  Client: TControl): Boolean;
begin
  if not JvGlobalDockIsLoading then
    ResetDockClient(Client, NewTarget);
  Result := inherited DoUnDock(NewTarget, Client);
end;

// NEW! -WPostma.
// Calls FADVTree.QueryControls which finds forms containing JvDockClient
// objects that are directly or indirectly docked to this panel.

procedure TJvDockAdvPanel.GetDockedControls(WinControls: TList); //override;
begin
  { (rb) Same result could be get via iterating property TWinControl.DockClients }
  Assert(Assigned(WinControls));
  if Assigned(JvDockManager) then
  begin
    WinControls.Clear;
    {$IFDEF JVDOCK_QUERY}
    JvDockManager.ControlQuery({Docked to self}Self, WinControls);
    {$ENDIF JVDOCK_QUERY}
  end;
end;

//=== { TJvDockAdvStyle } ====================================================

function TJvDockAdvStyle.DockClientWindowProc(DockClient: TJvDockClient;
  var Msg: TMessage): Boolean;
begin
  if (DockClient <> nil) and (Msg.Msg = WM_NCLBUTTONDBLCLK) then
    if DockClient.CanFloat then
      DockClient.RestoreChild;
  Result := inherited DockClientWindowProc(DockClient, Msg);
end;

//=== { TJvDockAdvTabPageControl } ===========================================

destructor TJvDockAdvTabPageControl.Destroy;
//var
//  DockClient: TJvDockClient;
begin
  { Now handled in TJvDockClient.SetLastDockSite }
  //  { Parent is always nil? Self is maintained by TJvDockTabHostForm (=Parent),
  //    Self is destroyed only if TJvDockTabHostForm is destroyed (thus is nil at
  //    this point }
  //  DockClient := FindDockClient(Parent);
  //  if (DockClient <> nil) and (DockClient.LastDockSite is TJvDockPanel) then
  //    with TJvDockPanel(DockClient.LastDockSite) do
  //      if UseDockManager and (JvDockManager <> nil) then
  //        JvDockManager.RemoveControl(Self.Parent);
  inherited Destroy;
end;

procedure TJvDockAdvTabPageControl.CMUnDockClient(var Msg: TCMUnDockClient);
begin
  inherited;
end;

procedure TJvDockAdvTabPageControl.CustomDockDrop(Source: TJvDockDragDockObject;
  X, Y: Integer);
begin
  if not JvGlobalDockIsLoading then
    ResetDockClient(Source.Control, Source.TargetControl);
  inherited CustomDockDrop(Source, X, Y);
end;

function TJvDockAdvTabPageControl.CustomUnDock(Source: TJvDockDragDockObject;
  NewTarget: TWinControl; Client: TControl): Boolean;
begin
  if not JvGlobalDockIsLoading then
    ResetDockClient(Source.Control, NewTarget);
  Result := inherited CustomUnDock(Source, NewTarget, Client)
end;

procedure TJvDockAdvTabPageControl.DockDrop(Source: TDragDockObject;
  X, Y: Integer);
begin
  if not JvGlobalDockIsLoading then
    ResetDockClient(Source.Control, TControl(Source.DragTarget));
  inherited DockDrop(Source, X, Y);
end;

function TJvDockAdvTabPageControl.DoUnDock(NewTarget: TWinControl;
  Client: TControl): Boolean;
begin
  if not JvGlobalDockIsLoading then
    ResetDockClient(Client, NewTarget);
  Result := inherited DoUnDock(NewTarget, Client);
end;

//=== { TJvDockBaseControl } =================================================

constructor TJvDockBaseControl.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  { Dangerous/Dirty }
  FParentForm := TForm(AOwner);
  FEnableDock := True;
  FLeftDock := True;
  FTopDock := True;
  FCustomDock := True; {Allowed to dock in custom area!}
  FRightDock := True;
  FBottomDock := True;
  FEachOtherDock := True;
  FDockStyle := nil;
  if not (csDesigning in ComponentState) then
  begin
    FOldOnClose := FParentForm.OnClose;
    ParentForm.OnClose := DoFormOnClose;
    FOldOnCreate := FParentForm.OnCreate;
    ParentForm.OnCreate := DoFormOnCreate;
    FOldWindowProc := FParentForm.WindowProc;
    FParentForm.WindowProc := WindowProc;
  end;
end;

destructor TJvDockBaseControl.Destroy;
begin
  if not (csDesigning in ComponentState) then
  begin
    if Assigned(FOldWindowProc) then
      FParentForm.WindowProc := FOldWindowProc;
    FOldWindowProc := nil;
    { ?? FDockStyle is always a TJvDockBasicStyle }
    if Assigned(FDockStyle) {and not (FDockStyle is TJvDockBasicStyle)} then
      FDockStyle.SetDockBaseControl(False, Self);
  end;
  DockStyle := nil;
  inherited Destroy;
end;

procedure TJvDockBaseControl.AddDockStyle(ADockStyle: TJvDockBasicStyle);
begin
  { Notification }
end;

procedure TJvDockBaseControl.Assign(Source: TPersistent);
begin
  if Source is TJvDockBaseControl then
  begin
    EnableDock := TJvDockBaseControl(Source).EnableDock;
    LeftDock := TJvDockBaseControl(Source).LeftDock;
    TopDock := TJvDockBaseControl(Source).TopDock;
    RightDock := TJvDockBaseControl(Source).RightDock;
    BottomDock := TJvDockBaseControl(Source).BottomDock;
    CustomDock := TJvDockBaseControl(Source).CustomDock; {NEW!}
    EachOtherDock := TJvDockBaseControl(Source).EachOtherDock;
    DockStyle := TJvDockBaseControl(Source).DockStyle;
  end
  else
    inherited Assign(Source);
end;

function TJvDockBaseControl.CanSetBottomDocked: Boolean;
begin
  if DockStyle <> nil then
    Result := DockStyle.CanSetBottomDocked(Self)
  else
    Result := True;
end;

function TJvDockBaseControl.CanSetEachOtherDocked: Boolean;
begin
  if DockStyle <> nil then
    Result := DockStyle.CanSetEachOtherDocked(Self)
  else
    Result := True;
end;

function TJvDockBaseControl.CanSetEnableDocked: Boolean;
begin
  if DockStyle <> nil then
    Result := DockStyle.CanSetEnableDocked(Self)
  else
    Result := True;
end;

function TJvDockBaseControl.CanSetLeftDocked: Boolean;
begin
  if DockStyle <> nil then
    Result := DockStyle.CanSetLeftDocked(Self)
  else
    Result := True;
end;

function TJvDockBaseControl.CanSetRightDocked: Boolean;
begin
  if DockStyle <> nil then
    Result := DockStyle.CanSetRightDocked(Self)
  else
    Result := True;
end;

function TJvDockBaseControl.CanSetTopDocked: Boolean;
begin
  if DockStyle <> nil then
    Result := DockStyle.CanSetTopDocked(Self)
  else
    Result := True;
end;

procedure TJvDockBaseControl.DoFormOnClose(Sender: TObject;
  var Action: TCloseAction);
begin
  { Code is moved to AddDockStyle, RemoveDockStyle; if a user assigns OnClose,
    OnCreate handlers things would go wrong.
  }
  if Assigned(FOldOnClose) then
    FOldOnClose(Sender, Action);
end;

procedure TJvDockBaseControl.DoFormOnCreate(Sender: TObject);
begin
  { Code is moved to AddDockStyle, RemoveDockStyle; if a user assigns OnClose,
    OnCreate handlers things would go wrong.
  }
  if Assigned(FOldOnCreate) then
    FOldOnCreate(Sender);
end;

{$IFNDEF USEJVCL}
function TJvDockBaseControl.GetDockStyleVersion: string;
begin
  Result := RsDockManagerVersion;
end;
{$ENDIF !USEJVCL}

procedure TJvDockBaseControl.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if Operation = opRemove then
    if AComponent = FDockStyle then
      DockStyle := nil;
end;

procedure TJvDockBaseControl.RemoveDockStyle(ADockStyle: TJvDockBasicStyle);
begin
  { Notification }
end;

procedure TJvDockBaseControl.SetBottomDock(const Value: Boolean);
begin
  if CanSetBottomDocked then
    FBottomDock := Value;
end;

procedure TJvDockBaseControl.SetDockStyle(ADockStyle: TJvDockBasicStyle);
begin
  {$IFDEF JVDOCK_DEBUG}
  OutputDebugString('TJvDockBaseControl.SetDockStyle');
  {$ENDIF JVDOCK_DEBUG}
  if ADockStyle <> FDockStyle then
  begin
    ParentForm.DisableAlign;
    try
      if FDockStyle <> nil then
      begin
        FDockStyle.RemoveFreeNotification(Self);

        { Remove Self from the internal list of the dock style component }
        FDockStyle.RemoveDockBaseControl(Self);

        { Give the ancestors a change to respond }
        RemoveDockStyle(FDockStyle);
      end;

      FDockStyle := ADockStyle;

      if FDockStyle <> nil then
      begin
        { Let the style initialize the TJvDockClient/TJvDockServer }
        FDockStyle.SetDockBaseControl([csLoading, csDesigning] * ComponentState <> [], Self);

        { Add Self to the internal list of the dock style component }
        FDockStyle.AddDockBaseControl(Self);

        { Give the ancestors a change to respond }
        AddDockStyle(FDockStyle);

        FDockStyle.FreeNotification(Self);
      end;
    finally
      ParentForm.EnableAlign;
    end;
  end;
end;

procedure TJvDockBaseControl.SetEachOtherDock(const Value: Boolean);
begin
  if CanSetEachOtherDocked then
    FEachOtherDock := Value;
end;

procedure TJvDockBaseControl.SetEnableDock(const Value: Boolean);
begin
  if CanSetEnableDocked then
    FEnableDock := Value;
end;

procedure TJvDockBaseControl.SetLeftDock(const Value: Boolean);
begin
  if CanSetLeftDocked then
    FLeftDock := Value;
end;

procedure TJvDockBaseControl.SetParentComponent(Value: TComponent);
var
  DockBaseControl: TJvDockBaseControl;
begin
  DockBaseControl := FindDockBaseControl(ParentForm);
  if Assigned(DockBaseControl) and (DockBaseControl <> Self) then
    raise EInvalidOperation.CreateResFmt(@RsEDockCannotLayAnother, [DockBaseControl.ClassName, ClassName]);
  inherited SetParentComponent(Value);
end;

procedure TJvDockBaseControl.SetRightDock(const Value: Boolean);
begin
  if CanSetRightDocked then
    FRightDock := Value;
end;

procedure TJvDockBaseControl.SetTopDock(const Value: Boolean);
begin
  if CanSetTopDocked then
    FTopDock := Value;
end;

procedure TJvDockBaseControl.WindowProc(var Msg: TMessage);
begin
  if not (csDesigning in ComponentState) then
    if Assigned(FOldWindowProc) then
      FOldWindowProc(Msg);
end;

//=== { TJvDockBasicStyle } ==================================================

constructor TJvDockBasicStyle.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  DockPanelClass := DefaultDockPanelClass;
  DockSplitterClass := DefaultDockSplitterClass;
  ConjoinPanelClass := DefaultConjoinPanelClass;
  TabDockClass := DefaultTabDockClass;
  DockPanelTreeClass := DefaultDockTreeClass;
  DockPanelZoneClass := DefaultDockZoneClass;
  ConjoinPanelTreeClass := DefaultDockTreeClass;
  ConjoinPanelZoneClass := DefaultDockZoneClass;
  FDockBaseControls := TList.Create;
end;

destructor TJvDockBasicStyle.Destroy;
begin
  FDockBaseControls.Free;
  FreeServerOption;
  inherited Destroy;
end;

procedure TJvDockBasicStyle.AddDockBaseControl(ADockBaseControl: TJvDockBaseControl);
begin
  {$IFDEF JVDOCK_DEBUG}
  OutputDebugString('TJvDockBasicStyle.AddDockBaseControl');
  {$ENDIF JVDOCK_DEBUG}
  if ADockBaseControl = nil then
    Exit;
  FDockBaseControls.Add(ADockBaseControl);
end;

function TJvDockBasicStyle.CanSetBottomDocked(ADockBaseControl: TJvDockBaseControl): Boolean;
begin
  Result := True;
end;

function TJvDockBasicStyle.CanSetEachOtherDocked(ADockBaseControl: TJvDockBaseControl): Boolean;
begin
  Result := True;
end;

function TJvDockBasicStyle.CanSetEnableDocked(ADockBaseControl: TJvDockBaseControl): Boolean;
begin
  Result := True;
end;

function TJvDockBasicStyle.CanSetLeftDocked(ADockBaseControl: TJvDockBaseControl): Boolean;
begin
  Result := True;
end;

function TJvDockBasicStyle.CanSetRightDocked(ADockBaseControl: TJvDockBaseControl): Boolean;
begin
  Result := True;
end;

function TJvDockBasicStyle.CanSetTopDocked(ADockBaseControl: TJvDockBaseControl): Boolean;
begin
  Result := True;
end;

function TJvDockBasicStyle.DockClientWindowProc(DockClient: TJvDockClient; var Msg: TMessage): Boolean;
begin
  Result := False;
end;

function TJvDockBasicStyle.DockServerWindowProc(DockServer: TJvDockServer;
  var Msg: TMessage): Boolean;
begin
  Result := False;
end;

procedure TJvDockBasicStyle.FormDockDrop(DockClient: TJvDockClient;
  Source: TJvDockDragDockObject; X, Y: Integer);
var
  ARect, DRect: TRect;
  DockType: TAlign;
  Host: TCustomForm;
  APanelDock: TWinControl;
begin
  if IsDockable(DockClient.ParentForm, Source.Control, Source.DropOnControl, Source.DropAlign) then
  begin
    Host := nil;

    if not JvGlobalDockIsLoading then
      JvDockLockWindow(nil);
    try
      with DockClient do
      begin
        DockType := ComputeDockingRect(DockClient.ParentForm, ARect, Point(X, Y));

        if ParentForm.HostDockSite is TJvDockPanel then
        begin
          if DockType = alClient then
          begin
            if Source.Control is TJvDockTabHostForm then
            begin
              APanelDock := ParentForm.HostDockSite;
              ARect := ParentForm.BoundsRect;
              ParentForm.ManualDock(TJvDockTabHostForm(Source.Control).PageControl, nil, alClient);
              TJvDockTabHostForm(Source.Control).PageControl.ActivePage.PageIndex := 0;
              Source.Control.BoundsRect := ARect;
              Source.Control.ManualDock(APanelDock, nil, alClient);
              if ParentForm.FormStyle = fsStayOnTop then
                TForm(Source.Control).FormStyle := fsStayOnTop;
            end
            else
            begin
              APanelDock := ParentForm.HostDockSite;
              DRect.TopLeft := ParentForm.HostDockSite.ClientToScreen(Point(0, 0));
              Host := CreateTabHostAndDockControl(ParentForm, Source.Control);
              SetDockSite(ParentForm, False);
              SetDockSite(TWinControl(Source.Control), False);
              Host.Top := DRect.Top;
              Host.Left := DRect.Left;
              Host.ManualDock(APanelDock, nil, alClient);
              Host.Visible := True;
            end;
          end
          else
          begin
            DRect := ParentForm.HostDockSite.BoundsRect;
            Source.Control.ManualDock(ParentForm.HostDockSite, nil, DockType);
            ParentForm.HostDockSite.BoundsRect := DRect;
          end;
          Exit;
        end;

        if DockType = alClient then
        begin
          Host := CreateTabHostAndDockControl(ParentForm, Source.Control);
          SetDockSite(ParentForm, False);
          SetDockSite(TWinControl(Source.Control), False);
          Host.Visible := True;
        end
        else
        if DockType <> alNone then
        begin
          Host := CreateConjoinHostAndDockControl(ParentForm, Source.Control, DockType);
          SetDockSite(ParentForm, False);
          SetDockSite(TWinControl(Source.Control), False);
          Host.Visible := True;
        end;

        if Host <> nil then
        begin
          Host.LRDockWidth := Source.Control.LRDockWidth;
          Host.TBDockHeight := Source.Control.TBDockHeight;
        end;
      end;
    finally
      if not JvGlobalDockIsLoading then
        JvDockUnLockWindow;
    end;
  end;
end;

procedure TJvDockBasicStyle.FormDockOver(DockClient: TJvDockClient;
  Source: TJvDockDragDockObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
var
  ARect: TRect;
begin
  with DockClient do
  begin
    Accept := EnableDock and EachOtherDock and
      IsDockable(ParentForm.HostDockSite, Source.Control, Source.DropOnControl, Source.DropAlign);
    if Accept and (State = dsDragMove) and
      (ComputeDockingRect(ParentForm, ARect, Point(X, Y)) <> alNone) then
      Source.DockRect := ARect;
  end;
end;

procedure TJvDockBasicStyle.FormEndDock(DockClient: TJvDockClient;
  Target: TObject; X, Y: Integer);
begin
end;

procedure TJvDockBasicStyle.FormGetDockEdge(DockClient: TJvDockClient;
  Source: TJvDockDragDockObject; MousePos: TPoint; var DropAlign: TAlign);
begin
  DropAlign := TControlAccessProtected(DockClient.ParentForm).GetDockEdge(MousePos);
end;

procedure TJvDockBasicStyle.FormGetSiteInfo(Source: TJvDockDragDockObject;
  DockClient: TJvDockClient; Client: TControl; var InfluenceRect: TRect;
  MousePos: TPoint; var CanDock: Boolean);
begin
  with DockClient do
    CanDock := EnableDock and EachOtherDock and
      IsDockable(ParentForm, Client, Source.DropOnControl, Source.DropAlign);
end;

procedure TJvDockBasicStyle.FormPositionDockRect(DockClient: TJvDockClient;
  Source: TJvDockDragDockObject);
var
  NewWidth, NewHeight: Integer;
  TempX, TempY: Double;
  R: TRect;
begin
  with Source do
  begin
    if (DragTarget = nil) or (not TWinControlAccessProtected(DragTarget).UseDockManager) then
    begin
      NewWidth := Control.UndockWidth;
      NewHeight := Control.UndockHeight;

      TempX := DragPos.X - ((NewWidth) * MouseDeltaX);
      TempY := DragPos.Y - ((NewHeight) * MouseDeltaY);
      with DockRect do
      begin
        Left := Round(TempX);
        Top := Round(TempY);
        Right := Left + NewWidth;
        Bottom := Top + NewHeight;
      end;

      AdjustDockRect(DockRect);
    end
    else
    begin
      GetWindowRect(TargetControl.Handle, R);
      DockRect := R;
      if TWinControlAccessProtected(DragTarget).UseDockManager then
        if TargetControl is TJvDockCustomPanel then
          if (TJvDockCustomPanel(DragTarget).JvDockManager <> nil) then
          begin
            R := DockRect;
            TJvDockCustomPanel(DragTarget).JvDockManager.PositionDockRect(Control,
              DropOnControl, DropAlign, R);
            DockRect := R;
          end;
    end;
  end;
end;

procedure TJvDockBasicStyle.FormStartDock(DockClient: TJvDockClient;
  var Source: TJvDockDragDockObject);
begin
end;

function TJvDockBasicStyle.FormUnDock(DockClient: TJvDockClient; NewTarget: TWinControl;
  Client: TControl): Boolean;
begin
  Result := True;
end;

{$IFNDEF USEJVCL}
function TJvDockBasicStyle.GetControlName: string;
begin
  Result := RsDockStyleName;
end;
{$ENDIF !USEJVCL}

function TJvDockBasicStyle.GetDockBaseControlCount: Integer;
begin
  Result := FDockBaseControls.Count;
end;

function TJvDockBasicStyle.GetDockBaseControl(Index: Integer): TJvDockBaseControl;
begin
  Result := TJvDockBaseControl(FDockBaseControls[Index]);
end;

function TJvDockBasicStyle.GetDockFormVisible(ADockClient: TJvDockClient): Boolean;
begin
  Result := True;
  if ADockClient <> nil then
  begin
    if ADockClient.ParentForm.Visible then
    begin
      if ADockClient.ParentForm.HostDockSite <> nil then
      begin
        if ADockClient.ParentForm.HostDockSite is TJvDockPanel then
          Result := ADockClient.ParentForm.HostDockSite.Width * ADockClient.ParentForm.HostDockSite.Height > 0
        else
          Result := GetFormVisible(ADockClient.ParentForm.HostDockSite.Parent);
      end;
    end
    else
      Result := False;
  end;
end;

function TJvDockBasicStyle.GetDockState(DockClient: TJvDockClient): Integer;
begin
  Result := JvDockState_Unknown;
  if (DockClient <> nil) and (DockClient.ParentForm <> nil) then
    if DockClient.ParentForm.Floating then
      Result := JvDockState_Floating
    else
      Result := JvDockState_Docking;
end;

{$IFNDEF USEJVCL}
function TJvDockBasicStyle.GetDockStyleVersion: string;
begin
  Result := RsDockStyleVersion;
end;
{$ENDIF !USEJVCL}

procedure TJvDockBasicStyle.HideDockForm(ADockClient: TJvDockClient);
begin
  if ADockClient <> nil then
  begin
    ADockClient.ParentForm.Visible := False;
    ADockClient.MakeHideEvent;
  end;
end;

procedure TJvDockBasicStyle.RemoveDockBaseControl(ADockBaseControl: TJvDockBaseControl);
begin
  FDockBaseControls.Remove(ADockBaseControl);
end;

procedure TJvDockBasicStyle.ResetCursor(Source: TJvDockDragDockObject);
begin
  if (Source.TargetControl = nil) and (Source.Control <> nil) and (Source.Control.Floating) then
    Windows.SetCursor(Screen.Cursors[crDefault])
  else
  if (Source.TargetControl = nil) and (not JvGlobalDockClient.CanFloat) then
    Windows.SetCursor(Screen.Cursors[crNo])
  else
    Windows.SetCursor(Screen.Cursors[crDefault]);
end;

procedure TJvDockBasicStyle.RestoreClient(DockClient: TJvDockClient);
var
  TmpLastDockSite: TWinControl;
  TmpUnDockLeft, TmpUnDockTop: Integer;
  I: Integer;
  ADockClient: TJvDockClient;
  ADockServer: TJvDockServer;
  ARect: TRect;

  procedure DoFloatParentForm;
  begin
    with DockClient do
      if (ParentForm.HostDockSite <> nil) then
      begin
        ARect := Bounds(TmpUnDockLeft, TmpUnDockTop, ParentForm.UndockWidth, ParentForm.UndockHeight);
        ParentForm.ManualFloat(ARect);
        if (ParentForm.Left <> ARect.Left) or (ParentForm.Top <> ARect.Top) then
        begin
          ParentForm.Left := ARect.Left;
          ParentForm.Top := ARect.Top;
        end;
      end;
  end;

begin
  if DockClient = nil then
    Exit;
  if not DockClient.CanFloat then
    Exit;
  with DockClient do
  begin
    if not EnableDock then
      Exit;
    if LastDockSite is TJvDockPanel then
    begin
      with TJvDockPanel(LastDockSite) do
      begin
        if ((not LeftDock) and (Align = alLeft)) or
          ((not RightDock) and (Align = alRight)) or
          ((not TopDock) and (Align = alTop)) or
          ((not BottomDock) and (Align = alBottom)) then
        begin
          DoFloatParentForm;
          Exit;
        end;

        ADockServer := DockServer;
        if ADockServer <> nil then
          if (not ADockServer.EnableDock) or
            ((not ADockServer.LeftDock) and (Align = alLeft)) or
            ((not ADockServer.RightDock) and (Align = alRight)) or
            ((not ADockServer.TopDock) and (Align = alTop)) or
            ((not ADockServer.BottomDock) and (Align = alBottom)) then
          begin
            DoFloatParentForm;
            Exit;
          end;
      end;
    end;

    if ParentForm is TJvDockConjoinHostForm then
    begin
      with TJvDockConjoinHostForm(ParentForm).Panel do
        for I := DockClientCount - 1 downto 0 do
        begin
          ADockClient := FindDockClient(DockClients[I]);
          if (ADockClient <> nil) and (ADockClient.LastDockSite is TJvDockPanel) then
            ADockClient.RestoreChild;
        end;
      Exit;
    end;

    TmpLastDockSite := LastDockSite;
    TmpUnDockLeft := UnDockLeft;
    TmpUnDockTop := UnDockTop;

    ResetDockClient(DockClient, nil);

    DoFloatParentForm;

    if TmpLastDockSite is TJvDockPanel then
    begin
      with TJvDockPanel(TmpLastDockSite) do
      begin
        if UseDockManager and (JvDockManager <> nil) then
        begin
          if not JvDockManager.HasZoneWithControl(ParentForm) then
            Exit;
          DisableAlign;
          try
            ParentForm.Dock(TmpLastDockSite, Rect(0, 0, 0, 0));

            JvDockManager.ShowControl(ParentForm);

            ParentForm.ActiveControl := nil;
            SetDockSite(ParentForm, False);

            if ParentForm.Visible and ParentForm.CanFocus then
              ParentForm.SetFocus;
            ShowDockPanel(True, ParentForm, sdfDockPanel);
          finally
            EnableAlign;
          end;
        end;
      end;
    end;
  end;
end;

procedure TJvDockBasicStyle.SetDockBaseControl(IsCreate: Boolean;
  DockBaseControl: TJvDockBaseControl);
begin
end;

procedure TJvDockBasicStyle.ShowDockForm(ADockClient: TJvDockClient);
begin
  if ADockClient <> nil then
  begin
    ADockClient.ParentForm.Visible := True;
    ADockClient.MakeShowEvent;
  end;
end;

//=== { TJvDockClient } ======================================================

constructor TJvDockClient.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FParentVisible := ParentForm.Visible;
  ParentForm.DragKind := dkDock;
  ParentForm.DragMode := dmAutomatic;
  ParentForm.UseDockManager := False;
  if not (ParentForm is TJvDockableForm) then
    SetDockSite(ParentForm, True);
  LRDockWidth := 100;
  TBDockHeight := 100;
  if JvGlobalDockClient = nil then
    JvGlobalDockClient := Self;
  FDirectDrag := False;
  FShowHint := True;
  FCanFloat := True;
  FDockLevel := 0;
  EnableCloseButton := True;
end;

destructor TJvDockClient.Destroy;
begin
  if not (ParentForm is TJvDockableForm) then
    SetDockSite(ParentForm, False);
  ParentForm.DragKind := dkDrag;
  ParentForm.DragMode := dmManual;
  LastDockSite := nil;
  inherited Destroy;
end;

procedure TJvDockClient.Activate;
begin
  if ParentForm.HostDockSite is TJvDockCustomPanel then
    TJvDockCustomPanel(ParentForm.HostDockSite).JvDockManager.ActiveControl := ParentForm;
end;

procedure TJvDockClient.AddDockStyle(ADockStyle: TJvDockBasicStyle);
begin
  JvGlobalDockManager.RegisterDockClient(Self);

  if Assigned(ADockStyle) and Assigned(ADockStyle.ConjoinPanelClass) then
    FConjoinPanelClass := ADockStyle.ConjoinPanelClass
  else
    FConjoinPanelClass := DefaultConjoinPanelClass;

  if Assigned(ADockStyle) and Assigned(ADockStyle.TabDockClass) then
    FTabDockClass := ADockStyle.TabDockClass
  else
    FTabDockClass := DefaultTabDockClass;
end;

procedure TJvDockClient.Assign(Source: TPersistent);
begin
  if Source is TJvDockClient then
  begin
    FConjoinPanelClass := TJvDockClient(Source).FConjoinPanelClass;
    FTabDockClass := TJvDockClient(Source).FTabDockClass;
    ParentVisible := TJvDockClient(Source).ParentVisible;
    NCPopupMenu := TJvDockClient(Source).NCPopupMenu;
    DirectDrag := TJvDockClient(Source).DirectDrag;
    ShowHint := TJvDockClient(Source).ShowHint;
    CanFloat := TJvDockClient(Source).CanFloat;
    // (rom) either bug or needs comment
    FDockLevel := TJvDockClient(Source).DockLevel;
    CustomDock := TJvDockClient(Source).CustomDock; {NEW!}
    DockStyle := TJvDockClient(Source).DockStyle;
  end;
  inherited Assign(Source); // Also copy base class properties!
end;

procedure TJvDockClient.CMVisibleChanged(var Msg: TMessage);
begin
end;

function TJvDockClient.CreateConjoinHostAndDockControl(Control1, Control2: TControl;
  DockType: TAlign): TJvDockConjoinHostForm;
var
  APanel: TJvDockConjoinPanel;
  OldDockWidth, OldDockHeight: Integer;
begin
  Result := TJvDockConjoinHostForm.Create(Application);

  { CreateConjoinPanelClass implicitly sets Result.DockClient.DockStyle via the
    assign in that function }
  APanel := CreateConjoinPanelClass(Result);

  Result.BoundsRect := Control1.BoundsRect;

  Result.Width := Control1.UndockWidth;
  Result.Height := Control1.UndockHeight;

  OldDockWidth := Control1.LRDockWidth;
  OldDockHeight := Control1.TBDockHeight;
  Control1.ManualDock(APanel, nil, alNone);
  Control1.LRDockWidth := OldDockWidth;
  Control1.TBDockHeight := OldDockHeight;

  OldDockWidth := Control2.LRDockWidth;
  OldDockHeight := Control2.TBDockHeight;
  Control2.ManualDock(APanel, nil, DockType);
  Control2.LRDockWidth := OldDockWidth;
  Control2.TBDockHeight := OldDockHeight;

  SetDockSite(Result, False);
end;

function TJvDockClient.CreateConjoinPanelClass(ConjoinHost: TForm): TJvDockConjoinPanel;
begin
  Result := nil;
  TJvDockConjoinHostForm(ConjoinHost).DockClient.Assign(Self);
  if (FConjoinPanelClass <> nil) and
    (FConjoinPanelClass <> TJvDockConjoinPanelClass(ClassType)) then
  begin
    Result := FConjoinPanelClass.Create(ConjoinHost);
    Result.Align := alClient;
    TJvDockConjoinHostForm(ConjoinHost).DockableControl := Result;
    TJvDockConjoinHostForm(ConjoinHost).Panel := Result;
    SetDockSite(Result, True);
  end;
end;

{ CreateTabDockClass creates a TJvDockTabPageControl subclass. The actual subclass
  used is stored in  FTabDockClass which is assigned by the Docking Style object,
  so this is truly polymorphic.

  We need a TJvDockTabPageControl to do tabbed-docking inside a container form.
  The typical container this is placed inside of is either a
  TJvDockConjoinHostForm or TJvDockTabHostForm.
}

function TJvDockClient.CreateTabDockClass(TabHost: TForm): TJvDockTabPageControl;
begin
  Result := nil;
  { copy properties of the JvTabDockPageControl's DockClient
    from the form it contains. }
  TJvDockTabHostForm(TabHost).DockClient.Assign(Self);

  Assert(TJvDockTabHostForm(TabHost).DockClient.CustomDock, 'DEBUG HELPER: Not working!');

  if (FTabDockClass <> nil) and (FTabDockClass <> TJvDockTabClass(ClassType)) then
  begin
    Result := FTabDockClass.Create(TabHost);
    Result.Align := alClient;
    TJvDockTabHostForm(TabHost).DockableControl := Result;
    TJvDockTabHostForm(TabHost).PageControl := Result;
    SetDockSite(Result, True);
  end;
end;

{ This is the main function for creating a tabbed dock, given two non-tab-docked
 controls (usually these are actually Forms), we create a TJvDockTabHostForm,
 and then inside it we create a TabDock container.  A TJvDockTabHostForm is
 an empty TForm containing a DockClient object, and then it contains a set of
 tabbed pages inside the TJvDockTabPageControl object (Page). }

function TJvDockClient.CreateTabHostAndDockControl(Control1, Control2: TControl): TJvDockTabHostForm;
var
  Page: TJvDockTabPageControl;
  OldDockWidth, OldDockHeight: Integer;
begin
  Result := TJvDockTabHostForm.Create(Application);
  Result.Name := 'TJvDockTabHostForm_' + Control1.Name + '_' + Control2.Name + '_' +
    IntToHex(Integer(Result), 8);

  { CreateTabDockClass implicitly sets Result.DockClient.DockStyle via the
    assign in that function }
  Page := CreateTabDockClass(Result);
  Page.Name := Page.ClassName + '_' + Control1.Name + '_' + Control2.Name; // debug!

  Result.BoundsRect := Control1.BoundsRect;

  Result.Width := Control1.UndockWidth;
  Result.Height := Control1.UndockHeight;

  OldDockWidth := Control1.LRDockWidth;
  OldDockHeight := Control1.TBDockHeight;
  Control1.ManualDock(Page, nil, alClient);
  Control1.LRDockWidth := OldDockWidth;
  Control1.TBDockHeight := OldDockHeight;

  OldDockWidth := Control2.LRDockWidth;
  OldDockHeight := Control2.TBDockHeight;
  Control2.ManualDock(Page, nil, alClient);
  Control2.LRDockWidth := OldDockWidth;
  Control2.TBDockHeight := OldDockHeight;

  SetDockSite(Result, False);
  //TJvDockTabHostFormCreatedEvent:
  if Assigned(FOnTabHostFormCreated) then
    FOnTabHostFormCreated(Self, {TabHost:TJvDockTabHostForm} Result);
end;

procedure TJvDockClient.Deactivate;
begin
  if ParentForm.HostDockSite is TJvDockCustomPanel then
    if TJvDockCustomPanel(ParentForm.HostDockSite).JvDockManager <> nil then
      TJvDockCustomPanel(ParentForm.HostDockSite).JvDockManager.ActiveControl := nil;
end;

procedure TJvDockClient.DoFloatDockClients(PanelAlign: TAlign);
begin
  if not (csDestroying in ParentForm.ComponentState) and
    (ParentForm.HostDockSite is TJvDockPanel) and
    (PanelAlign = ParentForm.HostDockSite.Align) then
    RestoreChild;
end;

procedure TJvDockClient.DoFloatDockEachOther;
begin
  if not (csDestroying in ParentForm.ComponentState) and
    (ParentForm.HostDockSite <> nil) and
    (ParentForm.HostDockSite.Parent is TJvDockableForm) then
    RestoreChild;
end;

procedure TJvDockClient.DoFormOnClose(Sender: TObject; var Action: TCloseAction);
begin
  if Action = caHide then
  begin
    HideDockForm(ParentForm);
    FParentVisible := True;
  end;
  inherited DoFormOnClose(Sender, Action);
end;

procedure TJvDockClient.DoFormShowHint(HTFlag: Integer; var HintStr: string;
  var CanShow: Boolean);
begin
  if Assigned(FOnFormShowHint) then
    FOnFormShowHint(HTFlag, HintStr, CanShow);
end;

procedure TJvDockClient.DoMenuPopup(X, Y: Integer);
begin
  if FNCPopupMenu <> nil then
  begin
    FNCPopupMenu.PopupComponent := ParentForm;
    FNCPopupMenu.Popup(X, Y);
  end;
end;

procedure TJvDockClient.DoNCButtonDblClk(Msg: TWMNCHitMessage; Button: TMouseButton;
  MouseStation: TJvDockMouseStation);
begin
  if Assigned(FOnNCButtonDblClk) then
    FOnNCButtonDblClk(Self, Button, Msg.XCursor, Msg.YCursor,
      Msg.HitTest, MouseStation);
end;

procedure TJvDockClient.DoNCButtonDown(Msg: TWMNCHitMessage;
  Button: TMouseButton; MouseStation: TJvDockMouseStation);
begin
  if Assigned(FOnNCButtonDown) then
    FOnNCButtonDown(Self, Button, Msg.XCursor, Msg.YCursor,
      Msg.HitTest, MouseStation);
end;

procedure TJvDockClient.DoNCButtonUp(Msg: TWMNCHitMessage;
  Button: TMouseButton; MouseStation: TJvDockMouseStation);
begin
  if Assigned(FOnNCButtonUp) then
    FOnNCButtonUp(Self, Button, Msg.XCursor, Msg.YCursor,
      Msg.HitTest, MouseStation);
  if Button = mbRight then
    DoMenuPopup(Msg.XCursor, Msg.YCursor);
end;

procedure TJvDockClient.DoNCMouseMove(Msg: TWMNCHitMessage;
  MouseStation: TJvDockMouseStation);
begin
  if Assigned(FOnNCMouseMove) then
    FOnNCMouseMove(Self, Msg.XCursor, Msg.YCursor,
      Msg.HitTest, MouseStation);
end;

procedure TJvDockClient.DoPaintDockGrabber(Canvas: TCanvas;
  Control: TControl; const ARect: TRect);
begin
  if Assigned(FOnPaintDockGrabber) then
    FOnPaintDockGrabber(Canvas, Control, ARect);
end;

procedure TJvDockClient.DoPaintDockSplitter(Canvas: TCanvas;
  Control: TControl; const ARect: TRect);
begin
  if Assigned(FOnPaintDockSplitter) then
    FOnPaintDockSplitter(Canvas, Control, ARect);
end;

// return nil if not found, otherwise, get currently docked parent tabhost form if there is one.

function TJvDockClient.FindTabHostForm: TForm;
var
  OwnerWin: TWinControl;
  TabSheet: TJvDockTabSheet;
  CheckForm: TComponent;
begin
  Result := nil;
  if not Assigned(Owner) then
    Exit;
  if not (Owner is TWinControl) then
    Exit;
  OwnerWin := TWinControl(Owner);
  if Self.DockState <> JvDockState_Docking then
    Exit;
  if not Assigned(OwnerWin.Parent) then
    Exit;
  if OwnerWin.Parent is TJvDockTabSheet then
  begin
    TabSheet := TJvDockTabSheet(OwnerWin.Parent);
    if TabSheet.Owner is TJvDockPageControl then
    begin
      CheckForm := TJvDockPageControl(TabSheet.Owner).Owner;
      if CheckForm is TJvDockTabHostForm then
        Result := TForm(CheckForm);
    end;
  end;
end;

procedure TJvDockClient.FormDockDrop(Source: TJvDockDragDockObject;
  X, Y: Integer);
begin
  if Assigned(DockStyle) then
    DockStyle.FormDockDrop(Self, Source, X, Y);
end;

procedure TJvDockClient.FormDockOver(Source: TJvDockDragDockObject;
  X, Y: Integer; State: TDragState; var Accept: Boolean);
begin
  FormPositionDockRect(Source);
  if Assigned(DockStyle) then
    DockStyle.FormDockOver(Self, Source, X, Y, State, Accept);
end;

procedure TJvDockClient.FormEndDock(Target: TObject; X, Y: Integer);
begin
  if Assigned(DockStyle) then
    DockStyle.FormEndDock(Self, Target, X, Y);
end;

procedure TJvDockClient.FormGetDockEdge(Source: TJvDockDragDockObject;
  MousePos: TPoint; var DropAlign: TAlign);
begin
  if Assigned(DockStyle) then
    DockStyle.FormGetDockEdge(Self, Source, MousePos, DropAlign)
  else
    DropAlign := alNone;
end;

procedure TJvDockClient.FormGetSiteInfo(Source: TJvDockDragDockObject; Client: TControl;
  var InfluenceRect: TRect; MousePos: TPoint; var CanDock: Boolean);
begin
  GetWindowRect(ParentForm.Handle, InfluenceRect);
  InflateRect(InfluenceRect, -4, -4);
  if Assigned(DockStyle) then
    DockStyle.FormGetSiteInfo(Source, Self, Client, InfluenceRect, MousePos, CanDock);
end;

procedure TJvDockClient.FormPositionDockRect(Source: TJvDockDragDockObject);
begin
  if Assigned(DockStyle) then
    DockStyle.FormPositionDockRect(Self, Source);
end;

procedure TJvDockClient.FormStartDock(var Source: TJvDockDragDockObject);
begin
  if Assigned(DockStyle) then
    DockStyle.FormStartDock(Self, Source);
end;

function TJvDockClient.FormUnDock(NewTarget: TWinControl;
  Client: TControl): Boolean;
begin
  if Assigned(DockStyle) then
    Result := DockStyle.FormUnDock(Self, NewTarget, Client)
  else
    Result := False;
end;

function TJvDockClient.GetDockState: Integer;
begin
  Result := JvDockState_Unknown;
  if DockStyle <> nil then
    Result := DockStyle.GetDockState(Self);
end;

function TJvDockClient.GetLRDockWidth: Integer;
begin
  Result := ParentForm.LRDockWidth;
end;

function TJvDockClient.GetTBDockHeight: Integer;
begin
  Result := ParentForm.TBDockHeight;
end;

procedure TJvDockClient.HideParentForm;
begin
  HideDockForm(ParentForm);
end;

procedure TJvDockClient.MakeHideEvent;
begin
  ParentVisible := False;
  if Assigned(FOnFormHide) then
    FOnFormHide(Self);
end;

procedure TJvDockClient.MakeShowEvent;
begin
  if ParentForm.Visible then
  begin
    if Assigned(FOnFormShow) then
      FOnFormShow(Self);
    ParentVisible := True;
  end;
end;

procedure TJvDockClient.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if Operation = opRemove then
  begin
    if AComponent = FLastDockSite then
      LastDockSite := nil
    else
    if AComponent = NCPopupMenu then
      NCPopupMenu := nil;
  end;
end;

procedure TJvDockClient.RemoveDockStyle(ADockStyle: TJvDockBasicStyle);
begin
  DoFloatDockClients(alTop);
  DoFloatDockClients(alBottom);
  DoFloatDockClients(alLeft);
  DoFloatDockClients(alRight);
  DoFloatDockEachOther;

  FConjoinPanelClass := nil;
  FTabDockClass := nil;

  if JvGlobalDockManager <> nil then
    JvGlobalDockManager.UnRegisterDockClient(Self);
end;

procedure TJvDockClient.RestoreChild;
begin
  DockStyle.RestoreClient(Self);
end;

procedure TJvDockClient.SetBottomDock(const Value: Boolean);
begin
  if not Value then
    DoFloatDockClients(alBottom);
  inherited SetBottomDock(Value);
end;

procedure TJvDockClient.SetCanFloat(const Value: Boolean);
begin
  FCanFloat := Value;
end;

procedure TJvDockClient.SetCurrentDockSite(const Value: TWinControl);
begin
  FCurrentDockSite := Value;
end;

procedure TJvDockClient.SetDockLevel(const Value: Integer);
begin
  if not ParentForm.Floating then
    if FDockLevel <> Value then
      DoFloatForm(ParentForm);
  FDockLevel := Value;
end;

procedure TJvDockClient.SetEachOtherDock(const Value: Boolean);
begin
  if not Value then
    DoFloatDockEachOther;
  inherited SetEachOtherDock(Value);
end;

procedure TJvDockClient.SetEnableCloseButton(const Value: Boolean);
begin
  FEnableCloseButton := Value;
end;

procedure TJvDockClient.SetEnableDock(const Value: Boolean);
begin
  if not Value then
  begin
    DoFloatDockClients(alTop);
    DoFloatDockClients(alBottom);
    DoFloatDockClients(alLeft);
    DoFloatDockClients(alRight);
    DoFloatDockEachOther;
  end;
  if ParentForm <> nil then
    if Value then
      ParentForm.DragKind := dkDock
    else
      ParentForm.DragKind := dkDrag;
  inherited SetEnableDock(Value);
end;

procedure TJvDockClient.SetLastDockSite(ALastDockSite: TWinControl);
var
  JvDockManager: IJvDockManager;
begin
  if ALastDockSite <> FLastDockSite then
  begin
    if FLastDockSite <> nil then
    begin
      FLastDockSite.RemoveFreeNotification(Self);

      if TWinControlAccessProtected(FLastDockSite).UseDockManager and
        Supports(TWinControlAccessProtected(FLastDockSite).DockManager, IJvDockManager, JvDockManager) then
        JvDockManager.RemoveControl(Self.ParentForm);
    end;

    FLastDockSite := ALastDockSite;

    if FLastDockSite <> nil then
      FLastDockSite.FreeNotification(Self);
  end;
end;

procedure TJvDockClient.SetLeftDock(const Value: Boolean);
begin
  if not Value then
    DoFloatDockClients(alLeft);
  inherited SetLeftDock(Value);
end;

procedure TJvDockClient.SetLRDockWidth(const Value: Integer);
begin
  if ParentForm.LRDockWidth <> Value then
    ParentForm.LRDockWidth := Value;
end;

procedure TJvDockClient.SetNCPopupMenu(Value: TPopupMenu);
begin
  FNCPopupMenu := Value;
  if Value <> nil then
    Value.FreeNotification(Self);
end;

procedure TJvDockClient.SetParentVisible(const Value: Boolean);
begin
  FParentVisible := Value;
end;

procedure TJvDockClient.SetRightDock(const Value: Boolean);
begin
  if not Value then
    DoFloatDockClients(alRight);
  inherited SetRightDock(Value);
end;

procedure TJvDockClient.SetTBDockHeight(const Value: Integer);
begin
  if ParentForm.TBDockHeight <> Value then
    ParentForm.TBDockHeight := Value;
end;

procedure TJvDockClient.SetTopDock(const Value: Boolean);
begin
  if not Value then
    DoFloatDockClients(alTop);
  inherited SetTopDock(Value);
end;

procedure TJvDockClient.SetUnDockLeft(const Value: Integer);
begin
  FUnDockLeft := Value;
end;

procedure TJvDockClient.SetUnDockTop(const Value: Integer);
begin
  FUnDockTop := Value;
end;

procedure TJvDockClient.SetVSPaneWidth(const Value: Integer);
begin
  FVSPaneWidth := Value;
end;

procedure TJvDockClient.ShowParentForm;
begin
  ShowDockForm(ParentForm);
end;

procedure TJvDockClient.WindowProc(var Msg: TMessage);
var
  OldOrient: TDockOrientation;
begin
  if Assigned(FDockStyle) then
    if FDockStyle.DockClientWindowProc(Self, Msg) then
      Exit;
  if not (csDesigning in ComponentState) then
  begin
    case Msg.Msg of
      CM_SHOWINGCHANGED:
        if IsWinXP and JvGlobalDockIsLoading then
          Exit;
      WM_NCLBUTTONDOWN:
        begin
          WMNCLButtonDown(TWMNCHitMessage(Msg));
          if Msg.Result = 1 then
            Exit;
        end;
      WM_NCLBUTTONUP:
        WMNCLButtonUp(TWMNCHitMessage(Msg));
      WM_NCLBUTTONDBLCLK:
        WMNCLButtonDblClk(TWMNCHitMessage(Msg));
      WM_NCMBUTTONDOWN:
        WMNCMButtonDown(TWMNCHitMessage(Msg));
      WM_NCMBUTTONUP:
        WMNCMButtonUp(TWMNCHitMessage(Msg));
      WM_NCMBUTTONDBLCLK:
        WMNCMButtonDblClk(TWMNCHitMessage(Msg));
      WM_NCRBUTTONDOWN:
        begin
          WMNCRButtonDown(TWMNCHitMessage(Msg));
          if FNCPopupMenu <> nil then
            Exit;
        end;
      WM_NCRBUTTONUP:
        WMNCRButtonUp(TWMNCHitMessage(Msg));
      WM_NCRBUTTONDBLCLK:
        WMNCRButtonDblClk(TWMNCHitMessage(Msg));
      WM_NCMOUSEMOVE:
        WMNCMouseMove(TWMNCHitMessage(Msg));
      WM_SIZE:
        WMSize(TWMSize(Msg));
      WM_ACTIVATE:
        WMActivate(TWMActivate(Msg));
      WM_WINDOWPOSCHANGED:
        begin
          ParentForm.ControlState := ParentForm.ControlState + [csDocking];
          OldOrient := ParentForm.DockOrientation;
          ParentForm.DockOrientation := doNoOrient;
          try
            inherited WindowProc(Msg);
          finally
            ParentForm.ControlState := ParentForm.ControlState - [csDocking];
            ParentForm.DockOrientation := OldOrient;
          end;
          Exit;
        end;
      CM_ENTER:
        Activate;
      CM_EXIT:
        Deactivate;
      CM_VISIBLECHANGED:
        CMVisibleChanged(Msg);
    end;
  end;

  inherited WindowProc(Msg);

  if Msg.Msg = WM_SETTEXT then
    if ParentForm.HostDockSite is TJvDockCustomControl then
      TJvDockCustomContr