VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
  Persistable = 0  'NotPersistable
  DataBindingBehavior = 0  'vbNone
  DataSourceBehavior  = 0  'vbNone
  MTSTransactionMode  = 0  'NotAnMTSObject
END
Attribute VB_Name = "SADockSystem"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit

' Pane IDs for docking system
' Tag format :-
'-   &hYYYY XXXX
'-   X's are numeric type identifier
'-   Y's are bit flags
'-   X values (TAGIDs) :-
' See msamain.bas for sa2001 default type values
Private Const SADOCK_TAGID_MASK As Long = 32767         ' TagIDs only used in the low word (&HFFFF - can't use due to sign extension)
Private Const SADOCK_TAGFLAGS_ISINUSE As Long = &H10000 ' Tag Flags only used in the high word

Public Enum SADOCKSYS_DOCKINGAREA
    SADS_DA_Top = 1
    SADS_DA_Bottom = 2
    SADS_DA_Left = 4
    SADS_DA_Right = 8
    SADS_DA_Float = 16
    SADS_DA_Docked = 64 ' We don't know where it is docked, but it is docked
    SADS_DA_Unknown = 128 ' Unknown to the docking system, this is definitely not docked
End Enum
Public Enum SADOCKSYS_WINDOWSTATE
    SADS_WS_Normal = 0
    SADS_WS_Minimised = 1
    SADS_WS_Maximised = 2
End Enum

Private m_colDockedPanesByhWnd As New Collection
Private m_colDockedFormsByPaneID As New Collection
Private m_bDestroyingPane As Boolean
Private m_bClosingDockSystem As Boolean

Private DockIdFreedList As Collection  ' Collection used to hold Dock Ids which have been freed
Private NextAvailableDockID As Long 'Next dockID to use

Private lLastActivePaneID As Long

Public Event PaneClose(ByVal v_lngDockID As Long)

Public WithEvents m_objDock As DockingPane
Attribute m_objDock.VB_VarHelpID = -1

Public Function Init(ByRef r_objDockPane As DockingPane)
    Set m_objDock = r_objDockPane   ' Init our reference to the docking system
    Set DockIdFreedList = New Collection
    
#If DOCKDEBUGGING Then
    LogMessageDock "Init Dock System" 'DEV_STRING
#End If
    
    ' Initialise the docking system with the commandbar control - CodeJock specific
    m_objDock.SetCommandBars fMainForm.ctlCommandBar
    
    With m_objDock.Options
        .AlphaDockingContext = True
        .ThemedFloatingFrames = True
        .ShowDockingContextStickers = True
        .HideClient = False
        .ShowCaptionMaximizeButton = True
        .ShowFloatingFramePinButton = True
    End With
    With m_objDock.PaintManager
        .HighlightActiveCaption = True
    End With
    m_objDock.ToolTipContext.Style = xtpToolTipBalloon
    
    Set m_objDock.Icons = fMainForm.ctlImageMan.Icons
    NextAvailableDockID = -1
    
    SetupControlLocale
End Function

Private Sub SetupControlLocale()
    Dim strValue As String
    Dim strResource As String
    Dim strAppPath As String

    On Error GoTo ErrorHandler

    Call SAGetSetting("Locale", strValue, 3, "SystemArchitect") 'DEV_STRING
        
    If strValue = "" Then 'DEV_STRING
        strValue = "409" 'DEV_STRING
    End If
    
    strResource = "SuitePro.Resource" & strValue & ".dll" 'DEV_STRING

    strAppPath = SA_File_GetFolderLocation(fMainForm.hWnd, SASF_SA2001InstallPath)
    strAppPath = SA_File_AddSlashIfNeeded(strAppPath)
    
    DockingPaneGlobalSettings.ResourceFile = strAppPath & strResource
    
    Exit Sub
    
ErrorHandler:
    If CmdLineQAReporting Then
        SAMessageBox "Unable to set the requested language for the docking system" 'DEV_STRING
    End If
End Sub

Public Sub Load(ByVal v_strFilename As String)
    Dim varFile As Variant
    Dim strProfile As String
    
#If DOCKDEBUGGING Then
    LogMessageDock "Load Dock file " & v_strFilename 'DEV_STRING
#End If
    
    varFile = FreeFile
    On Error Resume Next
    Open v_strFilename For Input As varFile
    If Err.Number = 0 Then
        Input #varFile, strProfile
        Close varFile
    End If
    On Error GoTo 0
    
    SetState strProfile
