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 @@
@@ -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 @@
@@ -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 @@
@@ -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