Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@1569 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
40 changed files with 2406 additions and 580 deletions
|
After Width: | Height: | Size: 619 B |
|
After Width: | Height: | Size: 728 B |
|
After Width: | Height: | Size: 750 B |
@ -0,0 +1,83 @@ |
|||||||
|
/* |
||||||
|
* Created by SharpDevelop. |
||||||
|
* User: David |
||||||
|
* Date: 29/06/2006 |
||||||
|
* Time: 12:36 PM |
||||||
|
* |
||||||
|
* To change this template use Tools | Options | Coding | Edit Standard Headers. |
||||||
|
*/ |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Windows.Forms; |
||||||
|
using ICSharpCode.Core; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Commands |
||||||
|
{ |
||||||
|
public class NavigateBack : AbstractMenuCommand |
||||||
|
{ |
||||||
|
ToolBarSplitButton splitButton = null; |
||||||
|
|
||||||
|
public override bool IsEnabled { |
||||||
|
get { |
||||||
|
UpdateEnabledState(); |
||||||
|
return NavigationService.CanNavigateBack; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override void Run() |
||||||
|
{ |
||||||
|
//LoggingService.Debug("Jumping back...");
|
||||||
|
NavigationService.Go(-1); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnOwnerChanged(EventArgs e) |
||||||
|
{ |
||||||
|
base.OnOwnerChanged(e); |
||||||
|
|
||||||
|
// grab the owner so we can manipulate the buttons later
|
||||||
|
splitButton = (ToolBarSplitButton)Owner; |
||||||
|
|
||||||
|
// wire up our event handlers
|
||||||
|
NavigationService.HistoryChanged += NavHistoryChanged; |
||||||
|
|
||||||
|
// trigger state change to match initial state
|
||||||
|
NavHistoryChanged(this, EventArgs.Empty); |
||||||
|
} |
||||||
|
|
||||||
|
public void NavHistoryChanged(object sender, EventArgs e) |
||||||
|
{ |
||||||
|
INavigationPoint p = NavigationService.CurrentPosition; |
||||||
|
// LoggingService.DebugFormatted("NavHistoryChanged ({0}): {1}",
|
||||||
|
// NavigationService.Count,
|
||||||
|
// (p==null?"null":p.ToString()));
|
||||||
|
|
||||||
|
UpdateEnabledState(); |
||||||
|
} |
||||||
|
|
||||||
|
public void UpdateEnabledState() |
||||||
|
{ |
||||||
|
splitButton.ButtonEnabled = NavigationService.CanNavigateBack; |
||||||
|
splitButton.DropDownEnabled = NavigationService.Count>1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class NavigateForward : AbstractMenuCommand |
||||||
|
{ |
||||||
|
public override bool IsEnabled { |
||||||
|
get { |
||||||
|
return NavigationService.CanNavigateForwards; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override void Run() |
||||||
|
{ |
||||||
|
//LoggingService.Debug("Jumping forwards...");
|
||||||
|
NavigationService.Go(+1); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnOwnerChanged(EventArgs e) |
||||||
|
{ |
||||||
|
base.OnOwnerChanged(e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,38 @@ |
|||||||
|
using System; |
||||||
|
using System.IO; |
||||||
|
using System.Xml; |
||||||
|
|
||||||
|
using ICSharpCode.SharpDevelop.Gui; |
||||||
|
|
||||||
|
namespace ICSharpCode.Core |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Tests the <see cref="NavigationService"/> for the presence of points
|
||||||
|
/// to jump back to.
|
||||||
|
/// </summary>
|
||||||
|
/// <example title="Test if the NavigationService can jump back.">
|
||||||
|
/// <Condition name = "CanNavigateBack" >
|
||||||
|
/// </example>
|
||||||
|
public class CanNavigateBackConditionEvaluator : IConditionEvaluator |
||||||
|
{ |
||||||
|
public bool IsValid(object caller, Condition condition) |
||||||
|
{ |
||||||
|
return NavigationService.CanNavigateBack || NavigationService.CanNavigateForwards; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests the <see cref="NavigationService"/> for the presence of points
|
||||||
|
/// to jump forward to.
|
||||||
|
/// </summary>
|
||||||
|
/// <example title="Test if the NavigationService can jump forward.">
|
||||||
|
/// <Condition name = "CanNavigateForward" >
|
||||||
|
/// </example>
|
||||||
|
public class CanNavigateForwardConditionEvaluator : IConditionEvaluator |
||||||
|
{ |
||||||
|
public bool IsValid(object caller, Condition condition) |
||||||
|
{ |
||||||
|
return NavigationService.CanNavigateForwards; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,130 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="David Alpert" email="david@spinthemoose.com"/>
|
||||||
|
// <version>$Revision: $</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Drawing; |
||||||
|
|
||||||
|
namespace ICSharpCode.Core |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Default implementation for classes that wrap Navigational
|
||||||
|
/// information for the <see cref="NavigationService"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class DefaultNavigationPoint : INavigationPoint |
||||||
|
{ |
||||||
|
string fileName; |
||||||
|
object data; |
||||||
|
|
||||||
|
#region constructor
|
||||||
|
public DefaultNavigationPoint() : this(String.Empty, null) {} |
||||||
|
public DefaultNavigationPoint(string fileName) : this(fileName, null) {} |
||||||
|
public DefaultNavigationPoint(string fileName, object data) |
||||||
|
{ |
||||||
|
this.fileName = fileName; |
||||||
|
this.data = data; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region overrides
|
||||||
|
public override string ToString() |
||||||
|
{ |
||||||
|
return String.Format("[{0}: {1}]", |
||||||
|
this.GetType().Name, |
||||||
|
this.Description); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region INavigationPoint implementation
|
||||||
|
public virtual string FileName { |
||||||
|
get { |
||||||
|
return fileName; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public virtual string Description { |
||||||
|
get { |
||||||
|
return String.Format("{0}: {1}", fileName, data); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public virtual string FullDescription { |
||||||
|
get { |
||||||
|
return Description; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public virtual string ToolTip { |
||||||
|
get { |
||||||
|
return Description; |
||||||
|
} |
||||||
|
} |
||||||
|
// public string TabName {
|
||||||
|
// get {
|
||||||
|
// return tabName;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
public virtual int Index { |
||||||
|
get { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public object NavigationData { |
||||||
|
get { |
||||||
|
return data; |
||||||
|
} |
||||||
|
set { |
||||||
|
data = value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void JumpTo() |
||||||
|
{ |
||||||
|
FileService.JumpToFilePosition(this.FileName, 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
public void FileNameChanged(string newName) |
||||||
|
{ |
||||||
|
fileName = newName; |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void ContentChanging(object sender, EventArgs e) |
||||||
|
{ |
||||||
|
//throw new NotImplementedException();
|
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IComparable
|
||||||
|
public virtual int CompareTo(object obj) |
||||||
|
{ |
||||||
|
if (this.GetType() != obj.GetType()) { |
||||||
|
return this.GetType().Name.CompareTo(obj.GetType().Name); |
||||||
|
} |
||||||
|
DefaultNavigationPoint b = obj as DefaultNavigationPoint; |
||||||
|
return this.FileName.CompareTo(b.FileName); |
||||||
|
} |
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Equality
|
||||||
|
|
||||||
|
public override bool Equals(object obj) |
||||||
|
{ |
||||||
|
DefaultNavigationPoint b = obj as DefaultNavigationPoint; |
||||||
|
if (b == null) return false; |
||||||
|
return this.FileName == b.FileName; |
||||||
|
} |
||||||
|
|
||||||
|
public override int GetHashCode() |
||||||
|
{ |
||||||
|
return this.FileName.GetHashCode(); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,85 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="David Alpert" email="david@spinthemoose.com"/>
|
||||||
|
// <version>$Revision: $</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
|
||||||
|
namespace ICSharpCode.Core |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Interface for classes that store Navigational information for
|
||||||
|
/// the <see cref="NavigationService"/>.
|
||||||
|
/// </summary>
|
||||||
|
public interface INavigationPoint : IComparable |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// The path to the file containing the <see cref="INavigationPoint"/>
|
||||||
|
/// </summary>
|
||||||
|
string FileName { |
||||||
|
get; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the text that will appear in the drop-down menu to select
|
||||||
|
/// this <see cref="INavigationPoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
string Description { |
||||||
|
get; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets more detailed text that cam be used to describe
|
||||||
|
/// this <see cref="INavigationPoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
string FullDescription { |
||||||
|
get; |
||||||
|
} |
||||||
|
|
||||||
|
string ToolTip { |
||||||
|
get; |
||||||
|
} |
||||||
|
|
||||||
|
// /// <summary>
|
||||||
|
// ///
|
||||||
|
// /// </summary>
|
||||||
|
// string TabName {
|
||||||
|
// get;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the specific data, if any, needed to
|
||||||
|
/// navigate to this <see cref="INavigationPoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
object NavigationData { |
||||||
|
get; |
||||||
|
} |
||||||
|
|
||||||
|
int Index { |
||||||
|
get; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Navigates to this <see cref="INavigationPoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
void JumpTo(); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the <see cref="FileName"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="newName"></param>
|
||||||
|
void FileNameChanged(string newName); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Responsible for updating the internal data of the
|
||||||
|
/// <see cref="INavigationPoint"/> to synch it with
|
||||||
|
/// changes in the IViewContent containing the point.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
void ContentChanging(object sender, EventArgs e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,317 @@ |
|||||||
|
/* |
||||||
|
* Created by SharpDevelop. |
||||||
|
* User: David |
||||||
|
* Date: 23/06/2006 |
||||||
|
* Time: 12:14 AM |
||||||
|
* |
||||||
|
* To change this template use Tools | Options | Coding | Edit Standard Headers. |
||||||
|
*/ |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
using ICSharpCode.SharpDevelop.Gui; |
||||||
|
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; |
||||||
|
using ICSharpCode.TextEditor; |
||||||
|
|
||||||
|
namespace ICSharpCode.Core |
||||||
|
{ |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides the infrastructure to handle generalized code navigation.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>This service is not limited to navigating code; rather, it
|
||||||
|
/// integrates with SharpDevelop's extendable <see cref="IViewContent"/>
|
||||||
|
/// interface so that each window has the opportunity to implement a
|
||||||
|
/// contextually appropriate navigation scheme.</para>
|
||||||
|
/// <para>The default scheme, <see cref="DefaultNavigationPoint"/>, is
|
||||||
|
/// created automatically in the <see cref="AbstractViewContent"/>
|
||||||
|
/// implementation. This scheme supports the basic function of logging a
|
||||||
|
/// filename and returning to that file's default view.</para>
|
||||||
|
/// <para>The default text editor provides a slightly more sophisticated
|
||||||
|
/// scheme, <see cref="ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.TextEditorNavigationPoint">
|
||||||
|
/// TextEditorNavigationPoint</see>, that logs filename and line number.</para>
|
||||||
|
/// <para>To implement your own navigation scheme, implement
|
||||||
|
/// <see cref="IViewContent"/> or derive from
|
||||||
|
/// <see cref="AbstractViewContent"/> and override the
|
||||||
|
/// <see cref="IViewContent.BuildNavigationPoint">BuildNavigationPoint</see>
|
||||||
|
/// method.</para>
|
||||||
|
/// <para>
|
||||||
|
/// <i>History logic based in part on Orlando Curioso's <i>Code Project</i> article:
|
||||||
|
/// <see href="http://www.codeproject.com/cs/miscctrl/WinFormsHistory.asp">
|
||||||
|
/// Navigational history (go back/forward) for WinForms controls</see></i>
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public class NavigationService |
||||||
|
{ |
||||||
|
#region Private members
|
||||||
|
static LinkedList<INavigationPoint> history; |
||||||
|
static LinkedListNode<INavigationPoint> currentNode; |
||||||
|
static bool loggingSuspended; |
||||||
|
#endregion
|
||||||
|
|
||||||
|
static NavigationService() |
||||||
|
{ |
||||||
|
history = new LinkedList<INavigationPoint>(); |
||||||
|
currentNode = null; |
||||||
|
loggingSuspended = false; |
||||||
|
|
||||||
|
WorkbenchSingleton.WorkbenchCreated += WorkbenchCreatedHandler; |
||||||
|
FileService.FileRenamed += FileService_FileRenamed; |
||||||
|
} |
||||||
|
|
||||||
|
#region Public Properties
|
||||||
|
|
||||||
|
public static bool CanNavigateBack { |
||||||
|
get { return currentNode != history.First && currentNode != null;} |
||||||
|
} |
||||||
|
public static bool CanNavigateForwards { |
||||||
|
get {return currentNode != history.Last && currentNode != null;} |
||||||
|
} |
||||||
|
public static int Count { |
||||||
|
get { return history.Count; } |
||||||
|
} |
||||||
|
|
||||||
|
public static INavigationPoint CurrentPosition { |
||||||
|
get { |
||||||
|
return currentNode==null ? (INavigationPoint)null : currentNode.Value; |
||||||
|
} |
||||||
|
set { |
||||||
|
Log(value); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static bool IsLogging { |
||||||
|
get { return !loggingSuspended;} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public Methods
|
||||||
|
|
||||||
|
public static void ContentChanging(object sender, EventArgs e) |
||||||
|
{ |
||||||
|
foreach (INavigationPoint p in history) |
||||||
|
{ |
||||||
|
p.ContentChanging(sender, e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#region private helpers
|
||||||
|
static void Log(IWorkbenchWindow window) |
||||||
|
{ |
||||||
|
if (window==null) return; |
||||||
|
// TODO: Navigation - enable logging of subpanes via window.ActiveViewContent
|
||||||
|
Log(window.ViewContent); |
||||||
|
} |
||||||
|
|
||||||
|
static void Log(IViewContent vc) |
||||||
|
{ |
||||||
|
if (vc==null) return; |
||||||
|
Log(vc.BuildNavPoint()); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
public static void Log(INavigationPoint p) |
||||||
|
{ |
||||||
|
if (loggingSuspended) { |
||||||
|
return; |
||||||
|
} |
||||||
|
LogInternal(p); |
||||||
|
} |
||||||
|
|
||||||
|
// refactoring this out of Log() allows the NavigationService
|
||||||
|
// to call this and ensure it will work regardless of the
|
||||||
|
// requested state of loggingSuspended
|
||||||
|
private static void LogInternal(INavigationPoint p) |
||||||
|
{ |
||||||
|
if (p == null |
||||||
|
|| p.FileName==null) { // HACK: why/how do we get here?
|
||||||
|
return; |
||||||
|
} |
||||||
|
if (currentNode==null) { |
||||||
|
currentNode = history.AddFirst(p); |
||||||
|
} else if (p.Equals(currentNode.Value)) { |
||||||
|
// replace it
|
||||||
|
currentNode.Value = p; |
||||||
|
} else { |
||||||
|
currentNode = history.AddAfter(currentNode, p); |
||||||
|
} |
||||||
|
OnHistoryChanged(); |
||||||
|
} |
||||||
|
|
||||||
|
// untested
|
||||||
|
public static INavigationPoint Log() |
||||||
|
{ |
||||||
|
// IWorkbenchWindow window = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow;
|
||||||
|
// if (window == null) {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// IViewContent view = window.ViewContent;
|
||||||
|
// if (view == null) {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return view.BuildNavPoint();
|
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public static List<INavigationPoint> GetListOfPoints() |
||||||
|
{ |
||||||
|
return new List<INavigationPoint>(history); |
||||||
|
} |
||||||
|
|
||||||
|
public static void ClearHistory() |
||||||
|
{ |
||||||
|
ClearHistory(false); |
||||||
|
} |
||||||
|
|
||||||
|
public static void ClearHistory(bool clearCurrentPosition) |
||||||
|
{ |
||||||
|
INavigationPoint currentPosition = CurrentPosition; |
||||||
|
history.Clear(); |
||||||
|
currentNode = null; |
||||||
|
if (!clearCurrentPosition) { |
||||||
|
LogInternal(currentPosition); |
||||||
|
} |
||||||
|
OnHistoryChanged(); |
||||||
|
} |
||||||
|
|
||||||
|
public static void Go(int n) |
||||||
|
{ |
||||||
|
if (0 == n) { |
||||||
|
return; |
||||||
|
} else if (0>n) { |
||||||
|
// move backwards
|
||||||
|
while (0>n && currentNode!=history.First) { |
||||||
|
currentNode = currentNode.Previous; |
||||||
|
n++; |
||||||
|
} |
||||||
|
} else { |
||||||
|
// move forwards
|
||||||
|
while (0<n && currentNode!=history.Last) { |
||||||
|
currentNode = currentNode.Next; |
||||||
|
n--; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
SyncViewWithModel(); |
||||||
|
} |
||||||
|
|
||||||
|
public static void Go(INavigationPoint target) |
||||||
|
{ |
||||||
|
if (target==null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
LinkedListNode<INavigationPoint> targetNode; |
||||||
|
targetNode = history.Find(target); |
||||||
|
if (targetNode!=null) { |
||||||
|
currentNode = targetNode; |
||||||
|
} else { |
||||||
|
LoggingService.ErrorFormatted("Logging additional point: {0}", target); |
||||||
|
LogInternal(target); |
||||||
|
//currentNode = history.AddAfter(currentNode, target);
|
||||||
|
} |
||||||
|
|
||||||
|
SyncViewWithModel(); |
||||||
|
} |
||||||
|
|
||||||
|
private static void SyncViewWithModel() |
||||||
|
{ |
||||||
|
//LoggingService.Info("suspend logging");
|
||||||
|
SuspendLogging(); |
||||||
|
if (CurrentPosition!=null) { |
||||||
|
CurrentPosition.JumpTo(); |
||||||
|
} |
||||||
|
//LoggingService.Info("resume logging");
|
||||||
|
ResumeLogging(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void SuspendLogging() |
||||||
|
{ |
||||||
|
loggingSuspended = true; |
||||||
|
} |
||||||
|
public static void ResumeLogging() |
||||||
|
{ |
||||||
|
// ENH: possible enhancement: use int instead of bool so resume statements are incremental rather than definitive.
|
||||||
|
loggingSuspended = false; |
||||||
|
} |
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
// the following code is not covered by Unit tests as i wasn't sure
|
||||||
|
// how to test code triggered by the user interacting with the workbench
|
||||||
|
#region event trapping
|
||||||
|
|
||||||
|
#region ViewContent events
|
||||||
|
public static void WorkbenchCreatedHandler(object sender, EventArgs e) |
||||||
|
{ |
||||||
|
WorkbenchSingleton.Workbench.ViewOpened += |
||||||
|
new ViewContentEventHandler(ViewContentOpened); |
||||||
|
WorkbenchSingleton.Workbench.ViewClosed += |
||||||
|
new ViewContentEventHandler(ViewContentClosed); |
||||||
|
} |
||||||
|
|
||||||
|
static void ViewContentOpened(object sender, ViewContentEventArgs e) |
||||||
|
{ |
||||||
|
//Log(e.Content);
|
||||||
|
e.Content.WorkbenchWindow.WindowSelected += WorkBenchWindowSelected; |
||||||
|
} |
||||||
|
|
||||||
|
static void ViewContentClosed(object sender, ViewContentEventArgs e) |
||||||
|
{ |
||||||
|
e.Content.WorkbenchWindow.WindowSelected -= WorkBenchWindowSelected; |
||||||
|
} |
||||||
|
|
||||||
|
static IWorkbenchWindow lastSelectedWindow = null; |
||||||
|
static void WorkBenchWindowSelected(object sender, EventArgs e) |
||||||
|
{ |
||||||
|
try { |
||||||
|
IWorkbenchWindow window = sender as IWorkbenchWindow; |
||||||
|
if (window == lastSelectedWindow) { |
||||||
|
return; |
||||||
|
} |
||||||
|
int n = NavigationService.Count; |
||||||
|
Log(window); |
||||||
|
//LoggingService.DebugFormatted("WorkbenchSelected: logging {0}", window.Title);
|
||||||
|
|
||||||
|
// HACK: Navigation - for some reason, JumpToFilePosition returns _before_ this
|
||||||
|
// gets fired, (not the behaviour i expected) so we need to remember the
|
||||||
|
// previous selected window to ensure that we only log once per visit to
|
||||||
|
// a given window.
|
||||||
|
lastSelectedWindow = window; |
||||||
|
|
||||||
|
} catch (Exception ex) { |
||||||
|
LoggingService.ErrorFormatted("{0}:\n{1}",ex.Message, ex.StackTrace); |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
static void FileService_FileRenamed(object sender, FileRenameEventArgs e) |
||||||
|
{ |
||||||
|
foreach (INavigationPoint p in history) { |
||||||
|
if (p.FileName.Equals(e.SourceFile)) { |
||||||
|
p.FileNameChanged(e.TargetFile); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Public Events
|
||||||
|
public static event System.EventHandler HistoryChanged; |
||||||
|
|
||||||
|
public static void OnHistoryChanged() |
||||||
|
{ |
||||||
|
if (HistoryChanged!=null) { |
||||||
|
HistoryChanged(NavigationService.CurrentPosition, EventArgs.Empty); |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,62 @@ |
|||||||
|
/* |
||||||
|
* Created by SharpDevelop. |
||||||
|
* User: David |
||||||
|
* Date: 23/04/2006 |
||||||
|
* Time: 11:47 AM |
||||||
|
* |
||||||
|
* To change this template use Tools | Options | Coding | Edit Standard Headers. |
||||||
|
*/ |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Drawing; |
||||||
|
|
||||||
|
using ICSharpCode.Core; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Description of TextEditorNavigationPoint.
|
||||||
|
/// </summary>
|
||||||
|
public class TextEditorNavigationPoint : DefaultNavigationPoint |
||||||
|
{ |
||||||
|
public TextEditorNavigationPoint(string fileName, int line, int col) : |
||||||
|
base(fileName, new Point(col, line)) {} |
||||||
|
|
||||||
|
public int Line { |
||||||
|
get { |
||||||
|
return ((Point)base.NavigationData).Y; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public override string Description { |
||||||
|
get { |
||||||
|
return String.Format("{0}: {1}", this.FileName, this.Line); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override int Index { |
||||||
|
get { |
||||||
|
return this.Line; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override bool Equals(object obj) |
||||||
|
{ |
||||||
|
TextEditorNavigationPoint b = obj as TextEditorNavigationPoint; |
||||||
|
if (b == null) return false; |
||||||
|
return b.FileName == this.FileName && b.Line == this.Line; |
||||||
|
} |
||||||
|
|
||||||
|
public override int GetHashCode() |
||||||
|
{ |
||||||
|
return base.GetHashCode() ^ this.Line; |
||||||
|
} |
||||||
|
|
||||||
|
public override void JumpTo() |
||||||
|
{ |
||||||
|
Point p = (Point)this.NavigationData; |
||||||
|
FileService.JumpToFilePosition(this.FileName, p.Y, p.X); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,116 @@ |
|||||||
|
/* |
||||||
|
* Created by SharpDevelop. |
||||||
|
* User: David |
||||||
|
* Date: 06/07/2006 |
||||||
|
* Time: 12:40 PM |
||||||
|
* |
||||||
|
* To change this template use Tools | Options | Coding | Edit Standard Headers. |
||||||
|
*/ |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Drawing; |
||||||
|
using System.IO; |
||||||
|
|
||||||
|
using ICSharpCode.Core; |
||||||
|
|
||||||
|
namespace ICSharpCode.TextEditor.Document |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Description of TextNavigationPoint.
|
||||||
|
/// </summary>
|
||||||
|
public class TextNavigationPoint : DefaultNavigationPoint |
||||||
|
{ |
||||||
|
const int THREASHOLD = 5; |
||||||
|
|
||||||
|
#region constructor
|
||||||
|
public TextNavigationPoint() : this(String.Empty, 0, 0) {} |
||||||
|
public TextNavigationPoint(string fileName) : this(fileName, 0, 0) {} |
||||||
|
public TextNavigationPoint(string fileName, int lineNumber, int column) : this(fileName, lineNumber, column, String.Empty) {} |
||||||
|
public TextNavigationPoint(string fileName, int lineNumber, int column, string content) : base(fileName, new Point(column, lineNumber)) |
||||||
|
{ |
||||||
|
this.content = content; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
// TODO: Navigation - eventually, we'll store a reference to the document
|
||||||
|
// itself so we can track filename changes, inserts (that affect
|
||||||
|
// line numbers), and dynamically retrieve the text at this.lineNumber
|
||||||
|
//
|
||||||
|
// what happens to the doc reference when the document is closed?
|
||||||
|
//
|
||||||
|
string content; |
||||||
|
|
||||||
|
public int LineNumber { |
||||||
|
get {return ((Point)this.NavigationData).Y;} |
||||||
|
} |
||||||
|
|
||||||
|
public int Column { |
||||||
|
get {return ((Point)this.NavigationData).X;} |
||||||
|
} |
||||||
|
|
||||||
|
public override void JumpTo() |
||||||
|
{ |
||||||
|
FileService.JumpToFilePosition(this.FileName, |
||||||
|
this.LineNumber, |
||||||
|
this.Column); |
||||||
|
} |
||||||
|
|
||||||
|
public override void ContentChanging(object sender, EventArgs e) |
||||||
|
{ |
||||||
|
// TODO: Navigation - finish ContentChanging
|
||||||
|
// if (e is DocumentEventArgs) {
|
||||||
|
// DocumentEventArgs de = (DocumentEventArgs)e;
|
||||||
|
// if (this.LineNumber >=
|
||||||
|
// }
|
||||||
|
} |
||||||
|
|
||||||
|
#region IComparable
|
||||||
|
public override int CompareTo(object obj) |
||||||
|
{ |
||||||
|
int result = base.CompareTo(obj); |
||||||
|
if (0!=result) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
TextNavigationPoint b = obj as TextNavigationPoint; |
||||||
|
if (this.LineNumber==b.LineNumber) { |
||||||
|
return 0; |
||||||
|
} else if (this.LineNumber>b.LineNumber) { |
||||||
|
return 1; |
||||||
|
} else { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Equality
|
||||||
|
public override bool Equals(object obj) |
||||||
|
{ |
||||||
|
TextNavigationPoint b = obj as TextNavigationPoint; |
||||||
|
if (b==null) return false; |
||||||
|
return this.FileName.Equals(b.FileName) |
||||||
|
&& (Math.Abs(this.LineNumber - b.LineNumber)<=THREASHOLD); |
||||||
|
} |
||||||
|
|
||||||
|
public override int GetHashCode() |
||||||
|
{ |
||||||
|
return this.FileName.GetHashCode() ^ this.LineNumber.GetHashCode(); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
public override string Description { |
||||||
|
get { |
||||||
|
return String.Format("{0}: {1}", |
||||||
|
this.LineNumber, |
||||||
|
this.content); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override string FullDescription { |
||||||
|
get { |
||||||
|
return String.Format("{0} - {1}", |
||||||
|
Path.GetFileName(this.FileName), |
||||||
|
this.Description); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,114 @@ |
|||||||
|
/* |
||||||
|
* Created by SharpDevelop. |
||||||
|
* User: David |
||||||
|
* Date: 04/03/2006 |
||||||
|
* Time: 5:28 PM |
||||||
|
* |
||||||
|
* To change this template use Tools | Options | Coding | Edit Standard Headers. |
||||||
|
*/ |
||||||
|
|
||||||
|
using System; |
||||||
|
using NUnit.Framework; |
||||||
|
|
||||||
|
using ICSharpCode.Core; |
||||||
|
|
||||||
|
namespace NavigationServiceTests |
||||||
|
{ |
||||||
|
[TestFixture] |
||||||
|
public class INavigationPointTextFixture |
||||||
|
{ |
||||||
|
INavigationPoint p1; |
||||||
|
INavigationPoint p2; |
||||||
|
|
||||||
|
[TestFixtureSetUp] |
||||||
|
public void Init() |
||||||
|
{ |
||||||
|
int line = 3; |
||||||
|
|
||||||
|
p1 = new TestNavigationPoint("test1.cs", line); |
||||||
|
p2 = new TestNavigationPoint("test2.cs", line+2); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// A navigation point must store the filename of the file containing
|
||||||
|
/// them so that they can switch to the correct file, reopening it
|
||||||
|
/// if needed.
|
||||||
|
/// </summary>
|
||||||
|
public void FileNameTest() |
||||||
|
{ |
||||||
|
Assert.AreNotEqual("test1.css", p1.FileName, "FileName differs: expected test1.cs, received "+p1.FileName); |
||||||
|
Assert.AreEqual("test1.cs", p1.FileName); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// A navigation point must remember whatever additional data is needed
|
||||||
|
/// to navigation to the appropriate view-position within that file.
|
||||||
|
/// </summary>
|
||||||
|
public void DataTagTest() |
||||||
|
{ |
||||||
|
Assert.AreEqual(3, (int)p1.NavigationData); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// A navigation point must provide a description of itself for the
|
||||||
|
/// menu subsystem (ie. for menu text).
|
||||||
|
/// </summary>
|
||||||
|
public void DescriptionTest() |
||||||
|
{ |
||||||
|
Assert.AreNotEqual(String.Empty, p1.Description); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// A navigation point must provide an index for sorting purposes.
|
||||||
|
/// </summary>
|
||||||
|
public void IndexTest() |
||||||
|
{ |
||||||
|
Assert.AreNotEqual(null, p1.Description); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// A navigation point must provide a tooltip for the menu system.
|
||||||
|
/// </summary>
|
||||||
|
public void ToolTipText() |
||||||
|
{ |
||||||
|
Assert.AreNotEqual(String.Empty, p1.ToolTip); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// A navigation point must take responsibility for restoring the
|
||||||
|
/// cursor to whatever state is "held" (i.e. "described by") it's data.
|
||||||
|
/// </summary>
|
||||||
|
public void JumpToTest() |
||||||
|
{ |
||||||
|
TestNavigationPoint.CurrentTestPosition = null; |
||||||
|
Assert.AreEqual(TestNavigationPoint.CurrentTestPosition, null); |
||||||
|
|
||||||
|
p1.JumpTo(); |
||||||
|
Assert.AreEqual("test1.cs", TestNavigationPoint.CurrentTestPosition.FileName); |
||||||
|
Assert.AreEqual(3, (int)TestNavigationPoint.CurrentTestPosition.NavigationData); |
||||||
|
|
||||||
|
p2.JumpTo(); |
||||||
|
Assert.AreEqual("test2.cs", TestNavigationPoint.CurrentTestPosition.FileName); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// A navigation point must take responsibility for evaluating equality tests.
|
||||||
|
/// </summary>
|
||||||
|
public void EqualityTest() |
||||||
|
{ |
||||||
|
Assert.IsTrue(p1.Equals(p1)); |
||||||
|
Assert.IsFalse(p1.Equals(p2)); |
||||||
|
Assert.IsFalse(p1.Equals("not an INavigationPoint...")); |
||||||
|
|
||||||
|
Assert.AreNotEqual(p1.GetHashCode(), p2.GetHashCode()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,616 @@ |
|||||||
|
/* |
||||||
|
* Created by SharpDevelop. |
||||||
|
* User: David |
||||||
|
* Date: 22/06/2006 |
||||||
|
* Time: 11:45 PM |
||||||
|
* |
||||||
|
* To change this template use Tools | Options | Coding | Edit Standard Headers. |
||||||
|
*/ |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using NUnit.Framework; |
||||||
|
|
||||||
|
using ICSharpCode.Core; |
||||||
|
|
||||||
|
namespace NavigationServiceTests |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Provides unit tests for the <see cref="NavigationService"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>Code Navigation Requirements:</para>
|
||||||
|
/// <list type="definition">
|
||||||
|
/// <term><see href="http://wiki.sharpdevelop.net/default.aspx/SharpDevelop.SharpDevelop21Features">#develop wiki</see>:</term>
|
||||||
|
/// <description>
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item>backwards & forwards through visited positions in the editor windows</item>
|
||||||
|
/// </list>
|
||||||
|
/// </description>
|
||||||
|
/// <term>Daniel Grunwald [sharpdevelop-contributors@lists.sourceforge.net]:</term>
|
||||||
|
/// <description>
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item>includes back/forward command to reset the cursor position/active file</item>
|
||||||
|
/// <item>saves class+method+line info of the cursor</item>
|
||||||
|
/// <item>"undo" cursor position changes</item>
|
||||||
|
/// <item>when adding a cursor position to the history, all other
|
||||||
|
/// cursor positions in the same method are removed</item>
|
||||||
|
/// <item>the "navigate back" command would be a SplitButton in the toolbar</item>
|
||||||
|
/// <item>the dropdown would show class+method names</item>
|
||||||
|
/// </list>
|
||||||
|
/// </description>
|
||||||
|
/// </list>
|
||||||
|
/// <para> The <see cref="NavigationService.Count">Count</see> and list of
|
||||||
|
/// points returned by <see cref="NavigationService.GetListOfPoints">
|
||||||
|
/// GetListOfPoints()</see> are both assumed to contain the
|
||||||
|
/// <see cref="NavigationService.CurrentPosition">CurrentPosition</see>.
|
||||||
|
/// </para>
|
||||||
|
/// <para>As the current position is also exposed a property, clients can
|
||||||
|
/// then make the choice to include or exclude it when iterating over the
|
||||||
|
/// list of points.</para>
|
||||||
|
/// </remarks>
|
||||||
|
[TestFixture] |
||||||
|
public class NavigationServiceTestFixture |
||||||
|
{ |
||||||
|
#region private members
|
||||||
|
INavigationPoint p; |
||||||
|
INavigationPoint p_5; |
||||||
|
INavigationPoint p_6; |
||||||
|
INavigationPoint p_37; |
||||||
|
INavigationPoint q; |
||||||
|
INavigationPoint r; |
||||||
|
INavigationPoint s; |
||||||
|
INavigationPoint t; |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region the tests
|
||||||
|
|
||||||
|
// TODO: build "CreateNUnitTest" command
|
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// expose an <see cref="INavigationPoint"/>
|
||||||
|
/// reference for the current "position" in the
|
||||||
|
/// editor windows, and return <see langword="null"/>
|
||||||
|
/// when the history is empty.
|
||||||
|
/// </summary>
|
||||||
|
public void CurrentPositionTest() |
||||||
|
{ |
||||||
|
Assert.IsNull(NavigationService.CurrentPosition); |
||||||
|
|
||||||
|
NavigationService.CurrentPosition = p; |
||||||
|
Assert.IsInstanceOfType(typeof(INavigationPoint), |
||||||
|
NavigationService.CurrentPosition); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// be able to log and remember changes to the
|
||||||
|
/// <see cref="NavigationService.CurrentPosition">
|
||||||
|
/// CurrentPosition</see>.
|
||||||
|
/// </summary>
|
||||||
|
public void LogTest() |
||||||
|
{ |
||||||
|
NavigationService.CurrentPosition = p; |
||||||
|
Assert.AreEqual(p, NavigationService.CurrentPosition); |
||||||
|
|
||||||
|
NavigationService.CurrentPosition = q; |
||||||
|
Assert.AreEqual(q, NavigationService.CurrentPosition); |
||||||
|
|
||||||
|
NavigationService.CurrentPosition = r; |
||||||
|
Assert.AreEqual(r, NavigationService.CurrentPosition); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// expose a list of points in it's history.
|
||||||
|
/// <see cref="List<T>"/> of type
|
||||||
|
/// <see cref="INavigationPoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>necessary for testing and for menu building</remarks>
|
||||||
|
public void GetListOfPointsTest() |
||||||
|
{ |
||||||
|
Assert.IsInstanceOfType(typeof(List<INavigationPoint>), |
||||||
|
NavigationService.GetListOfPoints()); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// expose a method to empty the points in its
|
||||||
|
/// history.
|
||||||
|
/// </summary>
|
||||||
|
public void ClearHistoryTest() |
||||||
|
{ |
||||||
|
NavigationService.ClearHistory(true); |
||||||
|
|
||||||
|
List<INavigationPoint> history = NavigationService.GetListOfPoints(); |
||||||
|
Assert.AreEqual(0, history.Count); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// expose a property of type <see cref="int"/>
|
||||||
|
/// indicating how many points are currently
|
||||||
|
/// stored in it's history.
|
||||||
|
/// </summary>
|
||||||
|
public void CountTest() |
||||||
|
{ |
||||||
|
Assert.IsInstanceOfType(typeof(int), |
||||||
|
NavigationService.Count); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// expose a property of type <see cref="int"/>
|
||||||
|
/// indicating how many points are currently
|
||||||
|
/// stored in it's history.
|
||||||
|
/// </summary>
|
||||||
|
public void CountingTest() |
||||||
|
{ |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
|
||||||
|
NavigationService.CurrentPosition = p; |
||||||
|
Assert.AreEqual(1, NavigationService.Count); |
||||||
|
|
||||||
|
NavigationService.CurrentPosition = q; |
||||||
|
Assert.AreEqual(2, NavigationService.Count); |
||||||
|
|
||||||
|
NavigationService.CurrentPosition = r; |
||||||
|
Assert.AreEqual(3, NavigationService.Count); |
||||||
|
|
||||||
|
NavigationService.ClearHistory(true); |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// ignore requests to log a null reference.
|
||||||
|
/// </summary>
|
||||||
|
public void LogNullTest() |
||||||
|
{ |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
NavigationService.CurrentPosition = null; |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
|
||||||
|
NavigationService.CurrentPosition = p; |
||||||
|
NavigationService.CurrentPosition = null; |
||||||
|
Assert.AreEqual(p, NavigationService.CurrentPosition); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// expose methods that allow clients to
|
||||||
|
/// suspend and resume logging of positions.
|
||||||
|
/// </summary>
|
||||||
|
public void SuspendLoggingTest() |
||||||
|
{ |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
|
||||||
|
NavigationService.SuspendLogging(); |
||||||
|
NavigationService.CurrentPosition = p; |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
|
||||||
|
NavigationService.ResumeLogging(); |
||||||
|
NavigationService.CurrentPosition = q; |
||||||
|
Assert.AreEqual(q, NavigationService.CurrentPosition); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// expose a Property to access the state of
|
||||||
|
/// logging.
|
||||||
|
/// </summary>
|
||||||
|
public void IsLoggingTest() |
||||||
|
{ |
||||||
|
Assert.IsTrue(NavigationService.IsLogging); |
||||||
|
|
||||||
|
NavigationService.SuspendLogging(); |
||||||
|
Assert.IsFalse(NavigationService.IsLogging); |
||||||
|
|
||||||
|
NavigationService.ResumeLogging(); |
||||||
|
Assert.IsTrue(NavigationService.IsLogging); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// <list type="bullet>
|
||||||
|
/// <item>include a back/forward command to reset the
|
||||||
|
/// cursor position/active file</item>
|
||||||
|
/// <item>be able to "undo" cursor position changes</item>
|
||||||
|
/// </list>
|
||||||
|
/// </summary>
|
||||||
|
public void GoTest() |
||||||
|
{ |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
Assert.IsNull(NavigationService.CurrentPosition); |
||||||
|
|
||||||
|
TestNavigationPoint.CurrentTestPosition = null; |
||||||
|
Assert.IsNull(TestNavigationPoint.CurrentTestPosition); |
||||||
|
|
||||||
|
NavigationService.CurrentPosition = p; |
||||||
|
NavigationService.CurrentPosition = q; |
||||||
|
NavigationService.CurrentPosition = TestNavigationPoint.CurrentTestPosition = r; |
||||||
|
Assert.AreEqual(3, NavigationService.Count); |
||||||
|
Assert.AreEqual(r, NavigationService.CurrentPosition); |
||||||
|
Assert.AreEqual(r, TestNavigationPoint.CurrentTestPosition); |
||||||
|
|
||||||
|
NavigationService.Go(0); |
||||||
|
Assert.AreEqual(3, NavigationService.Count); |
||||||
|
Assert.AreEqual(r, NavigationService.CurrentPosition); |
||||||
|
Assert.AreEqual(r, TestNavigationPoint.CurrentTestPosition); |
||||||
|
|
||||||
|
NavigationService.Go(-1); |
||||||
|
Assert.AreEqual(3, NavigationService.Count); |
||||||
|
Assert.AreEqual(q, NavigationService.CurrentPosition); |
||||||
|
Assert.AreEqual(q, TestNavigationPoint.CurrentTestPosition); |
||||||
|
|
||||||
|
NavigationService.Go(1); |
||||||
|
Assert.AreEqual(3, NavigationService.Count); |
||||||
|
Assert.AreEqual(r, NavigationService.CurrentPosition); |
||||||
|
Assert.AreEqual(r, TestNavigationPoint.CurrentTestPosition); |
||||||
|
|
||||||
|
NavigationService.Go(-2); |
||||||
|
Assert.AreEqual(p, NavigationService.CurrentPosition); |
||||||
|
Assert.AreEqual(p, TestNavigationPoint.CurrentTestPosition); |
||||||
|
|
||||||
|
NavigationService.Go(1); |
||||||
|
Assert.AreEqual(q, NavigationService.CurrentPosition); |
||||||
|
Assert.AreEqual(q, TestNavigationPoint.CurrentTestPosition); |
||||||
|
|
||||||
|
NavigationService.Go(1); |
||||||
|
Assert.AreEqual(r, NavigationService.CurrentPosition); |
||||||
|
Assert.AreEqual(r, TestNavigationPoint.CurrentTestPosition); |
||||||
|
|
||||||
|
// now attempt to go beyond the bounds of the list;
|
||||||
|
// we should meet this request as best as possible
|
||||||
|
// and generate no errors.
|
||||||
|
NavigationService.Go(-5); |
||||||
|
Assert.AreEqual(p, NavigationService.CurrentPosition); |
||||||
|
Assert.AreEqual(p, TestNavigationPoint.CurrentTestPosition); |
||||||
|
|
||||||
|
NavigationService.Go(7); |
||||||
|
Assert.AreEqual(r, NavigationService.CurrentPosition); |
||||||
|
Assert.AreEqual(r, TestNavigationPoint.CurrentTestPosition); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// support navigating directly to a specific
|
||||||
|
/// point.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// When the target point is not in the history,
|
||||||
|
/// the <see cref="NavigationService"/> must
|
||||||
|
/// add it such that advancing back restores the
|
||||||
|
/// position that was current before this request
|
||||||
|
/// and advancing forwards returns the same results
|
||||||
|
/// had this request never been made.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public void GoDirectTest() |
||||||
|
{ |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
|
||||||
|
NavigationService.Log(p); |
||||||
|
NavigationService.Log(q); |
||||||
|
NavigationService.Log(r); |
||||||
|
TestNavigationPoint.CurrentTestPosition = r; |
||||||
|
|
||||||
|
Assert.AreEqual(3, NavigationService.Count); |
||||||
|
Assert.AreEqual(r, NavigationService.CurrentPosition); |
||||||
|
Assert.AreEqual(r, TestNavigationPoint.CurrentTestPosition); |
||||||
|
Assert.IsTrue(NavigationService.CanNavigateBack); |
||||||
|
Assert.IsFalse(NavigationService.CanNavigateForwards); |
||||||
|
|
||||||
|
NavigationService.Go(p); |
||||||
|
|
||||||
|
Assert.AreEqual(3, NavigationService.Count); |
||||||
|
Assert.AreEqual(p, NavigationService.CurrentPosition); |
||||||
|
Assert.AreEqual(p, TestNavigationPoint.CurrentTestPosition); |
||||||
|
Assert.IsFalse(NavigationService.CanNavigateBack); |
||||||
|
Assert.IsTrue(NavigationService.CanNavigateForwards); |
||||||
|
|
||||||
|
NavigationService.Go(s); |
||||||
|
|
||||||
|
Assert.AreEqual(4, NavigationService.Count); |
||||||
|
Assert.AreEqual(s, NavigationService.CurrentPosition); |
||||||
|
Assert.AreEqual(s, TestNavigationPoint.CurrentTestPosition); |
||||||
|
Assert.IsTrue(NavigationService.CanNavigateBack); |
||||||
|
Assert.IsTrue(NavigationService.CanNavigateForwards); |
||||||
|
|
||||||
|
NavigationService.Go(-1); |
||||||
|
Assert.AreEqual(p, NavigationService.CurrentPosition); |
||||||
|
Assert.AreEqual(p, TestNavigationPoint.CurrentTestPosition); |
||||||
|
|
||||||
|
NavigationService.Go(2); |
||||||
|
Assert.AreEqual(q, NavigationService.CurrentPosition); |
||||||
|
Assert.AreEqual(q, TestNavigationPoint.CurrentTestPosition); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// expose boolean properties indicating whether
|
||||||
|
/// or not it is possible to navigate forwards
|
||||||
|
/// or backwards within the history.
|
||||||
|
/// </summary>
|
||||||
|
public void CanNavigateTest() |
||||||
|
{ |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
Assert.IsFalse(NavigationService.CanNavigateBack); |
||||||
|
Assert.IsFalse(NavigationService.CanNavigateForwards); |
||||||
|
|
||||||
|
NavigationService.Log(p); |
||||||
|
Assert.IsFalse(NavigationService.CanNavigateBack); |
||||||
|
Assert.IsFalse(NavigationService.CanNavigateForwards); |
||||||
|
|
||||||
|
NavigationService.Log(q); |
||||||
|
Assert.IsTrue(NavigationService.CanNavigateBack); |
||||||
|
Assert.IsFalse(NavigationService.CanNavigateForwards); |
||||||
|
|
||||||
|
NavigationService.Go(-1); |
||||||
|
Assert.IsFalse(NavigationService.CanNavigateBack); |
||||||
|
Assert.IsTrue(NavigationService.CanNavigateForwards); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// ignore multiple successive requests to
|
||||||
|
/// log identical points.
|
||||||
|
/// </summary>
|
||||||
|
public void LogMultipleIdenticalSuccessiveTest() |
||||||
|
{ |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
|
||||||
|
NavigationService.Log(p); |
||||||
|
NavigationService.Log(p); |
||||||
|
Assert.AreEqual(1, NavigationService.Count); |
||||||
|
Assert.AreEqual(p, NavigationService.CurrentPosition); |
||||||
|
|
||||||
|
NavigationService.Log(q); |
||||||
|
NavigationService.Log(r); |
||||||
|
NavigationService.Log(r); |
||||||
|
Assert.AreEqual(3, NavigationService.Count); |
||||||
|
Assert.AreEqual(r, NavigationService.CurrentPosition); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// support multiple successive requests to
|
||||||
|
/// log equivalent points, where equivalency
|
||||||
|
/// is measured by INavigationPoint.Equals(),
|
||||||
|
/// in which case the new point replaces the
|
||||||
|
/// current point.
|
||||||
|
/// </summary>
|
||||||
|
public void LogMultipleEquivalentSuccessiveTest() |
||||||
|
{ |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
Assert.IsTrue(p_5.Equals(p_6)); |
||||||
|
|
||||||
|
NavigationService.Log(p_5); |
||||||
|
NavigationService.Log(p_5); |
||||||
|
Assert.AreEqual(1, NavigationService.Count); |
||||||
|
Assert.AreEqual(p_5, NavigationService.CurrentPosition); |
||||||
|
|
||||||
|
NavigationService.Log(p_6); |
||||||
|
Assert.AreEqual(1, NavigationService.Count); |
||||||
|
Assert.AreEqual(p_6, NavigationService.CurrentPosition); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// allow requests to log multiple instances of
|
||||||
|
/// the same position (where sameness is tested
|
||||||
|
/// by INavigationPoint.<see cref="INavigationPoint.Equals">
|
||||||
|
/// Equals()</see>), provided they are not logged
|
||||||
|
/// successively.
|
||||||
|
/// </summary>
|
||||||
|
public void LogMultipleEquivalentDisjointTest() |
||||||
|
{ |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
Assert.IsTrue(p_5.Equals(p_6)); |
||||||
|
|
||||||
|
NavigationService.Log(p_5); |
||||||
|
NavigationService.Log(p_5); |
||||||
|
Assert.AreEqual(1, NavigationService.Count); |
||||||
|
Assert.AreEqual(p_5, NavigationService.CurrentPosition); |
||||||
|
|
||||||
|
NavigationService.Log(q); |
||||||
|
|
||||||
|
NavigationService.Log(p_6); |
||||||
|
Assert.AreEqual(3, NavigationService.Count); |
||||||
|
Assert.AreEqual(p_6, NavigationService.CurrentPosition); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// expose an event that fires when the
|
||||||
|
/// navigation list has changed
|
||||||
|
/// </summary>
|
||||||
|
public void HistoryChangedTest() |
||||||
|
{ |
||||||
|
navigationChangedCount = 0; |
||||||
|
NavigationService.HistoryChanged += NavigationHistoryChanged; |
||||||
|
|
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
Assert.AreEqual(0, navigationChangedCount); |
||||||
|
|
||||||
|
NavigationService.Log(p); |
||||||
|
Assert.AreEqual(1, NavigationService.Count); |
||||||
|
Assert.AreEqual(1, navigationChangedCount); |
||||||
|
|
||||||
|
NavigationService.Log(p_5); |
||||||
|
Assert.AreEqual(1, NavigationService.Count); |
||||||
|
Assert.AreEqual(2, navigationChangedCount); |
||||||
|
|
||||||
|
NavigationService.Log(q); |
||||||
|
Assert.AreEqual(2, NavigationService.Count); |
||||||
|
Assert.AreEqual(3, navigationChangedCount); |
||||||
|
|
||||||
|
NavigationService.ClearHistory(true); |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
Assert.AreEqual(4, navigationChangedCount); |
||||||
|
|
||||||
|
NavigationService.HistoryChanged -= NavigationHistoryChanged; |
||||||
|
} |
||||||
|
|
||||||
|
int navigationChangedCount; |
||||||
|
|
||||||
|
public void NavigationHistoryChanged(object sender, EventArgs e) |
||||||
|
{ |
||||||
|
navigationChangedCount++; |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
[Ignore("System.NullReferenceException: Object reference not set to an instance of an object.")] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// expose a method to generate an
|
||||||
|
/// <see cref="INavigationPoint"/> from a
|
||||||
|
/// given window.
|
||||||
|
/// </summary>
|
||||||
|
public void GenerateCurrentPositionTest() |
||||||
|
{ |
||||||
|
INavigationPoint p = NavigationService.Log(); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// expose a method to empty the points in its
|
||||||
|
/// history without forgetting the current
|
||||||
|
/// position
|
||||||
|
/// </summary>
|
||||||
|
public void ClearHistoryRetainCurrentTest() |
||||||
|
{ |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
|
||||||
|
NavigationService.Log(p); |
||||||
|
NavigationService.Log(q); |
||||||
|
|
||||||
|
Assert.AreEqual(2, NavigationService.Count); |
||||||
|
Assert.AreEqual(q, NavigationService.CurrentPosition); |
||||||
|
NavigationService.ClearHistory(); |
||||||
|
|
||||||
|
Assert.AreEqual(1, NavigationService.Count); |
||||||
|
Assert.AreEqual(q, NavigationService.CurrentPosition); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// ignore requests to go directly to a null
|
||||||
|
/// position.
|
||||||
|
/// </summary>
|
||||||
|
public void GoDirectToNullTest() |
||||||
|
{ |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
|
||||||
|
NavigationService.Log(p); |
||||||
|
NavigationService.Log(q); |
||||||
|
NavigationService.Log(r); |
||||||
|
|
||||||
|
Assert.AreEqual(3, NavigationService.Count); |
||||||
|
Assert.AreEqual(r, NavigationService.CurrentPosition); |
||||||
|
|
||||||
|
NavigationService.Go(null); |
||||||
|
|
||||||
|
Assert.AreEqual(3, NavigationService.Count); |
||||||
|
Assert.AreEqual(r, NavigationService.CurrentPosition); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="NavigationService"/> must
|
||||||
|
/// ignore requests to log a point equivalent
|
||||||
|
/// to the next position either forwards or back.
|
||||||
|
/// </summary>
|
||||||
|
public void LogDuplicateNextTest() |
||||||
|
{ |
||||||
|
Assert.AreEqual(0, NavigationService.Count); |
||||||
|
|
||||||
|
NavigationService.Log(p); |
||||||
|
NavigationService.Log(q); |
||||||
|
NavigationService.Log(r); |
||||||
|
|
||||||
|
NavigationService.Go(-1); |
||||||
|
|
||||||
|
Assert.AreEqual(3, NavigationService.Count); |
||||||
|
Assert.AreEqual(q, NavigationService.CurrentPosition); |
||||||
|
Assert.IsTrue(NavigationService.CanNavigateBack); |
||||||
|
Assert.IsTrue(NavigationService.CanNavigateForwards); |
||||||
|
|
||||||
|
NavigationService.Log(p); |
||||||
|
|
||||||
|
Assert.AreEqual(3, NavigationService.Count); |
||||||
|
Assert.AreEqual(q, NavigationService.CurrentPosition); |
||||||
|
Assert.IsTrue(NavigationService.CanNavigateBack); |
||||||
|
Assert.IsTrue(NavigationService.CanNavigateForwards); |
||||||
|
|
||||||
|
NavigationService.Log(r); |
||||||
|
|
||||||
|
Assert.AreEqual(3, NavigationService.Count); |
||||||
|
Assert.AreEqual(q, NavigationService.CurrentPosition); |
||||||
|
Assert.IsTrue(NavigationService.CanNavigateBack); |
||||||
|
Assert.IsTrue(NavigationService.CanNavigateForwards); |
||||||
|
} |
||||||
|
|
||||||
|
#region setup / tear down
|
||||||
|
|
||||||
|
[SetUp] |
||||||
|
public void BeforeEachTest() |
||||||
|
{ |
||||||
|
NavigationService.ClearHistory(true); |
||||||
|
NavigationService.ResumeLogging(); |
||||||
|
} |
||||||
|
|
||||||
|
[TearDown] |
||||||
|
public void AfterEachTest() |
||||||
|
{ |
||||||
|
NavigationService.ClearHistory(true); |
||||||
|
NavigationService.ResumeLogging(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create several <see cref="TestNavigationPoint"/>s
|
||||||
|
/// for use during tests.
|
||||||
|
/// </summary>
|
||||||
|
[TestFixtureSetUp] |
||||||
|
public void Init() |
||||||
|
{ |
||||||
|
p = new TestNavigationPoint("p.cs"); |
||||||
|
p_5 = new TestNavigationPoint("p.cs", 5); |
||||||
|
p_6 = new TestNavigationPoint("p.cs", 6); |
||||||
|
p_37 = new TestNavigationPoint("p.cs", 37); |
||||||
|
q = new TestNavigationPoint("q.cs"); |
||||||
|
r = new TestNavigationPoint("r.cs"); |
||||||
|
s = new TestNavigationPoint("s.cs"); |
||||||
|
t = new TestNavigationPoint("t.cs"); |
||||||
|
} |
||||||
|
|
||||||
|
[TestFixtureTearDown] |
||||||
|
public void Dispose() |
||||||
|
{ |
||||||
|
// TODO: Add tear down code.
|
||||||
|
} |
||||||
|
|
||||||
|
#endregion
|
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,70 @@ |
|||||||
|
/* |
||||||
|
* Created by SharpDevelop. |
||||||
|
* User: David |
||||||
|
* Date: 11/03/2006 |
||||||
|
* Time: 11:28 AM |
||||||
|
* |
||||||
|
* To change this template use Tools | Options | Coding | Edit Standard Headers. |
||||||
|
*/ |
||||||
|
|
||||||
|
using System; |
||||||
|
|
||||||
|
using ICSharpCode.Core; |
||||||
|
|
||||||
|
namespace NavigationServiceTests |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Description of TestNavigationPoint.
|
||||||
|
/// </summary>
|
||||||
|
public class TestNavigationPoint : DefaultNavigationPoint |
||||||
|
{ |
||||||
|
public TestNavigationPoint(string filename) : this(filename, 0) {} |
||||||
|
public TestNavigationPoint(string filename, int line): base(filename) |
||||||
|
{ |
||||||
|
this.LineNumber = line; |
||||||
|
} |
||||||
|
|
||||||
|
public new int NavigationData { |
||||||
|
get { |
||||||
|
return (int)base.NavigationData; |
||||||
|
} |
||||||
|
set { |
||||||
|
base.NavigationData = value; |
||||||
|
} |
||||||
|
} |
||||||
|
public int LineNumber { |
||||||
|
get { |
||||||
|
return this.NavigationData; |
||||||
|
} |
||||||
|
set { |
||||||
|
this.NavigationData = value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#region IComparable
|
||||||
|
public override bool Equals(object obj) |
||||||
|
{ |
||||||
|
TestNavigationPoint b = obj as TestNavigationPoint; |
||||||
|
if (b == null) return false; |
||||||
|
return this.FileName == b.FileName |
||||||
|
&& Math.Abs(this.LineNumber - b.LineNumber) <= 5; |
||||||
|
} |
||||||
|
|
||||||
|
public override int GetHashCode() |
||||||
|
{ |
||||||
|
return this.FileName.GetHashCode() ^ this.LineNumber.GetHashCode(); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
public override void JumpTo() |
||||||
|
{ |
||||||
|
// simulate the case where jumping triggers a call to log an intermediate position
|
||||||
|
NavigationService.Log(new TestNavigationPoint(this.FileName, -500)); |
||||||
|
|
||||||
|
// simulate changing something outside the NavigationService's model
|
||||||
|
CurrentTestPosition = this; |
||||||
|
} |
||||||
|
|
||||||
|
public static INavigationPoint CurrentTestPosition = null; |
||||||
|
} |
||||||
|
} |
||||||
Binary file not shown.
Loading…
Reference in new issue