End Sub

Public Sub SetState(ByVal v_strProfile As String)
    Dim objPane As Pane
    Dim lngIndex As Long
    Dim lngDummy As Long
        
#If DOCKDEBUGGING Then
    LogMessageDock "SetState on dock system" 'DEV_STRING
#End If
    
    On Error Resume Next
    m_objDock.LoadStateFromString v_strProfile
    
    Set m_colDockedFormsByPaneID = New Collection
    Set m_colDockedPanesByhWnd = New Collection
    Set DockIdFreedList = New Collection
    
    SetUIThemes
    
    NextAvailableDockID = GetNextAvailableDockIDStart(Me, NEXTAVAILABLEDOCKIDSTART)
    Call SetDockingPaneFont(m_objDock)
End Sub

Public Sub Save(ByVal v_strFilename As String)
    Dim varFile As Variant
    
#If DOCKDEBUGGING Then
    LogMessageDock "Save Dock System - " & v_strFilename 'DEV_STRING
#End If
    
    varFile = FreeFile()
    Open v_strFilename For Output As varFile
    Print #varFile, m_objDock.SaveStateToString
    Close varFile
End Sub

Public Function GetState() As String
#If DOCKDEBUGGING Then
    LogMessageDock "GetState from Dock System" 'DEV_STRING
#End If
    
    GetState = m_objDock.SaveStateToString
End Function

Public Sub CloseDockSystem()
    Dim objPane As Pane
    Dim lngIndex As Long
    
#If DOCKDEBUGGING Then
    LogMessageDock "Close Dock System" 'DEV_STRING
#End If

    m_bClosingDockSystem = True
    
    For lngIndex = m_objDock.PanesCount To 1 Step -1
        Set objPane = m_objDock.Panes(lngIndex)
#If DOCKDEBUGGING Then
        LogMessageDock "Close Dock System - Destroying pane - " & objPane.Title 'DEV_STRING
#End If
        DestroyPaneByID objPane.Id
    Next
    
    m_bClosingDockSystem = False
End Sub

Public Function GetSpecialPanesCount() As Integer

    'When exiting SA save the open/close state of any special windows
    'On future starts of SA we want to display any open windows

    Dim objPane As Pane
    Dim lngIndex As Long
    Dim lngMax As Long
    Dim iCnt As Integer
    
    On Error GoTo ErrorHandler1
    lngMax = m_objDock.PanesCount

    On Error GoTo ErrorHandler2
    For lngIndex = 1 To lngMax
        Set objPane = m_objDock.Panes(lngIndex)
        ' Note you can't check for closed / hidden panes here
        Select Case GetTagID(objPane.Tag)
            Case SADOCK_TAGID_BROWSE, _
                SADOCK_TAGID_NEW_BROWSE, _
                SADOCK_TAGID_DETAIL, _
                SADOCK_TAGID_FRMDGMPREVIEW, _
                SADOCK_TAGID_REFERENCEBY, _
                SADOCK_TAGID_MATRIXBROWSER, _
                SADOCK_TAGID_PICBROWSE, _
                SADOCK_TAGID_FRAMEWORKGRID:
                iCnt = iCnt + 1
        End Select
ResumePt:
    Next

    GetSpecialPanesCount = iCnt

    Exit Function
    
ErrorHandler2:
    Resume ResumePt

ErrorHandler1:
End Function

' iMode = 0: Show, 1: Selected, 2: Active, 3: Show Fwk panes&PicBrow only, 4: Show Explorer panes only
Public Sub LoadSpecialPanesState(ByVal v_iMode As Integer)
End Sub

Public Sub SaveSpecialPanesState(Optional ByVal bSaveActivePane As Boolean = True)
End Sub

Public Function IsDocked(ByRef r_frmForm As Form) As Boolean
    Dim objPane As Pane
        
    On Error Resume Next
    Set objPane = m_colDockedPanesByhWnd("hWnd" & r_frmForm.hWnd) 'DEV_STRING
    On Error GoTo 0
    If Not objPane Is Nothing Then
        IsDocked = True
    End If

#If DOCKDEBUGGING Then
    LogMessageDock "IsDocked - " & r_frmForm.Caption & " = " & IsDocked 'DEV_STRING
#End If
End Function

