You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1064 lines
31 KiB
1064 lines
31 KiB
/*************************************************************************************
|
|
|
|
Extended WPF Toolkit
|
|
|
|
Copyright (C) 2007-2013 Xceed Software Inc.
|
|
|
|
This program is provided to you under the terms of the Microsoft Public
|
|
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|
|
|
For more features, controls, and fast professional support,
|
|
pick up the Plus Edition at http://xceed.com/wpf_toolkit
|
|
|
|
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
|
|
|
|
***********************************************************************************/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows;
|
|
using System.Collections.ObjectModel;
|
|
using System.Windows.Markup;
|
|
using System.Xml.Serialization;
|
|
using Standard;
|
|
using System.Xml;
|
|
using System.Xml.Schema;
|
|
using System.Windows.Controls;
|
|
|
|
namespace Xceed.Wpf.AvalonDock.Layout
|
|
{
|
|
[ContentProperty( "RootPanel" )]
|
|
[Serializable]
|
|
public class LayoutRoot : LayoutElement, ILayoutContainer, ILayoutRoot, IXmlSerializable
|
|
{
|
|
#region Constructors
|
|
|
|
public LayoutRoot()
|
|
{
|
|
RightSide = new LayoutAnchorSide();
|
|
LeftSide = new LayoutAnchorSide();
|
|
TopSide = new LayoutAnchorSide();
|
|
BottomSide = new LayoutAnchorSide();
|
|
RootPanel = new LayoutPanel( new LayoutDocumentPane() );
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
#region RootPanel
|
|
|
|
private LayoutPanel _rootPanel;
|
|
public LayoutPanel RootPanel
|
|
{
|
|
get
|
|
{
|
|
return _rootPanel;
|
|
}
|
|
set
|
|
{
|
|
if( _rootPanel != value )
|
|
{
|
|
RaisePropertyChanging( "RootPanel" );
|
|
if( _rootPanel != null &&
|
|
_rootPanel.Parent == this )
|
|
_rootPanel.Parent = null;
|
|
_rootPanel = value;
|
|
|
|
if( _rootPanel == null )
|
|
_rootPanel = new LayoutPanel( new LayoutDocumentPane() );
|
|
|
|
if( _rootPanel != null )
|
|
_rootPanel.Parent = this;
|
|
RaisePropertyChanged( "RootPanel" );
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TopSide
|
|
|
|
private LayoutAnchorSide _topSide = null;
|
|
public LayoutAnchorSide TopSide
|
|
{
|
|
get
|
|
{
|
|
return _topSide;
|
|
}
|
|
set
|
|
{
|
|
if( _topSide != value )
|
|
{
|
|
RaisePropertyChanging( "TopSide" );
|
|
_topSide = value;
|
|
if( _topSide != null )
|
|
_topSide.Parent = this;
|
|
RaisePropertyChanged( "TopSide" );
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RightSide
|
|
|
|
private LayoutAnchorSide _rightSide;
|
|
public LayoutAnchorSide RightSide
|
|
{
|
|
get
|
|
{
|
|
return _rightSide;
|
|
}
|
|
set
|
|
{
|
|
if( _rightSide != value )
|
|
{
|
|
RaisePropertyChanging( "RightSide" );
|
|
_rightSide = value;
|
|
if( _rightSide != null )
|
|
_rightSide.Parent = this;
|
|
RaisePropertyChanged( "RightSide" );
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region LeftSide
|
|
|
|
private LayoutAnchorSide _leftSide = null;
|
|
public LayoutAnchorSide LeftSide
|
|
{
|
|
get
|
|
{
|
|
return _leftSide;
|
|
}
|
|
set
|
|
{
|
|
if( _leftSide != value )
|
|
{
|
|
RaisePropertyChanging( "LeftSide" );
|
|
_leftSide = value;
|
|
if( _leftSide != null )
|
|
_leftSide.Parent = this;
|
|
RaisePropertyChanged( "LeftSide" );
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region BottomSide
|
|
|
|
private LayoutAnchorSide _bottomSide = null;
|
|
public LayoutAnchorSide BottomSide
|
|
{
|
|
get
|
|
{
|
|
return _bottomSide;
|
|
}
|
|
set
|
|
{
|
|
if( _bottomSide != value )
|
|
{
|
|
RaisePropertyChanging( "BottomSide" );
|
|
_bottomSide = value;
|
|
if( _bottomSide != null )
|
|
_bottomSide.Parent = this;
|
|
RaisePropertyChanged( "BottomSide" );
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region FloatingWindows
|
|
|
|
ObservableCollection<LayoutFloatingWindow> _floatingWindows = null;
|
|
|
|
public ObservableCollection<LayoutFloatingWindow> FloatingWindows
|
|
{
|
|
get
|
|
{
|
|
if( _floatingWindows == null )
|
|
{
|
|
_floatingWindows = new ObservableCollection<LayoutFloatingWindow>();
|
|
_floatingWindows.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler( _floatingWindows_CollectionChanged );
|
|
}
|
|
|
|
return _floatingWindows;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region HiddenAnchorables
|
|
|
|
ObservableCollection<LayoutAnchorable> _hiddenAnchorables = null;
|
|
|
|
public ObservableCollection<LayoutAnchorable> Hidden
|
|
{
|
|
get
|
|
{
|
|
if( _hiddenAnchorables == null )
|
|
{
|
|
_hiddenAnchorables = new ObservableCollection<LayoutAnchorable>();
|
|
_hiddenAnchorables.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler( _hiddenAnchorables_CollectionChanged );
|
|
}
|
|
|
|
return _hiddenAnchorables;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Children
|
|
|
|
public IEnumerable<ILayoutElement> Children
|
|
{
|
|
get
|
|
{
|
|
if( RootPanel != null )
|
|
yield return RootPanel;
|
|
if( _floatingWindows != null )
|
|
{
|
|
foreach( var floatingWindow in _floatingWindows )
|
|
yield return floatingWindow;
|
|
}
|
|
if( TopSide != null )
|
|
yield return TopSide;
|
|
if( RightSide != null )
|
|
yield return RightSide;
|
|
if( BottomSide != null )
|
|
yield return BottomSide;
|
|
if( LeftSide != null )
|
|
yield return LeftSide;
|
|
if( _hiddenAnchorables != null )
|
|
{
|
|
foreach( var hiddenAnchorable in _hiddenAnchorables )
|
|
yield return hiddenAnchorable;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ChildrenCount
|
|
|
|
public int ChildrenCount
|
|
{
|
|
get
|
|
{
|
|
return 5 +
|
|
( _floatingWindows != null ? _floatingWindows.Count : 0 ) +
|
|
( _hiddenAnchorables != null ? _hiddenAnchorables.Count : 0 );
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ActiveContent
|
|
|
|
[field: NonSerialized]
|
|
private WeakReference _activeContent = null;
|
|
private bool _activeContentSet = false;
|
|
|
|
[XmlIgnore]
|
|
public LayoutContent ActiveContent
|
|
{
|
|
get
|
|
{
|
|
return _activeContent.GetValueOrDefault<LayoutContent>();
|
|
}
|
|
set
|
|
{
|
|
var currentValue = ActiveContent;
|
|
if( currentValue != value )
|
|
{
|
|
InternalSetActiveContent( currentValue, value );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region LastFocusedDocument
|
|
|
|
[field: NonSerialized]
|
|
private WeakReference _lastFocusedDocument = null;
|
|
[field: NonSerialized]
|
|
private bool _lastFocusedDocumentSet = false;
|
|
|
|
[XmlIgnore]
|
|
public LayoutContent LastFocusedDocument
|
|
{
|
|
get
|
|
{
|
|
return _lastFocusedDocument.GetValueOrDefault<LayoutContent>();
|
|
}
|
|
private set
|
|
{
|
|
var currentValue = LastFocusedDocument;
|
|
if( currentValue != value )
|
|
{
|
|
RaisePropertyChanging( "LastFocusedDocument" );
|
|
if( currentValue != null )
|
|
currentValue.IsLastFocusedDocument = false;
|
|
_lastFocusedDocument = new WeakReference( value );
|
|
currentValue = LastFocusedDocument;
|
|
if( currentValue != null )
|
|
currentValue.IsLastFocusedDocument = true;
|
|
_lastFocusedDocumentSet = currentValue != null;
|
|
RaisePropertyChanged( "LastFocusedDocument" );
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Manager
|
|
|
|
|
|
[NonSerialized]
|
|
private DockingManager _manager = null;
|
|
|
|
[XmlIgnore]
|
|
public DockingManager Manager
|
|
{
|
|
get
|
|
{
|
|
return _manager;
|
|
}
|
|
internal set
|
|
{
|
|
if( _manager != value )
|
|
{
|
|
RaisePropertyChanging( "Manager" );
|
|
_manager = value;
|
|
RaisePropertyChanged( "Manager" );
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Overrides
|
|
|
|
#if TRACE
|
|
public override void ConsoleDump(int tab)
|
|
{
|
|
System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) );
|
|
System.Diagnostics.Trace.WriteLine( "RootPanel()" );
|
|
|
|
RootPanel.ConsoleDump(tab + 1);
|
|
|
|
System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) );
|
|
System.Diagnostics.Trace.WriteLine( "FloatingWindows()" );
|
|
|
|
foreach (LayoutFloatingWindow fw in FloatingWindows)
|
|
fw.ConsoleDump(tab + 1);
|
|
|
|
System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) );
|
|
System.Diagnostics.Trace.WriteLine( "Hidden()" );
|
|
|
|
foreach (LayoutAnchorable hidden in Hidden)
|
|
hidden.ConsoleDump(tab + 1);
|
|
}
|
|
#endif
|
|
|
|
#endregion
|
|
|
|
#region Public Methods
|
|
|
|
public void RemoveChild( ILayoutElement element )
|
|
{
|
|
if( element == RootPanel )
|
|
RootPanel = null;
|
|
else if( _floatingWindows != null && _floatingWindows.Contains( element ) )
|
|
_floatingWindows.Remove( element as LayoutFloatingWindow );
|
|
else if( _hiddenAnchorables != null && _hiddenAnchorables.Contains( element ) )
|
|
_hiddenAnchorables.Remove( element as LayoutAnchorable );
|
|
else if( element == TopSide )
|
|
TopSide = null;
|
|
else if( element == RightSide )
|
|
RightSide = null;
|
|
else if( element == BottomSide )
|
|
BottomSide = null;
|
|
else if( element == LeftSide )
|
|
LeftSide = null;
|
|
|
|
}
|
|
|
|
public void ReplaceChild( ILayoutElement oldElement, ILayoutElement newElement )
|
|
{
|
|
if( oldElement == RootPanel )
|
|
RootPanel = ( LayoutPanel )newElement;
|
|
else if( _floatingWindows != null && _floatingWindows.Contains( oldElement ) )
|
|
{
|
|
int index = _floatingWindows.IndexOf( oldElement as LayoutFloatingWindow );
|
|
_floatingWindows.Remove( oldElement as LayoutFloatingWindow );
|
|
_floatingWindows.Insert( index, newElement as LayoutFloatingWindow );
|
|
}
|
|
else if( _hiddenAnchorables != null && _hiddenAnchorables.Contains( oldElement ) )
|
|
{
|
|
int index = _hiddenAnchorables.IndexOf( oldElement as LayoutAnchorable );
|
|
_hiddenAnchorables.Remove( oldElement as LayoutAnchorable );
|
|
_hiddenAnchorables.Insert( index, newElement as LayoutAnchorable );
|
|
}
|
|
else if( oldElement == TopSide )
|
|
TopSide = ( LayoutAnchorSide )newElement;
|
|
else if( oldElement == RightSide )
|
|
RightSide = ( LayoutAnchorSide )newElement;
|
|
else if( oldElement == BottomSide )
|
|
BottomSide = ( LayoutAnchorSide )newElement;
|
|
else if( oldElement == LeftSide )
|
|
LeftSide = ( LayoutAnchorSide )newElement;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes any empty container not directly referenced by other layout items
|
|
/// </summary>
|
|
public void CollectGarbage()
|
|
{
|
|
bool exitFlag = true;
|
|
|
|
#region collect empty panes
|
|
do
|
|
{
|
|
exitFlag = true;
|
|
|
|
//for each content that references via PreviousContainer a disconnected Pane set the property to null
|
|
foreach( var content in this.Descendents().OfType<ILayoutPreviousContainer>().Where( c => c.PreviousContainer != null &&
|
|
( c.PreviousContainer.Parent == null || c.PreviousContainer.Parent.Root != this ) ) )
|
|
{
|
|
content.PreviousContainer = null;
|
|
}
|
|
|
|
//for each pane that is empty
|
|
foreach( var emptyPane in this.Descendents().OfType<ILayoutPane>().Where( p => p.ChildrenCount == 0 ) )
|
|
{
|
|
//...set null any reference coming from contents not yet hosted in a floating window
|
|
foreach( var contentReferencingEmptyPane in this.Descendents().OfType<LayoutContent>()
|
|
.Where( c => ( ( ILayoutPreviousContainer )c ).PreviousContainer == emptyPane && !c.IsFloating ) )
|
|
{
|
|
if( contentReferencingEmptyPane is LayoutAnchorable &&
|
|
!( ( LayoutAnchorable )contentReferencingEmptyPane ).IsVisible )
|
|
continue;
|
|
|
|
( ( ILayoutPreviousContainer )contentReferencingEmptyPane ).PreviousContainer = null;
|
|
contentReferencingEmptyPane.PreviousContainerIndex = -1;
|
|
}
|
|
|
|
//...if this pane is the only documentpane present in the layout than skip it
|
|
if( emptyPane is LayoutDocumentPane &&
|
|
this.Descendents().OfType<LayoutDocumentPane>().Count( c => c != emptyPane ) == 0 )
|
|
continue;
|
|
|
|
//...if this empty panes is not referenced by anyone, than removes it from its parent container
|
|
if( !this.Descendents().OfType<ILayoutPreviousContainer>().Any( c => c.PreviousContainer == emptyPane ) )
|
|
{
|
|
var parentGroup = emptyPane.Parent as ILayoutContainer;
|
|
parentGroup.RemoveChild( emptyPane );
|
|
exitFlag = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !exitFlag )
|
|
{
|
|
//removes any empty anchorable pane group
|
|
foreach( var emptyPaneGroup in this.Descendents().OfType<LayoutAnchorablePaneGroup>().Where( p => p.ChildrenCount == 0 ) )
|
|
{
|
|
var parentGroup = emptyPaneGroup.Parent as ILayoutContainer;
|
|
parentGroup.RemoveChild( emptyPaneGroup );
|
|
exitFlag = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !exitFlag )
|
|
{
|
|
//removes any empty layout panel
|
|
foreach( var emptyPaneGroup in this.Descendents().OfType<LayoutPanel>().Where( p => p.ChildrenCount == 0 ) )
|
|
{
|
|
var parentGroup = emptyPaneGroup.Parent as ILayoutContainer;
|
|
parentGroup.RemoveChild( emptyPaneGroup );
|
|
exitFlag = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !exitFlag )
|
|
{
|
|
//removes any empty floating window
|
|
foreach( var emptyPaneGroup in this.Descendents().OfType<LayoutFloatingWindow>().Where( p => p.ChildrenCount == 0 ) )
|
|
{
|
|
var parentGroup = emptyPaneGroup.Parent as ILayoutContainer;
|
|
parentGroup.RemoveChild( emptyPaneGroup );
|
|
exitFlag = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !exitFlag )
|
|
{
|
|
//removes any empty anchor group
|
|
foreach( var emptyPaneGroup in this.Descendents().OfType<LayoutAnchorGroup>().Where( p => p.ChildrenCount == 0 ) )
|
|
{
|
|
var parentGroup = emptyPaneGroup.Parent as ILayoutContainer;
|
|
parentGroup.RemoveChild( emptyPaneGroup );
|
|
exitFlag = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
while( !exitFlag );
|
|
#endregion
|
|
|
|
#region collapse single child anchorable pane groups
|
|
do
|
|
{
|
|
exitFlag = true;
|
|
//for each pane that is empty
|
|
foreach( var paneGroupToCollapse in this.Descendents().OfType<LayoutAnchorablePaneGroup>().Where( p => p.ChildrenCount == 1 && p.Children[ 0 ] is LayoutAnchorablePaneGroup ).ToArray() )
|
|
{
|
|
var singleChild = paneGroupToCollapse.Children[ 0 ] as LayoutAnchorablePaneGroup;
|
|
paneGroupToCollapse.Orientation = singleChild.Orientation;
|
|
paneGroupToCollapse.RemoveChild( singleChild );
|
|
while( singleChild.ChildrenCount > 0 )
|
|
{
|
|
paneGroupToCollapse.InsertChildAt(
|
|
paneGroupToCollapse.ChildrenCount, singleChild.Children[ 0 ] );
|
|
}
|
|
|
|
exitFlag = false;
|
|
break;
|
|
}
|
|
|
|
}
|
|
while( !exitFlag );
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
#region collapse single child document pane groups
|
|
do
|
|
{
|
|
exitFlag = true;
|
|
//for each pane that is empty
|
|
foreach( var paneGroupToCollapse in this.Descendents().OfType<LayoutDocumentPaneGroup>().Where( p => p.ChildrenCount == 1 && p.Children[ 0 ] is LayoutDocumentPaneGroup ).ToArray() )
|
|
{
|
|
var singleChild = paneGroupToCollapse.Children[ 0 ] as LayoutDocumentPaneGroup;
|
|
paneGroupToCollapse.Orientation = singleChild.Orientation;
|
|
paneGroupToCollapse.RemoveChild( singleChild );
|
|
while( singleChild.ChildrenCount > 0 )
|
|
{
|
|
paneGroupToCollapse.InsertChildAt(
|
|
paneGroupToCollapse.ChildrenCount, singleChild.Children[ 0 ] );
|
|
}
|
|
|
|
exitFlag = false;
|
|
break;
|
|
}
|
|
|
|
}
|
|
while( !exitFlag );
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
//do
|
|
//{
|
|
// exitFlag = true;
|
|
// //for each panel that has only one child
|
|
// foreach( var panelToCollapse in this.Descendents().OfType<LayoutPanel>().Where( p => p.ChildrenCount == 1 && p.Children[ 0 ] is LayoutPanel ).ToArray() )
|
|
// {
|
|
// var singleChild = panelToCollapse.Children[ 0 ] as LayoutPanel;
|
|
// panelToCollapse.Orientation = singleChild.Orientation;
|
|
// panelToCollapse.RemoveChild( singleChild );
|
|
// ILayoutPanelElement[] singleChildChildren = new ILayoutPanelElement[ singleChild.ChildrenCount ];
|
|
// singleChild.Children.CopyTo( singleChildChildren, 0 );
|
|
// while( singleChild.ChildrenCount > 0 )
|
|
// {
|
|
// panelToCollapse.InsertChildAt(
|
|
// panelToCollapse.ChildrenCount, singleChildChildren[ panelToCollapse.ChildrenCount ] );
|
|
// }
|
|
|
|
// exitFlag = false;
|
|
// break;
|
|
// }
|
|
|
|
//}
|
|
//while( !exitFlag );
|
|
|
|
#region Update ActiveContent and LastFocusedDocument properties
|
|
UpdateActiveContentProperty();
|
|
#endregion
|
|
#if DEBUG
|
|
System.Diagnostics.Debug.Assert(
|
|
!this.Descendents().OfType<LayoutAnchorablePane>().Any( a => a.ChildrenCount == 0 && a.IsVisible ) );
|
|
#if TRACE
|
|
RootPanel.ConsoleDump(4);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
public XmlSchema GetSchema()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public void ReadXml( XmlReader reader )
|
|
{
|
|
reader.MoveToContent();
|
|
if( reader.IsEmptyElement )
|
|
{
|
|
reader.Read();
|
|
return;
|
|
}
|
|
|
|
Orientation orientation;
|
|
var layoutPanelElements = this.ReadRootPanel( reader, out orientation );
|
|
if( layoutPanelElements != null )
|
|
{
|
|
this.RootPanel = new LayoutPanel() { Orientation = orientation };
|
|
//Add all children to RootPanel
|
|
for( int i = 0; i < layoutPanelElements.Count; ++i )
|
|
{
|
|
this.RootPanel.Children.Add( layoutPanelElements[ i ] );
|
|
}
|
|
}
|
|
|
|
this.TopSide = new LayoutAnchorSide();
|
|
if( this.ReadElement( reader ) != null )
|
|
{
|
|
this.FillLayoutAnchorSide( reader, TopSide );
|
|
}
|
|
this.RightSide = new LayoutAnchorSide();
|
|
if( this.ReadElement( reader ) != null )
|
|
{
|
|
this.FillLayoutAnchorSide( reader, RightSide );
|
|
}
|
|
this.LeftSide = new LayoutAnchorSide();
|
|
if( this.ReadElement( reader ) != null )
|
|
{
|
|
this.FillLayoutAnchorSide( reader, LeftSide );
|
|
}
|
|
this.BottomSide = new LayoutAnchorSide();
|
|
if( this.ReadElement( reader ) != null )
|
|
{
|
|
this.FillLayoutAnchorSide( reader, BottomSide );
|
|
}
|
|
|
|
this.FloatingWindows.Clear();
|
|
var floatingWindows = this.ReadElementList( reader, true );
|
|
foreach( var floatingWindow in floatingWindows )
|
|
{
|
|
this.FloatingWindows.Add( ( LayoutFloatingWindow )floatingWindow );
|
|
}
|
|
|
|
this.Hidden.Clear();
|
|
var hidden = this.ReadElementList( reader, false );
|
|
foreach( var hiddenObject in hidden )
|
|
{
|
|
this.Hidden.Add( ( LayoutAnchorable )hiddenObject );
|
|
}
|
|
}
|
|
|
|
public void WriteXml( XmlWriter writer )
|
|
{
|
|
writer.WriteStartElement( "RootPanel" );
|
|
if( this.RootPanel != null )
|
|
{
|
|
this.RootPanel.WriteXml( writer );
|
|
}
|
|
writer.WriteEndElement();
|
|
|
|
writer.WriteStartElement( "TopSide" );
|
|
if( this.TopSide != null )
|
|
{
|
|
this.TopSide.WriteXml( writer );
|
|
}
|
|
writer.WriteEndElement();
|
|
|
|
writer.WriteStartElement( "RightSide" );
|
|
if( this.RightSide != null )
|
|
{
|
|
this.RightSide.WriteXml( writer );
|
|
}
|
|
writer.WriteEndElement();
|
|
|
|
writer.WriteStartElement( "LeftSide" );
|
|
if( this.LeftSide != null )
|
|
{
|
|
this.LeftSide.WriteXml( writer );
|
|
}
|
|
writer.WriteEndElement();
|
|
|
|
writer.WriteStartElement( "BottomSide" );
|
|
if( this.BottomSide != null )
|
|
{
|
|
this.BottomSide.WriteXml( writer );
|
|
}
|
|
writer.WriteEndElement();
|
|
|
|
// Write all floating windows (can be LayoutDocumentFloatingWindow or LayoutAnchorableFloatingWindow).
|
|
// To prevent "can not create instance of abstract type", the type is retrieved with GetType().Name
|
|
writer.WriteStartElement( "FloatingWindows" );
|
|
foreach( var layoutFloatingWindow in FloatingWindows )
|
|
{
|
|
writer.WriteStartElement( layoutFloatingWindow.GetType().Name );
|
|
layoutFloatingWindow.WriteXml( writer );
|
|
writer.WriteEndElement();
|
|
}
|
|
writer.WriteEndElement();
|
|
|
|
writer.WriteStartElement( "Hidden" );
|
|
foreach( var layoutAnchorable in Hidden )
|
|
{
|
|
writer.WriteStartElement( layoutAnchorable.GetType().Name );
|
|
layoutAnchorable.WriteXml( writer );
|
|
writer.WriteEndElement();
|
|
}
|
|
writer.WriteEndElement();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Internal Methods
|
|
|
|
internal static Type FindType( string name )
|
|
{
|
|
foreach( var assembly in AppDomain.CurrentDomain.GetAssemblies() )
|
|
{
|
|
foreach( var type in assembly.GetTypes() )
|
|
{
|
|
if( type.Name.Equals( name ) )
|
|
return type;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
internal void FireLayoutUpdated()
|
|
{
|
|
if( Updated != null )
|
|
Updated( this, EventArgs.Empty );
|
|
}
|
|
|
|
internal void OnLayoutElementAdded( LayoutElement element )
|
|
{
|
|
if( ElementAdded != null )
|
|
ElementAdded( this, new LayoutElementEventArgs( element ) );
|
|
}
|
|
|
|
internal void OnLayoutElementRemoved( LayoutElement element )
|
|
{
|
|
if( element.Descendents().OfType<LayoutContent>().Any( c => c == LastFocusedDocument ) )
|
|
LastFocusedDocument = null;
|
|
if( element.Descendents().OfType<LayoutContent>().Any( c => c == ActiveContent ) )
|
|
ActiveContent = null;
|
|
if( ElementRemoved != null )
|
|
ElementRemoved( this, new LayoutElementEventArgs( element ) );
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
|
|
private void _floatingWindows_CollectionChanged( object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e )
|
|
{
|
|
if( e.OldItems != null && ( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove ||
|
|
e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) )
|
|
{
|
|
foreach( LayoutFloatingWindow element in e.OldItems )
|
|
{
|
|
if( element.Parent == this )
|
|
element.Parent = null;
|
|
}
|
|
}
|
|
|
|
if( e.NewItems != null && ( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add ||
|
|
e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) )
|
|
{
|
|
foreach( LayoutFloatingWindow element in e.NewItems )
|
|
element.Parent = this;
|
|
}
|
|
}
|
|
|
|
private void _hiddenAnchorables_CollectionChanged( object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e )
|
|
{
|
|
if( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove ||
|
|
e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace )
|
|
{
|
|
if( e.OldItems != null )
|
|
{
|
|
foreach( LayoutAnchorable element in e.OldItems )
|
|
{
|
|
if( element.Parent == this )
|
|
element.Parent = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add ||
|
|
e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace )
|
|
{
|
|
if( e.NewItems != null )
|
|
{
|
|
foreach( LayoutAnchorable element in e.NewItems )
|
|
{
|
|
if( element.Parent != this )
|
|
{
|
|
if( element.Parent != null )
|
|
element.Parent.RemoveChild( element );
|
|
element.Parent = this;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
private void InternalSetActiveContent( LayoutContent currentValue, LayoutContent newActiveContent )
|
|
{
|
|
RaisePropertyChanging( "ActiveContent" );
|
|
if( currentValue != null )
|
|
currentValue.IsActive = false;
|
|
_activeContent = new WeakReference( newActiveContent );
|
|
currentValue = ActiveContent;
|
|
if( currentValue != null )
|
|
currentValue.IsActive = true;
|
|
RaisePropertyChanged( "ActiveContent" );
|
|
_activeContentSet = currentValue != null;
|
|
if( currentValue != null )
|
|
{
|
|
if( currentValue.Parent is LayoutDocumentPane || currentValue is LayoutDocument )
|
|
LastFocusedDocument = currentValue;
|
|
}
|
|
else
|
|
LastFocusedDocument = null;
|
|
}
|
|
|
|
private void UpdateActiveContentProperty()
|
|
{
|
|
var activeContent = ActiveContent;
|
|
if( _activeContentSet && ( activeContent == null || activeContent.Root != this ) )
|
|
{
|
|
_activeContentSet = false;
|
|
InternalSetActiveContent( activeContent, null );
|
|
}
|
|
}
|
|
|
|
private void FillLayoutAnchorSide( XmlReader reader, LayoutAnchorSide layoutAnchorSide )
|
|
{
|
|
var result = new List<LayoutAnchorGroup>();
|
|
|
|
while( true )
|
|
{
|
|
//Read all layoutAnchorSide children
|
|
var element = ReadElement( reader ) as LayoutAnchorGroup;
|
|
if( element != null )
|
|
{
|
|
result.Add( element );
|
|
}
|
|
else if( reader.NodeType == XmlNodeType.EndElement )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
reader.ReadEndElement();
|
|
foreach( var las in result )
|
|
{
|
|
layoutAnchorSide.Children.Add( las );
|
|
}
|
|
}
|
|
|
|
private List<ILayoutPanelElement> ReadRootPanel( XmlReader reader, out Orientation orientation )
|
|
{
|
|
orientation = Orientation.Horizontal;
|
|
var result = new List<ILayoutPanelElement>();
|
|
|
|
var startElementName = reader.LocalName;
|
|
reader.Read();
|
|
if( reader.LocalName.Equals( startElementName ) && ( reader.NodeType == XmlNodeType.EndElement ) )
|
|
{
|
|
return null;
|
|
}
|
|
|
|
while( reader.NodeType == XmlNodeType.Whitespace )
|
|
{
|
|
reader.Read();
|
|
}
|
|
|
|
if( reader.LocalName.Equals( "RootPanel" ) )
|
|
{
|
|
orientation = (reader.GetAttribute( "Orientation" ) == "Vertical") ? Orientation.Vertical : Orientation.Horizontal;
|
|
reader.Read();
|
|
|
|
while( true )
|
|
{
|
|
//Read all RootPanel children
|
|
var element = ReadElement( reader ) as ILayoutPanelElement;
|
|
if( element != null )
|
|
{
|
|
result.Add( element );
|
|
}
|
|
else if( reader.NodeType == XmlNodeType.EndElement )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
reader.ReadEndElement();
|
|
|
|
return result;
|
|
}
|
|
|
|
private List<object> ReadElementList( XmlReader reader, bool isFloatingWindow )
|
|
{
|
|
var resultList = new List<object>();
|
|
|
|
while( reader.NodeType == XmlNodeType.Whitespace )
|
|
{
|
|
reader.Read();
|
|
}
|
|
|
|
if( reader.IsEmptyElement )
|
|
{
|
|
reader.Read();
|
|
return resultList;
|
|
}
|
|
|
|
var startElementName = reader.LocalName;
|
|
reader.Read();
|
|
if( reader.LocalName.Equals( startElementName ) && ( reader.NodeType == XmlNodeType.EndElement ) )
|
|
{
|
|
return null;
|
|
}
|
|
|
|
while( reader.NodeType == XmlNodeType.Whitespace )
|
|
{
|
|
reader.Read();
|
|
}
|
|
|
|
while( true )
|
|
{
|
|
if( isFloatingWindow )
|
|
{
|
|
var result = this.ReadElement( reader ) as LayoutFloatingWindow;
|
|
if( result == null )
|
|
{
|
|
break;
|
|
}
|
|
resultList.Add( result );
|
|
}
|
|
else
|
|
{
|
|
var result = this.ReadElement( reader ) as LayoutAnchorable;
|
|
if( result == null )
|
|
{
|
|
break;
|
|
}
|
|
resultList.Add( result );
|
|
}
|
|
}
|
|
|
|
reader.ReadEndElement();
|
|
|
|
return resultList;
|
|
}
|
|
|
|
private object ReadElement( XmlReader reader )
|
|
{
|
|
while( reader.NodeType == XmlNodeType.Whitespace )
|
|
{
|
|
reader.Read();
|
|
}
|
|
|
|
if( reader.NodeType == XmlNodeType.EndElement )
|
|
{
|
|
return null;
|
|
}
|
|
|
|
XmlSerializer serializer;
|
|
switch( reader.LocalName )
|
|
{
|
|
case "LayoutAnchorablePaneGroup":
|
|
serializer = new XmlSerializer( typeof( LayoutAnchorablePaneGroup ) );
|
|
break;
|
|
case "LayoutAnchorablePane":
|
|
serializer = new XmlSerializer( typeof( LayoutAnchorablePane ) );
|
|
break;
|
|
case "LayoutAnchorable":
|
|
serializer = new XmlSerializer( typeof( LayoutAnchorable ) );
|
|
break;
|
|
case "LayoutDocumentPaneGroup":
|
|
serializer = new XmlSerializer( typeof( LayoutDocumentPaneGroup ) );
|
|
break;
|
|
case "LayoutDocumentPane":
|
|
serializer = new XmlSerializer( typeof( LayoutDocumentPane ) );
|
|
break;
|
|
case "LayoutDocument":
|
|
serializer = new XmlSerializer( typeof( LayoutDocument ) );
|
|
break;
|
|
case "LayoutAnchorGroup":
|
|
serializer = new XmlSerializer( typeof( LayoutAnchorGroup ) );
|
|
break;
|
|
case "LayoutPanel":
|
|
serializer = new XmlSerializer( typeof( LayoutPanel ) );
|
|
break;
|
|
case "LayoutDocumentFloatingWindow":
|
|
serializer = new XmlSerializer( typeof( LayoutDocumentFloatingWindow ) );
|
|
break;
|
|
case "LayoutAnchorableFloatingWindow":
|
|
serializer = new XmlSerializer( typeof( LayoutAnchorableFloatingWindow ) );
|
|
break;
|
|
case "LeftSide":
|
|
case "RightSide":
|
|
case "TopSide":
|
|
case "BottomSide":
|
|
if( reader.IsEmptyElement )
|
|
{
|
|
reader.Read();
|
|
return null;
|
|
}
|
|
return reader.Read();
|
|
default:
|
|
var type = LayoutRoot.FindType( reader.LocalName );
|
|
if( type == null )
|
|
{
|
|
throw new ArgumentException( "AvalonDock.LayoutRoot doesn't know how to deserialize " + reader.LocalName );
|
|
}
|
|
serializer = new XmlSerializer( type );
|
|
break;
|
|
}
|
|
|
|
return serializer.Deserialize( reader );
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Events
|
|
|
|
public event EventHandler Updated;
|
|
public event EventHandler<LayoutElementEventArgs> ElementAdded;
|
|
public event EventHandler<LayoutElementEventArgs> ElementRemoved;
|
|
|
|
#endregion
|
|
}
|
|
}
|
|
|