Subversion Repositories SoapBoxCore

Rev

Rev 7 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

//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.ComponentModel;
using System.Diagnostics;


namespace AvalonDock
{
    /// <summary>
    /// Represent a document which can be host by a <see cref="DocumentPane"/>.
    /// </summary>
    /// <remarks>A document is always hosted by a <see cref="DocumentPane"/> usually in the central area of <see cref="DockingManager"/>.
    /// It has limited dragging features becaus it can be only moved to an other <see cref="DocumentPane"/> and can't float as a separate window.
    /// You can access all documents within <see cref="DockingManager"/> with property <see cref="DockingManager.Documents"/>.</remarks>
    public class DocumentContent : ManagedContent
    {

        static DocumentContent()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DocumentContent), new FrameworkPropertyMetadata(typeof(DocumentContent)));

            //Control.WidthProperty.OverrideMetadata(typeof(DocumentContent),
            //    new FrameworkPropertyMetadata(new PropertyChangedCallback(OnSizePropertyChanged), new CoerceValueCallback(CourceSizeToNaN)));
            //Control.HeightProperty.OverrideMetadata(typeof(DocumentContent),
            //    new FrameworkPropertyMetadata(new PropertyChangedCallback(OnSizePropertyChanged), new CoerceValueCallback(CourceSizeToNaN)));
        }

        public DocumentContent()
        {
            //base.PropertyChanged += new PropertyChangedEventHandler(DocumentContent_PropertyChanged);
        }

        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(string.Format(
            //        "Unable to find DockingManager object in the logical tree of document '{0}'", Title));

            //manager.Documents.Add(this);

            base.OnContentLoaded();
        }

        protected override void OnContentUnloaded()
        {
            //if (Manager != null)
            //    Manager.Documents.Remove(this);

            base.OnContentUnloaded();
        }

        #region InfoTip

        /// <summary>
        /// InfoTip Dependency Property
        /// </summary>
        public static readonly DependencyProperty InfoTipProperty =
            DependencyProperty.Register("InfoTip", typeof(string), typeof(DocumentContent),
                new FrameworkPropertyMetadata(null));

        /// <summary>
        /// Gets or sets the InfoTip property.  This dependency property
        /// indicates information text attached to the document content.
        /// </summary>
        /// <remarks>This text is usually displayed when users switch between documents and helps them to choose the right one.</remarks>
        public string InfoTip
        {
            get { return (string)GetValue(InfoTipProperty); }
            set { SetValue(InfoTipProperty, value); }
        }

        #endregion

        #region ContentTypeDescription

        /// <summary>
        /// ContentTypeDescription Dependency Property
        /// </summary>
        public static readonly DependencyProperty ContentTypeDescriptionProperty =
            DependencyProperty.Register("ContentTypeDescription", typeof(string), typeof(DocumentContent),
                new FrameworkPropertyMetadata((string)string.Empty));

        /// <summary>
        /// Gets or sets the ContentTypeDescription property.  This dependency property
        /// indicates a text which describes the type of content contained in this document.
        /// </summary>
        public string ContentTypeDescription
        {
            get { return (string)GetValue(ContentTypeDescriptionProperty); }
            set { SetValue(ContentTypeDescriptionProperty, value); }
        }

        #endregion

        /// <summary>
        /// Gets or sets a value indicating if this document can float over main window (VS2010 Feature).
        /// </summary>
        public bool IsFloatingAllowed
        {
            get { return (bool)GetValue(IsFloatingAllowedProperty); }
            set { SetValue(IsFloatingAllowedProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsFloatingAllowed.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsFloatingAllowedProperty =
            DependencyProperty.Register("IsFloatingAllowed", typeof(bool), typeof(DocumentContent), new PropertyMetadata(true));


        #region IsFloating

        /// <summary>
        /// IsFloating Read-Only Dependency Property
        /// </summary>
        private static readonly DependencyPropertyKey IsFloatingPropertyKey
            = DependencyProperty.RegisterReadOnly("IsFloating", typeof(bool), typeof(DocumentContent),
                new FrameworkPropertyMetadata((bool)false));

        public static readonly DependencyProperty IsFloatingProperty
            = IsFloatingPropertyKey.DependencyProperty;

        /// <summary>
        /// Gets the IsFloating property.  This dependency property
        /// indicates if the DocumentContent is floating inside an external window.
        /// </summary>
        public bool IsFloating
        {
            get { return (bool)GetValue(IsFloatingProperty); }
        }

        /// <summary>
        /// Provides a secure method for setting the IsFloating property.  
        /// This dependency property indicates if the DocumentContent is floating inside an external window.
        /// </summary>
        /// <param name="value">The new value for the property.</param>
        internal void SetIsFloating(bool value)
        {
            SetValue(IsFloatingPropertyKey, value);
        }

        #endregion


        protected override void OnDragStart(Point ptMouse, Point ptRelativeMouse)
        {
            if (IsFloatingAllowed)
            {
                Manager.Drag(this, HelperFunc.PointToScreenWithoutFlowDirection(this, ptMouse), ptRelativeMouse);
            }

            base.OnDragStart(ptMouse, ptRelativeMouse);
        }

        protected override void OnDragMouseMove(object sender, MouseEventArgs e)
        {
            base.OnDragMouseMove(sender, e);
        }

        protected override void OnDragMouseLeave(object sender, MouseEventArgs e)
        {
           
            base.OnDragMouseLeave(sender, e);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            if (DragEnabledArea != null)
            {
                if (string.IsNullOrEmpty((string)DragEnabledArea.ToolTip))
                    DragEnabledArea.ToolTip = InfoTip;
            }
        }

        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);

            this.CommandBindings.Add(
                new CommandBinding(DocumentContentCommands.FloatingDocument, this.OnExecuteCommand, this.OnCanExecuteCommand));
            this.CommandBindings.Add(
                new CommandBinding(DocumentContentCommands.TabbedDocument, this.OnExecuteCommand, this.OnCanExecuteCommand));
        }

        void OnExecuteCommand(object sender, ExecutedRoutedEventArgs e)
        {
            if (!e.Handled && e.Command == DocumentContentCommands.FloatingDocument)
            {
                this.Show(true);

                e.Handled = true;
            }
            else if (!e.Handled && e.Command == DocumentContentCommands.TabbedDocument)
            {
                this.Show(false);

                e.Handled = true;
            }
        }

        void OnCanExecuteCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = CanExecuteCommand(e.Command);
        }

        /// <summary>
        /// Show <see cref="DocumentContent"/> as tabbed document
        /// </summary>
        public override void Show()
        {
            Show(false);
        }

        /// <summary>
        /// Show <see cref="DocumentContent"/> as tabbed document inside the provided <see cref="DockingManager"/>
        /// </summary>
        /// <param name="manager">Docking manager target</param>
        public override void Show(DockingManager manager)
        {
            Show(manager, false);
        }

        /// <summary>
        /// Show <see cref="DocumentContent"/> as tabbed document or inside a floating window
        /// </summary>
        public void Show(bool showAsFloatingWindow)
        {
            if (!CanExecuteCommand(ManagedContentCommands.Show))
                throw new InvalidOperationException("This operation can be executed in this state");

            Manager.Show(this, showAsFloatingWindow);
        }

        /// <summary>
        /// Show <see cref="DocumentContent"/> as tabbed document inside the provided <see cref="DockingManager"/>
        /// </summary>
        /// <param name="manager">Docking manager target</param>
        /// <param name="showAsFloatingWindow">True if document should be shown inside a floating window (<see cref="DocumentFloatingWindow"/>)</param>
        public void Show(DockingManager manager, bool showAsFloatingWindow)
        {
            if (Manager != null && Manager != manager)
                throw new InvalidOperationException("Please remove the content from previous DockingManager (using the Close method)");

            if (!CanExecuteCommand(ManagedContentCommands.Show))
                throw new InvalidOperationException("This operation can be executed in this state");

            manager.Show(this, showAsFloatingWindow);

            manager.Documents.Add(this);
        }

        /// <summary>
        /// Activate the document showing its header if it's not visible
        /// </summary>
        public override void Activate()
        {
            base.Activate();

            if (!DocumentTabPanel.GetIsHeaderVisible(this))
            {
                DocumentPane parentPane = this.ContainerPane as DocumentPane;
                if (parentPane != null &&
                    parentPane.GetManager() != null &&
                    parentPane.Items.IndexOf(this) != 0)
                {
                    parentPane.Items.Remove(this);
                    parentPane.Items.Insert(0, this);
                    parentPane.SelectedIndex = 0;
                }
            }
        }

        /// <summary>
        /// Retrive a value indicating if the command can be executed based to the dockable content state
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        protected override bool CanExecuteCommand(ICommand command)
        {
            if (command == DocumentContentCommands.FloatingDocument)
            {
                return !IsFloating && IsFloatingAllowed;
            }
            else if (command == DocumentContentCommands.TabbedDocument)
            {
                return IsFloating;
            }

            return true;
        }

        /// <summary>
        /// Close this content without notifications
        /// </summary>
        internal void InternalClose()
        {
            DockingManager manager = Manager;

            if (manager != null)
            {
                if (manager.ActiveContent == this)
                    manager.ActiveContent = null;

                if (manager.ActiveDocument == this)
                    manager.ActiveDocument = null;
            }          
           
            DocumentPane parentPane = ContainerPane as DocumentPane;
            FloatingDocumentPane floatingParentPane = ContainerPane as FloatingDocumentPane;

            if (floatingParentPane != null)
            {
                floatingParentPane.RemoveContent(0);
                if (floatingParentPane.FloatingWindow != null &&
                    !floatingParentPane.FloatingWindow.IsClosing)
                    floatingParentPane.FloatingWindow.Close();
            }
            else if (parentPane != null)
            {
                parentPane.Items.Remove(this);

                parentPane.CheckContentsEmpty();
            }
        }

        /// <summary>
        /// Close this document removing it from its parent container
        /// </summary>
        /// <remarks>Use this function to close a document and remove it from its parent container. Please note
        /// that if you simply remove it from its parent <see cref="DocumentPane"/> without call this method, events like
        /// <see cref="OnClosing"/>/<see cref="OnClosed"/> are not called.
        /// </remarks>
        public override bool Close()
        {
            if (!IsCloseable)
                return false;

            ////if documents are attached to an external source via DockingManager.DocumentsSource
            ////let application host handle the document closing by itself
            //if (Manager.DocumentsSource != null)
            //{
            //    //return Manager.FireRequestDocumentCloseEvent(this);
            //    Manager.HandleDocumentClose(this);
            //}


            CancelEventArgs e = new CancelEventArgs(false);
            OnClosing(e);
           
            if (e.Cancel)
                return false;

            DockingManager oldManager = Manager;

            if (Manager != null)
                Manager.FireDocumentClosingEvent(e);

            if (e.Cancel)
                return false;

            InternalClose();

            OnClosed();

            //if documents are attached to an external source via DockingManager.DocumentsSource
            //let application host handle the document closing by itself
            if (Manager.DocumentsSource != null)
            {
                Manager.HandleDocumentClose(this);
            }

            if (oldManager != null)
                oldManager.FireDocumentClosedEvent();


            Debug.Assert(Parent == null, "Parent MUST bu null after Doc is closed");
            return true;
        }

        /// <summary>
        /// Hide the <see cref="DocumentContent"/> (Close the document)
        /// </summary>
        /// <returns></returns>
        public override bool Hide()
        {
            return Close();
        }



        #region Save/RestoreLayout
        public override void SaveLayout(System.Xml.XmlWriter storeWriter)
        {
            base.SaveLayout(storeWriter);
        }

        public override void RestoreLayout(System.Xml.XmlElement contentElement)
        {
            base.RestoreLayout(contentElement);
        }
        #endregion
    }
}