context: //Copyright (c) 2007-2010, Adolfo Marinucci
  //All rights reserved.
  
  //Redistribution and use in source and binary forms, with or without modification, 
  //are permitted provided that the following conditions are met:
  //
  //* Redistributions of source code must retain the above copyright notice, 
  //  this list of conditions and the following disclaimer.
  //* Redistributions in binary form must reproduce the above copyright notice, 
  //  this list of conditions and the following disclaimer in the documentation 
  //  and/or other materials provided with the distribution.
  //* Neither the name of Adolfo Marinucci nor the names of its contributors may 
  //  be used to endorse or promote products derived from this software without 
  //  specific prior written permission.
  //
  //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  //AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
  //WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
  //IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
  //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
  //PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  //HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
  //OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
  //EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  
  using System;
  using System.Collections.Generic;
  using System.Text;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Controls.Primitives;
  using System.Windows.Data;
  using System.Windows.Documents;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Media.Imaging;
  using System.Windows.Shapes;
  using System.Diagnostics;
  using System.Xml;
  using System.ComponentModel;
  using System.Linq;
  
  namespace AvalonDock
  {
      /// <summary>
      /// Enumerates all the possible states of <see cref="DockableContent"/>
      /// </summary>
      public enum DockableContentState
      {
          /// <summary>
          /// Content is not associated with any <see cref="DockingManager"/> (Default State)
          /// </summary>
          None,
  
          /// <summary>
          /// Content is docked to a border of a <see cref="ResizingPanel"/> within as <see cref="DockingManager"/> control
          /// </summary>
          Docked,
  
          /// <summary>
          /// Content is hosted by a flyout window and is visible only when user move mouse over an anchor thumb located to a <see cref="DockingManager"/> controlo border
          /// </summary>
          AutoHide,
  
          /// <summary>
          /// Content is hosted by a floating window and user can redock is on its <see cref="DockingManager"/> container control
          /// </summary>
          DockableWindow,
  
          /// <summary>
          /// Content is hosted by a floating window that can't be docked to a its <see cref="DockingManager"/> container control
          /// </summary>
          FloatingWindow,
  
          /// <summary>
          /// Content is hosted into a <see cref="DocmumentPane"/>
          /// </summary>
          Document,
  
          /// <summary>
          /// Content is hidden
          /// </summary>
          Hidden,
      }
  
  
      /// <summary>
      /// Defines how a dockable content can be dragged over a docking manager
      /// </summary>
      /// <remarks>This style can be composed with the 'or' operator.</remarks>
      public enum DockableStyle : uint
      { 
          /// <summary>
          /// Content is not dockable at all
          /// </summary>
          None = 0x0000,
  
          /// <summary>
          /// Dockable as document
          /// </summary>
          Document    = 0x0001,
  
          /// <summary>
          /// Dockable to the left border of <see cref="DockingManager"/>
          /// </summary>
          LeftBorder  = 0x0002,
  
          /// <summary>
          /// Dockable to the right border of <see cref="DockingManager"/>
          /// </summary>
          RightBorder = 0x0004,
  
          /// <summary>
          /// Dockable to the top border of <see cref="DockingManager"/>
          /// </summary>
          TopBorder   = 0x0008,
  
          /// <summary>
          /// Dockable to the bottom border of <see cref="DockingManager"/>
          /// </summary>
          BottomBorder= 0x0010,
  
          /// <summary>
          /// A <see cref="DockableContent"/> with this style can be hosted in a <see cref="FloatingWindow"/>
          /// </summary>
          Floating = 0x0020,
          
          /// <summary>
          /// A <see cref="DockableContent"/> with this style can be the only one content in a <see cref="DockablePane"/> pane (NOT YET SUPPORTED)
          /// </summary>
          /// <remarks>This style is not compatible with <see cref="DockableStyle.Document"/> style</remarks>
          Single = 0x0040,
  
          /// <summary>
          /// A <see cref="DockableContet"/> with this style can be autohidden.
          /// </summary>
          AutoHide = 0x0080,
  
          /// <summary>
          /// Dockable only to a border of a <see cref="DockingManager"/>
          /// </summary>
          DockableToBorders = LeftBorder | RightBorder | TopBorder | BottomBorder | AutoHide,
          
          /// <summary>
          /// Dockable to a border of a <see cref="DockingManager"/> and into a <see cref="DocumentPane"/>
          /// </summary>
          Dockable = DockableToBorders | Document | Floating,
  
          /// <summary>
          /// Dockable to a border of a <see cref="DockingManager"/> and into a <see cref="DocumentPane"/> but not in autohidden mode (WinForms controls)
          /// </summary>
          DockableButNotAutoHidden = Dockable & ~AutoHide
      }
  
  
      /// <summary>
      /// Represent a state of a dockable content that can be used to restore it after it's hidden
      /// </summary>
      internal class DockableContentStateAndPosition
      {
          public readonly Pane ContainerPane = null;
          public readonly Guid ContainerPaneID;
          public readonly int ChildIndex = -1;
          public readonly double Width;
          public readonly double Height;
          public readonly DockableContentState State;
          public readonly AnchorStyle Anchor = AnchorStyle.None;
  
          public DockableContentStateAndPosition(
              Pane containerPane,
              int childIndex,
              double width,
              double height,
              AnchorStyle anchor,
  			DockableContentState state)
          {
              ContainerPane = containerPane;
              ChildIndex = childIndex;
              Width = Math.Max(width, 100.0);
              Height = Math.Max(height, 100.0);
              Anchor = anchor;
  			State = state;
          }
  
          public DockableContentStateAndPosition(
              Guid containerPaneID,
              int childIndex,
              double width,
              double height,
              AnchorStyle anchor,
              DockableContentState state)
          {
              ContainerPaneID = containerPaneID;
              ChildIndex = childIndex;
              Width = Math.Max(width, 100.0);
              Height = Math.Max(height, 100.0);
              Anchor = anchor;
              State = state;
          }
  
         public DockableContentStateAndPosition(
              DockableContent cntToSave)
          {
              ContainerPane = cntToSave.ContainerPane;
              ChildIndex = ContainerPane.Items.IndexOf(cntToSave);
              Width = Math.Max(ContainerPane.ActualWidth, 100.0);
              Height = Math.Max(ContainerPane.ActualHeight, 100.0);
              State = cntToSave.State;
  
              DockablePane dockablePane = ContainerPane as DockablePane;
              if (dockablePane != null)
              {
                  Anchor = dockablePane.Anchor;
              }
          }
      }
  
      /// <summary>
      /// Identifies a content that can be drag over a <see cref="DockingManager"/> control or hosted by a window floating over it (<see cref="FloatingWindow"/>).
      /// </summary>
      public class DockableContent : ManagedContent
      {
          static DockableContent()
          {
              DefaultStyleKeyProperty.OverrideMetadata(typeof(DockableContent), new FrameworkPropertyMetadata(typeof(DockableContent)));
          }
  
          public DockableContent()
          {
          }
  
          protected override void OnContentLoaded()
          {
              //now the logical tree is up
              DockingManager manager = GetParentManager(null);
  
              //if can't find the manager there is a problem
              //if (manager == null)
              //    throw new InvalidOperationException("Unable to find DockingManager object in the logical tree");
              //if (manager != null)
              //    manager.DockableContents.Add(this);
  
              base.OnContentLoaded();
          }
  
          protected override void OnContentUnloaded()
          {
              //if (Manager != null && !Manager.HiddenContents.Contains(this))
              //    Manager.DockableContents.Remove(this);
  
              base.OnContentUnloaded();
          }
  
  		SizeToContent _floatingWindowSizeToContent = SizeToContent.Manual;
  
  		/// <summary>
  		/// Gets or sets a value indicating if this dockable content should change the size of a FloatingWindow when undocked
  		/// </summary>
  		public SizeToContent FloatingWindowSizeToContent
  		{
  			get { return _floatingWindowSizeToContent; }
  			set
  			{
  				_floatingWindowSizeToContent = value;
                  RaisePropertyChanged("FloatingWindowSizeToContent");
  			}
  		}
  
          #region Drag content
          protected override void OnDragMouseMove(object sender, MouseEventArgs e)
          {
              base.OnDragMouseMove(sender, e);
          }
  
          protected override void OnDragStart(Point ptMouse, Point ptRelativeMouse)
          {
              if (DockableStyle != DockableStyle.None && 
                  (State == DockableContentState.Docked || State == DockableContentState.Document || State == DockableContentState.DockableWindow) &&
                  !Manager.DragPaneServices.IsDragging)
              {
                  Manager.Drag(this, HelperFunc.PointToScreenWithoutFlowDirection(this, ptMouse), ptRelativeMouse);                
              }
  
              base.OnDragStart(ptMouse, ptRelativeMouse);
          }        
          
          #endregion
  
          #region State Properties & Events
  
          #region StateChanged
  
          /// <summary>
          /// StateChanged Routed Event
          /// </summary>
          public static readonly RoutedEvent StateChangedEvent = EventManager.RegisterRoutedEvent("StateChanged",
              RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(DockableContent));
  
          /// <summary>
          /// Occurs when State property changes
          /// </summary>
          public event RoutedEventHandler StateChanged
          {
              add { AddHandler(StateChangedEvent, value); }
              remove { RemoveHandler(StateChangedEvent, value); }
          }
  
          /// <summary>
          /// A helper method to raise the StateChanged event.
          /// </summary>
          protected RoutedEventArgs RaiseStateChangedEvent()
          {
              return RaiseStateChangedEvent(this);
          }
  
          /// <summary>
          /// A static helper method to raise the StateChanged event on a target element.
          /// </summary>
          /// <param name="target">UIElement or ContentElement on which to raise the event</param>
          static RoutedEventArgs RaiseStateChangedEvent(DependencyObject target)
          {
              if (target == null) return null;
  
              RoutedEventArgs args = new RoutedEventArgs();
              args.RoutedEvent = StateChangedEvent;
              RoutedEventHelper.RaiseEvent(target, args);
              return args;
          }
  
          #endregion
         
          /// <summary>
          /// Gets the state of <see cref="DockableContent"/>
          /// </summary>
          public DockableContentState State
          {
              get { return (DockableContentState)GetValue(StatePropertyKey.DependencyProperty); }
              protected set { SetValue(StatePropertyKey, value); }
          }
  
          // Using a DependencyProperty as the backing store for State.  This enables animation, styling, binding, etc...
          public static readonly DependencyPropertyKey StatePropertyKey =
              DependencyProperty.RegisterReadOnly("State",
              typeof(DockableContentState),
              typeof(DockableContent),
              new FrameworkPropertyMetadata(
                  DockableContentState.None,
                  new PropertyChangedCallback(
                      (s, e) =>
                      {
                          ((DockableContent)s).OnStateChanged((DockableContentState)e.OldValue, (DockableContentState)e.NewValue);
                      }
                      )));
  
          protected virtual void OnStateChanged(DockableContentState oldState, DockableContentState newState)
          {
              RaiseStateChangedEvent(this);
  
              if (ContainerPane is DockablePane)
                  ((DockablePane)ContainerPane).UpdateCanAutohideProperty();
          }
  
          public static readonly DependencyProperty StateProperty =
              StatePropertyKey.DependencyProperty;
  
          #region DockableStyle
  
          /// <summary>
          /// DockableStyle Dependency Property
          /// </summary>
          public static readonly DependencyProperty DockableStyleProperty =
              DependencyProperty.Register("DockableStyle", typeof(DockableStyle), typeof(DockableContent),
                  new FrameworkPropertyMetadata(DockableStyle.Dockable));
  
          /// <summary>
          /// Get or sets a value that indicates how a dockable content can be dragged over and docked to a <see cref="DockingManager"/>
          /// </summary>
          public DockableStyle DockableStyle
          {
              get { return (DockableStyle)GetValue(DockableStyleProperty); }
              set { SetValue(DockableStyleProperty, value); }
          }
  
          #endregion
  
          
  
  
          protected override void OnVisualParentChanged(DependencyObject oldParent)
          {
  
              base.OnVisualParentChanged(oldParent);           
              
              //if (oldParent == null && State == DockableContentState.None)
              //{
              //    if (Parent is FloatingDockablePane)
              //    {
              //        throw new InvalidOperationException();
              //    }
  
              //    SetStateToDock();
              //}
  
          }
          
  
  	    #endregion  
  
          #region StateMachine
  
          internal void SetStateToAutoHide()
          {
              State = DockableContentState.AutoHide;
          }
  
          internal void SetStateToDock()
          {
              State = DockableContentState.Docked;
          }
  
          internal void SetStateToDockableWindow()
          {
              if (State == DockableContentState.DockableWindow)
                  return;
  
              Debug.Assert(
                  State == DockableContentState.None ||
                  State == DockableContentState.Document ||
                  State == DockableContentState.Docked ||
                  State == DockableContentState.FloatingWindow ||
                  State == DockableContentState.Hidden);
  
              State = DockableContentState.DockableWindow;
          }
  
          internal void SetStateToFloatingWindow()
          {
              if (State == DockableContentState.FloatingWindow)
                  return;
  
              Debug.Assert(
                  State == DockableContentState.Document ||
                  State == DockableContentState.Docked ||
                  State == DockableContentState.DockableWindow);
  
              State = DockableContentState.FloatingWindow;
          }
  
          internal void SetStateToHidden()
          {
              State = DockableContentState.Hidden;
          }
          
          internal void SetStateToDocument()
          {
              State = DockableContentState.Document;
          }
          #endregion 
  
          #region HideOnClose
          public static DependencyProperty HideOnCloseKey = DependencyProperty.Register("HideOnClose", typeof(bool), typeof(DockableContent), new PropertyMetadata(true));
  
          public bool HideOnClose
          {
              get { return (bool)GetValue(HideOnCloseKey); }
              set { SetValue(HideOnCloseKey, value); }
          }
          #endregion
  
          //#region OnIsActiveContentChanged (flyout windows)
          //protected override void OnIsActiveContentChanged(DependencyPropertyChangedEventArgs e)
          //{
          //    if (State == DockableContentState.AutoHide)
          //        Manager.ShowFlyoutWindow(this, null);
  
          //    base.OnIsActiveContentChanged(e);
          //}
          //#endregion
          
          protected override void OnInitialized(EventArgs e)
          {
              base.OnInitialized(e);
  
              this.CommandBindings.Add(
                  new CommandBinding(DockableContentCommands.FloatingWindow, this.OnExecuteCommand, this.OnCanExecuteCommand));
              this.CommandBindings.Add(
                  new CommandBinding(DockableContentCommands.DockableFloatingWindow, this.OnExecuteCommand, this.OnCanExecuteCommand));
              this.CommandBindings.Add(
                  new CommandBinding(ManagedContentCommands.Show, this.OnExecuteCommand, this.OnCanExecuteCommand));
              this.CommandBindings.Add(
                  new CommandBinding(DockableContentCommands.ShowAsDocument, this.OnExecuteCommand, this.OnCanExecuteCommand));
              this.CommandBindings.Add(
                  new CommandBinding(DockableContentCommands.ToggleAutoHide, this.OnExecuteCommand, this.OnCanExecuteCommand));
              this.CommandBindings.Add(
                  new CommandBinding(ManagedContentCommands.Hide, this.OnExecuteCommand, this.OnCanExecuteCommand));
          }
  
          #region Commands
  
          void OnExecuteCommand(object sender, ExecutedRoutedEventArgs e)
          {
              if (!e.Handled &&
                  e.Command == DockableContentCommands.ToggleAutoHide)
              {
                  ToggleAutoHide();
  
                  e.Handled = true;
              }
              else if (!e.Handled && e.Command == DockableContentCommands.FloatingWindow)
              {
                  ShowAsFloatingWindow(false);
  
                  e.Handled = true;
              }
              else if (!e.Handled && e.Command == DockableContentCommands.DockableFloatingWindow)
              {
                  ShowAsFloatingWindow(true);
  
                  e.Handled = true;
              }
              else if (!e.Handled && e.Command == DockableContentCommands.ShowAsDocument)
              {
                  ShowAsDocument();
                  e.Handled = true;
              }
          }
  
          void OnCanExecuteCommand(object sender, CanExecuteRoutedEventArgs e)
          {
              e.CanExecute = CanExecuteCommand(e.Command);
          }
  
          /// <summary>
          /// Show <see cref="DockableContent"/> as docked pane
          /// </summary>
          public override void Show()
          {
              Show(Manager);
          }
  
          /// <summary>
          /// Show <see cref="DockableContent"/> as docked pane within provided <see cref="DockingManager"/>
          /// </summary>
          public override void Show(DockingManager manager)
          {
              if (SavedStateAndPosition != null && State == DockableContentState.Hidden)
                  Show(manager, SavedStateAndPosition.Anchor);
              else
                  Show(manager, AnchorStyle.None);
          }
  
          /// <summary>
          /// Show <see cref="DockableContent"/> as docked pane
          /// </summary>
          /// <param name="desideredAnchor">Desidered anchor position</param>
          public void Show(AnchorStyle desideredAnchor)
          {
              Show(Manager, desideredAnchor);
          }
  
          /// <summary>
          /// Show <see cref="DockableContent"/> as docked pane
          /// </summary>
          public void Show(DockingManager manager, AnchorStyle desideredAnchor)
          {
              if (Manager != null && Manager != manager)
                  throw new InvalidOperationException("Please remove the content from previous DockingManager (using the Close method)");
  
              if (manager == null && !CanExecuteCommand(ManagedContentCommands.Show))
                  throw new InvalidOperationException("This operation can be executed in this state");
  
              if (State == DockableContentState.Docked)
              {
                  //if already shown as docked content just activate it
                  Activate();
              }
              else
              {
                  if (SavedStateAndPosition != null && State == DockableContentState.Hidden)
                      manager.Show(this, SavedStateAndPosition.State, desideredAnchor);
                  else
                      manager.Show(this, DockableContentState.Docked, desideredAnchor);
              }
          }
  
          /// <summary>
          /// Show as <see cref="DockableContent"/> as a tabbed document
          /// </summary>
          public void ShowAsDocument()
          {
              ShowAsDocument(Manager);
          }
  
          /// <summary>
          /// Show as <see cref="DockableContent"/> as a tabbed document under the provided <see cref="DockingManager"/>
          /// </summary>
          public void ShowAsDocument(DockingManager manager)
          {
              if (Manager != null && Manager != manager)
                  throw new InvalidOperationException("Please remove the content from previous DockingManager (using the Close method)");
  
              //Manager = manager; 
  
              if (manager == null && !CanExecuteCommand(DockableContentCommands.ShowAsDocument))
                  throw new InvalidOperationException("This operation can be executed in this state");
  
              manager.Show(this, DockableContentState.Document);
          }
  
          /// <summary>
          /// Show the content as floating window inside the provided <see cref="DockingManager"/>
          /// </summary>
          /// <param name="dockableWindow">True if the resulting floating window can the be re-docked to the docking manager.</param>
          public void ShowAsFloatingWindow(bool dockableWindow)
          {
              ShowAsFloatingWindow(Manager, dockableWindow);
          }
  
          /// <summary>
          /// Show the content ad floating window
          /// </summary>
          /// <param name="dockableWindow">True if the resulting floating window can the be re-docked to the docking manager.</param>
          public void ShowAsFloatingWindow(DockingManager manager, bool dockableWindow)
          {
              if (Manager != null && Manager != manager)
                  throw new InvalidOperationException("Please remove the content from previous DockingManager (using the Close method)");
  
              //Manager = manager;
  
              if (manager == null)
              {
                  if (dockableWindow &&
                      !CanExecuteCommand(DockableContentCommands.DockableFloatingWindow))
                      throw new InvalidOperationException("This operation can be executed in this state");
                  if (!dockableWindow &&
                      !CanExecuteCommand(DockableContentCommands.FloatingWindow))
                      throw new InvalidOperationException("This operation can be executed in this state");
              }
  
              manager.Show(this, dockableWindow ? DockableContentState.DockableWindow : DockableContentState.FloatingWindow);
          }
  
  
          /// <summary>
          /// Hides this content
          /// </summary>
          public override bool Hide()
          {
              if (!CanExecuteCommand(ManagedContentCommands.Hide))
                  return false;
  
              Manager.Hide(this);
              return true;
          }
  
          /// <summary>
          /// Close content
          /// </summary>
          public override bool Close()
          {
              return CloseOrHide();
          }
  
          /// <summary>
          /// Close content
          /// </summary>
          /// <param name="forceClose">If true forces the content closing regardless of the <see cref="HideOnClose"/> property.</param>
          public bool Close(bool forceClose)
          {
              return CloseOrHide(true);
          }
  
          /// <summary>
          /// Closes or hides provided content depending on HideOnClose property
          /// </summary>
          internal virtual bool CloseOrHide()
          {
              return CloseOrHide(false);
          }
  
          /// <summary>
          /// Closes or hides content depending on HideOnClose property
          /// </summary>
          internal virtual bool CloseOrHide(bool force)
          {
  			bool closed = false;
  
  			if( !force && !IsCloseable ) {
  				closed = false;
  			}
  			else if (!force && HideOnClose)
              {
                  Hide();
                  closed = true;
              }
              else
              {
  				if( !CanExecuteCommand( ManagedContentCommands.Close ) ) {
  					throw new InvalidOperationException( "This operation can be executed in this state" );
  				}
  
                  CancelEventArgs e = new CancelEventArgs( false );
                  OnClosing( e );
  
  				if( e.Cancel ) {
  					closed = false;
  				}
  				else {
  					if( ContainerPane != null ) {
  						ContainerPane.RemoveContent( ContainerPane.Items.IndexOf( this ) );
  					}
  
  					//Patch 8244 
  					Manager.RemoveContentFromTabGroup( this );
  
  					OnClosed();
  					closed = true;
  				}
              }
  			return closed;
          }
  
          /// <summary>
          /// Slides out this content to a border of the containing docking manager
          /// </summary>
          public void ToggleAutoHide()
          {
              if (!CanExecuteCommand(DockableContentCommands.ToggleAutoHide))
                  throw new InvalidOperationException("This operation can be executed in this state");
  
              (ContainerPane as DockablePane).ToggleAutoHide();
          }
  
          public override void Activate()
          {
              if (State == DockableContentState.AutoHide)
              {
                  if (Manager != null && this.IsLoaded)
                  {
                      Manager.ShowFlyoutWindow(this, null);
                  }
              }
  
gt:             else if (State == DockableContentState.Document)