Free cookie consent management tool by TermsFeed Policy Generator

source: branches/CodeEditor/HeuristicLab.ExtLibs/HeuristicLab.AvalonEdit/5.0.1/AvalonEdit-5.0.1/Editing/TextAreaInputHandler.cs @ 11700

Last change on this file since 11700 was 11700, checked in by jkarder, 9 years ago

#2077: created branch and added first version

File size: 7.8 KB
Line 
1// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4// software and associated documentation files (the "Software"), to deal in the Software
5// without restriction, including without limitation the rights to use, copy, modify, merge,
6// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7// to whom the Software is furnished to do so, subject to the following conditions:
8//
9// The above copyright notice and this permission notice shall be included in all copies or
10// substantial portions of the Software.
11//
12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17// DEALINGS IN THE SOFTWARE.
18
19using ICSharpCode.AvalonEdit.Utils;
20using System;
21using System.Collections.Generic;
22using System.Collections.ObjectModel;
23using System.Windows.Input;
24
25namespace ICSharpCode.AvalonEdit.Editing
26{
27  /// <summary>
28  /// A set of input bindings and event handlers for the text area.
29  /// </summary>
30  /// <remarks>
31  /// <para>
32  /// There is one active input handler per text area (<see cref="Editing.TextArea.ActiveInputHandler"/>), plus
33  /// a number of active stacked input handlers.
34  /// </para>
35  /// <para>
36  /// The text area also stores a reference to a default input handler, but that is not necessarily active.
37  /// </para>
38  /// <para>
39  /// Stacked input handlers work in addition to the set of currently active handlers (without detaching them).
40  /// They are detached in the reverse order of being attached.
41  /// </para>
42  /// </remarks>
43  public interface ITextAreaInputHandler
44  {
45    /// <summary>
46    /// Gets the text area that the input handler belongs to.
47    /// </summary>
48    TextArea TextArea {
49      get;
50    }
51   
52    /// <summary>
53    /// Attaches an input handler to the text area.
54    /// </summary>
55    void Attach();
56   
57    /// <summary>
58    /// Detaches the input handler from the text area.
59    /// </summary>
60    void Detach();
61  }
62 
63  /// <summary>
64  /// Stacked input handler.
65  /// Uses OnEvent-methods instead of registering event handlers to ensure that the events are handled in the correct order.
66  /// </summary>
67  public abstract class TextAreaStackedInputHandler : ITextAreaInputHandler
68  {
69    readonly TextArea textArea;
70   
71    /// <inheritdoc/>
72    public TextArea TextArea {
73      get { return textArea; }
74    }
75   
76    /// <summary>
77    /// Creates a new TextAreaInputHandler.
78    /// </summary>
79    protected TextAreaStackedInputHandler(TextArea textArea)
80    {
81      if (textArea == null)
82        throw new ArgumentNullException("textArea");
83      this.textArea = textArea;
84    }
85   
86    /// <inheritdoc/>
87    public virtual void Attach()
88    {
89    }
90   
91    /// <inheritdoc/>
92    public virtual void Detach()
93    {
94    }
95   
96    /// <summary>
97    /// Called for the PreviewKeyDown event.
98    /// </summary>
99    public virtual void OnPreviewKeyDown(KeyEventArgs e)
100    {
101    }
102   
103    /// <summary>
104    /// Called for the PreviewKeyUp event.
105    /// </summary>
106    public virtual void OnPreviewKeyUp(KeyEventArgs e)
107    {
108    }
109  }
110 
111  /// <summary>
112  /// Default-implementation of <see cref="ITextAreaInputHandler"/>.
113  /// </summary>
114  /// <remarks><inheritdoc cref="ITextAreaInputHandler"/></remarks>
115  public class TextAreaInputHandler : ITextAreaInputHandler
116  {
117    readonly ObserveAddRemoveCollection<CommandBinding> commandBindings;
118    readonly ObserveAddRemoveCollection<InputBinding> inputBindings;
119    readonly ObserveAddRemoveCollection<ITextAreaInputHandler> nestedInputHandlers;
120    readonly TextArea textArea;
121    bool isAttached;
122   
123    /// <summary>
124    /// Creates a new TextAreaInputHandler.
125    /// </summary>
126    public TextAreaInputHandler(TextArea textArea)
127    {
128      if (textArea == null)
129        throw new ArgumentNullException("textArea");
130      this.textArea = textArea;
131      commandBindings = new ObserveAddRemoveCollection<CommandBinding>(CommandBinding_Added, CommandBinding_Removed);
132      inputBindings = new ObserveAddRemoveCollection<InputBinding>(InputBinding_Added, InputBinding_Removed);
133      nestedInputHandlers = new ObserveAddRemoveCollection<ITextAreaInputHandler>(NestedInputHandler_Added, NestedInputHandler_Removed);
134    }
135   
136    /// <inheritdoc/>
137    public TextArea TextArea {
138      get { return textArea; }
139    }
140   
141    /// <summary>
142    /// Gets whether the input handler is currently attached to the text area.
143    /// </summary>
144    public bool IsAttached {
145      get { return isAttached; }
146    }
147   
148    #region CommandBindings / InputBindings
149    /// <summary>
150    /// Gets the command bindings of this input handler.
151    /// </summary>
152    public ICollection<CommandBinding> CommandBindings {
153      get { return commandBindings; }
154    }
155   
156    void CommandBinding_Added(CommandBinding commandBinding)
157    {
158      if (isAttached)
159        textArea.CommandBindings.Add(commandBinding);
160    }
161   
162    void CommandBinding_Removed(CommandBinding commandBinding)
163    {
164      if (isAttached)
165        textArea.CommandBindings.Remove(commandBinding);
166    }
167   
168    /// <summary>
169    /// Gets the input bindings of this input handler.
170    /// </summary>
171    public ICollection<InputBinding> InputBindings {
172      get { return inputBindings; }
173    }
174   
175    void InputBinding_Added(InputBinding inputBinding)
176    {
177      if (isAttached)
178        textArea.InputBindings.Add(inputBinding);
179    }
180   
181    void InputBinding_Removed(InputBinding inputBinding)
182    {
183      if (isAttached)
184        textArea.InputBindings.Remove(inputBinding);
185    }
186   
187    /// <summary>
188    /// Adds a command and input binding.
189    /// </summary>
190    /// <param name="command">The command ID.</param>
191    /// <param name="modifiers">The modifiers of the keyboard shortcut.</param>
192    /// <param name="key">The key of the keyboard shortcut.</param>
193    /// <param name="handler">The event handler to run when the command is executed.</param>
194    public void AddBinding(ICommand command, ModifierKeys modifiers, Key key, ExecutedRoutedEventHandler handler)
195    {
196      this.CommandBindings.Add(new CommandBinding(command, handler));
197      this.InputBindings.Add(new KeyBinding(command, key, modifiers));
198    }
199    #endregion
200   
201    #region NestedInputHandlers
202    /// <summary>
203    /// Gets the collection of nested input handlers. NestedInputHandlers are activated and deactivated
204    /// together with this input handler.
205    /// </summary>
206    public ICollection<ITextAreaInputHandler> NestedInputHandlers {
207      get { return nestedInputHandlers; }
208    }
209   
210    void NestedInputHandler_Added(ITextAreaInputHandler handler)
211    {
212      if (handler == null)
213        throw new ArgumentNullException("handler");
214      if (handler.TextArea != textArea)
215        throw new ArgumentException("The nested handler must be working for the same text area!");
216      if (isAttached)
217        handler.Attach();
218    }
219   
220    void NestedInputHandler_Removed(ITextAreaInputHandler handler)
221    {
222      if (isAttached)
223        handler.Detach();
224    }
225    #endregion
226   
227    #region Attach/Detach
228    /// <inheritdoc/>
229    public virtual void Attach()
230    {
231      if (isAttached)
232        throw new InvalidOperationException("Input handler is already attached");
233      isAttached = true;
234     
235      textArea.CommandBindings.AddRange(commandBindings);
236      textArea.InputBindings.AddRange(inputBindings);
237      foreach (ITextAreaInputHandler handler in nestedInputHandlers)
238        handler.Attach();
239    }
240   
241    /// <inheritdoc/>
242    public virtual void Detach()
243    {
244      if (!isAttached)
245        throw new InvalidOperationException("Input handler is not attached");
246      isAttached = false;
247     
248      foreach (CommandBinding b in commandBindings)
249        textArea.CommandBindings.Remove(b);
250      foreach (InputBinding b in inputBindings)
251        textArea.InputBindings.Remove(b);
252      foreach (ITextAreaInputHandler handler in nestedInputHandlers)
253        handler.Detach();
254    }
255    #endregion
256  }
257}
Note: See TracBrowser for help on using the repository browser.