void IActivationSite.TunnelActivation()
        {
            if (this.lastActiveChildSite == null)
            {
                if (this.host != null)
                {
                    // We need to pick one.  Pick the biggest one by area.
                    var slotTable = new Dictionary <string, ActivatableTabControl>();

                    foreach (var child in this.host.Children.OfType <ActivatableTabControl>())
                    {
                        slotTable[SlotPanel.GetSlotName(child)] = child;
                    }

                    var pair = slotTable.OrderBy(kvp => kvp.Value.ActualHeight * kvp.Value.ActualWidth).FirstOrDefault();

                    this.lastActiveChildSite = pair.Value;
                }
            }

            if (this.lastActiveChildSite != null)
            {
                this.lastActiveChildSite.TunnelActivation();
            }
        }
        // NOTE:  This method is static, because the actual SplitTabsControl that created the view may not be the one in which
        // that view lives at the time it is closed.  Being static forces the method to use the sender to obtain the appropriate
        // parent control.
        static void OnViewClosed(object sender, EventArgs e)
        {
            View view = sender as View;

            if (view == null)
            {
                return;
            }

            ActivatableTabItem    item             = ActivatableTabItem.GetTabItem(view);
            ActivatableTabControl tabControl       = item.TabControlParent;
            SplitTabsControl      splitTabsControl = tabControl.FindParent <SplitTabsControl>();
            TabNode node        = tabControl.TabNode;
            bool    switchFocus = tabControl.IsKeyboardFocusWithin;

            splitTabsControl.RemoveItemFromControl(item);

            if (switchFocus)
            {
                if (node.TabControl.SelectedItem is ActivatableTabItem)
                {
                    ((ActivatableTabItem)node.TabControl.SelectedItem).Focus();
                }
                else if (node == splitTabsControl.activeTabNode)
                {
                    // We just closed the last view in the active node.  Need to switch the active
                    // tab node to the last active one.
                    splitTabsControl.ActivateLastActiveTabNode();
                }
            }

            view.Closed -= OnViewClosed;
        }
        void RebuildDropTargetWindow(ActivatableTabControl targetControl)
        {
            if (this.dropTarget == null)
            {
                this.dropTarget = new TabDropTargetWindow()
                {
                    AllowsTransparency = true,      // It would be nice to be able to set these in the style...
                    WindowStyle        = WindowStyle.None,
                };
            }

            bool controlDown = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);

            if (targetControl != null && !controlDown)
            {
                TabNode node = targetControl.TabNode;

                if (!this.dropTarget.IsVisible || this.dropTarget.TargetNode != node)
                {
                    this.dropTarget.Hide();
                    this.dropTarget.UpdateLayout();

                    var pos = new Point(0, 0);
                    pos = targetControl.PointToScreenIndependent(pos);

                    this.dropTarget.Left   = pos.X;
                    this.dropTarget.Top    = pos.Y;
                    this.dropTarget.Width  = targetControl.ActualWidth;
                    this.dropTarget.Height = targetControl.ActualHeight;

                    var parent      = node.Parent;
                    var grandparent = parent == null ? null : parent.Parent;

                    this.dropTarget.VerticalParentNode   = parent;
                    this.dropTarget.HorizontalParentNode = parent;

                    if (grandparent != null && parent.Slot.Orientation == Orientation.Vertical)
                    {
                        this.dropTarget.VerticalParentNode = grandparent;
                    }
                    else if (grandparent != null && parent.Slot.Orientation == Orientation.Horizontal)
                    {
                        this.dropTarget.HorizontalParentNode = grandparent;
                    }

                    this.dropTarget.TargetNode          = node;
                    this.dropTarget.IsTabbedSpotVisible = true;
                    this.dropTarget.AreDockSpotsVisible = (targetControl != this.sourceControl || this.sourceControl.Items.Count > 1);
                    this.dropTarget.Show();
                    this.dropTarget.UpdateLayout();
                }
            }
            else
            {
                this.dropTarget.Hide();
            }
        }
        void IActivationSite.BubbleActivation(object child)
        {
            var tabControl = child as ActivatableTabControl;

            if ((tabControl != null) && (this.ParentSite != null))
            {
                this.lastActiveChildSite = tabControl;
                this.ParentSite.BubbleActivation(this);
            }
        }
        void StartMoving()
        {
            var content = this.draggedItem.Content as FrameworkElement;

            if (content != null)
            {
                this.dragWindowSize = new Size(content.ActualWidth, content.ActualHeight);
            }
            else
            {
                this.dragWindowSize = new Size(500, 300);
            }

            this.draggedItem.Cursor = Cursors.SizeAll;
            this.dragShadow         = new Window
            {
                AllowsTransparency = true,
                ShowInTaskbar      = false,
                WindowStyle        = WindowStyle.None,
                Width         = dragWindowSize.Width,
                Height        = dragWindowSize.Height,
                Background    = new SolidColorBrush(Color.FromArgb(0x70, 0xbf, 0xdf, 0xff)),
                Topmost       = true,
                ShowActivated = false
            };

            var dragImage = new ActivatableTabControl()
            {
                Background = Brushes.Transparent, Opacity = 0.7
            };

            dragImage.Items.Add(new ActivatableTabItem {
                Header = draggedItem.Header
            });
            this.dragShadow.Content = dragImage;
            this.dragShadow.Show();

            var pos = this.draggedItem.PointToScreenIndependent(this.offset);

            this.dragShadow.Left = pos.X - offset.X;
            this.dragShadow.Top  = pos.Y - offset.Y;
            this.preMoving       = false;

            this.focusedElement = Keyboard.FocusedElement as DependencyObject;
            if (this.focusedElement != null)
            {
                Keyboard.AddPreviewKeyDownHandler(this.focusedElement, new KeyEventHandler(OnPreviewKeyDown));
                Keyboard.AddPreviewKeyUpHandler(this.focusedElement, new KeyEventHandler(OnPreviewKeyUp));
            }
        }
        private void OnMouseLeftButtonDown(ActivatableTabItem item, MouseButtonEventArgs e)
        {
            e.MouseDevice.Capture(item);

            this.draggedItem            = item;
            this.sourceControl          = item.FindParent <ActivatableTabControl>();
            this.sourceSplitTabsControl = this.sourceControl.FindParent <SplitTabsControl>();

            this.offset    = e.GetPosition(item);
            this.preMoving = true;

            item.LostMouseCapture  += this.OnLostMouseCapture;
            item.MouseLeftButtonUp += this.OnMouseLeftButtonUp;
            item.MouseMove         += this.OnMouseMove;
        }
        private void OnMouseLeftButtonDown(ActivatableTabItem item, MouseButtonEventArgs e)
        {
            e.MouseDevice.Capture(item);

            this.draggedItem = item;
            this.sourceControl = item.FindParent<ActivatableTabControl>();
            this.sourceSplitTabsControl = this.sourceControl.FindParent<SplitTabsControl>();

            this.offset = e.GetPosition(item);
            this.preMoving = true;

            item.LostMouseCapture += this.OnLostMouseCapture;
            item.MouseLeftButtonUp += this.OnMouseLeftButtonUp;
            item.MouseMove += this.OnMouseMove;
        }
        public void AddItemToControl(ActivatableTabItem item, ActivatableTabControl tabControl, bool giveFocus)
        {
            Debug.Assert(tabControl.FindParent <SplitTabsControl>() == this, "Can't add item to a tab control not owned by this split tabs control!");

            if (giveFocus)
            {
                RoutedEventHandler loadedHandler = null;

                loadedHandler = (s, e2) =>
                {
                    item.Focus();
                    item.Loaded -= loadedHandler;
                };
                item.Loaded += loadedHandler;
            }

            tabControl.ParentSite = this;
            tabControl.Items.Add(item);
        }
        void StartMoving()
        {
            var content = this.draggedItem.Content as FrameworkElement;

            if (content != null)
            {
                this.dragWindowSize = new Size(content.ActualWidth, content.ActualHeight);
            }
            else
            {
                this.dragWindowSize = new Size(500, 300);
            }

            this.draggedItem.Cursor = Cursors.SizeAll;
            this.dragShadow = new Window
            {
                AllowsTransparency = true,
                ShowInTaskbar = false,
                WindowStyle = WindowStyle.None,
                Width = dragWindowSize.Width,
                Height = dragWindowSize.Height,
                Background = new SolidColorBrush(Color.FromArgb(0x70, 0xbf, 0xdf, 0xff)),
                Topmost = true,
                ShowActivated = false
            };

            var dragImage = new ActivatableTabControl() { Background = Brushes.Transparent, Opacity = 0.7 };
            dragImage.Items.Add(new ActivatableTabItem { Header = draggedItem.Header });
            this.dragShadow.Content = dragImage;
            this.dragShadow.Show();

            var pos = this.draggedItem.PointToScreenIndependent(this.offset);
            this.dragShadow.Left = pos.X - offset.X;
            this.dragShadow.Top = pos.Y - offset.Y;
            this.preMoving = false;

            this.focusedElement = Keyboard.FocusedElement as DependencyObject;
            if (this.focusedElement != null)
            {
                Keyboard.AddPreviewKeyDownHandler(this.focusedElement, new KeyEventHandler(OnPreviewKeyDown));
                Keyboard.AddPreviewKeyUpHandler(this.focusedElement, new KeyEventHandler(OnPreviewKeyUp));
            }
        }
        void CreateNewTabGroup(Orientation orientation)
        {
            TabNode newTab = new TabNode {
                Slot = new Slot {
                    Name = GetNextSlotName()
                }, TabControl = new ActivatableTabControl()
            };
            ActivatableTabControl originTabControl = this.activeTabNode.TabControl;
            TabNode nodeToSplit;
            double  starSize;
            int     newIndex;

            SlotPanel.SetSlotName(newTab.TabControl, newTab.Slot.Name);
            host.Children.Add(newTab.TabControl);
            newTab.TabControl.TabNode = newTab;

            if (this.activeTabNode.Parent != null && this.activeTabNode.Parent.Slot.Orientation == orientation)
            {
                // We're further splitting the parent in the same orientation, so we are only adding the one node
                nodeToSplit   = this.activeTabNode.Parent;
                newTab.Parent = this.activeTabNode.Parent;
                newIndex      = nodeToSplit.Children.IndexOf(this.activeTabNode) + 1;

                starSize = 0d;
                foreach (var d in nodeToSplit.Slot.Children)
                {
                    starSize += d.Length.Value;
                }

                starSize = starSize / nodeToSplit.Slot.Children.Count;

                // The currently active tab doesn't get altered, but the parent gets a new child.
                nodeToSplit.Children.Insert(newIndex, newTab);
                nodeToSplit.Slot.Children.Insert(newIndex, newTab.Slot);
            }
            else
            {
                // This is a new split of the active node, so we need to add a pair of child nodes
                TabNode top = new TabNode {
                    Parent = this.activeTabNode, Slot = new Slot {
                        Name = GetNextSlotName()
                    }, TabControl = originTabControl
                };

                nodeToSplit   = this.activeTabNode;
                newTab.Parent = this.activeTabNode;

                SlotPanel.SetSlotName(top.TabControl, top.Slot.Name);
                top.TabControl.TabNode = top;

                nodeToSplit.Slot.Children.Add(top.Slot);
                nodeToSplit.Slot.Children.Add(newTab.Slot);
                nodeToSplit.Slot.Orientation = orientation;
            }

            // Move the active tab to the newly created tab control
            var item = originTabControl.SelectedItem as ActivatableTabItem;

            if (item != null)
            {
                if (!item.IsKeyboardFocusWithin)
                {
                    item.Focus();
                }

                var focusedElement = Keyboard.FocusedElement as FrameworkElement;

                originTabControl.Items.Remove(item);
                newTab.TabControl.Items.Add(item);

                // This may not work, depending on template behavior (recreation of elements?)
                if (focusedElement != null)
                {
                    RoutedEventHandler reacquireFocus = null;
                    reacquireFocus = (s, e) =>
                    {
                        focusedElement.Focus();
                        focusedElement.Loaded -= reacquireFocus;
                    };
                    focusedElement.Loaded += reacquireFocus;
                }
            }
            else
            {
                Debug.Fail("Only ActivatableTabItem objects should be added to ActivatableTabControls");
            }

            ActivateTabNode(newTab);
        }
 void SetNewDropTarget(ActivatableTabControl newTargetControl)
 {
     RebuildDropTargetWindow(newTargetControl);
     this.controlUnderCursor = newTargetControl;
 }
        void IActivationSite.NotifyActivation(object child)
        {
            var tabControl = child as ActivatableTabControl;

            if ((tabControl != null) && (this.ParentSite != null))
            {
                this.lastActiveChildSite = tabControl;
                this.ParentSite.NotifyActivation(this);
            }
        }
        void IActivationSite.TunnelActivation()
        {
            if (this.lastActiveChildSite == null)
            {
                if (this.host != null)
                {
                    // We need to pick one.  Pick the biggest one by area.
                    var slotTable = new Dictionary<string, ActivatableTabControl>();

                    foreach (var child in this.host.Children.OfType<ActivatableTabControl>())
                    {
                        slotTable[SlotPanel.GetSlotName(child)] = child;
                    }

                    var pair = slotTable.OrderBy(kvp => kvp.Value.ActualHeight * kvp.Value.ActualWidth).FirstOrDefault();

                    this.lastActiveChildSite = pair.Value;
                }
            }

            if (this.lastActiveChildSite != null)
            {
                this.lastActiveChildSite.TunnelActivation();
            }
        }
        public void AddItemToControl(ActivatableTabItem item, ActivatableTabControl tabControl, bool giveFocus)
        {
            Debug.Assert(tabControl.FindParent<SplitTabsControl>() == this, "Can't add item to a tab control not owned by this split tabs control!");

            if (giveFocus)
            {
                RoutedEventHandler loadedHandler = null;

                loadedHandler = (s, e2) =>
                {
                    item.Focus();
                    item.Loaded -= loadedHandler;
                };
                item.Loaded += loadedHandler;
            }

            tabControl.ParentSite = this;
            tabControl.Items.Add(item);
        }
        void RebuildDropTargetWindow(ActivatableTabControl targetControl)
        {
            if (this.dropTarget == null)
            {
                this.dropTarget = new TabDropTargetWindow()
                {
                    AllowsTransparency = true,      // It would be nice to be able to set these in the style...
                    WindowStyle = WindowStyle.None,
                };
            }

            bool controlDown = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);

            if (targetControl != null && !controlDown)
            {
                TabNode node = targetControl.TabNode;

                if (!this.dropTarget.IsVisible || this.dropTarget.TargetNode != node)
                {
                    this.dropTarget.Hide();
                    this.dropTarget.UpdateLayout();

                    var pos = new Point(0, 0);
                    pos = targetControl.PointToScreenIndependent(pos);

                    this.dropTarget.Left = pos.X;
                    this.dropTarget.Top = pos.Y;
                    this.dropTarget.Width = targetControl.ActualWidth;
                    this.dropTarget.Height = targetControl.ActualHeight;

                    var parent = node.Parent;
                    var grandparent = parent == null ? null : parent.Parent;

                    this.dropTarget.VerticalParentNode = parent;
                    this.dropTarget.HorizontalParentNode = parent;

                    if (grandparent != null && parent.Slot.Orientation == Orientation.Vertical)
                    {
                        this.dropTarget.VerticalParentNode = grandparent;
                    }
                    else if (grandparent != null && parent.Slot.Orientation == Orientation.Horizontal)
                    {
                        this.dropTarget.HorizontalParentNode = grandparent;
                    }

                    this.dropTarget.TargetNode = node;
                    this.dropTarget.IsTabbedSpotVisible = true;
                    this.dropTarget.AreDockSpotsVisible = (targetControl != this.sourceControl || this.sourceControl.Items.Count > 1);
                    this.dropTarget.Show();
                    this.dropTarget.UpdateLayout();
                }
            }
            else
            {
                this.dropTarget.Hide();
            }
        }
 void SetNewDropTarget(ActivatableTabControl newTargetControl)
 {
     RebuildDropTargetWindow(newTargetControl);
     this.controlUnderCursor = newTargetControl;
 }