Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceOverhaul/HeuristicLab.ExtLibs/HeuristicLab.AvalonEdit/5.0.1/AvalonEdit-5.0.1/Editing/Selection.cs @ 18242

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

#2077: created branch and added first version

File size: 10.0 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.Collections.Generic;
21using System.Text;
22using System.Windows;
23
24using ICSharpCode.AvalonEdit.Document;
25using ICSharpCode.AvalonEdit.Highlighting;
26using ICSharpCode.AvalonEdit.Utils;
27#if NREFACTORY
28using ICSharpCode.NRefactory.Editor;
29#endif
30
31namespace ICSharpCode.AvalonEdit.Editing
32{
33  /// <summary>
34  /// Base class for selections.
35  /// </summary>
36  public abstract class Selection
37  {
38    /// <summary>
39    /// Creates a new simple selection that selects the text from startOffset to endOffset.
40    /// </summary>
41    public static Selection Create(TextArea textArea, int startOffset, int endOffset)
42    {
43      if (textArea == null)
44        throw new ArgumentNullException("textArea");
45      if (startOffset == endOffset)
46        return textArea.emptySelection;
47      else
48        return new SimpleSelection(textArea,
49                                   new TextViewPosition(textArea.Document.GetLocation(startOffset)),
50                                   new TextViewPosition(textArea.Document.GetLocation(endOffset)));
51    }
52   
53    internal static Selection Create(TextArea textArea, TextViewPosition start, TextViewPosition end)
54    {
55      if (textArea == null)
56        throw new ArgumentNullException("textArea");
57      if (textArea.Document.GetOffset(start.Location) == textArea.Document.GetOffset(end.Location) && start.VisualColumn == end.VisualColumn)
58        return textArea.emptySelection;
59      else
60        return new SimpleSelection(textArea, start, end);
61    }
62   
63    /// <summary>
64    /// Creates a new simple selection that selects the text in the specified segment.
65    /// </summary>
66    public static Selection Create(TextArea textArea, ISegment segment)
67    {
68      if (segment == null)
69        throw new ArgumentNullException("segment");
70      return Create(textArea, segment.Offset, segment.EndOffset);
71    }
72   
73    internal readonly TextArea textArea;
74   
75    /// <summary>
76    /// Constructor for Selection.
77    /// </summary>
78    protected Selection(TextArea textArea)
79    {
80      if (textArea == null)
81        throw new ArgumentNullException("textArea");
82      this.textArea = textArea;
83    }
84   
85    /// <summary>
86    /// Gets the start position of the selection.
87    /// </summary>
88    public abstract TextViewPosition StartPosition { get; }
89   
90    /// <summary>
91    /// Gets the end position of the selection.
92    /// </summary>
93    public abstract TextViewPosition EndPosition { get; }
94   
95    /// <summary>
96    /// Gets the selected text segments.
97    /// </summary>
98    public abstract IEnumerable<SelectionSegment> Segments { get; }
99   
100    /// <summary>
101    /// Gets the smallest segment that contains all segments in this selection.
102    /// May return null if the selection is empty.
103    /// </summary>
104    public abstract ISegment SurroundingSegment { get; }
105   
106    /// <summary>
107    /// Replaces the selection with the specified text.
108    /// </summary>
109    public abstract void ReplaceSelectionWithText(string newText);
110   
111    internal string AddSpacesIfRequired(string newText, TextViewPosition start, TextViewPosition end)
112    {
113      if (EnableVirtualSpace && InsertVirtualSpaces(newText, start, end)) {
114        var line = textArea.Document.GetLineByNumber(start.Line);
115        string lineText = textArea.Document.GetText(line);
116        var vLine = textArea.TextView.GetOrConstructVisualLine(line);
117        int colDiff = start.VisualColumn - vLine.VisualLengthWithEndOfLineMarker;
118        if (colDiff > 0) {
119          string additionalSpaces = "";
120          if (!textArea.Options.ConvertTabsToSpaces && lineText.Trim('\t').Length == 0) {
121            int tabCount = (int)(colDiff / textArea.Options.IndentationSize);
122            additionalSpaces = new string('\t', tabCount);
123            colDiff -= tabCount * textArea.Options.IndentationSize;
124          }
125          additionalSpaces += new string(' ', colDiff);
126          return additionalSpaces + newText;
127        }
128      }
129      return newText;
130    }
131   
132    bool InsertVirtualSpaces(string newText, TextViewPosition start, TextViewPosition end)
133    {
134      return (!string.IsNullOrEmpty(newText) || !(IsInVirtualSpace(start) && IsInVirtualSpace(end)))
135        && newText != "\r\n"
136        && newText != "\n"
137        && newText != "\r";
138    }
139   
140    bool IsInVirtualSpace(TextViewPosition pos)
141    {
142      return pos.VisualColumn > textArea.TextView.GetOrConstructVisualLine(textArea.Document.GetLineByNumber(pos.Line)).VisualLength;
143    }
144   
145    /// <summary>
146    /// Updates the selection when the document changes.
147    /// </summary>
148    public abstract Selection UpdateOnDocumentChange(DocumentChangeEventArgs e);
149   
150    /// <summary>
151    /// Gets whether the selection is empty.
152    /// </summary>
153    public virtual bool IsEmpty {
154      get { return Length == 0; }
155    }
156   
157    /// <summary>
158    /// Gets whether virtual space is enabled for this selection.
159    /// </summary>
160    public virtual bool EnableVirtualSpace {
161      get { return textArea.Options.EnableVirtualSpace; }
162    }
163   
164    /// <summary>
165    /// Gets the selection length.
166    /// </summary>
167    public abstract int Length { get; }
168   
169    /// <summary>
170    /// Returns a new selection with the changed end point.
171    /// </summary>
172    /// <exception cref="NotSupportedException">Cannot set endpoint for empty selection</exception>
173    public abstract Selection SetEndpoint(TextViewPosition endPosition);
174   
175    /// <summary>
176    /// If this selection is empty, starts a new selection from <paramref name="startPosition"/> to
177    /// <paramref name="endPosition"/>, otherwise, changes the endpoint of this selection.
178    /// </summary>
179    public abstract Selection StartSelectionOrSetEndpoint(TextViewPosition startPosition, TextViewPosition endPosition);
180   
181    /// <summary>
182    /// Gets whether the selection is multi-line.
183    /// </summary>
184    public virtual bool IsMultiline {
185      get {
186        ISegment surroundingSegment = this.SurroundingSegment;
187        if (surroundingSegment == null)
188          return false;
189        int start = surroundingSegment.Offset;
190        int end = start + surroundingSegment.Length;
191        var document = textArea.Document;
192        if (document == null)
193          throw ThrowUtil.NoDocumentAssigned();
194        return document.GetLineByOffset(start) != document.GetLineByOffset(end);
195      }
196    }
197   
198    /// <summary>
199    /// Gets the selected text.
200    /// </summary>
201    public virtual string GetText()
202    {
203      var document = textArea.Document;
204      if (document == null)
205        throw ThrowUtil.NoDocumentAssigned();
206      StringBuilder b = null;
207      string text = null;
208      foreach (ISegment s in Segments) {
209        if (text != null) {
210          if (b == null)
211            b = new StringBuilder(text);
212          else
213            b.Append(text);
214        }
215        text = document.GetText(s);
216      }
217      if (b != null) {
218        if (text != null) b.Append(text);
219        return b.ToString();
220      } else {
221        return text ?? string.Empty;
222      }
223    }
224   
225    /// <summary>
226    /// Creates a HTML fragment for the selected text.
227    /// </summary>
228    public string CreateHtmlFragment(HtmlOptions options)
229    {
230      if (options == null)
231        throw new ArgumentNullException("options");
232      IHighlighter highlighter = textArea.GetService(typeof(IHighlighter)) as IHighlighter;
233      StringBuilder html = new StringBuilder();
234      bool first = true;
235      foreach (ISegment selectedSegment in this.Segments) {
236        if (first)
237          first = false;
238        else
239          html.AppendLine("<br>");
240        html.Append(HtmlClipboard.CreateHtmlFragment(textArea.Document, highlighter, selectedSegment, options));
241      }
242      return html.ToString();
243    }
244   
245    /// <inheritdoc/>
246    public abstract override bool Equals(object obj);
247   
248    /// <inheritdoc/>
249    public abstract override int GetHashCode();
250   
251    /// <summary>
252    /// Gets whether the specified offset is included in the selection.
253    /// </summary>
254    /// <returns>True, if the selection contains the offset (selection borders inclusive);
255    /// otherwise, false.</returns>
256    public virtual bool Contains(int offset)
257    {
258      if (this.IsEmpty)
259        return false;
260      if (this.SurroundingSegment.Contains(offset, 0)) {
261        foreach (ISegment s in this.Segments) {
262          if (s.Contains(offset, 0)) {
263            return true;
264          }
265        }
266      }
267      return false;
268    }
269   
270    /// <summary>
271    /// Creates a data object containing the selection's text.
272    /// </summary>
273    public virtual DataObject CreateDataObject(TextArea textArea)
274    {
275      DataObject data = new DataObject();
276     
277      // Ensure we use the appropriate newline sequence for the OS
278      string text = TextUtilities.NormalizeNewLines(GetText(), Environment.NewLine);
279     
280      // Enable drag/drop to Word, Notepad++ and others
281      if (EditingCommandHandler.ConfirmDataFormat(textArea, data, DataFormats.UnicodeText)) {
282        data.SetText(text);
283      }
284     
285      // Enable drag/drop to SciTe:
286      // We cannot use SetText, thus we need to use typeof(string).FullName as data format.
287      // new DataObject(object) calls SetData(object), which in turn calls SetData(Type, data),
288      // which then uses Type.FullName as format.
289      // We immitate that behavior here as well:
290      if (EditingCommandHandler.ConfirmDataFormat(textArea, data, typeof(string).FullName)) {
291        data.SetData(typeof(string).FullName, text);
292      }
293     
294      // Also copy text in HTML format to clipboard - good for pasting text into Word
295      // or to the SharpDevelop forums.
296      if (EditingCommandHandler.ConfirmDataFormat(textArea, data, DataFormats.Html)) {
297        HtmlClipboard.SetHtml(data, CreateHtmlFragment(new HtmlOptions(textArea.Options)));
298      }
299      return data;
300    }
301  }
302}
Note: See TracBrowser for help on using the repository browser.