OSDN Git Service

バージョンナンバーを増やした
[fooeditengine/FooEditEngine.git] / Core / AutoCompleteBoxBase.cs
1 using System;
2 using System.Linq;
3
4 namespace FooEditEngine
5 {
6     /// <summary>
7     /// イベントパラメーター
8     /// </summary>
9     public sealed class ShowingCompleteBoxEventArgs : EventArgs
10     {
11         /// <summary>
12         /// 入力された文字
13         /// </summary>
14         public string KeyChar;
15         /// <summary>
16         /// 入力した単語と一致したコレクションのインデックス。一致しないなら-1をセットする
17         /// </summary>
18         public int foundIndex;
19         /// <summary>
20         /// 入力しようとした単語を設定する
21         /// </summary>
22         public string inputedWord;
23         /// <summary>
24         /// 補完対象のテキストボックス
25         /// </summary>
26         public Document textbox;
27         /// <summary>
28         /// キャレット座標
29         /// </summary>
30         public Point CaretPostion;
31         /// <summary>
32         /// コンストラクター
33         /// </summary>
34         /// <param name="keyChar"></param>
35         /// <param name="textbox"></param>
36         /// <param name="caret_pos"></param>
37         public ShowingCompleteBoxEventArgs(string keyChar, Document textbox, Point caret_pos)
38         {
39             this.inputedWord = null;
40             this.KeyChar = keyChar;
41             this.foundIndex = -1;
42             this.textbox = textbox;
43             this.CaretPostion = caret_pos;
44         }
45     }
46
47     /// <summary>
48     /// イベントパラメーター
49     /// </summary>
50     public sealed class SelectItemEventArgs : EventArgs
51     {
52         /// <summary>
53         /// 入力中の単語
54         /// </summary>
55         public string inputing_word;
56         /// <summary>
57         /// 補完対象のテキストボックス
58         /// </summary>
59         public Document textbox;
60         /// <summary>
61         /// 補完候補
62         /// </summary>
63         public ICompleteItem item;
64         /// <summary>
65         /// コンストラクター
66         /// </summary>
67         /// <param name="item"></param>
68         /// <param name="inputing_word"></param>
69         /// <param name="textbox"></param>
70         public SelectItemEventArgs(ICompleteItem item, string inputing_word, Document textbox)
71         {
72             this.item = item;
73             this.inputing_word = inputing_word;
74             this.textbox = textbox;
75         }
76     }
77
78     /// <summary>
79     /// イベントパラメーターイベントパラメーター
80     /// </summary>
81     public sealed class CollectCompleteItemEventArgs : EventArgs
82     {
83         /// <summary>
84         /// 入力された行
85         /// </summary>
86         public int InputedRow;
87         /// <summary>
88         /// 補完対象のテキストボックス
89         /// </summary>
90         public Document textbox;
91         /// <summary>
92         /// コンストラクター
93         /// </summary>
94         /// <param name="textbox"></param>
95         public CollectCompleteItemEventArgs(Document textbox)
96         {
97             this.textbox = textbox;
98             this.InputedRow = textbox.CaretPostion.row - 1;
99             if (this.InputedRow < 0)
100                 this.InputedRow = 0;
101         }
102     }
103
104     /// <summary>
105     /// イベントパンドラーの定義
106     /// </summary>
107     /// <param name="sender"></param>
108     /// <param name="e"></param>
109     public delegate void SelectItemEventHandler(object sender,SelectItemEventArgs e);
110     /// <summary>
111     /// イベントパンドラーの定義
112     /// </summary>
113     /// <param name="sender"></param>
114     /// <param name="e"></param>
115     public delegate void ShowingCompleteBoxEnventHandler(object sender, ShowingCompleteBoxEventArgs e);
116
117     /// <summary>
118     /// 自動補完のベースクラス
119     /// </summary>
120     public class AutoCompleteBoxBase
121     {
122         const int InputLength = 2;  //補完を開始する文字の長さ
123
124         /// <summary>
125         /// 対象となるドキュメント
126         /// </summary>
127         protected Document Document
128         {
129             get;
130             private set;
131         }
132
133         /// <summary>
134         /// コンストラクター
135         /// </summary>
136         /// <param name="document">対象となるDocumentWindow</param>
137         public AutoCompleteBoxBase(Document document)
138         {
139             this.SelectItem = (s, e) => {
140                 string inputing_word = e.inputing_word;
141                 string word = e.item.word;
142
143                 var doc = e.textbox;
144                 //キャレットは入力された文字の後ろにあるので、一致する分だけ選択して置き換える
145                 int caretIndex = doc.LayoutLines.GetIndexFromTextPoint(e.textbox.CaretPostion);
146                 int start = caretIndex - inputing_word.Length;
147                 if (start < 0)
148                     start = 0;
149                 doc.Replace(start, inputing_word.Length, word);
150                 doc.RequestRedraw();
151             };
152             this.ShowingCompleteBox = (s, e) => {
153                 AutoCompleteBoxBase box = (AutoCompleteBoxBase)s;
154
155                 var doc = e.textbox;
156                 int caretIndex = doc.LayoutLines.GetIndexFromTextPoint(e.textbox.CaretPostion);
157                 int inputingIndex = caretIndex - 1;
158                 if (inputingIndex < 0)
159                     inputingIndex = 0;
160
161                 e.inputedWord = CompleteHelper.GetWord(doc, inputingIndex, box.Operators) + e.KeyChar;
162
163                 if (e.inputedWord == null)
164                     return;
165
166                 for (int i = 0; i < box.Items.Count; i++)
167                 {
168                     CompleteWord item = (CompleteWord)box.Items[i];
169                     if (item.word.StartsWith(e.inputedWord))
170                     {
171                         e.foundIndex = i;
172                         break;
173                     }
174                 }
175             };
176             this.CollectItems = (s, e) =>
177             {
178                 AutoCompleteBoxBase box = (AutoCompleteBoxBase)s;
179                 CompleteHelper.AddCompleteWords(box.Items, box.Operators, e.textbox.LayoutLines[e.InputedRow]);
180             };
181             this.Operators = new char[] { ' ', '\t', Document.NewLine };
182             this.Document = document;
183         }
184
185         internal void ParseInput(string input_text)
186         {
187             if (this.Operators == null ||
188                 this.ShowingCompleteBox == null ||
189                 (this.IsCloseCompleteBox == false && input_text == "\b"))
190                 return;
191
192             if (input_text == "\r" || input_text == "\n")
193             {
194                 this.CollectItems(this, new CollectCompleteItemEventArgs(this.Document));
195                 return;
196             }
197
198             this.OpenCompleteBox(input_text);
199         }
200
201         /// <summary>
202         /// 補完候補を追加可能な時に発生するイベント
203         /// </summary>
204         public EventHandler<CollectCompleteItemEventArgs> CollectItems;
205         /// <summary>
206         /// 補完すべき単語が選択されたときに発生するイベント
207         /// </summary>
208         public SelectItemEventHandler SelectItem;
209         /// <summary>
210         /// UI表示前のイベント
211         /// </summary>
212         public ShowingCompleteBoxEnventHandler ShowingCompleteBox;
213
214         /// <summary>
215         /// 区切り文字のリスト
216         /// </summary>
217         public char[] Operators
218         {
219             get;
220             set;
221         }
222
223         /// <summary>
224         /// オートコンプリートの対象となる単語のリスト
225         /// </summary>
226         public virtual CompleteCollection<ICompleteItem> Items
227         {
228             get;
229             set;
230         }
231
232         internal Func<TextPoint,Document, Point> GetPostion;
233
234         /// <summary>
235         /// 自動補完リストが表示されているかどうか
236         /// </summary>
237         protected virtual bool IsCloseCompleteBox
238         {
239             get;
240         }
241
242         /// <summary>
243         /// 自動補完を行うかどうか。行うなら真
244         /// </summary>
245         public bool Enabled
246         {
247             get;
248             set;
249         }
250
251         /// <summary>
252         /// 補完候補の表示要求を処理する
253         /// </summary>
254         /// <param name="ev"></param>
255         protected virtual void RequestShowCompleteBox(ShowingCompleteBoxEventArgs ev)
256         {
257         }
258
259         /// <summary>
260         /// 補完候補の非表示要求を処理する
261         /// </summary>
262         protected virtual void RequestCloseCompleteBox()
263         {
264         }
265
266         /// <summary>
267         /// 補完候補を表示する
268         /// </summary>
269         /// <param name="key_char">入力しようとしていた文字列</param>
270         /// <param name="force">補完候補がなくても表示するなら真。そうでないなら偽</param>
271         public void OpenCompleteBox(string key_char, bool force = false)
272         {
273             if (!this.Enabled)
274                 return;
275
276             if (this.GetPostion == null)
277                 throw new InvalidOperationException("GetPostionがnullです");
278             Point p = this.GetPostion(this.Document.CaretPostion,this.Document);
279
280             ShowingCompleteBoxEventArgs ev = new ShowingCompleteBoxEventArgs(key_char, this.Document, p);
281             ShowingCompleteBox(this, ev);
282
283             bool hasCompleteItem = ev.foundIndex != -1 && ev.inputedWord != null && ev.inputedWord != string.Empty && ev.inputedWord.Length >= InputLength;
284             System.Diagnostics.Debug.WriteLine("hasCompleteItem:{0}", hasCompleteItem);
285             if (force || hasCompleteItem)
286             {
287                 RequestShowCompleteBox(ev);
288             }
289             else
290             {
291                 RequestCloseCompleteBox();
292             }
293         }
294
295     }
296 }