Browse Source

Make FoldingManager independent of TextView.

This allows using a single FoldingManager in multiple TextViews.
pull/15/head
Daniel Grunwald 15 years ago
parent
commit
7b011cf067
  1. 56
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingElementGenerator.cs
  2. 75
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingManager.cs
  3. 36
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingSection.cs
  4. 6
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/CollapsedLineSection.cs
  5. 6
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs

56
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingElementGenerator.cs

@ -2,11 +2,11 @@ @@ -2,11 +2,11 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.TextFormatting;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils;
@ -15,21 +15,57 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -15,21 +15,57 @@ namespace ICSharpCode.AvalonEdit.Folding
/// <summary>
/// A <see cref="VisualLineElementGenerator"/> that produces line elements for folded <see cref="FoldingSection"/>s.
/// </summary>
public class FoldingElementGenerator : VisualLineElementGenerator
public sealed class FoldingElementGenerator : VisualLineElementGenerator, ITextViewConnect
{
readonly List<TextView> textViews = new List<TextView>();
FoldingManager foldingManager;
#region FoldingManager property / connecting with TextView
/// <summary>
/// Gets/Sets the folding manager from which the foldings should be shown.
/// </summary>
public FoldingManager FoldingManager { get; set; }
public FoldingManager FoldingManager {
get {
return foldingManager;
}
set {
if (foldingManager != value) {
if (foldingManager != null) {
foreach (TextView v in textViews)
foldingManager.RemoveFromTextView(v);
}
foldingManager = value;
if (foldingManager != null) {
foreach (TextView v in textViews)
foldingManager.AddToTextView(v);
}
}
}
}
void ITextViewConnect.AddToTextView(TextView textView)
{
textViews.Add(textView);
if (foldingManager != null)
foldingManager.AddToTextView(textView);
}
void ITextViewConnect.RemoveFromTextView(TextView textView)
{
textViews.Remove(textView);
if (foldingManager != null)
foldingManager.RemoveFromTextView(textView);
}
#endregion
/// <inheritdoc/>
public override void StartGeneration(ITextRunConstructionContext context)
{
base.StartGeneration(context);
if (FoldingManager != null) {
if (context.TextView != FoldingManager.textView)
if (foldingManager != null) {
if (!foldingManager.textViews.Contains(context.TextView))
throw new ArgumentException("Invalid TextView");
if (context.Document != FoldingManager.document)
if (context.Document != foldingManager.document)
throw new ArgumentException("Invalid document");
}
}
@ -37,8 +73,8 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -37,8 +73,8 @@ namespace ICSharpCode.AvalonEdit.Folding
/// <inheritdoc/>
public override int GetFirstInterestedOffset(int startOffset)
{
if (FoldingManager != null)
return FoldingManager.GetNextFoldedFoldingStart(startOffset);
if (foldingManager != null)
return foldingManager.GetNextFoldedFoldingStart(startOffset);
else
return -1;
}
@ -46,11 +82,11 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -46,11 +82,11 @@ namespace ICSharpCode.AvalonEdit.Folding
/// <inheritdoc/>
public override VisualLineElement ConstructElement(int offset)
{
if (FoldingManager == null)
if (foldingManager == null)
return null;
int foldedUntil = -1;
FoldingSection foldingSection = null;
foreach (FoldingSection fs in FoldingManager.GetFoldingsAt(offset)) {
foreach (FoldingSection fs in foldingManager.GetFoldingsAt(offset)) {
if (fs.IsFolded) {
if (fs.EndOffset > foldedUntil) {
foldedUntil = fs.EndOffset;

75
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingManager.cs

@ -20,27 +20,33 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -20,27 +20,33 @@ namespace ICSharpCode.AvalonEdit.Folding
/// </summary>
public class FoldingManager : IWeakEventListener
{
internal readonly TextView textView;
internal readonly TextDocument document;
internal readonly List<TextView> textViews = new List<TextView>();
readonly TextSegmentCollection<FoldingSection> foldings;
#region Constructor
/// <summary>
/// Creates a new FoldingManager instance.
/// </summary>
public FoldingManager(TextView textView, TextDocument document)
public FoldingManager(TextDocument document)
{
if (textView == null)
throw new ArgumentNullException("textView");
if (document == null)
throw new ArgumentNullException("document");
this.textView = textView;
this.document = document;
this.foldings = new TextSegmentCollection<FoldingSection>();
document.VerifyAccess();
TextDocumentWeakEventManager.Changed.AddListener(document, this);
}
/// <summary>
/// Creates a new FoldingManager instance.
/// </summary>
[Obsolete("Use the (TextDocument) constructor instead.")]
public FoldingManager(TextView textView, TextDocument document)
: this(document)
{
}
#endregion
#region ReceiveWeakEvent
@ -73,6 +79,57 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -73,6 +79,57 @@ namespace ICSharpCode.AvalonEdit.Folding
}
#endregion
#region Manage TextViews
internal void AddToTextView(TextView textView)
{
if (textView == null || textViews.Contains(textView))
throw new ArgumentException();
textViews.Add(textView);
foreach (FoldingSection fs in foldings) {
if (fs.collapsedSections != null) {
Array.Resize(ref fs.collapsedSections, textViews.Count);
fs.collapsedSections[fs.collapsedSections.Length - 1] = fs.CollapseSection(textView);
}
}
}
internal void RemoveFromTextView(TextView textView)
{
int pos = textViews.IndexOf(textView);
if (pos < 0)
throw new ArgumentException();
foreach (FoldingSection fs in foldings) {
if (fs.collapsedSections != null) {
CollapsedLineSection[] c = new CollapsedLineSection[textViews.Count];
Array.Copy(fs.collapsedSections, 0, c, 0, pos);
Array.Copy(fs.collapsedSections, pos + 1, c, pos, c.Length - pos);
fs.collapsedSections = c;
}
}
}
internal CollapsedLineSection[] CollapseLines(DocumentLine start, DocumentLine end)
{
CollapsedLineSection[] c = new CollapsedLineSection[textViews.Count];
for (int i = 0; i < c.Length; i++) {
c[i] = textViews[i].CollapseLines(start, end);
}
return c;
}
internal void Redraw()
{
foreach (TextView textView in textViews)
textView.Redraw();
}
internal void Redraw(FoldingSection fs)
{
foreach (TextView textView in textViews)
textView.Redraw(fs);
}
#endregion
#region Create / Remove / Clear
/// <summary>
/// Creates a folding for the specified text section.
@ -83,7 +140,7 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -83,7 +140,7 @@ namespace ICSharpCode.AvalonEdit.Folding
throw new ArgumentException("startOffset must be less than endOffset");
FoldingSection fs = new FoldingSection(this, startOffset, endOffset);
foldings.Add(fs);
textView.Redraw(fs, DispatcherPriority.Normal);
Redraw(fs);
return fs;
}
@ -96,7 +153,7 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -96,7 +153,7 @@ namespace ICSharpCode.AvalonEdit.Folding
throw new ArgumentNullException("fs");
fs.IsFolded = false;
foldings.Remove(fs);
textView.Redraw(fs, DispatcherPriority.Normal);
Redraw(fs);
}
/// <summary>
@ -108,7 +165,7 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -108,7 +165,7 @@ namespace ICSharpCode.AvalonEdit.Folding
foreach (FoldingSection s in foldings)
s.IsFolded = false;
foldings.Clear();
textView.Redraw();
Redraw();
}
#endregion
@ -264,7 +321,7 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -264,7 +321,7 @@ namespace ICSharpCode.AvalonEdit.Folding
FoldingMargin margin;
FoldingElementGenerator generator;
public FoldingManagerInstallation(TextArea textArea) : base(textArea.TextView, textArea.Document)
public FoldingManagerInstallation(TextArea textArea) : base(textArea.Document)
{
this.textArea = textArea;
margin = new FoldingMargin() { FoldingManager = this };

36
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingSection.cs

@ -13,9 +13,9 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -13,9 +13,9 @@ namespace ICSharpCode.AvalonEdit.Folding
/// </summary>
public sealed class FoldingSection : TextSegment
{
FoldingManager manager;
readonly FoldingManager manager;
bool isFolded;
CollapsedLineSection collapsedSection;
internal CollapsedLineSection[] collapsedSections;
string title;
/// <summary>
@ -32,18 +32,29 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -32,18 +32,29 @@ namespace ICSharpCode.AvalonEdit.Folding
DocumentLine endLine = manager.document.GetLineByOffset(EndOffset);
if (startLine != endLine) {
DocumentLine startLinePlusOne = startLine.NextLine;
collapsedSection = manager.textView.CollapseLines(startLinePlusOne, endLine);
collapsedSections = manager.CollapseLines(startLinePlusOne, endLine);
}
}
} else {
RemoveCollapsedLineSection();
}
if (manager != null)
manager.textView.Redraw(this, DispatcherPriority.Normal);
manager.Redraw(this);
}
}
}
internal CollapsedLineSection CollapseSection(TextView textView)
{
DocumentLine startLine = manager.document.GetLineByOffset(StartOffset);
DocumentLine endLine = manager.document.GetLineByOffset(EndOffset);
if (startLine != endLine) {
DocumentLine startLinePlusOne = startLine.NextLine;
return textView.CollapseLines(startLinePlusOne, endLine);
}
return null;
}
/// <summary>
/// Gets/Sets the text used to display the collapsed version of the folding section.
/// </summary>
@ -55,7 +66,7 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -55,7 +66,7 @@ namespace ICSharpCode.AvalonEdit.Folding
if (title != value) {
title = value;
if (this.IsFolded && manager != null)
manager.textView.Redraw(this, DispatcherPriority.Normal);
manager.Redraw(this);
}
}
}
@ -74,16 +85,13 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -74,16 +85,13 @@ namespace ICSharpCode.AvalonEdit.Folding
void RemoveCollapsedLineSection()
{
if (collapsedSection != null) {
if (collapsedSection.Start != null)
collapsedSection.Uncollapse();
collapsedSection = null;
if (collapsedSections != null) {
foreach (var collapsedSection in collapsedSections) {
if (collapsedSection != null && collapsedSection.Start != null)
collapsedSection.Uncollapse();
}
collapsedSections = null;
}
}
internal void Removed()
{
manager = null;
}
}
}

