#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 System.Threading;
using Ingenious.Mvc;
using Ingenious.Mvc.Configuration;
using Ingenious.Mvc.Util;
using Ingenious.Mvc.ViewManagers;
using Ingenious.Mvc.Windows.Forms.Views;
namespace Ingenious.Mvc.Windows.Forms.ViewManagers{
/// <include file='FormsViewManager.doc.xml' path='/doc/member[@name="T:FormsViewManager"]/*'/>
[Serializable]
public class FormsViewManager : ViewManagerBase
{
private IDictionary<Task, TaskInfo> _tasks;
private object _tasksLock;
private static readonly Log _log = Log.CreateForType(typeof(FormsViewManager));
/// <include file='FormsViewManager.doc.xml' path='/doc/member[@name="E:ViewCreated"]/*'/>
[field: NonSerialized]
public event EventHandler<ViewEventArgs> ViewCreated;
/// <include file='FormsViewManager.doc.xml' path='/doc/member[@name="E:ViewDisplaying"]/*'/>
[field: NonSerialized]
public event EventHandler<ViewEventArgs> ViewDisplaying;
/// <include file='FormsViewManager.doc.xml' path='/doc/member[@name="E:ViewDisplayed"]/*'/>
[field: NonSerialized]
public event EventHandler<ViewEventArgs> ViewDisplayed;
/// <include file='FormsViewManager.doc.xml' path='/doc/member[@name="E:ViewClosed"]/*'/>
[field: NonSerialized]
public event EventHandler<ViewEventArgs> ViewClosed;
/// <include file='FormsViewManager.doc.xml' path='/doc/member[@name="M:.ctor(Ingenious.Mvc.Id`1,Ingenious.Mvc.TaskManager)"]/*'/>
public FormsViewManager(Id<IViewManager> id, TaskManager taskManager) : base(id, taskManager)
{
_tasks = new Dictionary<Task, TaskInfo>();
_tasksLock = new object();
_log.Verbose("Constructed FormsViewManager with ID '{0}'.", id);
}
/// <include file='FormsViewManager.doc.xml' path='/doc/member[@name="M:Activate(Ingenious.Mvc.Task,Ingenious.Mvc.Id`1,System.Object)"]/*'/>
public override IView Activate(Task task, Id<IView> viewId, object viewData)
{
ArgumentHelper.AssertNotNull(task, "task");
ArgumentHelper.AssertNotEmpty(viewId, "viewId");
_log.Verbose("Activating view with ID '{0}' for task with ID '{1}'.", viewId, task.Id);
IView view = null;
bool viewCreated = false;
ViewInfo viewInfo = GetViewInfo(task, viewId);
FormBase.CustomConfiguration customConfiguration = viewInfo.CustomConfiguration as FormBase.CustomConfiguration;
if ((customConfiguration != null) && (customConfiguration.SingleInstance.GetValueOrDefault()))
{
//we have to make sure only one instance of this view is created and visible
_log.Verbose("Single instance is configured for view - checking existing view cache.");
view = GetViewInTask(task, viewId);
}
if (view == null)
{
_log.Verbose("Creating view.");
view = CreateView(task, viewId);
viewCreated = true;
}
//the view type must implement IFormView, not just IView
ExceptionHelper.ThrowIf(!(view is IFormView), "Activate.viewTypeDoesntImplementInterface", viewId, view.GetType().FullName, typeof(IFormView).FullName);
ExceptionHelper.ThrowIf(view.Task != task, "Activate.viewTaskNotSet", viewId, task.Id);
IFormView formView = (IFormView) view;
if (viewCreated)
{
//raise the ViewCreated event
OnViewCreated(formView);
//store the view in a list of views for the relevant task
AddViewToTask(formView);
}
//pass any data to the view
formView.SetData(viewData);
//get the currently active view for the relevant task
IFormView activeView = GetActiveView(formView.Task);
bool closeActiveView = false;
if ((activeView != null) && (!activeView.LeaveOpen))
{
//we won't close the active view if the next view has it as its parent
closeActiveView = (formView.ParentId != activeView.Id);
}
//close the active view if we have determined that to be necessary
if (closeActiveView)
{
_log.Verbose("Closing active view with ID '{0}'.", activeView.Id);
activeView.Close();
}
//find the parent view if any
IFormView parentView = GetParentViewForView(formView);
if ((viewCreated) && (parentView != null))
{
//make sure the parent is set for the view
_log.Verbose("Assigning parent view with ID '{0}'.", parentView.Id);
formView.SetParent(parentView);
}
//raise the ViewDisplaying event
OnViewDisplaying(formView);
if (parentView != null)
{
//make sure the parent knows that a child was opened
parentView.ChildOpening(formView);
}
_log.Verbose("Showing view with ID '{0}'.", viewId);
//show the sucker
formView.Show(formView.IsModal);
//raise the ViewDisplayed event
OnViewDisplayed(formView);
//return the view that was / is displayed
return formView;
}
/// <include file='FormsViewManager.doc.xml' path='/doc/member[@name="M:GetActiveView(Ingenious.Mvc.Task)"]/*'/>
public IFormView GetActiveView(Task task)
{
ArgumentHelper.AssertNotNull(task, "task");
lock (_tasksLock)
{
ExceptionHelper.ThrowIf(!_tasks.ContainsKey(task), "GetActiveView.taskNotFound", task.Id, Id);
return _tasks[task].ActiveView;
}
}
/// <include file='FormsViewManager.doc.xml' path='/doc/member[@name="M:OnViewCreated(Ingenious.Mvc.Windows.Forms.Views.IFormView)"]/*'/>
protected virtual void OnViewCreated(IFormView view)
{
EventHelper.Raise(ViewCreated, this, new ViewEventArgs(view));
}
/// <include file='FormsViewManager.doc.xml' path='/doc/member[@name="M:OnViewDisplaying(Ingenious.Mvc.Windows.Forms.Views.IFormView)"]/*'/>
protected virtual void OnViewDisplaying(IFormView view)
{
EventHelper.Raise(ViewDisplaying, this, new ViewEventArgs(view));
}
/// <include file='FormsViewManager.doc.xml' path='/doc/member[@name="M:OnViewDisplayed(Ingenious.Mvc.Windows.Forms.Views.IFormView)"]/*'/>
protected virtual void OnViewDisplayed(IFormView view)
{
EventHelper.Raise(ViewDisplayed, this, new ViewEventArgs(view));
}
/// <include file='FormsViewManager.doc.xml' path='/doc/member[@name="M:OnViewClosed(Ingenious.Mvc.Windows.Forms.Views.IFormView)"]/*'/>
protected virtual void OnViewClosed(IFormView view)
{
EventHelper.Raise(ViewClosed, this, new ViewEventArgs(view));
}
private void AddViewToTask(IFormView view)
{
_log.Verbose("Adding view with ID '{0}' to current task.", view.Id);
lock (_tasksLock)
{
TaskInfo taskInfo;
if (!_tasks.TryGetValue(view.Task, out taskInfo))
{
taskInfo = new TaskInfo();
_tasks[view.Task] = taskInfo;
}
//add the view to the list of views for the task
taskInfo.Views.Add(view);
//make sure we handle the various events raised by the view
view.Activated += new EventHandler<EventArgs>(view_Activated);
view.Deactivated += new EventHandler<EventArgs>(view_Deactivated);
view.Closed += new EventHandler<EventArgs>(view_Closed);
}
}
private IFormView GetViewInTask(Task task, Id<IView> viewId)
{
lock (_tasksLock)
{
if (_tasks.ContainsKey(task))
{
TaskInfo taskInfo = _tasks[task];
foreach (IFormView view in taskInfo.Views)
{
if (view.Id == viewId)
{
return view;
}
}
}
return null;
}
}
private void RemoveViewFromTask(IFormView view)
{
_log.Verbose("Removing view with ID '{0}' from current task.", view.Id);
lock (_tasksLock)
{
Debug.Assert(_tasks.ContainsKey(view.Task));
TaskInfo taskInfo = _tasks[view.Task];
Debug.Assert(taskInfo.Views.Contains(view));
//find and remove any child views of the view
for (int i = 0; i < taskInfo.Views.Count; ++i)
{
if (taskInfo.Views[i].ParentId == view.Id)
{
IFormView childView = taskInfo.Views[i];
_log.Verbose("Removing child view with ID '{0}'.", childView.Id);
//remove the view from the list of views for the task
taskInfo.Views.RemoveAt(i);
//detach from handling the closed event
childView.Closed -= new EventHandler<EventArgs>(view_Closed);
//close the child view
childView.Close();
--i;
}
}
//remove the view from the list of views for the task
taskInfo.Views.Remove(view);
//detach from handling the closed event
view.Closed -= new EventHandler<EventArgs>(view_Closed);
//end the task if there are no more views open for it
if (taskInfo.Views.Count == 0)
{
if (view.Task.State == TaskState.Started)
{
view.Task.End();
}
else
{
//this accommodates having a modal form as an entry point to a task
view.Task.Started += delegate
{
view.Task.End();
};
}
}
}
}
private void SetActiveView(IFormView view)
{
Debug.Assert(view != null);
lock (_tasksLock)
{
Debug.Assert(_tasks.ContainsKey(view.Task));
TaskInfo taskInfo = _tasks[view.Task];
Debug.Assert(taskInfo.Views.Contains(view));
//now set the active view
taskInfo.ActiveView = view;
}
}
private IFormView GetParentViewForView(IFormView view)
{
IFormView retVal = null;
if (!view.ParentId.IsEmpty)
{
lock (_tasksLock)
{
Debug.Assert(_tasks.ContainsKey(view.Task));
TaskInfo taskInfo = _tasks[view.Task];
Debug.Assert(taskInfo.Views.Contains(view));
foreach (IFormView taskView in taskInfo.Views)
{
if (taskView.Id == view.ParentId)
{
retVal = taskView;
break;
}
}
}
ExceptionHelper.ThrowIf(retVal == null, "GetParentViewForView.parentViewNotFound", view.ParentId, view.Id, view.Task.Id);
}
return retVal;
}
private void view_Activated(object sender, EventArgs e)
{
IFormView formView = (IFormView) sender;
//remember the active view for each task
SetActiveView(formView);
//raise the ViewActivated event
OnViewActivated(formView);
}
private void view_Deactivated(object sender, EventArgs e)
{
IFormView formView = (IFormView) sender;
//raise the ViewDeactivated event
OnViewDeactivated(formView);
}
private void view_Closed(object sender, EventArgs e)
{
IFormView formView = (IFormView) sender;
IFormView parentView = GetParentViewForView(formView);
//the view has been closed so remove it from the list of views for the related task
RemoveViewFromTask(formView);
//raise the ViewClosed event
OnViewClosed(formView);
if (parentView != null)
{
//make sure the parent knows that a child closed
parentView.ChildClosed(formView);
}
}
[Serializable]
private sealed class TaskInfo
{
[field: NonSerialized]
private IFormView _activeView;
[field: NonSerialized]
private IList<IFormView> _views;
public IFormView ActiveView
{
get
{
return _activeView;
}
set
{
_activeView = value;
}
}
public IList<IFormView> Views
{
get
{
return _views;
}
}
public TaskInfo()
{
_views = new List<IFormView>();
}
}
}
}
|