#region License
/**
* Ingenious MVC : An MVC framework for .NET 2.0
* Copyright (C) 2006, JDP Group
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: - Kent Boogaart (kentcb@internode.on.net)
*/
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Ingenious.Mvc;
using Ingenious.Mvc.Configuration;
using Ingenious.Mvc.Configuration.Configurators;
using Ingenious.Mvc.Util;
namespace Ingenious.Mvc.Navigators{
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="T:GraphNavigator"]/*'/>
[Serializable]
[XmlCustomParser(typeof(GraphNavigatorXmlCustomParser))]
public class GraphNavigator : NavigatorBase, ICustomConfigurable
{
private IDictionary<Id<IView>, IDictionary<Id<IView>, Id<IView>>> _sourceViewsToAliases;
private static readonly Log _log = Log.CreateForType(typeof(GraphNavigator));
//gets / sets a dictionary mapping aliases to destination views for a specified source view (fromView)
private IDictionary<Id<IView>, Id<IView>> this[Id<IView> fromView]
{
get
{
if (_sourceViewsToAliases.ContainsKey(fromView))
{
return _sourceViewsToAliases[fromView];
}
return null;
}
set
{
_sourceViewsToAliases[fromView] = value;
}
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="M:.ctor(Ingenious.Mvc.Id`1,Ingenious.Mvc.Task,Ingenious.Mvc.Id`1,Ingenious.Mvc.IViewManager)"]/*'/>
public GraphNavigator(Id<INavigator> id, Task task, Id<IView> startingViewId, IViewManager viewManager) : base(id, task, startingViewId, viewManager)
{
//this maps source view IDs to a dictionary of aliases
_sourceViewsToAliases = new Dictionary<Id<IView>, IDictionary<Id<IView>, Id<IView>>>();
_log.Verbose("Constructed GraphNavigator with ID '{0}' for task with ID '{1}'.", id, task.Id);
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="M:AddAlias(Ingenious.Mvc.Id`1,Ingenious.Mvc.Id`1,Ingenious.Mvc.Id`1)"]/*'/>
public virtual void AddAlias(Id<IView> fromView, Id<IView> toView, Id<IView> viewAliasId)
{
ArgumentHelper.AssertNotEmpty(fromView, "fromView");
ArgumentHelper.AssertNotEmpty(toView, "toView");
ArgumentHelper.AssertNotEmpty(viewAliasId, "viewAliasId");
//first get the alias -> destination view dictionary
IDictionary<Id<IView>, Id<IView>> aliasesToDestinationViews = this[fromView];
if (aliasesToDestinationViews == null)
{
//don't have any existing mappings for the source view so add in a dictionary
aliasesToDestinationViews = new Dictionary<Id<IView>, Id<IView>>();
this[fromView] = aliasesToDestinationViews;
}
//check whether that mapping already exists
ExceptionHelper.ThrowIf(aliasesToDestinationViews.ContainsKey(viewAliasId), "AddAlias.aliasAlreadyExists", viewAliasId, fromView, toView);
//now add a mapping from the specified alias to the specified destination view
aliasesToDestinationViews[viewAliasId] = toView;
_log.Information("Added alias called '{0}' from view '{1}' to view '{2}'.", viewAliasId, fromView, toView);
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="M:RemoveAlias(Ingenious.Mvc.Id`1,Ingenious.Mvc.Id`1)"]/*'/>
public void RemoveAlias(Id<IView> fromView, Id<IView> viewAliasId)
{
ArgumentHelper.AssertNotEmpty(fromView, "fromView");
ArgumentHelper.AssertNotEmpty(viewAliasId, "viewAliasId");
//first get the alias -> destination view dictionary
IDictionary<Id<IView>, Id<IView>> aliasesToDestinationViews = this[fromView];
if (aliasesToDestinationViews != null)
{
aliasesToDestinationViews.Remove(viewAliasId);
_log.Information("Removed alias called '{0}' from view '{1}'.", viewAliasId, fromView);
}
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="M:GetViewForAlias(Ingenious.Mvc.Id`1)"]/*'/>
public Id<IView> GetViewForAlias(Id<IView> viewAliasId)
{
ArgumentHelper.AssertNotEmpty(viewAliasId, "viewAliasId");
ExceptionHelper.ThrowIf(ViewManager.ActiveView == null, "GetViewForAlias.noActiveView", viewAliasId);
return GetViewForAlias(ViewManager.ActiveView.Id, viewAliasId);
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="M:GetViewForAlias(Ingenious.Mvc.Id`1,Ingenious.Mvc.Id`1)"]/*'/>
public Id<IView> GetViewForAlias(Id<IView> fromView, Id<IView> viewAliasId)
{
ArgumentHelper.AssertNotEmpty(fromView, "fromView");
ArgumentHelper.AssertNotEmpty(viewAliasId, "viewAliasId");
//first get the alias -> destination view dictionary
IDictionary<Id<IView>, Id<IView>> aliasesToDestinationViews = this[fromView];
if (aliasesToDestinationViews != null)
{
if (aliasesToDestinationViews.ContainsKey(viewAliasId))
{
return aliasesToDestinationViews[viewAliasId];
}
}
return Id<IView>.Empty;
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="M:GetAliasForView(Ingenious.Mvc.Id`1)"]/*'/>
public Id<IView> GetAliasForView(Id<IView> toView)
{
ArgumentHelper.AssertNotEmpty(toView, "toView");
ExceptionHelper.ThrowIf(ViewManager.ActiveView == null, "GetAliasForView.noActiveView", toView);
return GetAliasForView(ViewManager.ActiveView.Id, toView);
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="M:GetAliasForView(Ingenious.Mvc.Id`1,Ingenious.Mvc.Id`1)"]/*'/>
public Id<IView> GetAliasForView(Id<IView> fromView, Id<IView> toView)
{
ArgumentHelper.AssertNotEmpty(fromView, "fromView");
ArgumentHelper.AssertNotEmpty(toView, "toView");
//first get the alias -> destination view dictionary
IDictionary<Id<IView>, Id<IView>> aliasesToDestinationViews = this[fromView];
if (aliasesToDestinationViews != null)
{
//do a (relatively slow) reverse lookup to get the alias ID
foreach (Id<IView> viewAliasId in aliasesToDestinationViews.Keys)
{
if (aliasesToDestinationViews[viewAliasId] == toView)
{
return viewAliasId;
}
}
}
return Id<IView>.Empty;
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="M:AssertNavigateToValid(Ingenious.Mvc.Id`1)"]/*'/>
protected override bool AssertNavigateToValid(ref Id<IView> viewOrViewAliasId, bool throwOnError)
{
ArgumentHelper.AssertNotEmpty(viewOrViewAliasId, "viewOrViewAliasId");
Id<IView> targetViewId;
if (LastNavigateTo.IsEmpty)
{
//requested view must be starting view
if (viewOrViewAliasId != StartingViewId)
{
_log.Error("Navigating to '{0}' is not permitted because the first view must be the starting view (with ID '{1}').", viewOrViewAliasId, StartingViewId);
if (throwOnError)
{
ExceptionHelper.Throw("NavigateTo.firstViewMustBeStartingView", new object[] {ViewManager.ActiveView, viewOrViewAliasId}, StartingViewId, viewOrViewAliasId);
}
else
{
return false;
}
}
targetViewId = viewOrViewAliasId;
}
else
{
//look for an alias first
targetViewId = GetViewForAlias((Id<IView>) viewOrViewAliasId);
if (targetViewId.IsEmpty)
{
//and if no alias is found, look for a destination view instead
if (!GetAliasForView(viewOrViewAliasId).IsEmpty)
{
targetViewId = viewOrViewAliasId;
}
else
{
//no alias or destination view was found for the ID viewOrViewAliasId so we need to error out
_log.Error("Navigating to '{0}' is not permitted because no destination view or alias was found for the current view with ID '{1}'.", viewOrViewAliasId, ViewManager.ActiveView.Id);
if (throwOnError)
{
ExceptionHelper.Throw("NavigateTo.viewMappingNotFound", new object[] { ViewManager.ActiveView, viewOrViewAliasId }, viewOrViewAliasId, ViewManager.ActiveView.Id);
}
else
{
return false;
}
}
}
}
Debug.Assert(!targetViewId.IsEmpty);
viewOrViewAliasId = targetViewId;
return true;
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="M:Ingenious.Mvc.Configuration.ICustomConfigurable.SetCustomConfiguration(System.Object)"]/*'/>
void ICustomConfigurable.SetCustomConfiguration(object customConfiguration)
{
ApplyCustomConfiguration(customConfiguration);
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="M:ApplyCustomConfiguration(System.Object)"]/*'/>
protected void ApplyCustomConfiguration(object customConfiguration)
{
ArgumentHelper.AssertNotNull(customConfiguration, "customConfiguration");
CustomConfiguration customConfig = customConfiguration as CustomConfiguration;
ExceptionHelper.ThrowIf(customConfig == null, "ApplyCustomConfiguration.incorrectType", typeof(CustomConfiguration).FullName, customConfiguration.GetType().FullName);
_sourceViewsToAliases.Clear();
foreach (AliasInfo aliasInfo in customConfig)
{
AddAlias(aliasInfo.FromView, aliasInfo.ToView, aliasInfo.Alias);
}
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="T:GraphNavigator+AliasInfo"]/*'/>
[Serializable]
public sealed class AliasInfo
{
private Id<IView> _fromView;
private Id<IView> _toView;
private Id<IView> _alias;
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="P:AliasInfo.FromView"]/*'/>
public Id<IView> FromView
{
get
{
return _fromView;
}
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="P:AliasInfo.ToView"]/*'/>
public Id<IView> ToView
{
get
{
return _toView;
}
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="P:AliasInfo.Alias"]/*'/>
public Id<IView> Alias
{
get
{
return _alias;
}
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="P:AliasInfo.ctor()"]/*'/>
public AliasInfo(Id<IView> fromView, Id<IView> toView, Id<IView> alias)
{
_fromView = fromView;
_toView = toView;
_alias = alias;
}
}
/// <include file='GraphNavigator.doc.xml' path='/doc/member[@name="T:GraphNavigator+CustomConfiguration"]/*'/>
[Serializable]
public sealed class CustomConfiguration : List<AliasInfo>
{
}
}
}
|