Index: Core/Common/src/Core.Common.Gui/Core.Common.Gui.csproj =================================================================== diff -u -r36fcd01e8a56df5d658ee4bbd4ad48e3d34d5722 -r16b0a9d843ae378f8fdf8b052e46c8894302710d --- Core/Common/src/Core.Common.Gui/Core.Common.Gui.csproj (.../Core.Common.Gui.csproj) (revision 36fcd01e8a56df5d658ee4bbd4ad48e3d34d5722) +++ Core/Common/src/Core.Common.Gui/Core.Common.Gui.csproj (.../Core.Common.Gui.csproj) (revision 16b0a9d843ae378f8fdf8b052e46c8894302710d) @@ -242,7 +242,6 @@ SplashScreen.xaml - Index: Core/Common/src/Core.Common.Gui/Forms/MainWindow/IMainWindow.cs =================================================================== diff -u -rb743d495d10779d51c8f75b7cb04b5babb4b226f -r16b0a9d843ae378f8fdf8b052e46c8894302710d --- Core/Common/src/Core.Common.Gui/Forms/MainWindow/IMainWindow.cs (.../IMainWindow.cs) (revision b743d495d10779d51c8f75b7cb04b5babb4b226f) +++ Core/Common/src/Core.Common.Gui/Forms/MainWindow/IMainWindow.cs (.../IMainWindow.cs) (revision 16b0a9d843ae378f8fdf8b052e46c8894302710d) @@ -21,6 +21,7 @@ using System.Windows.Forms; using Core.Common.Gui.Forms.MessageWindow; +using Core.Common.Gui.Forms.ViewManager; namespace Core.Common.Gui.Forms.MainWindow { @@ -40,6 +41,11 @@ IMessageWindow MessageWindow { get; } /// + /// Gets the docking manager control. + /// + DockingManagerControl DockingManagerControl { get; } + + /// /// Gets or sets the title of the main user interface. /// string Title { get; set; } Index: Core/Common/src/Core.Common.Gui/Forms/MainWindow/MainWindow.xaml.cs =================================================================== diff -u -r36fcd01e8a56df5d658ee4bbd4ad48e3d34d5722 -r16b0a9d843ae378f8fdf8b052e46c8894302710d --- Core/Common/src/Core.Common.Gui/Forms/MainWindow/MainWindow.xaml.cs (.../MainWindow.xaml.cs) (revision 36fcd01e8a56df5d658ee4bbd4ad48e3d34d5722) +++ Core/Common/src/Core.Common.Gui/Forms/MainWindow/MainWindow.xaml.cs (.../MainWindow.xaml.cs) (revision 16b0a9d843ae378f8fdf8b052e46c8894302710d) @@ -134,6 +134,14 @@ } } + public DockingManagerControl DockingManagerControl + { + get + { + return dockingManagerControl; + } + } + /// /// Gets or sets a value indicating whether or not the main user interface is visible. /// Fisheye: Tag 16b0a9d843ae378f8fdf8b052e46c8894302710d refers to a dead (removed) revision in file `Core/Common/src/Core.Common.Gui/Forms/ViewManager/AvalonDockDockingManager.cs'. Fisheye: No comparison available. Pass `N' to diff? Index: Core/Common/src/Core.Common.Gui/Forms/ViewManager/DockingManagerControl.xaml.cs =================================================================== diff -u -r36fcd01e8a56df5d658ee4bbd4ad48e3d34d5722 -r16b0a9d843ae378f8fdf8b052e46c8894302710d --- Core/Common/src/Core.Common.Gui/Forms/ViewManager/DockingManagerControl.xaml.cs (.../DockingManagerControl.xaml.cs) (revision 36fcd01e8a56df5d658ee4bbd4ad48e3d34d5722) +++ Core/Common/src/Core.Common.Gui/Forms/ViewManager/DockingManagerControl.xaml.cs (.../DockingManagerControl.xaml.cs) (revision 16b0a9d843ae378f8fdf8b052e46c8894302710d) @@ -19,19 +19,111 @@ // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. -using System.Windows.Controls; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Windows; +using System.Windows.Forms; +using System.Windows.Forms.Integration; +using System.Windows.Input; +using System.Windows.Media.Imaging; +using Core.Common.Controls.Views; using Xceed.Wpf.AvalonDock; +using Xceed.Wpf.AvalonDock.Layout; +using MouseEventArgs = System.Windows.Forms.MouseEventArgs; +using Orientation = System.Windows.Controls.Orientation; +using Point = System.Drawing.Point; namespace Core.Common.Gui.Forms.ViewManager { /// - /// Interaction logic for DockingManagerControl.xaml + /// Provides view docking management based on the 'Avalon Docking framework'. /// - public partial class DockingManagerControl : UserControl + public partial class DockingManagerControl : IDockingManager { + private IView focussedView; + private readonly LayoutAnchorablePane leftPane; + private readonly LayoutAnchorablePane bottomPane; + private readonly LayoutAnchorablePane rightPane; + private readonly LayoutDocumentPane layoutDocumentPane; + + public event EventHandler ViewClosed; + public event EventHandler ActiveContentChanged; + public event Action ViewSelectionMouseDown; + private readonly List documentViews; + private readonly List toolViews; + private readonly List hostControls; + + /// + /// Initializes a new instance of the class. + /// public DockingManagerControl() { InitializeComponent(); + + leftPane = new LayoutAnchorablePane(); + bottomPane = new LayoutAnchorablePane(); + rightPane = new LayoutAnchorablePane(); + layoutDocumentPane = new LayoutDocumentPane(); + + dockingManager.Layout.RootPanel = new LayoutPanel + { + Orientation = Orientation.Horizontal, + Children = + { + new LayoutAnchorablePaneGroup + { + Orientation = Orientation.Vertical, + DockWidth = new GridLength(260), + Children = + { + leftPane + } + }, + new LayoutPanel + { + Orientation = Orientation.Vertical, + Children = + { + new LayoutDocumentPaneGroup + { + Children = + { + layoutDocumentPane + } + }, + new LayoutAnchorablePaneGroup + { + DockHeight = new GridLength(150), + Children = + { + bottomPane + } + } + } + }, + new LayoutAnchorablePaneGroup + { + Orientation = Orientation.Vertical, + DockWidth = new GridLength(220), + Children = + { + rightPane + } + } + } + }; + + documentViews = new List(); + toolViews = new List(); + hostControls = new List(); + + dockingManager.MouseDown += DockingManagerMouseDown; + dockingManager.ActiveContentChanged += DockingManagerOnActiveContentChanged; } public DockingManager DockingManager @@ -41,5 +133,342 @@ return dockingManager; } } + + public IEnumerable DocumentViews + { + get + { + return documentViews; + } + } + + public IEnumerable ToolViews + { + get + { + return toolViews; + } + } + + public void AddDocumentView(IView view) + { + CheckForDuplicateView(view); + + var control = (Control)view; + var hostControl = new WindowsFormsHost + { + Child = control + }; + var layoutDocument = new LayoutDocument + { + Title = view.Text, + Content = hostControl, + ContentId = view.Text + }; + + documentViews.Add(view); + hostControls.Add(hostControl); + layoutDocumentPane.Children.Add(layoutDocument); + + control.TextChanged += ControlOnTextChanged; + layoutDocument.Closed += OnLayoutDocumentClosed; + } + + public void AddToolView(IView view, ViewLocation location) + { + CheckForDuplicateView(view); + + var control = (Control)view; + var hostControl = new WindowsFormsHost + { + Child = control + }; + var layoutAnchorable = new LayoutAnchorable + { + Content = hostControl, + Title = view.Text, + ContentId = view.Text + }; + + toolViews.Add(view); + hostControls.Add(hostControl); + + if (location == ViewLocation.Left) + { + leftPane.Children.Add(layoutAnchorable); + } + else if (location == ViewLocation.Bottom) + { + bottomPane.Children.Add(layoutAnchorable); + } + else if (location == ViewLocation.Right) + { + rightPane.Children.Add(layoutAnchorable); + } + + layoutAnchorable.Hiding += OnLayoutAnchorableHiding; + } + + public void Remove(IView view) + { + if (documentViews.Contains(view)) + { + GetLayoutContent(view).Close(); + } + else if (toolViews.Contains(view)) + { + GetLayoutContent(view).Hide(); + } + } + + public void SetToolTip(IView view, string tooltip) + { + var layoutContent = GetLayoutContent(view); + if (layoutContent != null) + { + layoutContent.ToolTip = tooltip; + } + } + + public void SetImage(IView view, Image image) + { + var layoutContent = GetLayoutContent(view); + if (layoutContent != null) + { + layoutContent.IconSource = BitmapImageFromBitmap(image); + } + } + + public void SetFocusToView(IView view) + { + if (documentViews.Contains(view)) + { + var layoutDocument = GetLayoutContent(view); + if (!layoutDocument.IsActive) + { + dockingManager.Layout.ActiveContent = layoutDocument; + } + } + else if (toolViews.Contains(view)) + { + var layoutAnchorable = GetLayoutContent(view); + if (!layoutAnchorable.IsActive) + { + dockingManager.Layout.ActiveContent = layoutAnchorable; + } + } + } + + private void CheckForDuplicateView(IView view) + { + if (documentViews.Contains(view) || toolViews.Contains(view)) + { + throw new InvalidOperationException(Properties.Resources.AvalonDockDockingManager_Add_View_was_already_added_activate_it_instead_of_add); + } + } + + private void DockingManagerMouseDown(object sender, MouseButtonEventArgs e) + { + if (e.MiddleButton == MouseButtonState.Pressed) + { + return; // view already being closed by avalon dock itself + } + + if (ViewSelectionMouseDown == null) + { + return; + } + + var layoutDocument = GetLayoutDocumentFromUIElement(Mouse.DirectlyOver); + if (layoutDocument == null) + { + return; + } + + var view = ((WindowsFormsHost)layoutDocument.Content).Child as IView; + if (view == null) + { + return; + } + + var position = ToViewCoordinate(e, view); + ViewSelectionMouseDown(view, new MouseEventArgs(GetMouseButtons(e.LeftButton, e.MiddleButton, e.RightButton), + 1, position.X, position.Y, 0), view); + } + + private static Point ToViewCoordinate(MouseButtonEventArgs e, IView view) + { + var screen = e.GetPosition(null); + return ((Control)view).PointToClient(new Point((int)screen.X, (int)screen.Y)); + } + + private static LayoutDocument GetLayoutDocumentFromUIElement(IInputElement inputElement) + { + var frameworkElement = inputElement as FrameworkElement; + if (frameworkElement != null) + { + return frameworkElement.DataContext as LayoutDocument; + } + + var frameworkContentElement = inputElement as FrameworkContentElement; + if (frameworkContentElement != null) + { + return frameworkContentElement.DataContext as LayoutDocument; + } + + return null; + } + + private static MouseButtons GetMouseButtons(MouseButtonState leftButton, MouseButtonState middleButton, MouseButtonState rightButton) + { + if (leftButton == MouseButtonState.Pressed) + { + return MouseButtons.Left; + } + if (middleButton == MouseButtonState.Pressed) + { + return MouseButtons.Middle; + } + if (rightButton == MouseButtonState.Pressed) + { + return MouseButtons.Right; + } + return MouseButtons.None; + } + + private void DockingManagerOnActiveContentChanged(object sender, EventArgs eventArgs) + { + if (focussedView != null) + { + ControlHelper.UnfocusActiveControl(focussedView as IContainerControl); + } + + focussedView = GetView(dockingManager.ActiveContent); + + if (ActiveContentChanged != null) + { + ActiveContentChanged(this, new ActiveViewChangeEventArgs(focussedView)); + } + } + + private static BitmapImage BitmapImageFromBitmap(Image bitmap) + { + if (bitmap == null) + { + return null; + } + + using (var memory = new MemoryStream()) + { + var bitmapImage = new BitmapImage(); + bitmap.Save(memory, ImageFormat.Png); + memory.Position = 0; + bitmapImage.DecodePixelHeight = bitmap.Height; + bitmapImage.DecodePixelWidth = bitmap.Width; + bitmapImage.BeginInit(); + bitmapImage.StreamSource = memory; + bitmapImage.CacheOption = BitmapCacheOption.OnLoad; + bitmapImage.EndInit(); + bitmapImage.Freeze(); + return bitmapImage; + } + } + + private void CleanupHostControl(IView view) + { + var hostControl = hostControls.First(hc => hc.Child == view); + + hostControl.Child = null; // Prevent views from getting disposed here by clearing the child + hostControl.Dispose(); + + hostControls.Remove(hostControl); + } + + private void ControlOnTextChanged(object sender, EventArgs eventArgs) + { + var view = sender as IView; + if (view == null) + { + return; + } + + var layoutDocument = GetLayoutContent(view); + if (layoutDocument == null) + { + return; + } + + layoutDocument.Title = view.Text; + } + + # region Helper methods + + private T GetLayoutContent(IView view) where T : LayoutContent + { + return dockingManager.Layout.Descendents() + .OfType() + .FirstOrDefault(d => GetView(d.Content) == view); + } + + private static IView GetView(object content) + { + var host = content as WindowsFormsHost; + if (host != null) + { + return host.Child as IView; + } + + return null; + } + + # endregion + + # region Logic for handling view close actions coming from DockManager + + private void OnLayoutDocumentClosed(object sender, EventArgs e) + { + var layoutDocument = (LayoutDocument)sender; + + layoutDocument.Closed -= OnLayoutDocumentClosed; + + OnViewClosed(GetView(layoutDocument.Content)); + } + + private void OnLayoutAnchorableHiding(object sender, CancelEventArgs e) + { + var layoutAnchorable = (LayoutAnchorable)sender; + + layoutAnchorable.Hiding -= OnLayoutAnchorableHiding; + + OnViewClosed(GetView(layoutAnchorable.Content)); + } + + private void OnViewClosed(IView view) + { + var control = (Control)view; + + if (documentViews.Contains(view)) + { + control.TextChanged -= ControlOnTextChanged; + + documentViews.Remove(view); + } + else + { + toolViews.Remove(view); + } + + CleanupHostControl(view); + + if (ViewClosed != null) + { + ViewClosed(this, new ViewClosedEventArgs + { + View = view + }); + } + } + + # endregion } -} +} \ No newline at end of file Index: Core/Common/src/Core.Common.Gui/GuiCore.cs =================================================================== diff -u -r36fcd01e8a56df5d658ee4bbd4ad48e3d34d5722 -r16b0a9d843ae378f8fdf8b052e46c8894302710d --- Core/Common/src/Core.Common.Gui/GuiCore.cs (.../GuiCore.cs) (revision 36fcd01e8a56df5d658ee4bbd4ad48e3d34d5722) +++ Core/Common/src/Core.Common.Gui/GuiCore.cs (.../GuiCore.cs) (revision 16b0a9d843ae378f8fdf8b052e46c8894302710d) @@ -70,7 +70,7 @@ private bool runFinished; private bool isExiting; - private readonly AvalonDockDockingManager dockingManager; + private readonly DockingManagerControl dockingManager; /// /// Initializes a new instance of the class. @@ -115,7 +115,7 @@ isAlreadyRunningInstanceOfIGui = true; instanceCreationStackTrace = new StackTrace().ToString(); - dockingManager = new AvalonDockDockingManager(this.mainWindow.dockingManagerControl.DockingManager); + dockingManager = mainWindow.DockingManagerControl; Plugins = new List(); Index: Core/Common/test/Core.Common.Gui.Test/Core.Common.Gui.Test.csproj =================================================================== diff -u -r3f4c957c64429fe5a5b09a15ab0e5c893e899d17 -r16b0a9d843ae378f8fdf8b052e46c8894302710d --- Core/Common/test/Core.Common.Gui.Test/Core.Common.Gui.Test.csproj (.../Core.Common.Gui.Test.csproj) (revision 3f4c957c64429fe5a5b09a15ab0e5c893e899d17) +++ Core/Common/test/Core.Common.Gui.Test/Core.Common.Gui.Test.csproj (.../Core.Common.Gui.Test.csproj) (revision 16b0a9d843ae378f8fdf8b052e46c8894302710d) @@ -123,7 +123,6 @@ - UserControl Fisheye: Tag 16b0a9d843ae378f8fdf8b052e46c8894302710d refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/ViewManager/AvalonDockDockingManagerTest.cs'. Fisheye: No comparison available. Pass `N' to diff?