<UserControl x:Class="Tango.MachineStudio.Common.Controls.MdiContainerControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:local="clr-namespace:Tango.MachineStudio.Common.Controls"
xmlns:converters="clr-namespace:Tango.MachineStudio.Common.Converters"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<converters:PointToMarginConverter x:Key="PointToMarginConverter"></converters:PointToMarginConverter>
</UserControl.Resources>
<Grid>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl,Mode=FindAncestor},Path=ItemsSource}" x:Name="itemsControl">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas x:Name="canvas" HorizontalAlignment="Left" VerticalAlignment="Top"></Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="FrameworkElement">
<Setter Property="Canvas.Left" Value="{Binding Location.X}"></Setter>
<Setter Property="Canvas.Top" Value="{Binding Location.Y}"></Setter>
<EventSetter Event="PreviewMouseDown" Handler="OnControlMouseDown"></EventSetter>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="10" />
</Grid.Effect>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="277*"/>
</Grid.RowDefinitions>
<Grid Background="{StaticResource AccentColorBrush}">
<Thumb Opacity="0" DragDelta="OnControlDragging" Tag="{Binding}"></Thumb>
<DockPanel LastChildFill="False">
<StackPanel IsHitTestVisible="False" DockPanel.Dock="Left" VerticalAlignment="Center" Orientation="Horizontal" Margin="5 0 0 0">
<materialDesign:PackIcon Kind="{Binding Icon}" Foreground="White"></materialDesign:PackIcon>
<TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Foreground="White" Text="{Binding Header}"></TextBlock>
</StackPanel>
<StackPanel DockPanel.Dock="Right" VerticalAlignment="Center" Orientation="Horizontal">
<Button Foreground="White" Style="{StaticResource MaterialDesignFlatButton}" ToolTip="Close" Width="24" Height="24" Padding="0" Click="OnControlClosed" Tag="{Binding}">
<materialDesign:PackIcon Kind="WindowClose" />
</Button>
</StackPanel>
</DockPanel>
</Grid>
<Grid Grid.Row="1" MinWidth="100" MinHeight="100">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<ContentPresenter Content="{Binding View}"></ContentPresenter>
</ScrollViewer>
<Thumb HorizontalAlignment="Right" VerticalAlignment="Stretch" Opacity="0" Width="5" Cursor="SizeWE" DragDelta="OnControlusing System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tango.Core.Helpers;
using Tango.MachineStudio.Common.StudioApplication;
using Tango.MachineStudio.Common.Navigation;
using System.Reflection;
using System.Collections;
using Tango.Core;
using Tango.Logging;
using Tango.MachineStudio.Common.Modules;
using Tango.MachineStudio.Common;
using Tango.Settings;
using System.Windows;
using Tango.Integration.ExternalBridge;
using Tango.MachineStudio.Common.EventLogging;
using Tango.BL.Enumerations;
using Tango.Core.DI;
using Tango.BL.Entities;
using Tango.BL;
using Tango.MachineStudio.UI.ViewModels;
using Tango.MachineStudio.Common.Notifications;
using Tango.MachineStudio.UI.Views;
using Tango.Integration.Operation;
using Tango.MachineStudio.UI.Windows;
namespace Tango.MachineStudio.UI.StudioApplication
{
/// <summary>
/// Represents the default Machine Studio <see cref="IStudioApplicationManager">Application Manager</see>.
/// </summary>
/// <seealso cref="Tango.Core.ExtendedObject" />
/// <seealso cref="Tango.MachineStudio.Common.StudioApplication.IStudioApplicationManager" />
public class DefaultStudioApplicationManager : ExtendedObject, IStudioApplicationManager
{
private INavigationManager _navigationManager;
private IStudioModuleLoader _moduleLoader;
private INotificationProvider _notification;
private List<Window> _openedWindows;
private List<IStudioViewModel> _notified_view_models;
/// <summary>
/// Occurs when the application is ready.
/// </summary>
public event EventHandler ApplicationReady;
/// <summary>
/// Initializes a new instance of the <see cref="DefaultStudioApplicationManager" /> class.
/// </summary>
/// <param name="navigationManager">The navigation manager.</param>
public DefaultStudioApplicationManager(INavigationManager navigationManager, IStudioModuleLoader moduleLoader, INotificationProvider notification)
{
_moduleLoader = moduleLoader;
_navigationManager = navigationManager;
_notification = notification;
_openedWindows = new List<Window>();
_notified_view_models = new List<IStudioViewModel>();
Application.Current.MainWindow.ContentRendered += (_, __) =>
{
TangoIOC.Default.GetAllInstancesByBase<IStudioViewModel>().ToList().ForEach(x => x.OnApplicationStarted());
};
}
/// <summary>
/// Gets a value indicating whether Machine Studio is shutting down.
/// </summary>
public bool IsShuttingDown { get; private set; }
/// <summary>
/// Occurs when the connected machine property has changed.
/// </summary>
public event EventHandler<IExternalBridgeClient> ConnectedMachineChanged;
/// <summary>
/// Gets or sets the machine.
/// </summary>
public Machine Machine { get; private set; }
private IExternalBridgeClient _connectedMachine;
/// <summary>
/// Gets or sets the currently connected machine if any.
/// </summary>
public IExternalBridgeClient ConnectedMachine
{
get { return _connectedMachine; }
private set
{
if (_connectedMachine != value)
{
_connectedMachine = value;
RaisePropertyChangedAuto();
RaisePropertyChanged(nameof(IsMachineConnected));
RaisePropertyChanged(nameof(IsMachineConnectedViaTCP));
if (_connectedMachine != null)
{
_connectedMachine.StateChanged -= ConnectedMachine_StateChanged;
_connectedMachine.StateChanged += ConnectedMachine_StateChanged;
}
ConnectedMachineChanged?.Invoke(this, _connectedMachine);
}
}
}
/// <summary>
/// Gets a value indicating whether the <see cref="P:Tango.MachineStudio.Common.StudioApplication.IStudioApplicationManager.ConnectedMachine" /> is valid and connected through TCP/IP.
/// </summary>
public bool IsMachineConnectedViaTCP
{
get { return IsMachineConnected && ConnectedMachine is ExternalBridgeTcpClient; }
}
/// <summary>
/// Handles the <see cref="ConnectedMachine"/> state changed event.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The e.</param>
private void ConnectedMachine_StateChanged(object sender, Transport.TransportComponentState e)
{
if (e == Transport.TransportComponentState.Disconnected || e == Transport.TransportComponentState.Failed)
{
ConnectedMachine = null;
if (e == Transport.TransportComponentState.Failed)
{
String failed_reason = (sender as IMachineOperator).FailedStateException.Message;
ConnectionLostViewVM vm = new ConnectionLostViewVM()
{
Exception = failed_reason
};
InvokeUI(() =>
{
_notification.ShowModalDialog<ConnectionLostViewVM, ConnectionLostView>(vm, (x) => { }, () => { });
});
}
}
}
/// <summary>
/// Gets a value indicating whether the <see cref="P:Tango.MachineStudio.Common.StudioApplication.IStudioApplicationManager.ConnectedMachine" /> is valid.
/// </summary>
public bool IsMachineConnected
{
get { return ConnectedMachine != null; }
}
/// <summary>
/// Gets the machine studio application version.
/// </summary>
public Version Version
{
get
{
return AssemblyHelper.GetCurrentAssemblyVersion();
}
}
/// <summary>
/// Shutdown the application.
/// </summary>
public async void ShutDown()
{
if (IsShuttingDown) return;
IsShuttingDown = true;
try
{
Rect r = new Rect(
MainWindow.Instance.Left,
MainWindow.Instance.Top,
MainWindow.Instance.Width,
MainWindow.Instance.Height);
await Task.Factory.StartNew(async () =>
{
try
{
//Do Shutdown Procedures...
foreach (var vm in TangoIOC.Default.GetAllInstancesByBase<IStudioViewModel>())
{
try
{
var result = await vm.OnShutdownRequest();
if (!result)
{
IsShuttingDown = false;
return;
}
}
catch (Exception ex)
{
LogManager.Log(ex, "Error on shutdown request with " + vm.GetType().Name);
}
}
foreach (var vm in TangoIOC.Default.GetAllInstancesByBase<IStudioViewModel>())
{
vm.OnShuttingDown();
}
var settings = SettingsManager.Default.GetOrCreate<MachineStudioSettings>();
settings.LastBounds = r;
settings.StudioModulesBounds.Clear();
foreach (var window in _openedWindows.OfType<Windows.ModuleWindow>())
{
window.Invoke(() =>
{
var context = window.ModuleContext;
if (context != null)
{
settings.StudioModulesBounds.Add(new MachineStudioSettings.StudioModuleBounds()
{
Bounds = window.RestoreBounds,
State = window.WindowState,
Name = context.Module.Name,
});
}
});
}
var mainViewVM = TangoIOC.Default.GetInstance<MainViewVM>();
settings.LastMainModuleName = mainViewVM.CurrentModule != null ? mainViewVM.CurrentModule.Name : null;
try
{
SettingsManager.Default.Save();
}
catch (Exception ex)
{
LogManager.Log(ex, "Error saving settings.");
}
await _navigationManager.NavigateTo(NavigationView.ShutdownView);
Thread.Sleep(1500);
foreach (var window in _openedWindows)
{
ThreadsHelper.InvokeUI(() =>
{
window.Close();
});
}
try
{
if (ConnectedMachine != null)
{
ConnectedMachine.Disconnect().Wait();
}
}
catch (Exception ex)
{
LogManager.Log(ex, "Error disconnecting from machine.");
}
var eventLogger = TangoIOC.Default.GetInstance<IEventLogger>();
if (eventLogger != null)
{
eventLogger.Log(EventTypes.APPLICATION_TERMINATED, "Application Terminated!");
eventLogger.FlushAll();
}
Thread.Sleep(1500);
Environment.Exit(0);
}
catch
{
Environment.Exit(0);
}
});
}
catch (Exception ex)
{
IsShuttingDown = false;
LogManager.Log(ex, "An error occurred while shutting down machine studio.");
}
}
/// <summary>
/// Notify the application manager about an external opened window.
/// When application exists. All registered windows will be closed.
/// </summary>
/// <param name="window">The window.</param>
public void RegisterOpenedWindow(Window window)
{
_openedWindows.Add(window);
window.Closed += (x, y) => { _openedWindows.Remove(window); };
}
public bool IsModuleInNewWindow(IStudioModule module)
{
return _openedWindows.Exists(x => (x as ModuleWindow).ModuleContext.Module == module);
}
/// <summary>
/// Gets the core libraries version.
/// </summary>
public Version CoreVersion
{
get
{
return typeof(ExtendedObject).Assembly.GetName().Version;
}
}
/// <summary>
/// Gets the build date.
/// </summary>
public string BuildDate
{
get
{
return AssemblyHelper.GetCurrentAssemblyBuildDate().ToShortDateString();
}
}
/// <summary>
/// Gets the change log.
/// </summary>
public string ChangeLog
{
get
{
return EmbeddedResourceHelper.GetEmbeddedResourceText("Tango.MachineStudio.UI.ChangeLog.txt");
}
}
/// <summary>
/// Raises the application ready event.
/// </summary>
public void NotifyApplicationReady()
{
TangoIOC.Default.GetAllInstancesByBase<IStudioViewModel>().ToList().ForEach(x =>
{
if (!_notified_view_models.Contains(x))
{
x.OnApplicationReady();
_notified_view_models.Add(x);
}
});
ApplicationReady?.Invoke(this, new EventArgs());
}
/// <summary>
/// Sets the connected machine.
/// </summary>
/// <param name="connectedMachine">The connected machine.</param>
public void SetConnectedMachine(IExternalBridgeClient connectedMachine)
{
if (connectedMachine != null)
{
Machine = ObservablesStaticCollections.Instance.Machines.SingleOrDefault(x => x.SerialNumber == connectedMachine.SerialNumber);
if (Machine == null)
{
throw new NullReferenceException($"The specified machine '{connectedMachine.SerialNumber}' could not be found on the database.");
}
ConnectedMachine = connectedMachine;
ConnectedMachine.SetMachine(Machine);
var settings = SettingsManager.Default.GetOrCreate<MachineStudioSettings>();
ConnectedMachine.JobUploadStrategy = settings.JobUploadStrategy;
}
else
{
Machine = null;
ConnectedMachine = null;
}
}
}
}