Public Function IsPaneDocked(ByVal lngPaneID As Long) As Boolean
    Dim objPane As Pane
        
    On Error Resume Next
    Set objPane = GetPaneByID(lngPaneID)
    On Error GoTo 0
    If Not objPane Is Nothing Then
        If objPane.Floating Then
            IsPaneDocked = False
        Else
            IsPaneDocked = True
        End If
    End If

#If DOCKDEBUGGING Then
    LogMessageDock "IsPaneDocked - " & lngPaneID & " = " & IsPaneDocked 'DEV_STRING
#End If
End Function

Public Function DockingArea(ByRef r_frmForm As Form) As SADOCKSYS_DOCKINGAREA
    Dim objPane As Pane
    
    On Error Resume Next
    Set objPane = m_colDockedPanesByhWnd("hWnd" & r_frmForm.hWnd) 'DEV_STRING
    On Error GoTo 0
    If Not objPane Is Nothing Then
        If objPane.Floating Then
            DockingArea = SADS_DA_Float
        Else
            DockingArea = SADS_DA_Docked
        End If
    Else
        DockingArea = SADS_DA_Unknown
    End If
    
#If DOCKDEBUGGING Then
    LogMessageDock "DockingArea - " & r_frmForm.Caption & " = " & DockingArea 'DEV_STRING
#End If
    
End Function

Public Function GetPaneByID(ByVal v_lngPaneID As Long) As Pane
    Dim objPane As Pane
    Dim lngIndex As Long
    
    If v_lngPaneID <> 0 Then
        For lngIndex = 1 To m_objDock.PanesCount
            Set objPane = m_objDock.Panes(lngIndex)
            If objPane.Id = v_lngPaneID Then
                Set GetPaneByID = objPane
                Exit For
            End If
        Next
    End If
#If DOCKDEBUGGING Then
    Dim strTitle As String
    On Error Resume Next
    strTitle = GetPaneByID.Title
    LogMessageDock "GetPaneByID - " & v_lngPaneID & " = " & strTitle 'DEV_STRING
#End If
End Function

Public Function GetPaneIDByhWnd(ByVal v_lngHWnd As Long) As Long
    Dim objPane As Pane
    Dim lngIndex As Long
    
    Set objPane = GetPaneByhWnd(v_lngHWnd)
    If Not objPane Is Nothing Then
        GetPaneIDByhWnd = objPane.Id
    End If
    
#If DOCKDEBUGGING Then
    LogMessageDock "GetPaneIDByhWnd - " & v_lngHWnd & " = " & GetPaneIDByhWnd 'DEV_STRING
#End If
End Function

Public Function GetPaneByhWnd(ByVal v_lngHWnd As Long) As Pane
    Dim objPane As Pane
    Dim lngIndex As Long
    
    On Error Resume Next
    Set GetPaneByhWnd = m_colDockedPanesByhWnd("hWnd" & v_lngHWnd) 'DEV_STRING
    On Error GoTo 0
    
    If GetPaneByhWnd Is Nothing Then
        ' Double check through the panes collection
        For lngIndex = 1 To m_objDock.PanesCount
            Set objPane = m_objDock.Panes(lngIndex)
            If objPane.Handle = v_lngHWnd Then
                Set GetPaneByhWnd = objPane
                Exit For
            End If
        Next
    End If
#If DOCKDEBUGGING Then
    Dim strTitle As String
    On Error Resume Next
    strTitle = GetPaneByhWnd.Title
    LogMessageDock "GetPaneByhWnd - " & v_lngHWnd & " = " & strTitle 'DEV_STRING
#End If
End Function

Public Sub Resize()
    Dim objPane As Pane
    Dim lngIndex As Long
    Dim lngWidth As Long
    Dim lngHeight As Long
    
#If DOCKDEBUGGING Then
    LogMessageDock "Resize Dock System" 'DEV_STRING
#End If
    
    For lngIndex = 1 To m_objDock.PanesCount
        Set objPane = m_objDock.Panes(lngIndex)
        
        If objPane.Hidden Then
            lngWidth = (fMainForm.Width / Screen.TwipsPerPixelX) / 2
            lngHeight = (fMainForm.Height / Screen.TwipsPerPixelY) / 2
        Else
            lngWidth = (fMainForm.Width / Screen.TwipsPerPixelX)
            lngHeight = (fMainForm.Height / Screen.TwipsPerPixelY)
        End If
        
        If lngWidth < 100 Then
            lngWidth = fMainForm.ScaleWidth / Screen.TwipsPerPixelX
        End If
        
        If lngHeight < 100 Then
            lngHeight = fMainForm.ScaleHeight / Screen.TwipsPerPixelY
        End If
        
        objPane.MaxTrackSize.SetSize lngWidth, lngHeight
    Next
    m_objDock.RecalcLayout
    m_objDock.RedrawPanes
