aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/PPC/Tango.PPC.UI/Navigation/DefaultNavigationManager.cs
blob: fe3cabcc1f3e4fe0c3e6dec69b557cd806e0d2a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.Core.DI;
using Tango.PPC.Browser.ViewModels;

namespace Tango.PPC.Browser
{
    public static class ViewModelLocator
    {
        /// <summary>
        /// Initializes a new instance of the ViewModelLocator class.
        /// </summary>
        static ViewModelLocator()
        {
            TangoIOC.Default.Register<BrowserViewVM>();
        }

        /// <summary>
        /// Gets the main view VM.
        /// </summary>
        public static BrowserViewVM BrowserViewVM
        {
            get
            {
                return TangoIOC.Default.GetInstance<BrowserViewVM>();
            }
        }
    }
}
='#n299'>299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using Tango.Core;
using Tango.Core.Commands;
using Tango.PPC.Common;
using Tango.PPC.Common.Modules;
using Tango.PPC.Common.Navigation;
using Tango.PPC.Common.Threading;
using Tango.PPC.UI.Views;
using Tango.SharedUI.Controls;

namespace Tango.PPC.UI.Navigation
{
    /// <summary>
    /// Represents the default PPC navigation manager.
    /// </summary>
    /// <seealso cref="Tango.PPC.Common.Navigation.INavigationManager" />
    public class DefaultNavigationManager : ExtendedObject, INavigationManager
    {
        private event Action<Object, Object> NavigationCycleCompleted;

        private IDispatcherProvider _dispatcherProvider;
        private IPPCModuleLoader _moduleLoader;
        private Object _currentVM;
        private String _lastFullPath;
        private bool _preventHistory;
        private bool _navigating_back;

        private Stack<String> _navigationHistory;

        /// <summary>
        /// Gets the current view model.
        /// </summary>
        public PPCViewModel CurrentVM
        {
            get { return _currentVM as PPCViewModel; }
        }

        private IPPCModule _currentModule;
        /// <summary>
        /// Gets or sets the current module.
        /// </summary>
        public IPPCModule CurrentModule
        {
            get { return _currentModule; }
            private set { _currentModule = value; RaisePropertyChangedAuto(); }
        }

        /// <summary>
        /// Navigates to the previous view.
        /// </summary>
        public RelayCommand NavigateBackCommand { get; private set; }

