// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Design;
using System.Windows.Forms.Design.Behavior;
using static Interop;

namespace System.Windows.Forms.Design
{
    /// <summary>
    ///  The ParentControlDesigner class builds on the ControlDesigner.  It adds the ability
    ///  to manipulate child components, and provides a selection UI handler for all
    ///  components it contains.
    /// </summary>
    public partial class ParentControlDesigner : ControlDesigner, IOleDragClient
    {
        private Point _mouseDragBase = InvalidPoint;                        // the base point of the drag
        private Rectangle _mouseDragOffset = Rectangle.Empty;               // always keeps the current rectangle
        private ToolboxItem _mouseDragTool;                                 // the tool that's being dragged, if we're creating a component
        private FrameStyle _mouseDragFrame;                                 // the frame style of this mouse drag

        private OleDragDropHandler _oleDragDropHandler;                     // handler for ole drag drop operations
        private EscapeHandler _escapeHandler;                               // active during drags to override escape.
        private Control _pendingRemoveControl;                              // we've gotten an OnComponentRemoving, and are waiting for OnComponentRemove
        private IComponentChangeService _componentChangeSvc;
        private DragAssistanceManager _dragManager;                         //used to apply snaplines when dragging a new tool rect on the designer's surface
        private ToolboxSnapDragDropEventArgs _toolboxSnapDragDropEventArgs; //used to store extra info about a beh. svc. dragdrop from the toolbx
        private ToolboxItemSnapLineBehavior _toolboxItemSnapLineBehavior;   //this is our generic snapline box for dragging comps from the toolbx
        private Graphics _graphics;                                         //graphics object of the adornerwindow (via BehaviorService)

        // Services that we keep around for the duration of a drag.  you should always check
        // to see if you need to get this service.  We cache it, but demand create it.
        //
        private IToolboxService _toolboxService;

        private const int MinGridSize = 2;
        private const int MaxGridSize = 200;

        // designer options...
        //
        private Point _adornerWindowToScreenOffset;                         //quick lookup for offsetting snaplines for new tools

        private bool _checkSnapLineSetting = true;                          // Since layout options is global for the duration of the designer, we should only query it once.
        private bool _defaultUseSnapLines;

        private bool _gridSnap = true;
        private Size _gridSize = Size.Empty;
        private bool _drawGrid = true;

        private bool _parentCanSetDrawGrid = true;                          //since we can inherit the grid/snap setting of our parent,
        private bool _parentCanSetGridSize = true;                          //  these 3 properties let us know if these values have
        private bool _parentCanSetGridSnap = true;                          //  been set explicitly by a user - so to ignore the parent's setting

        private bool _getDefaultDrawGrid = true;
        private bool _getDefaultGridSize = true;
        private bool _getDefaultGridSnap = true;
        private StatusCommandUI _statusCommandUI;                           // UI for setting the StatusBar Information..

        private int _suspendChanging;

        /// <summary>
        ///  This is called after the user selects a toolbox item (that has a ParentControlDesigner
        ///  associated with it) and draws a reversible rectangle on a designer's surface.  If
        ///  this property returns true, it is indicating that the Controls that were lasso'd on the
        ///  designer's surface will be re-parented to this designer's control.
        /// </summary>
        protected virtual bool AllowControlLasso
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        ///  This is called to check whether a generic dragbox should be drawn when dragging a toolbox item
        ///  over the designer's surface.
        /// </summary>
        protected virtual bool AllowGenericDragBox
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        ///  This is called to check whether the z-order of dragged controls should be maintained when dropped on a
        ///  ParentControlDesigner. By default it will, but e.g. FlowLayoutPanelDesigner wants to do its own z-ordering.
        ///  If this returns true, then the DropSourceBehavior will attempt to set the index of the controls being
        ///  dropped to preserve the original order (in the dragSource). If it returns false, the index will not
        ///  be set.
        ///  If this is set to false, then the DropSourceBehavior will not treat a drag as a local drag even
        ///  if the dragSource and the dragTarget are the same. This will allow a ParentControlDesigner to hook
        ///  OnChildControlAdded to set the right child index, since in this case, the control(s) being dragged
        ///  will be removed from the dragSource and then added to the dragTarget.
        /// </summary>
        protected internal virtual bool AllowSetChildIndexOnDrop
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        ///  This is called when the component is added to the parent container.
        ///  Theoretically it performs the same function as IsDropOK does, but
        ///  unfortunately IsDropOK is not robust enough and does not allow for specific error messages.
        ///  This method is a chance to display the same error as is displayed at runtime.
        /// </summary>
        protected internal virtual bool CanAddComponent(IComponent component)
        {
            return true;
        }

        /// <summary>
        ///  This can be called to determine the current grid spacing and mode.
        ///  It is sensitive to what modifier keys the user currently has down and
        ///  will either return the current grid snap dimensons, or a 1x1 point
        ///  indicating no snap.
        /// </summary>
        private Size CurrentGridSize
        {
            get
            {
                return GridSize;
            }
        }

        /// <summary>
        ///  Determines the default location for a control added to this designer.
        ///  it is usualy (0,0), but may be modified if the container has special borders, etc.
        /// </summary>
        protected virtual Point DefaultControlLocation
        {
            get
            {
                return new Point(0, 0);
            }
        }

        private bool DefaultUseSnapLines
        {
            get
            {
                if (_checkSnapLineSetting)
                {
                    _checkSnapLineSetting = false;
                    _defaultUseSnapLines = DesignerUtils.UseSnapLines(Component.Site);
                }

                return _defaultUseSnapLines;
            }
        }