End Sub

Public Sub AttachPane(ByVal v_lngDockSourceID As Long, ByVal v_lngDockTargetID As Long)
#If DOCKDEBUGGING Then
    LogMessageDock "AttachPane - " & v_lngDockSourceID & " - " & v_lngDockTargetID 'DEV_STRING
#End If
    
    m_objDock.AttachPane GetPaneByID(v_lngDockSourceID), GetPaneByID(v_lngDockTargetID)
End Sub

' v_lngPaneID used by ShowNewBrowse when reusing closed pane
Public Function Dock(ByRef r_frmForm As Form, ByVal v_enuDockArea As SADOCKSYS_DOCKINGAREA, ByVal v_lngDockType As Long, Optional ByVal v_strTitle As String, Optional ByRef r_frmNeighbourForm As Form = Nothing, Optional ByVal v_bShow As Boolean = True, Optional ByVal v_blnAttachToPreviousType As Boolean = True, Optional ByVal v_lngPaneID As Long) As Long
    Dim objPane As Pane
    Dim objPaneAttachTo As Pane
    Dim objPaneNeighbour As Pane
    Dim enuDockingDir As DockingDirection
    Dim lngPaneID As Long
    Dim strDummy As String
        
    Select Case v_enuDockArea
        Case SADS_DA_Top:
            enuDockingDir = DockTopOf
        Case SADS_DA_Bottom:
            enuDockingDir = DockBottomOf
        Case SADS_DA_Left:
            enuDockingDir = DockLeftOf
        Case SADS_DA_Right:
            enuDockingDir = DockRightOf
        Case Else
            enuDockingDir = DockLeftOf
    End Select
    
    On Error Resume Next
    Set objPaneNeighbour = m_colDockedPanesByhWnd("hWnd" & r_frmNeighbourForm.hWnd) 'DEV_STRING
    On Error GoTo ErrorHandler
    
    On Error Resume Next
    Set objPane = m_colDockedPanesByhWnd("hWnd" & r_frmForm.hWnd) 'DEV_STRING
    On Error GoTo ErrorHandler
    
    If objPane Is Nothing Then
        If Not v_lngPaneID = 0 Then
            lngPaneID = v_lngPaneID
        Else
            ' Not found - try to find an empty pane to use
            lngPaneID = FindLastPaneByType(v_lngDockType)
        End If
        On Error Resume Next
        Set objPane = GetPaneByID(lngPaneID)
        On Error GoTo ErrorHandler
        If Not objPane Is Nothing Then
            
            If (objPane.Tag And SADOCK_TAGFLAGS_ISINUSE) <> SADOCK_TAGFLAGS_ISINUSE Then
                On Error Resume Next
                ' Remove any preexisting entries for this ID and Handle
                m_colDockedFormsByPaneID.Remove "ID" & lngPaneID 'DEV_STRING
                m_colDockedPanesByhWnd.Remove "hWnd" & r_frmForm.hWnd 'DEV_STRING

                r_frmForm.Visible = False
                strDummy = r_frmForm.Caption  ' Ensure we have a hwnd - this forces a load
                
                ' Add the new entries for this ID and handle
                m_colDockedPanesByhWnd.Add objPane, "hWnd" & r_frmForm.hWnd 'DEV_STRING
                m_colDockedFormsByPaneID.Add r_frmForm, "ID" & lngPaneID 'DEV_STRING
                objPane.Tag = objPane.Tag Or SADOCK_TAGFLAGS_ISINUSE