        /// <summary>
        /// Navigates to the specified full path in command parameter.
        /// </summary>
        public RelayCommand<String> NavigateToCommand { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="DefaultNavigationManager"/> class.
        /// </summary>
        /// <param name="moduleLoader">The module loader.</param>
        public DefaultNavigationManager(IPPCModuleLoader moduleLoader, IDispatcherProvider dispatcherProvider)
        {
            _navigationHistory = new Stack<String>();
            _moduleLoader = moduleLoader;

            NavigateToCommand = new RelayCommand<string>(async (x) => await NavigateTo(x));
            NavigateBackCommand = new RelayCommand(async () => await NavigateBack());

            _dispatcherProvider = dispatcherProvider;
        }

        /// <summary>
        /// Navigates to the specified PPC view.
        /// </summary>
        /// <param name="view">The view.</param>
        public Task<bool> NavigateTo(NavigationView view, bool pushToHistory = true)
        {
            if (view == NavigationView.HomeModule)
            {
                _navigationHistory.Clear();
                _lastFullPath = null;

                var firstModule = _moduleLoader.UserModules.FirstOrDefault();

                if (firstModule != null)
                {
                    var moduleAtt = firstModule.GetType().GetCustomAttribute<PPCModuleAttribute>();

                    if (moduleAtt != null)
                    {
                        return NavigateTo(firstModule.GetType(), pushToHistory, moduleAtt.HomeViewName);
                    }
                    else
                    {
                        return NavigateTo(firstModule.GetType(), pushToHistory);
                    }
                }
                else
                {
                    return NavigateTo(NavigationView.NoPermissionsView);
                }
            }
            else
            {

                LogManager.Log($"Navigating to: {view.ToString()}...");
                MainView.Instance.NavigationControl.NavigateTo(view.ToString());
                return Task.FromResult(true);
            }
        }

        /// <summary>
        /// Navigates to the specified PPC view with the specified receive object.
        /// </summary>
        /// <param name="view">The view.</param>
        /// <param name="obj"></param>
        /// <param name="pushToHistory"></param>
        /// <returns></returns>
        public Task<bool> NavigateWithObject<TPass>(NavigationView view, TPass obj, bool pushToHistory = true)
        {
            LogManager.Log($"Navigating to: {view.ToString()}, with object {typeof(TPass).Name}...");
            MainView.Instance.NavigationControl.NavigateTo(view.ToString());
            INavigationObjectReceiver<TPass> receiver = MainView.Instance.NavigationControl.Elements.FirstOrDefault(x => (x.GetType().Name == view.ToString() || NavigationControl.GetNavigationName(x) == view.ToString()) && x.DataContext is INavigationObjectReceiver<TPass>).DataContext as INavigationObjectReceiver<TPass>;

            if (receiver != null)
            {
                receiver.OnNavigatedToWithObject(obj);
            }

            return Task.FromResult(true);
        }

        /// <summary>
        /// Navigates to the specified module.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public Task<bool> NavigateTo<T>(bool pushToHistory = true) where T : IPPCModule
        {
            return NavigateTo(typeof(T));
        }

        /// <summary>
        /// Navigates to the specified module using the view path (e.g MainView.JobsView).
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="viewPath">The view path.</param>
        public Task<bool> NavigateTo<T>(string viewPath, bool pushToHistory = true) where T : IPPCModule
        {
            return NavigateTo<T>(pushToHistory, viewPath.Split('.'));
        }

        /// <summary>
        /// Navigates to the specified module using the view path (e.g MainView,JobsView).
        /// This method makes it easy to do stuff like NavigateTo(nameof(MainView),nameof(JobsView));
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="viewPath">The view path.</param>
        public Task<bool> NavigateTo<T>(bool pushToHistory = true, params String[] viewPath) where T : IPPCModule
        {
            return NavigateTo(typeof(T), pushToHistory, viewPath);
        }

        /// <summary>
        /// Navigates to the specified module and view by full path (e.g Jobs.JobsView).
        /// </summary>
        /// <param name="fullPath">The full path.</param>
        public async Task<bool> NavigateTo(String fullPath, bool pushToHistory = true)
        {
            String[] path = fullPath.Split('.');
            var module = _moduleLoader.UserModules.SingleOrDefault(x => x.GetType().Name == path[0] || x.Name == path[0]);

            if (path.Length == 1 && path[0] == CurrentModule.Name) return true;

            LogManager.Log($"Navigating to: {fullPath}...");

            var fromVM = _currentVM;

            if (_currentVM != null && _currentVM is INavigationBlocker)
            {
                if (_navigating_back)
                {
                    if (!await (_currentVM as INavigationBlocker).OnNavigateBackRequest())
                    {
                        return false;
                    }
                }
                else
                {
                    if (!await (_currentVM as INavigationBlocker).OnNavigateOutRequest())
                    {
                        return false;
                    }
                }
            }

            if (pushToHistory && _lastFullPath != null && !_preventHistory)
            {
                _navigationHistory.Push(_lastFullPath);
                RaisePropertyChanged(nameof(CanNavigateBack));
            }

            _lastFullPath = fullPath;

            MainView.Instance.NavigationControl.NavigateTo(NavigationView.LayoutView.ToString());
            var navigationControl = LayoutView.Instance.NavigationControl;
            CurrentModule = module;
            var moduleView = navigationControl.NavigateTo(module.Name);

            _currentVM = moduleView.DataContext;

            if (path.Length > 1)
            {
                var moduleNavigation = moduleView.FindChildOffline<NavigationControl>();

                if (moduleNavigation != null)
                {
                    moduleNavigation.RegisterForLoadedOrNow(async (x, e) =>
                    {
                        foreach (var view in path.Skip(1))
                        {
                            await Task.Delay(100);
                            var v = moduleNavigation.NavigateTo(view);

                            if (v != null)
                            {
                                _currentVM = v.DataContext;

                                if (view != path.Last())
                                {
                                    moduleNavigation = v.FindChildOffline<NavigationControl>();
                                }
                            }
                            else
                            {
                                throw LogManager.Log(new ArgumentNullException("Could not navigate to " + fullPath));
                            }
                        }

                        NavigationCycleCompleted?.Invoke(fromVM, _currentVM);
                    });
                }
                else
                {
                    NavigationCycleCompleted?.Invoke(fromVM, _currentVM);
                }
            }

            return true;
        }

        /// <summary>
        /// Navigates for result.
        /// </summary>
        /// <typeparam name="TModule">The type of the module.</typeparam>
        /// <typeparam name="TView">The type of the view.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <typeparam name="TObject">The type of the object.</typeparam>
        /// <param name="obj">The object.</param>
        /// <param name="pushToHistory">if set to <c>true</c> [push to history].</param>
        /// <returns></returns>
        public Task<TResult> NavigateForResult<TModule, TView, TResult, TObject>(TObject obj, bool pushToHistory = true)
               where TModule : IPPCModule
        {
            TaskCompletionSource<TResult> source = new TaskCompletionSource<TResult>();

            var fromVM = _currentVM;
            Object toVM = null;


            Action<Object, Object> handler = null;

            handler = (from, to) =>
            {
                if (toVM == null)
                {
                    toVM = to;
                    if (toVM is INavigationResultProvider<TResult, TObject>)
                    {
                        (toVM as INavigationResultProvider<TResult, TObject>).OnNavigationObjectReceived(obj);
                    }
                }
                else
                {
                    if (to == fromVM && from == toVM)
                    {
                        if (from is INavigationResultProvider<TResult, TObject>)
                        {
                            source.SetResult((from as INavigationResultProvider<TResult, TObject>).GetNavigationResult());
                        }
                    }

                    NavigationCycleCompleted -= handler;
                }
            };

            NavigationCycleCompleted += handler;

            NavigateTo<TModule>(typeof(TView).Name, pushToHistory);

            return source.Task;
        }

        /// <summary>
        /// Navigates to the specified module and view with the specified object.
        /// </summary>
        /// <typeparam name="TModule">The type of the module.</typeparam>
        /// <typeparam name="TView">The type of the view.</typeparam>
        /// <typeparam name="TPass">The type of the pass.</typeparam>
        /// <param name="obj">The object.</param>
        /// <param name="pushToHistory">if set to <c>true</c> [push to history].</param>
        /// <returns></returns>
        public Task<bool> NavigateWithObject<TModule, TView, TPass>(TPass obj, bool pushToHistory = true) where TModule : IPPCModule
        {
            TaskCompletionSource<bool> source = new TaskCompletionSource<bool>();

            Action<Object, Object> handler = null;

            handler = (from, to) =>
            {
                if (to is INavigationObjectReceiver<TPass>)
                {
                    (to as INavigationObjectReceiver<TPass>).OnNavigatedToWithObject(obj);
                }

                NavigationCycleCompleted -= handler;
            };

            NavigationCycleCompleted += handler;

            NavigateTo<TModule>(typeof(TView).Name, pushToHistory);

            return source.Task;
        }

        private Task<bool> NavigateTo(Type moduleType, bool pushToHistory = true, params String[] viewPath)
        {
            if (viewPath != null && viewPath.Length > 0)
            {
                return NavigateTo(moduleType.Name + "." + String.Join(".", viewPath), pushToHistory);
            }
            else
            {
                return NavigateTo(moduleType.Name, pushToHistory);
            }
        }

        /// <summary>
        /// Gets a value indicating whether the navigation system is able to navigate to the previous view.
        /// </summary>
        public bool CanNavigateBack
        {
            get { return _navigationHistory.Count > 0; }
        }

        /// <summary>
        /// Navigates to the previous view if <see cref="P:Tango.PPC.Common.Navigation.INavigationManager.CanNavigateBack" /> is true.
        /// </summary>
        public async Task<bool> NavigateBack()
        {
            LogManager.Log("Navigating back...");

            _navigating_back = true;

            String first = _navigationHistory.Pop();
            _preventHistory = true;


            if (await NavigateTo(first))
            {
                RaisePropertyChanged(nameof(CanNavigateBack));
                _preventHistory = false;
                _navigating_back = false;
                return true;
            }
            else
            {
                _navigationHistory.Push(first);
                _preventHistory = false;
                _navigating_back = false;
                RaisePropertyChanged(nameof(CanNavigateBack));
                return false;
            }
        }

        /// <summary>
        /// Clears the navigation back history.
        /// </summary>
        public void ClearHistory()
        {
            LogManager.Log("Navigation history cleared.");
            _navigationHistory.Clear();
            RaisePropertyChanged(nameof(CanNavigateBack));
        }

        /// <summary>
        /// Clears the navigation back history except the specified view type.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void ClearHistoryExcept<T>()
        {
            LogManager.Log($"Navigation history cleared except for {typeof(T).Name}.");

            var history_list = _navigationHistory.ToList();
            history_list = history_list.Where(x => x.Contains(typeof(T).Name)).Distinct().ToList();
            _navigationHistory.Clear();

            foreach (var item in history_list)
            {
                _navigationHistory.Push(item);
            }

            RaisePropertyChanged(nameof(CanNavigateBack));
        }
    }
}