File: AuthoringOM\Design\MessageFilters\WindowManager.cs
Project: ndp\cdf\src\WF\Common\System.Workflow.ComponentModel.csproj (System.Workflow.ComponentModel)
namespace System.Workflow.ComponentModel.Design
{
    using System;
    using System.Drawing;
    using System.Diagnostics;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Windows.Forms;
    using System.ComponentModel;
    using System.ComponentModel.Design;
 
    #region Class WindowManager
    //This behavior needs the logical coordinates
    internal sealed class WindowManager : WorkflowDesignerMessageFilter
    {
        #region Members and Constructor
        private ActivityDesigner currentActiveDesigner = null;
 
        internal WindowManager()
        {
        }
        #endregion
 
        #region MessageFilter Overrides
        protected override bool OnMouseDown(MouseEventArgs eventArgs)
        {
            Point clientPoint = new Point(eventArgs.X, eventArgs.Y);
 
            //If the point is not in clickable area then return
            WorkflowView parentView = ParentView;
            if (!parentView.IsClientPointInActiveLayout(clientPoint))
                return true;
 
            //Check if the mouse is hit on designer
            object selectedObject = null;
            HitTestInfo hitTestInfo = MessageHitTestContext;
            if (hitTestInfo == HitTestInfo.Nowhere)
                selectedObject = parentView.RootDesigner.Activity;
            else
                selectedObject = hitTestInfo.SelectableObject;
 
            //Selection service handles KeyModifiers, ctrl and shift will be handled as per the standard behavior
            if (selectedObject != null)
            {
                ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
                if (selectionService != null)
                    selectionService.SetSelectedComponents(new object[] { selectedObject }, SelectionTypes.Primary);
            }
 
            //Designer designates an area as action area if there is some special significance associated with the area ie Expand Collapse
            //In such cases we give activity designer an oppertunity to take action when mouse click happens on the area
            //if there are Ctrl or Shift keys pressed, only do the selection change, dont call the child designer
            //Now that the designer is selected
            if (this.currentActiveDesigner != hitTestInfo.AssociatedDesigner)
            {
                if (this.currentActiveDesigner != null)
                    ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseLeave();
 
                this.currentActiveDesigner = hitTestInfo.AssociatedDesigner;
 
                if (this.currentActiveDesigner != null)
                    ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseEnter(eventArgs);
            }
 
            if (this.currentActiveDesigner != null && ((Control.ModifierKeys & (Keys.Control | Keys.Shift)) == 0))
                ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseDown(eventArgs);
 
            return false;
        }
 
        protected override bool OnMouseMove(MouseEventArgs eventArgs)
        {
            Point clientPoint = new Point(eventArgs.X, eventArgs.Y);
 
            //If the mouse is not in a valid area then we return
            if (!ParentView.IsClientPointInActiveLayout(clientPoint))
            {
                if (this.currentActiveDesigner != null)
                    ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseLeave();
                this.currentActiveDesigner = null;
                return true;
            }
 
            //Now check which designer is hit
            HitTestInfo hitTestInfo = MessageHitTestContext;
            if (this.currentActiveDesigner != hitTestInfo.AssociatedDesigner)
            {
                if (this.currentActiveDesigner != null)
                    ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseLeave();
 
                this.currentActiveDesigner = hitTestInfo.AssociatedDesigner;
 
                if (this.currentActiveDesigner != null)
                    ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseEnter(eventArgs);
            }
            else
            {
                if (this.currentActiveDesigner != null)
                    ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseMove(eventArgs);
            }
 
            return false;
        }
 