' DO NOT DO THIS - It breaks the Dock system focus-                objPane.Handle = r_frmForm.hWnd

                If v_strTitle <> SA_VB_EmptyString Then
                    objPane.Title = v_strTitle
                Else
                    objPane.Title = r_frmForm.Caption
                End If
                r_frmForm.Caption = SA_VB_EmptyString

                If v_bShow Then ' The following ShowPane call triggers the AttachPane event if lngPaneID is valid
                    m_objDock.ShowPane lngPaneID        ' DO NOT change the Closed property state - we do not get attached
                    DoEvents    ' Ensure we get attached
                Else
                    objPane.Closed = True
                End If
            Else
                If v_blnAttachToPreviousType Then
                    ' Caller wants to attach to preexisting panes of this type
                    Set objPaneAttachTo = objPane
                End If
                Set objPane = Nothing   ' This pane is not being used as the pane for this dock operation
            End If
        End If
    End If
    
    If objPane Is Nothing Then
        ' Still no pane so create it
        lngPaneID = GetNextAvailableDockID()
        
        ' Sort out the flags
        If v_enuDockArea = SADS_DA_Float Then
            ' Asked to float - do not neighbour
            Set objPaneNeighbour = Nothing
        End If
        If Not v_blnAttachToPreviousType Then
            ' Do not want to attach
            Set objPaneAttachTo = Nothing
        End If
        If Not objPaneAttachTo Is Nothing Then
            ' We are attaching to a pane not neigbouring with one
            Set objPaneNeighbour = Nothing
        End If
        
        Set objPane = m_objDock.CreatePane(lngPaneID, r_frmForm.Width / Screen.TwipsPerPixelX, r_frmForm.Height / Screen.TwipsPerPixelY, enuDockingDir, objPaneNeighbour)
        objPane.Tag = v_lngDockType ' Set the type
        
        If v_enuDockArea = SADS_DA_Float And objPaneAttachTo Is Nothing Then
            m_objDock.FloatPane objPane, (fMainForm.Left + 100) / Screen.TwipsPerPixelX, (fMainForm.Top + 100) / Screen.TwipsPerPixelY, (fMainForm.Left + 100 + r_frmForm.Width) / Screen.TwipsPerPixelX, (fMainForm.Top + 100 + r_frmForm.Height) / Screen.TwipsPerPixelY
        End If
        
        r_frmForm.Visible = False
        strDummy = r_frmForm.Caption  ' Ensure we have a hwnd - this forces a load
        
        m_colDockedPanesByhWnd.Add objPane, "hWnd" & r_frmForm.hWnd 'DEV_STRING
        m_colDockedFormsByPaneID.Add r_frmForm, "ID" & lngPaneID 'DEV_STRING
        objPane.Tag = objPane.Tag Or SADOCK_TAGFLAGS_ISINUSE
' DO NOT DO THIS - It breaks the Dock system focus-                objPane.Handle = r_frmForm.hWnd
        
        If v_strTitle <> SA_VB_EmptyString Then
            objPane.Title = v_strTitle
        Else
            objPane.Title = r_frmForm.Caption
        End If
        r_frmForm.Caption = SA_VB_EmptyString
        
        If Not objPaneAttachTo Is Nothing Then
            m_objDock.AttachPane objPane, objPaneAttachTo
        End If
        If v_bShow Then
            ShowPane objPane.Id
        Else
            objPane.Closed = True
        End If
        
    End If
    
    If Not objPane Is Nothing Then
        SetPaneIcon objPane
        Dock = objPane.Id
        If v_bShow Then
            objPane.Select
        End If
    End If
    
    m_objDock.RecalcLayout
    m_objDock.RedrawPanes
    m_objDock.UpdatePanes

    If Not r_frmNeighbourForm Is Nothing Then
        r_frmNeighbourForm.Refresh
    End If
    If Not r_frmForm Is Nothing Then
        r_frmForm.Refresh
    End If
                
#If DOCKDEBUGGING Then
    Dim strCaptionNeighbour As String
    On Error Resume Next
    strCaptionNeighbour = r_frmNeighbourForm.Caption
    LogMessageDock "Dock Dock System - " & r_frmForm.Caption & " - Area=" & v_enuDockArea & " - Type=" & v_lngDockType & " - Title=" & v_strTitle & " - Neighbour=" & strCaptionNeighbour & " - Show=" & v_bShow & " - AttachType=" & v_blnAttachToPreviousType 'DEV_STRING
#End If
    Exit Function
    
ErrorHandler:
    #If DOCKDEBUGGING Then
    LogMessageDock "Error - " & Err.Number & " - " & Err.Description
    #End If
    Resume Next
End Function

Public Sub ShowPane(ByVal v_lngDockID As Long)
    Dim objForm As Form
    On Error Resume Next
    If v_lngDockID <> 0 Then
        m_objDock.ShowPane v_lngDockID
        
        On Error Resume Next
        Set objForm = m_colDockedFormsByPaneID("ID" & v_lngDockID) 'DEV_STRING
        objForm.Refresh
        m_objDock.UpdatePanes
        ' The following has been removed because it triggered a deadlock causing the UI to freeze, CR448844
        ' DoEvents                ' Give the form a nudge
        On Error GoTo 0
        
        SelectPane v_lngDockID
    End If