        /// <summary>
        ///  Accessor method for the DrawGrid property.  This property determines
        ///  if the grid should be drawn on a control.
        /// </summary>
        protected virtual bool DrawGrid
        {
            get
            {
                // If snaplines are on, the we never want to draw the grid

                if (DefaultUseSnapLines)
                {
                    return false;
                }
                else if (_getDefaultDrawGrid)
                {
                    _drawGrid = true;

                    //Before we check our options page, we need to see if our parent
                    //is a ParentControlDesigner, is so, then we will want to inherit all
                    //our grid/snap setting from it - instead of our options page
                    //
                    ParentControlDesigner parent = GetParentControlDesignerOfParent();
                    if (parent != null)
                    {
                        _drawGrid = parent.DrawGrid;
                    }
                    else
                    {
                        object value = DesignerUtils.GetOptionValue(ServiceProvider, "ShowGrid");
                        if (value is bool)
                        {
                            _drawGrid = (bool)value;
                        }
                    }
                }

                return _drawGrid;
            }

            set
            {
                if (value != _drawGrid)
                {
                    if (_parentCanSetDrawGrid)
                    {
                        _parentCanSetDrawGrid = false;
                    }

                    if (_getDefaultDrawGrid)
                    {
                        _getDefaultDrawGrid = false;
                    }

                    _drawGrid = value;

                    //invalidate the cotnrol to remove or draw the grid based on the new value
                    Control control = Control;
                    if (control != null)
                    {
                        control.Invalidate(true);
                    }

                    //now, notify all child parent control designers that we have changed our setting
                    // 'cause they might to change along with us, unless the user has explicitly set
                    // those values...
                    IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
                    if (host != null)
                    {
                        // for (int i = 0; i < children.Length; i++) {
                        foreach (Control child in Control.Controls)
                        {
                            ParentControlDesigner designer = host.GetDesigner(child) as ParentControlDesigner;
                            if (designer != null)
                            {
                                designer.DrawGridOfParentChanged(_drawGrid);
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        ///  Determines whether drag rects can be drawn on this designer.
        /// </summary>
        protected override bool EnableDragRect
        {
            get
            {
                return true;
            }
        }

        internal Size ParentGridSize
        {
            get
            {
                return GridSize;
            }
        }

        /// <summary>
        ///  Gets/Sets the GridSize property for a form or user control.
        /// </summary>
        protected Size GridSize
        {
            get
            {
                if (_getDefaultGridSize)
                {
                    _gridSize = new Size(8, 8);

                    //Before we check our options page, we need to see if our parent
                    //is a ParentControlDesigner, is so, then we will want to inherit all
                    //our grid/snap setting from it - instead of our options page
                    //
                    ParentControlDesigner parent = GetParentControlDesignerOfParent();
                    if (parent != null)
                    {
                        _gridSize = parent.GridSize;
                    }
                    else
                    {
                        object value = DesignerUtils.GetOptionValue(ServiceProvider, "GridSize");
                        if (value is Size)
                        {
                            _gridSize = (Size)value;
                        }
                    }
                }

                return _gridSize;
            }
            set
            {
                if (_parentCanSetGridSize)
                {
                    _parentCanSetGridSize = false;
                }

                if (_getDefaultGridSize)
                {
                    _getDefaultGridSize = false;
                }

                //do some validation checking here, against min & max GridSize
                //
                if (value.Width < MinGridSize || value.Height < MinGridSize ||
                     value.Width > MaxGridSize || value.Height > MaxGridSize)
                    throw new ArgumentException(string.Format(SR.InvalidArgument,
                                                              "GridSize",
                                                              value.ToString()));
                _gridSize = value;

                //invalidate the control
                Control control = Control;
                if (control != null)
                {
                    control.Invalidate(true);
                }

                //now, notify all child parent control designers that we have changed our setting
                // 'cause they might to change along with us, unless the user has explicitly set
                // those values...
                IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
                if (host != null)
                {
                    foreach (Control child in Control.Controls)
                    {
                        ParentControlDesigner designer = host.GetDesigner(child) as ParentControlDesigner;
                        if (designer != null)
                        {
                            designer.GridSizeOfParentChanged(_gridSize);
                        }
                    }
                }
            }
        }

        /// <summary>
        ///  This property is used by deriving classes to determine if the designer is
        ///  in a state where it has a valid MouseDragTool.
        /// </summary>
        [CLSCompliant(false)]
        protected ToolboxItem MouseDragTool
        {
            get
            {
                return _mouseDragTool;
            }
        }

        /// <summary>
        ///  This property is used by deriving classes to determine if it returns the control being designed or some other
        ///  Container ...
        ///  while adding a component to it.
        ///  e.g: When SplitContainer is selected and a component is being added ... the SplitContainer designer would return a
        ///  SelectedPanel as the ParentControl for all the items being added rather than itself.
        /// </summary>
        protected virtual Control GetParentForComponent(IComponent component)
        {
            return Control;
        }

        // We need to allocation new ArrayList and pass it to the caller..
        // So its ok to Suppress this.
        protected void AddPaddingSnapLines(ref ArrayList snapLines)
        {
            if (snapLines == null)
            {
                snapLines = new ArrayList(4);
            }

            //In order to add padding, we need to get the offset from the usable client area of our control
            //and the actual origin of our control.  In other words: how big is the non-client area here?
            // Ex: we want to add padding on a form to the insides of the borders and below the titlebar.
            Point offset = GetOffsetToClientArea();

            //the desplay rectangle should be the client area combined with the padding value
            Rectangle displayRectangle = Control.DisplayRectangle;
            displayRectangle.X += offset.X;//offset for non-client area
            displayRectangle.Y += offset.Y;//offset for non-client area

            //add the four paddings of our control

            // Even if a control does not have padding, we still want to add Padding snaplines.
            // This is because we only try to match to matching snaplines. Makes the code a little easier...
            snapLines.Add(new SnapLine(SnapLineType.Vertical, displayRectangle.Left, SnapLine.PaddingLeft, SnapLinePriority.Always));
            snapLines.Add(new SnapLine(SnapLineType.Vertical, displayRectangle.Right, SnapLine.PaddingRight, SnapLinePriority.Always));
            snapLines.Add(new SnapLine(SnapLineType.Horizontal, displayRectangle.Top, SnapLine.PaddingTop, SnapLinePriority.Always));
            snapLines.Add(new SnapLine(SnapLineType.Horizontal, displayRectangle.Bottom, SnapLine.PaddingBottom, SnapLinePriority.Always));
        }

        /// <summary>
        ///  Returns a list of SnapLine objects representing interesting
        ///  alignment points for this control.  These SnapLines are used
        ///  to assist in the positioning of the control on a parent's
        ///  surface.
        /// </summary>
        public override IList SnapLines
        {
            get
            {
                ArrayList snapLines = base.SnapLines as ArrayList;

                if (snapLines == null)
                {
                    Debug.Fail("why did base.SnapLines return null?");
                    snapLines = new ArrayList(4);
                }

                AddPaddingSnapLines(ref snapLines);
                return snapLines;
            }
        }

        private IServiceProvider ServiceProvider
        {
            get
            {
                if (Component != null)
                {
                    return Component.Site;
                }

                return null;
            }
        }

        /// <summary>
        ///  Determines if we should snap to grid or not.
        /// </summary>
        private bool SnapToGrid
        {
            get
            {
                // If snaplines are on, the we never want to snap to grid
                if (DefaultUseSnapLines)
                {
                    return false;
                }
                else if (_getDefaultGridSnap)
                {
                    _gridSnap = true;

                    //Before we check our options page, we need to see if our parent
                    //is a ParentControlDesigner, is so, then we will want to inherit all
                    //our grid/snap setting from it - instead of our options page
                    //
                    ParentControlDesigner parent = GetParentControlDesignerOfParent();
                    if (parent != null)
                    {
                        _gridSnap = parent.SnapToGrid;
                    }
                    else
                    {
                        object optionValue = DesignerUtils.GetOptionValue(ServiceProvider, "SnapToGrid");
                        if (optionValue != null && optionValue is bool)
                        {
                            _gridSnap = (bool)optionValue;
                        }
                    }
                }

                return _gridSnap;
            }
            set
            {
                if (_gridSnap != value)
                {
                    if (_parentCanSetGridSnap)
                    {
                        _parentCanSetGridSnap = false;
                    }

                    if (_getDefaultGridSnap)
                    {
                        _getDefaultGridSnap = false;
                    }

                    _gridSnap = value;

                    //now, notify all child parent control designers that we have changed our setting
                    // 'cause they might to change along with us, unless the user has explicitly set
                    // those values...
                    IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
                    if (host != null)
                    {
                        foreach (Control child in Control.Controls)
                        {
                            ParentControlDesigner designer = host.GetDesigner(child) as ParentControlDesigner;
                            if (designer != null)
                            {
                                designer.GridSnapOfParentChanged(_gridSnap);
                            }
                        }
                    }
                }
            }
        }

        internal virtual void AddChildControl(Control newChild)
        {
            if (newChild.Left == 0 && newChild.Top == 0 && newChild.Width >= Control.Width && newChild.Height >= Control.Height)
            {
                // bump the control down one gridsize just so it's selectable...
                //
                Point loc = newChild.Location;
                loc.Offset(GridSize.Width, GridSize.Height);
                newChild.Location = loc;
            }

            Control.Controls.Add(newChild);
            Control.Controls.SetChildIndex(newChild, 0);
        }

        internal void AddControl(Control newChild, IDictionary defaultValues)
        {
            Point location = Point.Empty;
            Size size = Size.Empty;
            Size offset = new Size(0, 0);
            bool hasLocation = (defaultValues != null && defaultValues.Contains("Location"));
            bool hasSize = (defaultValues != null && defaultValues.Contains("Size"));

            if (hasLocation)
                location = (Point)defaultValues["Location"];
            if (hasSize)
                size = (Size)defaultValues["Size"];
            if (defaultValues != null && defaultValues.Contains("Offset"))
            {
                offset = (Size)defaultValues["Offset"];
            }

            // If this component doesn't have a control designer, or if this control
            // is top level, then ignore it.  We have the reverse logic in OnComponentAdded
            // in the document designer so that we will add those guys to the tray.
            // Also, if the child-control has already been parented, we assume it's also been located and return immediately.
            // Otherwise, proceed with the parenting and locating.
            //
            IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
            if (host != null
                && newChild != null
                && !Control.Contains(newChild)
                && (host.GetDesigner(newChild) as ControlDesigner) != null
                && !(newChild is Form && ((Form)newChild).TopLevel))
            {
                Rectangle bounds = new Rectangle();

                // If we were provided with a location, convert it to parent control coordinates.
                // Otherwise, get the control's size and put the location in the middle of it
                //
                if (hasLocation)
                {
                    location = Control.PointToClient(location);
                    bounds.X = location.X;
                    bounds.Y = location.Y;
                }
                else
                {
                    // is the currently selected control this container?
                    //
                    ISelectionService selSvc = (ISelectionService)GetService(typeof(ISelectionService));
                    object primarySelection = selSvc.PrimarySelection;
                    Control selectedControl = null;
                    if (primarySelection != null)
                    {
                        selectedControl = ((IOleDragClient)this).GetControlForComponent(primarySelection);
                    }

                    // If the resulting control that came back isn't sited, it's not part of the
                    // design surface and should not be used as a marker.
                    //
                    if (selectedControl != null && selectedControl.Site == null)
                    {
                        selectedControl = null;
                    }

                    // if the currently selected container is this parent
                    // control, default to 0,0
                    //
                    if (primarySelection == Component || selectedControl == null)
                    {
                        bounds.X = DefaultControlLocation.X;
                        bounds.Y = DefaultControlLocation.Y;
                    }
                    else
                    {
                        // otherwise offset from selected control.
                        //
                        bounds.X = selectedControl.Location.X + GridSize.Width;
                        bounds.Y = selectedControl.Location.Y + GridSize.Height;
                    }
                }

                // If we were not given a size, ask the control for its default.  We
                // also update the location here so the control is in the middle of
                // the user's point, rather than at the edge.
                //
                if (hasSize)
                {
                    bounds.Width = size.Width;
                    bounds.Height = size.Height;
                }
                else
                {
                    bounds.Size = GetDefaultSize(newChild);
                }

                // If we were given neither, center the control
                //
                if (!hasSize && !hasLocation)
                {
                    // get the adjusted location, then inflate
                    // the rect so we can find a nice spot
                    // for this control to live.
                    //
                    Rectangle tempBounds = GetAdjustedSnapLocation(Rectangle.Empty, bounds);

                    // compute the stacking location
                    //
                    tempBounds = GetControlStackLocation(tempBounds);
                    bounds = tempBounds;
                }
                else
                {
                    // Finally, convert the bounds to the appropriate grid snaps
                    //
                    bounds = GetAdjustedSnapLocation(Rectangle.Empty, bounds);
                }

                // Adjust for the offset, if any
                //
                bounds.X += offset.Width;
                bounds.Y += offset.Height;

                //check to see if we have additional information for bounds from
                //the behaviorservice dragdrop logic
                if (defaultValues != null && defaultValues.Contains("ToolboxSnapDragDropEventArgs"))
                {
                    ToolboxSnapDragDropEventArgs e = defaultValues["ToolboxSnapDragDropEventArgs"] as ToolboxSnapDragDropEventArgs;
                    Debug.Assert(e != null, "Why can't we get a ToolboxSnapDragDropEventArgs object out of our default values?");

                    Rectangle snappedBounds = DesignerUtils.GetBoundsFromToolboxSnapDragDropInfo(e, bounds, Control.IsMirrored);

                    //Make sure the snapped bounds intersects with the bounds of the root control before we go
                    //adjusting the drag offset.  A race condition exists where the user can drag a tbx item so fast
                    //that the adorner window will never receive the proper drag/mouse move messages and
                    //never properly adjust the snap drag info.  This cause the control to be added @ 0,0 w.r.t.
                    //the adorner window.
                    Control rootControl = host.RootComponent as Control;
                    if (rootControl != null && snappedBounds.IntersectsWith(rootControl.ClientRectangle))
                    {
                        bounds = snappedBounds;
                    }
                }

                // Parent the control to the designer and set it to the front.
                //
                //
                PropertyDescriptor controlsProp = TypeDescriptor.GetProperties(Control)["Controls"];
                if (_componentChangeSvc != null)
                {
                    _componentChangeSvc.OnComponentChanging(Control, controlsProp);
                }

                AddChildControl(newChild);

                // Now see if the control has size and location properties.  Update
                // these values if it does.
                //
                PropertyDescriptorCollection props = TypeDescriptor.GetProperties(newChild);
                if (props != null)
                {
                    PropertyDescriptor prop = props["Size"];
                    if (prop != null)
                    {
                        prop.SetValue(newChild, new Size(bounds.Width, bounds.Height));
                    }

                    //VSWhidbey# 364133 - ControlDesigner shadows the Location property. If the control is parented
                    //and the parent is a scrollable control, then it expects the Location to be in displayrectangle coordinates.
                    //At this point bounds are in clientrectangle coordinates, so we need to check if we need to adjust the coordinates.
                    //The reason this worked in Everett was that the AddChildControl was done AFTER this. The AddChildControl was moved
                    //above a while back. Not sure what will break if AddChildControl is moved down below, so let's just fix up things
                    //here.

                    Point pt = new Point(bounds.X, bounds.Y);
                    ScrollableControl p = newChild.Parent as ScrollableControl;
                    if (p != null)
                    {
                        Point ptScroll = p.AutoScrollPosition;
                        pt.Offset(-ptScroll.X, -ptScroll.Y); //always want to add the control below/right of the AutoScrollPosition
                    }

                    prop = props["Location"];
                    if (prop != null)
                    {
                        prop.SetValue(newChild, pt);
                    }
                }

                if (_componentChangeSvc != null)
                {
                    _componentChangeSvc.OnComponentChanged(Control, controlsProp, Control.Controls, Control.Controls);
                }

                newChild.Update();
            }
        }

        /// <summary>
        ///  Adds all the child components of a component
        ///  to the given container
        /// </summary>
        private void AddChildComponents(IComponent component, IContainer container, IDesignerHost host)
        {
            Control control = GetControl(component);

            if (control != null)
            {
                Control parent = control;

                Control[] children = new Control[parent.Controls.Count];
                parent.Controls.CopyTo(children, 0);

                string name;
                ISite childSite;

                for (int i = 0; i < children.Length; i++)
                {
                    childSite = ((IComponent)children[i]).Site;

                    IContainer childContainer;
                    if (childSite != null)
                    {
                        name = childSite.Name;
                        if (container.Components[name] != null)
                        {
                            name = null;
                        }

                        childContainer = childSite.Container;
                    }
                    else
                    {
                        //name = null;
                        // we don't want to add unsited child controls because
                        // these may be items from a composite control.  if they
                        // are legitamite children, the ComponentModelPersister would have
                        // sited them already.
                        //
                        continue;
                    }

                    if (childContainer != null)
                    {
                        childContainer.Remove(children[i]);
                    }

                    if (name != null)
                    {
                        container.Add(children[i], name);
                    }
                    else
                    {
                        container.Add(children[i]);
                    }

                    if (children[i].Parent != parent)
                    {
                        parent.Controls.Add(children[i]);
                    }
                    else
                    {
                        // ugh, last resort
                        int childIndex = parent.Controls.GetChildIndex(children[i]);
                        parent.Controls.Remove(children[i]);
                        parent.Controls.Add(children[i]);
                        parent.Controls.SetChildIndex(children[i], childIndex);
                    }

                    IComponentInitializer init = host.GetDesigner(component) as IComponentInitializer;
                    if (init != null)
                    {
                        init.InitializeExistingComponent(null);
                    }

                    // recurse;
                    AddChildComponents(children[i], container, host);
                }
            }
        }

        /// <summary>
        ///  Disposes this component.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                // Stop any drag that we are currently processing.

                // HACK HACK HACK
                //
                // See VSWhidbey #575663.
                //
                // If we are not in a mousedrag, then pretend we are cancelling.
                // This is such that the base will not set the primaryselection to be
                // the associated Component. Doing so can cause a crash in hosted designers.
                // It doesn't make sense to do so anyway, since the designer (and thus
                // the component) is being disposed.
                OnMouseDragEnd((_mouseDragBase == InvalidPoint) ? true : false);

                EnableDragDrop(false);

                if (Control is ScrollableControl)
                {
                    ((ScrollableControl)Control).Scroll -= new ScrollEventHandler(OnScroll);
                }

                IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
                if (host != null)
                {
                    _componentChangeSvc.ComponentRemoving -= new ComponentEventHandler(OnComponentRemoving);
                    _componentChangeSvc.ComponentRemoved -= new ComponentEventHandler(OnComponentRemoved);
                    _componentChangeSvc = null;
                }
            }

            base.Dispose(disposing);
        }

        /// <summary>
        ///  This is called by the parent when the ParentControlDesigner's
        ///  grid/snap settings have changed.  Unless the user has explicitly
        ///  set these values, this designer will just inherit the new ones
        ///  from the parent.
        /// </summary>
        private void DrawGridOfParentChanged(bool drawGrid)
        {
            if (_parentCanSetDrawGrid)
            {
                // If the parent sets us, then treat this as if no one set us
                bool getDefaultDrawGridTemp = _getDefaultDrawGrid;
                DrawGrid = drawGrid;
                _parentCanSetDrawGrid = true;
                _getDefaultDrawGrid = getDefaultDrawGridTemp;
            }
        }

        /// <summary>
        ///  This is called by the parent when the ParentControlDesigner's
        ///  grid/snap settings have changed.  Unless the user has explicitly
        ///  set these values, this designer will just inherit the new ones
        ///  from the parent.
        /// </summary>
        private void GridSizeOfParentChanged(Size gridSize)
        {
            if (_parentCanSetGridSize)
            {
                // If the parent sets us, then treat this as if no one set us
                bool getDefaultGridSizeTemp = _getDefaultGridSize;
                GridSize = gridSize;
                _parentCanSetGridSize = true;
                _getDefaultGridSize = getDefaultGridSizeTemp;
            }
        }

        /// <summary>
        ///  This is called by the parent when the ParentControlDesigner's
        ///  grid/snap settings have changed.  Unless the user has explicitly
        ///  set these values, this designer will just inherit the new ones
        ///  from the parent.
        /// </summary>
        private void GridSnapOfParentChanged(bool gridSnap)
        {
            if (_parentCanSetGridSnap)
            {
                // If the parent sets us, then treat this as if no one set us
                bool getDefaultGridSnapTemp = _getDefaultGridSnap;
                SnapToGrid = gridSnap;
                _parentCanSetGridSnap = true;
                _getDefaultGridSnap = getDefaultGridSnapTemp;
            }
        }

        /// <summary>
        ///  <para>[To be supplied.]</para>
        /// </summary>
        protected static void InvokeCreateTool(ParentControlDesigner toInvoke, ToolboxItem tool)
        {
            toInvoke.CreateTool(tool);
        }

        /// <summary>
        ///  Determines if the this designer can parent to the specified desinger --
        ///  generally this means if the control for this designer can parent the
        ///  given ControlDesigner's control.
        /// </summary>
        public virtual bool CanParent(ControlDesigner controlDesigner)
        {
            return CanParent(controlDesigner.Control);
        }

        /// <summary>
        ///  Determines if the this designer can parent to the specified desinger --
        ///  generally this means if the control for this designer can parent the
        ///  given ControlDesigner's control.
        /// </summary>
        public virtual bool CanParent(Control control)
        {
            return !control.Contains(Control);
        }

        /// <summary>
        ///  Creates the given tool in the center of the currently selected
        ///  control.  The default size for the tool is used.
        /// </summary>
        protected void CreateTool(ToolboxItem tool)
        {
            CreateToolCore(tool, 0, 0, 0, 0, false, false);
        }

        /// <summary>
        ///  Creates the given tool in the currently selected control at the
        ///  given position.  The default size for the tool is used.
        /// </summary>
        [CLSCompliant(false)]
        protected void CreateTool(ToolboxItem tool, Point location)
        {
            CreateToolCore(tool, location.X, location.Y, 0, 0, true, false);
        }

        /// <summary>
        ///  Creates the given tool in the currently selected control.  The
        ///  tool is created with the provided shape.
        /// </summary>
        [CLSCompliant(false)]
        protected void CreateTool(ToolboxItem tool, Rectangle bounds)
        {
            CreateToolCore(tool, bounds.X, bounds.Y, bounds.Width, bounds.Height, true, true);
        }

        /// <summary>
        ///  This is the worker method of all CreateTool methods.  It is the only one
        ///  that can be overridden.
        /// </summary>
        [CLSCompliant(false)]
        protected virtual IComponent[] CreateToolCore(ToolboxItem tool, int x, int y, int width, int height, bool hasLocation, bool hasSize)
        {
            IComponent[] comp = null;

            try
            {
                // We invoke the drag drop handler for this.  This implementation is shared between all designers that
                // create components.
                //
                comp = GetOleDragHandler().CreateTool(tool, Control, x, y, width, height, hasLocation, hasSize, _toolboxSnapDragDropEventArgs);
            }
            finally
            {
                //clear the toolboxSnap drag args so we won't provide bad information the next time around
                _toolboxSnapDragDropEventArgs = null;
            }

            return comp;
        }

        /// <summary>
        ///  Used when draggin a new tool rect on the designer's surface -
        ///  this will return some generic snaplines Allowing the rect to
        ///  snap to existing control edges on the surface.
        /// </summary>
        private SnapLine[] GenerateNewToolSnapLines(Rectangle r)
        {
            return new SnapLine[]
            {
                new SnapLine(SnapLineType.Left, r.Right),
                new SnapLine(SnapLineType.Right, r.Right),
                new SnapLine(SnapLineType.Bottom, r.Bottom),
                new SnapLine(SnapLineType.Top, r.Bottom)
            };
        }

        /// <summary>
        ///  Finds the array of components within the given rectangle.  This uses the rectangle to
        ///  find controls within our control, and then uses those controls to find the actual
        ///  components.  It returns an object array so the output can be directly fed into
        ///  the selection service.
        /// </summary>
        internal object[] GetComponentsInRect(Rectangle value, bool screenCoords, bool containRect)
        {
            ArrayList list = new ArrayList();
            Rectangle rect = screenCoords ? Control.RectangleToClient(value) : value;

            IContainer container = Component.Site.Container;

            Control control = Control;
            int controlCount = control.Controls.Count;

            for (int i = 0; i < controlCount; i++)
            {
                Control child = control.Controls[i];
                Rectangle bounds = child.Bounds;

                container = DesignerUtils.CheckForNestedContainer(container); // ...necessary to support SplitterPanel components

                if (child.Visible && ((containRect && rect.Contains(bounds)) || (!containRect && bounds.IntersectsWith(rect))) &&
                    child.Site != null && child.Site.Container == container)
                {
                    list.Add(child);
                }
            }

            return list.ToArray();
        }

        /// <summary>
        ///  Returns the control that represents the UI for the given component.
        /// </summary>
        protected Control GetControl(object component)
        {
            IComponent comp = component as IComponent;
            if (comp != null)
            {
                IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
                if (host != null)
                {
                    ControlDesigner cd = host.GetDesigner(comp) as ControlDesigner;
                    if (cd != null)
                    {
                        return cd.Control;
                    }
                }
            }

            return null;
        }

        /// <summary>
        /// Computes the next default location for a control. It tries to find a spot
        /// where no other controls are being obscured and the new control has 2 corners
        /// that don't have other controls under them.
        /// </summary>
        private Rectangle GetControlStackLocation(Rectangle centeredLocation)
        {
            Control parent = Control;

            int parentHeight = parent.ClientSize.Height;
            int parentWidth = parent.ClientSize.Width;

            if (centeredLocation.Bottom >= parentHeight ||
                centeredLocation.Right >= parentWidth)
            {
                centeredLocation.X = DefaultControlLocation.X;
                centeredLocation.Y = DefaultControlLocation.Y;
            }

            return centeredLocation;
        }

        /// <summary>
        ///  Retrieves the default dimensions for the given component class.
        /// </summary>
        private Size GetDefaultSize(IComponent component)
        {
            //Check to see if the control is AutoSized. VSWhidbey #416721
            PropertyDescriptor prop = TypeDescriptor.GetProperties(component)["AutoSize"];

            Size size;
            if (prop != null &&
                !(prop.Attributes.Contains(DesignerSerializationVisibilityAttribute.Hidden) ||
                  prop.Attributes.Contains(BrowsableAttribute.No)))
            {
                bool autoSize = (bool)prop.GetValue(component);
                if (autoSize)
                {
                    prop = TypeDescriptor.GetProperties(component)["PreferredSize"];
                    if (prop != null)
                    {
                        size = (Size)prop.GetValue(component);
                        if (size != Size.Empty)
                        {
                            return size;
                        }
                    }
                }
            }

            // attempt to get the size property of our component
            //
            prop = TypeDescriptor.GetProperties(component)["Size"];

            if (prop != null)
            {
                // first, let's see if we can get a valid size...
                size = (Size)prop.GetValue(component);

                // ...if not, we'll see if there's a default size attribute...
                if (size.Width <= 0 || size.Height <= 0)
                {
                    var sizeAttr = (DefaultValueAttribute)prop.Attributes[typeof(DefaultValueAttribute)];
                    if (sizeAttr != null)
                    {
                        return ((Size)sizeAttr.Value);
                    }
                }
                else
                {
                    return size;
                }
            }

            // Couldn't get the size or a def size attrib, returning 75,23...
            //
            return (new Size(75, 23));
        }

        /// <summary>
        ///  Returns a 'BodyGlyph' representing the bounds of this control.
        ///  The BodyGlyph is responsible for hit testing the related CtrlDes
        ///  and forwarding messages directly to the designer.
        /// </summary>
        protected override ControlBodyGlyph GetControlGlyph(GlyphSelectionType selectionType)
        {
            OnSetCursor();

            Rectangle controlRect = BehaviorService.ControlRectInAdornerWindow(Control);

            Control parent = Control.Parent;
            IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));

            if (parent != null && host != null && host.RootComponent != Component)
            {
                Rectangle parentRect = BehaviorService.ControlRectInAdornerWindow(parent);
                Rectangle nonClipRect = Rectangle.Intersect(parentRect, controlRect);

                // If we are not selected...

                if (selectionType == GlyphSelectionType.NotSelected)
                {
                    // If we are partially clipped (not fully clipped or wholly contained) by
                    // our parent,then adjust the bounds of the glyph to be the "visible" rect. VSWhidbey 530929
                    if (!nonClipRect.IsEmpty && !parentRect.Contains(controlRect))
                    {
                        return new ControlBodyGlyph(nonClipRect, Cursor.Current, Control, this);
                    }

                    // If we are completely clipped, then we do not want to be a drop target at all
                    else if (nonClipRect.IsEmpty)
                    {
                        return null;
                    }
                }
            }

            return new ControlBodyGlyph(controlRect, Cursor.Current, Control, this);
        }

        /// <summary>
        ///  Adds our ContainerSelectorGlyph to the selection glyphs.
        /// </summary>
        public override GlyphCollection GetGlyphs(GlyphSelectionType selectionType)
        {
            GlyphCollection glyphs = base.GetGlyphs(selectionType);

            //only add this glyph if our container is 1) moveable 2) not read-only
            //AND 3) it is selected .
            if ((SelectionRules & SelectionRules.Moveable) != 0 &&
              InheritanceAttribute != InheritanceAttribute.InheritedReadOnly && selectionType != GlyphSelectionType.NotSelected)
            {
                //get the adornerwindow-relative coords for the container control
                Point loc = BehaviorService.ControlToAdornerWindow((Control)Component);
                Rectangle translatedBounds = new Rectangle(loc, ((Control)Component).Size);

                int glyphOffset = (int)(DesignerUtils.CONTAINERGRABHANDLESIZE * .5);

                //if the control is too small for our ideal position...
                if (translatedBounds.Width < 2 * DesignerUtils.CONTAINERGRABHANDLESIZE)
                {
                    glyphOffset = -1 * glyphOffset;
                }

                ContainerSelectorBehavior behavior = new ContainerSelectorBehavior((Control)Component, Component.Site, true);
                ContainerSelectorGlyph containerSelectorGlyph = new ContainerSelectorGlyph(translatedBounds, DesignerUtils.CONTAINERGRABHANDLESIZE, glyphOffset, behavior);

                glyphs.Insert(0, containerSelectorGlyph);
            }

            return glyphs;
        }

        internal OleDragDropHandler GetOleDragHandler()
        {
            if (_oleDragDropHandler == null)
            {
                _oleDragDropHandler = new OleDragDropHandler(null, (IServiceProvider)GetService(typeof(IDesignerHost)), this);
            }

            return _oleDragDropHandler;
        }

        /// <summary>
        /// This method return the ParentControlDesigner of the parenting control,
        /// it is used for inheriting the grid size, snap to grid, and draw grid
        /// of parenting controls.
        /// </summary>
        private ParentControlDesigner GetParentControlDesignerOfParent()
        {
            Control parent = Control.Parent;
            IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
            if (parent != null && host != null)
            {
                return (host.GetDesigner(parent) as ParentControlDesigner);
            }

            return null;
        }

        /// <summary>
        ///  Updates the location of the control according to the GridSnap and Size.
        ///  This method simply calls GetUpdatedRect(), then ignores the width and
        ///  height
        /// </summary>
        private Rectangle GetAdjustedSnapLocation(Rectangle originalRect, Rectangle dragRect)
        {
            Rectangle adjustedRect = GetUpdatedRect(originalRect, dragRect, true);

            //now, preserve the width and height that was originally passed in
            adjustedRect.Width = dragRect.Width;
            adjustedRect.Height = dragRect.Height;

            //we need to keep in mind that if we adjust to the snap, that we could
            //have possibly moved the control's position outside of the display rect.
            //ex: groupbox's display rect.x = 3, but we might snap to 0.
            //so we need to check with the control's designer to make sure this
            //doesn't happen
            //
            Point minimumLocation = DefaultControlLocation;
            if (adjustedRect.X < minimumLocation.X)
            {
                adjustedRect.X = minimumLocation.X;
            }

            if (adjustedRect.Y < minimumLocation.Y)
            {
                adjustedRect.Y = minimumLocation.Y;
            }

            //here's our rect that has been snapped to grid
            return adjustedRect;
        }

        internal Point GetSnappedPoint(Point pt)
        {
            Rectangle r = GetUpdatedRect(Rectangle.Empty, new Rectangle(pt.X, pt.Y, 0, 0), false);
            return new Point(r.X, r.Y);
        }

        internal Rectangle GetSnappedRect(Rectangle originalRect, Rectangle dragRect, bool updateSize)
        {
            return GetUpdatedRect(originalRect, dragRect, updateSize);
        }

        /// <summary>
        ///  Updates the given rectangle, adjusting it for grid snaps as
        ///  needed.
        /// </summary>
        protected Rectangle GetUpdatedRect(Rectangle originalRect, Rectangle dragRect, bool updateSize)
        {
            Rectangle updatedRect;
            if (SnapToGrid)
            {
                Size gridSize = GridSize;
                Point halfGrid = new Point(gridSize.Width / 2, gridSize.Height / 2);

                updatedRect = dragRect;
                updatedRect.X = originalRect.X;
                updatedRect.Y = originalRect.Y;

                // decide to snap the start location to grid ...
                //
                if (dragRect.X != originalRect.X)
                {
                    updatedRect.X = (dragRect.X / gridSize.Width) * gridSize.Width;

                    // Snap the location to the grid point closest to the dragRect location
                    //
                    if (dragRect.X - updatedRect.X > halfGrid.X)
                    {
                        updatedRect.X += gridSize.Width;
                    }
                }

                if (dragRect.Y != originalRect.Y)
                {
                    updatedRect.Y = (dragRect.Y / gridSize.Height) * gridSize.Height;

                    // Snap the location to the grid point closest to the dragRect location
                    //
                    if (dragRect.Y - updatedRect.Y > halfGrid.Y)
                    {
                        updatedRect.Y += gridSize.Height;
                    }
                }

                // here, we need to calculate the new size depending on how we snap to the grid ...
                //
                if (updateSize)
                {
                    // update the width and the height
                    //
                    updatedRect.Width = ((dragRect.X + dragRect.Width) / gridSize.Width) * gridSize.Width - updatedRect.X;
                    updatedRect.Height = ((dragRect.Y + dragRect.Height) / gridSize.Height) * gridSize.Height - updatedRect.Y;

                    // ASURT 71552 <subhag> Added so that if the updated dimnesion is smaller than grid dimension then snap that dimension to
                    // the grid dimension
                    //
                    if (updatedRect.Width < gridSize.Width)
                        updatedRect.Width = gridSize.Width;
                    if (updatedRect.Height < gridSize.Height)
                        updatedRect.Height = gridSize.Height;
                }
            }
            else
            {
                updatedRect = dragRect;
            }

            return updatedRect;
        }

        /// <summary>
        ///  Initializes the designer with the given component.  The designer can
        ///  get the component's site and request services from it in this call.
        /// </summary>
        public override void Initialize(IComponent component)
        {
            base.Initialize(component);

            if (Control is ScrollableControl)
            {
                ((ScrollableControl)Control).Scroll += new ScrollEventHandler(OnScroll);
            }

            EnableDragDrop(true);

            // Hook load events.  At the end of load, we need to do a scan through all
            // of our child controls to see which ones are being inherited.  We
            // connect these up.
            //
            IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
            if (host != null)
            {
                _componentChangeSvc = (IComponentChangeService)host.GetService(typeof(IComponentChangeService));
                if (_componentChangeSvc != null)
                {
                    _componentChangeSvc.ComponentRemoving += new ComponentEventHandler(OnComponentRemoving);
                    _componentChangeSvc.ComponentRemoved += new ComponentEventHandler(OnComponentRemoved);
                }
            }

            // update the Status Command
            _statusCommandUI = new StatusCommandUI(component.Site);
        }

        /// <summary>
        /// </summary>
        public override void InitializeNewComponent(IDictionary defaultValues)
        {
            base.InitializeNewComponent(defaultValues);

            if (!AllowControlLasso)
            {
                return;
            }

            if (defaultValues != null && defaultValues["Size"] != null && defaultValues["Location"] != null && defaultValues["Parent"] != null)
            {
                //build our rect that may have covered some child controls
                Rectangle bounds = new Rectangle((Point)defaultValues["Location"], (Size)defaultValues["Size"]);

                //ask the parent to give us the comps within this rect
                IComponent parent = defaultValues["Parent"] as IComponent;
                if (parent == null)
                {
                    Debug.Fail("Couldn't get the parent instance from 'defaultValues'");
                    return;
                }

                IDesignerHost host = GetService(typeof(IDesignerHost)) as IDesignerHost;
                if (host == null)
                {
                    Debug.Fail("Failed to IDesignerHost");
                    return;
                }

                ParentControlDesigner parentDesigner = host.GetDesigner(parent) as ParentControlDesigner;
                if (parentDesigner == null)
                {
                    Debug.Fail("Could not get ParentControlDesigner for " + parent);
                    return;
                }

                object[] comps = parentDesigner.GetComponentsInRect(bounds, true, true /* component should be fully contained*/);

                if (comps == null || comps.Length == 0)
                {
                    //no comps to re-parent
                    return;
                }

                ArrayList selectedControls = new ArrayList(comps);

                //remove this
                if (selectedControls.Contains(Control))
                {
                    selectedControls.Remove(Control);
                }

                //Finally, we have identified that we need to re-parent the lasso'd controls.
                //We will start a designer transaction, send some changing notifications
                //and swap parents...
                //
                ReParentControls(Control, selectedControls, string.Format(SR.ParentControlDesignerLassoShortcutRedo, Control.Site.Name), host);
            }
        }

        /// <summary>
        ///  Checks if an option has the default value
        /// </summary>
        private bool IsOptionDefault(string optionName, object value)
        {
            IDesignerOptionService optSvc = (IDesignerOptionService)GetService(typeof(IDesignerOptionService));

            object defaultValue = null;

            if (optSvc == null)
            {
                if (optionName.Equals("ShowGrid"))
                {
                    defaultValue = true;
                }
                else if (optionName.Equals("SnapToGrid"))
                {
                    defaultValue = true;
                }
                else if (optionName.Equals("GridSize"))
                {
                    defaultValue = new Size(8, 8);
                }
            }
            else
            {
                defaultValue = DesignerUtils.GetOptionValue(ServiceProvider, optionName);
            }

            if (defaultValue != null)
            {
                return defaultValue.Equals(value);
            }
            else
            {
                return value == null;
            }
        }

        /// <summary>
        /// </summary>
        private void OnComponentRemoving(object sender, ComponentEventArgs e)
        {
            Control comp = e.Component as Control;
            if (comp != null && comp.Parent != null && comp.Parent == Control)
            {
                _pendingRemoveControl = comp;
                //We suspend Component Changing Events for bulk operations to avoid unnecessary serialization\deserialization for undo
                // see bug 488115
                if (_suspendChanging == 0)
                {
                    _componentChangeSvc.OnComponentChanging(Control, TypeDescriptor.GetProperties(Control)["Controls"]);
                }
            }
        }

        /// <summary>
        /// </summary>
        private void OnComponentRemoved(object sender, ComponentEventArgs e)
        {
            if (e.Component == _pendingRemoveControl)
            {
                _pendingRemoveControl = null;
                _componentChangeSvc.OnComponentChanged(Control, TypeDescriptor.GetProperties(Control)["Controls"], null, null);
            }
        }

        internal void SuspendChangingEvents()
        {
            _suspendChanging++;
            Debug.Assert(_suspendChanging > 0, "Unbalanced SuspendChangingEvents\\ResumeChangingEvents");
        }

        internal void ResumeChangingEvents()
        {
            _suspendChanging--;
            Debug.Assert(_suspendChanging >= 0, "Unbalanced SuspendChangingEvents\\ResumeChangingEvents");
        }

        internal void ForceComponentChanging()
        {
            _componentChangeSvc.OnComponentChanging(Control, TypeDescriptor.GetProperties(Control)["Controls"]);
        }

        /// <summary>
        ///  Called in order to cleanup a drag and drop operation.  Here we
        ///  cleanup any operations that were performed at the beginning of a drag.
        /// </summary>
        protected override void OnDragComplete(DragEventArgs de)
        {
            DropSourceBehavior.BehaviorDataObject data = de.Data as DropSourceBehavior.BehaviorDataObject;
            if (data != null)
            {
                data.CleanupDrag();
            }
        }

        /// <summary>
        ///  Called in response to a drag drop for OLE drag and drop.  Here we
        ///  drop a toolbox component on our parent control.
        /// </summary>
        // Standard 'catch all - rethrow critical' exception pattern
        protected override void OnDragDrop(DragEventArgs de)
        {
            //if needed, cache extra info about the behavior dragdrop event
            //ex: snapline and offset info
            if (de is ToolboxSnapDragDropEventArgs)
            {
                _toolboxSnapDragDropEventArgs = de as ToolboxSnapDragDropEventArgs;
            }

            DropSourceBehavior.BehaviorDataObject data = de.Data as DropSourceBehavior.BehaviorDataObject;
            if (data != null)
            {
                data.Target = Component;
                data.EndDragDrop(AllowSetChildIndexOnDrop);

                OnDragComplete(de);
            }

            // this should only occur when D&Ding between component trays on two separate forms.
            else if (_mouseDragTool == null && data == null)
            {
                OleDragDropHandler ddh = GetOleDragHandler();
                if (ddh != null)
                {
                    IOleDragClient target = ddh.Destination;
                    if (target != null && target.Component != null && target.Component.Site != null)
                    {
                        IContainer container = target.Component.Site.Container;
                        if (container != null)
                        {
                            object[] dragComps = ddh.GetDraggingObjects(de);
                            for (int i = 0; i < dragComps.Length; i++)
                            {
                                IComponent comp = dragComps[i] as IComponent;
                                container.Add(comp);
                            }
                        }
                    }
                }
            }

            if (_mouseDragTool != null)
            {
                IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
                if (host != null)
                {
                    host.Activate();
                }

                try
                {
                    //There may be a wizard displaying as a result of CreateTool.
                    //we do not want the behavior service thinking there he is dragging while this wizard is up
                    //it causes the cursor to constantly flicker to the toolbox cursor.
                    if (BehaviorService != null)
                    {
                        //this will cause the BehSvc to return from 'drag mode'
                        //
                        BehaviorService.EndDragNotification();
                    }

                    CreateTool(_mouseDragTool, new Point(de.X, de.Y));
                }
                catch (Exception e)
                {
                    if (ClientUtils.IsCriticalException(e))
                    {
                        throw;
                    }
                    else
                    {
                        DisplayError(e);
                    }
                }

                _mouseDragTool = null;
                return;
            }
        }

        /// <summary>
        ///  Called in response to a drag enter for OLE drag and drop.
        /// </summary>
        protected override void OnDragEnter(DragEventArgs de)
        {
            // Are we are new target, meaning is the drop target different than the drag source
            bool newTarget = false;

            DropSourceBehavior.BehaviorDataObject behDataObject = null;
            DropSourceBehavior.BehaviorDataObject data = de.Data as DropSourceBehavior.BehaviorDataObject;
            if (data != null)
            {
                behDataObject = data;
                behDataObject.Target = Component;
                de.Effect = (Control.ModifierKeys == Keys.Control) ? DragDropEffects.Copy : DragDropEffects.Move;
                newTarget = !(data.Source.Equals(Component)); //Check if we are moving to a new target
            }

            // If tab order UI is being shown, then don't allow anything to be
            // dropped here.
            //
            IMenuCommandService ms = (IMenuCommandService)GetService(typeof(IMenuCommandService));
            if (ms != null)
            {
                MenuCommand tabCommand = ms.FindCommand(StandardCommands.TabOrder);
                if (tabCommand != null && tabCommand.Checked)
                {
                    de.Effect = DragDropEffects.None;
                    return;
                }
            }

            // Get the objects that are being dragged
            //
            object[] dragComps;
            if (behDataObject != null && behDataObject.DragComponents != null)
            {
                dragComps = new object[behDataObject.DragComponents.Count];
                behDataObject.DragComponents.CopyTo(dragComps, 0);
            }
            else
            {
                OleDragDropHandler ddh = GetOleDragHandler();
                dragComps = ddh.GetDraggingObjects(de);
            }

            Control draggedControl = null;

            IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
            if (host != null)
            {
                DocumentDesigner parentDesigner = host.GetDesigner(host.RootComponent) as DocumentDesigner;
                if (parentDesigner != null)
                {
                    if (!parentDesigner.CanDropComponents(de))
                    {
                        de.Effect = DragDropEffects.None;
                        return;
                    }
                }
            }

            if (dragComps != null)
            {
                if (data == null)
                {
                    // This should only be true, when moving a component from the Tray,
                    // to a new form. In this case, we are moving targets.
                    newTarget = true;
                }

                for (int i = 0; i < dragComps.Length; i++)
                {
                    IComponent comp = dragComps[i] as IComponent;
                    if (host == null || comp == null)
                    {
                        continue;
                    }

                    if (newTarget)
                    {
                        // If we are dropping on a new target, then check to see if any of the components
                        // are inherited. If so, don't allow them to be moved.
                        InheritanceAttribute attr = (InheritanceAttribute)TypeDescriptor.GetAttributes(comp)[typeof(InheritanceAttribute)];
                        if (attr != null && !attr.Equals(InheritanceAttribute.NotInherited) && !attr.Equals(InheritanceAttribute.InheritedReadOnly))
                        {
                            de.Effect = DragDropEffects.None;
                            return;
                        }
                    }

                    // try go get the control for the thing that's being dragged
                    //
                    object draggedDesigner = host.GetDesigner(comp);
                    if (draggedDesigner is IOleDragClient)
                    {
                        draggedControl = ((IOleDragClient)this).GetControlForComponent(dragComps[i]);
                    }

                    Control ctrl = dragComps[i] as Control;
                    if (draggedControl == null && ctrl != null)
                    {
                        draggedControl = ctrl;
                    }

                    // oh well, it's not a control so it doesn't matter
                    //
                    if (draggedControl == null)
                    {
                        continue;
                    }

                    // If we're inheriting from a private container, we can't modify the controls collection.
                    // So drag-drop is only allowed within the container i.e. the dragged controls must already
                    // be parented to this container.
                    //
                    if (InheritanceAttribute == InheritanceAttribute.InheritedReadOnly && draggedControl.Parent != Control)
                    {
                        de.Effect = DragDropEffects.None;
                        return;
                    }

                    //Can the component be dropped on this parent? I.e. you can only
                    //drop a tab page on a tab control, not say a panel
                    if (!((IOleDragClient)this).IsDropOk(comp))
                    {
                        de.Effect = DragDropEffects.None;
                        return;
                    }
                }

                // should only occur when dragging and dropping
                // from the component tray.
                if (data == null)
                {
                    PerformDragEnter(de, host);
                }
            }

            if (_toolboxService == null)
            {
                _toolboxService = (IToolboxService)GetService(typeof(IToolboxService));
            }

            // Only assume the items came from the ToolBox if dragComps == null
            //
            if (_toolboxService != null && dragComps == null)
            {
                _mouseDragTool = _toolboxService.DeserializeToolboxItem(de.Data, host);

                //If we have a valid toolbox item to drag and
                //we haven't pushed our behaivor, then do so now...
                if ((_mouseDragTool != null) && BehaviorService != null && BehaviorService.UseSnapLines)
                {
                    //demand create
                    if (_toolboxItemSnapLineBehavior == null)
                    {
                        _toolboxItemSnapLineBehavior = new ToolboxItemSnapLineBehavior(Component.Site, BehaviorService, this, AllowGenericDragBox);
                    }

                    if (!_toolboxItemSnapLineBehavior.IsPushed)
                    {
                        BehaviorService.PushBehavior(_toolboxItemSnapLineBehavior);
                        _toolboxItemSnapLineBehavior.IsPushed = true;
                    }
                }

                if (_mouseDragTool != null)
                {
                    PerformDragEnter(de, host);
                }

                // This must be called last. Tell the behavior that we are beginning a drag.
                // Yeah, this is OnDragEnter, but to the behavior this is as if we are starting a drag.
                // VSWhidbey 487816
                if (_toolboxItemSnapLineBehavior != null)
                {
                    _toolboxItemSnapLineBehavior.OnBeginDrag();
                }
            }
        }

        private void PerformDragEnter(DragEventArgs de, IDesignerHost host)
        {
            if (host != null)
            {
                host.Activate();
            }

            Debug.Assert(0 != (de.AllowedEffect & (DragDropEffects.Move | DragDropEffects.Copy)), "DragDropEffect.Move | .Copy isn't allowed?");
            if ((de.AllowedEffect & DragDropEffects.Move) != 0)
            {
                de.Effect = DragDropEffects.Move;
            }
            else
            {
                de.Effect = DragDropEffects.Copy;
            }

            // If we're inheriting from a private container, we can't modify the controls collection.
            if (InheritanceAttribute == InheritanceAttribute.InheritedReadOnly)
            {
                de.Effect = DragDropEffects.None;
                return;
            }

            // Also, select this parent control to indicate it will be the drop target.
            //
            ISelectionService sel = (ISelectionService)GetService(typeof(ISelectionService));
            if (sel != null)
            {
                sel.SetSelectedComponents(new object[] { Component }, SelectionTypes.Replace);
            }
        }

        /// <summary>
        ///  Called when a drag-drop operation leaves the control designer view
        /// </summary>
        protected override void OnDragLeave(EventArgs e)
        {
            //if we're dragging around our generic snapline box - let's remove it here
            if (_toolboxItemSnapLineBehavior != null && _toolboxItemSnapLineBehavior.IsPushed)
            {
                BehaviorService.PopBehavior(_toolboxItemSnapLineBehavior);
                _toolboxItemSnapLineBehavior.IsPushed = false;
            }

            _mouseDragTool = null;
        }

        /// <summary>
        ///  Called when a drag drop object is dragged over the control designer view
        /// </summary>
        protected override void OnDragOver(DragEventArgs de)
        {
            DropSourceBehavior.BehaviorDataObject data = de.Data as DropSourceBehavior.BehaviorDataObject;
            if (data != null)
            {
                data.Target = Component;
                de.Effect = (Control.ModifierKeys == Keys.Control) ? DragDropEffects.Copy : DragDropEffects.Move;
            }

            Debug.WriteLineIf(CompModSwitches.DragDrop.TraceInfo, "\tParentControlDesigner.OnDragOver: " + de.ToString());

            // If tab order UI is being shown, then don't allow anything to be
            // dropped here.
            //
            IMenuCommandService ms = (IMenuCommandService)GetService(typeof(IMenuCommandService));
            if (ms != null)
            {
                MenuCommand tabCommand = ms.FindCommand(StandardCommands.TabOrder);
                Debug.Assert(tabCommand != null, "Missing tab order command");
                if (tabCommand != null && tabCommand.Checked)
                {
                    de.Effect = DragDropEffects.None;
                    return;
                }
            }

            IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
            if (host != null)
            {
                DocumentDesigner parentDesigner = host.GetDesigner(host.RootComponent) as DocumentDesigner;
                if (parentDesigner != null)
                {
                    if (!parentDesigner.CanDropComponents(de))
                    {
                        de.Effect = DragDropEffects.None;
                        return;
                    }
                }
            }

            if (_mouseDragTool != null)
            {
                Debug.Assert(0 != (de.AllowedEffect & DragDropEffects.Copy), "DragDropEffect.Move isn't allowed?");
                de.Effect = DragDropEffects.Copy;
                return;
            }

            Debug.WriteLineIf(CompModSwitches.DragDrop.TraceInfo, "\tParentControlDesigner.OnDragOver: " + de.ToString());
        }

        /// <summary>
        ///  Called in response to the left mouse button being pressed on a
        ///  component.  The designer overrides this to provide a
        ///  "lasso" selection for components within the control.
        /// </summary>

        private static int FrameWidth(FrameStyle style)
        {
            return (style == FrameStyle.Dashed ? 1 : 2);
        }

        protected override void OnMouseDragBegin(int x, int y)
        {
            Control control = Control;

            // Figure out the drag frame style.  We use a dotted line for selecting
            // a component group, and a thick line for creating a new component.
            // If we are a privately inherited component, then we always use the
            // selection frame because we can't add components.
            //
            if (!InheritanceAttribute.Equals(InheritanceAttribute.InheritedReadOnly))
            {
                if (_toolboxService == null)
                {
                    _toolboxService = (IToolboxService)GetService(typeof(IToolboxService));
                }

                if (_toolboxService != null)
                {
                    _mouseDragTool = _toolboxService.GetSelectedToolboxItem((IDesignerHost)GetService(typeof(IDesignerHost)));
                }
            }

            // Set the mouse capture and clipping to this control.
            //
            control.Capture = true;

            RECT winRect = default;
            User32.GetWindowRect(control.Handle, ref winRect);
            Rectangle.FromLTRB(winRect.left, winRect.top, winRect.right, winRect.bottom);

            _mouseDragFrame = (_mouseDragTool == null) ? FrameStyle.Dashed : FrameStyle.Thick;

            // Setting this non-null signifies that we are dragging with the
            // mouse.
            //
            _mouseDragBase = new Point(x, y);

            // Select the given object.
            //
            ISelectionService selsvc = (ISelectionService)GetService(typeof(ISelectionService));

            if (selsvc != null)
            {
                selsvc.SetSelectedComponents(new object[] { Component }, SelectionTypes.Primary);
            }

            // Get the event handler service.  We push a handler to handle the escape
            // key.
            //
            IEventHandlerService eventSvc = (IEventHandlerService)GetService(typeof(IEventHandlerService));
            //UNDONE: Behavior Work
            //Debug.Assert(escapeHandler == null, "Why is there already an escape handler?");

            if (eventSvc != null && _escapeHandler == null)
            {
                _escapeHandler = new EscapeHandler(this);
                eventSvc.PushHandler(_escapeHandler);
            }

            //Need this since we are drawing the frame in the adorner window
            _adornerWindowToScreenOffset = BehaviorService.AdornerWindowToScreen();
        }

        /// <summary>
        ///  Called at the end of a drag operation.  This either commits or rolls back the
        ///  drag.
        /// </summary>
        // Standard 'catch all - rethrow critical' exception pattern
        protected override void OnMouseDragEnd(bool cancel)
        {
            // Do nothing if we're not dragging anything around
            //
            if (_mouseDragBase == InvalidPoint)
            {
                Debug.Assert(_graphics == null);
                // make sure we force the drag end
                base.OnMouseDragEnd(cancel);
                return;
            }

            // Important to null these out here, just in case we throw an exception
            //
            Rectangle offset = _mouseDragOffset;
            ToolboxItem tool = _mouseDragTool;
            Point baseVar = _mouseDragBase;

            _mouseDragOffset = Rectangle.Empty;
            _mouseDragBase = InvalidPoint;
            _mouseDragTool = null;

            Control.Capture = false;
            Cursor.Clip = Rectangle.Empty;

            // Clear out the drag frame.
            if (!offset.IsEmpty && _graphics != null)
            {
                Rectangle frameRect = new Rectangle(offset.X - _adornerWindowToScreenOffset.X,
                                                     offset.Y - _adornerWindowToScreenOffset.Y,
                                                     offset.Width, offset.Height);

                int frameWidth = FrameWidth(_mouseDragFrame);
                _graphics.SetClip(frameRect);

                using (Region newRegion = new Region(frameRect))
                {
                    newRegion.Exclude(Rectangle.Inflate(frameRect, -frameWidth, -frameWidth));
                    BehaviorService.Invalidate(newRegion);
                }

                _graphics.ResetClip();
            }

            if (_graphics != null)
            {
                _graphics.Dispose();
                _graphics = null;
            }

            //destroy the snapline engine (if we used it)
            if (_dragManager != null)
            {
                _dragManager.OnMouseUp();
                _dragManager = null;
            }

            // Get the event handler service and pop our handler.
            //
            IEventHandlerService eventSvc = (IEventHandlerService)GetService(typeof(IEventHandlerService));
            if (eventSvc != null && _escapeHandler != null)
            {
                eventSvc.PopHandler(_escapeHandler);
                _escapeHandler = null;
            }

            // Set Status Information - but only if the offset is not empty, if it is, the user didn't move the mouse
            if (_statusCommandUI != null && !offset.IsEmpty)
            {
                Point location = new(baseVar.X, baseVar.Y);
                User32.MapWindowPoints(IntPtr.Zero, Control.Handle, ref location, 1);
                if (_statusCommandUI != null)
                {
                    _statusCommandUI.SetStatusInformation(new Rectangle(location.X, location.Y, offset.Width, offset.Height));
                }
            }

            // Quit now if we don't have an offset rect.  This indicates that
            // the user didn't move the mouse.
            //
            if (offset.IsEmpty && !cancel)
            {
                // BUT, if we have a selected tool, create it here
                if (tool != null)
                {
                    try
                    {
                        CreateTool(tool, baseVar);
                        if (_toolboxService != null)
                        {
                            _toolboxService.SelectedToolboxItemUsed();
                        }
                    }
                    catch (Exception e)
                    {
                        if (ClientUtils.IsCriticalException(e))
                        {
                            throw;
                        }
                        else
                        {
                            DisplayError(e);
                        }
                    }
                }

                return;
            }

            // Don't do anything else if the user wants to cancel.
            //
            if (cancel)
            {
                return;
            }

            // If we have a valid toolbox item, create the tool
            //
            if (tool != null)
            {
                try
                {
                    //avoid allowing the user creating a 1x1 sized control (for ex)
                    //by enforcing a min size 2xMinDragSize...
                    Size minControlSize = new Size(DesignerUtils.MinDragSize.Width * 2, DesignerUtils.MinDragSize.Height * 2);
                    if (offset.Width < minControlSize.Width)
                    {
                        offset.Width = minControlSize.Width;
                    }

                    if (offset.Height < minControlSize.Height)
                    {
                        offset.Height = minControlSize.Height;
                    }

                    CreateTool(tool, offset);
                    if (_toolboxService != null)
                    {
                        _toolboxService.SelectedToolboxItemUsed();
                    }
                }
                catch (Exception e)
                {
                    if (ClientUtils.IsCriticalException(e))
                    {
                        throw;
                    }
                    else
                    {
                        DisplayError(e);
                    }
                }
            }
            else
            {
                // Now find the set of controls within this offset and
                // select them.
                //
                var selSvc = (ISelectionService)GetService(typeof(ISelectionService));
                if (selSvc != null)
                {
                    object[] selection = GetComponentsInRect(offset, true, false /*component does not need to be fully contained*/);
                    if (selection.Length > 0)
                    {
                        selSvc.SetSelectedComponents(selection);
                    }
                }
            }
        }

        /// <summary>
        ///  Called for each movement of the mouse.  This will check to see if a drag operation
        ///  is in progress.  If so, it will pass the updated drag dimensions on to the selection
        ///  UI service.
        /// </summary>
        protected override void OnMouseDragMove(int x, int y)
        {
            //if we puhsed a snapline behavior during a drag operation - make sure we have popped it
            //if we're now receiving mouse move messages.
            if (_toolboxItemSnapLineBehavior != null && _toolboxItemSnapLineBehavior.IsPushed)
            {
                BehaviorService.PopBehavior(_toolboxItemSnapLineBehavior);
                _toolboxItemSnapLineBehavior.IsPushed = false;
            }

            // if we're doing an OLE drag, do nothing, or
            // Do nothing if we haven't initiated a drag
            //
            if (GetOleDragHandler().Dragging || _mouseDragBase == InvalidPoint)
            {
                return;
            }

            Rectangle oldFrameRect = _mouseDragOffset;

            // Calculate the new offset.
            //
            _mouseDragOffset.X = _mouseDragBase.X;
            _mouseDragOffset.Y = _mouseDragBase.Y;
            _mouseDragOffset.Width = x - _mouseDragBase.X;
            _mouseDragOffset.Height = y - _mouseDragBase.Y;

            //if we have a valid dragtool - then we'll spin up our snapline engine
            //and use it when the user drags a reversible rect -- but only if the
            //parentcontroldesigner wants to allow Snaplines

            if (_dragManager == null && ParticipatesWithSnapLines && _mouseDragTool != null && BehaviorService.UseSnapLines)
            {
                _dragManager = new DragAssistanceManager(Component.Site);
            }

            if (_dragManager != null)
            {
                //here, we build up our new rect (offset by the adorner window)
                //and ask the snapline engine to adjust our coords
                Rectangle r = new Rectangle(_mouseDragBase.X - _adornerWindowToScreenOffset.X,
                                       _mouseDragBase.Y - _adornerWindowToScreenOffset.Y,
                                       x - _mouseDragBase.X, y - _mouseDragBase.Y);
                Point offset = _dragManager.OnMouseMove(r, GenerateNewToolSnapLines(r));
                _mouseDragOffset.Width += offset.X;
                _mouseDragOffset.Height += offset.Y;
                _dragManager.RenderSnapLinesInternal();
            }

            if (_mouseDragOffset.Width < 0)
            {
                _mouseDragOffset.X += _mouseDragOffset.Width;
                _mouseDragOffset.Width = -_mouseDragOffset.Width;
            }

            if (_mouseDragOffset.Height < 0)
            {
                _mouseDragOffset.Y += _mouseDragOffset.Height;
                _mouseDragOffset.Height = -_mouseDragOffset.Height;
            }

            // If we're dragging out a new component, update the drag rectangle
            // to use snaps, if they're set.
            //
            if (_mouseDragTool != null)
            {
                // To snap properly, we must snap in client coordinates.  So, convert, snap
                // and re-convert.
                //
                _mouseDragOffset = Control.RectangleToClient(_mouseDragOffset);
                _mouseDragOffset = GetUpdatedRect(Rectangle.Empty, _mouseDragOffset, true);
                _mouseDragOffset = Control.RectangleToScreen(_mouseDragOffset);
            }

            if (_graphics == null)
            {
                _graphics = BehaviorService.AdornerWindowGraphics;
            }

            // And draw the new drag frame
            if (!_mouseDragOffset.IsEmpty && _graphics != null)
            {
                Rectangle frameRect = new Rectangle(_mouseDragOffset.X - _adornerWindowToScreenOffset.X,
                                                     _mouseDragOffset.Y - _adornerWindowToScreenOffset.Y,
                                                     _mouseDragOffset.Width, _mouseDragOffset.Height);

                //graphics.SetClip(frameRect);

                //draw the new border
                using (Region newRegion = new Region(frameRect))
                {
                    int frameWidth = FrameWidth(_mouseDragFrame);
                    newRegion.Exclude(Rectangle.Inflate(frameRect, -frameWidth, -frameWidth));

                    //erase the right part of the old frame
                    if (!oldFrameRect.IsEmpty)
                    {
                        oldFrameRect.X -= _adornerWindowToScreenOffset.X;
                        oldFrameRect.Y -= _adornerWindowToScreenOffset.Y;

                        //Let's not try and be smart about invalidating just the part of the old frame
                        //that's not part of the new frame. When I did that (using the commented out
                        //lines below), you could get serious screen artifacts when dragging fast. I think
                        //this might be because of some bad region forming (bad region, bad), or some missing
                        //updates.

                        // Since we invalidate and then immediately redraw, the flicker should be minimal.
                        using (Region oldRegion = new Region(oldFrameRect))
                        {
                            oldRegion.Exclude(Rectangle.Inflate(oldFrameRect, -frameWidth, -frameWidth));
                            //oldRegion.Union(newRegion);
                            //oldRegion.Exclude(newRegion);
                            BehaviorService.Invalidate(oldRegion);
                        }
                    }

                    DesignerUtils.DrawFrame(_graphics, newRegion, _mouseDragFrame, Control.BackColor);
                }

                //graphics.ResetClip();
            }

            // We are looking at the primary control
            if (_statusCommandUI != null)
            {
                Point offset = new(_mouseDragOffset.X, _mouseDragOffset.Y);
                User32.MapWindowPoints(IntPtr.Zero, Control.Handle, ref offset, 1);
                if (_statusCommandUI != null)
                {
                    _statusCommandUI.SetStatusInformation(new Rectangle(offset.X, offset.Y, _mouseDragOffset.Width, _mouseDragOffset.Height));
                }
            }
        }

        /// <summary>
        ///  Called after our component has finished painting.  Here we draw our grid surface
        /// </summary>
        protected override void OnPaintAdornments(PaintEventArgs pe)
        {
            if (DrawGrid)
            {
                Control control = Control;

                Rectangle displayRect = Control.DisplayRectangle;
                Rectangle clientRect = Control.ClientRectangle;

                Rectangle paintRect = new(Math.Min(displayRect.X, clientRect.X),
                                          Math.Min(displayRect.Y, clientRect.Y),
                                          Math.Max(displayRect.Width, clientRect.Width),
                                          Math.Max(displayRect.Height, clientRect.Height));

                float xlateX = paintRect.X;
                float xlateY = paintRect.Y;
                pe.Graphics.TranslateTransform(xlateX, xlateY);
                paintRect.X = paintRect.Y = 0;
                paintRect.Width++; // gpr: FillRectangle with a TextureBrush comes up one pixel short
                paintRect.Height++;
                ControlPaint.DrawGrid(pe.Graphics, paintRect, GridSize, control.BackColor);
                pe.Graphics.TranslateTransform(-xlateX, -xlateY);
            }

            base.OnPaintAdornments(pe);
        }

        /// <summary>
        ///  When the control is scrolled, we want to invalidate areas previously covered by glyphs.
        /// </summary>
        private void OnScroll(object sender, ScrollEventArgs se)
        {
            BehaviorService.Invalidate(BehaviorService.ControlRectInAdornerWindow(Control));
        }

        /// <summary>
        ///  Called each time the cursor needs to be set.  The ParentControlDesigner behavior here
        ///  will set the cursor to one of three things:
        ///  1.  If the toolbox service has a tool selected, it will allow the toolbox service to
        ///  set the cursor.
        ///  2.  The arrow will be set.  Parent controls allow dragging within their interior.
        /// </summary>
        protected override void OnSetCursor()
        {
            if (_toolboxService == null)
            {
                _toolboxService = (IToolboxService)GetService(typeof(IToolboxService));
            }

            try
            {
                if (_toolboxService == null || !_toolboxService.SetCursor() || InheritanceAttribute.Equals(InheritanceAttribute.InheritedReadOnly))
                {
                    Cursor.Current = Cursors.Default;
                }
            }

            catch
            {  // VSWhidbey 502536
                Cursor.Current = Cursors.Default;
            }
        }

        /// <summary>
        ///  Allows a designer to filter the set of properties
        ///  the component it is designing will expose through the
        ///  TypeDescriptor object.  This method is called
        ///  immediately before its corresponding "Post" method.
        ///  If you are overriding this method you should call
        ///  the base implementation before you perform your own
        ///  filtering.
        /// </summary>
        protected override void PreFilterProperties(IDictionary properties)
        {
            base.PreFilterProperties(properties);

            // add the "GridSize, SnapToGrid and DrawGrid" property  from the property grid
            // iff the LayoutOption.SnapToGrid Attribute is Set...

            if (!DefaultUseSnapLines)
            {
                properties["DrawGrid"] = TypeDescriptor.CreateProperty(typeof(ParentControlDesigner), "DrawGrid", typeof(bool),
                                                              BrowsableAttribute.Yes,
                                                              DesignOnlyAttribute.Yes,
                                                              new SRDescriptionAttribute("ParentControlDesignerDrawGridDescr"),
                                                              CategoryAttribute.Design);

                properties["SnapToGrid"] = TypeDescriptor.CreateProperty(typeof(ParentControlDesigner), "SnapToGrid", typeof(bool),
                                                                BrowsableAttribute.Yes,
                                                                DesignOnlyAttribute.Yes,
                                                                new SRDescriptionAttribute("ParentControlDesignerSnapToGridDescr"),
                                                                CategoryAttribute.Design);

                properties["GridSize"] = TypeDescriptor.CreateProperty(typeof(ParentControlDesigner), "GridSize", typeof(Size),
                                                              BrowsableAttribute.Yes,
                                                              new SRDescriptionAttribute(SR.ParentControlDesignerGridSizeDescr),
                                                              DesignOnlyAttribute.Yes,
                                                              CategoryAttribute.Design);
            }

            // We need this one always to make sure that Format -> Horizontal/Vertical Spacing works.
            properties["CurrentGridSize"] = TypeDescriptor.CreateProperty(typeof(ParentControlDesigner), "CurrentGridSize", typeof(Size),
                                                             BrowsableAttribute.No,
                                                             DesignerSerializationVisibilityAttribute.Hidden);
        }

        /// <summary>
        ///  Called after we have decided that the user has drawn a control (with a toolbox item picked) onto the designer
        ///  surface and intends to have the controls beneath the new one re-parented.  Example: A user selects the 'Panel'
        ///  Control in the toolbox then drags a rectangle around four Buttons on the Form's surface.  We'll attempt
        ///  to re-parent those four Buttons to the newly created Panel.
        /// </summary>
        private void ReParentControls(Control newParent, ArrayList controls, string transactionName, IDesignerHost host)
        {
            using (DesignerTransaction dt = host.CreateTransaction(transactionName))
            {
                IComponentChangeService changeSvc = GetService(typeof(IComponentChangeService)) as IComponentChangeService;

                PropertyDescriptor controlsProp = TypeDescriptor.GetProperties(newParent)["Controls"];
                PropertyDescriptor locationProp = TypeDescriptor.GetProperties(newParent)["Location"];

                //get the location of our parent - so we can correctly offset the new lasso'd controls
                //once they are re-parented
                Point parentLoc = Point.Empty;
                if (locationProp != null)
                {
                    parentLoc = (Point)locationProp.GetValue(newParent);
                }

                if (changeSvc != null)
                {
                    changeSvc.OnComponentChanging(newParent, controlsProp);
                }

                //enumerate the lasso'd controls relocate and re-parent...
                //
                foreach (object comp in controls)
                {
                    Control control = comp as Control;
                    Control oldParent = control.Parent;
                    Point controlLoc = Point.Empty;

                    //do not want to reparent any control that is inherited readonly
                    InheritanceAttribute inheritanceAttribute = (InheritanceAttribute)TypeDescriptor.GetAttributes(control)[typeof(InheritanceAttribute)];
                    if (inheritanceAttribute != null && inheritanceAttribute == InheritanceAttribute.InheritedReadOnly)
                    {
                        continue;
                    }

                    //get the current location of the control
                    PropertyDescriptor locProp = TypeDescriptor.GetProperties(control)["Location"];
                    if (locProp != null)
                    {
                        controlLoc = (Point)locProp.GetValue(control);
                    }

                    //fire comp changing on parent and control
                    if (oldParent != null)
                    {
                        if (changeSvc != null)
                        {
                            changeSvc.OnComponentChanging(oldParent, controlsProp);
                        }

                        //remove control from the old parent
                        oldParent.Controls.Remove(control);
                    }

                    //finally add & relocate the control with the new parent
                    newParent.Controls.Add(control);

                    Point newLoc = Point.Empty;

                    //this condition will determine which way we need to 'offset' our control location
                    //based on whether we are moving controls into a child or bringing them out to
                    //a parent
                    if (oldParent != null)
                    {
                        if (oldParent.Controls.Contains(newParent))
                        {
                            newLoc = new Point(controlLoc.X - parentLoc.X, controlLoc.Y - parentLoc.Y);
                        }
                        else
                        {
                            Point oldParentLoc = (Point)locProp.GetValue(oldParent);
                            newLoc = new Point(controlLoc.X + oldParentLoc.X, controlLoc.Y + oldParentLoc.Y);
                        }
                    }

                    locProp.SetValue(control, newLoc);

                    //fire our comp changed events
                    if (changeSvc != null && oldParent != null)
                    {
                        changeSvc.OnComponentChanged(oldParent, controlsProp, null, null);
                    }
                }

                if (changeSvc != null)
                {
                    changeSvc.OnComponentChanged(newParent, controlsProp, null, null);
                }

                //commit the transaction
                dt.Commit();
            }
        }

        /// <summary>
        ///  Determines if the DrawGrid property should be persisted.
        /// </summary>
        private bool ShouldSerializeDrawGrid()
        {
            //To determine if we need to persist this value, we first need to check
            //if we have a parent who is a parentcontroldesigner, then get their
            //setting...
            //
            ParentControlDesigner parent = GetParentControlDesignerOfParent();
            if (parent != null)
            {
                return !(DrawGrid == parent.DrawGrid);
            }

            //Otherwise, we'll compare the value to the options page...
            //
            return !IsOptionDefault("ShowGrid", DrawGrid);
        }

        /// <summary>
        ///  Determines if the SnapToGrid property should be persisted.
        /// </summary>
        private bool ShouldSerializeSnapToGrid()
        {
            //To determine if we need to persist this value, we first need to check
            //if we have a parent who is a parentcontroldesigner, then get their
            //setting...
            //
            ParentControlDesigner parent = GetParentControlDesignerOfParent();
            if (parent != null)
            {
                return !(SnapToGrid == parent.SnapToGrid);
            }

            //Otherwise, we'll compare the value to the options page...
            //
            return !IsOptionDefault("SnapToGrid", SnapToGrid);
        }

        /// <summary>
        ///  Determines if the GridSize property should be persisted.
        /// </summary>
        private bool ShouldSerializeGridSize()
        {
            //To determine if we need to persist this value, we first need to check
            //if we have a parent who is a parentcontroldesigner, then get their
            //setting...
            //
            ParentControlDesigner parent = GetParentControlDesignerOfParent();
            if (parent != null)
            {
                return !(GridSize.Equals(parent.GridSize));
            }

            //Otherwise, we'll compare the value to the options page...
            //
            return !IsOptionDefault("GridSize", GridSize);
        }

        private void ResetGridSize()
        {
            _getDefaultGridSize = true;
            _parentCanSetGridSize = true;
            //invalidate the control
            Control control = Control;
            if (control != null)
            {
                control.Invalidate(true);
            }
        }

        private void ResetDrawGrid()
        {
            _getDefaultDrawGrid = true;
            _parentCanSetDrawGrid = true;
            //invalidate the control
            Control control = Control;
            if (control != null)
            {
                control.Invalidate(true);
            }
        }

        private void ResetSnapToGrid()
        {
            _getDefaultGridSnap = true;
            _parentCanSetGridSnap = true;
        }

        /// <internalonly/>
        IComponent IOleDragClient.Component
        {
            get
            {
                return Component;
            }
        }

        /// <internalonly/>
        /// <summary>
        /// Retrieves the control view instance for the designer that
        /// is hosting the drag.
        /// </summary>
        bool IOleDragClient.AddComponent(IComponent component, string name, bool firstAdd)
        {
            IContainer container = DesignerUtils.CheckForNestedContainer(Component.Site.Container); // ...necessary to support SplitterPanel components

            bool containerMove = true;
            IContainer oldContainer = null;
            IDesignerHost localDesignerHost = (IDesignerHost)GetService(typeof(IDesignerHost));

            if (!firstAdd)
            {
                // just a move, so reparent
                if (component.Site != null)
                {
                    oldContainer = component.Site.Container;
                    containerMove = container != oldContainer;
                    if (containerMove)
                    {
                        oldContainer.Remove(component);
                    }
                }

                if (containerMove)
                {
                    // check if there's already a component by this name in the
                    // container
                    if (name != null && container.Components[name] != null)
                    {
                        name = null;
                    }

                    // add it back
                    if (name != null)
                    {
                        container.Add(component, name);
                    }
                    else
                    {
                        container.Add(component);
                    }
                }
            }

            // make sure this designer will accept this component -- we wait until
            // now to be sure the components designer has been created.
            //
            if (!((IOleDragClient)this).IsDropOk(component))
            {
                try
                {
                    IUIService uiSvc = (IUIService)GetService(typeof(IUIService));
                    string error = string.Format(SR.DesignerCantParentType, component.GetType().Name, Component.GetType().Name);
                    if (uiSvc != null)
                    {
                        uiSvc.ShowError(error);
                    }
                    else
                    {
                        RTLAwareMessageBox.Show(null, error, null, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, 0);
                    }

                    return false;
                }
                finally
                {
                    if (containerMove)
                    {
                        // move it back.
                        container.Remove(component);
                        if (oldContainer != null)
                        {
                            oldContainer.Add(component);
                        }
                    }
                    else
                    {
                        //there wad no container move ... but then this operation is not supported so
                        //just remove this component
                        container.Remove(component);
                    }
                }
            }

            // this is a chance to display a more specific error messages than on IsDropOK failure
            if (!CanAddComponent(component))
            {
                return false;
            }

            // make sure we can handle this thing, otherwise hand it to the base components designer
            //
            Control c = GetControl(component);

            if (c != null)
            {
                // set it's handler to this
                Control parent = GetParentForComponent(component);
                Form form = c as Form;

                if (form == null || !form.TopLevel)
                {
                    if (c.Parent != parent)
                    {
                        PropertyDescriptor controlsProp = TypeDescriptor.GetProperties(parent)["Controls"];
                        // we want to insert rather than add it, so we add then move
                        // to the beginning

                        if (c.Parent != null)
                        {
                            Control cParent = c.Parent;
                            if (_componentChangeSvc != null)
                            {
                                _componentChangeSvc.OnComponentChanging(cParent, controlsProp);
                            }

                            cParent.Controls.Remove(c);
                            if (_componentChangeSvc != null)
                            {
                                _componentChangeSvc.OnComponentChanged(cParent, controlsProp, cParent.Controls, cParent.Controls);
                            }
                        }

                        if (_suspendChanging == 0 && _componentChangeSvc != null)
                        {
                            _componentChangeSvc.OnComponentChanging(parent, controlsProp);
                        }

                        parent.Controls.Add(c);
                        // sburke 78059 -- not sure why we need this call. this should move things to the beginning of the
                        // z-order, but do we need that?
                        //
                        //parent.Controls.SetChildIndex(c, 0);
                        if (_componentChangeSvc != null)
                        {
                            _componentChangeSvc.OnComponentChanged(parent, controlsProp, parent.Controls, parent.Controls);
                        }
                    }
                    else
                    {
                        // here, we redo the add to make sure the handlers get setup right
                        int childIndex = parent.Controls.GetChildIndex(c);
                        parent.Controls.Remove(c);
                        parent.Controls.Add(c);
                        parent.Controls.SetChildIndex(c, childIndex);
                    }
                }

                c.Invalidate(true);
            }

            if (localDesignerHost != null && containerMove)
            {
                // sburke -- looks like we always want to do this to ensure that sited children get
                // handled properly.  if we respected the boolean before, the ui selection handlers
                // would cache designers, handlers, etc. and cause problems.
                IComponentInitializer init = localDesignerHost.GetDesigner(component) as IComponentInitializer;
                if (init != null)
                {
                    init.InitializeExistingComponent(null);
                }

                AddChildComponents(component, container, localDesignerHost);
            }

            return true;
        }

        /// <internalonly/>
        /// <summary>
        /// Checks if the client is read only.  That is, if components can
        /// be added or removed from the designer.
        /// </summary>
        bool IOleDragClient.CanModifyComponents
        {
            get
            {
                return (!InheritanceAttribute.Equals(InheritanceAttribute.InheritedReadOnly));
            }
        }

        /// <internalonly/>
        /// <summary>
        /// Checks if it is valid to drop this type of a component on this client.
        /// </summary>
        bool IOleDragClient.IsDropOk(IComponent component)
        {
            IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));

            if (host != null)
            {
                IDesigner designer = host.GetDesigner(component);
                bool disposeDesigner = false;

                // we need to create one then
                if (designer == null)
                {
                    designer = TypeDescriptor.CreateDesigner(component, typeof(IDesigner));
                    ControlDesigner cd = designer as ControlDesigner;
                    if (cd != null)
                    {
                        //Make sure the component doesn't get set to Visible
                        cd.ForceVisible = false;
                    }

                    designer.Initialize(component);
                    disposeDesigner = true;
                }

                try
                {
                    ComponentDesigner cd = designer as ComponentDesigner;
                    if (cd != null)
                    {
                        if (cd.CanBeAssociatedWith(this))
                        {
                            ControlDesigner controlDesigner = cd as ControlDesigner;
                            if (controlDesigner != null)
                            {
                                return CanParent(controlDesigner);
                            }
                        }
                        else
                        {
                            return false;
                        }
                    }
                }
                finally
                {
                    if (disposeDesigner)
                    {
                        designer.Dispose();
                    }
                }
            }

            return true;
        }

        /// <internalonly/>
        /// <summary>
        /// Retrieves the control view instance for the designer that
        /// is hosting the drag.
        /// </summary>
        Control IOleDragClient.GetDesignerControl()
        {
            return Control;
        }

        /// <internalonly/>
        /// <summary>
        /// Retrieves the control view instance for the given component.
        /// For Win32 designer, this will often be the component itself.
        /// </summary>
        Control IOleDragClient.GetControlForComponent(object component)
        {
            return GetControl(component);
        }
    }
}
