OSDN Git Service

Fix Code scanning alerts #4: Upcast array used in pointer arithmetic
[winmerge-jp/winmerge-jp.git] / Externals / crystaledit / editlib / ccrystaleditview.cpp
1 ///////////////////////////////////////////////////////////////////////////
2 //  File:       ccrystaleditview.cpp
3 //  Version:    1.2.0.5
4 //  Created:    29-Dec-1998
5 //
6 //  Copyright:  Stcherbatchenko Andrei
7 //  E-mail:     windfall@gmx.de
8 //
9 //  Implementation of the CCrystalEditView class, a part of the Crystal Edit -
10 //  syntax coloring text editor.
11 //
12 //  You are free to use or modify this code to the following restrictions:
13 //  - Acknowledge me somewhere in your about box, simple "Parts of code by.."
14 //  will be enough. If you can't (or don't want to), contact me personally.
15 //  - LEAVE THIS HEADER INTACT
16 ////////////////////////////////////////////////////////////////////////////
17
18 ////////////////////////////////////////////////////////////////////////////
19 //  21-Feb-99
20 //      Paul Selormey, James R. Twine:
21 //  +   FEATURE: description for Undo/Redo actions
22 //  +   FEATURE: multiple MSVC-like bookmarks
23 //  +   FEATURE: 'Disable backspace at beginning of line' option
24 //  +   FEATURE: 'Disable drag-n-drop editing' option
25 //
26 //  +   FEATURE: Auto indent
27 //  +   FIX: ResetView() was overriden to provide cleanup
28 ////////////////////////////////////////////////////////////////////////////
29
30 ////////////////////////////////////////////////////////////////////////////
31 //  19-Jul-99
32 //      Ferdinand Prantl:
33 //  +   FEATURE: support for autoindenting brackets and parentheses
34 //  +   FEATURE: menu options, view and window
35 //  +   FEATURE: SDI+MDI versions with help
36 //  +   FEATURE: extended registry support for saving settings
37 //  +   FEATURE: some other things I've forgotten ...
38 //  27-Jul-99
39 //  +   FIX: treating groups in regular expressions corrected
40 //  +   FIX: autocomplete corrected
41 //
42 //  ... it's being edited very rapidly so sorry for non-commented
43 //        and maybe "ugly" code ...
44 ////////////////////////////////////////////////////////////////////////////
45
46 ////////////////////////////////////////////////////////////////////////////
47 //  ??-Aug-99
48 //      Sven Wiegand (search for "//BEGIN SW" to find my changes):
49 //  + FEATURE: "Go to last change" (sets the cursor on the position where
50 //          the user did his last edit actions
51 //  + FEATURE: Support for incremental search in CCrystalTextView
52 ////////////////////////////////////////////////////////////////////////////
53
54 ////////////////////////////////////////////////////////////////////////////
55 //  24-Oct-99
56 //      Sven Wiegand
57 //  + FEATURE: Supporting [Return] to exit incremental-search-mode
58 //           (see OnChar())
59 ////////////////////////////////////////////////////////////////////////////
60
61 /**
62  * @file  ccrystaleditview.cpp
63  *
64  * @brief Implementation of the CCrystalEditView class
65  */
66
67 #include "StdAfx.h"
68 #include "editcmd.h"
69 #include "editreg.h"
70 #include "ccrystaleditview.h"
71 #include "ccrystaltextbuffer.h"
72 #include "dialogs/ceditreplacedlg.h"
73 #include "dialogs/chcondlg.h"
74 #include "utils/registry.h"
75 #include "utils/cs2cs.h"
76 #include "utils/string_util.h"
77 #include "utils/icu.hpp"
78
79 #ifndef __AFXPRIV_H__
80 #pragma message("Include <afxpriv.h> in your stdafx.h to avoid this message")
81 #include <afxpriv.h>
82 #endif
83 #ifndef __AFXOLE_H__
84 #pragma message("Include <afxole.h> in your stdafx.h to avoid this message")
85 #include <afxole.h>
86 #endif
87
88 #ifdef _DEBUG
89 #define new DEBUG_NEW
90 #endif
91
92 static const unsigned int MAX_TAB_LEN = 64;  // Same as in CrystalViewText.cpp
93
94 #define DRAG_BORDER_X       5
95 #define DRAG_BORDER_Y       5
96
97 /////////////////////////////////////////////////////////////////////////////
98 // CEditDropTargetImpl class declaration
99
100 class CEditDropTargetImpl : public COleDropTarget
101   {
102 private :
103     CCrystalEditView * m_pOwner;
104 public :
105     explicit CEditDropTargetImpl (CCrystalEditView * pOwner)
106       : m_pOwner(pOwner), m_pAlternateDropTarget(nullptr)
107     {
108     };
109
110     virtual DROPEFFECT OnDragEnter (CWnd * pWnd, COleDataObject * pDataObject, DWORD dwKeyState, CPoint point);
111     virtual void OnDragLeave (CWnd * pWnd);
112     virtual DROPEFFECT OnDragOver (CWnd * pWnd, COleDataObject * pDataObject, DWORD dwKeyState, CPoint point);
113     virtual BOOL OnDrop (CWnd * pWnd, COleDataObject * pDataObject, DROPEFFECT dropEffect, CPoint point);
114     virtual DROPEFFECT OnDragScroll (CWnd * pWnd, DWORD dwKeyState, CPoint point);
115
116     IDropTarget * m_pAlternateDropTarget;
117   };
118
119
120 /////////////////////////////////////////////////////////////////////////////
121 // CCrystalEditView
122
123 IMPLEMENT_DYNCREATE (CCrystalEditView, CCrystalTextView)
124
125 CCrystalEditView::CCrystalEditView ()
126 : m_nLastReplaceLen(0)
127 , m_mapExpand(new CMap<CString, LPCTSTR, CString, LPCTSTR> (10))
128 , m_bLastReplace(false)
129 , m_dwLastReplaceFlags(0)
130 , m_pEditReplaceDlg(nullptr)
131 , m_bDropPosVisible(false)
132 , m_bSelectionPushed(false)
133 , m_bAutoIndent(true)
134 , m_bDisableBSAtSOL(false)
135 , m_pDropTarget(nullptr)
136 , m_bMergeUndo(false)
137 {
138 }
139
140 CCrystalEditView:: ~CCrystalEditView ()
141 {
142   delete m_mapExpand;
143   delete m_pEditReplaceDlg;
144 }
145
146 bool CCrystalEditView::
147 DoSetTextType (CrystalLineParser::TextDefinition *def)
148 {
149   m_CurSourceDef = def;
150   SetAutoIndent ((def->flags & SRCOPT_AUTOINDENT) != 0);
151   SetDisableBSAtSOL ((def->flags & SRCOPT_BSATBOL) == 0);
152   m_mapExpand->RemoveAll ();
153   CReg reg;
154   CString sKey = AfxGetApp ()->m_pszRegistryKey;
155   sKey += _T("\\") EDITPAD_SECTION _T("\\");
156   sKey += def->name;
157   sKey += _T ("\\Expand");
158   if (reg.Open (HKEY_CURRENT_USER, sKey, KEY_READ))
159     {
160       LPCTSTR pszValue;
161       RegVal regVal;
162       if (reg.FindFirstValue (pszValue, &regVal))
163         {
164           CString sData;
165           do
166             if (RegValGetString (&regVal, sData))
167               m_mapExpand->SetAt (pszValue, sData);
168           while (reg.FindNextValue (pszValue, &regVal));
169         }
170       reg.FindClose ();
171     }
172   return CCrystalTextView::DoSetTextType (def);
173 }
174
175 BEGIN_MESSAGE_MAP (CCrystalEditView, CCrystalTextView)
176 //{{AFX_MSG_MAP(CCrystalEditView)
177 ON_COMMAND (ID_EDIT_PASTE, OnEditPaste)
178 ON_UPDATE_COMMAND_UI (ID_EDIT_CUT, OnUpdateEditCut)
179 ON_COMMAND (ID_EDIT_CUT, OnEditCut)
180 ON_UPDATE_COMMAND_UI (ID_EDIT_PASTE, OnUpdateEditPaste)
181 ON_COMMAND (ID_EDIT_DELETE, OnEditDelete)
182 ON_WM_CHAR ()
183 ON_COMMAND (ID_EDIT_DELETE_BACK, OnEditDeleteBack)
184 ON_COMMAND (ID_EDIT_UNTAB, OnEditUntab)
185 ON_COMMAND (ID_EDIT_TAB, OnEditTab)
186 ON_COMMAND (ID_EDIT_SWITCH_OVRMODE, OnEditSwitchOvrmode)
187 ON_UPDATE_COMMAND_UI (ID_EDIT_SWITCH_OVRMODE, OnUpdateEditSwitchOvrmode)
188 ON_WM_CREATE ()
189 ON_WM_DESTROY ()
190 ON_COMMAND (ID_EDIT_REPLACE, OnEditReplace)
191 ON_UPDATE_COMMAND_UI (ID_EDIT_UNDO, OnUpdateEditUndo)
192 ON_COMMAND (ID_EDIT_UNDO, OnEditUndo)
193 ON_UPDATE_COMMAND_UI (ID_EDIT_REDO, OnUpdateEditRedo)
194 ON_COMMAND (ID_EDIT_REDO, OnEditRedo)
195 ON_UPDATE_COMMAND_UI (ID_EDIT_AUTOCOMPLETE, OnUpdateEditAutoComplete)
196 ON_COMMAND (ID_EDIT_AUTOCOMPLETE, OnEditAutoComplete)
197 ON_UPDATE_COMMAND_UI (ID_EDIT_AUTOEXPAND, OnUpdateEditAutoExpand)
198 ON_COMMAND (ID_EDIT_AUTOEXPAND, OnEditAutoExpand)
199 ON_UPDATE_COMMAND_UI (ID_EDIT_LOWERCASE, OnUpdateEditLowerCase)
200 ON_COMMAND (ID_EDIT_LOWERCASE, OnEditLowerCase)
201 ON_UPDATE_COMMAND_UI (ID_EDIT_UPPERCASE, OnUpdateEditUpperCase)
202 ON_COMMAND (ID_EDIT_UPPERCASE, OnEditUpperCase)
203 ON_UPDATE_COMMAND_UI (ID_EDIT_SWAPCASE, OnUpdateEditSwapCase)
204 ON_COMMAND (ID_EDIT_SWAPCASE, OnEditSwapCase)
205 ON_UPDATE_COMMAND_UI (ID_EDIT_SWAPCASE, OnUpdateEditSwapCase)
206 ON_COMMAND (ID_EDIT_SWAPCASE, OnEditSwapCase)
207 ON_UPDATE_COMMAND_UI (ID_EDIT_CAPITALIZE, OnUpdateEditCapitalize)
208 ON_COMMAND (ID_EDIT_CAPITALIZE, OnEditCapitalize)
209 ON_UPDATE_COMMAND_UI (ID_EDIT_SENTENCE, OnUpdateEditSentence)
210 ON_COMMAND (ID_EDIT_SENTENCE, OnEditSentence)
211 ON_UPDATE_COMMAND_UI(ID_EDIT_GOTO_LAST_CHANGE, OnUpdateEditGotoLastChange)
212 ON_COMMAND(ID_EDIT_GOTO_LAST_CHANGE, OnEditGotoLastChange)
213 ON_COMMAND(ID_EDIT_DELETE_WORD, OnEditDeleteWord)
214 ON_COMMAND(ID_EDIT_DELETE_WORD_BACK, OnEditDeleteWordBack)
215 ON_WM_KILLFOCUS ()
216 //}}AFX_MSG_MAP
217 ON_UPDATE_COMMAND_UI (ID_EDIT_INDICATOR_READ, OnUpdateIndicatorRead)
218 ON_UPDATE_COMMAND_UI (ID_INDICATOR_OVR, OnUpdateIndicatorOvr)
219 ON_UPDATE_COMMAND_UI (ID_EDIT_INDICATOR_POSITION, OnUpdateIndicatorPosition)
220 ON_UPDATE_COMMAND_UI (ID_TOOLS_SPELLING, OnUpdateToolsSpelling)
221 ON_COMMAND (ID_TOOLS_SPELLING, OnToolsSpelling)
222 ON_UPDATE_COMMAND_UI (ID_TOOLS_CHARCODING, OnUpdateToolsCharCoding)
223 ON_COMMAND (ID_TOOLS_CHARCODING, OnToolsCharCoding)
224 // cursor movement commands
225 ON_COMMAND (ID_EDIT_CHAR_LEFT, OnCharLeft)
226 ON_COMMAND (ID_EDIT_EXT_CHAR_LEFT, OnExtCharLeft)
227 ON_COMMAND (ID_EDIT_CHAR_RIGHT, OnCharRight)
228 ON_COMMAND (ID_EDIT_EXT_CHAR_RIGHT, OnExtCharRight)
229 ON_COMMAND (ID_EDIT_WORD_LEFT, OnWordLeft)
230 ON_COMMAND (ID_EDIT_EXT_WORD_LEFT, OnExtWordLeft)
231 ON_COMMAND (ID_EDIT_WORD_RIGHT, OnWordRight)
232 ON_COMMAND (ID_EDIT_EXT_WORD_RIGHT, OnExtWordRight)
233 ON_COMMAND (ID_EDIT_LINE_UP, OnLineUp)
234 ON_COMMAND (ID_EDIT_EXT_LINE_UP, OnExtLineUp)
235 ON_COMMAND (ID_EDIT_LINE_DOWN, OnLineDown)
236 ON_COMMAND (ID_EDIT_EXT_LINE_DOWN, OnExtLineDown)
237 ON_COMMAND (ID_EDIT_SCROLL_UP, ScrollUp)
238 ON_COMMAND (ID_EDIT_SCROLL_DOWN, ScrollDown)
239 ON_COMMAND (ID_EDIT_PAGE_UP, OnPageUp)
240 ON_COMMAND (ID_EDIT_EXT_PAGE_UP, OnExtPageUp)
241 ON_COMMAND (ID_EDIT_PAGE_DOWN, OnPageDown)
242 ON_COMMAND (ID_EDIT_EXT_PAGE_DOWN, OnExtPageDown)
243 ON_COMMAND (ID_EDIT_LINE_END, OnLineEnd)
244 ON_COMMAND (ID_EDIT_EXT_LINE_END, OnExtLineEnd)
245 ON_COMMAND (ID_EDIT_HOME, OnHome)
246 ON_COMMAND (ID_EDIT_EXT_HOME, OnExtHome)
247 ON_COMMAND (ID_EDIT_TEXT_BEGIN, OnTextBegin)
248 ON_COMMAND (ID_EDIT_EXT_TEXT_BEGIN, OnExtTextBegin)
249 ON_COMMAND (ID_EDIT_TEXT_END, OnTextEnd)
250 ON_COMMAND (ID_EDIT_EXT_TEXT_END, OnExtTextEnd)
251 ON_WM_LBUTTONDOWN ()
252 ON_WM_RBUTTONDOWN ()
253 END_MESSAGE_MAP ()
254
255
256 /////////////////////////////////////////////////////////////////////////////
257 // CCrystalEditView message handlers
258
259 void CCrystalEditView::ResetView ()
260 {
261   // m_bAutoIndent = true;
262   m_bOvrMode = false;
263   m_bLastReplace = false;
264   CCrystalTextView::ResetView ();
265 }
266
267 bool CCrystalEditView::
268 QueryEditable ()
269 {
270   if (m_pTextBuffer == nullptr)
271     return false;
272   return !m_pTextBuffer->GetReadOnly ();
273 }
274
275 void CCrystalEditView::
276 OnEditPaste ()
277 {
278   Paste ();
279 }
280
281 void CCrystalEditView::
282 OnUpdateEditPaste (CCmdUI * pCmdUI)
283 {
284   pCmdUI->Enable (TextInClipboard ());
285 }
286
287 void CCrystalEditView::
288 OnUpdateEditCut (CCmdUI * pCmdUI)
289 {
290   pCmdUI->Enable (IsSelection ());
291 }
292
293 void CCrystalEditView::
294 OnEditCut ()
295 {
296   Cut ();
297 }
298
299 bool CCrystalEditView::
300 DeleteCurrentSelection ()
301 {
302   if (IsSelection ())
303     {
304       auto [ptSelStart, ptSelEnd] = GetSelection ();
305
306       CPoint ptCursorPos = ptSelStart;
307       ASSERT_VALIDTEXTPOS (ptCursorPos);
308       SetAnchor (ptCursorPos);
309       SetSelection (ptCursorPos, ptCursorPos);
310       SetCursorPos (ptCursorPos);
311       EnsureVisible (ptCursorPos);
312
313       // [JRT]:
314       m_pTextBuffer->DeleteText (this, ptSelStart.y, ptSelStart.x, ptSelEnd.y, ptSelEnd.x, CE_ACTION_DELSEL);
315       return true;
316     }
317   return false;
318 }
319
320 bool CCrystalEditView::
321 DeleteCurrentColumnSelection (int nAction, bool bFlushUndoGroup /*= true*/, bool bUpdateCursorPosition /*= true*/)
322 {
323   if (IsSelection ())
324     {
325       if (bFlushUndoGroup)
326         m_pTextBuffer->BeginUndoGroup ();
327
328       auto [ptSelStart, ptSelEnd] = GetSelection ();
329
330       int nSelLeft, nSelRight;
331       GetColumnSelection (m_ptDrawSelStart.y, nSelLeft, nSelRight);
332       CPoint ptCursorPos(nSelLeft, m_ptDrawSelStart.y);
333       int nStartLine = m_ptDrawSelStart.y;
334       int nEndLine = m_ptDrawSelEnd.y;
335
336       if (GetEnableHideLines ())
337         {
338           for (int nLineIndex = nEndLine; nLineIndex >= nStartLine; nLineIndex--)
339             {
340               if (!(GetLineFlags (nLineIndex) & LF_INVISIBLE))
341                 {
342                   int nEndLine2 = nLineIndex;
343                   int nStartLine2;
344                   for (nStartLine2 = nLineIndex - 1; nStartLine2 >= nStartLine; nStartLine2--)
345                     {
346                       if (GetLineFlags (nStartLine2) & LF_INVISIBLE)
347                         break;
348                     }  
349                   nStartLine2++;
350                   nLineIndex = nStartLine2;
351                   DeleteCurrentColumnSelection2 (nStartLine2, nEndLine2, nAction);
352                 }
353             }
354         }
355       else
356         {
357           DeleteCurrentColumnSelection2 (ptSelStart.y, ptSelEnd.y, nAction);
358         }
359
360       if (bFlushUndoGroup)
361         m_pTextBuffer->FlushUndoGroup (this);
362
363       if (bUpdateCursorPosition)
364         {
365           ASSERT_VALIDTEXTPOS (ptCursorPos);
366           SetAnchor (ptCursorPos);
367           SetSelection (ptCursorPos, ptCursorPos);
368           SetCursorPos (ptCursorPos);
369           EnsureVisible (ptCursorPos);
370         }
371       return true;
372     }
373   return false;
374 }
375
376 bool CCrystalEditView::
377 DeleteCurrentColumnSelection2 (int nStartLine, int nEndLine, int nAction)
378 {
379   int nBufSize = 1;
380   for (int L = nStartLine; L <= nEndLine; L++)
381     nBufSize += GetFullLineLength (L);
382
383   CString text;
384   LPTSTR p, pszBuf = text.GetBuffer (nBufSize);
385   p = pszBuf;
386
387   for (int I = nStartLine; I <= nEndLine; I++)
388     {
389       LPCTSTR pszChars = GetLineChars (I);
390       int nSelLeft, nSelRight;
391       GetColumnSelection (I, nSelLeft, nSelRight);
392       if (nSelLeft > 0)
393         {
394           memcpy (p, pszChars, sizeof (TCHAR) * nSelLeft);
395           p += nSelLeft;
396         }
397       int nLineLength = GetFullLineLength (I);
398       if (nSelRight < nLineLength)
399         {
400           memcpy (p, pszChars + nSelRight, sizeof (TCHAR) * (nLineLength - nSelRight));
401           p += nLineLength - nSelRight;
402         }
403     }
404
405   p[0] = 0;
406   text.ReleaseBuffer (static_cast<int>(p - pszBuf));
407   text.FreeExtra ();
408
409   if (nEndLine + 1 < GetLineCount())
410     m_pTextBuffer->DeleteText (this, nStartLine, 0, nEndLine + 1, 0, nAction);
411   else
412     m_pTextBuffer->DeleteText (this, nStartLine, 0, nEndLine, GetLineLength (nEndLine), nAction);
413   int x, y;
414   m_pTextBuffer->InsertText (this, nStartLine, 0, text, text.GetLength(), y, x, nAction);
415
416   return true;
417 }
418
419 bool CCrystalEditView::
420 InsertColumnText (int nLine, int nPos, LPCTSTR pszText, int cchText, int nAction, bool bFlushUndoGroup)
421 {
422   if (pszText == nullptr || cchText == 0)
423     return false;
424
425   CTypedPtrArray<CPtrArray, LPTSTR> aLines;
426   CDWordArray aLineLengths;
427   int nLineBegin = 0;
428   for (int nTextPos = 0; nTextPos < cchText; )
429     {
430       TCHAR ch = 0;
431       aLines.Add ((LPTSTR)&pszText[nTextPos]);
432
433       for (; nTextPos < cchText; nTextPos++)
434         {
435           ch = pszText[nTextPos];
436           if (ch=='\r' || ch=='\n'/*iseol(pszText[nTextPos]*/)
437             break;
438         }
439
440       aLineLengths.Add (nTextPos - nLineBegin);
441
442       // advance after EOL of line
443       if (ch=='\r' && pszText[nTextPos + 1]=='\n'/*isdoseol(&pszText[nTextPos])*/)
444         nTextPos += 2;
445       else if (ch=='\r' || ch=='\n'/*iseol(pszText[nTextPos])*/)
446         nTextPos++;
447       nLineBegin = nTextPos;
448     }
449
450   int L;
451   int nBufSize = 1;
452   int nLineCount = GetLineCount ();
453   ASSERT(aLineLengths.GetSize() < INT_MAX);
454   int nPasteTextLineCount = static_cast<int>(aLineLengths.GetSize ());
455   for (L = 0; L < nPasteTextLineCount; L++)
456     {
457       if (nLine + L < nLineCount)
458         nBufSize += GetFullLineLength (nLine + L) + aLineLengths[L] + 2;
459       else
460         nBufSize += aLineLengths[L] + 2;
461     }
462
463   LPTSTR pszBuf = new TCHAR[nBufSize];
464   LPTSTR p = pszBuf;
465   int nTopBeginCharPos = CalculateActualOffset (nLine, nPos, true);
466   for (L = 0; L < nPasteTextLineCount; L++)
467     {
468       if (nLine + L < nLineCount)
469         {
470           int nLineLength = GetFullLineLength (nLine + L);
471           LPCTSTR pszChars = GetLineChars (nLine + L);
472           int nOffset = ApproxActualOffset (nLine + L, nTopBeginCharPos);
473           memcpy(p, pszChars, nOffset * sizeof(TCHAR));
474           p += nOffset;
475           memcpy(p, aLines[L], aLineLengths[L] * sizeof(TCHAR));
476           p += aLineLengths[L];
477           memcpy(p, pszChars + nOffset, (nLineLength - nOffset) * sizeof(TCHAR));
478           p += nLineLength - nOffset;
479         }
480       else
481         {
482           CString sEol = m_pTextBuffer->GetDefaultEol ();
483           if (p > pszBuf && p[-1] != '\r' && p[-1] != '\n')
484             {
485               memcpy(p, sEol, sEol.GetLength () * sizeof(TCHAR));
486               p += sEol.GetLength ();
487             }
488           memcpy(p, aLines[L], aLineLengths[L] * sizeof(TCHAR));
489           p += aLineLengths[L];
490           memcpy(p, sEol, sEol.GetLength () * sizeof(TCHAR));
491           p += sEol.GetLength ();
492         }
493     }
494   p[0] = 0;
495
496   if (bFlushUndoGroup)
497     m_pTextBuffer->BeginUndoGroup ();
498
499   if (nLine + nPasteTextLineCount + 1 < nLineCount)
500     m_pTextBuffer->DeleteText (this, nLine, 0, nLine + nPasteTextLineCount, 0, nAction);
501   else if (nLine != nLineCount - 1 || GetLineLength (nLineCount - 1) != 0)
502     m_pTextBuffer->DeleteText (this, nLine, 0, nLineCount - 1, GetLineLength (nLineCount - 1), nAction);
503   int x, y;
504   m_pTextBuffer->InsertText (this, nLine, 0, pszBuf, static_cast<int>(p - pszBuf), x, y, nAction);
505
506   if (bFlushUndoGroup)
507     m_pTextBuffer->FlushUndoGroup (this);
508
509   delete [] pszBuf;
510
511   return true;
512 }
513
514 void CCrystalEditView::
515 Paste ()
516 {
517   if (!QueryEditable ())
518     return;
519   if (m_pTextBuffer == nullptr)
520     return;
521
522   CString text;
523   bool bColumnSelection;
524   if (GetFromClipboard (text, bColumnSelection))
525     {
526       m_pTextBuffer->BeginUndoGroup ();
527     
528       CPoint ptCursorPos;
529       if (IsSelection ())
530         {
531           auto [ptSelStart, ptSelEnd] = GetSelection ();
532
533           ptCursorPos = ptSelStart;
534           /*SetAnchor (ptCursorPos);
535           SetSelection (ptCursorPos, ptCursorPos);
536           SetCursorPos (ptCursorPos);
537           EnsureVisible (ptCursorPos);*/
538
539           // [JRT]:
540           if (!m_bRectangularSelection)
541             m_pTextBuffer->DeleteText (this, ptSelStart.y, ptSelStart.x, ptSelEnd.y, ptSelEnd.x, CE_ACTION_PASTE);
542           else
543             DeleteCurrentColumnSelection (CE_ACTION_PASTE, false, false);
544         }
545       else
546         {
547           ptCursorPos = GetCursorPos ();
548         }
549       ASSERT_VALIDTEXTPOS (ptCursorPos);
550       
551       if (!bColumnSelection)
552         {
553           int x, y;
554           m_pTextBuffer->InsertText (this, ptCursorPos.y, ptCursorPos.x, text, text.GetLength(), y, x, CE_ACTION_PASTE);  //  [JRT]
555           ptCursorPos.x = x;
556           ptCursorPos.y = y;
557         }
558       else
559         InsertColumnText (ptCursorPos.y, ptCursorPos.x, text, text.GetLength(), CE_ACTION_PASTE, false);
560
561       ASSERT_VALIDTEXTPOS (ptCursorPos);
562       SetAnchor (ptCursorPos);
563       SetSelection (ptCursorPos, ptCursorPos);
564       SetCursorPos (ptCursorPos);
565       EnsureVisible (ptCursorPos);
566
567       m_pTextBuffer->FlushUndoGroup (this);
568     }
569 }
570
571 void CCrystalEditView::
572 Cut ()
573 {
574   if (!QueryEditable ())
575     return;
576   if (m_pTextBuffer == nullptr)
577     return;
578   if (!IsSelection ())
579     return;
580
581   auto [ptSelStart, ptSelEnd] = GetSelection ();
582   CString text;
583   if (!m_bRectangularSelection)
584     GetText (ptSelStart, ptSelEnd, text);
585   else
586     GetTextInColumnSelection (text);
587   PutToClipboard (text, text.GetLength());
588
589   if (!m_bRectangularSelection)
590     {
591       CPoint ptCursorPos = ptSelStart;
592       ASSERT_VALIDTEXTPOS (ptCursorPos);
593       SetAnchor (ptCursorPos);
594       SetSelection (ptCursorPos, ptCursorPos);
595       SetCursorPos (ptCursorPos);
596       EnsureVisible (ptCursorPos);
597
598       m_pTextBuffer->DeleteText (this, ptSelStart.y, ptSelStart.x, ptSelEnd.y, ptSelEnd.x, CE_ACTION_CUT);  // [JRT]
599     }
600   else
601     DeleteCurrentColumnSelection (CE_ACTION_CUT);
602 }
603
604 void CCrystalEditView::
605 OnEditDelete ()
606 {
607   if (!QueryEditable () || m_pTextBuffer == nullptr)
608     return;
609
610   auto [ptSelStart, ptSelEnd] = GetSelection ();
611   if (ptSelStart == ptSelEnd)
612     {
613       if (ptSelEnd.x == GetLineLength (ptSelEnd.y))
614         {
615           if (ptSelEnd.y == GetLineCount () - 1)
616             return;
617           ptSelEnd.y++;
618           ptSelEnd.x = 0;
619         }
620       else 
621         {
622           auto pIterChar = ICUBreakIterator::getCharacterBreakIterator(GetLineChars(ptSelEnd.y), GetLineLength(ptSelEnd.y));
623           ptSelEnd.x = pIterChar->following(ptSelEnd.x);
624         }
625     }
626
627   if (!m_bRectangularSelection)
628     {
629       CPoint ptCursorPos = ptSelStart;
630       ASSERT_VALIDTEXTPOS (ptCursorPos);
631       SetAnchor (ptCursorPos);
632       SetSelection (ptCursorPos, ptCursorPos);
633       SetCursorPos (ptCursorPos);
634       EnsureVisible (ptCursorPos);
635
636       m_pTextBuffer->DeleteText (this, ptSelStart.y, ptSelStart.x, ptSelEnd.y, ptSelEnd.x, CE_ACTION_DELETE);   // [JRT]
637     }
638   else
639     DeleteCurrentColumnSelection (CE_ACTION_DELETE);
640 }
641
642 void CCrystalEditView::
643 OnChar (UINT nChar, UINT nRepCnt, UINT nFlags)
644 {
645   //BEGIN SW
646   // check if incremental search is active before call to CCrystalTextView::OnChar()
647   bool bIncrementalSearch = m_bIncrementalSearchForward || m_bIncrementalSearchBackward;
648   //END Sw
649   CCrystalTextView::OnChar (static_cast<wchar_t>(nChar), nRepCnt, nFlags);
650   //BEGIN SW
651   // if we are in incremental search mode ignore the character
652   if( m_bIncrementalSearchForward || m_bIncrementalSearchBackward )
653     return;
654   //END SW
655
656   // if we *were* in incremental search mode and CCrystalTextView::OnChar()
657   // exited it the ignore the character (VK_RETURN)
658   if( bIncrementalSearch && !m_bIncrementalSearchForward && !m_bIncrementalSearchBackward )
659     return;
660   //END SW
661
662   if ((::GetAsyncKeyState (VK_LBUTTON) & 0x8000) != 0 ||
663         (::GetAsyncKeyState (VK_RBUTTON) & 0x8000) != 0)
664     return;
665
666   if (nChar == VK_RETURN)
667     {
668       if (m_bOvrMode)
669         {
670           CPoint ptCursorPos = GetCursorPos ();
671           ASSERT_VALIDTEXTPOS (ptCursorPos);
672           if (ptCursorPos.y < GetLineCount () - 1)
673             {
674               ptCursorPos.x = 0;
675               ptCursorPos.y++;
676
677               ASSERT_VALIDTEXTPOS (ptCursorPos);
678               SetSelection (ptCursorPos, ptCursorPos);
679               SetAnchor (ptCursorPos);
680               SetCursorPos (ptCursorPos);
681               EnsureVisible (ptCursorPos);
682               return;
683             }
684         }
685
686       m_pTextBuffer->BeginUndoGroup(m_bMergeUndo);
687       m_bMergeUndo = false;
688
689       if (QueryEditable () && m_pTextBuffer != nullptr)
690         {
691           CPoint ptCursorPos;
692           if (IsSelection ())
693             {
694               auto [ptSelStart, ptSelEnd] = GetSelection ();
695         
696               ptCursorPos = ptSelStart;
697               /*SetAnchor (ptCursorPos);
698               SetSelection (ptCursorPos, ptCursorPos);
699               SetCursorPos (ptCursorPos);
700               EnsureVisible (ptCursorPos);*/
701         
702               // [JRT]:
703               m_pTextBuffer->DeleteText (this, ptSelStart.y, ptSelStart.x, ptSelEnd.y, ptSelEnd.x, CE_ACTION_TYPING);
704             }
705           else
706             ptCursorPos = GetCursorPos ();
707           ASSERT_VALIDTEXTPOS (ptCursorPos);
708           LPCTSTR pszText = m_pTextBuffer->GetDefaultEol();
709           int cchText = (int) _tcslen(pszText);
710
711           int x, y;
712           m_pTextBuffer->InsertText (this, ptCursorPos.y, ptCursorPos.x, pszText, cchText, y, x, CE_ACTION_TYPING);  //  [JRT]
713
714           ptCursorPos.x = x;
715           ptCursorPos.y = y;
716           ASSERT_VALIDTEXTPOS (ptCursorPos);
717           SetSelection (ptCursorPos, ptCursorPos);
718           SetAnchor (ptCursorPos);
719           SetCursorPos (ptCursorPos);
720           EnsureVisible (ptCursorPos);
721         }
722
723       m_pTextBuffer->FlushUndoGroup (this);
724       return;
725     }
726   // Accept control characters other than [\t\n\r] through Alt-Numpad
727   if (nChar > 31
728   || GetKeyState(VK_CONTROL) >= 0 &&
729       (nChar != 27 || GetKeyState(VK_ESCAPE) >= 0) &&
730       nChar != 9 && nChar != 10 && nChar != 13)
731     {
732       if (QueryEditable () && m_pTextBuffer != nullptr)
733         {
734           m_pTextBuffer->BeginUndoGroup (m_bMergeUndo);
735           m_bMergeUndo = true;
736
737           auto [ptSelStart, ptSelEnd] = GetSelection ();
738           CPoint ptCursorPos;
739           if (ptSelStart != ptSelEnd)
740             {
741               ptCursorPos = ptSelStart;
742               if (IsSelection ())
743                 {
744                   auto [ptSelStart1, ptSelEnd1] = GetSelection ();
745
746                   /*SetAnchor (ptCursorPos);
747                   SetSelection (ptCursorPos, ptCursorPos);
748                   SetCursorPos (ptCursorPos);
749                   EnsureVisible (ptCursorPos);*/
750             
751                   // [JRT]:
752                   m_pTextBuffer->DeleteText (this, ptSelStart1.y, ptSelStart1.x, ptSelEnd1.y, ptSelEnd1.x, CE_ACTION_TYPING);
753                 }
754             }
755           else
756             {
757               ptCursorPos = GetCursorPos ();
758               if (m_bOvrMode && ptCursorPos.x < GetLineLength (ptCursorPos.y))
759                 m_pTextBuffer->DeleteText (this, ptCursorPos.y, ptCursorPos.x, ptCursorPos.y, ptCursorPos.x + 1, CE_ACTION_TYPING);     // [JRT]
760
761             }
762
763           ASSERT_VALIDTEXTPOS (ptCursorPos);
764
765           TCHAR pszText[2];
766           pszText[0] = (TCHAR) nChar;
767           pszText[1] = 0;
768
769           int x, y;
770           m_pTextBuffer->InsertText (this, ptCursorPos.y, ptCursorPos.x, pszText, 1, y, x, CE_ACTION_TYPING);    // [JRT]
771
772           ptCursorPos.x = x;
773           ptCursorPos.y = y;
774           ASSERT_VALIDTEXTPOS (ptCursorPos);
775           SetSelection (ptCursorPos, ptCursorPos);
776           SetAnchor (ptCursorPos);
777           SetCursorPos (ptCursorPos);
778           EnsureVisible (ptCursorPos);
779
780           m_pTextBuffer->FlushUndoGroup (this);
781         }
782     }
783 }
784
785
786 //
787 //  [JRT]: Added Support For "Disable Backspace At Start Of Line"
788 //
789 void CCrystalEditView::
790 OnEditDeleteBack ()
791 {
792   //BEGIN SW
793   // if we are in incremental search mode ignore backspace
794   CCrystalTextView::OnEditDeleteBack();
795   if( m_bIncrementalSearchForward || m_bIncrementalSearchBackward )
796     return;
797   //END SW
798
799   if (IsSelection ())
800     {
801       OnEditDelete ();
802       return;
803     }
804
805   if (!QueryEditable () || m_pTextBuffer == nullptr)
806     return;
807
808   CPoint ptCursorPos = GetCursorPos ();
809   CPoint ptCurrentCursorPos = ptCursorPos;
810   bool bDeleted = false;
811
812   if (!(ptCursorPos.x))         // If At Start Of Line
813
814     {
815       if (!m_bDisableBSAtSOL)   // If DBSASOL Is Disabled
816
817         {
818           if (ptCursorPos.y > 0)    // If Previous Lines Available
819
820             {
821               ptCursorPos.y--;  // Decrement To Previous Line
822
823               ptCursorPos.x = GetLineLength (
824                                 ptCursorPos.y);   // Set Cursor To End Of Previous Line
825
826               bDeleted = true;  // Set Deleted Flag
827
828             }
829         }
830     }
831   else                          // If Caret Not At SOL
832
833     {
834       auto pIterChar = ICUBreakIterator::getCharacterBreakIterator(GetLineChars(ptCursorPos.y), GetLineLength(ptCursorPos.y));
835       ptCursorPos.x = pIterChar->preceding(ptCursorPos.x);
836       bDeleted = true;          // Set Deleted Flag
837     }
838   /*
839      if (ptCursorPos.x == 0)
840      {
841      if (ptCursorPos.y == 0)
842      return;
843      ptCursorPos.y --;
844      ptCursorPos.x = GetLineLength(ptCursorPos.y);
845      }
846      else
847      ptCursorPos.x --;
848    */
849   ASSERT_VALIDTEXTPOS (ptCursorPos);
850   SetAnchor (ptCursorPos);
851   SetSelection (ptCursorPos, ptCursorPos);
852   SetCursorPos (ptCursorPos);
853   EnsureVisible (ptCursorPos);
854
855   if (bDeleted)
856     {
857       m_pTextBuffer->DeleteText (this, ptCursorPos.y, ptCursorPos.x, ptCurrentCursorPos.y, ptCurrentCursorPos.x, CE_ACTION_BACKSPACE);  // [JRT]
858
859     }
860   return;
861 }
862
863 void CCrystalEditView::
864 OnEditTab ()
865 {
866   if (!QueryEditable () || m_pTextBuffer == nullptr)
867     return;
868
869   bool bTabify = false;
870   CPoint ptSelStart, ptSelEnd;
871   if (IsSelection ())
872     {
873       GetSelection (ptSelStart, ptSelEnd);
874       
875       // If we have more than one line selected, tabify sel lines
876       if ( ptSelStart.y != ptSelEnd.y )
877         {
878           bTabify = true;
879         }
880     }
881
882   CPoint ptCursorPos = GetCursorPos ();
883   ASSERT_VALIDTEXTPOS (ptCursorPos);
884
885   TCHAR pszText[MAX_TAB_LEN + 1] = {0};
886   // If inserting tabs, then initialize the text to a tab.
887   if (m_pTextBuffer->GetInsertTabs())
888     {
889       pszText[0] = '\t';
890       pszText[1] = '\0';
891     }
892   else //...otherwise, built whitespace depending on the location and tab stops
893     {
894       int nTabSize = GetTabSize ();
895       int nChars = nTabSize - ptCursorPos.x % nTabSize;
896       for (int i = 0; i < nChars; i++)
897         pszText[i] = ' ';
898       pszText[nChars] = '\0';
899     }
900
901   // Indent selected lines (multiple lines selected)
902   if (bTabify)
903     {
904       m_pTextBuffer->BeginUndoGroup ();
905
906       int nStartLine = ptSelStart.y;
907       int nEndLine = ptSelEnd.y;
908       ptSelStart.x = 0;
909       if (ptSelEnd.x > 0)
910         {
911           if (ptSelEnd.y == GetLineCount () - 1)
912             {
913               ptSelEnd.x = GetLineLength (ptSelEnd.y);
914             }
915           else
916             {
917               ptSelEnd.x = 0;
918               ptSelEnd.y++;
919             }
920         }
921       else  //...otherwise, do not indent the empty line.
922         nEndLine--;
923       SetSelection (ptSelStart, ptSelEnd);
924       SetCursorPos (ptSelEnd);
925       EnsureVisible (ptSelEnd);
926
927       //  Shift selection to right
928       m_bHorzScrollBarLocked = true;
929       for (int L = nStartLine; L <= nEndLine; L++)
930         {
931           int x, y;
932           if (m_pTextBuffer->IsIndentableLine (L))
933             m_pTextBuffer->InsertText (this, L, 0, pszText, (int) _tcslen(pszText), y, x, CE_ACTION_INDENT);  //  [JRT]
934         }
935       m_bHorzScrollBarLocked = false;
936       RecalcHorzScrollBar ();
937
938       m_pTextBuffer->FlushUndoGroup (this);
939       return;
940     }
941
942   // Overwrite mode, replace next char with tab/spaces
943   if (m_bOvrMode)
944     {
945       CPoint ptCursorPos1 = GetCursorPos ();
946       ASSERT_VALIDTEXTPOS (ptCursorPos1);
947
948       int nLineLength = GetLineLength (ptCursorPos1.y);
949       LPCTSTR pszLineChars = GetLineChars (ptCursorPos1.y);
950
951       // Not end of line
952       if (ptCursorPos1.x < nLineLength)
953         {
954           int nTabSize = GetTabSize ();
955           int nChars = nTabSize - CalculateActualOffset(
956               ptCursorPos1.y, ptCursorPos1.x ) % nTabSize;
957           ASSERT (nChars > 0 && nChars <= nTabSize);
958
959           while (nChars > 0)
960             {
961               if (ptCursorPos1.x == nLineLength)
962                 break;
963               if (pszLineChars[ptCursorPos1.x] == _T ('\t'))
964                 {
965                   ptCursorPos1.x++;
966                   break;
967                 }
968               ptCursorPos1.x++;
969               nChars--;
970             }
971           ASSERT (ptCursorPos1.x <= nLineLength);
972           ASSERT_VALIDTEXTPOS (ptCursorPos1);
973
974           SetSelection (ptCursorPos1, ptCursorPos1);
975           SetAnchor (ptCursorPos1);
976           SetCursorPos (ptCursorPos1);
977           EnsureVisible (ptCursorPos1);
978           return;
979         }
980     }
981
982   m_pTextBuffer->BeginUndoGroup ();
983
984   int x, y;     // For cursor position
985
986   // Text selected, no overwrite mode, replace sel with tab
987   if (IsSelection ())
988     {
989       auto [ptSelStart1, ptSelEnd1] = GetSelection ();
990
991       /*SetAnchor (ptCursorPos);
992       SetSelection (ptCursorPos, ptCursorPos);
993       SetCursorPos (ptCursorPos);
994       EnsureVisible (ptCursorPos);*/
995
996       // [JRT]:
997       m_pTextBuffer->DeleteText (this, ptSelStart1.y, ptSelStart1.x, ptSelEnd1.y, ptSelEnd1.x, CE_ACTION_TYPING);
998       m_pTextBuffer->InsertText( this, ptSelStart1.y, ptSelStart1.x, pszText, (int) _tcslen(pszText), y, x, CE_ACTION_TYPING );
999     }
1000   // No selection, add tab
1001   else
1002     {
1003       m_pTextBuffer->InsertText (this, ptCursorPos.y, ptCursorPos.x, pszText, (int) _tcslen(pszText), y, x, CE_ACTION_TYPING);  //  [JRT]
1004     }
1005
1006   ptCursorPos.x = x;
1007   ptCursorPos.y = y;
1008   ASSERT_VALIDTEXTPOS (ptCursorPos);
1009   SetSelection (ptCursorPos, ptCursorPos);
1010   SetAnchor (ptCursorPos);
1011   SetCursorPos (ptCursorPos);
1012   EnsureVisible (ptCursorPos);
1013
1014   m_pTextBuffer->FlushUndoGroup (this);
1015 }
1016
1017 void CCrystalEditView::
1018 OnEditUntab ()
1019 {
1020   if (!QueryEditable () || m_pTextBuffer == nullptr)
1021     return;
1022
1023   bool bTabify = false;
1024   if (IsSelection ())
1025     {
1026       auto [ptSelStart, ptSelEnd] = GetSelection ();
1027       bTabify = ptSelStart.y != ptSelEnd.y;
1028     }
1029
1030   if (bTabify)
1031     {
1032       m_pTextBuffer->BeginUndoGroup ();
1033
1034       auto [ptSelStart, ptSelEnd] = GetSelection ();
1035       int nStartLine = ptSelStart.y;
1036       int nEndLine = ptSelEnd.y;
1037       ptSelStart.x = 0;
1038       if (ptSelEnd.x > 0)
1039         {
1040           if (ptSelEnd.y == GetLineCount () - 1)
1041             {
1042               ptSelEnd.x = GetLineLength (ptSelEnd.y);
1043             }
1044           else
1045             {
1046               ptSelEnd.x = 0;
1047               ptSelEnd.y++;
1048             }
1049         }
1050       else
1051         nEndLine--;
1052       SetSelection (ptSelStart, ptSelEnd);
1053       SetCursorPos (ptSelEnd);
1054       EnsureVisible (ptSelEnd);
1055
1056       //  Shift selection to left
1057       m_bHorzScrollBarLocked = true;
1058       for (int L = nStartLine; L <= nEndLine; L++)
1059         {
1060           int nLength = GetLineLength (L);
1061           if (nLength > 0)
1062             {
1063               LPCTSTR pszChars = GetLineChars (L);
1064               int nPos = 0, nOffset = 0;
1065               while (nPos < nLength)
1066                 {
1067                   if (pszChars[nPos] == _T (' '))
1068                     {
1069                       nPos++;
1070                       if (++nOffset >= GetTabSize ())
1071                         break;
1072                     }
1073                   else
1074                     {
1075                       if (pszChars[nPos] == _T ('\t'))
1076                         nPos++;
1077                       break;
1078                     }
1079                 }
1080
1081               if (nPos > 0)
1082                 m_pTextBuffer->DeleteText (this, L, 0, L, nPos, CE_ACTION_INDENT);  // [JRT]
1083
1084             }
1085         }
1086       m_bHorzScrollBarLocked = false;
1087       RecalcHorzScrollBar ();
1088
1089       m_pTextBuffer->FlushUndoGroup (this);
1090     }
1091   else
1092     {
1093       CPoint ptCursorPos = GetCursorPos ();
1094       ASSERT_VALIDTEXTPOS (ptCursorPos);
1095       if (ptCursorPos.x > 0)
1096         {
1097           int nTabSize = GetTabSize ();
1098           int nOffset = CalculateActualOffset (ptCursorPos.y, ptCursorPos.x);
1099           int nNewOffset = nOffset / nTabSize * nTabSize;
1100           if (nOffset == nNewOffset && nNewOffset > 0)
1101             nNewOffset -= nTabSize;
1102           ASSERT (nNewOffset >= 0);
1103
1104           LPCTSTR pszChars = GetLineChars (ptCursorPos.y);
1105           int nCurrentOffset = 0;
1106           int I = 0;
1107           while (nCurrentOffset < nNewOffset)
1108             {
1109               if (pszChars[I] == _T ('\t'))
1110                 nCurrentOffset = nCurrentOffset / nTabSize * nTabSize + nTabSize;
1111               else
1112                 nCurrentOffset++;
1113               I++;
1114             }
1115
1116           ASSERT (nCurrentOffset == nNewOffset);
1117
1118           ptCursorPos.x = I;
1119           ASSERT_VALIDTEXTPOS (ptCursorPos);
1120           SetSelection (ptCursorPos, ptCursorPos);
1121           SetAnchor (ptCursorPos);
1122           SetCursorPos (ptCursorPos);
1123           EnsureVisible (ptCursorPos);
1124         }
1125     }
1126 }
1127
1128 void CCrystalEditView::
1129 OnUpdateIndicatorCol (CCmdUI * pCmdUI)
1130 {
1131   pCmdUI->Enable (false);
1132 }
1133
1134 void CCrystalEditView::
1135 OnUpdateIndicatorOvr (CCmdUI * pCmdUI)
1136 {
1137   pCmdUI->Enable (m_bOvrMode);
1138 }
1139
1140 void CCrystalEditView::
1141 OnUpdateIndicatorRead (CCmdUI * pCmdUI)
1142 {
1143   if (m_pTextBuffer == nullptr)
1144     pCmdUI->Enable (false);
1145   else
1146     pCmdUI->Enable (m_pTextBuffer->GetReadOnly ());
1147 }
1148
1149 void CCrystalEditView::
1150 OnEditSwitchOvrmode ()
1151 {
1152   m_bOvrMode = !m_bOvrMode;
1153   UpdateCaret ();
1154 }
1155
1156 void CCrystalEditView::
1157 OnUpdateEditSwitchOvrmode (CCmdUI * pCmdUI)
1158 {
1159   pCmdUI->SetCheck (m_bOvrMode ? 1 : 0);
1160 }
1161
1162 DROPEFFECT CEditDropTargetImpl::
1163 OnDragEnter (CWnd * pWnd, COleDataObject * pDataObject, DWORD dwKeyState, CPoint point)
1164 {
1165   CLIPFORMAT fmt = CCrystalTextView::GetClipTcharTextFormat();
1166   if (!pDataObject->IsDataAvailable (fmt))
1167     {
1168       if (m_pAlternateDropTarget != nullptr)
1169         {
1170           DROPEFFECT dwEffect = DROPEFFECT_NONE;
1171           m_pAlternateDropTarget->DragEnter(pDataObject->m_lpDataObject, dwKeyState, { point.x, point.y }, &dwEffect);
1172           return dwEffect;
1173         }
1174       m_pOwner->HideDropIndicator ();
1175       return DROPEFFECT_NONE;
1176     }
1177   m_pOwner->ShowDropIndicator (point);
1178   if (dwKeyState & MK_CONTROL)
1179     return DROPEFFECT_COPY;
1180   return DROPEFFECT_MOVE;
1181 }
1182
1183 void CEditDropTargetImpl::
1184 OnDragLeave (CWnd * pWnd)
1185 {
1186   m_pOwner->HideDropIndicator ();
1187 }
1188
1189 DROPEFFECT CEditDropTargetImpl::
1190 OnDragOver (CWnd * pWnd, COleDataObject * pDataObject, DWORD dwKeyState, CPoint point)
1191 {
1192   //
1193   // [JRT]
1194   //
1195   bool bDataSupported = false;
1196
1197   if ((m_pOwner == nullptr) ||            // If No Owner
1198         (!(m_pOwner->QueryEditable ())) ||   // Or Not Editable
1199         (m_pOwner->GetDisableDragAndDrop ()))    // Or Drag And Drop Disabled
1200
1201     {
1202       if (m_pAlternateDropTarget != nullptr)
1203         {
1204           DROPEFFECT dwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK;
1205           m_pAlternateDropTarget->DragOver(dwKeyState, { point.x, point.y }, &dwEffect);
1206           return dwEffect;
1207         }
1208       m_pOwner->HideDropIndicator ();   // Hide Drop Caret
1209
1210       return DROPEFFECT_NONE;   // Return DE_NONE
1211
1212     }
1213   //  if ((pDataObject->IsDataAvailable( CF_TEXT ) ) ||       // If Text Available
1214   //          ( pDataObject -> IsDataAvailable( xxx ) ) ||    // Or xxx Available
1215   //          ( pDataObject -> IsDataAvailable( yyy ) ) )     // Or yyy Available
1216   CLIPFORMAT fmt = CCrystalTextView::GetClipTcharTextFormat();      // CF_TEXT or CF_UNICODETEXT
1217   if (pDataObject->IsDataAvailable (fmt))   // If Text Available
1218
1219     {
1220       bDataSupported = true;    // Set Flag
1221
1222     }
1223   if (!bDataSupported)          // If No Supported Formats Available
1224
1225     {
1226       if (m_pAlternateDropTarget != nullptr)
1227         {
1228           DROPEFFECT dwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK;
1229           m_pAlternateDropTarget->DragOver(dwKeyState, { point.x, point.y }, &dwEffect);
1230           return dwEffect;
1231         }
1232       m_pOwner->HideDropIndicator ();   // Hide Drop Caret
1233
1234       return DROPEFFECT_NONE;   // Return DE_NONE
1235
1236     }
1237   m_pOwner->ShowDropIndicator (point);
1238   if (dwKeyState & MK_CONTROL)
1239     return DROPEFFECT_COPY;
1240   return DROPEFFECT_MOVE;
1241 }
1242
1243 BOOL CEditDropTargetImpl::
1244 OnDrop (CWnd * pWnd, COleDataObject * pDataObject, DROPEFFECT dropEffect, CPoint point)
1245 {
1246   //
1247   // [JRT]            ( m_pOwner -> GetDisableDragAndDrop() ) )       // Or Drag And Drop Disabled
1248   //
1249   bool bDataSupported = false;
1250
1251   m_pOwner->HideDropIndicator ();   // Hide Drop Caret
1252
1253   if ((m_pOwner == nullptr) ||            // If No Owner
1254         (!(m_pOwner->QueryEditable ())) ||   // Or Not Editable
1255         (m_pOwner->GetDisableDragAndDrop ()))    // Or Drag And Drop Disabled
1256
1257     {
1258       if (m_pAlternateDropTarget != nullptr)
1259         {
1260           DROPEFFECT dwEffect = DROPEFFECT_NONE;
1261           m_pAlternateDropTarget->Drop(pDataObject->m_lpDataObject, 0, { point.x, point.y }, &dwEffect);
1262           return dwEffect;
1263         }
1264       return DROPEFFECT_NONE;   // Return DE_NONE
1265
1266     }
1267   //  if( ( pDataObject -> IsDataAvailable( CF_TEXT ) ) ||    // If Text Available
1268   //          ( pDataObject -> IsDataAvailable( xxx ) ) ||    // Or xxx Available
1269   //          ( pDataObject -> IsDataAvailable( yyy ) ) )     // Or yyy Available
1270   CLIPFORMAT fmt = CCrystalTextView::GetClipTcharTextFormat();      // CF_TEXT or CF_UNICODETEXT
1271   if (pDataObject->IsDataAvailable (fmt))   // If Text Available
1272
1273     {
1274       bDataSupported = true;    // Set Flag
1275
1276     }
1277   if (!bDataSupported)          // If No Supported Formats Available
1278
1279     {
1280       if (m_pAlternateDropTarget != nullptr)
1281         {
1282           DROPEFFECT dwEffect = DROPEFFECT_NONE;
1283           m_pAlternateDropTarget->Drop(pDataObject->m_lpDataObject, 0, { point.x, point.y }, &dwEffect);
1284           return dwEffect;
1285         }
1286       return DROPEFFECT_NONE;   // Return DE_NONE
1287
1288     }
1289   return (m_pOwner->DoDropText (pDataObject, point));   // Return Result Of Drop
1290
1291 }
1292
1293 DROPEFFECT CEditDropTargetImpl::
1294 OnDragScroll (CWnd * pWnd, DWORD dwKeyState, CPoint point)
1295 {
1296   ASSERT (m_pOwner == pWnd);
1297   m_pOwner->DoDragScroll (point);
1298
1299   if (dwKeyState & MK_CONTROL)
1300     return DROPEFFECT_COPY;
1301   return DROPEFFECT_MOVE;
1302 }
1303
1304 void CCrystalEditView::
1305 DoDragScroll (const CPoint & point)
1306 {
1307   CRect rcClientRect;
1308   GetClientRect (rcClientRect);
1309   if (point.y < rcClientRect.top + DRAG_BORDER_Y)
1310     {
1311       HideDropIndicator ();
1312       ScrollUp ();
1313       UpdateWindow ();
1314       ShowDropIndicator (point);
1315       //UpdateSiblingScrollPos(false);
1316       return;
1317     }
1318   if (point.y >= rcClientRect.bottom - DRAG_BORDER_Y)
1319     {
1320       HideDropIndicator ();
1321       ScrollDown ();
1322       UpdateWindow ();
1323       ShowDropIndicator (point);
1324       //UpdateSiblingScrollPos(false);
1325       return;
1326     }
1327   if (point.x < rcClientRect.left + GetMarginWidth () + DRAG_BORDER_X)
1328     {
1329       HideDropIndicator ();
1330       ScrollLeft ();
1331       UpdateWindow ();
1332       ShowDropIndicator (point);
1333       //UpdateSiblingScrollPos(true);
1334       return;
1335     }
1336   if (point.x >= rcClientRect.right - DRAG_BORDER_X)
1337     {
1338       HideDropIndicator ();
1339       ScrollRight ();
1340       UpdateWindow ();
1341       ShowDropIndicator (point);
1342       //UpdateSiblingScrollPos(true);
1343       return;
1344     }
1345 }
1346
1347 void CCrystalEditView::
1348 SetAlternateDropTarget (IDropTarget *pDropTarget)
1349 {
1350   ASSERT(m_pDropTarget->m_pAlternateDropTarget == nullptr);
1351   m_pDropTarget->m_pAlternateDropTarget = pDropTarget;
1352   m_pDropTarget->m_pAlternateDropTarget->AddRef();
1353 }
1354
1355 bool CCrystalEditView::
1356 DoDropText (COleDataObject * pDataObject, const CPoint & ptClient)
1357 {
1358   CLIPFORMAT fmt = GetClipTcharTextFormat();      // CF_TEXT or CF_UNICODETEXT
1359   HGLOBAL hData = pDataObject->GetGlobalData (fmt);
1360   if (hData == nullptr)
1361     return false;
1362
1363   CPoint ptDropPos = ClientToText (ptClient);
1364   if (IsDraggingText () && IsInsideSelection (ptDropPos))
1365     {
1366       SetAnchor (ptDropPos);
1367       SetSelection (ptDropPos, ptDropPos);
1368       SetCursorPos (ptDropPos);
1369       EnsureVisible (ptDropPos);
1370       return false;
1371     }
1372
1373   UINT cbData = (UINT) ::GlobalSize (hData);
1374   UINT cchText = cbData / sizeof(TCHAR) - 1;
1375   LPTSTR pszText = (LPTSTR)::GlobalLock (hData);
1376   if (pszText == nullptr)
1377     return false;
1378
1379   // Open the undo group
1380   // When we drag from the same panel, it is already open, so do nothing
1381   // (we could test m_pTextBuffer->m_bUndoGroup if it were not a protected member)
1382   bool bGroupFlag = false;
1383   if (! IsDraggingText())
1384     {
1385       m_pTextBuffer->BeginUndoGroup ();
1386       bGroupFlag = true;
1387     } 
1388
1389   int x, y;
1390   m_pTextBuffer->InsertText (this, ptDropPos.y, ptDropPos.x, pszText, cchText, y, x, CE_ACTION_DRAGDROP);  //   [JRT]
1391
1392   CPoint ptCurPos (x, y);
1393   ASSERT_VALIDTEXTPOS (ptCurPos);
1394   SetAnchor (ptDropPos);
1395   SetSelection (ptDropPos, ptCurPos);
1396   SetCursorPos (ptCurPos);
1397   EnsureVisible (ptCurPos);
1398
1399   if (bGroupFlag)
1400     m_pTextBuffer->FlushUndoGroup (this);
1401
1402   ::GlobalUnlock (hData);
1403   return true;
1404 }
1405
1406 int CCrystalEditView::
1407 OnCreate (LPCREATESTRUCT lpCreateStruct)
1408 {
1409   if (CCrystalTextView::OnCreate (lpCreateStruct) == -1)
1410     return -1;
1411
1412   ASSERT (m_pDropTarget == nullptr);
1413   m_pDropTarget = new CEditDropTargetImpl (this);
1414   if (!m_pDropTarget->Register (this))
1415     {
1416       TRACE0 ("Warning: Unable to register drop target for ccrystaleditview.\n");
1417       delete m_pDropTarget;
1418       m_pDropTarget = nullptr;
1419     }
1420
1421   return 0;
1422 }
1423
1424 void CCrystalEditView::
1425 OnDestroy ()
1426 {
1427   if (m_pDropTarget != nullptr)
1428     {
1429       m_pDropTarget->Revoke ();
1430       if (m_pDropTarget->m_pAlternateDropTarget)
1431         m_pDropTarget->m_pAlternateDropTarget->Release();
1432       delete m_pDropTarget;
1433       m_pDropTarget = nullptr;
1434     }
1435
1436   CCrystalTextView::OnDestroy ();
1437 }
1438
1439 void CCrystalEditView::
1440 ShowDropIndicator (const CPoint & point)
1441 {
1442   if (!m_bDropPosVisible)
1443     {
1444       HideCursor ();
1445       m_ptSavedCaretPos = GetCursorPos ();
1446       m_bDropPosVisible = true;
1447       ::CreateCaret (m_hWnd, (HBITMAP) 1, 2, GetLineHeight ());
1448     }
1449   m_ptDropPos = ClientToText (point);
1450   // NB: m_ptDropPos.x is index into char array, which is uncomparable to m_nOffsetChar.
1451   CPoint ptCaretPos = TextToClient (m_ptDropPos);
1452   if (ptCaretPos.x >= GetMarginWidth())
1453     {
1454       SetCaretPos (ptCaretPos);
1455       ShowCaret ();
1456     }
1457   else
1458     {
1459       HideCaret ();
1460     }
1461 }
1462
1463 void CCrystalEditView::
1464 HideDropIndicator ()
1465 {
1466   if (m_bDropPosVisible)
1467     {
1468       SetCursorPos (m_ptSavedCaretPos);
1469       ShowCursor ();
1470       m_bDropPosVisible = false;
1471     }
1472 }
1473
1474 DROPEFFECT CCrystalEditView::
1475 GetDropEffect ()
1476 {
1477   return DROPEFFECT_COPY | DROPEFFECT_MOVE;
1478 }
1479
1480 void CCrystalEditView::
1481 OnDropSource (DROPEFFECT de)
1482 {
1483   if (!IsDraggingText ())
1484     return;
1485
1486   ASSERT_VALIDTEXTPOS (m_ptDraggedTextBegin);
1487   ASSERT_VALIDTEXTPOS (m_ptDraggedTextEnd);
1488
1489   if (de == DROPEFFECT_MOVE)
1490     {
1491       m_pTextBuffer->DeleteText (this, m_ptDraggedTextBegin.y, m_ptDraggedTextBegin.x, m_ptDraggedTextEnd.y,
1492                                  m_ptDraggedTextEnd.x, CE_ACTION_DRAGDROP);     // [JRT]
1493
1494     }
1495 }
1496
1497 void CCrystalEditView::
1498 UpdateView (CCrystalTextView * pSource, CUpdateContext * pContext, DWORD dwFlags, int nLineIndex /*= -1*/ )
1499 {
1500   CCrystalTextView::UpdateView (pSource, pContext, dwFlags, nLineIndex);
1501
1502   if (m_bSelectionPushed && pContext != nullptr)
1503     {
1504       pContext->RecalcPoint (m_ptSavedSelStart);
1505       pContext->RecalcPoint (m_ptSavedSelEnd);
1506       ASSERT_VALIDTEXTPOS (m_ptSavedSelStart);
1507       ASSERT_VALIDTEXTPOS (m_ptSavedSelEnd);
1508     }
1509   if (m_bDropPosVisible )
1510     {
1511       pContext->RecalcPoint (m_ptSavedCaretPos);
1512       ASSERT_VALIDTEXTPOS (m_ptSavedCaretPos);
1513     }
1514 }
1515
1516 void CCrystalEditView::
1517 OnEditReplace ()
1518 {
1519   if (!QueryEditable ())
1520     return;
1521
1522   CWinApp *pApp = AfxGetApp ();
1523   ASSERT (pApp != nullptr);
1524
1525   delete m_pEditReplaceDlg;
1526   m_pEditReplaceDlg = new CEditReplaceDlg(this);
1527   LastSearchInfos * lastSearch = m_pEditReplaceDlg->GetLastSearchInfos();
1528
1529   if (m_bLastReplace)
1530     {
1531       //  Get the latest Replace parameters
1532       lastSearch->m_bMatchCase = (m_dwLastReplaceFlags & FIND_MATCH_CASE) != 0;
1533       lastSearch->m_bWholeWord = (m_dwLastReplaceFlags & FIND_WHOLE_WORD) != 0;
1534       lastSearch->m_bRegExp = (m_dwLastReplaceFlags & FIND_REGEXP) != 0;
1535       lastSearch->m_bNoWrap = (m_dwLastReplaceFlags & FIND_NO_WRAP) != 0;
1536       if (m_pszLastFindWhat != nullptr)
1537         lastSearch->m_sText = m_pszLastFindWhat;
1538     }
1539   else
1540     {
1541       DWORD dwFlags = pApp->GetProfileInt (EDITPAD_SECTION, _T("ReplaceFlags"), 0);
1542       lastSearch->m_bMatchCase = (dwFlags & FIND_MATCH_CASE) != 0;
1543       lastSearch->m_bWholeWord = (dwFlags & FIND_WHOLE_WORD) != 0;
1544       lastSearch->m_bRegExp = (dwFlags & FIND_REGEXP) != 0;
1545       lastSearch->m_bNoWrap = (dwFlags & FIND_NO_WRAP) != 0;
1546     }
1547   lastSearch->m_nDirection = 1;
1548   m_pEditReplaceDlg->UseLastSearch ();
1549
1550
1551   if (IsSelection ())
1552     {
1553       GetSelection (m_ptSavedSelStart, m_ptSavedSelEnd);
1554       m_bSelectionPushed = true;
1555
1556       m_pEditReplaceDlg->SetScope(true);       //  Replace in current selection
1557       m_pEditReplaceDlg->m_ptCurrentPos = m_ptSavedSelStart;
1558       m_pEditReplaceDlg->m_bEnableScopeSelection = true;
1559       m_pEditReplaceDlg->m_ptBlockBegin = m_ptSavedSelStart;
1560       m_pEditReplaceDlg->m_ptBlockEnd = m_ptSavedSelEnd;
1561
1562       // If the selection is in one line, copy text to dialog
1563       if (m_ptSavedSelStart.y == m_ptSavedSelEnd.y)
1564         GetText(m_ptSavedSelStart, m_ptSavedSelEnd, m_pEditReplaceDlg->m_sText);
1565     }
1566   else
1567     {
1568       m_pEditReplaceDlg->SetScope(false);      // Set scope when no selection
1569       m_pEditReplaceDlg->m_ptCurrentPos = GetCursorPos ();
1570       m_pEditReplaceDlg->m_bEnableScopeSelection = false;
1571
1572       CPoint ptCursorPos = GetCursorPos ();
1573       CPoint ptStart = WordToLeft (ptCursorPos);
1574       CPoint ptEnd = WordToRight (ptCursorPos);
1575       if (IsValidTextPos (ptStart) && IsValidTextPos (ptEnd) && ptStart != ptEnd)
1576         GetText (ptStart, ptEnd, m_pEditReplaceDlg->m_sText);
1577     }
1578
1579   //  Execute Replace dialog
1580   m_pEditReplaceDlg->Create(CEditReplaceDlg::IDD, this);
1581   m_pEditReplaceDlg->ShowWindow(SW_SHOW);
1582 }
1583
1584 void CCrystalEditView::
1585 SaveLastSearch(LastSearchInfos *lastSearch)
1586 {
1587   //  Save Replace parameters for 'F3' command
1588   m_bLastReplace = true;
1589   if (m_pszLastFindWhat != nullptr)
1590     free (m_pszLastFindWhat);
1591   m_pszLastFindWhat = _tcsdup (lastSearch->m_sText);
1592   m_dwLastReplaceFlags = 0;
1593   if (lastSearch->m_bMatchCase)
1594     m_dwLastReplaceFlags |= FIND_MATCH_CASE;
1595   if (lastSearch->m_bWholeWord)
1596     m_dwLastReplaceFlags |= FIND_WHOLE_WORD;
1597   if (lastSearch->m_bRegExp)
1598     m_dwLastReplaceFlags |= FIND_REGEXP;
1599   if (lastSearch->m_bNoWrap)
1600     m_dwLastReplaceFlags |= FIND_NO_WRAP;
1601
1602   //  Restore selection
1603   if (m_bSelectionPushed)
1604     {
1605       SetSelection (m_ptSavedSelStart, m_ptSavedSelEnd);
1606       m_bSelectionPushed = false;
1607     }
1608
1609   //  Save search parameters to registry
1610   VERIFY (AfxGetApp()->WriteProfileInt (EDITPAD_SECTION, _T ("ReplaceFlags"), m_dwLastReplaceFlags));
1611 }
1612
1613 /**
1614  * @brief Replace selected text.
1615  * This function replaces selected text in the editor pane with given text.
1616  * @param [in] pszNewText The text replacing selected text.
1617  * @param [in] cchNewText Length of the replacing text.
1618  * @param [in] dwFlags Additional modifier flags:
1619  * - FIND_REGEXP: use the regular expression.
1620  * @return true if succeeded.
1621  */
1622 bool CCrystalEditView::
1623 ReplaceSelection (LPCTSTR pszNewText, size_t cchNewText, DWORD dwFlags, bool bGroupWithPrevious)
1624 {
1625   if (!cchNewText)
1626     return DeleteCurrentSelection();
1627   ASSERT (pszNewText != nullptr);
1628
1629   m_pTextBuffer->BeginUndoGroup(bGroupWithPrevious);
1630
1631   CPoint ptCursorPos;
1632   if (IsSelection ())
1633     {
1634       auto [ptSelStart, ptSelEnd] = GetSelection ();
1635
1636       ptCursorPos = ptSelStart;
1637
1638       m_pTextBuffer->DeleteText (this, ptSelStart.y, ptSelStart.x, ptSelEnd.y, ptSelEnd.x, CE_ACTION_REPLACE);
1639     }
1640   else
1641     ptCursorPos = GetCursorPos ();
1642   ASSERT_VALIDTEXTPOS (ptCursorPos);
1643
1644   int x = 0;
1645   int y = 0;
1646   if (dwFlags & FIND_REGEXP)
1647     {
1648       LPTSTR lpszNewStr = nullptr;
1649       if (m_pszMatched && !RxReplace(pszNewText, m_pszMatched, m_nLastFindWhatLen, m_rxmatch, &lpszNewStr, &m_nLastReplaceLen))
1650         {
1651           CString text;
1652           if (lpszNewStr != nullptr && m_nLastReplaceLen > 0)
1653             {
1654               LPTSTR buf = text.GetBuffer (m_nLastReplaceLen + 1);
1655               _tcsncpy_s (buf, m_nLastReplaceLen+1, lpszNewStr, m_nLastReplaceLen);
1656               text.ReleaseBuffer (m_nLastReplaceLen);
1657             }
1658           else
1659             text.Empty ();
1660           m_pTextBuffer->InsertText (this, ptCursorPos.y, ptCursorPos.x, text, text.GetLength(), y, x, CE_ACTION_REPLACE);  //  [JRT+FRD]
1661           if (lpszNewStr != nullptr)
1662             free(lpszNewStr);
1663         }
1664     }
1665   else
1666     {
1667       m_pTextBuffer->InsertText (this, ptCursorPos.y, ptCursorPos.x, pszNewText, cchNewText, y, x, CE_ACTION_REPLACE);  //  [JRT]
1668       ASSERT(cchNewText < INT_MAX);
1669       m_nLastReplaceLen = static_cast<int>(cchNewText);
1670     }
1671
1672   CPoint ptEndOfBlock = CPoint (x, y);
1673   if (ptEndOfBlock.x == m_pTextBuffer->GetLineLength (ptEndOfBlock.y))
1674     {
1675       if (ptEndOfBlock.y < m_pTextBuffer->GetLineCount() - 1)
1676         {
1677           ptEndOfBlock.x = 0;
1678           ptEndOfBlock.y++;
1679         }
1680     }
1681   ASSERT_VALIDTEXTPOS (ptCursorPos);
1682   ASSERT_VALIDTEXTPOS (ptEndOfBlock);
1683   SetAnchor (ptEndOfBlock);
1684   SetSelection (ptCursorPos, ptEndOfBlock);
1685   SetCursorPos (ptEndOfBlock);
1686
1687   m_pTextBuffer->FlushUndoGroup(this);
1688
1689   return true;
1690 }
1691
1692 void CCrystalEditView::
1693 OnUpdateEditUndo (CCmdUI * pCmdUI)
1694 {
1695   bool bCanUndo = m_pTextBuffer != nullptr && m_pTextBuffer->CanUndo ();
1696   pCmdUI->Enable (bCanUndo);
1697
1698   //  Since we need text only for menus...
1699   if (pCmdUI->m_pMenu != nullptr)
1700     {
1701       //  Tune up 'resource handle'
1702       HINSTANCE hOldResHandle = AfxGetResourceHandle ();
1703       AfxSetResourceHandle (GetResourceHandle ());
1704
1705       CString menu;
1706       if (bCanUndo)
1707         {
1708           //  Format menu item text using the provided item description
1709           CString desc;
1710           m_pTextBuffer->GetUndoDescription (desc);
1711           menu.Format (IDS_MENU_UNDO_FORMAT, (LPCTSTR)desc);
1712         }
1713       else
1714         {
1715           //  Just load default menu item text
1716           menu.LoadString (IDS_MENU_UNDO_DEFAULT);
1717         }
1718
1719       //  Restore original handle
1720       AfxSetResourceHandle (hOldResHandle);
1721
1722       //  Set menu item text
1723       pCmdUI->SetText (menu);
1724     }
1725 }
1726
1727 void CCrystalEditView::
1728 OnEditUndo ()
1729 {
1730   DoEditUndo();
1731 }
1732
1733 bool CCrystalEditView::
1734 DoEditUndo ()
1735 {
1736   if (m_pTextBuffer != nullptr && m_pTextBuffer->CanUndo ())
1737     {
1738       CPoint ptCursorPos;
1739       if (m_pTextBuffer->Undo (this, ptCursorPos))
1740         {
1741           ASSERT_VALIDTEXTPOS (ptCursorPos);
1742           SetAnchor (ptCursorPos);
1743           SetSelection (ptCursorPos, ptCursorPos);
1744           SetCursorPos (ptCursorPos);
1745           EnsureVisible (ptCursorPos);
1746           return true;
1747         }
1748     }
1749   return false;
1750 }
1751
1752 //  [JRT]
1753 void CCrystalEditView::
1754 SetDisableBSAtSOL (bool bDisableBSAtSOL)
1755 {
1756   m_bDisableBSAtSOL = bDisableBSAtSOL;
1757 }
1758
1759 void CCrystalEditView::
1760 CopyProperties (CCrystalTextView* pSource)
1761 {
1762   CCrystalTextView::CopyProperties(pSource);
1763   auto pSourceEditView = dynamic_cast<decltype(this)>(pSource);
1764   if (!pSourceEditView)
1765       return;
1766   m_bDisableBSAtSOL = pSourceEditView->m_bDisableBSAtSOL;
1767   m_bOvrMode = pSourceEditView->m_bOvrMode;
1768   m_bAutoIndent = pSourceEditView->m_bAutoIndent;
1769 }
1770
1771 void CCrystalEditView::
1772 OnEditRedo ()
1773 {
1774   DoEditRedo();
1775 }
1776
1777 bool CCrystalEditView::
1778 DoEditRedo ()
1779 {
1780   if (m_pTextBuffer != nullptr && m_pTextBuffer->CanRedo ())
1781     {
1782       CPoint ptCursorPos;
1783       if (m_pTextBuffer->Redo (this, ptCursorPos))
1784         {
1785           ASSERT_VALIDTEXTPOS (ptCursorPos);
1786           SetAnchor (ptCursorPos);
1787           SetSelection (ptCursorPos, ptCursorPos);
1788           SetCursorPos (ptCursorPos);
1789           EnsureVisible (ptCursorPos);
1790           return true;
1791         }
1792     }
1793   return false;
1794 }
1795
1796 void CCrystalEditView::
1797 OnUpdateEditRedo (CCmdUI * pCmdUI)
1798 {
1799   bool bCanRedo = m_pTextBuffer != nullptr && m_pTextBuffer->CanRedo ();
1800   pCmdUI->Enable (bCanRedo);
1801
1802   //  Since we need text only for menus...
1803   if (pCmdUI->m_pMenu != nullptr)
1804     {
1805       //  Tune up 'resource handle'
1806       HINSTANCE hOldResHandle = AfxGetResourceHandle ();
1807       AfxSetResourceHandle (GetResourceHandle ());
1808
1809       CString menu;
1810       if (bCanRedo)
1811         {
1812           //  Format menu item text using the provided item description
1813           CString desc;
1814           m_pTextBuffer->GetRedoDescription (desc);
1815           menu.Format (IDS_MENU_REDO_FORMAT, (LPCTSTR)desc);
1816         }
1817       else
1818         {
1819           //  Just load default menu item text
1820           menu.LoadString (IDS_MENU_REDO_DEFAULT);
1821         }
1822
1823       //  Restore original handle
1824       AfxSetResourceHandle (hOldResHandle);
1825
1826       //  Set menu item text
1827       pCmdUI->SetText (menu);
1828     }
1829 }
1830
1831 bool
1832 isopenbrace (TCHAR c)
1833 {
1834   return c == _T ('{') || c == _T ('(') || c == _T ('[') || c == _T ('<');
1835 }
1836
1837 bool
1838 isclosebrace (TCHAR c)
1839 {
1840   return c == _T ('}') || c == _T (')') || c == _T (']') || c == _T ('>');
1841 }
1842
1843 bool
1844 isopenbrace (LPCTSTR s)
1845 {
1846   return s[1] == _T ('\0') && isopenbrace (*s);
1847 }
1848
1849 bool
1850 isclosebrace (LPCTSTR s)
1851 {
1852   return s[1] == _T ('\0') && isclosebrace (*s);
1853 }
1854
1855 int bracetype (TCHAR c);
1856 int bracetype (LPCTSTR s);
1857
1858 void CCrystalEditView::
1859 OnEditOperation (int nAction, LPCTSTR pszText, size_t cchText)
1860 {
1861   if (m_bAutoIndent)
1862     {
1863       //  Analyse last action...
1864       if (nAction == CE_ACTION_TYPING && (
1865           _tcsncmp (pszText, _T ("\r\n"), cchText) == 0 ||
1866           (cchText == 1 && (*pszText == '\r' || *pszText == '\n')))
1867           && !m_bOvrMode && !m_pTextBuffer->GetTableEditing())
1868         {
1869           //  Enter stroke!
1870           CPoint ptCursorPos = GetCursorPos ();
1871           ASSERT (ptCursorPos.y > 0);
1872
1873           //  Take indentation from the previous line
1874           int nLength = m_pTextBuffer->GetLineLength (ptCursorPos.y - 1);
1875           LPCTSTR pszLineChars = m_pTextBuffer->GetLineChars (ptCursorPos.y - 1);
1876           int nPos = 0;
1877           while (nPos < nLength && xisspace (pszLineChars[nPos]))
1878             nPos++;
1879
1880           if (nPos > 0)
1881             {
1882               if ((GetFlags () & SRCOPT_BRACEGNU) && isclosebrace (pszLineChars[nLength - 1]) && ptCursorPos.y > 0 && nPos && nPos == nLength - 1)
1883                 {
1884                   if (pszLineChars[nPos - 1] == _T ('\t'))
1885                     {
1886                       nPos--;
1887                     }
1888                   else
1889                     {
1890                       int nTabSize = GetTabSize (),
1891                         nDelta = nTabSize - nPos % nTabSize;
1892                       if (!nDelta)
1893                         {
1894                           nDelta = nTabSize;
1895                         }
1896                       nPos -= nDelta;
1897                       if (nPos < 0)
1898                         {
1899                           nPos = 0;
1900                         }
1901                     }
1902                 }
1903               //  Insert part of the previous line
1904               TCHAR *pszInsertStr;
1905               if ((GetFlags () & (SRCOPT_BRACEGNU|SRCOPT_BRACEANSI)) && isopenbrace (pszLineChars[nLength - 1]))
1906                 {
1907                   if (m_pTextBuffer->GetInsertTabs())
1908                     {
1909                       const size_t InsertSiz = (nPos + 2);
1910                       pszInsertStr = static_cast<TCHAR *> (_alloca (sizeof(TCHAR) * InsertSiz));
1911                       _tcsncpy_s (pszInsertStr, InsertSiz, pszLineChars, nPos);
1912                       pszInsertStr[nPos++] = _T ('\t');
1913                     }
1914                   else
1915                     {
1916                       int nTabSize = GetTabSize ();
1917                       int nChars = nTabSize - nPos % nTabSize;
1918                       const size_t InsertSiz = (nPos + nChars + 1);
1919                       pszInsertStr = static_cast<TCHAR *> (_alloca (sizeof (TCHAR) * InsertSiz));
1920                       _tcsncpy_s (pszInsertStr, InsertSiz, pszLineChars, nPos);
1921                       while (nChars--)
1922                         {
1923                           pszInsertStr[nPos++] = _T (' ');
1924                         }
1925                     }
1926                 }
1927               else
1928                 {
1929                   const size_t InsertSiz = (nPos + 1);
1930                   pszInsertStr = static_cast<TCHAR *> (_alloca (sizeof (TCHAR) * InsertSiz));
1931                   _tcsncpy_s (pszInsertStr, InsertSiz, pszLineChars, nPos);
1932                 }
1933               pszInsertStr[nPos] = 0;
1934
1935               // m_pTextBuffer->BeginUndoGroup ();
1936               int x, y;
1937               m_pTextBuffer->InsertText (nullptr, ptCursorPos.y, ptCursorPos.x,
1938                                          pszInsertStr, nPos, y, x, CE_ACTION_AUTOINDENT);
1939               CPoint pt (x, y);
1940               SetSelection (pt, pt);
1941               SetAnchor (pt);
1942               SetCursorPos (pt);
1943               EnsureVisible (pt);
1944               // m_pTextBuffer->FlushUndoGroup (this);
1945             }
1946           else
1947             {
1948               //  Insert part of the previous line
1949               if ((GetFlags () & (SRCOPT_BRACEGNU|SRCOPT_BRACEANSI)) && isopenbrace (pszLineChars[nLength - 1]))
1950                 {
1951                   TCHAR *pszInsertStr;
1952                   if (m_pTextBuffer->GetInsertTabs())
1953                     {
1954                       pszInsertStr = (TCHAR *) _alloca (sizeof (TCHAR) * 2);
1955                       pszInsertStr[nPos++] = _T ('\t');
1956                     }
1957                   else
1958                     {
1959                       int nTabSize = GetTabSize ();
1960                       int nChars = nTabSize - nPos % nTabSize;
1961                       pszInsertStr = (TCHAR *) _alloca (sizeof (TCHAR) * (nChars + 1));
1962                       while (nChars--)
1963                         {
1964                           pszInsertStr[nPos++] = _T (' ');
1965                         }
1966                     }
1967                   pszInsertStr[nPos] = 0;
1968
1969                   // m_pTextBuffer->BeginUndoGroup ();
1970                   int x, y;
1971                   m_pTextBuffer->InsertText (nullptr, ptCursorPos.y, ptCursorPos.x,
1972                                              pszInsertStr, nPos, y, x, CE_ACTION_AUTOINDENT);
1973                   CPoint pt (x, y);
1974                   SetSelection (pt, pt);
1975                   SetAnchor (pt);
1976                   SetCursorPos (pt);
1977                   EnsureVisible (pt);
1978                   // m_pTextBuffer->FlushUndoGroup (this);
1979                 }
1980             }
1981         }
1982       else if (nAction == CE_ACTION_TYPING && (GetFlags () & SRCOPT_FNBRACE) && bracetype (pszText) == 3)
1983         {
1984           //  Enter stroke!
1985           CPoint ptCursorPos = GetCursorPos ();
1986           LPCTSTR pszChars = m_pTextBuffer->GetLineChars (ptCursorPos.y);
1987           if (ptCursorPos.x > 1 && xisalnum (pszChars[ptCursorPos.x - 2]))
1988             {
1989               LPTSTR pszInsertStr = (TCHAR *) _alloca (sizeof (TCHAR) * 2);
1990               *pszInsertStr = _T (' ');
1991               pszInsertStr[1] = _T ('\0');
1992               // m_pTextBuffer->BeginUndoGroup ();
1993               int x, y;
1994               m_pTextBuffer->InsertText (nullptr, ptCursorPos.y, ptCursorPos.x - 1,
1995                                          pszInsertStr, 1, y, x, CE_ACTION_AUTOINDENT);
1996               ptCursorPos.x = x + 1;
1997               ptCursorPos.y = y;
1998               SetSelection (ptCursorPos, ptCursorPos);
1999               SetAnchor (ptCursorPos);
2000               SetCursorPos (ptCursorPos);
2001               EnsureVisible (ptCursorPos);
2002               // m_pTextBuffer->FlushUndoGroup (this);
2003             }
2004         }
2005       else if (nAction == CE_ACTION_TYPING && (GetFlags () & SRCOPT_BRACEGNU) && isopenbrace (pszText))
2006         {
2007           //  Enter stroke!
2008           CPoint ptCursorPos = GetCursorPos ();
2009
2010           //  Take indentation from the previous line
2011           int nLength = m_pTextBuffer->GetLineLength (ptCursorPos.y);
2012           LPCTSTR pszLineChars = m_pTextBuffer->GetLineChars (ptCursorPos.y );
2013           int nPos = 0;
2014           while (nPos < nLength && xisspace (pszLineChars[nPos]))
2015             nPos++;
2016           if (nPos == nLength - 1)
2017             {
2018               TCHAR *pszInsertStr;
2019               if (m_pTextBuffer->GetInsertTabs())
2020                 {
2021                   pszInsertStr = (TCHAR *) _alloca (sizeof (TCHAR) * 2);
2022                   *pszInsertStr = _T ('\t');
2023                   nPos = 1;
2024                 }
2025               else
2026                 {
2027                   int nTabSize = GetTabSize ();
2028                   int nChars = nTabSize - nPos % nTabSize;
2029                   pszInsertStr = (TCHAR *) _alloca (sizeof (TCHAR) * (nChars + 1));
2030                   nPos = 0;
2031                   while (nChars--)
2032                     {
2033                       pszInsertStr[nPos++] = _T (' ');
2034                     }
2035                 }
2036               pszInsertStr[nPos] = 0;
2037
2038               // m_pTextBuffer->BeginUndoGroup ();
2039               int x, y;
2040               m_pTextBuffer->InsertText (nullptr, ptCursorPos.y, ptCursorPos.x - 1,
2041                                          pszInsertStr, nPos, y, x, CE_ACTION_AUTOINDENT);
2042               CPoint pt (x + 1, y);
2043               SetSelection (pt, pt);
2044               SetAnchor (pt);
2045               SetCursorPos (pt);
2046               EnsureVisible (pt);
2047               // m_pTextBuffer->FlushUndoGroup (this);
2048             }
2049         }
2050       else if (nAction == CE_ACTION_TYPING && (GetFlags () & (SRCOPT_BRACEGNU|SRCOPT_BRACEANSI)) && isclosebrace (pszText))
2051         {
2052           //  Enter stroke!
2053           CPoint ptCursorPos = GetCursorPos ();
2054
2055           //  Take indentation from the previous line
2056           int nLength = m_pTextBuffer->GetLineLength (ptCursorPos.y);
2057           LPCTSTR pszLineChars = m_pTextBuffer->GetLineChars (ptCursorPos.y );
2058           int nPos = 0;
2059           while (nPos < nLength && xisspace (pszLineChars[nPos]))
2060             nPos++;
2061           if (ptCursorPos.y > 0 && nPos && nPos == nLength - 1)
2062             {
2063               if (pszLineChars[nPos - 1] == _T ('\t'))
2064                 {
2065                   nPos = 1;
2066                 }
2067               else
2068                 {
2069                   int nTabSize = GetTabSize ();
2070                   nPos = nTabSize - (ptCursorPos.x - 1) % nTabSize;
2071                   if (!nPos)
2072                     {
2073                       nPos = nTabSize;
2074                     }
2075                   if (nPos > nLength - 1)
2076                     {
2077                       nPos = nLength - 1;
2078                     }
2079                 }
2080               // m_pTextBuffer->BeginUndoGroup ();
2081               m_pTextBuffer->DeleteText (nullptr, ptCursorPos.y, ptCursorPos.x - nPos - 1,
2082                 ptCursorPos.y, ptCursorPos.x - 1, CE_ACTION_AUTOINDENT);
2083               ptCursorPos.x -= nPos;
2084               SetCursorPos (ptCursorPos);
2085               SetSelection (ptCursorPos, ptCursorPos);
2086               SetAnchor (ptCursorPos);
2087               EnsureVisible (ptCursorPos);
2088               // m_pTextBuffer->FlushUndoGroup (this);
2089             }
2090         }
2091     }
2092 }
2093
2094 void CCrystalEditView::
2095 OnEditAutoComplete ()
2096 {
2097   CPoint ptCursorPos = GetCursorPos ();
2098   int nLength = m_pTextBuffer->GetLineLength (ptCursorPos.y);
2099   LPCTSTR pszText = m_pTextBuffer->GetLineChars (ptCursorPos.y), pszEnd = pszText + ptCursorPos.x;
2100   if (ptCursorPos.x > 0 && ptCursorPos.y > 0 && (nLength == ptCursorPos.x || !xisalnum (*pszEnd)) && xisalnum (pszEnd[-1]))
2101     {
2102       LPCTSTR pszBegin = pszEnd - 1;
2103       while (pszBegin > pszText && xisalnum (*pszBegin))
2104         pszBegin--;
2105       if (!xisalnum (*pszBegin))
2106         pszBegin++;
2107       nLength = static_cast<int>(pszEnd - pszBegin);
2108       CString sText;
2109       LPTSTR pszBuffer = sText.GetBuffer (nLength + 2);
2110       *pszBuffer = _T('<');
2111       _tcsncpy_s (pszBuffer + 1, nLength + 1, pszBegin, nLength);
2112       sText.ReleaseBuffer (nLength + 1);
2113       CPoint ptTextPos;
2114       ptCursorPos.x -= nLength;
2115       bool bFound = FindText (sText, ptCursorPos, FIND_MATCH_CASE|FIND_REGEXP|FIND_DIRECTION_UP, true, &ptTextPos);
2116       if (!bFound)
2117         {
2118           ptCursorPos.x += nLength;
2119           bFound = FindText (sText, ptCursorPos, FIND_MATCH_CASE|FIND_REGEXP, true, &ptTextPos);
2120           ptCursorPos.x -= nLength;
2121         }
2122       if (bFound)
2123         {
2124           const int nLineLength = m_pTextBuffer->GetLineLength (ptTextPos.y);
2125           int nFound = nLineLength;
2126           pszText = m_pTextBuffer->GetLineChars (ptTextPos.y) + ptTextPos.x + m_nLastFindWhatLen;
2127           nFound -= ptTextPos.x + m_nLastFindWhatLen;
2128           pszBuffer = sText.GetBuffer (nFound + 1);
2129           while (nFound-- && xisalnum (*pszText))
2130             *pszBuffer++ = *pszText++;
2131           sText.ReleaseBuffer (nLineLength - (ptTextPos.x + m_nLastFindWhatLen) - nFound - 1);
2132           if (!sText.IsEmpty ())
2133             {
2134               m_pTextBuffer->BeginUndoGroup ();
2135               int x, y;
2136               m_pTextBuffer->InsertText (this, ptCursorPos.y, ptCursorPos.x + nLength, sText, sText.GetLength(), y, x, CE_ACTION_AUTOCOMPLETE);
2137               ptCursorPos.x = x;
2138               ptCursorPos.y = y;
2139               SetCursorPos (ptCursorPos);
2140               SetSelection (ptCursorPos, ptCursorPos);
2141               SetAnchor (ptCursorPos);
2142               EnsureVisible (ptCursorPos);
2143               m_pTextBuffer->FlushUndoGroup (this);
2144             }
2145         }
2146     }
2147 }
2148
2149 void CCrystalEditView::
2150 OnUpdateEditAutoComplete (CCmdUI * pCmdUI)
2151 {
2152   CPoint ptCursorPos = GetCursorPos ();
2153   int nLength = m_pTextBuffer->GetLineLength (ptCursorPos.y);
2154   LPCTSTR pszText = m_pTextBuffer->GetLineChars (ptCursorPos.y) + ptCursorPos.x;
2155   pCmdUI->Enable (ptCursorPos.x > 0 && ptCursorPos.y > 0 && (nLength == ptCursorPos.x || !xisalnum (*pszText)) && xisalnum (pszText[-1]));
2156 }
2157
2158 void CCrystalEditView::
2159 OnEditAutoExpand ()
2160 {
2161   CPoint ptCursorPos = GetCursorPos ();
2162   int nLength = m_pTextBuffer->GetLineLength (ptCursorPos.y);
2163   LPCTSTR pszText = m_pTextBuffer->GetLineChars (ptCursorPos.y), pszEnd = pszText + ptCursorPos.x;
2164   if (ptCursorPos.x > 0 && ptCursorPos.y > 0 && (nLength == ptCursorPos.x || !xisalnum (*pszEnd)) && xisalnum (pszEnd[-1]))
2165     {
2166       LPCTSTR pszBegin = pszEnd - 1;
2167       while (pszBegin > pszText && xisalnum (*pszBegin))
2168         pszBegin--;
2169       if (!xisalnum (*pszBegin))
2170         pszBegin++;
2171       nLength = static_cast<int>(pszEnd - pszBegin);
2172       CString sText, sExpand;
2173       LPTSTR pszBuffer = sText.GetBuffer (nLength + 1);
2174       _tcsncpy_s (pszBuffer, nLength + 1, pszBegin, nLength);
2175       sText.ReleaseBuffer (nLength);
2176       CPoint ptTextPos;
2177       ptCursorPos.x -= nLength;
2178       bool bFound = !!m_mapExpand->Lookup (sText, sExpand);
2179       if (bFound && !sExpand.IsEmpty ())
2180         {
2181           m_pTextBuffer->BeginUndoGroup ();
2182           int x, y;
2183           m_pTextBuffer->DeleteText (this, ptCursorPos.y, ptCursorPos.x, ptCursorPos.y, ptCursorPos.x + nLength, CE_ACTION_AUTOEXPAND);
2184           LPTSTR pszExpand = sExpand.GetBuffer (sExpand.GetLength () + 1);
2185           LPTSTR pszSlash = _tcschr (pszExpand, _T ('\\'));
2186           if (pszSlash == nullptr)
2187             {
2188               m_pTextBuffer->InsertText (this, ptCursorPos.y, ptCursorPos.x, pszExpand, _tcslen(pszExpand), y, x, CE_ACTION_AUTOEXPAND);
2189               ptCursorPos.x = x;
2190               ptCursorPos.y = y;
2191               ASSERT_VALIDTEXTPOS (ptCursorPos);
2192               SetCursorPos (ptCursorPos);
2193               SetSelection (ptCursorPos, ptCursorPos);
2194               SetAnchor (ptCursorPos);
2195             }
2196           else
2197             {
2198               *pszSlash++ = _T ('\0');
2199               for(;;)
2200                 {
2201                   m_pTextBuffer->InsertText (this, ptCursorPos.y, ptCursorPos.x, pszExpand, _tcslen(pszExpand), y, x, CE_ACTION_AUTOEXPAND);
2202                   ptCursorPos.x = x;
2203                   ptCursorPos.y = y;
2204                   ASSERT_VALIDTEXTPOS (ptCursorPos);
2205                   SetSelection (ptCursorPos, ptCursorPos);
2206                   SetAnchor (ptCursorPos);
2207                   SetCursorPos (ptCursorPos);
2208                   OnEditOperation (CE_ACTION_TYPING, pszExpand, _tcslen(pszExpand));
2209                   ptCursorPos = GetCursorPos ();
2210                   if (pszSlash == nullptr)
2211                     break;
2212                   switch (*pszSlash)
2213                     {
2214                       case _T ('n'):
2215                         {
2216                           const static TCHAR szText[3] = _T ("\r\n");
2217                           m_pTextBuffer->InsertText (this, ptCursorPos.y, ptCursorPos.x, szText, _tcslen(szText), y, x, CE_ACTION_AUTOEXPAND);  //  [JRT]
2218                           ptCursorPos.x = x;
2219                           ptCursorPos.y = y;
2220                           ASSERT_VALIDTEXTPOS (ptCursorPos);
2221                           SetSelection (ptCursorPos, ptCursorPos);
2222                           SetAnchor (ptCursorPos);
2223                           SetCursorPos (ptCursorPos);
2224                           OnEditOperation (CE_ACTION_TYPING, szText, _tcslen(pszExpand));
2225                         }
2226                         break;
2227                       case _T ('u'):
2228                         MoveUp (false);
2229                         break;
2230                       case _T ('d'):
2231                         MoveDown (false);
2232                         break;
2233                       case _T ('l'):
2234                         MoveLeft (false);
2235                         break;
2236                       case _T ('r'):
2237                         MoveRight (false);
2238                         break;
2239                       case _T ('h'):
2240                         MoveHome (false);
2241                         break;
2242                       case _T ('f'):
2243                         MoveEnd (false);
2244                         break;
2245                       case _T ('b'):
2246                         {
2247                           CPoint ptSelStart = ptCursorPos;
2248                           bool bDeleted = false;
2249                           if (!(ptCursorPos.x))         // If At Start Of Line
2250
2251                             {
2252                               if (!m_bDisableBSAtSOL)   // If DBSASOL Is Disabled
2253
2254                                 {
2255                                   if (ptCursorPos.y > 0)    // If Previous Lines Available
2256
2257                                     {
2258                                       ptCursorPos.y--;  // Decrement To Previous Line
2259
2260                                       ptCursorPos.x = GetLineLength (
2261                                                         ptCursorPos.y);   // Set Cursor To End Of Previous Line
2262
2263                                       bDeleted = true;  // Set Deleted Flag
2264
2265                                     }
2266                                 }
2267                             }
2268                           else                          // If Caret Not At SOL
2269
2270                             {
2271                               ptCursorPos.x--;          // Decrement Position
2272
2273                               bDeleted = true;          // Set Deleted Flag
2274
2275                             }
2276                           ASSERT_VALIDTEXTPOS (ptCursorPos);
2277                           SetAnchor (ptCursorPos);
2278                           SetSelection (ptCursorPos, ptCursorPos);
2279                           SetCursorPos (ptCursorPos);
2280
2281                           if (bDeleted)
2282                               m_pTextBuffer->DeleteText (this, ptCursorPos.y, ptCursorPos.x, ptSelStart.y, ptSelStart.x, CE_ACTION_AUTOEXPAND);  // [JRT]
2283                         }
2284                         break;
2285                       case _T ('e'):
2286                         {
2287                           CPoint ptSelEnd = ptCursorPos;
2288                           if (ptSelEnd.x == GetLineLength (ptSelEnd.y))
2289                             {
2290                               if (ptSelEnd.y == GetLineCount () - 1)
2291                                 break;
2292                               ptSelEnd.y++;
2293                               ptSelEnd.x = 0;
2294                             }
2295                           else
2296                             ptSelEnd.x++;
2297                           m_pTextBuffer->DeleteText (this, ptCursorPos.y, ptCursorPos.x, ptSelEnd.y, ptSelEnd.x, CE_ACTION_AUTOEXPAND);   // [JRT]
2298                         }
2299                         break;
2300                       case _T ('t'):
2301                         {
2302                           static TCHAR szText[32];
2303                           if (m_pTextBuffer->GetInsertTabs())
2304                             {
2305                               *szText = '\t';
2306                               szText[1] = '\0';
2307                             }
2308                           else
2309                             {
2310                               int nTabSize = GetTabSize ();
2311                               int nChars = nTabSize - ptCursorPos.x % nTabSize;
2312                               for (int i = 0; i < nChars; i++)
2313                                 szText[i] = ' ';
2314                               szText[nChars] = '\0';
2315                             }
2316                           m_pTextBuffer->InsertText (this, ptCursorPos.y, ptCursorPos.x, szText, _tcslen(szText), y, x, CE_ACTION_AUTOEXPAND);  //  [JRT]
2317                           ptCursorPos.x = x;
2318                           ptCursorPos.y = y;
2319                           ASSERT_VALIDTEXTPOS (ptCursorPos);
2320                           SetSelection (ptCursorPos, ptCursorPos);
2321                           SetAnchor (ptCursorPos);
2322                           SetCursorPos (ptCursorPos);
2323                         }
2324                     }
2325                   ptCursorPos = GetCursorPos ();
2326                   pszExpand = pszSlash + 1;
2327                   pszSlash = _tcschr (pszExpand, '\\');
2328                   if (pszSlash != nullptr)
2329                     *pszSlash++ = '\0';
2330                 }
2331             }
2332           sExpand.ReleaseBuffer ();
2333           EnsureVisible (ptCursorPos);
2334           m_pTextBuffer->FlushUndoGroup (this);
2335         }
2336     }
2337 }
2338
2339 void CCrystalEditView::
2340 OnUpdateEditAutoExpand (CCmdUI * pCmdUI)
2341 {
2342   if (m_mapExpand->IsEmpty ())
2343     pCmdUI->Enable (false);
2344   else
2345     OnUpdateEditAutoComplete (pCmdUI);
2346 }
2347
2348 void CCrystalEditView::
2349 OnUpdateEditLowerCase (CCmdUI * pCmdUI)
2350 {
2351   pCmdUI->Enable (IsSelection ());
2352 }
2353
2354 void CCrystalEditView::
2355 OnEditLowerCase ()
2356 {
2357   if (IsSelection ())
2358     {
2359       CPoint ptCursorPos = GetCursorPos ();
2360       auto [ptSelStart, ptSelEnd] = GetSelection ();
2361       CString text;
2362       GetText (ptSelStart, ptSelEnd, text);
2363       text.MakeLower ();
2364
2365       m_pTextBuffer->BeginUndoGroup ();
2366
2367       if (IsSelection ())
2368         {
2369           auto [ptSelStart1, ptSelEnd1] = GetSelection ();
2370     
2371           ptCursorPos = ptSelStart1;
2372           /*SetAnchor (ptCursorPos);
2373           SetSelection (ptCursorPos, ptCursorPos);
2374           SetCursorPos (ptCursorPos);
2375           EnsureVisible (ptCursorPos);*/
2376     
2377           // [JRT]:
2378           m_pTextBuffer->DeleteText (this, ptSelStart1.y, ptSelStart1.x, ptSelEnd1.y, ptSelEnd1.x, CE_ACTION_LOWERCASE);
2379         }
2380
2381       int x, y;
2382       m_pTextBuffer->InsertText (this, ptSelStart.y, ptSelStart.x, text, text.GetLength(), y, x, CE_ACTION_LOWERCASE);
2383
2384       ASSERT_VALIDTEXTPOS (ptCursorPos);
2385       SetAnchor (ptCursorPos);
2386       SetSelection (ptSelStart, ptSelEnd);
2387       SetCursorPos (ptCursorPos);
2388       EnsureVisible (ptCursorPos);
2389
2390       m_pTextBuffer->FlushUndoGroup (this);
2391     }
2392 }
2393
2394 void CCrystalEditView::
2395 OnUpdateEditUpperCase (CCmdUI * pCmdUI)
2396 {
2397   pCmdUI->Enable (IsSelection ());
2398 }
2399
2400 void CCrystalEditView::
2401 OnEditUpperCase ()
2402 {
2403   if (IsSelection ())
2404     {
2405       CPoint ptCursorPos = GetCursorPos ();
2406       auto [ptSelStart, ptSelEnd] = GetSelection ();
2407       CString text;
2408       GetText (ptSelStart, ptSelEnd, text);
2409       text.MakeUpper ();
2410
2411       m_pTextBuffer->BeginUndoGroup ();
2412
2413       if (IsSelection ())
2414         {
2415           auto [ptSelStart1, ptSelEnd1] = GetSelection ();
2416     
2417           ptCursorPos = ptSelStart1;
2418           /*SetAnchor (ptCursorPos);
2419           SetSelection (ptCursorPos, ptCursorPos);
2420           SetCursorPos (ptCursorPos);
2421           EnsureVisible (ptCursorPos);*/
2422     
2423           // [JRT]:
2424           m_pTextBuffer->DeleteText (this, ptSelStart1.y, ptSelStart1.x, ptSelEnd1.y, ptSelEnd1.x, CE_ACTION_UPPERCASE);
2425         }
2426
2427       int x, y;
2428       m_pTextBuffer->InsertText (this, ptSelStart.y, ptSelStart.x, text, text.GetLength(), y, x, CE_ACTION_UPPERCASE);
2429
2430       ASSERT_VALIDTEXTPOS (ptCursorPos);
2431       SetAnchor (ptCursorPos);
2432       SetSelection (ptSelStart, ptSelEnd);
2433       SetCursorPos (ptCursorPos);
2434       EnsureVisible (ptCursorPos);
2435
2436       m_pTextBuffer->FlushUndoGroup (this);
2437     }
2438 }
2439
2440 void CCrystalEditView::
2441 OnUpdateEditSwapCase (CCmdUI * pCmdUI)
2442 {
2443   pCmdUI->Enable (IsSelection ());
2444 }
2445
2446 void CCrystalEditView::
2447 OnEditSwapCase ()
2448 {
2449   if (IsSelection ())
2450     {
2451       CPoint ptCursorPos = GetCursorPos ();
2452       auto [ptSelStart, ptSelEnd] = GetSelection ();
2453       CString text;
2454       GetText (ptSelStart, ptSelEnd, text);
2455       int nLen = text.GetLength ();
2456       LPTSTR pszText = text.GetBuffer (nLen + 1);
2457       while (*pszText)
2458         *pszText++ = (TCHAR)(_istlower (*pszText) ? _totupper (*pszText) : _totlower (*pszText));
2459       text.ReleaseBuffer (nLen);
2460
2461       m_pTextBuffer->BeginUndoGroup ();
2462
2463       if (IsSelection ())
2464         {
2465           auto [ptSelStart1, ptSelEnd1] = GetSelection ();
2466     
2467           ptCursorPos = ptSelStart1;
2468           /*SetAnchor (ptCursorPos);
2469           SetSelection (ptCursorPos, ptCursorPos);
2470           SetCursorPos (ptCursorPos);
2471           EnsureVisible (ptCursorPos);*/
2472     
2473           // [JRT]:
2474           m_pTextBuffer->DeleteText (this, ptSelStart1.y, ptSelStart1.x, ptSelEnd1.y, ptSelEnd1.x, CE_ACTION_SWAPCASE);
2475         }
2476
2477       int x, y;
2478       m_pTextBuffer->InsertText (this, ptSelStart.y, ptSelStart.x, text, text.GetLength(), y, x, CE_ACTION_SWAPCASE);
2479
2480       ASSERT_VALIDTEXTPOS (ptCursorPos);
2481       SetAnchor (ptCursorPos);
2482       SetSelection (ptSelStart, ptSelEnd);
2483       SetCursorPos (ptCursorPos);
2484       EnsureVisible (ptCursorPos);
2485
2486       m_pTextBuffer->FlushUndoGroup (this);
2487     }
2488 }
2489
2490 void CCrystalEditView::
2491 OnUpdateEditCapitalize (CCmdUI * pCmdUI)
2492 {
2493   pCmdUI->Enable (IsSelection ());
2494 }
2495
2496 void CCrystalEditView::
2497 OnEditCapitalize ()
2498 {
2499   if (IsSelection ())
2500     {
2501       CPoint ptCursorPos = GetCursorPos ();
2502       auto [ptSelStart, ptSelEnd] = GetSelection ();
2503       CString text;
2504       GetText (ptSelStart, ptSelEnd, text);
2505       int nLen = text.GetLength ();
2506       LPTSTR pszText = text.GetBuffer (nLen + 1);
2507       bool bCapitalize = true;
2508       while (*pszText)
2509         {
2510           if (xisspace (*pszText))
2511             bCapitalize = true;
2512           else if (_istalpha (*pszText))
2513             if (bCapitalize)
2514               {
2515                 *pszText = (TCHAR)_totupper (*pszText);
2516                 bCapitalize = false;
2517               }
2518             else
2519               *pszText = (TCHAR)_totlower (*pszText);
2520           pszText++;
2521         }
2522       text.ReleaseBuffer (nLen);
2523
2524       m_pTextBuffer->BeginUndoGroup ();
2525
2526       if (IsSelection ())
2527         {
2528           auto [ptSelStart1, ptSelEnd1] = GetSelection ();
2529     
2530           ptCursorPos = ptSelStart1;
2531           /*SetAnchor (ptCursorPos);
2532           SetSelection (ptCursorPos, ptCursorPos);
2533           SetCursorPos (ptCursorPos);
2534           EnsureVisible (ptCursorPos);*/
2535     
2536           // [JRT]:
2537           m_pTextBuffer->DeleteText (this, ptSelStart1.y, ptSelStart1.x, ptSelEnd1.y, ptSelEnd1.x, CE_ACTION_CAPITALIZE);
2538         }
2539
2540       int x, y;
2541       m_pTextBuffer->InsertText (this, ptSelStart.y, ptSelStart.x, text, text.GetLength(), y, x, CE_ACTION_CAPITALIZE);
2542
2543       ASSERT_VALIDTEXTPOS (ptCursorPos);
2544       SetAnchor (ptCursorPos);
2545       SetSelection (ptSelStart, ptSelEnd);
2546       SetCursorPos (ptCursorPos);
2547       EnsureVisible (ptCursorPos);
2548
2549       m_pTextBuffer->FlushUndoGroup (this);
2550     }
2551 }
2552
2553 void CCrystalEditView::
2554 OnUpdateEditSentence (CCmdUI * pCmdUI)
2555 {
2556   pCmdUI->Enable (IsSelection ());
2557 }
2558
2559 void CCrystalEditView::
2560 OnEditSentence ()
2561 {
2562   if (IsSelection ())
2563     {
2564       CPoint ptCursorPos = GetCursorPos ();
2565       auto [ptSelStart, ptSelEnd] = GetSelection ();
2566       CString text;
2567       GetText (ptSelStart, ptSelEnd, text);
2568       int nLen = text.GetLength ();
2569       LPTSTR pszText = text.GetBuffer (nLen + 1);
2570       bool bCapitalize = true;
2571       while (*pszText)
2572         {
2573           if (!xisspace (*pszText))
2574             if (*pszText == _T ('.'))
2575               {
2576                 if (pszText[1] && !_istdigit (pszText[1]))
2577                   bCapitalize = true;
2578               }
2579             else if (_istalpha (*pszText))
2580               if (bCapitalize)
2581                 {
2582                   *pszText = (TCHAR)_totupper (*pszText);
2583                   bCapitalize = false;
2584                 }
2585               else
2586                 *pszText = (TCHAR)_totlower (*pszText);
2587           pszText++;
2588         }
2589       text.ReleaseBuffer (nLen);
2590
2591       m_pTextBuffer->BeginUndoGroup ();
2592
2593       if (IsSelection ())
2594         {
2595           auto [ptSelStart1, ptSelEnd1] = GetSelection ();
2596     
2597           ptCursorPos = ptSelStart1;
2598           /*SetAnchor (ptCursorPos);
2599           SetSelection (ptCursorPos, ptCursorPos);
2600           SetCursorPos (ptCursorPos);
2601           EnsureVisible (ptCursorPos);*/
2602     
2603           // [JRT]:
2604           m_pTextBuffer->DeleteText (this, ptSelStart1.y, ptSelStart1.x, ptSelEnd1.y, ptSelEnd1.x, CE_ACTION_SENTENCIZE);
2605         }
2606
2607       int x, y;
2608       m_pTextBuffer->InsertText (this, ptSelStart.y, ptSelStart.x, text, text.GetLength(), y, x, CE_ACTION_SENTENCIZE);
2609
2610       ASSERT_VALIDTEXTPOS (ptCursorPos);
2611       SetAnchor (ptCursorPos);
2612       SetSelection (ptSelStart, ptSelEnd);
2613       SetCursorPos (ptCursorPos);
2614       EnsureVisible (ptCursorPos);
2615
2616       m_pTextBuffer->FlushUndoGroup (this);
2617     }
2618 }
2619
2620 //BEGIN SW
2621 void CCrystalEditView::OnUpdateEditGotoLastChange( CCmdUI *pCmdUI )
2622 {
2623   CPoint        ptLastChange = m_pTextBuffer->GetLastChangePos();
2624   pCmdUI->Enable( ptLastChange.x > 0 && ptLastChange.y > -1 );
2625 }
2626
2627 void CCrystalEditView::OnEditGotoLastChange()
2628 {
2629   CPoint        ptLastChange = m_pTextBuffer->GetLastChangePos();
2630   if( ptLastChange.x < 0 || ptLastChange.y < 0 )
2631     return;
2632
2633   // goto last change
2634   SetSelection( ptLastChange, ptLastChange );
2635   SetCursorPos( ptLastChange );
2636   EnsureVisible( ptLastChange );
2637 }
2638 //END SW
2639
2640 int CCrystalEditView::SpellGetLine (struct SpellData_t *pdata)
2641 {
2642   CCrystalEditView *pView = static_cast<CCrystalEditView*>(pdata->pUserData);
2643   static TCHAR szBuffer[4096];
2644
2645   if (pdata->nRow < pView->GetLineCount ())
2646     {
2647       int nCount = pView->GetLineLength (pdata->nRow) + 1;
2648       /*if (pdata->pszBuffer)
2649         free (pdata->pszBuffer);
2650       pdata->pszBuffer = (LPTSTR) malloc (nCount + 2);*/
2651       pdata->pszBuffer = szBuffer;
2652       *pdata->pszBuffer = _T ('^');
2653       if (nCount > 1)
2654         _tcscpy_s (pdata->pszBuffer + 1, sizeof(szBuffer)-1, pView->GetLineChars (pdata->nRow));
2655       else
2656         pdata->pszBuffer[nCount++] = _T (' ');
2657       pdata->pszBuffer[nCount++] = _T ('\n');
2658       pdata->pszBuffer[nCount] = _T ('\0');
2659       pdata->nRow++;
2660       return nCount;
2661     }
2662   pdata->pszBuffer = szBuffer;
2663   *pdata->pszBuffer = _T ('\0');
2664   return 0;
2665 }
2666
2667 int CCrystalEditView::SpellNotify (int nEvent, struct SpellData_t *pdata)
2668 {
2669   CCrystalEditView *pView = static_cast<CCrystalEditView*>(pdata->pUserData);
2670   CPoint ptStartPos, ptEndPos;
2671
2672   switch (nEvent)
2673     {
2674       case SN_FOUND:
2675         ptStartPos.x = pdata->nColumn - 1;
2676         ptStartPos.y = pdata->nRow - 1;
2677         ptEndPos.x = pdata->nColumn - 1 + static_cast<LONG>(_tcslen (pdata->pszWord));
2678         ptEndPos.y = pdata->nRow - 1;
2679         if (!pView->IsValidTextPos (ptStartPos))
2680           if (ptStartPos.x > 0)
2681             ptStartPos.x--;
2682           else
2683             ptStartPos.x = 0;
2684         if (!pView->IsValidTextPos (ptEndPos))
2685           if (ptEndPos.x > 0)
2686             ptEndPos.x--;
2687           else
2688             ptEndPos.x = 0;
2689         pView->SetAnchor (ptStartPos);
2690         pView->SetSelection (ptStartPos, ptEndPos);
2691         pView->SetCursorPos (ptStartPos);
2692         pView->EnsureVisible (ptStartPos);
2693       break;
2694       case SN_REPLACED:
2695         if (pView->IsSelection ())
2696           {
2697             int x, y;
2698             pView->GetSelection (ptStartPos, ptEndPos);
2699             pView->m_pTextBuffer->DeleteText (pView, ptStartPos.y, ptStartPos.x, ptEndPos.y, ptEndPos.x, CE_ACTION_SPELL);
2700             pView->m_pTextBuffer->InsertText (pView, ptStartPos.y, ptStartPos.x, pdata->pszWord, _tcslen(pdata->pszWord), y, x, CE_ACTION_SPELL);
2701             ptEndPos.x = x;
2702             ptEndPos.y = y;
2703             pView->SetAnchor (ptEndPos);
2704             pView->SetSelection (ptEndPos, ptEndPos);
2705             pView->SetCursorPos (ptEndPos);
2706           }
2707       break;
2708       case SN_FINISHED:
2709         ptStartPos = pView->GetCursorPos ();
2710         pView->SetAnchor (ptStartPos);
2711         pView->SetSelection (ptStartPos, ptStartPos);
2712         pView->SetCursorPos (ptStartPos);
2713         pView->EnsureVisible (ptStartPos);
2714         ::MessageBox (pdata->hParent, _T ("Spellchecking finished."), _T ("WIspell"), MB_OK|MB_ICONINFORMATION);
2715     }
2716   return 0;
2717 }
2718
2719 HMODULE CCrystalEditView::hSpellDll = nullptr;
2720 TCHAR CCrystalEditView::szWIspellPath[_MAX_PATH];
2721 SpellData CCrystalEditView::spellData;
2722 int (*CCrystalEditView::SpellInit) (SpellData*);
2723 int (*CCrystalEditView::SpellCheck) (SpellData*);
2724 int (*CCrystalEditView::SpellConfig) (SpellData*);
2725
2726 bool CCrystalEditView::LoadSpellDll (bool bAlert /*= true*/)
2727 {
2728   if (hSpellDll != nullptr)
2729     return true;
2730   CString sPath = szWIspellPath;
2731   if (!sPath.IsEmpty () && sPath[sPath.GetLength () - 1] != _T('\\'))
2732     sPath += _T ('\\');
2733   sPath += _T ("wispell.dll");
2734   hSpellDll = LoadLibrary (sPath);
2735   if (hSpellDll != nullptr)
2736     {
2737       SpellInit = (int (*) (SpellData*)) GetProcAddress (hSpellDll, "SpellInit");
2738       SpellCheck = (int (*) (SpellData*)) GetProcAddress (hSpellDll, "SpellCheck");
2739       SpellConfig = (int (*) (SpellData*)) GetProcAddress (hSpellDll, "SpellConfig");
2740       if (SpellInit)
2741         SpellInit (&spellData);
2742       _tcscpy_s (spellData.szIspell, szWIspellPath);
2743       spellData.GetLine = SpellGetLine;
2744       spellData.Notify = SpellNotify;
2745     }
2746   else
2747     {
2748       SpellInit = SpellCheck = SpellConfig = nullptr;
2749       if (bAlert)
2750         ::MessageBox (AfxGetMainWnd ()->GetSafeHwnd (), _T ("Error loading \"wispell.dll\"."), _T ("Error"), MB_OK|MB_ICONEXCLAMATION);
2751     }
2752   return hSpellDll != nullptr;
2753 }
2754
2755 void CCrystalEditView::
2756 OnUpdateToolsSpelling (CCmdUI * pCmdUI)
2757 {
2758   CPoint ptCursorPos = GetCursorPos ();
2759   int nLines = GetLineCount () - 1;
2760   pCmdUI->Enable (LoadSpellDll (false) && ptCursorPos.y < nLines);
2761 }
2762
2763 void CCrystalEditView::
2764 OnToolsSpelling ()
2765 {
2766   CPoint ptCursorPos = GetCursorPos ();
2767   if (LoadSpellDll () && ptCursorPos.y < GetLineCount ())
2768     {
2769       spellData.hParent = GetSafeHwnd ();
2770       spellData.nRow = ptCursorPos.y;
2771       spellData.pUserData = (LPVOID) (LPCVOID) this;
2772       spellData.pszBuffer = nullptr;
2773       m_pTextBuffer->BeginUndoGroup ();
2774       if (SpellCheck (&spellData) == IDCANCEL)
2775         {
2776           m_pTextBuffer->FlushUndoGroup (this);
2777           OnEditUndo ();
2778         }
2779       else
2780         m_pTextBuffer->FlushUndoGroup (this);
2781       /*if (spellData.pszBuffer)
2782         free (spellData.pszBuffer);*/
2783     }
2784 }
2785
2786 void CCrystalEditView::
2787 OnUpdateToolsCharCoding (CCmdUI * pCmdUI)
2788 {
2789   pCmdUI->Enable (IsSelection ());
2790 }
2791
2792 void CCrystalEditView::
2793 OnToolsCharCoding ()
2794 {
2795   if (IsSelection ())
2796     {
2797       CWaitCursor wait;
2798       CPoint ptCursorPos = GetCursorPos ();
2799       auto [ptSelStart, ptSelEnd] = GetSelection ();
2800       CString sText;
2801       GetText (ptSelStart, ptSelEnd, sText);
2802       CCharConvDlg dlg;
2803       dlg.m_sOriginal = sText;
2804       LPTSTR pszEnd = dlg.m_sOriginal.GetBuffer (dlg.m_sOriginal.GetLength () + 1);
2805       for (int i = 0; i < 13; i++)
2806         {
2807           pszEnd = _tcschr (pszEnd, _T ('\n'));
2808           if (pszEnd != nullptr)
2809             pszEnd++;
2810           else
2811             break;
2812         }
2813       if (pszEnd != nullptr)
2814         *pszEnd = _T ('\0');
2815       dlg.m_sOriginal.ReleaseBuffer ();
2816       if (dlg.DoModal () != IDOK)
2817         return;
2818       LPTSTR pszNew = nullptr;
2819       if (!iconvert_new (sText, &pszNew, dlg.m_nSource, dlg.m_nDest, dlg.m_bAlpha))
2820         {
2821           ASSERT (pszNew != nullptr);
2822           m_pTextBuffer->BeginUndoGroup ();
2823
2824           m_pTextBuffer->DeleteText (this, ptSelStart.y, ptSelStart.x, ptSelEnd.y, ptSelEnd.x, CE_ACTION_RECODE);
2825
2826           int x, y;
2827           m_pTextBuffer->InsertText (this, ptSelStart.y, ptSelStart.x, pszNew, _tcslen(pszNew), y, x, CE_ACTION_RECODE);
2828
2829           if (IsValidTextPos (ptCursorPos))
2830             ptCursorPos.x = 0;
2831           ASSERT_VALIDTEXTPOS (ptCursorPos);
2832           SetAnchor (ptCursorPos);
2833           SetSelection (ptSelStart, ptSelEnd);
2834           SetCursorPos (ptCursorPos);
2835           EnsureVisible (ptCursorPos);
2836
2837           m_pTextBuffer->FlushUndoGroup (this);
2838         }
2839       if (pszNew != nullptr)
2840         free (pszNew);
2841     }
2842 }
2843
2844 void CCrystalEditView::
2845 OnEditDeleteWord ()
2846 {
2847   if (!IsSelection ())
2848     MoveWordRight (true);
2849   if (IsSelection ())
2850     {
2851       auto [ptSelStart, ptSelEnd] = GetSelection ();
2852
2853       m_pTextBuffer->BeginUndoGroup ();
2854
2855       m_pTextBuffer->DeleteText (this, ptSelStart.y, ptSelStart.x, ptSelEnd.y, ptSelEnd.x, CE_ACTION_DELETE);
2856
2857       ASSERT_VALIDTEXTPOS (ptSelStart);
2858       SetAnchor (ptSelStart);
2859       SetSelection (ptSelStart, ptSelStart);
2860       SetCursorPos (ptSelStart);
2861       EnsureVisible (ptSelStart);
2862
2863       m_pTextBuffer->FlushUndoGroup (this);
2864     }
2865 }
2866
2867 void CCrystalEditView::
2868 OnEditDeleteWordBack ()
2869 {
2870   if (!IsSelection ())
2871     MoveWordLeft (true);
2872   if (IsSelection ())
2873     {
2874       auto [ptSelStart, ptSelEnd] = GetSelection ();
2875
2876       m_pTextBuffer->BeginUndoGroup ();
2877
2878       m_pTextBuffer->DeleteText (this, ptSelStart.y, ptSelStart.x, ptSelEnd.y, ptSelEnd.x, CE_ACTION_DELETE);
2879
2880       ASSERT_VALIDTEXTPOS (ptSelStart);
2881       SetAnchor (ptSelStart);
2882       SetSelection (ptSelStart, ptSelStart);
2883       SetCursorPos (ptSelStart);
2884       EnsureVisible (ptSelStart);
2885
2886       m_pTextBuffer->FlushUndoGroup (this);
2887     }
2888 }
2889
2890 void CCrystalEditView::
2891 OnKillFocus (CWnd * pNewWnd)
2892 {
2893   m_bMergeUndo = false;
2894   CCrystalTextView::OnKillFocus (pNewWnd);
2895 }
2896
2897 void CCrystalEditView::OnCharLeft()
2898 {
2899   m_bMergeUndo = false;
2900   CCrystalTextView::OnCharLeft();
2901 }
2902
2903 void CCrystalEditView::OnExtCharLeft()
2904 {
2905   m_bMergeUndo = false;
2906   CCrystalTextView::OnExtCharLeft();
2907 }
2908
2909 void CCrystalEditView::OnCharRight()
2910 {
2911   m_bMergeUndo = false;
2912   CCrystalTextView::OnCharRight();
2913 }
2914
2915 void CCrystalEditView::OnExtCharRight()
2916 {
2917   m_bMergeUndo = false;
2918   CCrystalTextView::OnExtCharRight();
2919 }
2920
2921 void CCrystalEditView::OnWordLeft()
2922 {
2923   m_bMergeUndo = false;
2924   CCrystalTextView::OnWordLeft();
2925 }
2926
2927 void CCrystalEditView::OnExtWordLeft()
2928 {
2929   m_bMergeUndo = false;
2930   CCrystalTextView::OnExtWordLeft();
2931 }
2932
2933 void CCrystalEditView::OnWordRight()
2934 {
2935   m_bMergeUndo = false;
2936   CCrystalTextView::OnWordRight();
2937 }
2938
2939 void CCrystalEditView::OnExtWordRight()
2940 {
2941   m_bMergeUndo = false;
2942   CCrystalTextView::OnExtWordRight();
2943 }
2944
2945 void CCrystalEditView::OnLineUp()
2946 {
2947   m_bMergeUndo = false;
2948   CCrystalTextView::OnLineUp();
2949 }
2950
2951 void CCrystalEditView::OnExtLineUp()
2952 {
2953   m_bMergeUndo = false;
2954   CCrystalTextView::OnExtLineUp();
2955 }
2956
2957 void CCrystalEditView::OnLineDown()
2958 {
2959   m_bMergeUndo = false;
2960   CCrystalTextView::OnLineDown();
2961 }
2962
2963 void CCrystalEditView::OnExtLineDown()
2964 {
2965   m_bMergeUndo = false;
2966   CCrystalTextView::OnExtLineDown();
2967 }
2968
2969 void CCrystalEditView::OnPageUp()
2970 {
2971   m_bMergeUndo = false;
2972   CCrystalTextView::OnPageUp();
2973 }
2974
2975 void CCrystalEditView::OnExtPageUp()
2976 {
2977   m_bMergeUndo = false;
2978   CCrystalTextView::OnExtPageUp();
2979 }
2980
2981 void CCrystalEditView::OnPageDown()
2982 {
2983   m_bMergeUndo = false;
2984   CCrystalTextView::OnPageDown();
2985 }
2986
2987 void CCrystalEditView::OnExtPageDown()
2988 {
2989   m_bMergeUndo = false;
2990   CCrystalTextView::OnExtPageDown();
2991 }
2992
2993 void CCrystalEditView::OnLineEnd()
2994 {
2995   m_bMergeUndo = false;
2996   CCrystalTextView::OnLineEnd();
2997 }
2998
2999 void CCrystalEditView::OnExtLineEnd()
3000 {
3001   m_bMergeUndo = false;
3002   CCrystalTextView::OnExtLineEnd();
3003 }
3004
3005 void CCrystalEditView::OnHome()
3006 {
3007   m_bMergeUndo = false;
3008   CCrystalTextView::OnHome();
3009 }
3010
3011 void CCrystalEditView::OnExtHome()
3012 {
3013   m_bMergeUndo = false;
3014   CCrystalTextView::OnExtHome();
3015 }
3016
3017 void CCrystalEditView::OnTextBegin()
3018 {
3019   m_bMergeUndo = false;
3020   CCrystalTextView::OnTextBegin();
3021 }
3022
3023 void CCrystalEditView::OnExtTextBegin()
3024 {
3025   m_bMergeUndo = false;
3026   CCrystalTextView::OnExtTextBegin();
3027 }
3028
3029 void CCrystalEditView::OnTextEnd()
3030 {
3031   m_bMergeUndo = false;
3032   CCrystalTextView::OnTextEnd();
3033 }
3034
3035 void CCrystalEditView::OnExtTextEnd()
3036 {
3037   m_bMergeUndo = false;
3038   CCrystalTextView::OnExtTextEnd();
3039 }
3040
3041 void CCrystalEditView::OnLButtonDown(UINT nFlags, CPoint point)
3042 {
3043   m_bMergeUndo = false;
3044   CCrystalTextView::OnLButtonDown(nFlags, point);
3045 }
3046
3047 void CCrystalEditView::OnRButtonDown(UINT nFlags, CPoint point)
3048 {
3049   m_bMergeUndo = false;
3050   CCrystalTextView::OnRButtonDown(nFlags, point);
3051 }
3052
3053 ////////////////////////////////////////////////////////////////////////////