2 * Copyright (C) 2013 FooProject
\r
3 * * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
\r
4 * the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
\r
6 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
\r
9 You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
\r
12 using System.Globalization;
\r
15 using System.Diagnostics;
\r
16 using System.Text.RegularExpressions;
\r
18 using System.Drawing;
\r
21 namespace FooEditEngine
\r
23 internal enum MoveFlow
\r
28 internal enum ScrollDirection
\r
36 /// ユーザー側からの処理を担当するクラス。一部を除き、こちらで行われた操作はアンドゥの対象になります
\r
38 internal sealed class Controller
\r
44 public Controller(Document doc, EditView view)
\r
46 this.Document = doc;
\r
47 this.Document.Update += new DocumentUpdateEventHandler(Document_Update);
\r
48 this.Document.Progress += Document_Progress;
\r
50 this.View.render.ChangedRightToLeft += render_ChangedRightToLeft;
\r
51 this.View.render.ChangedRenderResource += render_ChangedRenderResource;
\r
52 this.View.PerformLayouted += View_LineBreakChanged;
\r
53 this.View.PageBoundChanged += View_PageBoundChanged;
\r
54 this.Document.Clear();
\r
55 this.CaretMoved += new EventHandler((s, e) => { });
\r
61 public event EventHandler CaretMoved;
\r
65 /// 矩形選択モードなら真を返し、そうでない場合は偽を返す
\r
67 public bool RectSelection
\r
76 /// <remarks>SelectionLengthが0の場合、キャレット位置を表します</remarks>
\r
77 public int SelectionStart
\r
81 if (this.Document.Selections.Count == 0)
\r
82 return this.AnchorIndex;
\r
84 return this.Document.Selections.First().start;
\r
91 /// <remarks>矩形選択モードの場合、選択範囲の文字数ではなく、開始位置から終了位置までの長さとなります</remarks>
\r
92 public int SelectionLength
\r
96 if (this.Document.Selections.Count == 0)
\r
98 Selection last = this.Document.Selections.Last();
\r
99 return last.start + last.length - this.SelectionStart;
\r
107 /// 未選択状態で代入したときは追加され、そうでない場合は選択範囲の文字列と置き換えられます。
\r
109 public string SelectedText
\r
113 if (this.View.LayoutLines.Count == 0 || this.Document.Selections.Count == 0)
\r
115 if (this.RectSelection)
\r
116 return GetTextFromRectangleSelectArea(this.Document.Selections);
\r
118 return GetTextFromLineSelectArea(this.Document.Selections);
\r
122 if (this.Document.FireUpdateEvent == false)
\r
123 throw new InvalidOperationException("");
\r
124 this.RepleaceSelectionArea(this.Document.Selections, value);
\r
129 /// 選択範囲が逆転しているかどうかを判定する
\r
131 /// <returns>逆転しているなら真を返す</returns>
\r
132 public bool IsReverseSelect()
\r
134 int index = this.View.LayoutLines.GetIndexFromTextPoint(this.View.CaretPostion);
\r
135 return index < this.AnchorIndex;
\r
141 /// <param name="start"></param>
\r
142 /// <param name="length"></param>
\r
143 /// <remarks>RectSelectionの値によって動作が変わります。真の場合は矩形選択モードに、そうでない場合は行ごとに選択されます</remarks>
\r
144 public void Select(int start, int length)
\r
146 if (this.Document.FireUpdateEvent == false)
\r
147 throw new InvalidOperationException("");
\r
148 if (start < 0 || start + length < 0 || start + length > this.Document.Length)
\r
149 throw new ArgumentOutOfRangeException("startかendが指定できる範囲を超えてます");
\r
150 this.Document.Selections.Clear();
\r
153 int oldStart = start;
\r
155 length = oldStart - start;
\r
157 if (this.RectSelection && length != 0)
\r
159 TextPoint startTextPoint = this.View.GetLayoutLineFromIndex(start);
\r
160 TextPoint endTextPoint = this.View.GetLayoutLineFromIndex(start + length);
\r
161 this.SelectByRectangle(new TextRectangle(startTextPoint, endTextPoint));
\r
162 if (startTextPoint.col == endTextPoint.col)
\r
163 this.View.InsertPoint = new SelectCollection(this.Document.Selections);
\r
165 this.View.InsertPoint = null;
\r
169 this.Document.Selections.Add(Selection.Create(start, length));
\r
170 this.View.InsertPoint = null;
\r
174 public void Select(TextPoint tp, int width, int height)
\r
176 if (this.Document.FireUpdateEvent == false || !this.RectSelection)
\r
177 throw new InvalidOperationException("");
\r
178 TextPoint end = tp;
\r
180 end.row = tp.row + height;
\r
181 end.col = tp.col + width;
\r
183 if (end.row > this.View.LayoutLines.Count - 1)
\r
184 throw new ArgumentOutOfRangeException("");
\r
186 this.Document.Selections.Clear();
\r
188 this.SelectByRectangle(new TextRectangle(tp,end));
\r
191 this.View.InsertPoint = new SelectCollection(this.Document.Selections);
\r
193 this.View.InsertPoint = null;
\r
196 private void SelectByRectangle(TextRectangle rect)
\r
198 if (this.Document.FireUpdateEvent == false)
\r
199 throw new InvalidOperationException("");
\r
200 if (rect.TopLeft <= rect.BottomRight)
\r
202 for (int i = rect.TopLeft.row; i <= rect.BottomLeft.row; i++)
\r
204 LineToIndexTableData lineData = this.View.LayoutLines.GetData(i);
\r
205 int leftCol = rect.TopLeft.col,
\r
206 rightCol = rect.TopRight.col,
\r
207 lastCol = this.View.LayoutLines[i][lineData.Length - 1] == Document.NewLine ? lineData.Length - 1 : lineData.Length;
\r
210 if (rect.TopLeft.col > lastCol)
\r
212 if (rect.TopRight.col > lastCol)
\r
213 rightCol = lastCol;
\r
214 int padding = rect.TopLeft.col - leftCol;
\r
216 int StartIndex = this.View.LayoutLines.GetIndexFromTextPoint(new TextPoint(i, leftCol));
\r
217 int EndIndex = this.View.LayoutLines.GetIndexFromTextPoint(new TextPoint(i, rightCol));
\r
220 sel = Selection.Create(StartIndex, EndIndex - StartIndex,padding);
\r
222 this.Document.Selections.Add(sel);
\r
230 /// <param name="index">探索を開始するインデックス</param>
\r
231 public void SelectWord(int index)
\r
233 if (this.Document.FireUpdateEvent == false)
\r
234 throw new InvalidOperationException("");
\r
236 if (this.Document.Length <= 0 || index >= this.Document.Length)
\r
239 Document str = this.Document;
\r
242 while (start > 0 && !Util.IsWordSeparator(str[start]))
\r
245 if (Util.IsWordSeparator(str[start]))
\r
249 while (end < this.Document.Length && !Util.IsWordSeparator(str[end]))
\r
252 this.Select(start, end - start);
\r
256 /// 選択範囲内のUTF32コードポイントを文字列に変換します
\r
258 /// <returns>成功した場合は真。そうでない場合は偽を返す</returns>
\r
259 public bool ConvertToChar()
\r
261 if (this.SelectionLength == 0 || this.RectSelection)
\r
263 string str = this.Document.ToString(this.SelectionStart, this.SelectionLength);
\r
264 string[] codes = str.Split(new char[] { ' ' },StringSplitOptions.RemoveEmptyEntries);
\r
265 StringBuilder result = new StringBuilder();
\r
266 foreach (string code in codes)
\r
269 if (code[0] != 'U')
\r
271 if (Int32.TryParse(code.TrimStart('U'),NumberStyles.HexNumber,null, out utf32_code))
\r
272 result.Append(Char.ConvertFromUtf32(utf32_code));
\r
276 this.Document.Replace(this.SelectionStart, this.SelectionLength, result.ToString());
\r
281 /// 選択文字列をUTF32のコードポイントに変換します
\r
283 public void ConvertToCodePoint()
\r
285 if (this.SelectionLength == 0 || this.RectSelection)
\r
287 string str = this.Document.ToString(this.SelectionStart, this.SelectionLength);
\r
288 StringInfo info = new StringInfo(str);
\r
289 StringBuilder result = new StringBuilder();
\r
290 for (int i = 0; i < str.Length;)
\r
292 int utf32_code = Char.ConvertToUtf32(str, i);
\r
293 result.Append("U" + Convert.ToString(utf32_code,16));
\r
294 result.Append(' ');
\r
295 if(Char.IsHighSurrogate(str[i]))
\r
300 this.Document.Replace(this.SelectionStart, this.SelectionLength, result.ToString());
\r
306 public void DeSelectAll()
\r
308 if (this.Document.FireUpdateEvent == false)
\r
309 throw new InvalidOperationException("");
\r
311 this.Document.Selections.Clear();
\r
317 /// <param name="tp"></param>
\r
318 /// <param name="type"></param>
\r
319 /// <returns>真ならマーカーがある</returns>
\r
320 public bool IsMarker(TextPoint tp,HilightType type)
\r
322 if (this.Document.FireUpdateEvent == false)
\r
323 throw new InvalidOperationException("");
\r
324 int index = this.View.LayoutLines.GetIndexFromTextPoint(tp);
\r
325 return this.IsMarker(index, type);
\r
329 /// 任意のマーカーかどうか判定する
\r
331 /// <param name="index"></param>
\r
332 /// <param name="type"></param>
\r
333 /// <returns>真ならマーカーがある</returns>
\r
334 public bool IsMarker(int index, HilightType type)
\r
336 foreach (Marker m in this.Document.GetMarkers(index))
\r
338 if (m.hilight == type)
\r
347 public void AdjustCaret()
\r
349 int row = this.View.CaretPostion.row;
\r
350 if (row > this.View.LayoutLines.Count - 1)
\r
351 row = this.View.LayoutLines.Count - 1;
\r
352 int col = this.View.CaretPostion.col;
\r
353 if (col > 0 && col > this.View.LayoutLines[row].Length)
\r
354 col = this.View.LayoutLines[row].Length;
\r
355 this.JumpCaret(row, col);
\r
359 /// キャレットを指定した位置に移動させる
\r
361 /// <param name="index"></param>
\r
362 /// <param name="autoExpand">折り畳みを展開するなら真</param>
\r
363 public void JumpCaret(int index,bool autoExpand = true)
\r
365 if (index < 0 || index > this.Document.Length)
\r
366 throw new ArgumentOutOfRangeException("indexが設定できる範囲を超えています");
\r
367 TextPoint tp = this.View.GetLayoutLineFromIndex(index);
\r
369 this.JumpCaret(tp.row, tp.col,autoExpand);
\r
373 /// キャレットを指定した位置に移動させる
\r
375 /// <param name="row"></param>
\r
376 /// <param name="col"></param>
\r
377 /// <param name="autoExpand">折り畳みを展開するなら真</param>
\r
378 public void JumpCaret(int row, int col, bool autoExpand = true)
\r
380 if (this.Document.FireUpdateEvent == false)
\r
381 throw new InvalidOperationException("");
\r
383 this.View.JumpCaret(row, col,autoExpand);
\r
385 this.View.AdjustCaretAndSrc();
\r
387 this.SelectWithMoveCaret(false);
\r
389 this.CaretMoved(this, null);
\r
395 /// <param name="isSelected"></param>
\r
396 public void JumpToHead(bool isSelected)
\r
398 if (this.View.TryScroll(0, 0))
\r
400 this.View.JumpCaret(0, 0);
\r
401 this.View.AdjustCaretAndSrc();
\r
402 this.SelectWithMoveCaret(isSelected);
\r
403 this.CaretMoved(this, null);
\r
407 /// ドキュメントの終わりにに移動する
\r
409 /// <param name="isSelected"></param>
\r
410 public void JumpToEnd(bool isSelected)
\r
412 int srcRow = this.View.LayoutLines.Count - this.View.LineCountOnScreen - 1;
\r
415 if (this.View.TryScroll(0, srcRow))
\r
417 this.View.JumpCaret(this.View.LayoutLines.Count - 1, 0);
\r
418 this.View.AdjustCaretAndSrc();
\r
419 this.SelectWithMoveCaret(isSelected);
\r
420 this.CaretMoved(this, null);
\r
426 /// <param name="dir">方向を指定する</param>
\r
427 /// <param name="delta">スクロールする量。ScrollDirectionの値がUpやDownなら行数。LeftやRightならピクセル単位の値となる</param>
\r
428 /// <param name="isSelected">選択状態にするなら真</param>
\r
429 /// <param name="withCaret">同時にキャレットを移動させるなら真</param>
\r
430 public void Scroll(ScrollDirection dir, int delta, bool isSelected,bool withCaret)
\r
432 if (this.Document.FireUpdateEvent == false)
\r
433 throw new InvalidOperationException("");
\r
434 int toRow = this.View.Src.Row;
\r
435 double toX = this.View.Src.X;
\r
438 case ScrollDirection.Up:
\r
439 toRow = Math.Max(0, this.View.Src.Row - delta);
\r
440 toRow = this.View.AdjustRow(toRow, false);
\r
442 case ScrollDirection.Down:
\r
443 toRow = Math.Min(this.View.Src.Row + delta, this.View.LayoutLines.Count - 1);
\r
444 toRow = this.View.AdjustRow(toRow, true);
\r
446 case ScrollDirection.Left:
\r
449 case ScrollDirection.Right:
\r
453 throw new ArgumentOutOfRangeException();
\r
455 this.Scroll(toX, toRow, isSelected, withCaret);
\r
461 /// <param name="toX">スクロール先の座標</param>
\r
462 /// <param name="toRow">スクロール先の行</param>
\r
463 /// <param name="isSelected">選択状態にするなら真</param>
\r
464 /// <param name="withCaret">同時にキャレットを移動させるなら真</param>
\r
465 public void Scroll(double toX, int toRow, bool isSelected, bool withCaret)
\r
469 this.View.Scroll(toX, toRow);
\r
470 this.View.JumpCaret(toRow, 0);
\r
471 this.View.AdjustCaretAndSrc();
\r
472 this.SelectWithMoveCaret(isSelected);
\r
473 this.CaretMoved(this, null);
\r
477 this.View.Scroll(toX, toRow);
\r
478 this.View.HideCaret = true;
\r
483 /// キャレットを動かすことができるかどうか
\r
485 /// <param name="realLength"></param>
\r
486 /// <param name="flow"></param>
\r
487 /// <returns>移動できるなら真。そうでないなら偽</returns>
\r
488 public bool IsCanMoveCaret(int realLength,MoveFlow flow)
\r
490 LineToIndexTableData lineData = this.View.LayoutLines.GetData(this.View.CaretPostion.row);
\r
491 int index = lineData.Index + this.View.CaretPostion.col;
\r
492 int documentEndIndex = this.Document.Length - 1;
\r
493 FoldingItem foldingData = this.View.LayoutLines.FoldingCollection.GetFarestHiddenFoldingData(index, lineData.Length);
\r
494 if (foldingData != null && !foldingData.Expand && foldingData.End == documentEndIndex)
\r
496 documentEndIndex = lineData.Index + lineData.Length - 1;
\r
497 if (this.Document[documentEndIndex] == Document.NewLine)
\r
498 documentEndIndex--;
\r
501 if (flow == MoveFlow.Vertical)
\r
503 if (realLength < 0 && index == 0)
\r
505 else if (realLength > 0 && index >= documentEndIndex)
\r
508 else if (flow == MoveFlow.Horizontical)
\r
510 bool IncrimentCaret = realLength > 0;
\r
511 if (this.View.render.RightToLeft)
\r
512 IncrimentCaret = !IncrimentCaret;
\r
513 if (!IncrimentCaret && index == 0)
\r
515 else if (IncrimentCaret && index > documentEndIndex)
\r
522 /// キャレットを桁方向に移動させる
\r
524 /// <returns>移動できない場合は真を返す</returns>
\r
525 /// <param name="realLength">負の値なら左側へ、そうでないなら右側へ移動する</param>
\r
526 /// <param name="isSelected">選択範囲とするなら真。そうでないなら偽</param>
\r
527 /// <param name="alignWord">単語単位で移動するなら真。そうでないなら偽</param>
\r
528 public void MoveCaretHorizontical(int realLength, bool isSelected,bool alignWord = false)
\r
530 for (int i = Math.Abs(realLength); i > 0; i--)
\r
532 bool MoveFlow = realLength > 0;
\r
533 if (this.View.render.RightToLeft)
\r
534 MoveFlow = !MoveFlow;
\r
535 this.MoveCaretHorizontical(MoveFlow);
\r
538 this.AlignNearestWord(MoveFlow);
\r
540 this.View.AdjustCaretAndSrc(AdjustFlow.Col);
\r
541 this.SelectWithMoveCaret(isSelected);
\r
542 this.CaretMoved(this, null);
\r
545 void AlignNearestWord(bool MoveFlow)
\r
547 string str = this.View.LayoutLines[this.View.CaretPostion.row];
\r
548 while (this.View.CaretPostion.col > 0 &&
\r
549 this.View.CaretPostion.col < str.Length &&
\r
550 str[this.View.CaretPostion.col] != Document.NewLine)
\r
552 if (!Util.IsWordSeparator(str[this.View.CaretPostion.col]))
\r
554 this.MoveCaretHorizontical(MoveFlow);
\r
559 this.MoveCaretHorizontical(MoveFlow);
\r
566 /// キャレットを行方向に移動させる
\r
568 /// <returns>再描写する必要があるなら真を返す</returns>
\r
569 /// <param name="deltarow">移動量</param>
\r
570 /// <param name="isSelected"></param>
\r
571 public void MoveCaretVertical(int deltarow,bool isSelected)
\r
573 for (int i = Math.Abs(deltarow); i > 0; i--)
\r
574 this.MoveCaretVertical(deltarow > 0);
\r
575 this.View.AdjustCaretAndSrc(AdjustFlow.Both);
\r
576 this.SelectWithMoveCaret(isSelected);
\r
577 this.CaretMoved(this, null);
\r
581 /// キャレット位置の文字を一文字削除する
\r
583 public void DoDeleteAction()
\r
585 if (this.SelectionLength != 0)
\r
587 this.SelectedText = "";
\r
591 if (this.Document.FireUpdateEvent == false)
\r
592 throw new InvalidOperationException("");
\r
594 TextPoint CaretPostion = this.View.CaretPostion;
\r
595 int index = this.View.GetIndexFromLayoutLine(CaretPostion);
\r
597 if (index == this.Document.Length)
\r
600 LineToIndexTableData currentLine = this.View.LayoutLines.GetData(CaretPostion.row);
\r
602 int next = currentLine.Layout.AlignIndexToNearestCluster(CaretPostion.col, AlignDirection.Forward) + currentLine.Index;
\r
604 if (this.Document[index] == Document.NewLine)
\r
607 this.Document.Replace(index, next - index, "");
\r
611 /// キャレット位置の文字を一文字削除し、キャレット位置を後ろにずらす
\r
613 public void DoBackSpaceAction()
\r
615 if (this.View.InsertPoint != null)
\r
617 this.ReplaceBeforeSelectionArea(this.Document.Selections, 1, "");
\r
620 else if (this.SelectionLength > 0)
\r
622 this.SelectedText = "";
\r
626 if (this.Document.FireUpdateEvent == false)
\r
627 throw new InvalidOperationException("");
\r
629 TextPoint CurrentPostion = this.View.CaretPostion;
\r
631 if (CurrentPostion.row == 0 && CurrentPostion.col == 0)
\r
634 int oldIndex = this.View.GetIndexFromLayoutLine(CurrentPostion);
\r
636 int newCol, newIndex;
\r
637 if (CurrentPostion.col > 0)
\r
639 newCol = this.View.LayoutLines.GetData(CurrentPostion.row).Layout.AlignIndexToNearestCluster(CurrentPostion.col - 1, AlignDirection.Back);
\r
640 newIndex = this.View.GetIndexFromLayoutLine(new TextPoint(CurrentPostion.row, newCol));
\r
644 newIndex = this.View.GetIndexFromLayoutLine(CurrentPostion);
\r
648 this.Document.Replace(newIndex, oldIndex - newIndex, "");
\r
654 public void DoEnterAction()
\r
656 this.DoInputChar('\n');
\r
660 /// キャレット位置に文字を入力し、その分だけキャレットを進める。isInsertModeの値により動作が変わります
\r
662 /// <param name="ch"></param>
\r
663 public void DoInputChar(char ch)
\r
665 this.DoInputString(ch.ToString());
\r
669 /// キャレット位置に文字列を挿入し、その分だけキャレットを進める。isInsertModeの値により動作が変わります
\r
671 /// <param name="str"></param>
\r
672 /// <param name="fromTip"></param>
\r
673 public void DoInputString(string str,bool fromTip = false)
\r
675 if (this.View.InsertPoint != null)
\r
677 this.ReplaceBeforeSelectionArea(this.Document.Selections, 0, str);
\r
680 else if (this.SelectionLength != 0)
\r
682 this.RepleaceSelectionArea(this.Document.Selections, str, fromTip);
\r
686 if (this.Document.FireUpdateEvent == false)
\r
687 throw new InvalidOperationException("");
\r
689 int index = this.View.GetIndexFromLayoutLine(this.View.CaretPostion);
\r
691 if (this.View.InsertMode == false && index < this.Document.Length && this.Document[index] != Document.NewLine)
\r
693 TextPoint CaretPos = this.View.CaretPostion;
\r
694 string lineString = this.View.LayoutLines[CaretPos.row];
\r
695 int end = this.View.LayoutLines.GetData(CaretPos.row).Layout.AlignIndexToNearestCluster(CaretPos.col + str.Length - 1, AlignDirection.Forward);
\r
696 if (end > lineString.Length - 1)
\r
697 end = lineString.Length - 1;
\r
698 end += this.View.LayoutLines.GetData(CaretPos.row).Index;
\r
699 length = end - index;
\r
701 if (str == Document.NewLine.ToString())
\r
703 LineToIndexTableData lineData = this.View.LayoutLines.GetData(this.View.CaretPostion.row);
\r
704 FoldingItem foldingData = this.View.LayoutLines.FoldingCollection.GetFarestHiddenFoldingData(lineData.Index, lineData.Length);
\r
705 if (foldingData != null && !foldingData.Expand && index > foldingData.Start && index <= foldingData.End)
\r
706 index = foldingData.End + 1;
\r
708 this.Document.Replace(index, length, str);
\r
712 /// キャレットの移動に合わせて選択する
\r
714 /// <param name="isSelected">選択状態にするかどうか</param>
\r
716 /// キャレットを移動後、このメソッドを呼び出さない場合、Select()メソッドは正常に機能しません
\r
718 void SelectWithMoveCaret(bool isSelected)
\r
720 if (this.View.CaretPostion.col < 0 || this.View.CaretPostion.row < 0)
\r
723 if (this.Document.FireUpdateEvent == false)
\r
724 throw new InvalidOperationException("");
\r
726 int CaretPostion = this.View.GetIndexFromLayoutLine(this.View.CaretPostion);
\r
728 SelectCollection Selections = this.Document.Selections;
\r
730 this.Select(this.AnchorIndex, CaretPostion - this.AnchorIndex);
\r
733 this.Document.Selections.Clear();
\r
734 this.AnchorIndex = CaretPostion;
\r
735 this.View.InsertPoint = null;
\r
740 /// JumpCaretで移動した位置からキャレットを移動し、選択状態にする
\r
742 /// <param name="tp"></param>
\r
743 public void MoveCaretAndSelect(TextPoint tp)
\r
745 int CaretPostion = this.View.GetIndexFromLayoutLine(tp);
\r
746 this.Select(this.AnchorIndex, CaretPostion - this.AnchorIndex);
\r
747 this.View.JumpCaret(tp.row, tp.col);
\r
748 this.View.AdjustCaretAndSrc();
\r
751 public void MoveSelectBefore(TextPoint tp)
\r
753 int NewAnchorIndex;
\r
754 int SelectionLength;
\r
755 if (this.IsReverseSelect())
\r
757 NewAnchorIndex = this.View.GetIndexFromLayoutLine(tp);
\r
758 SelectionLength = this.SelectionLength + NewAnchorIndex - this.AnchorIndex;
\r
759 this.Select(this.SelectionStart, SelectionLength);
\r
763 NewAnchorIndex = this.View.GetIndexFromLayoutLine(tp);
\r
764 SelectionLength = this.SelectionLength + this.AnchorIndex - NewAnchorIndex;
\r
765 this.Select(NewAnchorIndex, SelectionLength);
\r
767 this.AnchorIndex = NewAnchorIndex;
\r
771 /// キャレット位置を既定の位置に戻す
\r
773 public void ResetCaretPostion()
\r
779 /// 行単位で移動後のキャレット位置を取得する
\r
781 /// <param name="count">移動量</param>
\r
782 /// <param name="current">現在のキャレット位置</param>
\r
783 /// <returns>移動後のキャレット位置</returns>
\r
784 public TextPoint GetTextPointAfterMoveLine(int count, TextPoint current)
\r
786 int row = current.row + count;
\r
790 else if (row >= this.View.LayoutLines.Count)
\r
791 row = this.View.LayoutLines.Count - 1;
\r
793 row = this.View.AdjustRow(row, count > 0);
\r
795 double x = this.View.GetXFromIndex(current.row, current.col);
\r
796 int col = this.View.GetIndexFromX(row, x);
\r
798 return new TextPoint(row, col);
\r
804 /// <param name="isMoveNext">真なら1文字すすめ、そうでなければ戻す</param>
\r
805 /// <remarks>このメソッドを呼び出した後でScrollToCaretメソッドとSelectWithMoveCaretメソッドを呼び出す必要があります</remarks>
\r
806 void MoveCaretHorizontical(bool isMoveNext)
\r
808 if (this.Document.FireUpdateEvent == false)
\r
809 throw new InvalidOperationException("");
\r
810 int delta = isMoveNext ? 0 : -1;
\r
811 int prevcol = this.View.CaretPostion.col;
\r
812 int col = this.View.CaretPostion.col + delta;
\r
813 string lineString = this.View.LayoutLines[this.View.CaretPostion.row];
\r
814 if (col < 0 || this.View.CaretPostion.row >= this.View.LayoutLines.Count)
\r
816 if (this.View.CaretPostion.row == 0)
\r
821 this.MoveCaretVertical(false);
\r
822 this.View.AdjustCaretAndSrc(AdjustFlow.Row); //この段階で調整しないとスクロールされない
\r
823 col = this.View.LayoutLines.GetData(this.View.CaretPostion.row).Length - 1; //最終行以外はすべて改行コードが付くはず
\r
825 else if (col >= lineString.Length || lineString[col] == Document.NewLine)
\r
827 if (this.View.CaretPostion.row < this.View.LayoutLines.Count - 1)
\r
829 this.MoveCaretVertical(true);
\r
830 this.View.AdjustCaretAndSrc(AdjustFlow.Row); //この段階で調整しないとスクロールされない
\r
836 AlignDirection direction = isMoveNext ? AlignDirection.Forward : AlignDirection.Back;
\r
837 col = this.View.LayoutLines.GetData(this.View.CaretPostion.row).Layout.AlignIndexToNearestCluster(col, direction);
\r
840 this.View.JumpCaret(this.View.CaretPostion.row, col,false);
\r
844 /// キャレットを行方向に移動させる
\r
846 /// <param name="isMoveNext">プラス方向に移動するなら真</param>
\r
847 /// <remarks>このメソッドを呼び出した後でScrollToCaretメソッドとSelectWithMoveCaretメソッドを呼び出す必要があります</remarks>
\r
848 void MoveCaretVertical(bool isMoveNext)
\r
850 if (this.Document.FireUpdateEvent == false)
\r
851 throw new InvalidOperationException("");
\r
853 TextPoint nextPoint = this.GetTextPointAfterMoveLine(isMoveNext ? 1 : -1, this.View.CaretPostion);
\r
855 this.View.JumpCaret(nextPoint.row, nextPoint.col,false);
\r
858 private void ReplaceBeforeSelectionArea(SelectCollection Selections, int removeLength, string insertStr)
\r
860 if (removeLength == 0 && insertStr.Length == 0)
\r
863 if (this.RectSelection == false || this.Document.FireUpdateEvent == false)
\r
864 throw new InvalidOperationException();
\r
866 SelectCollection temp = this.View.InsertPoint;
\r
867 int selectStart = temp.First().start;
\r
868 int selectEnd = temp.Last().start + temp.Last().length;
\r
870 //ドキュメント操作後に行うとうまくいかないので、あらかじめ取得しておく
\r
871 TextPoint start = this.View.LayoutLines.GetTextPointFromIndex(selectStart);
\r
872 TextPoint end = this.View.LayoutLines.GetTextPointFromIndex(selectEnd);
\r
874 bool reverse = temp.First().start > temp.Last().start;
\r
876 int lineHeadIndex = this.View.LayoutLines.GetIndexFromLineNumber(this.View.LayoutLines.GetLineNumberFromIndex(selectStart));
\r
877 if (selectStart - removeLength < lineHeadIndex)
\r
880 this.Document.UndoManager.BeginUndoGroup();
\r
881 this.Document.FireUpdateEvent = false;
\r
885 for (int i = 0; i < temp.Count; i++)
\r
887 this.ReplaceBeforeSelection(temp[i], removeLength, insertStr);
\r
892 for (int i = temp.Count - 1; i >= 0; i--)
\r
894 this.ReplaceBeforeSelection(temp[i], removeLength, insertStr);
\r
898 this.Document.FireUpdateEvent = true;
\r
899 this.Document.UndoManager.EndUndoGroup();
\r
901 int delta = insertStr.Length - removeLength;
\r
902 start.col += delta;
\r
906 this.JumpCaret(start.row, start.col);
\r
908 this.JumpCaret(end.row, end.col);
\r
910 this.Select(start, 0, end.row - start.row);
\r
913 private void ReplaceBeforeSelection(Selection sel, int removeLength, string insertStr)
\r
915 sel = Util.NormalizeIMaker<Selection>(sel);
\r
916 insertStr = Util.Generate(' ', sel.padding) + insertStr;
\r
917 this.Document.Replace(sel.start - removeLength, removeLength, insertStr);
\r
920 private void RepleaceSelectionArea(SelectCollection Selections, string value,bool updateInsertPoint = false)
\r
925 if (this.RectSelection == false)
\r
927 string str = value.Replace(Environment.NewLine, Document.NewLine.ToString());
\r
929 Selection sel = Selection.Create(this.AnchorIndex, 0);
\r
930 if (Selections.Count > 0)
\r
931 sel = Util.NormalizeIMaker<Selection>(this.Document.Selections.First());
\r
933 this.Document.Replace(sel.start, sel.length, str);
\r
937 if (this.Document.FireUpdateEvent == false)
\r
938 throw new InvalidOperationException("");
\r
940 int StartIndex = this.SelectionStart;
\r
942 SelectCollection newInsertPoint = new SelectCollection();
\r
944 if (this.SelectionLength == 0)
\r
948 this.Document.UndoManager.BeginUndoGroup();
\r
950 this.Document.FireUpdateEvent = false;
\r
952 string[] line = value.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
\r
954 TextPoint Current = this.View.GetLayoutLineFromIndex(this.SelectionStart);
\r
956 for (i = 0; i < line.Length && Current.row < this.View.LayoutLines.Count; i++, Current.row++)
\r
958 if (Current.col > this.View.LayoutLines[Current.row].Length)
\r
959 Current.col = this.View.LayoutLines[Current.row].Length;
\r
960 StartIndex = this.View.GetIndexFromLayoutLine(Current);
\r
961 this.Document.Replace(StartIndex, 0, line[i]);
\r
962 StartIndex += line[i].Length;
\r
965 for (; i < line.Length; i++)
\r
967 StartIndex = this.Document.Length;
\r
968 string str = Document.NewLine + line[i];
\r
969 this.Document.Replace(StartIndex, 0, str);
\r
970 StartIndex += str.Length;
\r
973 this.Document.FireUpdateEvent = true;
\r
975 this.Document.UndoManager.EndUndoGroup();
\r
979 SelectCollection temp = new SelectCollection(this.Document.Selections); //コピーしないとReplaceCommandを呼び出した段階で書き換えられてしまう
\r
981 this.Document.UndoManager.BeginUndoGroup();
\r
983 this.Document.FireUpdateEvent = false;
\r
985 if (temp.First().start < temp.Last().start)
\r
987 for (int i = temp.Count - 1; i >= 0; i--)
\r
989 Selection sel = Util.NormalizeIMaker<Selection>(temp[i]);
\r
991 StartIndex = sel.start;
\r
993 this.Document.Replace(sel.start, sel.length, value);
\r
995 newInsertPoint.Add(Selection.Create(sel.start + (value.Length - sel.length) * i,0));
\r
1000 for (int i = 0; i < temp.Count; i++)
\r
1002 Selection sel = Util.NormalizeIMaker<Selection>(temp[i]);
\r
1004 StartIndex = sel.start;
\r
1006 this.Document.Replace(sel.start, sel.length, value);
\r
1008 newInsertPoint.Add(Selection.Create(sel.start + (value.Length - sel.length) * i, 0));
\r
1012 this.Document.FireUpdateEvent = true;
\r
1014 this.Document.UndoManager.EndUndoGroup();
\r
1016 this.JumpCaret(StartIndex);
\r
1017 if (updateInsertPoint && newInsertPoint.Count > 0)
\r
1018 this.View.InsertPoint = newInsertPoint;
\r
1021 private string GetTextFromLineSelectArea(SelectCollection Selections)
\r
1023 Selection sel = Util.NormalizeIMaker<Selection>(Selections.First());
\r
1025 string str = this.Document.ToString(sel.start, sel.length).Replace(Document.NewLine.ToString(), Environment.NewLine);
\r
1030 string GetTextFromRectangleSelectArea(SelectCollection Selections)
\r
1032 StringBuilder temp = new StringBuilder();
\r
1033 if (Selections.First().start < Selections.Last().start)
\r
1035 for (int i = 0; i < this.Document.Selections.Count; i++)
\r
1037 Selection sel = Util.NormalizeIMaker<Selection>(Selections[i]);
\r
1039 string str = this.Document.ToString(sel.start, sel.length).Replace(Document.NewLine.ToString(), Environment.NewLine);
\r
1040 if (str.IndexOf(Environment.NewLine) == -1)
\r
1041 temp.AppendLine(str);
\r
1048 for (int i = this.Document.Selections.Count - 1; i >= 0; i--)
\r
1050 Selection sel = Util.NormalizeIMaker<Selection>(Selections[i]);
\r
1052 string str = this.Document.ToString(sel.start, sel.length).Replace(Document.NewLine.ToString(), Environment.NewLine);
\r
1053 if (str.IndexOf(Environment.NewLine) == -1)
\r
1054 temp.AppendLine(str);
\r
1059 return temp.ToString();
\r
1062 void View_LineBreakChanged(object sender, EventArgs e)
\r
1064 this.DeSelectAll();
\r
1065 this.AdjustCaret();
\r
1068 void View_PageBoundChanged(object sender, EventArgs e)
\r
1070 if (this.View.LineBreak == LineBreakMethod.PageBound && this.View.PageBound.Width - this.View.LineBreakingMarginWidth > 0)
\r
1071 this.View.PerfomLayouts();
\r
1072 this.AdjustCaret();
\r
1075 void render_ChangedRenderResource(object sender, ChangedRenderRsourceEventArgs e)
\r
1077 if (e.type == ResourceType.Font)
\r
1079 if (this.View.LineBreak != LineBreakMethod.None)
\r
1080 this.View.PerfomLayouts();
\r
1081 this.AdjustCaret();
\r
1085 void render_ChangedRightToLeft(object sender, EventArgs e)
\r
1087 this.AdjustCaret();
\r
1090 void Document_Update(object sender, DocumentUpdateEventArgs e)
\r
1094 case UpdateType.Replace:
\r
1095 this.JumpCaret(e.startIndex + e.insertLength,true);
\r
1097 case UpdateType.Clear:
\r
1098 this.View.TryScroll(0, 0);
\r
1103 void Document_Progress(object sender, ProgressEventArgs e)
\r
1105 if (e.state == ProgressState.Complete)
\r
1106 this.JumpCaret(0);
\r