        protected override bool OnMouseUp(MouseEventArgs eventArgs)
        {
            Point clientPoint = new Point(eventArgs.X, eventArgs.Y);
 
            //If the mouse is not in a valid area then we return
            if (!ParentView.IsClientPointInActiveLayout(clientPoint))
            {
                if (this.currentActiveDesigner != null)
                    ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseLeave();
                this.currentActiveDesigner = null;
                return true;
            }
 
            //Now check which designer is hit
            HitTestInfo hitTestInfo = MessageHitTestContext;
            if (this.currentActiveDesigner != hitTestInfo.AssociatedDesigner)
            {
                if (this.currentActiveDesigner != null)
                    ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseLeave();
 
                this.currentActiveDesigner = hitTestInfo.AssociatedDesigner;
 
                if (this.currentActiveDesigner != null)
                    ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseEnter(eventArgs);
            }
 
            //Dispatch the event
            if (this.currentActiveDesigner != null)
                ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseUp(eventArgs);
 
            return false;
        }
 
        protected override bool OnMouseDoubleClick(MouseEventArgs eventArgs)
        {
            ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
            if (selectionService != null)
            {
                ArrayList selectedComponents = new ArrayList(selectionService.GetSelectedComponents());
                for (int i = 0; i < selectedComponents.Count; i++)
                {
                    Activity selectedComponent = selectedComponents[i] as Activity;
                    if (selectedComponent == null)
                        continue;
 
                    IDesigner designer = ActivityDesigner.GetDesigner(selectedComponent) as IDesigner;
                    if (designer != null)
                    {
                        designer.DoDefaultAction();
                        ((IWorkflowDesignerMessageSink)designer).OnMouseDoubleClick(eventArgs);
                        break;
                    }
                }
            }
 
            return false;
        }
 
        protected override bool OnMouseEnter(MouseEventArgs eventArgs)
        {
            //Fire the event
            if (this.currentActiveDesigner != null)
                ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseEnter(eventArgs);
 
            return false;
        }
 
        protected override bool OnMouseHover(MouseEventArgs eventArgs)
        {
            //Fire the event
            if (this.currentActiveDesigner != null)
                ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseHover(eventArgs);
 
            return false;
        }
 
        protected override bool OnMouseLeave()
        {
            //Dispatch events
            if (this.currentActiveDesigner != null)
            {
                ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseLeave();
                this.currentActiveDesigner = null;
            }
 
            return false;
        }
 
        protected override bool OnMouseWheel(MouseEventArgs eventArgs)
        {
            UpdateViewOnMouseWheel(eventArgs, Control.ModifierKeys);
            return true;
        }
 
        protected override bool OnMouseCaptureChanged()
        {
            //Dispatch events
            if (this.currentActiveDesigner != null)
            {
                ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseCaptureChanged();
            }
 
            return false;
        }
 
        protected override bool OnDragEnter(DragEventArgs eventArgs)
        {
            if (this.currentActiveDesigner != null)
            {
                ((IWorkflowDesignerMessageSink)this.currentActiveDesigner).OnMouseLeave();
                this.currentActiveDesigner = null;
            }
 
            return false;
        }
 