#If DOCKDEBUGGING Then
    LogMessageDock "ShowPane - " & v_lngDockID 'DEV_STRING
#End If
End Sub

Public Sub HidePane(ByVal v_lngDockID As Long)
    On Error Resume Next
    Dim objPane As Pane
    Set objPane = GetPaneByID(v_lngDockID)
    If Not objPane Is Nothing Then
        m_objDock.HidePane objPane
    End If
#If DOCKDEBUGGING Then
    LogMessageDock "HidePane - " & v_lngDockID 'DEV_STRING
#End If
End Sub

Public Sub ClosePane(ByVal v_lngDockID As Long)
    On Error Resume Next
    Dim objPane As Pane
    Set objPane = GetPaneByID(v_lngDockID)
    If Not objPane Is Nothing Then
        objPane.Close
    End If
#If DOCKDEBUGGING Then
    LogMessageDock "ClosePane - " & v_lngDockID 'DEV_STRING
#End If
End Sub

Public Sub SelectPane(ByVal v_lngDockID As Long)
    On Error Resume Next
    Dim objPane As Pane
    
    Set objPane = GetPaneByID(v_lngDockID)
    If Not objPane Is Nothing Then
        objPane.Select
    End If
#If DOCKDEBUGGING Then
    LogMessageDock "SelectPane - " & v_lngDockID 'DEV_STRING
#End If
End Sub

Public Function IsPaneVisible(ByVal v_lngDockID As Long) As Boolean
    Dim objPane As Pane
    Set objPane = GetPaneByID(v_lngDockID)
    If Not objPane Is Nothing Then
        IsPaneVisible = Not objPane.Closed
    End If
#If DOCKDEBUGGING Then
    LogMessageDock "IsPaneVisible - " & v_lngDockID 'DEV_STRING
#End If
End Function

Public Function IsPaneDisplayingContent(ByVal v_lngDockID As Long) As Boolean
    Dim objPane As Pane
    Set objPane = GetPaneByID(v_lngDockID)
    If Not objPane Is Nothing Then
        IsPaneDisplayingContent = (objPane.Handle <> 0)
    End If
#If DOCKDEBUGGING Then
    LogMessageDock "IsPaneDisplayingContent - " & v_lngDockID 'DEV_STRING
#End If
End Function

' NB: this will keep the last pane of a given tagid type
Public Sub DestroyPaneByPane(ByRef objPane As Pane)
End Sub

Public Sub DestroyPaneByID(ByVal lPaneID As Long)
End Sub

Public Sub DestroyPaneByhWnd(ByVal v_lngHWnd As Long)
End Sub

Public Sub AutoHideAllPanes(ByVal bHide As Boolean)
End Sub

Public Sub CloseActivePane()
End Sub

Public Function IsActivePane() As Boolean
End Function

Public Sub HideActivePane()
End Sub

Public Sub FloatActivePane()
End Sub

Public Sub HideWorkspace()
End Sub


Public Function GetNextAvailableDockID() As Long
  If DockIdFreedList.Count > 0 Then
    GetNextAvailableDockID = DockIdFreedList.Item(1)
    DockIdFreedList.Remove (1) ' No longer available
  Else
    If NextAvailableDockID >= NEXTAVAILABLEDOCKIDEND Then
      
      SAMessageBox SAXRes.FormatLocalString(SAXRes.GetLocalString(IDS_sa2001sadocksystemcls_____toomanydockedpanesareopennrecommendedactionclosesomewindowsorrestart0), SAXRes.GetLocalString(IDSProductName)), vbOKOnly + vbCritical
      
      ' Get rid of the last dock pane added, and reuse the id
      On Error GoTo ErrExit
      DestroyPaneByID NextAvailableDockID - 1
      GetNextAvailableDockID = DockIdFreedList.Item(1) ' Re-use the id
      DockIdFreedList.Remove (1) ' Not available anymore
      
      LogMessage "Dock system - Out of dock pane IDs" 'DEV_STRING
      LogMessage "Dock system - Re-using dock pane ID : " + Format(GetNextAvailableDockID) 'DEV_STRING
      
    Else
      GetNextAvailableDockID = NextAvailableDockID
      NextAvailableDockID = NextAvailableDockID + 1
    End If
  End If
  Exit Function
