//This enables us to get children ICompositeViews from WorkflowViewElements.
        //Eg. get the WorkflowItemsPresenter from SequenceDesigner.
        //This is useful for Cut-Copy-Paste, Delete handling, etc.
        internal static void RegisterWithParentViewElement(ICompositeView container)
        {
            WorkflowViewElement parent = GetParentViewElement(container);

            if (parent != null)
            {
                CutCopyPasteHelper.AddChildContainer(parent, container);
            }
        }
        static ICompositeView GetContainerForPaste(ModelItem pasteModelItem, Point clickPoint)
        {
            ICompositeView pasteContainer = null;

            if (null != pasteModelItem && null != pasteModelItem.View && pasteModelItem.View is WorkflowViewElement)
            {
                pasteContainer = ((WorkflowViewElement)pasteModelItem.View).ActiveCompositeView;
            }
            if (null == pasteContainer)
            {
                //Get clicked container.
                if (clickPoint.X > 0 && clickPoint.Y > 0)
                {
                    pasteContainer = GetClickedContainer(pasteModelItem, clickPoint);
                }

                //If the container itself is a WVE, there's posibility that it's collapsed.
                //Thus, we need to check this as well.
                if (pasteContainer != null && pasteContainer is WorkflowViewElement)
                {
                    WorkflowViewElement view = pasteContainer as WorkflowViewElement;
                    if (!view.ShowExpanded)
                    {
                        pasteContainer = null;
                    }
                }
                else if (pasteContainer == null) //If the modelitem.View itself is a container.
                {
                    WorkflowViewElement view = pasteModelItem.View as WorkflowViewElement;
                    if (view != null && view.ShowExpanded)
                    {
                        pasteContainer = pasteModelItem.View as ICompositeView;
                    }
                }

                //Get the container registered with modelItem.View if unambigous
                //If nothing works take the container with keyboard focus if one exists.
                if (pasteContainer == null)
                {
                    HashSet <ICompositeView> childrenContainers = CutCopyPasteHelper.GetChildContainers(pasteModelItem.View as WorkflowViewElement);
                    if ((childrenContainers == null || childrenContainers.Count == 0) && null != pasteModelItem.View)
                    {
                        pasteContainer = (ICompositeView)DragDropHelper.GetCompositeView((WorkflowViewElement)pasteModelItem.View);
                    }
                    else if (null != childrenContainers && childrenContainers.Count == 1)
                    {
                        pasteContainer = new List <ICompositeView>(childrenContainers)[0];
                    }
                    else
                    {
                        pasteContainer = Keyboard.FocusedElement as ICompositeView;
                    }
                }
            }
            return(pasteContainer);
        }
        public static void DoCut(EditingContext context)
        {
            if (context == null)
            {
                throw FxTrace.Exception.AsError(new ArgumentNullException("context"));
            }
            Selection        currentSelection = context.Items.GetValue <Selection>();
            List <ModelItem> modelItemsToCut  = new List <ModelItem>(currentSelection.SelectedObjects);

            CutCopyPasteHelper.DoCut(modelItemsToCut, context);
        }
        public void OnItemsPasted(List <object> itemsToPaste, List <object> metaData, Point pastePoint, WorkflowViewElement pastePointReference)
        {
            // first see if a spacer is selected.
            int index = this.selectedSpacerIndex;

            // else see if we can paste after a selected child
            if (index < 0)
            {
                Selection currentSelection = this.Context.Items.GetValue <Selection>();
                index = this.Items.IndexOf(currentSelection.PrimarySelection);
                //paste after the selected child
                if (index >= 0)
                {
                    index++;
                }
            }
            if (index < 0)
            {
                index = addAtEndMarker;
            }

            IList <object> mergedItemsToPaste = CutCopyPasteHelper.SortFromMetaData(itemsToPaste, metaData);

            List <ModelItem> modelItemsToSelect = new List <ModelItem>();

            foreach (object itemToPaste in mergedItemsToPaste)
            {
                if (IsDropAllowed(itemToPaste))
                {
                    if (index == addAtEndMarker)
                    {
                        modelItemsToSelect.Add(this.Items.Add(itemToPaste));
                    }
                    else
                    {
                        modelItemsToSelect.Add(this.Items.Insert(index, itemToPaste));
                    }
                    if (index >= 0)
                    {
                        index++;
                    }
                }
            }

            this.Dispatcher.BeginInvoke(
                new Action(() =>
            {
                this.Context.Items.SetValue(new Selection(modelItemsToSelect));
            }),
                Windows.Threading.DispatcherPriority.ApplicationIdle,
                null);
        }
 void ICompositeView.OnItemsPasted(List <object> itemsToPaste, List <object> metaData, Point pastePoint, WorkflowViewElement pastePointReference)
 {
     if (itemsToPaste.Count == 1)
     {
         // Single Paste
         UpdateItem(itemsToPaste[0]);
     }
     else
     {
         // Mutiple Paste.
         IList <object> sortedList = CutCopyPasteHelper.SortFromMetaData(itemsToPaste, metaData);
         Fx.Assert(this.Item == null, "multi-paste on item != null is not supported now");
         this.DoAutoWrapDrop(InsertionPosition.None, sortedList);
     }
 }
        // Get rid of descendant model items when both ancestor and descendant and ancestor model items are selected
        internal static IEnumerable <ModelItem> GetModelItemsToDrag(IEnumerable <ModelItem> modelItems)
        {
            HashSet <ModelItem> modelItemsToDrag = new HashSet <ModelItem>();

            foreach (ModelItem modelItem in modelItems)
            {
                HashSet <ModelItem> parentModelItems = CutCopyPasteHelper.GetSelectableParentModelItems(modelItem);
                parentModelItems.IntersectWith(modelItems);
                if (parentModelItems.Count == 0)
                {
                    modelItemsToDrag.Add(modelItem);
                }
            }
            return(modelItemsToDrag);
        }
        //This is more efficient than walking up the VisualTree looking for WorkflowViewElements.
        //Assuming that Cut-Copy will always be against selected elements.
        //This implies that only elements under the BreadCrumbRoot can be cut/copied.
        static List <WorkflowViewElement> GetSelectableParentViewElements(WorkflowViewElement childElement)
        {
            List <WorkflowViewElement> parentViewElements = new List <WorkflowViewElement>();

            if (childElement != null)
            {
                UIElement      breadcrumbRoot = childElement.Context.Services.GetService <DesignerView>().RootDesigner;
                ICompositeView container      = (ICompositeView)DragDropHelper.GetCompositeView(childElement);
                while (!childElement.Equals(breadcrumbRoot) && container != null)
                {
                    childElement = CutCopyPasteHelper.GetParentViewElement(container);
                    Fx.Assert(childElement != null, "container should be present in a WorkflowViewElement");
                    parentViewElements.Add(childElement);
                    container = (ICompositeView)DragDropHelper.GetCompositeView(childElement);
                }
            }
            return(parentViewElements);
        }
        void OnItemsChanged(ModelItemCollection oldItemsCollection, ModelItemCollection newItemsCollection)
        {
            if (oldItemsCollection != null)
            {
                oldItemsCollection.CollectionChanged -= this.OnCollectionChanged;
            }

            if (newItemsCollection != null)
            {
                newItemsCollection.CollectionChanged += this.OnCollectionChanged;
            }

            if (!isRegisteredWithParent)
            {
                CutCopyPasteHelper.RegisterWithParentViewElement(this);
                isRegisteredWithParent = true;
            }
            populateOnLoad = false;
            PopulateContent();
        }
        static void CutCopyOperation(List <ModelItem> modelItemsToCutCopy, EditingContext context, bool isCutOperation)
        {
            List <object> objectsOnClipboard = null;
            List <object> metaData           = null;

            if (modelItemsToCutCopy.Count > 0)
            {
                objectsOnClipboard = new List <object>(modelItemsToCutCopy.Count);
                metaData           = new List <object>();
                Dictionary <ICompositeView, List <ModelItem> > notifyDictionary = new Dictionary <ICompositeView, List <ModelItem> >();
                UIElement breadCrumbRootView = ((DesignerView)context.Services.GetService <DesignerView>()).RootDesigner;
                foreach (ModelItem modelItem in modelItemsToCutCopy)
                {
                    object currentElement = modelItem.GetCurrentValue();

                    if (typeof(Activity).IsAssignableFrom(currentElement.GetType()))
                    {
                        string fileName;
                        if (AttachablePropertyServices.TryGetProperty(currentElement, XamlDebuggerXmlReader.FileNameName, out fileName))
                        {
                            AttachablePropertyServices.RemoveProperty(currentElement, XamlDebuggerXmlReader.FileNameName);
                        }
                    }

                    if (modelItem.View != null)
                    {
                        //The case where the breadcrumbroot designer is Cut/Copied. We do not delete the root designer, we only copy it.
                        if (breadCrumbRootView.Equals(modelItem.View))
                        {
                            notifyDictionary.Clear();
                            objectsOnClipboard.Add(modelItem.GetCurrentValue());
                            break;
                        }
                        else
                        {
                            ICompositeView container = (ICompositeView)DragDropHelper.GetCompositeView((WorkflowViewElement)modelItem.View);
                            if (container != null)
                            {
                                //If the parent and some of its children are selected and cut/copied, we ignore the children.
                                //The entire parent will be cut/copied.
                                //HashSet parentModelItems contains all the model items in the parent chain of current modelItem.
                                //We use HashSet.IntersectWith operation to determine if one of the parents is set to be cut.
                                HashSet <ModelItem> parentModelItems = CutCopyPasteHelper.GetSelectableParentModelItems(modelItem);
                                parentModelItems.IntersectWith(modelItemsToCutCopy);
                                if (parentModelItems.Count == 0)
                                {
                                    if (!notifyDictionary.ContainsKey(container))
                                    {
                                        notifyDictionary[container] = new List <ModelItem>();
                                    }
                                    notifyDictionary[container].Add(modelItem);
                                }
                            }
                        }
                    }
                }

                foreach (ICompositeView container in notifyDictionary.Keys)
                {
                    object containerMetaData = false;
                    if (isCutOperation)
                    {
                        containerMetaData = container.OnItemsCut(notifyDictionary[container]);
                    }
                    else
                    {
                        containerMetaData = container.OnItemsCopied(notifyDictionary[container]);
                    }
                    if (containerMetaData != null)
                    {
                        metaData.Add(containerMetaData);
                    }
                    //Put the actual activities and not the modelItems in the clipboard.
                    foreach (ModelItem modelItem in notifyDictionary[container])
                    {
                        objectsOnClipboard.Add(modelItem.GetCurrentValue());
                    }
                }
                if (metaData.Count == 0)
                {
                    metaData = null;
                }
            }
            try
            {
                FrameworkName targetFramework = context.Services.GetService <DesignerConfigurationService>().TargetFrameworkName;
                PutOnClipBoard(objectsOnClipboard, metaData, targetFramework);
            }
            catch (XamlObjectReaderException exception)
            {
                if (modelItemsToCutCopy.Count > 0 && ErrorActivity.GetHasErrorActivities(modelItemsToCutCopy[0].Root.GetCurrentValue()))
                {
                    ErrorReporting.ShowErrorMessage(SR.CutCopyErrorActivityMessage);
                }
                else
                {
                    ErrorReporting.ShowErrorMessage(exception.Message);
                }
            }
        }
 protected override void OnRender(DrawingContext drawingContext)
 {
     CutCopyPasteHelper.RegisterWithParentViewElement(this);
     base.OnRender(drawingContext);
 }