6
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/CollapsedLineSection.cs

@ -30,7 +30,9 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -30,7 +30,9 @@ namespace ICSharpCode.AvalonEdit.Rendering
this.start = start;
this.end = end;
#if DEBUG
this.ID = "#" + (nextId++);
unchecked {
this.ID = " #" + (nextId++);
}
#endif
}
@ -110,7 +112,7 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -110,7 +112,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString")]
public override string ToString()
{
return "[CollapsedSection " + ID + " Start=" + (start != null ? start.LineNumber.ToString() : "null")
return "[CollapsedSection" + ID + " Start=" + (start != null ? start.LineNumber.ToString() : "null")
+ " End=" + (end != null ? end.LineNumber.ToString() : "null") + " IsCollapsed=" + isCollapsed + "]";
}
}

6
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs

@ -406,7 +406,7 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -406,7 +406,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
/// <summary>
/// Causes the text editor to regenerate the specified visual line.
/// </summary>
public void Redraw(VisualLine visualLine, DispatcherPriority redrawPriority)
public void Redraw(VisualLine visualLine, DispatcherPriority redrawPriority = DispatcherPriority.Normal)
{
VerifyAccess();
if (allVisualLines.Remove(visualLine)) {
@ -419,7 +419,7 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -419,7 +419,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
/// <summary>
/// Causes the text editor to redraw all lines overlapping with the specified segment.
/// </summary>
public void Redraw(int offset, int length, DispatcherPriority redrawPriority)
public void Redraw(int offset, int length, DispatcherPriority redrawPriority = DispatcherPriority.Normal)
{
VerifyAccess();
bool removedLine = false;
@ -464,7 +464,7 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -464,7 +464,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
/// Causes the text editor to redraw all lines overlapping with the specified segment.
/// Does nothing if segment is null.
/// </summary>
public void Redraw(ISegment segment, DispatcherPriority redrawPriority)
public void Redraw(ISegment segment, DispatcherPriority redrawPriority = DispatcherPriority.Normal)
{
if (segment != null) {
Redraw(segment.Offset, segment.Length, redrawPriority);

Loading…
Cancel
Save