ErrExit:
  ' Not much else we can do
End Function

Public Function FreeDockId(theID As Long)
    On Error Resume Next
    DockIdFreedList.Add theID, str(theID)  ' Add the item - don't worry if it already exists
    On Error GoTo 0
End Function

Private Function GetNextAvailableDockIDStart(Dock As SADockSystem, StartId As Long) As Long
  ' Find the largest internal tool id
    Dim largestId As Long
    
    largestId = RenumberPanes(NEXTAVAILABLEDOCKIDSTART, NEXTAVAILABLEDOCKIDEND)
    GetNextAvailableDockIDStart = largestId + 1
End Function

Private Function RenumberPanes(ByVal v_lngMinId As Long, ByVal v_lngMaxID As Long) As Long
    Dim lngIndex As Long
    Dim objPane As Pane
    Dim objForm As Form
    Dim colTemp As New Collection
    
#If DOCKDEBUGGING Then
    LogMessageDock "Renumbering Panes" 'DEV_STRING
#End If
    Set m_colDockedFormsByPaneID = New Collection
    For lngIndex = 1 To m_objDock.PanesCount
        Set objPane = m_objDock.Panes(lngIndex)
                
        On Error Resume Next
        Set objForm = Nothing
        Set objForm = m_colDockedFormsByPaneID(objPane.Id)
        On Error GoTo 0
        
        If Not objForm Is Nothing Then
            colTemp.Add objForm, "ID" & lngIndex 'DEV_STRING
        End If
        objPane.Id = lngIndex
    Next
    While m_colDockedFormsByPaneID.Count > 0
        m_colDockedFormsByPaneID.Remove 1       ' Clear out the old collection
    Wend
    Set m_colDockedFormsByPaneID = Nothing  ' Nuke the old collection
    Set m_colDockedFormsByPaneID = colTemp  ' Use the new collection
    RenumberPanes = lngIndex
#If DOCKDEBUGGING Then
    LogMessageDock "Renumbering Panes - new available index = " & (lngIndex + 1) 'DEV_STRING
#End If
End Function

Public Function FindLastPaneByType(ByVal v_lngDockType As Long) As Long
    Dim lngIndex As Long
    Dim objPane As Pane
    
    For lngIndex = m_objDock.PanesCount To 1 Step -1
        Set objPane = m_objDock.Panes(lngIndex)
        If GetTagID(objPane.Tag) = v_lngDockType Then
            FindLastPaneByType = objPane.Id
            Exit For
        End If
    Next

#If DOCKDEBUGGING Then
    LogMessageDock "FindLastPaneByType - Type=" & v_lngDockType & " - ID=" & FindLastPaneByType 'DEV_STRING
#End If
End Function

Public Function FindFirstClosedPaneByType(ByVal v_lngDockType As Long) As Long
    Dim lngIndex As Long
    Dim objPane As Pane
    
    For lngIndex = m_objDock.PanesCount To 1 Step -1
        Set objPane = m_objDock.Panes(lngIndex)
        If GetTagID(objPane.Tag) = v_lngDockType And objPane.Handle = 0 Then
            FindFirstClosedPaneByType = objPane.Id
            Exit For
        End If
    Next

#If DOCKDEBUGGING Then
    LogMessageDock "FindFirstClosedPaneByType - Type=" & v_lngDockType & " - ID=" & FindLastPaneByType 'DEV_STRING
#End If
End Function

Private Function CountPanesByType(ByVal v_lngDockType As Long) As Long
    Dim lngIndex As Long
    Dim objPane As Pane
    Dim lngCount As Long
    
    For lngIndex = m_objDock.PanesCount To 1 Step -1
        Set objPane = m_objDock.Panes(lngIndex)
        If GetTagID(objPane.Tag) = v_lngDockType Then
            lngCount = lngCount + 1
        End If
    Next
    CountPanesByType = lngCount

#If DOCKDEBUGGING Then
    LogMessageDock "CountPanesByType - Type=" & v_lngDockType & " - Count=" & CountPanesByType 'DEV_STRING
