/*
         *  テキストを変更して、変更情報をアンドゥ/リドゥのスタックにプッシュします。
         */
        void PushUndoRedoStack(int sel_start, int sel_end, string new_text, Stack <TDiff> dst_stack)
        {
            // 変更範囲にある改行文字の個数
            int old_LF_cnt = GetLFCount(sel_start, sel_end);

            // 変更情報を作ります。
            TDiff diff = new TDiff(sel_start, sel_end - sel_start, new_text.Length);

            // 変更情報をアンドゥのスタックにプッシュします。
            dst_stack.Push(diff);

            // 削除する文字列をコピーします。
            Chars.CopyTo(sel_start, diff.RemovedChars, 0, diff.RemovedChars.Length);

            // 文字列を削除します。
            Chars.RemoveRange(sel_start, sel_end - sel_start);

            // 新しい文字列を挿入します。
            Chars.InsertRange(sel_start, (from x in new_text select new TChar(x)));

            // アプリ内で持っているテキストの選択位置を更新します。
            SelOrigin  = sel_start + new_text.Length;
            SelCurrent = SelOrigin;

            // 新しく挿入した文字列に含まれる改行文字の個数
            int new_LF_cnt = (from x in new_text where x == LF select x).Count();//   GetLFCount(sel_start, sel_start + new_text.Length);

            // 文書の行数を更新します。
            LineCount += new_LF_cnt - old_LF_cnt;
        }
        /*
         *  アンドゥとリドゥ
         */
        void UndoRedo(bool is_undo)
        {
            Stack <TDiff> src_stack;
            Stack <TDiff> dst_stack;

            // アンドゥとリドゥは操作対象のスタックが違うだけです。
            if (is_undo)
            {
                // アンドゥの場合

                // アンドゥのスタックからポップして、リドゥのスタックにプッシュします。
                src_stack = UndoStack;
                dst_stack = RedoStack;
            }
            else
            {
                // リドゥの場合

                // リドゥのスタックからポップして、アンドゥのスタックにプッシュします。
                src_stack = RedoStack;
                dst_stack = UndoStack;
            }

            if (src_stack.Count == 0)
            {
                // ポップするスタックが空の場合

                return;
            }

            // 変更情報をポップします。
            TDiff src_diff = src_stack.Pop();

            // 削除された文字列
            string removed_string = new string((from x in src_diff.RemovedChars select x.Chr).ToArray());

            // テキストを変更して、変更情報をアンドゥ/リドゥのスタックにプッシュします。
            PushUndoRedoStack(src_diff.DiffPos, src_diff.DiffPos + src_diff.InsertedCount, removed_string, dst_stack);

            // テキストの変更をIMEに伝えます。
            MyNotifyTextChanged(src_diff.DiffPos, src_diff.DiffPos + src_diff.InsertedCount, src_diff.RemovedChars.Length);

            // 再描画します。
            Win2DCanvas.Invalidate();
        }