        protected override bool OnKeyDown(KeyEventArgs eventArgs)
        {
            if (eventArgs != null && (eventArgs.KeyCode == Keys.PageUp || eventArgs.KeyCode == Keys.PageDown))
                UpdateViewOnPageUpDown(eventArgs.KeyCode == Keys.PageUp);
            ISelectionService selectionService = ((IServiceProvider)this.ParentView).GetService(typeof(ISelectionService)) as ISelectionService;
 
            //enter key (
            if (eventArgs.KeyCode == Keys.Enter)
            {
                // on enter key we want to do DoDefault of the designer
                IDesigner designer = ActivityDesigner.GetDesigner(selectionService.PrimarySelection as Activity) as IDesigner;
                if (designer != null)
                {
                    designer.DoDefaultAction();
                    eventArgs.Handled = true;
                }
            }
            else if (eventArgs.KeyCode == Keys.Escape)
            {
                if (!eventArgs.Handled)
                {
                    CompositeActivityDesigner parentDesigner = ActivityDesigner.GetParentDesigner(selectionService.PrimarySelection);
                    if (parentDesigner != null)
                        selectionService.SetSelectedComponents(new object[] { parentDesigner.Activity }, SelectionTypes.Replace);
 
                    eventArgs.Handled = true;
                }
            }
            else if (eventArgs.KeyCode == Keys.Delete)
            {
                // check if we are cutting root component
                IDesignerHost designerHost = ((IServiceProvider)this.ParentView).GetService(typeof(IDesignerHost)) as IDesignerHost;
                if (!(designerHost == null || selectionService.GetComponentSelected(designerHost.RootComponent)))
                {
                    //Check that we are cutting all activities
                    //Check if we are in writable context
                    ICollection components = selectionService.GetSelectedComponents();
                    if (DesignerHelpers.AreComponentsRemovable(components))
                    {
                        // check if we can delete these
                        List<Activity> topLevelActivities = new List<Activity>(Helpers.GetTopLevelActivities(selectionService.GetSelectedComponents()));
                        bool needToDelete = (topLevelActivities.Count > 0);
                        IDictionary commonParentActivities = Helpers.PairUpCommonParentActivities(topLevelActivities);
                        foreach (DictionaryEntry entry in commonParentActivities)
                        {
                            CompositeActivityDesigner compositeActivityDesigner = ActivityDesigner.GetDesigner(entry.Key as Activity) as CompositeActivityDesigner;
                            if (compositeActivityDesigner != null && !compositeActivityDesigner.CanRemoveActivities(new List<Activity>((Activity[])((ArrayList)entry.Value).ToArray(typeof(Activity))).AsReadOnly()))
                                needToDelete = false;
                        }
 
                        if (needToDelete)
                        {
                            List<ConnectorHitTestInfo> connectors = new List<ConnectorHitTestInfo>();
                            foreach (object component in components)
                            {
                                ConnectorHitTestInfo connector = component as ConnectorHitTestInfo;
                                if (connector != null)
                                    connectors.Add(connector);
                            }
 
                            //cache selcted connectors before calling this func
                            CompositeActivityDesigner.RemoveActivities((IServiceProvider)this.ParentView, topLevelActivities.AsReadOnly(), SR.GetString(SR.DeletingActivities));
 
                            //add connectors back to the selection service
                            if (selectionService != null && connectors.Count > 0)
                                selectionService.SetSelectedComponents(connectors, SelectionTypes.Add);
 
                            eventArgs.Handled = true;
                        }
                    }
                }
            }
            //navigation (left, right, up, down, tab, shift-tab)
            else if (eventArgs.KeyCode == Keys.Left || eventArgs.KeyCode == Keys.Right || eventArgs.KeyCode == Keys.Up || eventArgs.KeyCode == Keys.Down || eventArgs.KeyCode == Keys.Tab)
            {
                //we'll pass it to the parent designer of the primary selected designer
                //sequential designers just navigate between their children
                //free form designers may move their children on arrow keys and navigate on tab
                ActivityDesigner designer = ActivityDesigner.GetDesigner(selectionService.PrimarySelection as Activity) as ActivityDesigner;
                if (designer != null && designer.ParentDesigner != null)
                {
                    //we will let the parent see if it wants to handle the event, 
                    //otherwise the selected designer itself will be called from a designer message filter below
                    ((IWorkflowDesignerMessageSink)designer.ParentDesigner).OnKeyDown(eventArgs);
                    eventArgs.Handled = true;
                }
            }
 
            if (!eventArgs.Handled)
            {
                ActivityDesigner designerWithFocus = GetDesignerWithFocus();
                if (designerWithFocus != null)
                    ((IWorkflowDesignerMessageSink)designerWithFocus).OnKeyDown(eventArgs);
            }
 
            return eventArgs.Handled;
        }
 
        protected override bool OnKeyUp(KeyEventArgs eventArgs)
        {
            ActivityDesigner designerWithFocus = GetDesignerWithFocus();
            if (designerWithFocus != null)
                ((IWorkflowDesignerMessageSink)designerWithFocus).OnKeyUp(eventArgs);
 
            return false;
        }
 
