NEU
This commit is contained in:
809
FastColoredTextBox/Commands.cs
Normal file
809
FastColoredTextBox/Commands.cs
Normal file
@@ -0,0 +1,809 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Insert single char
|
||||
/// </summary>
|
||||
/// <remarks>This operation includes also insertion of new line and removing char by backspace</remarks>
|
||||
public class InsertCharCommand : UndoableCommand
|
||||
{
|
||||
public char c;
|
||||
char deletedChar = '\x0';
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
/// <param name="c">Inserting char</param>
|
||||
public InsertCharCommand(TextSource ts, char c): base(ts)
|
||||
{
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
ts.OnTextChanging();
|
||||
switch (c)
|
||||
{
|
||||
case '\n': MergeLines(sel.Start.iLine, ts); break;
|
||||
case '\r': break;
|
||||
case '\b':
|
||||
ts.CurrentTB.Selection.Start = lastSel.Start;
|
||||
char cc = '\x0';
|
||||
if (deletedChar != '\x0')
|
||||
{
|
||||
ts.CurrentTB.ExpandBlock(ts.CurrentTB.Selection.Start.iLine);
|
||||
InsertChar(deletedChar, ref cc, ts);
|
||||
}
|
||||
break;
|
||||
case '\t':
|
||||
ts.CurrentTB.ExpandBlock(sel.Start.iLine);
|
||||
for (int i = sel.FromX; i < lastSel.FromX; i++)
|
||||
ts[sel.Start.iLine].RemoveAt(sel.Start.iChar);
|
||||
ts.CurrentTB.Selection.Start = sel.Start;
|
||||
break;
|
||||
default:
|
||||
ts.CurrentTB.ExpandBlock(sel.Start.iLine);
|
||||
ts[sel.Start.iLine].RemoveAt(sel.Start.iChar);
|
||||
ts.CurrentTB.Selection.Start = sel.Start;
|
||||
break;
|
||||
}
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(sel.Start.iLine, sel.Start.iLine));
|
||||
|
||||
base.Undo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
ts.CurrentTB.ExpandBlock(ts.CurrentTB.Selection.Start.iLine);
|
||||
string s = c.ToString();
|
||||
ts.OnTextChanging(ref s);
|
||||
if (s.Length == 1)
|
||||
c = s[0];
|
||||
|
||||
if (String.IsNullOrEmpty(s))
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
|
||||
if (ts.Count == 0)
|
||||
InsertLine(ts);
|
||||
InsertChar(c, ref deletedChar, ts);
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(ts.CurrentTB.Selection.Start.iLine, ts.CurrentTB.Selection.Start.iLine));
|
||||
base.Execute();
|
||||
}
|
||||
|
||||
internal static void InsertChar(char c, ref char deletedChar, TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
if (!ts.CurrentTB.AllowInsertRemoveLines)
|
||||
throw new ArgumentOutOfRangeException("Cant insert this char in ColumnRange mode");
|
||||
if (ts.Count == 0)
|
||||
InsertLine(ts);
|
||||
InsertLine(ts);
|
||||
break;
|
||||
case '\r': break;
|
||||
case '\b'://backspace
|
||||
if (tb.Selection.Start.iChar == 0 && tb.Selection.Start.iLine == 0)
|
||||
return;
|
||||
if (tb.Selection.Start.iChar == 0)
|
||||
{
|
||||
if (!ts.CurrentTB.AllowInsertRemoveLines)
|
||||
throw new ArgumentOutOfRangeException("Cant insert this char in ColumnRange mode");
|
||||
if (tb.LineInfos[tb.Selection.Start.iLine - 1].VisibleState != VisibleState.Visible)
|
||||
tb.ExpandBlock(tb.Selection.Start.iLine - 1);
|
||||
deletedChar = '\n';
|
||||
MergeLines(tb.Selection.Start.iLine - 1, ts);
|
||||
}
|
||||
else
|
||||
{
|
||||
deletedChar = ts[tb.Selection.Start.iLine][tb.Selection.Start.iChar - 1].c;
|
||||
ts[tb.Selection.Start.iLine].RemoveAt(tb.Selection.Start.iChar - 1);
|
||||
tb.Selection.Start = new Place(tb.Selection.Start.iChar - 1, tb.Selection.Start.iLine);
|
||||
}
|
||||
break;
|
||||
case '\t':
|
||||
int spaceCountNextTabStop = tb.TabLength - (tb.Selection.Start.iChar % tb.TabLength);
|
||||
if (spaceCountNextTabStop == 0)
|
||||
spaceCountNextTabStop = tb.TabLength;
|
||||
|
||||
for (int i = 0; i < spaceCountNextTabStop; i++)
|
||||
ts[tb.Selection.Start.iLine].Insert(tb.Selection.Start.iChar, new Char(' '));
|
||||
|
||||
tb.Selection.Start = new Place(tb.Selection.Start.iChar + spaceCountNextTabStop, tb.Selection.Start.iLine);
|
||||
break;
|
||||
default:
|
||||
ts[tb.Selection.Start.iLine].Insert(tb.Selection.Start.iChar, new Char(c));
|
||||
tb.Selection.Start = new Place(tb.Selection.Start.iChar + 1, tb.Selection.Start.iLine);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void InsertLine(TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
if (!tb.Multiline && tb.LinesCount > 0)
|
||||
return;
|
||||
|
||||
if (ts.Count == 0)
|
||||
ts.InsertLine(0, ts.CreateLine());
|
||||
else
|
||||
BreakLines(tb.Selection.Start.iLine, tb.Selection.Start.iChar, ts);
|
||||
|
||||
tb.Selection.Start = new Place(0, tb.Selection.Start.iLine + 1);
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merge lines i and i+1
|
||||
/// </summary>
|
||||
internal static void MergeLines(int i, TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
if (i + 1 >= ts.Count)
|
||||
return;
|
||||
tb.ExpandBlock(i);
|
||||
tb.ExpandBlock(i + 1);
|
||||
int pos = ts[i].Count;
|
||||
//
|
||||
/*
|
||||
if(ts[i].Count == 0)
|
||||
ts.RemoveLine(i);
|
||||
else*/
|
||||
if (ts[i + 1].Count == 0)
|
||||
ts.RemoveLine(i + 1);
|
||||
else
|
||||
{
|
||||
ts[i].AddRange(ts[i + 1]);
|
||||
ts.RemoveLine(i + 1);
|
||||
}
|
||||
tb.Selection.Start = new Place(pos, i);
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
internal static void BreakLines(int iLine, int pos, TextSource ts)
|
||||
{
|
||||
Line newLine = ts.CreateLine();
|
||||
for(int i=pos;i<ts[iLine].Count;i++)
|
||||
newLine.Add(ts[iLine][i]);
|
||||
ts[iLine].RemoveRange(pos, ts[iLine].Count - pos);
|
||||
//
|
||||
ts.InsertLine(iLine+1, newLine);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new InsertCharCommand(ts, c);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert text
|
||||
/// </summary>
|
||||
public class InsertTextCommand : UndoableCommand
|
||||
{
|
||||
public string InsertedText;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
/// <param name="insertedText">Text for inserting</param>
|
||||
public InsertTextCommand(TextSource ts, string insertedText): base(ts)
|
||||
{
|
||||
this.InsertedText = insertedText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
ts.CurrentTB.Selection.Start = sel.Start;
|
||||
ts.CurrentTB.Selection.End = lastSel.Start;
|
||||
ts.OnTextChanging();
|
||||
ClearSelectedCommand.ClearSelected(ts);
|
||||
base.Undo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
ts.OnTextChanging(ref InsertedText);
|
||||
InsertText(InsertedText, ts);
|
||||
base.Execute();
|
||||
}
|
||||
|
||||
internal static void InsertText(string insertedText, TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
try
|
||||
{
|
||||
tb.Selection.BeginUpdate();
|
||||
char cc = '\x0';
|
||||
|
||||
if (ts.Count == 0)
|
||||
{
|
||||
InsertCharCommand.InsertLine(ts);
|
||||
tb.Selection.Start = Place.Empty;
|
||||
}
|
||||
tb.ExpandBlock(tb.Selection.Start.iLine);
|
||||
var len = insertedText.Length;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
var c = insertedText[i];
|
||||
if(c == '\r' && (i >= len - 1 || insertedText[i + 1] != '\n'))
|
||||
InsertCharCommand.InsertChar('\n', ref cc, ts);
|
||||
else
|
||||
InsertCharCommand.InsertChar(c, ref cc, ts);
|
||||
}
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
finally {
|
||||
tb.Selection.EndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new InsertTextCommand(ts, InsertedText);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert text into given ranges
|
||||
/// </summary>
|
||||
public class ReplaceTextCommand : UndoableCommand
|
||||
{
|
||||
string insertedText;
|
||||
List<Range> ranges;
|
||||
List<string> prevText = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
/// <param name="ranges">List of ranges for replace</param>
|
||||
/// <param name="insertedText">Text for inserting</param>
|
||||
public ReplaceTextCommand(TextSource ts, List<Range> ranges, string insertedText)
|
||||
: base(ts)
|
||||
{
|
||||
//sort ranges by place
|
||||
ranges.Sort((r1, r2)=>
|
||||
{
|
||||
if (r1.Start.iLine == r2.Start.iLine)
|
||||
return r1.Start.iChar.CompareTo(r2.Start.iChar);
|
||||
return r1.Start.iLine.CompareTo(r2.Start.iLine);
|
||||
});
|
||||
//
|
||||
this.ranges = ranges;
|
||||
this.insertedText = insertedText;
|
||||
lastSel = sel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
ts.OnTextChanging();
|
||||
tb.BeginUpdate();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
for (int i = 0; i<ranges.Count; i++)
|
||||
{
|
||||
tb.Selection.Start = ranges[i].Start;
|
||||
for (int j = 0; j < insertedText.Length; j++)
|
||||
tb.Selection.GoRight(true);
|
||||
ClearSelected(ts);
|
||||
InsertTextCommand.InsertText(prevText[prevText.Count - i - 1], ts);
|
||||
}
|
||||
tb.Selection.EndUpdate();
|
||||
tb.EndUpdate();
|
||||
|
||||
if (ranges.Count > 0)
|
||||
ts.OnTextChanged(ranges[0].Start.iLine, ranges[ranges.Count - 1].End.iLine);
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
prevText.Clear();
|
||||
|
||||
ts.OnTextChanging(ref insertedText);
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
tb.BeginUpdate();
|
||||
for (int i = ranges.Count - 1; i >= 0; i--)
|
||||
{
|
||||
tb.Selection.Start = ranges[i].Start;
|
||||
tb.Selection.End = ranges[i].End;
|
||||
prevText.Add(tb.Selection.Text);
|
||||
ClearSelected(ts);
|
||||
if (insertedText != "")
|
||||
InsertTextCommand.InsertText(insertedText, ts);
|
||||
}
|
||||
if(ranges.Count > 0)
|
||||
ts.OnTextChanged(ranges[0].Start.iLine, ranges[ranges.Count - 1].End.iLine);
|
||||
tb.EndUpdate();
|
||||
tb.Selection.EndUpdate();
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
|
||||
lastSel = new RangeInfo(tb.Selection);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new ReplaceTextCommand(ts, new List<Range>(ranges), insertedText);
|
||||
}
|
||||
|
||||
internal static void ClearSelected(TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
tb.Selection.Normalize();
|
||||
|
||||
Place start = tb.Selection.Start;
|
||||
Place end = tb.Selection.End;
|
||||
int fromLine = Math.Min(end.iLine, start.iLine);
|
||||
int toLine = Math.Max(end.iLine, start.iLine);
|
||||
int fromChar = tb.Selection.FromX;
|
||||
int toChar = tb.Selection.ToX;
|
||||
if (fromLine < 0) return;
|
||||
//
|
||||
if (fromLine == toLine)
|
||||
ts[fromLine].RemoveRange(fromChar, toChar - fromChar);
|
||||
else
|
||||
{
|
||||
ts[fromLine].RemoveRange(fromChar, ts[fromLine].Count - fromChar);
|
||||
ts[toLine].RemoveRange(0, toChar);
|
||||
ts.RemoveLine(fromLine + 1, toLine - fromLine - 1);
|
||||
InsertCharCommand.MergeLines(fromLine, ts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear selected text
|
||||
/// </summary>
|
||||
public class ClearSelectedCommand : UndoableCommand
|
||||
{
|
||||
string deletedText;
|
||||
|
||||
/// <summary>
|
||||
/// Construstor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
public ClearSelectedCommand(TextSource ts): base(ts)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
ts.CurrentTB.Selection.Start = new Place(sel.FromX, Math.Min(sel.Start.iLine, sel.End.iLine));
|
||||
ts.OnTextChanging();
|
||||
InsertTextCommand.InsertText(deletedText, ts);
|
||||
ts.OnTextChanged(sel.Start.iLine, sel.End.iLine);
|
||||
ts.CurrentTB.Selection.Start = sel.Start;
|
||||
ts.CurrentTB.Selection.End = sel.End;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
string temp = null;
|
||||
ts.OnTextChanging(ref temp);
|
||||
if (temp == "")
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
deletedText = tb.Selection.Text;
|
||||
ClearSelected(ts);
|
||||
lastSel = new RangeInfo(tb.Selection);
|
||||
ts.OnTextChanged(lastSel.Start.iLine, lastSel.Start.iLine);
|
||||
}
|
||||
|
||||
internal static void ClearSelected(TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
Place start = tb.Selection.Start;
|
||||
Place end = tb.Selection.End;
|
||||
int fromLine = Math.Min(end.iLine, start.iLine);
|
||||
int toLine = Math.Max(end.iLine, start.iLine);
|
||||
int fromChar = tb.Selection.FromX;
|
||||
int toChar = tb.Selection.ToX;
|
||||
if (fromLine < 0) return;
|
||||
//
|
||||
if (fromLine == toLine)
|
||||
ts[fromLine].RemoveRange(fromChar, toChar - fromChar);
|
||||
else
|
||||
{
|
||||
ts[fromLine].RemoveRange(fromChar, ts[fromLine].Count - fromChar);
|
||||
ts[toLine].RemoveRange(0, toChar);
|
||||
ts.RemoveLine(fromLine + 1, toLine - fromLine - 1);
|
||||
InsertCharCommand.MergeLines(fromLine, ts);
|
||||
}
|
||||
//
|
||||
tb.Selection.Start = new Place(fromChar, fromLine);
|
||||
//
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(fromLine, toLine));
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new ClearSelectedCommand(ts);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces text
|
||||
/// </summary>
|
||||
public class ReplaceMultipleTextCommand : UndoableCommand
|
||||
{
|
||||
List<ReplaceRange> ranges;
|
||||
List<string> prevText = new List<string>();
|
||||
|
||||
public class ReplaceRange
|
||||
{
|
||||
public Range ReplacedRange { get; set; }
|
||||
public String ReplaceText { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="ts">Underlaying textsource</param>
|
||||
/// <param name="ranges">List of ranges for replace</param>
|
||||
public ReplaceMultipleTextCommand(TextSource ts, List<ReplaceRange> ranges)
|
||||
: base(ts)
|
||||
{
|
||||
//sort ranges by place
|
||||
ranges.Sort((r1, r2) =>
|
||||
{
|
||||
if (r1.ReplacedRange.Start.iLine == r2.ReplacedRange.Start.iLine)
|
||||
return r1.ReplacedRange.Start.iChar.CompareTo(r2.ReplacedRange.Start.iChar);
|
||||
return r1.ReplacedRange.Start.iLine.CompareTo(r2.ReplacedRange.Start.iLine);
|
||||
});
|
||||
//
|
||||
this.ranges = ranges;
|
||||
lastSel = sel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
ts.OnTextChanging();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
for (int i = 0; i < ranges.Count; i++)
|
||||
{
|
||||
tb.Selection.Start = ranges[i].ReplacedRange.Start;
|
||||
for (int j = 0; j < ranges[i].ReplaceText.Length; j++)
|
||||
tb.Selection.GoRight(true);
|
||||
ClearSelectedCommand.ClearSelected(ts);
|
||||
var prevTextIndex = ranges.Count - 1 - i;
|
||||
InsertTextCommand.InsertText(prevText[prevTextIndex], ts);
|
||||
ts.OnTextChanged(ranges[i].ReplacedRange.Start.iLine, ranges[i].ReplacedRange.Start.iLine);
|
||||
}
|
||||
tb.Selection.EndUpdate();
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
prevText.Clear();
|
||||
|
||||
ts.OnTextChanging();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
for (int i = ranges.Count - 1; i >= 0; i--)
|
||||
{
|
||||
tb.Selection.Start = ranges[i].ReplacedRange.Start;
|
||||
tb.Selection.End = ranges[i].ReplacedRange.End;
|
||||
prevText.Add(tb.Selection.Text);
|
||||
ClearSelectedCommand.ClearSelected(ts);
|
||||
InsertTextCommand.InsertText(ranges[i].ReplaceText, ts);
|
||||
ts.OnTextChanged(ranges[i].ReplacedRange.Start.iLine, ranges[i].ReplacedRange.End.iLine);
|
||||
}
|
||||
tb.Selection.EndUpdate();
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
|
||||
lastSel = new RangeInfo(tb.Selection);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new ReplaceMultipleTextCommand(ts, new List<ReplaceRange>(ranges));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes lines
|
||||
/// </summary>
|
||||
public class RemoveLinesCommand : UndoableCommand
|
||||
{
|
||||
List<int> iLines;
|
||||
List<string> prevText = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
/// <param name="ranges">List of ranges for replace</param>
|
||||
/// <param name="insertedText">Text for inserting</param>
|
||||
public RemoveLinesCommand(TextSource ts, List<int> iLines)
|
||||
: base(ts)
|
||||
{
|
||||
//sort iLines
|
||||
iLines.Sort();
|
||||
//
|
||||
this.iLines = iLines;
|
||||
lastSel = sel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
ts.OnTextChanging();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
//tb.BeginUpdate();
|
||||
for (int i = 0; i < iLines.Count; i++)
|
||||
{
|
||||
var iLine = iLines[i];
|
||||
|
||||
if(iLine < ts.Count)
|
||||
tb.Selection.Start = new Place(0, iLine);
|
||||
else
|
||||
tb.Selection.Start = new Place(ts[ts.Count - 1].Count, ts.Count - 1);
|
||||
|
||||
InsertCharCommand.InsertLine(ts);
|
||||
tb.Selection.Start = new Place(0, iLine);
|
||||
var text = prevText[prevText.Count - i - 1];
|
||||
InsertTextCommand.InsertText(text, ts);
|
||||
ts[iLine].IsChanged = true;
|
||||
if (iLine < ts.Count - 1)
|
||||
ts[iLine + 1].IsChanged = true;
|
||||
else
|
||||
ts[iLine - 1].IsChanged = true;
|
||||
if(text.Trim() != string.Empty)
|
||||
ts.OnTextChanged(iLine, iLine);
|
||||
}
|
||||
//tb.EndUpdate();
|
||||
tb.Selection.EndUpdate();
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
prevText.Clear();
|
||||
|
||||
ts.OnTextChanging();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
for(int i = iLines.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var iLine = iLines[i];
|
||||
|
||||
prevText.Add(ts[iLine].Text);//backward
|
||||
ts.RemoveLine(iLine);
|
||||
//ts.OnTextChanged(ranges[i].Start.iLine, ranges[i].End.iLine);
|
||||
}
|
||||
tb.Selection.Start = new Place(0, 0);
|
||||
tb.Selection.EndUpdate();
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
|
||||
lastSel = new RangeInfo(tb.Selection);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new RemoveLinesCommand(ts, new List<int>(iLines));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper for multirange commands
|
||||
/// </summary>
|
||||
public class MultiRangeCommand : UndoableCommand
|
||||
{
|
||||
private UndoableCommand cmd;
|
||||
private Range range;
|
||||
private List<UndoableCommand> commandsByRanges = new List<UndoableCommand>();
|
||||
|
||||
public MultiRangeCommand(UndoableCommand command):base(command.ts)
|
||||
{
|
||||
this.cmd = command;
|
||||
range = ts.CurrentTB.Selection.Clone();
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
commandsByRanges.Clear();
|
||||
var prevSelection = range.Clone();
|
||||
var iChar = -1;
|
||||
var iStartLine = prevSelection.Start.iLine;
|
||||
var iEndLine = prevSelection.End.iLine;
|
||||
ts.CurrentTB.Selection.ColumnSelectionMode = false;
|
||||
ts.CurrentTB.Selection.BeginUpdate();
|
||||
ts.CurrentTB.BeginUpdate();
|
||||
ts.CurrentTB.AllowInsertRemoveLines = false;
|
||||
try
|
||||
{
|
||||
if (cmd is InsertTextCommand)
|
||||
ExecuteInsertTextCommand(ref iChar, (cmd as InsertTextCommand).InsertedText);
|
||||
else
|
||||
if (cmd is InsertCharCommand && (cmd as InsertCharCommand).c != '\x0' && (cmd as InsertCharCommand).c != '\b')//if not DEL or BACKSPACE
|
||||
ExecuteInsertTextCommand(ref iChar, (cmd as InsertCharCommand).c.ToString());
|
||||
else
|
||||
ExecuteCommand(ref iChar);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
ts.CurrentTB.AllowInsertRemoveLines = true;
|
||||
ts.CurrentTB.EndUpdate();
|
||||
|
||||
ts.CurrentTB.Selection = range;
|
||||
if (iChar >= 0)
|
||||
{
|
||||
ts.CurrentTB.Selection.Start = new Place(iChar, iStartLine);
|
||||
ts.CurrentTB.Selection.End = new Place(iChar, iEndLine);
|
||||
}
|
||||
ts.CurrentTB.Selection.ColumnSelectionMode = true;
|
||||
ts.CurrentTB.Selection.EndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteInsertTextCommand(ref int iChar, string text)
|
||||
{
|
||||
var lines = text.Split('\n');
|
||||
var iLine = 0;
|
||||
foreach (var r in range.GetSubRanges(true))
|
||||
{
|
||||
var line = ts.CurrentTB[r.Start.iLine];
|
||||
var lineIsEmpty = r.End < r.Start && line.StartSpacesCount == line.Count;
|
||||
if (!lineIsEmpty)
|
||||
{
|
||||
var insertedText = lines[iLine%lines.Length];
|
||||
if (r.End < r.Start && insertedText!="")
|
||||
{
|
||||
//add forwarding spaces
|
||||
insertedText = new string(' ', r.Start.iChar - r.End.iChar) + insertedText;
|
||||
r.Start = r.End;
|
||||
}
|
||||
ts.CurrentTB.Selection = r;
|
||||
var c = new InsertTextCommand(ts, insertedText);
|
||||
c.Execute();
|
||||
if (ts.CurrentTB.Selection.End.iChar > iChar)
|
||||
iChar = ts.CurrentTB.Selection.End.iChar;
|
||||
commandsByRanges.Add(c);
|
||||
}
|
||||
iLine++;
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteCommand(ref int iChar)
|
||||
{
|
||||
foreach (var r in range.GetSubRanges(false))
|
||||
{
|
||||
ts.CurrentTB.Selection = r;
|
||||
var c = cmd.Clone();
|
||||
c.Execute();
|
||||
if (ts.CurrentTB.Selection.End.iChar > iChar)
|
||||
iChar = ts.CurrentTB.Selection.End.iChar;
|
||||
commandsByRanges.Add(c);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Undo()
|
||||
{
|
||||
ts.CurrentTB.BeginUpdate();
|
||||
ts.CurrentTB.Selection.BeginUpdate();
|
||||
try
|
||||
{
|
||||
for (int i = commandsByRanges.Count - 1; i >= 0; i--)
|
||||
commandsByRanges[i].Undo();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ts.CurrentTB.Selection.EndUpdate();
|
||||
ts.CurrentTB.EndUpdate();
|
||||
}
|
||||
ts.CurrentTB.Selection = range.Clone();
|
||||
ts.CurrentTB.OnTextChanged(range);
|
||||
ts.CurrentTB.OnSelectionChanged();
|
||||
ts.CurrentTB.Selection.ColumnSelectionMode = true;
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remembers current selection and restore it after Undo
|
||||
/// </summary>
|
||||
public class SelectCommand : UndoableCommand
|
||||
{
|
||||
public SelectCommand(TextSource ts):base(ts)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
//remember selection
|
||||
lastSel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
}
|
||||
|
||||
protected override void OnTextChanged(bool invert)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Undo()
|
||||
{
|
||||
//restore selection
|
||||
ts.CurrentTB.Selection = new Range(ts.CurrentTB, lastSel.Start, lastSel.End);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
var result = new SelectCommand(ts);
|
||||
if(lastSel!=null)
|
||||
result.lastSel = new RangeInfo(new Range(ts.CurrentTB, lastSel.Start, lastSel.End));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user