OSDN Git Service

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