using System;
using System.Linq;
namespace FooEditEngine
{
///
/// イベントパラメーター
///
public sealed class ShowingCompleteBoxEventArgs : EventArgs
{
///
/// 入力された文字
///
public string KeyChar;
///
/// 入力した単語と一致したコレクションのインデックス。一致しないなら-1をセットする
///
public int foundIndex;
///
/// 入力しようとした単語を設定する
///
public string inputedWord;
///
/// 補完対象のテキストボックス
///
public Document textbox;
///
/// キャレット座標
///
public Point CaretPostion;
///
/// コンストラクター
///
///
///
///
public ShowingCompleteBoxEventArgs(string keyChar, Document textbox, Point caret_pos)
{
this.inputedWord = null;
this.KeyChar = keyChar;
this.foundIndex = -1;
this.textbox = textbox;
this.CaretPostion = caret_pos;
}
}
///
/// イベントパラメーター
///
public sealed class SelectItemEventArgs : EventArgs
{
///
/// 入力中の単語
///
public string inputing_word;
///
/// 補完対象のテキストボックス
///
public Document textbox;
///
/// 補完候補
///
public ICompleteItem item;
///
/// コンストラクター
///
///
///
///
public SelectItemEventArgs(ICompleteItem item, string inputing_word, Document textbox)
{
this.item = item;
this.inputing_word = inputing_word;
this.textbox = textbox;
}
}
///
/// イベントパラメーターイベントパラメーター
///
public sealed class CollectCompleteItemEventArgs : EventArgs
{
///
/// 入力された行
///
public int InputedRow;
///
/// 補完対象のテキストボックス
///
public Document textbox;
///
/// コンストラクター
///
///
public CollectCompleteItemEventArgs(Document textbox)
{
this.textbox = textbox;
this.InputedRow = textbox.CaretPostion.row - 1;
if (this.InputedRow < 0)
this.InputedRow = 0;
}
}
///
/// イベントパンドラーの定義
///
///
///
public delegate void SelectItemEventHandler(object sender,SelectItemEventArgs e);
///
/// イベントパンドラーの定義
///
///
///
public delegate void ShowingCompleteBoxEnventHandler(object sender, ShowingCompleteBoxEventArgs e);
///
/// 自動補完のベースクラス
///
public class AutoCompleteBoxBase
{
const int InputLength = 2; //補完を開始する文字の長さ
///
/// 対象となるドキュメント
///
protected Document Document
{
get;
private set;
}
///
/// コンストラクター
///
/// 対象となるDocumentWindow
public AutoCompleteBoxBase(Document document)
{
this.SelectItem = (s, e) => {
string inputing_word = e.inputing_word;
string word = e.item.word;
var doc = e.textbox;
//キャレットは入力された文字の後ろにあるので、一致する分だけ選択して置き換える
int caretIndex = doc.LayoutLines.GetIndexFromTextPoint(e.textbox.CaretPostion);
int start = caretIndex - inputing_word.Length;
if (start < 0)
start = 0;
doc.Replace(start, inputing_word.Length, word);
doc.RequestRedraw();
};
this.ShowingCompleteBox = (s, e) => {
AutoCompleteBoxBase box = (AutoCompleteBoxBase)s;
var doc = e.textbox;
int caretIndex = doc.LayoutLines.GetIndexFromTextPoint(e.textbox.CaretPostion);
int inputingIndex = caretIndex - 1;
if (inputingIndex < 0)
inputingIndex = 0;
e.inputedWord = CompleteHelper.GetWord(doc, inputingIndex, box.Operators) + e.KeyChar;
if (e.inputedWord == null)
return;
for (int i = 0; i < box.Items.Count; i++)
{
CompleteWord item = (CompleteWord)box.Items[i];
if (item.word.StartsWith(e.inputedWord))
{
e.foundIndex = i;
break;
}
}
};
this.CollectItems = (s, e) =>
{
AutoCompleteBoxBase box = (AutoCompleteBoxBase)s;
CompleteHelper.AddCompleteWords(box.Items, box.Operators, e.textbox.LayoutLines[e.InputedRow]);
};
this.Operators = new char[] { ' ', '\t', Document.NewLine };
this.Document = document;
}
internal void ParseInput(string input_text)
{
if (this.Operators == null ||
this.ShowingCompleteBox == null ||
(this.IsCloseCompleteBox == false && input_text == "\b"))
return;
if (input_text == "\r" || input_text == "\n")
{
this.CollectItems(this, new CollectCompleteItemEventArgs(this.Document));
return;
}
this.OpenCompleteBox(input_text);
}
///
/// 補完候補を追加可能な時に発生するイベント
///
public EventHandler CollectItems;
///
/// 補完すべき単語が選択されたときに発生するイベント
///
public SelectItemEventHandler SelectItem;
///
/// UI表示前のイベント
///
public ShowingCompleteBoxEnventHandler ShowingCompleteBox;
///
/// 区切り文字のリスト
///
public char[] Operators
{
get;
set;
}
///
/// オートコンプリートの対象となる単語のリスト
///
public virtual CompleteCollection Items
{
get;
set;
}
internal Func GetPostion;
///
/// 自動補完リストが表示されているかどうか
///
protected virtual bool IsCloseCompleteBox
{
get;
}
///
/// 自動補完を行うかどうか。行うなら真
///
public bool Enabled
{
get;
set;
}
///
/// 補完候補の表示要求を処理する
///
///
protected virtual void RequestShowCompleteBox(ShowingCompleteBoxEventArgs ev)
{
}
///
/// 補完候補の非表示要求を処理する
///
protected virtual void RequestCloseCompleteBox()
{
}
///
/// 補完候補を表示する
///
/// 入力しようとしていた文字列
/// 補完候補がなくても表示するなら真。そうでないなら偽
public void OpenCompleteBox(string key_char, bool force = false)
{
if (!this.Enabled)
return;
if (this.GetPostion == null)
throw new InvalidOperationException("GetPostionがnullです");
Point p = this.GetPostion(this.Document.CaretPostion,this.Document);
ShowingCompleteBoxEventArgs ev = new ShowingCompleteBoxEventArgs(key_char, this.Document, p);
ShowingCompleteBox(this, ev);
bool hasCompleteItem = ev.foundIndex != -1 && ev.inputedWord != null && ev.inputedWord != string.Empty && ev.inputedWord.Length >= InputLength;
System.Diagnostics.Debug.WriteLine("hasCompleteItem:{0}", hasCompleteItem);
if (force || hasCompleteItem)
{
RequestShowCompleteBox(ev);
}
else
{
RequestCloseCompleteBox();
}
}
}
}