OSDN Git Service

高dpiディスプレイを使用しているケースで予測候補の位置がずれるバグを修正した
[fooeditengine/FooEditEngine.git] / Common / DotNetTextStore / TextStoreBase.cs
1 // TSF のデバッグ表示を行うかどうか?\r
2 //#define TSF_DEBUG_OUTPUT\r
3 //#define TSF_DEBUG_OUTPUT_DISPLAY_ATTR\r
4 using System;\r
5 using System.Collections.Generic;\r
6 using System.Linq;\r
7 using System.Text;\r
8 using System.Diagnostics;\r
9 using System.Reflection;\r
10 using System.Runtime.CompilerServices;\r
11 using System.Runtime.InteropServices;\r
12 using System.Globalization;\r
13 \r
14 using DotNetTextStore.UnmanagedAPI.TSF;\r
15 using DotNetTextStore.UnmanagedAPI.TSF.TextStore;\r
16 using DotNetTextStore.UnmanagedAPI.WinDef;\r
17 using DotNetTextStore.UnmanagedAPI.WinError;\r
18 \r
19 namespace DotNetTextStore\r
20 {\r
21 #if TSF_DEBUG_OUTPUT\r
22     /// <summary>コールスタックの階層にあわせてインデントしてデバッグ表示するクラス。</summary>\r
23     public class DebugOut : IDisposable\r
24     {\r
25         public DebugOut(string i_string, params object[] i_params)\r
26         {\r
27             _text = string.Format(i_string, i_params);\r
28 \r
29             s_callCount++;\r
30             Debug.WriteLine("");\r
31             Debug.WriteLine(string.Format("{0, 4} : ↓↓↓ ", s_callCount) + _text);\r
32         }\r
33 \r
34         public static void Print(string i_string, params object[] i_params)\r
35         {\r
36             Debug.WriteLine(i_string, i_params);\r
37         }\r
38 \r
39         public void Dispose()\r
40         {\r
41             s_callCount++;\r
42             Debug.WriteLine(string.Format("{0, 4} : ↑↑↑ ", s_callCount) + _text);\r
43         }\r
44 \r
45         public static string GetCaller([CallerMemberName] string caller="")\r
46         {\r
47             return caller;\r
48         }\r
49 \r
50         string      _text;\r
51         static int  s_callCount = 0;\r
52     }\r
53 #endif\r
54 \r
55     //=============================================================================================\r
56 \r
57 \r
58     public struct TextDisplayAttribute\r
59     {\r
60         public int startIndex;\r
61         public int endIndex;\r
62         public TF_DISPLAYATTRIBUTE attribute;\r
63     }\r
64 \r
65     //========================================================================================\r
66 \r
67 \r
68     /// <summary>Dispose() で TextStore のロック解除を行うクラス。</summary>\r
69     public class Unlocker : IDisposable\r
70     {\r
71         /// <summary>コンストラクタ</summary>\r
72         public Unlocker(TextStoreBase io_textStore)\r
73         {\r
74             _textStore = io_textStore;\r
75         }\r
76         /// <summary>ロックが成功したかどうか調べる。</summary>\r
77         public bool IsLocked\r
78         {\r
79             get { return _textStore != null; }\r
80         }\r
81         /// <summary>アンロックを行う。</summary>\r
82         void IDisposable.Dispose()\r
83         {\r
84             if (_textStore != null)\r
85             {\r
86                 _textStore.UnlockDocument();\r
87                 _textStore = null;\r
88             }\r
89         }\r
90 \r
91         /// <summary>アンロックを行うテキストストア</summary>\r
92         TextStoreBase _textStore;\r
93     }\r
94 \r
95     public abstract class TextStoreBase\r
96     {\r
97         public delegate double GetDpiHandeler();\r
98         public event GetDpiHandeler GetDpi;\r
99 \r
100         public delegate bool IsReadOnlyHandler();\r
101         public event IsReadOnlyHandler IsReadOnly;\r
102 \r
103         public delegate bool IsLoadingHandler();\r
104         public event IsLoadingHandler IsLoading;\r
105 \r
106         public delegate int GetStringLengthHandler();\r
107         public event GetStringLengthHandler GetStringLength;\r
108 \r
109         public delegate void GetSelectionIndexHandler(out int o_start, out int o_end);\r
110         public event GetSelectionIndexHandler GetSelectionIndex;\r
111 \r
112         public delegate void SetSelectionIndexHandler(int i_start, int i_end);\r
113         public event SetSelectionIndexHandler SetSelectionIndex;\r
114 \r
115         public delegate string GetStringHandler(int start, int length);\r
116         public event GetStringHandler GetString;\r
117 \r
118         public delegate void InsertAtSelectionHandler(string i_value);\r
119         public event InsertAtSelectionHandler InsertAtSelection;\r
120 \r
121         public delegate void GetScreenExtentHandler(\r
122             out POINT o_pointTopLeft,\r
123             out POINT o_pointBottomRight\r
124         );\r
125         public event GetScreenExtentHandler GetScreenExtent;\r
126 \r
127         public delegate void GetStringExtentHandler(\r
128             int i_startIndex,\r
129             int i_endIndex,\r
130             out POINT o_pointTopLeft,\r
131             out POINT o_pointBottomRight\r
132         );\r
133         public event GetStringExtentHandler GetStringExtent;\r
134 \r
135         public delegate bool CompositionStartedHandler();\r
136         public event CompositionStartedHandler CompositionStarted;\r
137 \r
138         public delegate void CompostionUpdateHandler(int start, int end);\r
139         public event CompostionUpdateHandler CompositionUpdated;\r
140 \r
141         public delegate void CompositionEndedHandler();\r
142         public event CompositionEndedHandler CompositionEnded;\r
143 \r
144         #region "生成と破棄"\r
145         public TextStoreBase()\r
146         {\r
147 #if TSF_DEBUG_OUTPUT\r
148             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
149 #endif\r
150             {\r
151                 try\r
152                 {\r
153                     // スレッドマネージャ-の生成\r
154                     CreateThreadMgr();\r
155                     // カテゴリマネージャーの生成\r
156                     CreateCategoryMgr();\r
157                     // 表示属性マネージャーの生成\r
158                     CreateDisplayAttributeMgr();\r
159 \r
160                     // ドキュメントマネージャーの生成\r
161                     _threadMgr.CreateDocumentMgr(out _documentMgr);\r
162 \r
163                     // スレッドマネージャのアクティブ化\r
164                     int clientId = 0;\r
165                     _threadMgr.Activate(out clientId);\r
166 \r
167                     // コンテキストの生成\r
168                     _documentMgr.CreateContext(clientId, 0, this, out _context, out _editCookie);\r
169 \r
170                     // コンテキストの push\r
171                     _documentMgr.Push(_context);\r
172 \r
173                     // ファンクションプロバイダーを取得する。\r
174                     Guid guid = TfDeclarations.GUID_SYSTEM_FUNCTIONPROVIDER;\r
175                     _threadMgr.GetFunctionProvider(ref guid, out _functionProvider);\r
176 \r
177                     // ITfReconversion オブジェクトを取得する。\r
178                     var guidNull = new Guid();\r
179                     var guidReconversion = new Guid("4cea93c0-0a58-11d3-8df0-00105a2799b5");    //ITfFnReconversionの定義から\r
180                     object reconversion = null;\r
181                     _functionProvider.GetFunction(\r
182                         ref guidNull,\r
183                         ref guidReconversion,\r
184                         out reconversion\r
185                     );\r
186                     _reconversion = reconversion as ITfFnReconversion;\r
187 \r
188                     // MODEBIAS の初期化\r
189                     uint guidAtom = 0;\r
190                     Guid guidModebiasNone = TfDeclarations.GUID_MODEBIAS_NONE;\r
191                     _categoryMgr.RegisterGUID(ref guidModebiasNone, out guidAtom);\r
192                     _attributeInfo[0].attrID = TfDeclarations.GUID_PROP_MODEBIAS;\r
193                     _attributeInfo[0].flags = AttributeInfoFlags.None;\r
194                     _attributeInfo[0].currentValue.vt = (short)VarEnum.VT_EMPTY;\r
195                     _attributeInfo[0].defaultValue.vt = (short)VarEnum.VT_I4;\r
196                     _attributeInfo[0].defaultValue.data1 = (IntPtr)guidAtom;\r
197                 }\r
198                 catch (Exception exception)\r
199                 {\r
200                     Debug.WriteLine(exception.Message);\r
201                     Dispose(false);\r
202                 }\r
203             }\r
204         }\r
205 \r
206         /// <summary>\r
207         /// オブジェクトの破棄を行う。このメソッドは必ず呼び出す必要があります\r
208         /// </summary>\r
209         /// <param name="flag"></param>\r
210         protected void Dispose(bool flag)\r
211         {\r
212             if (flag)\r
213                 return;\r
214 #if TSF_DEBUG_OUTPUT\r
215             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
216 #endif\r
217             {\r
218                 ReleaseComObject("_reconversion", ref _reconversion);\r
219                 ReleaseComObject("_functionProvider", ref _functionProvider);\r
220                 ReleaseComObject("_context", ref _context);\r
221                 DestroyDocumentMgr();\r
222                 DestroyDisplayAttributeMgr();\r
223                 DestroyCategoryMgr();\r
224                 DestroyThreadMgr();\r
225 \r
226                 GC.SuppressFinalize(this);\r
227             }\r
228         }\r
229 \r
230         /// <summary>\r
231         /// スレッドマネージャの生成。このメソッドの実装は必須です\r
232         /// </summary>\r
233         /// \r
234         /// <exception cref="COMException">\r
235         /// スレッドマネージャーの生成に失敗した場合。\r
236         /// </exception>\r
237         protected virtual void CreateThreadMgr()\r
238         {\r
239             throw new NotImplementedException();\r
240         }\r
241 \r
242         /// <summary>\r
243         /// スレッドマネージャーの解放。\r
244         /// </summary>\r
245         void DestroyThreadMgr()\r
246         {\r
247             if (_threadMgr != null)\r
248             {\r
249                 try { _threadMgr.Deactivate(); }\r
250                 catch (Exception) { }\r
251 \r
252                 ReleaseComObject("_threadMgr", ref _threadMgr);\r
253             }\r
254         }\r
255 \r
256         /// <summary>\r
257         /// カテゴリマネージャーの生成。\r
258         /// </summary>\r
259         /// \r
260         /// <exception cref="COMException">\r
261         /// カテゴリマネージャーの生成に失敗した場合。\r
262         /// </exception>\r
263         void CreateCategoryMgr()\r
264         {\r
265             if (_categoryMgr == null)\r
266             {\r
267                 var clsid = Marshal.GetTypeFromCLSID(TfDeclarations.CLSID_TF_CategoryMgr);\r
268                 _categoryMgr = Activator.CreateInstance(clsid) as ITfCategoryMgr;\r
269 \r
270                 if (_categoryMgr == null)\r
271                 {\r
272                     const string message = "カテゴリマネージャーの生成に失敗しました。";\r
273                     Debug.WriteLine(message);\r
274                     throw new COMException(message, HRESULT.E_NOTIMPL);\r
275                 }\r
276             }\r
277         }\r
278 \r
279         /// <summary>\r
280         /// カテゴリマネージャーの解放。\r
281         /// </summary>\r
282         void DestroyCategoryMgr()\r
283         {\r
284             ReleaseComObject("_categoryMgr", ref _categoryMgr);\r
285         }\r
286 \r
287         /// <summary>\r
288         /// 表示属性マネージャーの生成。\r
289         /// </summary>\r
290         /// \r
291         /// <exception cref="COMException">\r
292         /// 表示属性マネージャーの生成に失敗した場合。\r
293         /// </exception>\r
294         void CreateDisplayAttributeMgr()\r
295         {\r
296             if (_displayAttributeMgr == null)\r
297             {\r
298                 var clsid = Marshal.GetTypeFromCLSID(TfDeclarations.CLSID_TF_DisplayAttributeMgr);\r
299                 _displayAttributeMgr = Activator.CreateInstance(clsid) as ITfDisplayAttributeMgr;\r
300 \r
301                 if (_displayAttributeMgr == null)\r
302                 {\r
303                     const string message = "表示属性マネージャーの生成に失敗しました。";\r
304                     Debug.WriteLine(message);\r
305                     throw new COMException(message, HRESULT.E_NOTIMPL);\r
306                 }\r
307             }\r
308         }\r
309 \r
310         /// <summary>\r
311         /// 表示属性マネージャーの解放。\r
312         /// </summary>\r
313         void DestroyDisplayAttributeMgr()\r
314         {\r
315             ReleaseComObject("_displayAttributeMgr", ref _displayAttributeMgr);\r
316         }\r
317 \r
318         /// <summary>\r
319         /// ドキュメントマネージャーの解放\r
320         /// </summary>\r
321         void DestroyDocumentMgr()\r
322         {\r
323             if (_documentMgr != null)\r
324             {\r
325                 try { _documentMgr.Pop(PopFlags.TF_POPF_ALL); }\r
326                 catch (Exception) { }\r
327 \r
328                 ReleaseComObject("_documentMgr", ref _documentMgr);\r
329             }\r
330         }\r
331 \r
332         /// <summary>\r
333         /// COM オブジェクトのリリースとデバッグメッセージ出力。\r
334         /// </summary>\r
335         protected static void ReleaseComObject<ComObject>(\r
336             string i_objectName,\r
337             ref ComObject io_comObject\r
338         )\r
339         {\r
340             if (io_comObject != null)\r
341             {\r
342                 var refCount = Marshal.ReleaseComObject(io_comObject);\r
343 #if TSF_DEBUG_OUTPUT\r
344                     Debug.WriteLine(\r
345                         "Marshal.ReleaseComObject({0}) returns {1}.",\r
346                         i_objectName,\r
347                         refCount\r
348                     );\r
349 #endif\r
350 \r
351                 io_comObject = default(ComObject);\r
352             }\r
353         }\r
354         #endregion\r
355 \r
356         #region "コントロール側が状況に応じて呼び出さなければいけない TSF に通知を送るメソッド"\r
357         /// <summary>\r
358         /// 選択領域が変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。\r
359         /// </summary>\r
360         public void NotifySelectionChanged()\r
361         {\r
362             if( _sink != null )\r
363             {\r
364 #if TSF_DEBUG_OUTPUT\r
365                 DebugOut.Print(DebugOut.GetCaller());\r
366 #endif\r
367                 if ((_adviseFlags & AdviseFlags.TS_AS_SEL_CHANGE) != 0)\r
368                     _sink.OnSelectionChange();\r
369             }\r
370         }\r
371 \r
372         \r
373         //=========================================================================================\r
374 \r
375 \r
376         /// <summary>\r
377         /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。\r
378         /// </summary>\r
379         void NotifyTextChanged(TS_TEXTCHANGE textChange)\r
380         {\r
381             if( _sink != null )\r
382             {\r
383 #if TSF_DEBUG_OUTPUT\r
384                 DebugOut.Print(DebugOut.GetCaller());\r
385 #endif\r
386                 if ((_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0)\r
387                     _sink.OnTextChange(0, ref textChange);\r
388                 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);\r
389             }\r
390         }\r
391 \r
392         \r
393         //=========================================================================================\r
394 \r
395         /// <summary>\r
396         /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。\r
397         /// </summary>\r
398         /// <param name="start">開始位置</param>\r
399         /// <param name="oldend">更新前の終了位置</param>\r
400         /// <param name="newend">更新後の終了位置</param>\r
401         /// <remarks>\r
402         /// 詳しいことはITextStoreACPSink::OnTextChangeを参照してください\r
403         /// </remarks>\r
404         public void NotifyTextChanged(int start,int oldend,int newend)\r
405         {\r
406             if (_sink != null)\r
407             {\r
408 #if TSF_DEBUG_OUTPUT\r
409                 DebugOut.Print(DebugOut.GetCaller());\r
410 #endif\r
411                 if ((_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0)\r
412                 {\r
413                     var textChange = new TS_TEXTCHANGE();\r
414                     textChange.start = start;\r
415                     textChange.oldEnd = oldend;\r
416                     textChange.newEnd = newend;\r
417 \r
418                     _sink.OnTextChange(0, ref textChange);\r
419                 }\r
420                 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);\r
421             }\r
422         }\r
423 \r
424         /// <summary>\r
425         /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。\r
426         /// </summary>\r
427         /// <param name="i_oldLength"></param>\r
428         /// <param name="i_newLength"></param>\r
429         public void NotifyTextChanged(int i_oldLength, int i_newLength)\r
430         {\r
431             if( _sink != null )\r
432             {\r
433 #if TSF_DEBUG_OUTPUT\r
434                 DebugOut.Print(DebugOut.GetCaller());\r
435 #endif\r
436                 if ((_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0)\r
437                 {\r
438                     var textChange = new TS_TEXTCHANGE();\r
439                     textChange.start = 0;\r
440                     textChange.oldEnd = i_oldLength;\r
441                     textChange.newEnd = i_newLength;\r
442 \r
443                     _sink.OnTextChange(0, ref textChange);\r
444                 }\r
445                 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);\r
446             }\r
447         }\r
448 \r
449         \r
450         \r
451         //=========================================================================================\r
452 \r
453 \r
454         /// <summary>コントロールがフォーカスを取得した時に呼び出さなければいけない。</summary>\r
455         public void SetFocus()\r
456         {\r
457 #if TSF_DEBUG_OUTPUT\r
458             DebugOut.Print(DebugOut.GetCaller());\r
459 #endif\r
460             if (_threadMgr != null)\r
461                 _threadMgr.SetFocus(_documentMgr);\r
462         }\r
463         #endregion "コントロール側が状況に応じて呼び出さなければいけない TSF に通知を送るメソッド"\r
464 \r
465         #region ロック関連\r
466         /// <summary>\r
467         /// ドキュメントのロックを行う。\r
468         /// </summary>\r
469         /// <param name="i_writable">読み書き両用ロックか?false の場合、読み取り専用。</param>\r
470         /// <returns>Unlocker のインスタンスを返す。失敗した場合 null を返す。</returns>\r
471         public Unlocker LockDocument(bool i_writable)\r
472         {\r
473             #if TSF_DEBUG_OUTPUT\r
474             using(var dbgout = new DebugOut("{0}({1})", DebugOut.GetCaller(),\r
475                                                         i_writable) )\r
476             #endif\r
477             {\r
478                 lock(this)\r
479                 {\r
480                     if( this._lockFlags == 0 )\r
481                     {\r
482                         if( i_writable )\r
483                             this._lockFlags = LockFlags.TS_LF_READWRITE;\r
484                         else\r
485                             this._lockFlags = LockFlags.TS_LF_READ;\r
486 \r
487                         #if TSF_DEBUG_OUTPUT\r
488                             Debug.WriteLine("LockDocument is succeeded.");\r
489                         #endif\r
490 \r
491                         return new Unlocker(this);\r
492                     }\r
493                     else\r
494                     {\r
495                         #if TSF_DEBUG_OUTPUT\r
496                             Debug.WriteLine("LockDocument is failed. {0}", _lockFlags);\r
497                         #endif\r
498 \r
499                         return null;\r
500                     }\r
501                 }\r
502             }\r
503         }\r
504 \r
505 \r
506         //========================================================================================\r
507 \r
508         \r
509         /// <summary>\r
510         /// ドキュメントのロックを行う。\r
511         /// </summary>\r
512         /// <param name="i_writable">読み書き両用ロックか?false の場合、読み取り専用。</param>\r
513         /// <returns>Unlocker のインスタンスを返す。失敗した場合 null を返す。</returns>\r
514         public Unlocker LockDocument(LockFlags i_flags)\r
515         {\r
516             #if TSF_DEBUG_OUTPUT\r
517             using(var dbgout = new DebugOut("{0}({1})", DebugOut.GetCaller(),\r
518                                                         i_flags) )\r
519             #endif\r
520             {\r
521                 lock(this)\r
522                 {\r
523                     if( this._lockFlags == 0 )\r
524                     {\r
525                         this._lockFlags = i_flags;\r
526 \r
527                         #if TSF_DEBUG_OUTPUT\r
528                             Debug.WriteLine("LockDocument is succeeded.");\r
529                         #endif\r
530 \r
531                         return new Unlocker(this);\r
532                     }\r
533                     else\r
534                     {\r
535                         #if TSF_DEBUG_OUTPUT\r
536                             Debug.WriteLine("LockDocument is failed. {0}", _lockFlags);\r
537                         #endif\r
538 \r
539                         return null;\r
540                     }\r
541                 }\r
542             }\r
543         }\r
544 \r
545 \r
546         //========================================================================================\r
547 \r
548         \r
549         /// <summary>\r
550         /// ドキュメントのアンロックを行う。\r
551         /// </summary>\r
552         public void UnlockDocument()\r
553         {\r
554             #if TSF_DEBUG_OUTPUT\r
555             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
556             #endif\r
557             {\r
558                 lock(this)\r
559                 {\r
560                     _lockFlags = 0;\r
561                 }\r
562 \r
563                 if( _pendingLockUpgrade )\r
564                 {\r
565                     _pendingLockUpgrade = false;\r
566                     int sessionResult;\r
567                     RequestLock(LockFlags.TS_LF_READWRITE, out sessionResult);\r
568                 }\r
569             }\r
570         }\r
571 \r
572 \r
573         //========================================================================================\r
574 \r
575         \r
576         /// <summary>\r
577         /// 指定されたフラグでロックしている状態かどうか調べる。\r
578         /// </summary>\r
579         /// <param name="i_lockFlags"></param>\r
580         /// <returns>ロックされている場合は true, されていない場合は false を返す。</returns>\r
581         public bool IsLocked(LockFlags i_lockFlags)\r
582         {\r
583             #if TSF_DEBUG_OUTPUT\r
584             using(var dbgout = new DebugOut("{0}({1})",\r
585                                             DebugOut.GetCaller(), i_lockFlags) )\r
586             #endif\r
587             {\r
588                 #if TSF_DEBUG_OUTPUT\r
589                     Debug.WriteLine(\r
590                         "IsLocked() returns " + ((this._lockFlags & i_lockFlags) == i_lockFlags)\r
591                     );\r
592                 #endif\r
593                 return (this._lockFlags & i_lockFlags) == i_lockFlags;\r
594             }\r
595         }\r
596 \r
597         /// <summary>\r
598         /// ロックされているか調べる\r
599         /// </summary>\r
600         /// <returns>ロックされているなら真、そうでなければ偽を返す</returns>\r
601         public bool IsLocked()\r
602         {\r
603 #if TSF_DEBUG_OUTPUT\r
604             using(var dbgout = new DebugOut("{0}",\r
605                                             DebugOut.GetCaller()) )\r
606 #endif\r
607             {\r
608                 bool retval = this._lockFlags != 0;\r
609 #if TSF_DEBUG_OUTPUT\r
610                     Debug.WriteLine(\r
611                         "IsLocked() returns " + retval\r
612                     );\r
613 #endif\r
614                 return retval;\r
615             }\r
616         }\r
617         #endregion\r
618 \r
619         #region ITextStroeACP,ITextStoreACP2の共通部分\r
620 \r
621         /// <summary>\r
622         /// 文字列を挿入する。\r
623         /// </summary>\r
624         public void InsertTextAtSelection(string s)\r
625         {\r
626             TS_TEXTCHANGE textChange = new TS_TEXTCHANGE();\r
627 \r
628             using (var unlocker = LockDocument(true))\r
629             {\r
630                 if (unlocker != null)\r
631                 {\r
632                     int startIndex, endIndex;\r
633 \r
634                     InsertTextAtSelection(\r
635                         UnmanagedAPI.TSF.TextStore.InsertAtSelectionFlags.TF_IAS_NOQUERY,\r
636                         s.ToCharArray(),\r
637                         s.Length,\r
638                         out startIndex,\r
639                         out endIndex,\r
640                         out textChange\r
641                     );\r
642                 }\r
643             }\r
644 \r
645             // シンクの OnSelectionChange() をコール。\r
646             NotifySelectionChanged();\r
647             NotifyTextChanged(textChange);\r
648         }\r
649 \r
650         public void InsertEmbeddedAtSelection(\r
651             InsertAtSelectionFlags flags,\r
652             object obj,\r
653             out int start,\r
654             out int end,\r
655             out TS_TEXTCHANGE change\r
656         )\r
657         {\r
658 #if TSF_DEBUG_OUTPUT\r
659             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
660 #endif\r
661             {\r
662                 throw new NotImplementedException();\r
663             }\r
664         }\r
665 \r
666         public void AdviseSink(ref Guid i_riid, object i_unknown, AdviseFlags i_mask)\r
667         {\r
668 #if TSF_DEBUG_OUTPUT\r
669             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
670 #endif\r
671             {\r
672                 if (i_riid != new Guid("22d44c94-a419-4542-a272-ae26093ececf")) //ITextStoreACPSinkの定義より\r
673                 {\r
674                     throw new COMException(\r
675                         "ITextStoreACPSink 以外のIIDが渡されました。",\r
676                         UnmanagedAPI.WinError.HRESULT.E_INVALIDARG\r
677                     );\r
678                 }\r
679 \r
680                 // 既存のシンクのマスクのみを更新\r
681                 if (_sink == i_unknown)\r
682                 {\r
683                     _adviseFlags = i_mask;\r
684                 }\r
685                 // シンクを複数登録しようとした\r
686                 else if (_sink != null)\r
687                 {\r
688                     throw new COMException(\r
689                         "既にシンクを登録済みです。",\r
690                         UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_ADVISELIMIT\r
691                     );\r
692                 }\r
693                 else\r
694                 {\r
695                     // 各種値を保存\r
696                     _services = (ITextStoreACPServices)i_unknown;\r
697                     _sink = (ITextStoreACPSink)i_unknown;\r
698                     _adviseFlags = i_mask;\r
699                 }\r
700             }\r
701         }\r
702 \r
703         public void UnadviseSink(object i_unknown)\r
704         {\r
705 #if TSF_DEBUG_OUTPUT\r
706             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
707 #endif\r
708             {\r
709                 if (_sink == null || _sink != i_unknown)\r
710                 {\r
711                     throw new COMException(\r
712                         "シンクは登録されていません。",\r
713                         UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_NOCONNECTION\r
714                     );\r
715                 }\r
716 \r
717                 _services = null;\r
718                 _sink = null;\r
719                 _adviseFlags = 0;\r
720             }\r
721         }\r
722 \r
723         public void RequestLock(LockFlags i_lockFlags, out int o_sessionResult)\r
724         {\r
725 #if TSF_DEBUG_OUTPUT\r
726             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
727 #endif\r
728             {\r
729                 o_sessionResult = UnmanagedAPI.WinError.HRESULT.E_FAIL;\r
730 \r
731                 if (_sink == null)\r
732                 {\r
733                     throw new COMException(\r
734                         "シンクが登録されていません。",\r
735                         UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_NOCONNECTION\r
736                     );\r
737                 }\r
738 \r
739                 if (_lockFlags != 0)   // すでにロックされた状態の場合。\r
740                 {\r
741                     if ((i_lockFlags & LockFlags.TS_LF_SYNC) != 0)\r
742                     {\r
743                         o_sessionResult = TsResult.TS_E_SYNCHRONOUS;\r
744                         return;\r
745                     }\r
746                     else\r
747                         if ((_lockFlags & LockFlags.TS_LF_READWRITE) == LockFlags.TS_LF_READ\r
748                         && (i_lockFlags & LockFlags.TS_LF_READWRITE) == LockFlags.TS_LF_READWRITE)\r
749                         {\r
750                             _pendingLockUpgrade = true;\r
751                             o_sessionResult = TsResult.TS_S_ASYNC;\r
752                             return;\r
753                         }\r
754 \r
755                     throw new COMException();\r
756                 }\r
757 \r
758                 using (var unlocker = LockDocument(i_lockFlags))\r
759                 {\r
760                     // ロックに失敗した場合は TS_E_SYNCHRONOUS をセットして S_OK を返す。\r
761                     if (unlocker == null)\r
762                     {\r
763                         o_sessionResult = TsResult.TS_E_SYNCHRONOUS;\r
764                     }\r
765                     // ロックに成功した場合は OnLockGranted() を呼び出す。\r
766                     else\r
767                     {\r
768                         try\r
769                         {\r
770                             o_sessionResult = _sink.OnLockGranted(i_lockFlags);\r
771                         }\r
772                         catch (COMException comException)\r
773                         {\r
774                             Debug.WriteLine("OnLockGranted() 呼び出し中に例外が発生。");\r
775                             Debug.WriteLine("  " + comException.Message);\r
776                             o_sessionResult = comException.HResult;\r
777                         }\r
778                         catch (Exception exception)\r
779                         {\r
780                             Debug.WriteLine("OnLockGranted() 呼び出し中に例外が発生。");\r
781                             Debug.WriteLine("  " + exception.Message);\r
782                         }\r
783                     }\r
784                 }\r
785             }\r
786         }\r
787 \r
788         public void GetStatus(out TS_STATUS o_documentStatus)\r
789         {\r
790 #if TSF_DEBUG_OUTPUT\r
791             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
792 #endif\r
793             {\r
794                 if (IsReadOnly != null && IsReadOnly())\r
795                     o_documentStatus.dynamicFlags = DynamicStatusFlags.TS_SD_READONLY;\r
796                 if (IsLoading != null && IsLoading())\r
797                     o_documentStatus.dynamicFlags = DynamicStatusFlags.TS_SD_LOADING;\r
798                 else\r
799                     o_documentStatus.dynamicFlags = 0;\r
800                 o_documentStatus.staticFlags = StaticStatusFlags.TS_SS_REGIONS;\r
801             }\r
802         }\r
803 \r
804         public void QueryInsert(\r
805             int i_startIndex,\r
806             int i_endIndex,\r
807             int i_length,\r
808             out int o_startIndex,\r
809             out int o_endIndex\r
810         )\r
811         {\r
812 #if TSF_DEBUG_OUTPUT\r
813             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
814 #endif\r
815             {\r
816                 if (GetStringLength == null)\r
817                     throw new NotImplementedException();\r
818 \r
819                 int documentLength = GetStringLength();\r
820 \r
821                 if (i_startIndex < 0\r
822                 || i_startIndex > i_endIndex\r
823                 || i_endIndex > documentLength)\r
824                 {\r
825                     throw new COMException(\r
826                         "インデックスが無効です。",\r
827                         UnmanagedAPI.WinError.HRESULT.E_INVALIDARG\r
828                     );\r
829                 }\r
830                 o_startIndex = i_startIndex;\r
831                 o_endIndex = i_endIndex;\r
832 \r
833 #if TSF_DEBUG_OUTPUT\r
834                 DebugOut.Print("o_startIndex:{0} o_endIndex:{1}", i_startIndex, i_endIndex);\r
835 #endif\r
836             }\r
837         }\r
838 \r
839         public void GetSelection(\r
840             int i_index,\r
841             int i_selectionBufferLength,\r
842             TS_SELECTION_ACP[] o_selections,\r
843             out int o_fetchedLength\r
844         )\r
845         {\r
846 #if TSF_DEBUG_OUTPUT\r
847             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
848 #endif\r
849             {\r
850                 if (GetSelectionIndex == null)\r
851                     throw new NotImplementedException();\r
852 \r
853                 o_fetchedLength = 0;\r
854 \r
855                 if (IsLocked(LockFlags.TS_LF_READ) == false)\r
856                 {\r
857                     throw new COMException(\r
858                         "読取用ロックがされていません。",\r
859                         TsResult.TS_E_NOLOCK\r
860                     );\r
861                 }\r
862 \r
863                 // -1 は TF_DEFAULT_SELECTION。選択は1つだけしかサポートしないので、\r
864                 // TF_DEFAULT_SELECTION でもなく、0 を超える数値が指定された場合はエラー。\r
865                 if (i_index != -1 && i_index > 0)\r
866                 {\r
867                     throw new COMException(\r
868                         "選択は1つだけしかサポートしていません。",\r
869                         UnmanagedAPI.WinError.HRESULT.E_INVALIDARG\r
870                     );\r
871                 }\r
872 \r
873                 if (i_selectionBufferLength > 0)\r
874                 {\r
875                     int start = 0, end = 0;\r
876                     GetSelectionIndex(out start, out end);\r
877                     if (start <= end)\r
878                     {\r
879                         o_selections[0].start = start;\r
880                         o_selections[0].end = end;\r
881                         o_selections[0].style.ase = TsActiveSelEnd.TS_AE_END;\r
882                         o_selections[0].style.interimChar = false;\r
883                     }\r
884                     else\r
885                     {\r
886                         o_selections[0].start = end;\r
887                         o_selections[0].end = start;\r
888                         o_selections[0].style.ase = TsActiveSelEnd.TS_AE_START;\r
889                         o_selections[0].style.interimChar = false;\r
890                     }\r
891 \r
892                     o_fetchedLength = 1;\r
893 \r
894 #if TSF_DEBUG_OUTPUT\r
895                     DebugOut.Print("sel start:{0} end:{1}", start, end);\r
896 #endif\r
897                 }\r
898             }\r
899         }\r
900 \r
901         public void SetSelection(int i_count, TS_SELECTION_ACP[] i_selections)\r
902         {\r
903 #if TSF_DEBUG_OUTPUT\r
904             using(var dbgout = new DebugOut("{0}({1}, {2})",\r
905                                             DebugOut.GetCaller(),\r
906                                             i_selections[0].start,\r
907                                             i_selections[0].end))\r
908 #endif\r
909             {\r
910                 if (SetSelectionIndex == null)\r
911                     throw new NotImplementedException();\r
912 \r
913                 if (i_count != 1)\r
914                 {\r
915                     throw new COMException(\r
916                         "選択は1つだけしかサポートしていません。",\r
917                         UnmanagedAPI.WinError.HRESULT.E_INVALIDARG\r
918                     );\r
919                 }\r
920 \r
921                 if (IsLocked(LockFlags.TS_LF_READWRITE) == false)\r
922                 {\r
923                     throw new COMException(\r
924                         "ロックされていません。",\r
925                         TsResult.TS_E_NOLOCK\r
926                     );\r
927                 }\r
928 \r
929                 SetSelectionIndex(i_selections[0].start, i_selections[0].end);\r
930 \r
931 #if TSF_DEBUG_OUTPUT\r
932                 DebugOut.Print("set selection startIndex:{0} endIndex:{1}", i_selections[0].start, i_selections[0].end);\r
933 #endif\r
934             }\r
935         }\r
936 \r
937         public void GetText(\r
938             int i_startIndex,\r
939             int i_endIndex,\r
940             char[] o_plainText,\r
941             int i_plainTextLength,\r
942             out int o_plainTextLength,\r
943             TS_RUNINFO[] o_runInfos,\r
944             int i_runInfoLength,\r
945             out int o_runInfoLength,\r
946             out int o_nextUnreadCharPos\r
947         )\r
948         {\r
949 #if TSF_DEBUG_OUTPUT\r
950             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
951 #endif\r
952             {\r
953                 if (GetStringLength == null || GetString == null)\r
954                     throw new NotImplementedException();\r
955 \r
956                 if (IsLocked(LockFlags.TS_LF_READ) == false)\r
957                 {\r
958                     throw new COMException(\r
959                         "読取用ロックがされていません。",\r
960                         TsResult.TS_E_NOLOCK\r
961                     );\r
962                 }\r
963 \r
964                 if ((i_endIndex != -1 && i_startIndex > i_endIndex)\r
965                 || i_startIndex < 0 || i_startIndex > GetStringLength()\r
966                 || i_endIndex > GetStringLength())\r
967                 {\r
968                     throw new COMException(\r
969                         "インデックスが無効です。",\r
970                         UnmanagedAPI.WinError.HRESULT.E_INVALIDARG\r
971                     );\r
972                 }\r
973 \r
974                 var textLength = 0;\r
975                 var copyLength = 0;\r
976 \r
977                 if (i_endIndex == -1)\r
978                     textLength = GetStringLength() - i_startIndex;\r
979                 else\r
980                     textLength = i_endIndex - i_startIndex;\r
981                 copyLength = Math.Min(i_plainTextLength, textLength);\r
982 \r
983                 // 文字列を格納。\r
984                 var text = GetString(i_startIndex, copyLength);\r
985 #if TSF_DEBUG_OUTPUT\r
986                 DebugOut.Print("got text:{0} from {1} length {2}", text,i_startIndex,copyLength);\r
987 #endif\r
988                 for (int i = 0; i < copyLength; i++)\r
989                 {\r
990                     o_plainText[i] = text[i];\r
991                 }\r
992 \r
993                 // 文字数を格納。\r
994                 o_plainTextLength = copyLength;\r
995                 // RUNINFO を格納。\r
996                 if (i_runInfoLength > 0)\r
997                 {\r
998                     o_runInfos[0].type = TsRunType.TS_RT_PLAIN;\r
999                     o_runInfos[0].length = copyLength;\r
1000                 }\r
1001                 o_runInfoLength = 1;\r
1002 \r
1003                 // 次の文字の位置を格納。\r
1004                 o_nextUnreadCharPos = i_startIndex + copyLength;\r
1005             }\r
1006         }\r
1007 \r
1008         public void SetText(\r
1009             SetTextFlags i_flags,\r
1010             int i_startIndex,\r
1011             int i_endIndex,\r
1012             char[] i_text,\r
1013             int i_length,\r
1014             out TS_TEXTCHANGE o_textChange\r
1015         )\r
1016         {\r
1017 #if TSF_DEBUG_OUTPUT\r
1018             using(var dbgout = new DebugOut("{0}({1}, {2})",\r
1019                                             DebugOut.GetCaller(),\r
1020                                             i_startIndex, i_endIndex) )\r
1021 #endif\r
1022             {\r
1023                 var selections = new TS_SELECTION_ACP[]\r
1024                 {\r
1025                     new TS_SELECTION_ACP\r
1026                     {\r
1027                         start = i_startIndex,\r
1028                         end   = i_endIndex,\r
1029                         style = new TS_SELECTIONSTYLE\r
1030                         {\r
1031                             ase = TsActiveSelEnd.TS_AE_END,\r
1032                             interimChar = false\r
1033                         }\r
1034                     }\r
1035                 };\r
1036 \r
1037                 int startIndex = 0, endIndex = 0;\r
1038                 SetSelection(1, selections);\r
1039                 InsertTextAtSelection(\r
1040                     InsertAtSelectionFlags.TF_IAS_NOQUERY,\r
1041                     i_text,\r
1042                     i_length,\r
1043                     out startIndex,\r
1044                     out endIndex,\r
1045                     out o_textChange\r
1046                 );\r
1047             }\r
1048         }\r
1049 \r
1050         public void GetFormattedText(int i_start, int i_end, out object o_obj)\r
1051         {\r
1052 #if TSF_DEBUG_OUTPUT\r
1053             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1054 #endif\r
1055             {\r
1056                 throw new NotImplementedException();\r
1057             }\r
1058         }\r
1059 \r
1060         public void GetEmbedded(\r
1061             int i_position,\r
1062             ref Guid i_guidService,\r
1063             ref Guid i_riid,\r
1064             out object o_obj\r
1065         )\r
1066         {\r
1067 #if TSF_DEBUG_OUTPUT\r
1068             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1069 #endif\r
1070             {\r
1071                 throw new NotImplementedException();\r
1072             }\r
1073         }\r
1074 \r
1075         public void QueryInsertEmbedded(\r
1076             ref Guid i_guidService,\r
1077             int i_formatEtc,\r
1078             out bool o_insertable\r
1079         )\r
1080         {\r
1081 #if TSF_DEBUG_OUTPUT\r
1082             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1083 #endif\r
1084             {\r
1085                 throw new NotImplementedException();\r
1086             }\r
1087         }\r
1088 \r
1089         public void InsertEmbedded(\r
1090             InsertEmbeddedFlags i_flags,\r
1091             int i_start,\r
1092             int i_end,\r
1093             object i_obj,\r
1094             out TS_TEXTCHANGE o_textChange\r
1095         )\r
1096         {\r
1097 #if TSF_DEBUG_OUTPUT\r
1098             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1099 #endif\r
1100             {\r
1101                 throw new NotImplementedException();\r
1102             }\r
1103         }\r
1104 \r
1105         public void InsertTextAtSelection(\r
1106             InsertAtSelectionFlags i_flags,\r
1107             char[] i_text,\r
1108             int i_length,\r
1109             out int o_startIndex,\r
1110             out int o_endIndex,\r
1111             out TS_TEXTCHANGE o_textChange\r
1112         )\r
1113         {\r
1114 #if TSF_DEBUG_OUTPUT\r
1115             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1116 #endif\r
1117             {\r
1118                 if (GetSelectionIndex == null || InsertAtSelection == null)\r
1119                     throw new NotImplementedException();\r
1120 \r
1121                 int selectionStart = 0, selectionEnd = 0;\r
1122                 GetSelectionIndex(out selectionStart, out selectionEnd);\r
1123 \r
1124                 // 問い合わせのみで実際には操作を行わない\r
1125                 if ((i_flags & InsertAtSelectionFlags.TF_IAS_QUERYONLY) != 0)\r
1126                 {\r
1127                     o_startIndex = Math.Min(selectionStart, selectionEnd);\r
1128                     o_endIndex = Math.Max(selectionStart, selectionEnd);//o_startIndex + i_length;\r
1129 \r
1130                     o_textChange.start = o_startIndex;\r
1131                     o_textChange.oldEnd = o_endIndex;\r
1132                     o_textChange.newEnd = o_startIndex + i_length;\r
1133                 }\r
1134                 else\r
1135                 {\r
1136                     var start = Math.Min(selectionStart, selectionEnd);\r
1137                     var end = Math.Max(selectionStart, selectionEnd);\r
1138 \r
1139 #if TSF_DEBUG_OUTPUT\r
1140                     DebugOut.Print("start: {0}, end: {1}, text: {2}", start, end, new string(i_text));\r
1141 #endif\r
1142 \r
1143                     InsertAtSelection(new string(i_text));\r
1144 \r
1145                     o_startIndex = start;\r
1146                     o_endIndex = start + i_length;\r
1147 \r
1148                     o_textChange.start = start;\r
1149                     o_textChange.oldEnd = end;\r
1150                     o_textChange.newEnd = start + i_length;\r
1151 \r
1152                     // InsertAtSelection() 内でカーソル位置を更新しているため、ここでは不要。\r
1153                     // 改行した時に位置が狂う。\r
1154                     // SetSelectionIndex(start, start + i_length);\r
1155                 }\r
1156             }\r
1157         }\r
1158 \r
1159         public void GetEndACP(out int o_length)\r
1160         {\r
1161 #if TSF_DEBUG_OUTPUT\r
1162             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1163 #endif\r
1164             {\r
1165                 if (GetStringLength == null)\r
1166                     throw new NotImplementedException();\r
1167 \r
1168                 if (IsLocked(LockFlags.TS_LF_READ) == false)\r
1169                 {\r
1170                     throw new COMException(\r
1171                         "読取用ロックがされていません。",\r
1172                         TsResult.TS_E_NOLOCK\r
1173                     );\r
1174                 }\r
1175 \r
1176                 o_length = GetStringLength();\r
1177             }\r
1178         }\r
1179 \r
1180         public void GetActiveView(out int o_viewCookie)\r
1181         {\r
1182 #if TSF_DEBUG_OUTPUT\r
1183             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1184 #endif\r
1185             {\r
1186                 o_viewCookie = 1;\r
1187             }\r
1188         }\r
1189 \r
1190         public void GetACPFromPoint(\r
1191             int i_viewCookie,\r
1192             ref POINT i_point,\r
1193             GetPositionFromPointFlags i_flags,\r
1194             out int o_index\r
1195         )\r
1196         {\r
1197 #if TSF_DEBUG_OUTPUT\r
1198             using (var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))\r
1199 #endif\r
1200             {\r
1201                 throw new NotImplementedException();\r
1202             }\r
1203         }\r
1204 \r
1205         public void GetTextExt(\r
1206             int i_viewCookie,\r
1207             int i_startIndex,\r
1208             int i_endIndex,\r
1209             out RECT o_rect,\r
1210             out bool o_isClipped\r
1211         )\r
1212         {\r
1213 #if TSF_DEBUG_OUTPUT\r
1214             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1215 #endif\r
1216             {\r
1217                 if (GetStringLength == null)\r
1218                     throw new NotImplementedException();\r
1219 \r
1220                 // 読取用ロックの確認。\r
1221                 if (IsLocked(LockFlags.TS_LF_READ) == false)\r
1222                 {\r
1223                     throw new COMException(\r
1224                         "読取用ロックがされていません。",\r
1225                         TsResult.TS_E_NOLOCK\r
1226                     );\r
1227                 }\r
1228 \r
1229                 if ((i_endIndex != -1 && i_startIndex > i_endIndex)\r
1230                 || i_startIndex < 0 || i_startIndex > GetStringLength()\r
1231                 || i_endIndex > GetStringLength())\r
1232                 {\r
1233                     throw new COMException(\r
1234                         "インデックスが無効です。",\r
1235                         UnmanagedAPI.WinError.HRESULT.E_INVALIDARG\r
1236                     );\r
1237                 }\r
1238 \r
1239                 if (i_endIndex == -1)\r
1240                     i_endIndex = GetStringLength();\r
1241 \r
1242                 var pointTopLeft = new POINT();\r
1243                 var pointBotttomRight = new POINT();\r
1244                 GetStringExtent(i_startIndex, i_endIndex, out pointTopLeft, out pointBotttomRight);\r
1245 \r
1246                 if(this.GetDpi == null)\r
1247                     throw new NotImplementedException();\r
1248 \r
1249                 double dpi = this.GetDpi();\r
1250 \r
1251                 o_rect.left = (int)(pointTopLeft.x * dpi / 96.0);\r
1252                 o_rect.top = (int)(pointTopLeft.y * dpi / 96.0);\r
1253                 o_rect.bottom = (int)(pointBotttomRight.y * dpi / 96.0);\r
1254                 o_rect.right = (int)(pointBotttomRight.x * dpi / 96.0);\r
1255                 o_isClipped = false;\r
1256 #if TSF_DEBUG_OUTPUT\r
1257                 DebugOut.Print("rect left:{0} top:{1} bottom:{2} right:{3}", o_rect.left, o_rect.top, o_rect.bottom, o_rect.right);\r
1258 #endif\r
1259             }\r
1260         }\r
1261 \r
1262         public void GetScreenExt(int i_viewCookie, out RECT o_rect)\r
1263         {\r
1264 #if TSF_DEBUG_OUTPUT\r
1265             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1266 #endif\r
1267             {\r
1268                 if (GetScreenExtent == null)\r
1269                     throw new NotImplementedException();\r
1270 \r
1271                 POINT pointTopLeft, pointBottomRight;\r
1272 \r
1273                 GetScreenExtent(out pointTopLeft, out pointBottomRight);\r
1274 \r
1275                 if (this.GetDpi == null)\r
1276                     throw new NotImplementedException();\r
1277 \r
1278                 double dpi = this.GetDpi();\r
1279 \r
1280                 o_rect.left = (int)(pointTopLeft.x * dpi / 96.0);\r
1281                 o_rect.top = (int)(pointTopLeft.y * dpi / 96.0);\r
1282                 o_rect.bottom = (int)(pointBottomRight.y * dpi / 96.0);\r
1283                 o_rect.right = (int)(pointBottomRight.x * dpi / 96.0);\r
1284 #if TSF_DEBUG_OUTPUT\r
1285                 DebugOut.Print("rect left:{0} top:{1} bottom:{2} right:{3}", o_rect.left, o_rect.top, o_rect.bottom, o_rect.right);\r
1286 #endif\r
1287             }\r
1288         }\r
1289 \r
1290         public void RequestSupportedAttrs(\r
1291             AttributeFlags i_flags,\r
1292             int i_length,\r
1293             Guid[] i_filterAttributes\r
1294         )\r
1295         {\r
1296 #if TSF_DEBUG_OUTPUT\r
1297             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1298 #endif\r
1299             {\r
1300                 for (int i = 0; i < i_length; i++)\r
1301                 {\r
1302                     if (i_filterAttributes[i].Equals(_attributeInfo[0].attrID))\r
1303                     {\r
1304                         _attributeInfo[0].flags = AttributeInfoFlags.Requested;\r
1305                         if ((i_flags & AttributeFlags.TS_ATTR_FIND_WANT_VALUE) != 0)\r
1306                         {\r
1307                             _attributeInfo[0].flags |= AttributeInfoFlags.Default;\r
1308                         }\r
1309                         else\r
1310                         {\r
1311                             _attributeInfo[0].currentValue = _attributeInfo[0].defaultValue;\r
1312                         }\r
1313                     }\r
1314                 }\r
1315             }\r
1316         }\r
1317 \r
1318         public void RequestAttrsAtPosition(\r
1319             int i_position,\r
1320             int i_length,\r
1321             Guid[] i_filterAttributes,\r
1322             AttributeFlags i_flags\r
1323         )\r
1324         {\r
1325 #if TSF_DEBUG_OUTPUT\r
1326             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1327 #endif\r
1328             {\r
1329                 for (int i = 0; i < i_length; i++)\r
1330                 {\r
1331                     if (i_filterAttributes[i].Equals(_attributeInfo[0].attrID))\r
1332                     {\r
1333                         _attributeInfo[0].flags = AttributeInfoFlags.Requested;\r
1334                         if ((i_flags & AttributeFlags.TS_ATTR_FIND_WANT_VALUE) != 0)\r
1335                         {\r
1336                             _attributeInfo[0].flags |= AttributeInfoFlags.Default;\r
1337                         }\r
1338                         else\r
1339                         {\r
1340                             _attributeInfo[0].currentValue = _attributeInfo[0].defaultValue;\r
1341                         }\r
1342                     }\r
1343                 }\r
1344             }\r
1345         }\r
1346 \r
1347         public void RequestAttrsTransitioningAtPosition(\r
1348             int i_position,\r
1349             int i_length,\r
1350             Guid[] i_filterAttributes,\r
1351             AttributeFlags i_flags\r
1352         )\r
1353         {\r
1354 #if TSF_DEBUG_OUTPUT\r
1355             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))\r
1356 #endif\r
1357             {\r
1358                 // 何もしない。\r
1359             }\r
1360         }\r
1361 \r
1362         public void FindNextAttrTransition(\r
1363             int i_start,\r
1364             int i_halt,\r
1365             int i_length,\r
1366             Guid[] i_filterAttributes,\r
1367             AttributeFlags i_flags,\r
1368             out int o_nextIndex,\r
1369             out bool o_found,\r
1370             out int o_foundOffset\r
1371         )\r
1372         {\r
1373 #if TSF_DEBUG_OUTPUT\r
1374             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1375 #endif\r
1376             {\r
1377                 throw new NotImplementedException();\r
1378             }\r
1379         }\r
1380 \r
1381         public void RetrieveRequestedAttrs(\r
1382             int i_length,\r
1383             TS_ATTRVAL[] o_attributeVals,\r
1384             out int o_fetchedLength\r
1385         )\r
1386         {\r
1387 #if TSF_DEBUG_OUTPUT\r
1388             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1389 #endif\r
1390             {\r
1391                 o_fetchedLength = 0;\r
1392                 for (int i = 0; i < _attributeInfo.Length && o_fetchedLength < i_length; i++)\r
1393                 {\r
1394                     if ((_attributeInfo[i].flags & AttributeInfoFlags.Requested) != 0)\r
1395                     {\r
1396                         o_attributeVals[o_fetchedLength].overlappedId = 0;\r
1397                         o_attributeVals[o_fetchedLength].attributeId = _attributeInfo[i].attrID;\r
1398                         o_attributeVals[o_fetchedLength].val = _attributeInfo[i].currentValue;\r
1399 \r
1400                         if ((_attributeInfo[i].flags & AttributeInfoFlags.Default) != 0)\r
1401                             _attributeInfo[i].currentValue = _attributeInfo[i].defaultValue;\r
1402 \r
1403                         o_fetchedLength++;\r
1404                         _attributeInfo[i].flags = AttributeInfoFlags.None;\r
1405                     }\r
1406                 }\r
1407             }\r
1408         }\r
1409         #endregion\r
1410 \r
1411         #region "ITfContextOwnerCompositionSink インターフェイスの実装"\r
1412         /// <summary>コンポジション入力が開始された時の処理。</summary>\r
1413         public void OnStartComposition(ITfCompositionView view, out bool ok)\r
1414         {\r
1415             #if TSF_DEBUG_OUTPUT\r
1416             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1417             #endif\r
1418             {\r
1419                 if( CompositionStarted != null )\r
1420                     ok = CompositionStarted();\r
1421                 else\r
1422                     ok = true;\r
1423             }\r
1424         }\r
1425 \r
1426 \r
1427         //========================================================================================\r
1428 \r
1429 \r
1430         /// <summary>コンポジションが変更された時の処理。</summary>\r
1431         public void OnUpdateComposition(ITfCompositionView view, ITfRange rangeNew)\r
1432         {\r
1433             #if TSF_DEBUG_OUTPUT\r
1434             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1435             #endif\r
1436             {\r
1437                 if (rangeNew == null)\r
1438                     return;\r
1439 \r
1440                 int start, count;\r
1441                 \r
1442                 ITfRangeACP rangeAcp = (ITfRangeACP)rangeNew;\r
1443                 \r
1444                 rangeAcp.GetExtent(out start, out count);\r
1445                 \r
1446                 if (this.CompositionUpdated != null)\r
1447                     this.CompositionUpdated(start, start + count);\r
1448             }\r
1449         }\r
1450 \r
1451         \r
1452         //========================================================================================\r
1453 \r
1454 \r
1455         /// <summary>コンポジション入力が終了した時の処理。</summary>\r
1456         public void OnEndComposition(ITfCompositionView view)\r
1457         {\r
1458             #if TSF_DEBUG_OUTPUT\r
1459             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1460             #endif\r
1461             {\r
1462                 if( CompositionEnded != null )\r
1463                     CompositionEnded();\r
1464             }\r
1465         }\r
1466         #endregion "ITfContextOwnerCompositionSink インターフェイスの実装"\r
1467 \r
1468         #region 表示属性\r
1469         /// <summary>表示属性の取得</summary>\r
1470         public IEnumerable<TextDisplayAttribute> EnumAttributes(int start, int end)\r
1471         {\r
1472             ITfRangeACP allRange;\r
1473             _services.CreateRange(start, end, out allRange);\r
1474 \r
1475             foreach (TextDisplayAttribute attr in this.EnumAttributes((ITfRange)allRange))\r
1476                 yield return attr;\r
1477 \r
1478             ReleaseComObject("allRange", ref allRange);\r
1479         }\r
1480 \r
1481         IEnumerable<TextDisplayAttribute> EnumAttributes(ITfRange range)\r
1482         {\r
1483 #if TSF_DEBUG_OUTPUT\r
1484             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))\r
1485 #endif\r
1486             {\r
1487                 ITfProperty property = null;    // プロパティインターフェイス\r
1488                 IEnumTfRanges enumRanges;         // 範囲の列挙子\r
1489                 Guid guidPropAttribute = TfDeclarations.GUID_PROP_ATTRIBUTE;\r
1490 \r
1491                 if (_context == null || _services == null)\r
1492                     yield break;\r
1493 \r
1494                 // GUID_PROP_ATTRIBUTE プロパティを取得。\r
1495                 _context.GetProperty(ref guidPropAttribute, out property);\r
1496                 if (property == null)\r
1497                     yield break;\r
1498 \r
1499                 // 全範囲の中で表示属性プロパティをもつ範囲を列挙する。\r
1500                 property.EnumRanges((int)_editCookie, out enumRanges, range);\r
1501 \r
1502                 ITfRange[] ranges = new ITfRange[1];\r
1503                 int fetchedLength = 0;\r
1504                 while (HRESULT.Succeeded(enumRanges.Next(1, ranges, out fetchedLength))\r
1505                     && fetchedLength > 0)\r
1506                 {\r
1507                     // ItfRange から ItfRangeACP を取得。\r
1508                     ITfRangeACP rangeACP = ranges[0] as ITfRangeACP;\r
1509                     if (rangeACP == null)\r
1510                         continue;   // 普通はあり得ない\r
1511 \r
1512                     // 範囲の開始位置と文字数を取得。\r
1513                     int start, count;\r
1514                     rangeACP.GetExtent(out start, out count);\r
1515 \r
1516                     // VARIANT 値としてプロパティ値を取得。VT_I4 の GUID ATOM がとれる。\r
1517                     VARIANT value = new VARIANT();\r
1518                     property.GetValue((int)_editCookie, ranges[0], ref value);\r
1519                     if (value.vt == (short)VarEnum.VT_I4)\r
1520                     {\r
1521                         Guid guid, clsid;\r
1522                         ITfDisplayAttributeInfo info;\r
1523                         TF_DISPLAYATTRIBUTE attribute;\r
1524 \r
1525                         // GUID ATOM から GUID を取得する。\r
1526                         _categoryMgr.GetGUID((int)value.data1, out guid);\r
1527                         // その GUID から IDisplayAttributeInfo インターフェイスを取得。\r
1528                         _displayAttributeMgr.GetDisplayAttributeInfo(\r
1529                             ref guid,\r
1530                             out info,\r
1531                             out clsid\r
1532                         );\r
1533                         // さらに IDisplayAttributeInfo インターフェイスから表示属性を取得する。\r
1534                         info.GetAttributeInfo(out attribute);\r
1535                         ReleaseComObject("info", ref info);\r
1536 \r
1537                         yield return new TextDisplayAttribute\r
1538                         {\r
1539                             startIndex = start,\r
1540                             endIndex = start + count,\r
1541                             attribute = attribute\r
1542                         };\r
1543 \r
1544 #if TSF_DEBUG_OUTPUT_DISPLAY_ATTR\r
1545                             Debug.WriteLine(\r
1546                                 "*******:::: DisplayAttribute: {0} ~ {1} :::::: *********",\r
1547                                 start, start + count\r
1548                             );\r
1549                             Debug.WriteLine(attribute.bAttr);\r
1550                             Debug.WriteLine(\r
1551                                 "LineColorType: {0}, {1}",\r
1552                                 attribute.crLine.type, attribute.crLine.indexOrColorRef\r
1553                             );\r
1554                             Debug.WriteLine(\r
1555                                 "TextColorType: {0}, {1}",\r
1556                                 attribute.crText.type, attribute.crText.indexOrColorRef\r
1557                             );\r
1558                             Debug.WriteLine(\r
1559                                 "BackColorType: {0}, {1}",\r
1560                                 attribute.crBk.type, attribute.crBk.indexOrColorRef\r
1561                             );\r
1562                             Debug.WriteLine(\r
1563                                 "Bold, Style  : {0}, {1}",\r
1564                                 attribute.fBoldLine, attribute.lsStyle\r
1565                             );\r
1566 #endif\r
1567                     }\r
1568 \r
1569                     ReleaseComObject("rangeACP", ref rangeACP);\r
1570                 }\r
1571 \r
1572                 ReleaseComObject("ranges[0]", ref ranges[0]);\r
1573                 ReleaseComObject("enumRanges", ref enumRanges);\r
1574                 ReleaseComObject("property", ref property);\r
1575             }\r
1576         }\r
1577         #endregion\r
1578 \r
1579 #if METRO\r
1580         protected ITfThreadMgr2 _threadMgr;\r
1581 #else\r
1582         protected ITfThreadMgr _threadMgr;\r
1583 #endif\r
1584         protected ITfDocumentMgr _documentMgr;\r
1585         protected ITfFunctionProvider _functionProvider;\r
1586         protected ITfFnReconversion _reconversion;\r
1587         protected ITfContext _context;\r
1588         protected ITfCategoryMgr _categoryMgr;\r
1589         protected ITfDisplayAttributeMgr _displayAttributeMgr;\r
1590         protected ITextStoreACPSink _sink;\r
1591         protected uint _editCookie = 0;\r
1592         protected ITextStoreACPServices _services;\r
1593         protected AdviseFlags               _adviseFlags = 0;\r
1594         protected LockFlags                 _lockFlags = 0;\r
1595         protected bool                      _pendingLockUpgrade = false;\r
1596 \r
1597         /// <summary>\r
1598         /// AttributeInfo で使用されるフラグ。各属性の状態を示す。\r
1599         /// </summary>\r
1600         protected enum AttributeInfoFlags\r
1601         {\r
1602             /// <summary>何もない。</summary>\r
1603             None        = 0,\r
1604             /// <summary>デフォルト値の要求。</summary>\r
1605             Default     = 1 << 0,\r
1606             /// <summary>要求された。</summary>\r
1607             Requested   = 1 << 1\r
1608         }\r
1609 \r
1610         protected struct AttributeInfo\r
1611         {\r
1612             public Guid                 attrID;\r
1613             public AttributeInfoFlags   flags;\r
1614             public VARIANT              currentValue;\r
1615             public VARIANT              defaultValue;\r
1616         }\r
1617 \r
1618         protected AttributeInfo[]       _attributeInfo = new AttributeInfo[1];\r
1619 \r
1620     }\r
1621 }\r