Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2870_AutoDiff-nuget/HeuristicLab.ExtLibs/HeuristicLab.AvalonEdit/5.0.1/AvalonEdit-5.0.1/Snippets/SnippetBoundElement.cs @ 16752

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

#2077: created branch and added first version

File size: 4.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 System;
20using System.Windows.Documents;
21using ICSharpCode.AvalonEdit.Document;
22using ICSharpCode.NRefactory.Editor;
23
24namespace ICSharpCode.AvalonEdit.Snippets
25{
26  /// <summary>
27  /// An element that binds to a <see cref="SnippetReplaceableTextElement"/> and displays the same text.
28  /// </summary>
29  [Serializable]
30  public class SnippetBoundElement : SnippetElement
31  {
32    SnippetReplaceableTextElement targetElement;
33   
34    /// <summary>
35    /// Gets/Sets the target element.
36    /// </summary>
37    public SnippetReplaceableTextElement TargetElement {
38      get { return targetElement; }
39      set { targetElement = value; }
40    }
41   
42    /// <summary>
43    /// Converts the text before copying it.
44    /// </summary>
45    public virtual string ConvertText(string input)
46    {
47      return input;
48    }
49   
50    /// <inheritdoc/>
51    public override void Insert(InsertionContext context)
52    {
53      if (targetElement != null) {
54        TextAnchor start = context.Document.CreateAnchor(context.InsertionPosition);
55        start.MovementType = AnchorMovementType.BeforeInsertion;
56        start.SurviveDeletion = true;
57        string inputText = targetElement.Text;
58        if (inputText != null) {
59          context.InsertText(ConvertText(inputText));
60        }
61        TextAnchor end = context.Document.CreateAnchor(context.InsertionPosition);
62        end.MovementType = AnchorMovementType.BeforeInsertion;
63        end.SurviveDeletion = true;
64        AnchorSegment segment = new AnchorSegment(start, end);
65        context.RegisterActiveElement(this, new BoundActiveElement(context, targetElement, this, segment));
66      }
67    }
68   
69    /// <inheritdoc/>
70    public override Inline ToTextRun()
71    {
72      if (targetElement != null) {
73        string inputText = targetElement.Text;
74        if (inputText != null) {
75          return new Italic(new Run(ConvertText(inputText)));
76        }
77      }
78      return base.ToTextRun();
79    }
80  }
81 
82  sealed class BoundActiveElement : IActiveElement
83  {
84    InsertionContext context;
85    SnippetReplaceableTextElement targetSnippetElement;
86    SnippetBoundElement boundElement;
87    internal IReplaceableActiveElement targetElement;
88    AnchorSegment segment;
89   
90    public BoundActiveElement(InsertionContext context, SnippetReplaceableTextElement targetSnippetElement, SnippetBoundElement boundElement, AnchorSegment segment)
91    {
92      this.context = context;
93      this.targetSnippetElement = targetSnippetElement;
94      this.boundElement = boundElement;
95      this.segment = segment;
96    }
97   
98    public void OnInsertionCompleted()
99    {
100      targetElement = context.GetActiveElement(targetSnippetElement) as IReplaceableActiveElement;
101      if (targetElement != null) {
102        targetElement.TextChanged += targetElement_TextChanged;
103      }
104    }
105   
106    void targetElement_TextChanged(object sender, EventArgs e)
107    {
108      // Don't copy text if the segments overlap (we would get an endless loop).
109      // This can happen if the user deletes the text between the replaceable element and the bound element.
110      if (SimpleSegment.GetOverlap(segment, targetElement.Segment) == SimpleSegment.Invalid) {
111        int offset = segment.Offset;
112        int length = segment.Length;
113        string text = boundElement.ConvertText(targetElement.Text);
114        if (length != text.Length || text != context.Document.GetText(offset, length)) {
115          // Call replace only if we're actually changing something.
116          // Without this check, we would generate an empty undo group when the user pressed undo.
117          context.Document.Replace(offset, length, text);
118          if (length == 0) {
119            // replacing an empty anchor segment with text won't enlarge it, so we have to recreate it
120            segment = new AnchorSegment(context.Document, offset, text.Length);
121          }
122        }
123      }
124    }
125   
126    public void Deactivate(SnippetEventArgs e)
127    {
128    }
129   
130    public bool IsEditable {
131      get { return false; }
132    }
133   
134    public ISegment Segment {
135      get { return segment; }
136    }
137  }
138}
Note: See TracBrowser for help on using the repository browser.