Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3889 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
27 changed files with 765 additions and 184 deletions
@ -0,0 +1,84 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <author name="Daniel Grunwald"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Windows.Input; |
||||||
|
using ICSharpCode.AvalonEdit.Document; |
||||||
|
|
||||||
|
namespace ICSharpCode.AvalonEdit.Gui |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Contains the predefined input handlers.
|
||||||
|
/// </summary>
|
||||||
|
public class TextAreaDefaultInputHandler : TextAreaInputHandler |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Gets the caret navigation input handler.
|
||||||
|
/// </summary>
|
||||||
|
public TextAreaInputHandler CaretNavigation { get; private set; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the editing input handler.
|
||||||
|
/// </summary>
|
||||||
|
public TextAreaInputHandler Editing { get; private set; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the mouse selection input handler.
|
||||||
|
/// </summary>
|
||||||
|
public ITextAreaInputHandler MouseSelection { get; private set; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new TextAreaDefaultInputHandler instance.
|
||||||
|
/// </summary>
|
||||||
|
public TextAreaDefaultInputHandler(TextArea textArea) : base(textArea) |
||||||
|
{ |
||||||
|
this.NestedInputHandlers.Add(CaretNavigation = CaretNavigationCommandHandler.Create(textArea)); |
||||||
|
this.NestedInputHandlers.Add(Editing = EditingCommandHandler.Create(textArea)); |
||||||
|
this.NestedInputHandlers.Add(MouseSelection = new SelectionMouseHandler(textArea)); |
||||||
|
|
||||||
|
this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Undo, ExecuteUndo, CanExecuteUndo)); |
||||||
|
this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Redo, ExecuteRedo, CanExecuteRedo)); |
||||||
|
} |
||||||
|
|
||||||
|
#region Undo / Redo
|
||||||
|
UndoStack GetUndoStack() |
||||||
|
{ |
||||||
|
TextDocument document = this.TextArea.Document; |
||||||
|
if (document != null) |
||||||
|
return document.UndoStack; |
||||||
|
else |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
void ExecuteUndo(object sender, ExecutedRoutedEventArgs e) |
||||||
|
{ |
||||||
|
var undoStack = GetUndoStack(); |
||||||
|
if (undoStack != null && undoStack.CanUndo) |
||||||
|
undoStack.Undo(); |
||||||
|
} |
||||||
|
|
||||||
|
void CanExecuteUndo(object sender, CanExecuteRoutedEventArgs e) |
||||||
|
{ |
||||||
|
var undoStack = GetUndoStack(); |
||||||
|
e.CanExecute = undoStack != null && undoStack.CanUndo; |
||||||
|
} |
||||||
|
|
||||||
|
void ExecuteRedo(object sender, ExecutedRoutedEventArgs e) |
||||||
|
{ |
||||||
|
var undoStack = GetUndoStack(); |
||||||
|
if (undoStack != null && undoStack.CanRedo) |
||||||
|
undoStack.Redo(); |
||||||
|
} |
||||||
|
|
||||||
|
void CanExecuteRedo(object sender, CanExecuteRoutedEventArgs e) |
||||||
|
{ |
||||||
|
var undoStack = GetUndoStack(); |
||||||
|
e.CanExecute = undoStack != null && undoStack.CanRedo; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,184 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <author name="Daniel Grunwald"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using ICSharpCode.AvalonEdit.Utils; |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Collections.ObjectModel; |
||||||
|
using System.Windows.Input; |
||||||
|
|
||||||
|
namespace ICSharpCode.AvalonEdit.Gui |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// A set of input bindings and event handlers for the text area.
|
||||||
|
/// </summary>
|
||||||
|
public interface ITextAreaInputHandler |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Gets the text area that the input handler belongs to.
|
||||||
|
/// </summary>
|
||||||
|
TextArea TextArea { |
||||||
|
get; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attaches an input handler to the text area.
|
||||||
|
/// </summary>
|
||||||
|
void Attach(); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Detaches the input handler from the text area.
|
||||||
|
/// </summary>
|
||||||
|
void Detach(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default-implementation of <see cref="ITextAreaInputHandler"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class TextAreaInputHandler : ITextAreaInputHandler |
||||||
|
{ |
||||||
|
readonly ObserveAddRemoveCollection<CommandBinding> commandBindings; |
||||||
|
readonly ObserveAddRemoveCollection<InputBinding> inputBindings; |
||||||
|
readonly ObserveAddRemoveCollection<ITextAreaInputHandler> nestedInputHandlers; |
||||||
|
readonly TextArea textArea; |
||||||
|
bool isAttached; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new TextAreaInputHandler.
|
||||||
|
/// </summary>
|
||||||
|
public TextAreaInputHandler(TextArea textArea) |
||||||
|
{ |
||||||
|
if (textArea == null) |
||||||
|
throw new ArgumentNullException("textArea"); |
||||||
|
this.textArea = textArea; |
||||||
|
commandBindings = new ObserveAddRemoveCollection<CommandBinding>(CommandBinding_Added, CommandBinding_Removed); |
||||||
|
inputBindings = new ObserveAddRemoveCollection<InputBinding>(InputBinding_Added, InputBinding_Removed); |
||||||
|
nestedInputHandlers = new ObserveAddRemoveCollection<ITextAreaInputHandler>(NestedInputHandler_Added, NestedInputHandler_Removed); |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public TextArea TextArea { |
||||||
|
get { return textArea; } |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether the input handler is currently attached to the text area.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAttached { |
||||||
|
get { return isAttached; } |
||||||
|
} |
||||||
|
|
||||||
|
#region CommandBindings / InputBindings
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the command bindings of this input handler.
|
||||||
|
/// </summary>
|
||||||
|
public ICollection<CommandBinding> CommandBindings { |
||||||
|
get { return commandBindings; } |
||||||
|
} |
||||||
|
|
||||||
|
void CommandBinding_Added(CommandBinding commandBinding) |
||||||
|
{ |
||||||
|
if (isAttached) |
||||||
|
textArea.CommandBindings.Add(commandBinding); |
||||||
|
} |
||||||
|
|
||||||
|
void CommandBinding_Removed(CommandBinding commandBinding) |
||||||
|
{ |
||||||
|
if (isAttached) |
||||||
|
textArea.CommandBindings.Remove(commandBinding); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the input bindings of this input handler.
|
||||||
|
/// </summary>
|
||||||
|
public ICollection<InputBinding> InputBindings { |
||||||
|
get { return inputBindings; } |
||||||
|
} |
||||||
|
|
||||||
|
void InputBinding_Added(InputBinding inputBinding) |
||||||
|
{ |
||||||
|
if (isAttached) |
||||||
|
textArea.InputBindings.Add(inputBinding); |
||||||
|
} |
||||||
|
|
||||||
|
void InputBinding_Removed(InputBinding inputBinding) |
||||||
|
{ |
||||||
|
if (isAttached) |
||||||
|
textArea.InputBindings.Remove(inputBinding); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a command and input binding.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="command">The command ID.</param>
|
||||||
|
/// <param name="modifiers">The modifiers of the keyboard shortcut.</param>
|
||||||
|
/// <param name="key">The key of the keyboard shortcut.</param>
|
||||||
|
/// <param name="handler">The event handler to run when the command is executed.</param>
|
||||||
|
protected void AddBinding(ICommand command, ModifierKeys modifiers, Key key, ExecutedRoutedEventHandler handler) |
||||||
|
{ |
||||||
|
this.CommandBindings.Add(new CommandBinding(command, handler)); |
||||||
|
this.InputBindings.Add(new KeyBinding(command, key, modifiers)); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region NestedInputHandlers
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the collection of nested input handlers. NestedInputHandlers are activated and deactivated
|
||||||
|
/// together with this input handler.
|
||||||
|
/// </summary>
|
||||||
|
public ICollection<ITextAreaInputHandler> NestedInputHandlers { |
||||||
|
get { return nestedInputHandlers; } |
||||||
|
} |
||||||
|
|
||||||
|
void NestedInputHandler_Added(ITextAreaInputHandler handler) |
||||||
|
{ |
||||||
|
if (handler == null) |
||||||
|
throw new ArgumentNullException("handler"); |
||||||
|
if (handler.TextArea != textArea) |
||||||
|
throw new ArgumentException("The nested handler must be working for the same text area!"); |
||||||
|
if (isAttached) |
||||||
|
handler.Attach(); |
||||||
|
} |
||||||
|
|
||||||
|
void NestedInputHandler_Removed(ITextAreaInputHandler handler) |
||||||
|
{ |
||||||
|
if (isAttached) |
||||||
|
handler.Detach(); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Attach/Detach
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public virtual void Attach() |
||||||
|
{ |
||||||
|
if (isAttached) |
||||||
|
throw new InvalidOperationException("Input handler is already attached"); |
||||||
|
isAttached = true; |
||||||
|
|
||||||
|
textArea.CommandBindings.AddRange(commandBindings); |
||||||
|
textArea.InputBindings.AddRange(inputBindings); |
||||||
|
foreach (ITextAreaInputHandler handler in nestedInputHandlers) |
||||||
|
handler.Attach(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public virtual void Detach() |
||||||
|
{ |
||||||
|
if (!isAttached) |
||||||
|
throw new InvalidOperationException("Input handler is not attached"); |
||||||
|
isAttached = false; |
||||||
|
|
||||||
|
foreach (CommandBinding b in commandBindings) |
||||||
|
textArea.CommandBindings.Remove(b); |
||||||
|
foreach (InputBinding b in inputBindings) |
||||||
|
textArea.InputBindings.Remove(b); |
||||||
|
foreach (ITextAreaInputHandler handler in nestedInputHandlers) |
||||||
|
handler.Detach(); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <author name="Daniel Grunwald"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.ObjectModel; |
||||||
|
|
||||||
|
namespace ICSharpCode.AvalonEdit.Utils |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// A collection where adding and removing items causes a callback.
|
||||||
|
/// </summary>
|
||||||
|
sealed class ObserveAddRemoveCollection<T> : Collection<T> |
||||||
|
{ |
||||||
|
readonly Action<T> onAdd, onRemove; |
||||||
|
|
||||||
|
public ObserveAddRemoveCollection(Action<T> onAdd, Action<T> onRemove) |
||||||
|
{ |
||||||
|
this.onAdd = onAdd; |
||||||
|
this.onRemove = onRemove; |
||||||
|
} |
||||||
|
|
||||||
|
protected override void ClearItems() |
||||||
|
{ |
||||||
|
if (onRemove != null) { |
||||||
|
foreach (T val in this) |
||||||
|
onRemove(val); |
||||||
|
} |
||||||
|
base.ClearItems(); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void InsertItem(int index, T item) |
||||||
|
{ |
||||||
|
if (onAdd != null) |
||||||
|
onAdd(item); |
||||||
|
base.InsertItem(index, item); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void RemoveItem(int index) |
||||||
|
{ |
||||||
|
if (onRemove != null) |
||||||
|
onRemove(this[index]); |
||||||
|
base.RemoveItem(index); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void SetItem(int index, T item) |
||||||
|
{ |
||||||
|
if (onRemove != null) |
||||||
|
onRemove(this[index]); |
||||||
|
try { |
||||||
|
if (onAdd != null) |
||||||
|
onAdd(item); |
||||||
|
} catch { |
||||||
|
// when adding the new item fails, just remove the old one
|
||||||
|
base.RemoveAt(index); |
||||||
|
throw; |
||||||
|
} |
||||||
|
base.SetItem(index, item); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue