//
//
//
//
// $Revision$
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using ICSharpCode.TextEditor.Undo;
namespace ICSharpCode.TextEditor.Document
{
///
/// Describes the caret marker
///
public enum LineViewerStyle {
///
/// No line viewer will be displayed
///
None,
///
/// The row in which the caret is will be marked
///
FullRow
}
///
/// Describes the indent style
///
public enum IndentStyle {
///
/// No indentation occurs
///
None,
///
/// The indentation from the line above will be
/// taken to indent the curent line
///
Auto,
///
/// Inteligent, context sensitive indentation will occur
///
Smart
}
///
/// Describes the bracket highlighting style
///
public enum BracketHighlightingStyle {
///
/// Brackets won't be highlighted
///
None,
///
/// Brackets will be highlighted if the caret is on the bracket
///
OnBracket,
///
/// Brackets will be highlighted if the caret is after the bracket
///
AfterBracket
}
///
/// Describes the selection mode of the text area
///
public enum DocumentSelectionMode {
///
/// The 'normal' selection mode.
///
Normal,
///
/// Selections will be added to the current selection or new
/// ones will be created (multi-select mode)
///
Additive
}
///
/// The default implementation.
///
internal sealed class DefaultDocument : IDocument
{
bool readOnly = false;
LineManager lineTrackingStrategy;
BookmarkManager bookmarkManager;
ITextBufferStrategy textBufferStrategy;
IFormattingStrategy formattingStrategy;
FoldingManager foldingManager;
UndoStack undoStack = new UndoStack();
ITextEditorProperties textEditorProperties = new DefaultTextEditorProperties();
MarkerStrategy markerStrategy;
public LineManager LineManager {
get { return lineTrackingStrategy; }
set { lineTrackingStrategy = value; }
}
public event EventHandler LineLengthChanged {
add { lineTrackingStrategy.LineLengthChanged += value; }
remove { lineTrackingStrategy.LineLengthChanged -= value; }
}
public event EventHandler LineCountChanged {
add { lineTrackingStrategy.LineCountChanged += value; }
remove { lineTrackingStrategy.LineCountChanged -= value; }
}
public event EventHandler LineDeleted {
add { lineTrackingStrategy.LineDeleted += value; }
remove { lineTrackingStrategy.LineDeleted -= value; }
}
public MarkerStrategy MarkerStrategy {
get { return markerStrategy; }
set { markerStrategy = value; }
}
public ITextEditorProperties TextEditorProperties {
get {
return textEditorProperties;
}
set {
textEditorProperties = value;
}
}
public UndoStack UndoStack {
get {
return undoStack;
}
}
public IList LineSegmentCollection {
get {
return lineTrackingStrategy.LineSegmentCollection;
}
}
public bool ReadOnly {
get {
return readOnly;
}
set {
readOnly = value;
}
}
public ITextBufferStrategy TextBufferStrategy {
get {
return textBufferStrategy;
}
set {
textBufferStrategy = value;
}
}
public IFormattingStrategy FormattingStrategy {
get {
return formattingStrategy;
}
set {
formattingStrategy = value;
}
}
public FoldingManager FoldingManager {
get {
return foldingManager;
}
set {
foldingManager = value;
}
}
public IHighlightingStrategy HighlightingStrategy {
get {
return lineTrackingStrategy.HighlightingStrategy;
}
set {
lineTrackingStrategy.HighlightingStrategy = value;
}
}
public int TextLength {
get {
return textBufferStrategy.Length;
}
}
public BookmarkManager BookmarkManager {
get {
return bookmarkManager;
}
set {
bookmarkManager = value;
}
}
public string TextContent {
get {
return GetText(0, textBufferStrategy.Length);
}
set {
Debug.Assert(textBufferStrategy != null);
Debug.Assert(lineTrackingStrategy != null);
OnDocumentAboutToBeChanged(new DocumentEventArgs(this, 0, 0, value));
textBufferStrategy.SetContent(value);
lineTrackingStrategy.SetContent(value);
undoStack.ClearAll();
OnDocumentChanged(new DocumentEventArgs(this, 0, 0, value));
OnTextContentChanged(EventArgs.Empty);
}
}
public void Insert(int offset, string text)
{
if (readOnly) {
return;
}
OnDocumentAboutToBeChanged(new DocumentEventArgs(this, offset, -1, text));
textBufferStrategy.Insert(offset, text);
lineTrackingStrategy.Insert(offset, text);
undoStack.Push(new UndoableInsert(this, offset, text));
OnDocumentChanged(new DocumentEventArgs(this, offset, -1, text));
}
public void Remove(int offset, int length)
{
if (readOnly) {
return;
}
OnDocumentAboutToBeChanged(new DocumentEventArgs(this, offset, length));
undoStack.Push(new UndoableDelete(this, offset, GetText(offset, length)));
textBufferStrategy.Remove(offset, length);
lineTrackingStrategy.Remove(offset, length);
OnDocumentChanged(new DocumentEventArgs(this, offset, length));
}
public void Replace(int offset, int length, string text)
{
if (readOnly) {
return;
}
OnDocumentAboutToBeChanged(new DocumentEventArgs(this, offset, length, text));
undoStack.Push(new UndoableReplace(this, offset, GetText(offset, length), text));
textBufferStrategy.Replace(offset, length, text);
lineTrackingStrategy.Replace(offset, length, text);
OnDocumentChanged(new DocumentEventArgs(this, offset, length, text));
}
public char GetCharAt(int offset)
{
return textBufferStrategy.GetCharAt(offset);
}
public string GetText(int offset, int length)
{
#if DEBUG
if (length < 0) throw new ArgumentOutOfRangeException("length", length, "length < 0");
#endif
return textBufferStrategy.GetText(offset, length);
}
public string GetText(ISegment segment)
{
return GetText(segment.Offset, segment.Length);
}
public int TotalNumberOfLines {
get {
return lineTrackingStrategy.TotalNumberOfLines;
}
}
public int GetLineNumberForOffset(int offset)
{
return lineTrackingStrategy.GetLineNumberForOffset(offset);
}
public LineSegment GetLineSegmentForOffset(int offset)
{
return lineTrackingStrategy.GetLineSegmentForOffset(offset);
}
public LineSegment GetLineSegment(int line)
{
return lineTrackingStrategy.GetLineSegment(line);
}
public int GetFirstLogicalLine(int lineNumber)
{
return lineTrackingStrategy.GetFirstLogicalLine(lineNumber);
}
public int GetLastLogicalLine(int lineNumber)
{
return lineTrackingStrategy.GetLastLogicalLine(lineNumber);
}
public int GetVisibleLine(int lineNumber)
{
return lineTrackingStrategy.GetVisibleLine(lineNumber);
}
// public int GetVisibleColumn(int logicalLine, int logicalColumn)
// {
// return lineTrackingStrategy.GetVisibleColumn(logicalLine, logicalColumn);
// }
//
public int GetNextVisibleLineAbove(int lineNumber, int lineCount)
{
return lineTrackingStrategy.GetNextVisibleLineAbove(lineNumber, lineCount);
}
public int GetNextVisibleLineBelow(int lineNumber, int lineCount)
{
return lineTrackingStrategy.GetNextVisibleLineBelow(lineNumber, lineCount);
}
public TextLocation OffsetToPosition(int offset)
{
int lineNr = GetLineNumberForOffset(offset);
LineSegment line = GetLineSegment(lineNr);
return new TextLocation(offset - line.Offset, lineNr);
}
public int PositionToOffset(TextLocation p)
{
if (p.Y >= this.TotalNumberOfLines) {
return 0;
}
LineSegment line = GetLineSegment(p.Y);
return Math.Min(this.TextLength, line.Offset + Math.Min(line.Length, p.X));
}
public void UpdateSegmentListOnDocumentChange(List list, DocumentEventArgs e) where T : ISegment
{
int removedCharacters = e.Length > 0 ? e.Length : 0;
int insertedCharacters = e.Text != null ? e.Text.Length : 0;
for (int i = 0; i < list.Count; ++i) {
ISegment s = list[i];
int segmentStart = s.Offset;
int segmentEnd = s.Offset + s.Length;
if (e.Offset <= segmentStart) {
segmentStart -= removedCharacters;
if (segmentStart < e.Offset)
segmentStart = e.Offset;
}
if (e.Offset < segmentEnd) {
segmentEnd -= removedCharacters;
if (segmentEnd < e.Offset)
segmentEnd = e.Offset;
}
Debug.Assert(segmentStart <= segmentEnd);
if (segmentStart == segmentEnd) {
list.RemoveAt(i);
--i;
continue;
}
if (e.Offset <= segmentStart)
segmentStart += insertedCharacters;
if (e.Offset < segmentEnd)
segmentEnd += insertedCharacters;
Debug.Assert(segmentStart < segmentEnd);
s.Offset = segmentStart;
s.Length = segmentEnd - segmentStart;
}
}
void OnDocumentAboutToBeChanged(DocumentEventArgs e)
{
if (DocumentAboutToBeChanged != null) {
DocumentAboutToBeChanged(this, e);
}
}
void OnDocumentChanged(DocumentEventArgs e)
{
if (DocumentChanged != null) {
DocumentChanged(this, e);
}
}
public event DocumentEventHandler DocumentAboutToBeChanged;
public event DocumentEventHandler DocumentChanged;
// UPDATE STUFF
List updateQueue = new List();
public List UpdateQueue {
get {
return updateQueue;
}
}
public void RequestUpdate(TextAreaUpdate update)
{
if (updateQueue.Count == 1 && updateQueue[0].TextAreaUpdateType == TextAreaUpdateType.WholeTextArea) {
// if we're going to update the whole text area, we don't need to store detail updates
return;
}
if (update.TextAreaUpdateType == TextAreaUpdateType.WholeTextArea) {
// if we're going to update the whole text area, we don't need to store detail updates
updateQueue.Clear();
}
updateQueue.Add(update);
}
public void CommitUpdate()
{
if (UpdateCommited != null) {
UpdateCommited(this, EventArgs.Empty);
}
}
void OnTextContentChanged(EventArgs e)
{
if (TextContentChanged != null) {
TextContentChanged(this, e);
}
}
public event EventHandler UpdateCommited;
public event EventHandler TextContentChanged;
[Conditional("DEBUG")]
internal static void ValidatePosition(IDocument document, TextLocation position)
{
document.GetLineSegment(position.Line);
}
}
}