        protected override bool OnScroll(ScrollBar sender, int value)
        {
            ActivityDesigner designerWithFocus = GetDesignerWithFocus();
            if (designerWithFocus != null)
                ((IWorkflowDesignerMessageSink)designerWithFocus).OnScroll(sender, value);
 
            return false;
        }
 
        protected override bool OnShowContextMenu(Point screenMenuPoint)
        {
            IMenuCommandService menuCommandService = GetService(typeof(IMenuCommandService)) as IMenuCommandService;
            if (menuCommandService != null)
                menuCommandService.ShowContextMenu(WorkflowMenuCommands.SelectionMenu, screenMenuPoint.X, screenMenuPoint.Y);
            return true;
        }
 
        protected override void OnLayout(LayoutEventArgs eventArgs)
        {
            WorkflowView parentView = ParentView;
            using (Graphics graphics = parentView.CreateGraphics())
            {
                if (parentView.RootDesigner != null)
                {
                    try
                    {
                        ((IWorkflowDesignerMessageSink)parentView.RootDesigner).OnLayoutSize(graphics);
                    }
                    catch (Exception e)
                    {
                        //Eat the exception thrown
                        Debug.WriteLine(e);
                    }
 
                    try
                    {
                        ((IWorkflowDesignerMessageSink)parentView.RootDesigner).OnLayoutPosition(graphics);
                    }
                    catch (Exception e)
                    {
                        //Eat the exception thrown
                        Debug.WriteLine(e);
                    }
                }
            }
        }
 
        protected override bool ProcessMessage(Message message)
        {
            ActivityDesigner designerWithFocus = GetDesignerWithFocus();
            if (designerWithFocus != null)
                ((IWorkflowDesignerMessageSink)designerWithFocus).ProcessMessage(message);
 
            return false;
        }
 
        protected override void OnThemeChange()
        {
            WorkflowView parentView = ParentView;
            if (parentView.RootDesigner != null)
                ((IWorkflowDesignerMessageSink)parentView.RootDesigner).OnThemeChange();
        }
        #endregion
 
        #region Helpers
        private ActivityDesigner GetDesignerWithFocus()
        {
            ActivityDesigner designerWithFocus = null;
 
            ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
            if (selectionService != null)
            {
                object primarySelection = selectionService.PrimarySelection;
                if (primarySelection is Activity)
                    designerWithFocus = ActivityDesigner.GetDesigner(primarySelection as Activity);
                else
                    designerWithFocus = ActivityDesigner.GetParentDesigner(primarySelection);
            }
 
            return designerWithFocus;
        }
 
        private void UpdateViewOnPageUpDown(bool pageUp)
        {
            WorkflowView parentView = ParentView;
            Point scrollPosition = parentView.ScrollPosition;
            scrollPosition.Y = scrollPosition.Y + ((pageUp ? -1 : 1) * parentView.VScrollBar.LargeChange);
            parentView.ScrollPosition = scrollPosition;
        }
 
        private void UpdateViewOnMouseWheel(MouseEventArgs eventArgs, Keys modifierKeys)
        {
            WorkflowView parentView = ParentView;
            if (Control.ModifierKeys == Keys.Control)
            {
                int newZoom = parentView.Zoom + ((eventArgs.Delta / 120) * 10);
                newZoom = Math.Max(newZoom, AmbientTheme.MinZoom);
                newZoom = Math.Min(newZoom, AmbientTheme.MaxZoom);
                parentView.Zoom = newZoom;
            }
            else
            {
                //scroll up and down
                int numberOfLogicalLines = -eventArgs.Delta / 120;
                int logicalLineHeight = parentView.VScrollBar.SmallChange;
                Point scrollPosition = parentView.ScrollPosition;
 
                scrollPosition.Y = scrollPosition.Y + (numberOfLogicalLines * logicalLineHeight);
                parentView.ScrollPosition = scrollPosition;
            }
        }
        #endregion
    }
    #endregion
}