OSDN Git Service

初回起動時にキャレットラインが常に表示されている問題を修正した
[fooeditengine/FooEditEngine.git] / Common / DocumentExtend.cs
1 /*\r
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
5 \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
8 \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
10  */\r
11 \r
12 //#define TEST_ASYNC\r
13 \r
14 using System;\r
15 using System.IO;\r
16 using System.Text;\r
17 using System.Threading;\r
18 using System.Threading.Tasks;\r
19 \r
20 namespace FooEditEngine\r
21 {\r
22     /// <summary>\r
23     /// Documentの拡張クラス\r
24     /// </summary>\r
25     public static class DocumentExtend\r
26     {\r
27         static Progress<ProgressEventArgs> _Progress = new Progress<ProgressEventArgs>();\r
28         /// <summary>\r
29         /// 進捗処理を表す\r
30         /// </summary>\r
31         public static event EventHandler<ProgressEventArgs> Progress\r
32         {\r
33             add\r
34             {\r
35                 _Progress.ProgressChanged += value;\r
36             }\r
37             remove\r
38             {\r
39                 _Progress.ProgressChanged -= value;\r
40             }\r
41         }\r
42 \r
43 #if !METRO\r
44         /// <summary>\r
45         /// ファイルからドキュメントを構築します\r
46         /// </summary>\r
47         /// <param name="doc">Documentオブジェクト</param>\r
48         /// <param name="filepath">読み取り先のファイル</param>\r
49         /// <param name="enc">エンコーディング</param>\r
50         /// <remarks>\r
51         /// 非同期操作中はこのメソッドを実行することはできません。\r
52         /// </remarks>\r
53         public static void Load(this Document doc, string filepath, Encoding enc)\r
54         {\r
55             if (doc.State != AsyncState.None)\r
56                 throw new InvalidOperationException();\r
57             using (StreamReader sr = new StreamReader(filepath, enc))\r
58             {\r
59                 Load(doc,sr);\r
60             }\r
61         }\r
62 \r
63         /// <summary>\r
64         /// ファイルからドキュメントを非同期的に構築します\r
65         /// </summary>\r
66         /// <param name="doc">Documentオブジェクト</param>\r
67         /// <param name="filepath">読み取り先のファイル</param>\r
68         /// <param name="enc">エンコーディング</param>\r
69         /// <param name="token">キャンセル用のトークン</param>\r
70         /// <remarks>\r
71         /// 読み取り操作は別スレッドで行われます。\r
72         /// また、非同期操作中にこのメソッドを読みだすことはできません\r
73         /// </remarks>\r
74         public static async Task LoadAsync(this Document doc, string filepath, Encoding enc, CancellationTokenSource token)\r
75         {\r
76             if (doc.State != AsyncState.None)\r
77                 throw new InvalidOperationException();\r
78             using (StreamReader sr = new StreamReader(filepath, enc))\r
79             {\r
80                 await LoadAsync(doc,sr, token);\r
81             }\r
82         }\r
83 #endif\r
84 \r
85         /// <summary>\r
86         /// ストリームからドキュメントを構築します\r
87         /// </summary>\r
88         /// <param name="doc">Documentオブジェクト</param>\r
89         /// <param name="sr">読み取り先のストリーム</param>\r
90         /// <remarks>\r
91         /// 非同期操作中はこのメソッドを実行することはできません\r
92         /// </remarks>\r
93         public static void Load(this Document doc, TextReader sr)\r
94         {\r
95             Task t = LoadAsync(doc,sr, null);\r
96             t.Wait();\r
97         }\r
98 \r
99         /// <summary>\r
100         /// ストリームからドキュメントを非同期的に構築します\r
101         /// </summary>\r
102         /// <param name="doc">Documentオブジェクト</param>\r
103         /// <param name="sr">読み取り先のストリーム</param>\r
104         /// <param name="tokenSource">キャンセルトークン</param>\r
105         /// <returns>Taskオブジェクト</returns>\r
106         /// <remarks>\r
107         /// 読み取り操作は別スレッドで行われます。\r
108         /// また、非同期操作中はこのメソッドを実行することはできません。\r
109         /// </remarks>\r
110         public static async Task LoadAsync(this Document doc, TextReader sr, CancellationTokenSource tokenSource = null)\r
111         {\r
112             if (doc.State != AsyncState.None)\r
113                 throw new InvalidOperationException();\r
114             if (sr.Peek() == -1)\r
115             {\r
116                 return;\r
117             }\r
118 \r
119             IProgress<ProgressEventArgs> progress = _Progress;\r
120             try\r
121             {\r
122                 progress.Report(new ProgressEventArgs(ProgressState.Start));\r
123                 doc.State = AsyncState.Loading;\r
124                 doc.FireUpdateEvent = false;\r
125                 doc.StringBuffer.Clear();\r
126                 doc.UndoManager.BeginLock();\r
127                 string str;\r
128                 for (int i = 0; (str = await sr.ReadLineAsync().ConfigureAwait(false)) != null; i++)\r
129                 {\r
130                     int index = doc.StringBuffer.Length;\r
131                     if (index < 0)\r
132                         index = 0;\r
133 \r
134                     doc.StringBuffer.Replace(index, 0, Util.GetEnumrator(str + Document.NewLine),str.Length + 1);\r
135 \r
136                     if (tokenSource != null)\r
137                         tokenSource.Token.ThrowIfCancellationRequested();\r
138 #if TEST_ASYNC\r
139                     System.Threading.Thread.Sleep(10);\r
140 #endif\r
141                 }\r
142             }\r
143             finally\r
144             {\r
145                 doc.FireUpdateEvent = true;\r
146                 doc.UndoManager.EndLock();\r
147                 doc.State = AsyncState.None;\r
148                 progress.Report(new ProgressEventArgs(ProgressState.Complete));\r
149             }\r
150         }\r
151 \r
152 #if !METRO\r
153         /// <summary>\r
154         /// ドキュメントをファイルに保存します\r
155         /// </summary>\r
156         /// <param name="doc">Documentオブジェクト</param>\r
157         /// <param name="filepath">保存先のファイル</param>\r
158         /// <param name="enc">保存したいエンコード</param>\r
159         /// <param name="newline">改行を表す文字列</param>\r
160         /// <remarks>非同期操作中はこのメソッドを実行することはできません</remarks>\r
161         public static void Save(this Document doc, string filepath, Encoding enc, string newline)\r
162         {\r
163             if (doc.State != AsyncState.None)\r
164                 throw new InvalidOperationException();\r
165             using (StreamWriter sw = new StreamWriter(filepath, false, enc))\r
166             {\r
167                 sw.NewLine = newline;\r
168                 Save(doc,sw);\r
169             }\r
170         }\r
171 \r
172         /// <summary>\r
173         /// ドキュメントをファイルに保存します\r
174         /// </summary>\r
175         /// <param name="doc">Documentオブジェクト</param>\r
176         /// <param name="filepath">保存先のファイル</param>\r
177         /// <param name="enc">保存したいエンコード</param>\r
178         /// <param name="newline">改行を表す文字列</param>\r
179         /// <param name="token">CancellationTokenSourceオブジェクト</param>\r
180         /// <remarks>非同期操作中はこのメソッドを実行することはできません</remarks>\r
181         public static async Task SaveAsync(this Document doc, string filepath, Encoding enc, string newline,CancellationTokenSource token)\r
182         {\r
183             if (doc.State != AsyncState.None)\r
184                 throw new InvalidOperationException();\r
185             using (StreamWriter sw = new StreamWriter(filepath, false, enc))\r
186             {\r
187                 sw.NewLine = newline;\r
188                 await SaveAsync(doc,sw, token);\r
189             }\r
190         }\r
191 #endif\r
192 \r
193         /// <summary>\r
194         /// ストリームに保存します\r
195         /// </summary>\r
196         /// <param name="doc">Documentオブジェクト</param>\r
197         /// <param name="sw">保存先のストリーム</param>\r
198         /// <returns>Taskオブジェクト</returns>\r
199         /// <remarks>非同期操作中はこのメソッドを実行することはできません</remarks>\r
200         public static void Save(this Document doc, StreamWriter sw)\r
201         {\r
202             Task t = SaveAsync(doc,sw, null);\r
203             t.Wait();\r
204         }\r
205 \r
206         /// <summary>\r
207         /// ストリームに非同期モードで保存します\r
208         /// </summary>\r
209         /// <param name="doc">Documentオブジェクト</param>\r
210         /// <param name="sw">保存先のストリーム</param>\r
211         /// <param name="tokenSource">キャンセルトークン</param>\r
212         /// <returns>Taskオブジェクト</returns>\r
213         /// <remarks>非同期操作中はこのメソッドを実行することはできません</remarks>\r
214         public static async Task SaveAsync(this Document doc,StreamWriter sw, CancellationTokenSource tokenSource = null)\r
215         {\r
216             if (doc.State != AsyncState.None)\r
217                 throw new InvalidOperationException();\r
218             IProgress<ProgressEventArgs> progress = _Progress;\r
219             try\r
220             {\r
221                 progress.Report(new ProgressEventArgs(ProgressState.Start));\r
222                 doc.State = AsyncState.Saving;\r
223                 StringBuilder line = new StringBuilder();\r
224                 for (int i = 0; i < doc.Length; i++)\r
225                 {\r
226                     char c = doc[i];\r
227                     line.Append(c);\r
228                     if (c == Document.NewLine || i == doc.Length - 1)\r
229                     {\r
230                         string str = line.ToString();\r
231                         str = str.Replace(Document.NewLine.ToString(), sw.NewLine);\r
232                         await sw.WriteAsync(str).ConfigureAwait(false);\r
233                         line.Clear();\r
234                         if (tokenSource != null)\r
235                             tokenSource.Token.ThrowIfCancellationRequested();\r
236 #if TEST_ASYNC\r
237                     System.Threading.Thread.Sleep(10);\r
238 #endif\r
239                     }\r
240                 }\r
241             }\r
242             finally\r
243             {\r
244                 doc.State = AsyncState.None;\r
245                 progress.Report(new ProgressEventArgs(ProgressState.Complete));\r
246             }\r
247         }\r
248     }\r
249 }\r