#End If
End Function

 Private Sub SetPaneIcon(ByRef oPane As Pane)
    
    'Sets the icon to be displayed when a pane is in auto hide mode.

    On Error GoTo ErrorHandler
    
    If Not oPane Is Nothing Then
        Select Case GetTagID(oPane.Tag)
            Case SADOCK_TAGID_BROWSE, SADOCK_TAGID_NEW_BROWSE:
                oPane.iconID = 30005
                
            Case SADOCK_TAGID_FRMDGMPREVIEW:
                oPane.iconID = 145
                
            Case SADOCK_TAGID_DETAIL:
                oPane.iconID = 10034
                
            Case SADOCK_TAGID_REFERENCEBY:
               oPane.iconID = 761
                
            Case SADOCK_TAGID_MATRIXBROWSER:
                oPane.iconID = 31002
                
            Case SADOCK_TAGID_FDISPLAY:
                oPane.iconID = 155
                
            Case SADOCK_TAGID_FRAMEWORKGRID:
                oPane.iconID = 31239
                
            Case SADOCK_TAGID_FRAMEWORKEDIT:
                oPane.iconID = 31240
                
            Case SADOCK_TAGID_PICBROWSE:
                oPane.iconID = 9
        End Select
    End If
    
    Exit Sub
    
ErrorHandler:
    
End Sub

Public Sub SetFocusToNextPane()

    On Error GoTo ErrorHandler

    Dim X As Long
    Dim lNextPane As Long
    
    'If no active pane then set focus to first visible pane
    If m_objDock.ActivePane Is Nothing Then
        lNextPane = NextVisiblePane(1)
        If lNextPane <> 0 Then
            m_objDock.Panes(lNextPane).Select
        End If
    Else
        'There is a current pane so find its position in the index
        For X = 1 To m_objDock.PanesCount
            If m_objDock.Panes(X).Id = m_objDock.ActivePane.Id Then
                'If we are at the end of the index loop back to the start
                If X = m_objDock.PanesCount Then
                    lNextPane = NextVisiblePane(1)
                Else
                    'Start search with the next pane in the index
                    lNextPane = NextVisiblePane(X + 1)
                End If
                If lNextPane <> 0 Then
                    m_objDock.Panes(lNextPane).Select
                End If
                Exit Sub
            End If
        Next X
    End If
    
    Exit Sub
    
ErrorHandler:
    
End Sub

Private Function NextVisiblePane(ByVal lStartPos As Long) As Long

    'Will find the next visible pane (not closed and not hidden).  Search starts at the index position passed in

    Dim X As Long

    On Error GoTo ErrorHandler

    For X = lStartPos To m_objDock.PanesCount
        If m_objDock.Panes(X).Hidden = False And m_objDock.Panes(X).Closed = False Then
            NextVisiblePane = X
            Exit Function
        End If
    Next X
    
    'Didn't find a visible pane yet so search again from the start of the index
    For X = 1 To lStartPos
        If m_objDock.Panes(X).Hidden = False And m_objDock.Panes(X).Closed = False Then
            NextVisiblePane = X
            Exit Function
        End If
    Next X
    
    Exit Function

ErrorHandler:
    
End Function

Private Sub SetUIThemes()

    Dim lValue As Long
    Dim sValue As String

    On Error GoTo ErrorHandler

    If GetColorDepth > 8 Then
        lValue = val(GetIniSetting("User Interface", "DockTheme", "-1")) 'DEV_STRING
        If lValue = -1 Then
            m_objDock.VisualTheme = DOCKINGTHEME
        Else
            m_objDock.VisualTheme = lValue
        End If
        
        sValue = GetIniSetting("User Interface", "UseLuna", "T") 'DEV_STRING
        If sValue = "F" Then 'DEV_STRING
            m_objDock.Options.LunaColors = False
        Else
            m_objDock.Options.LunaColors = True
        End If
    Else
        'Only 256 colors supported so force theme to Office 2000
        m_objDock.VisualTheme = ThemeOffice
    End If

    Exit Sub
    
ErrorHandler:
    
End Sub

Public Function GetTagID(ByVal v_lngTag As Long) As Long
    GetTagID = v_lngTag And SADOCK_TAGID_MASK
End Function

Public Function GetActiveForm() As Form
    On Error GoTo ErrHdlr
    Dim paneID As Long
    If Not m_objDock.ActivePane Is Nothing Then
        Set GetActiveForm = m_colDockedFormsByPaneID("ID" & m_objDock.ActivePane.Id)
        Exit Function
    End If
    
ErrHdlr:
    Set GetActiveForm = Nothing
End Function
Public Function GetFormByPaneId(ByVal sPaneID As String) As Form
    Set GetFormByPaneId = m_colDockedFormsByPaneID(sPaneID)
End Function

