Click here to Skip to main content
15,885,216 members
Articles / Desktop Programming / MFC

A Java Language IDE

Rate me:
Please Sign up or sign in to vote.
4.33/5 (26 votes)
13 May 2004CPOL3 min read 80.4K   3.4K   41  
This is a partially implemented IDE for the Java platform.
////////////////////////////////////////////////////////////////////////////
//  File:       ccrystaltextbuffer.cpp
//  Version:    1.0.0.0
//  Created:    29-Dec-1998
//
//  Author:     Stcherbatchenko Andrei
//  E-mail:     windfall@gmx.de
//
//  Implementation of the CCrystalTextBuffer class, a part of Crystal Edit -
//  syntax coloring text editor.
//
//  You are free to use or modify this code to the following restrictions:
//  - Acknowledge me somewhere in your about box, simple "Parts of code by.."
//  will be enough. If you can't (or don't want to), contact me personally.
//  - LEAVE THIS HEADER INTACT
////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
//  17-Feb-99
//  +   FIX: unnecessary 'HANDLE' in CCrystalTextBuffer::SaveToFile
////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
//  21-Feb-99
//      Paul Selormey, James R. Twine:
//  +   FEATURE: description for Undo/Redo actions
//  +   FEATURE: multiple MSVC-like bookmarks
//  +   FEATURE: 'Disable backspace at beginning of line' option
//  +   FEATURE: 'Disable drag-n-drop editing' option
//
//  +   FEATURE: changed layout of SUndoRecord. Now takes less memory
////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
//  19-Jul-99
//      Ferdinand Prantl:
//  +   FEATURE: some other things I've forgotten ...
//
//  ... it's being edited very rapidly so sorry for non-commented
//        and maybe "ugly" code ...
////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
//	??-Aug-99
//		Sven Wiegand (search for "//BEGIN SW" to find my changes):
//	+ FEATURE: Remembering the text-position of the latest change.
////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
//	24-Oct-99
//		Sven Wiegand
//	+ FIX: Setting m_ptLastChange to the beginning of the selection in
//		     InternalDeleteText(), so that position is valid in any case.
//		     Editor won't crash any more i.e. by selecting whole buffer and
//		     deleting it and then executing ID_EDIT_GOTO_LAST_CHANGE-command.
////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <malloc.h>
#include "editcmd.h"
#include "ccrystaltextbuffer.h"
#include "ccrystaltextview.h"
#include "filesup.h"
#include "cs2cs.h"

#ifndef __AFXPRIV_H__
#pragma message("Include <afxpriv.h> in your stdafx.h to avoid this message")
#include <afxpriv.h>
#endif

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//  Line allocation granularity
#define     CHAR_ALIGN                  16
#define     ALIGN_BUF_SIZE(size)        ((size) / CHAR_ALIGN) * CHAR_ALIGN + CHAR_ALIGN;

#define     UNDO_BUF_SIZE               1024

const TCHAR crlf[] = _T ("\r\n");

#ifdef _DEBUG
#define _ADVANCED_BUGCHECK  1
#endif

int CCrystalTextBuffer::m_nDefaultEncoding = -1;


/////////////////////////////////////////////////////////////////////////////
// CCrystalTextBuffer::SUndoRecord


void CCrystalTextBuffer::SUndoRecord::SetText (LPCTSTR pszText)
{
  m_pszText = NULL;
  if (pszText != NULL && pszText[0] != _T ('\0'))
    {
      int nLength = _tcslen (pszText);
      if (nLength > 1)
        {
          m_pszText = new TCHAR[(nLength + 1) * sizeof (TCHAR)];
          _tcscpy (m_pszText, pszText);
        }
      else
        {
          m_szText[0] = pszText[0];
        }
    }
}

void CCrystalTextBuffer::SUndoRecord::FreeText ()
{
  if (HIWORD ((DWORD) m_pszText) != 0)
    delete m_pszText;
}


/////////////////////////////////////////////////////////////////////////////
// CCrystalTextBuffer::CUpdateContext

void CCrystalTextBuffer::CInsertContext::RecalcPoint (CPoint & ptPoint)
{
  ASSERT (m_ptEnd.y > m_ptStart.y ||
          m_ptEnd.y == m_ptStart.y && m_ptEnd.x >= m_ptStart.x);
  if (ptPoint.y < m_ptStart.y)
    return;
  if (ptPoint.y > m_ptStart.y)
    {
      ptPoint.y += (m_ptEnd.y - m_ptStart.y);
      return;
    }
  if (ptPoint.x <= m_ptStart.x)
    return;
  ptPoint.y += (m_ptEnd.y - m_ptStart.y);
  ptPoint.x = m_ptEnd.x + (ptPoint.x - m_ptStart.x);
}

void CCrystalTextBuffer::CDeleteContext::RecalcPoint (CPoint & ptPoint)
{
  ASSERT (m_ptEnd.y > m_ptStart.y ||
          m_ptEnd.y == m_ptStart.y && m_ptEnd.x >= m_ptStart.x);
  if (ptPoint.y < m_ptStart.y)
    return;
  if (ptPoint.y > m_ptEnd.y)
    {
      ptPoint.y -= (m_ptEnd.y - m_ptStart.y);
      return;
    }
  if (ptPoint.y == m_ptEnd.y && ptPoint.x >= m_ptEnd.x)
    {
      ptPoint.y = m_ptStart.y;
      ptPoint.x = m_ptStart.x + (ptPoint.x - m_ptEnd.x);
      return;
    }
  if (ptPoint.y == m_ptStart.y)
    {
      if (ptPoint.x > m_ptStart.x)
        ptPoint.x = m_ptStart.x;
      return;
    }
  ptPoint = m_ptStart;
}


/////////////////////////////////////////////////////////////////////////////
// CCrystalTextBuffer
IMPLEMENT_DYNCREATE (CCrystalTextBuffer, CCmdTarget)

CCrystalTextBuffer::CCrystalTextBuffer ()
{
  m_bInit             = FALSE;
  m_bReadOnly         = FALSE;
  m_bModified         = FALSE;
  m_bCreateBackupFile = FALSE;
  m_nUndoPosition     = 0;
	//BEGIN SW
  m_ptLastChange.x    = m_ptLastChange.y = -1;
	//END SW
  m_nSourceEncoding   = m_nDefaultEncoding;
}

CCrystalTextBuffer:: ~ CCrystalTextBuffer ()
{
  ASSERT (!m_bInit);//  You must call FreeAll() before deleting the object
}


BEGIN_MESSAGE_MAP (CCrystalTextBuffer, CCmdTarget)
//{{AFX_MSG_MAP(CCrystalTextBuffer)
//}}AFX_MSG_MAP
END_MESSAGE_MAP ()


/////////////////////////////////////////////////////////////////////////////
// CCrystalTextBuffer message handlers

void CCrystalTextBuffer::InsertLine (LPCTSTR pszLine, int nLength /*= -1*/ , 
									 int nPosition /*= -1*/ )
{
  int nAcPos = nPosition;
  if (nLength == -1)
    {
      if (pszLine == NULL)
        nLength = 0;
      else
        nLength = _tcslen (pszLine);
    }

  SLineInfo *li = __newline()/*new SLineInfo*/;
  
  li->m_nLength = nLength;
  li->m_nMax = ALIGN_BUF_SIZE(li->m_nLength);
  ASSERT(li->m_nMax >= li->m_nLength);
  
  if (li->m_nMax > 0)
  {
    li->m_pcLine = new TCHAR[li->m_nMax];
  }
  
  if(li->m_nLength > 0)
    memcpy(li->m_pcLine, pszLine, sizeof (TCHAR) * li->m_nLength);

  if (nPosition == -1)
    nAcPos = m_aLines.Add(li);
  else
    m_aLines.InsertAt(nPosition,li);


#ifdef _DEBUG
  int nLines = m_aLines.GetSize ();
  if (nLines % 5000 == 0)
    TRACE1 ("%d lines loaded!\n", nLines);
#endif
}

void CCrystalTextBuffer::AddLine(char*)
{

}

void CCrystalTextBuffer::AppendLine (int nLineIndex, LPCTSTR pszChars, 
									 int nLength /*= -1*/ )
{
  if(nLength == -1)
  {
      if (pszChars == NULL)
        return;
      nLength = _tcslen (pszChars);
  }

  if (nLength == 0)
    return;

  register SLineInfo * li = m_aLines[nLineIndex];
  int nBufNeeded = li->m_nLength + nLength;
  if(nBufNeeded > li->m_nMax)
  {
      li->m_nMax = ALIGN_BUF_SIZE (nBufNeeded);
      ASSERT (li->m_nMax >= li->m_nLength + nLength);
      TCHAR *pcNewBuf = new TCHAR[li->m_nMax];
      
	  if (li->m_nLength > 0)
        memcpy (pcNewBuf, li->m_pcLine, sizeof (TCHAR) * li->m_nLength);

      delete li->m_pcLine;
      li->m_pcLine = pcNewBuf;
  }

  memcpy(li->m_pcLine + li->m_nLength, pszChars, sizeof (TCHAR) * nLength);
  li->m_nLength += nLength;
  ASSERT(li->m_nLength <= li->m_nMax);
}

void CCrystalTextBuffer::FreeAll()
{
  //  Free text
  int nCount = m_aLines.GetSize ();
  for(int I = 0; I < nCount; I++)
  {
      if (m_aLines[I]->m_nMax > 0)
        delete m_aLines[I]->m_pcLine;
	  delete m_aLines[I];
  }
  m_aLines.RemoveAll();

  //  Free undo buffer
  int nBufSize = m_aUndoBuf.GetSize ();
  for (I = 0; I < nBufSize; I++)
    m_aUndoBuf[I].FreeText ();
  m_aUndoBuf.RemoveAll ();

  m_bInit = FALSE;
	//BEGIN SW
  m_ptLastChange.x = m_ptLastChange.y = -1;
	//END SW
}

BOOL CCrystalTextBuffer::InitNew(int nCrlfStyle /*= CRLF_STYLE_DOS*/ )
{
  ASSERT (!m_bInit);
  ASSERT (m_aLines.GetSize () == 0);
  ASSERT (nCrlfStyle >= 0 && nCrlfStyle <= 2);
  InsertLine (_T (""));
  m_bInit = TRUE;
  m_bReadOnly = FALSE;
  m_nCRLFMode = nCrlfStyle;
  m_bModified = FALSE;
  m_nSyncPosition = m_nUndoPosition = 0;
  m_bUndoGroup = m_bUndoBeginGroup = FALSE;
  m_nUndoBufSize = UNDO_BUF_SIZE;
  ASSERT (m_aUndoBuf.GetSize () == 0);
  UpdateViews (NULL, NULL, UPDATE_RESET);
	//BEGIN SW
	m_ptLastChange.x = m_ptLastChange.y = -1;
	//END SW
  return TRUE;
}

BOOL CCrystalTextBuffer::GetReadOnly()const
{
  ASSERT (m_bInit);        //  Text buffer not yet initialized.
  //  You must call InitNew() or LoadFromFile() first!

  return m_bReadOnly;
}

void CCrystalTextBuffer::SetReadOnly(BOOL bReadOnly /*= TRUE*/ )
{
  ASSERT (m_bInit);             //  Text buffer not yet initialized.
  //  You must call InitNew() or LoadFromFile() first!

  m_bReadOnly = bReadOnly;
}

static LPCTSTR crlfs[] =
  {
    _T ("\x0d\x0a"), //  DOS/Windows style
    _T ("\x0a"),     //  UNIX style
    _T ("\x0a")      //  Macintosh style
  };

BOOL CCrystalTextBuffer::LoadFromFile(LPCTSTR pszFileName, 
									   int nCrlfStyle /*= CRLF_STYLE_AUTOMATIC*/ )
{
  ASSERT (!m_bInit);
  ASSERT (m_aLines.GetSize () == 0);

  HANDLE hFile = NULL;
  int nCurrentMax = 256;
  LPTSTR pcLineBuf = new TCHAR[nCurrentMax];

  BOOL bSuccess = FALSE;

  int nExt = GetExtPosition (pszFileName);
  if (pszFileName[nExt] == _T ('.'))
    nExt++;
  CCrystalTextView::TextDefinition *def = CCrystalTextView::GetTextType (pszFileName + nExt);
  if (def && def->encoding != -1)
    m_nSourceEncoding = def->encoding;

  __try
  {
    DWORD dwFileAttributes =::GetFileAttributes (pszFileName);
    if (dwFileAttributes == (DWORD) - 1)
      __leave;

      hFile =::CreateFile (pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
                           OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
      if (hFile == INVALID_HANDLE_VALUE)
        __leave;

        int nCurrentLength = 0;

        const DWORD dwBufSize = 32768;
        LPTSTR pcBuf = (LPTSTR) _alloca (dwBufSize);
        DWORD dwCurSize;
        if (!::ReadFile (hFile, pcBuf, dwBufSize, &dwCurSize, NULL))
          __leave;

          if (nCrlfStyle == CRLF_STYLE_AUTOMATIC)
            {
              //  Try to determine current CRLF mode
              for (DWORD I = 0; I < dwCurSize; I++)
                {
                  if ((pcBuf[I] == _T('\x0d')) || (pcBuf[I] == _T('\x0a')))
                    break;
                }
              if (I == dwCurSize)
                {
                  //  By default (or in the case of empty file), set DOS style
                  nCrlfStyle = CRLF_STYLE_DOS;
                }
              else
                {
                  //  Otherwise, analyse the first occurance of line-feed character
                  if (pcBuf[I] == _T('\x0a'))
                    {
                      nCrlfStyle = CRLF_STYLE_UNIX;
                    }
                  else
                    {
                      if (I < dwCurSize - 1 && pcBuf[I + 1] == _T ('\x0a'))
                        nCrlfStyle = CRLF_STYLE_DOS;
                      else
                        nCrlfStyle = CRLF_STYLE_MAC;
                    }
                }
            }

    ASSERT (nCrlfStyle >= 0 && nCrlfStyle <= 2);
    m_nCRLFMode = nCrlfStyle;
    LPCTSTR crlf = crlfs[nCrlfStyle];

    m_aLines.SetSize(0,4096);

    DWORD dwBufPtr = 0;
    int nCrlfPtr = 0;
    while (dwBufPtr < dwCurSize)
      {
        int c = pcBuf[dwBufPtr];
        dwBufPtr++;
        if (dwBufPtr == dwCurSize && dwCurSize == dwBufSize)
          {
            if (!::ReadFile (hFile, pcBuf, dwBufSize, &dwCurSize, NULL))
              __leave;
            dwBufPtr = 0;
          }

        pcLineBuf[nCurrentLength] = (TCHAR) c;
        nCurrentLength++;
        if (nCurrentLength == nCurrentMax)
          {
            //  Reallocate line buffer
            nCurrentMax += 256;
            LPTSTR pcNewBuf = new TCHAR[nCurrentMax];
            memcpy (pcNewBuf, pcLineBuf, nCurrentLength);
            delete pcLineBuf;
            pcLineBuf = pcNewBuf;
          }

        if ((TCHAR) c == crlf[nCrlfPtr])
          {
            nCrlfPtr++;
            if (crlf[nCrlfPtr] == 0)
              {
                pcLineBuf[nCurrentLength - nCrlfPtr] = 0;
                if (m_nSourceEncoding >= 0)
                  iconvert (pcLineBuf, m_nSourceEncoding, 1, m_nSourceEncoding == 15);
                InsertLine (pcLineBuf);
				AddLine(pcLineBuf);//for parser
                nCurrentLength = 0;
                nCrlfPtr = 0;
              }
          }
        else
          nCrlfPtr = 0;
      }

    pcLineBuf[nCurrentLength] = 0;
    InsertLine (pcLineBuf);

    ASSERT (m_aLines.GetSize () > 0);   //  At least one empty line must present

    m_bInit = TRUE;
    m_bReadOnly = (dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0;
    m_bModified = FALSE;
    m_bUndoGroup = m_bUndoBeginGroup = FALSE;
    m_nUndoBufSize = UNDO_BUF_SIZE;
    m_nSyncPosition = m_nUndoPosition = 0;
    ASSERT (m_aUndoBuf.GetSize () == 0);
    bSuccess = TRUE;

    RetypeViews (pszFileName);
    UpdateViews (NULL, NULL, UPDATE_RESET);
  }
  __finally
  {
    if (pcLineBuf != NULL)
      delete pcLineBuf;
      if (hFile != NULL)
        ::CloseHandle (hFile);
      }
	//BEGIN SW
	m_ptLastChange.x = m_ptLastChange.y = -1;
	//END SW
  return bSuccess;
}

BOOL CCrystalTextBuffer::SaveToFile(LPCTSTR pszFileName,
									 int nCrlfStyle /*= CRLF_STYLE_AUTOMATIC*/ ,
									 BOOL bClearModifiedFlag /*= TRUE*/ )
{
  ASSERT (nCrlfStyle == CRLF_STYLE_AUTOMATIC || nCrlfStyle == CRLF_STYLE_DOS ||
          nCrlfStyle == CRLF_STYLE_UNIX || nCrlfStyle == CRLF_STYLE_MAC);
  ASSERT (m_bInit);
  HANDLE hTempFile = INVALID_HANDLE_VALUE;
  HANDLE hSearch = INVALID_HANDLE_VALUE;
  TCHAR szTempFileDir[_MAX_PATH + 1];
  TCHAR szTempFileName[_MAX_PATH + 1];
  TCHAR szBackupFileName[_MAX_PATH + 1];
  BOOL bSuccess = FALSE;
  __try
  {
    TCHAR drive[_MAX_PATH], dir[_MAX_PATH], name[_MAX_PATH], ext[_MAX_PATH];
#ifdef _UNICODE
    _wsplitpath (pszFileName, drive, dir, name, ext);
#else
    _splitpath (pszFileName, drive, dir, name, ext);
#endif
    _tcscpy (szTempFileDir, drive);
    _tcscat (szTempFileDir, dir);
    _tcscpy (szBackupFileName, pszFileName);
    _tcscat (szBackupFileName, _T (".bak"));

    if (::GetTempFileName (szTempFileDir, _T ("CRE"), 0, szTempFileName) == 0)
      __leave;

      hTempFile =::CreateFile (szTempFileName, GENERIC_WRITE, 0, NULL,
                               CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
      if (hTempFile == INVALID_HANDLE_VALUE)
        __leave;

        if (nCrlfStyle == CRLF_STYLE_AUTOMATIC)
          nCrlfStyle = m_nCRLFMode;

          ASSERT (nCrlfStyle >= 0 && nCrlfStyle <= 2);
          LPCTSTR pszCRLF = crlfs[nCrlfStyle];
          int nCRLFLength = _tcslen (pszCRLF);

          int nLineCount = m_aLines.GetSize ();
          for (int nLine = 0; nLine < nLineCount; nLine++)
            {
              int nLength = m_aLines[nLine]->m_nLength;
              DWORD dwWrittenBytes;
              if (nLength > 0)
                {
                  LPCTSTR pszLine = m_aLines[nLine]->m_pcLine;
                  if (m_nSourceEncoding >= 0)
                    {
                      LPTSTR pszBuf;
                      iconvert_new (m_aLines[nLine]->m_pcLine, &pszBuf, 1, m_nSourceEncoding, m_nSourceEncoding == 15);
                      if (!::WriteFile (hTempFile, pszBuf, nLength, &dwWrittenBytes, NULL))
                        {
                          free (pszBuf);
                          __leave;
                        }
                      free (pszBuf);
                    }
                  else
                    if (!::WriteFile (hTempFile, pszLine, nLength, &dwWrittenBytes, NULL))
                      __leave;
                  if (nLength != (int) dwWrittenBytes)
                    __leave;
                }
              if (nLine < nLineCount - 1)     //  Last line must not end with CRLF

                {
                  if (!::WriteFile (hTempFile, pszCRLF, nCRLFLength, &dwWrittenBytes, NULL))
                    __leave;
                  if (nCRLFLength != (int) dwWrittenBytes)
                    __leave;
                }
            }
    ::CloseHandle (hTempFile);
    hTempFile = INVALID_HANDLE_VALUE;

    if (m_bCreateBackupFile)
      {
        WIN32_FIND_DATA wfd;
        hSearch =::FindFirstFile (pszFileName, &wfd);
        if (hSearch != INVALID_HANDLE_VALUE)
          {
            //  File exist - create backup file
            ::DeleteFile (szBackupFileName);
            if (!::MoveFile (pszFileName, szBackupFileName))
              __leave;
            ::FindClose (hSearch);
            hSearch = INVALID_HANDLE_VALUE;
          }
      }
    else
      {
        ::DeleteFile (pszFileName);
      }

    //  Move temporary file to target name
    if (!::MoveFile (szTempFileName, pszFileName))
      __leave;

      if (bClearModifiedFlag)
        {
          SetModified (FALSE);
          m_nSyncPosition = m_nUndoPosition;
        }
    bSuccess = TRUE;
  }
  __finally
  {
    if (hSearch != INVALID_HANDLE_VALUE)
      ::FindClose (hSearch);
      if (hTempFile != INVALID_HANDLE_VALUE)
        ::CloseHandle (hTempFile);
        ::DeleteFile (szTempFileName);
      }
      return bSuccess;
}

int CCrystalTextBuffer::GetCRLFMode()
{
  return m_nCRLFMode;
}

void CCrystalTextBuffer::SetCRLFMode(int nCRLFMode)
{
  /*ASSERT (nCRLFMode == CRLF_STYLE_DOS ||
          nCRLFMode == CRLF_STYLE_UNIX ||
          nCRLFMode == CRLF_STYLE_MAC);*/
  if (nCRLFMode >= 0)
    {
      m_nCRLFMode = nCRLFMode;
    }
}

int CCrystalTextBuffer::GetLineCount()
{
  ASSERT (m_bInit);             //  Text buffer not yet initialized.
  //  You must call InitNew() or LoadFromFile() first!

  return m_aLines.GetSize ();
}

int CCrystalTextBuffer::GetLineLength(int nLine)
{
  ASSERT (m_bInit);             //  Text buffer not yet initialized.
  //  You must call InitNew() or LoadFromFile() first!

  return m_aLines[nLine]->m_nLength;
}

LPTSTR CCrystalTextBuffer::GetLineChars(int nLine)
{
  ASSERT (m_bInit);             //  Text buffer not yet initialized.
  //  You must call InitNew() or LoadFromFile() first!

  return m_aLines[nLine]->m_pcLine;
}

DWORD CCrystalTextBuffer::GetLineFlags(int nLine)
{
  ASSERT (m_bInit);             //  Text buffer not yet initialized.
  //  You must call InitNew() or LoadFromFile() first!

  return m_aLines[nLine]->m_dwFlags;
}

static int FlagToIndex(DWORD dwFlag)
{
  int nIndex = 0;
  while ((dwFlag & 1) == 0)
    {
      dwFlag = dwFlag >> 1;
      nIndex++;
      if (nIndex == 32)
        return -1;
    }
  dwFlag = dwFlag & 0xFFFFFFFE;
  if (dwFlag != 0)
    return -1;
  return nIndex;

}

int CCrystalTextBuffer::FindLineWithFlag(DWORD dwFlag)
{
  int nSize = m_aLines.GetSize ();
  for (int L = 0; L < nSize; L++)
    {
      if ((m_aLines[L]->m_dwFlags & dwFlag) != 0)
        return L;
    }
  return -1;
}

int CCrystalTextBuffer::GetLineWithFlag(DWORD dwFlag)
{
  int nFlagIndex =::FlagToIndex (dwFlag);
  if (nFlagIndex < 0)
    {
      ASSERT (FALSE);           //  Invalid flag passed in

      return -1;
    }
  return FindLineWithFlag (dwFlag);
}

void CCrystalTextBuffer::SetLineFlag(int nLine, DWORD dwFlag, BOOL bSet,
									 BOOL bRemoveFromPreviousLine /*= TRUE*/ )
{
  ASSERT (m_bInit);             //  Text buffer not yet initialized.
  //  You must call InitNew() or LoadFromFile() first!

  int nFlagIndex =::FlagToIndex (dwFlag);
  if (nFlagIndex < 0)
    {
      ASSERT (FALSE);           //  Invalid flag passed in

      return;
    }

  if (nLine == -1)
    {
      ASSERT (!bSet);
      nLine = FindLineWithFlag (dwFlag);
      if (nLine == -1)
        return;
      bRemoveFromPreviousLine = FALSE;
    }

  DWORD dwNewFlags = m_aLines[nLine]->m_dwFlags;
  if (bSet)
    dwNewFlags = dwNewFlags | dwFlag;
  else
    dwNewFlags = dwNewFlags & ~dwFlag;

  if (m_aLines[nLine]->m_dwFlags != dwNewFlags)
    {
      if (bRemoveFromPreviousLine)
        {
          int nPrevLine = FindLineWithFlag (dwFlag);
          if (bSet)
            {
              if (nPrevLine >= 0)
                {
                  ASSERT ((m_aLines[nPrevLine]->m_dwFlags & dwFlag) != 0);
                  m_aLines[nPrevLine]->m_dwFlags &= ~dwFlag;
                  UpdateViews (NULL, NULL, UPDATE_SINGLELINE | UPDATE_FLAGSONLY, nPrevLine);
                }
            }
          else
            {
              ASSERT (nPrevLine == nLine);
            }
        }

      m_aLines[nLine]->m_dwFlags = dwNewFlags;
      UpdateViews (NULL, NULL, UPDATE_SINGLELINE | UPDATE_FLAGSONLY, nLine);
    }
}

void CCrystalTextBuffer::GetText(int nStartLine, int nStartChar, 
								  int nEndLine, int nEndChar, CString & text,
								  LPCTSTR pszCRLF /*= NULL*/ )
{
  ASSERT (m_bInit);             //  Text buffer not yet initialized.
  //  You must call InitNew() or LoadFromFile() first!

  ASSERT (nStartLine >= 0 && nStartLine < m_aLines.GetSize ());
  ASSERT (nStartChar >= 0 && nStartChar <= m_aLines[nStartLine]->m_nLength);
  ASSERT (nEndLine >= 0 && nEndLine < m_aLines.GetSize ());
  ASSERT (nEndChar >= 0 && nEndChar <= m_aLines[nEndLine]->m_nLength);
  ASSERT (nStartLine < nEndLine || nStartLine == nEndLine && nStartChar < nEndChar);

  if (pszCRLF == NULL)
    pszCRLF = crlf;
  int nCRLFLength = _tcslen (pszCRLF);
  ASSERT (nCRLFLength > 0);

  int nBufSize = 0;
  for (int L = nStartLine; L <= nEndLine; L++)
    {
      nBufSize += m_aLines[L]->m_nLength;
      nBufSize += nCRLFLength;
    }

  LPTSTR pszBuf = text.GetBuffer (nBufSize);

  if (nStartLine < nEndLine)
    {
      int nCount = m_aLines[nStartLine]->m_nLength - nStartChar;
      if (nCount > 0)
        {
          memcpy (pszBuf, m_aLines[nStartLine]->m_pcLine + nStartChar, sizeof (TCHAR) * nCount);
          pszBuf += nCount;
        }
      memcpy (pszBuf, pszCRLF, sizeof (TCHAR) * nCRLFLength);
      pszBuf += nCRLFLength;
      for (int I = nStartLine + 1; I < nEndLine; I++)
        {
          nCount = m_aLines[I]->m_nLength;
          if (nCount > 0)
            {
              memcpy (pszBuf, m_aLines[I]->m_pcLine, sizeof (TCHAR) * nCount);
              pszBuf += nCount;
            }
          memcpy (pszBuf, pszCRLF, sizeof (TCHAR) * nCRLFLength);
          pszBuf += nCRLFLength;
        }
      if (nEndChar > 0)
        {
          memcpy (pszBuf, m_aLines[nEndLine]->m_pcLine, sizeof (TCHAR) * nEndChar);
          pszBuf += nEndChar;
        }
    }
  else
    {
      int nCount = nEndChar - nStartChar;
      memcpy (pszBuf, m_aLines[nStartLine]->m_pcLine + nStartChar, sizeof (TCHAR) * nCount);
      pszBuf += nCount;
    }
  pszBuf[0] = 0;
  text.ReleaseBuffer ();
  text.FreeExtra ();
}

void CCrystalTextBuffer::AddView(CCrystalTextView * pView)
{
  m_lpViews.AddTail (pView);
}

void CCrystalTextBuffer::RemoveView(CCrystalTextView * pView)
{
  POSITION pos = m_lpViews.GetHeadPosition ();
  while (pos != NULL)
    {
      POSITION thispos = pos;
      CCrystalTextView *pvw = m_lpViews.GetNext (pos);
      if (pvw == pView)
        {
          m_lpViews.RemoveAt (thispos);
          return;
        }
    }
  ASSERT (FALSE);
}

CCrystalTextView::TextDefinition *CCrystalTextBuffer::RetypeViews(LPCTSTR lpszFileName)
{
  POSITION pos = m_lpViews.GetHeadPosition ();
  CString sNew = GetExt (lpszFileName);
  CCrystalTextView::TextDefinition *def = CCrystalTextView::GetTextType (sNew);
  while (pos != NULL)
  {
      CCrystalTextView *pView = m_lpViews.GetNext (pos);
      pView->SetTextType (def);
  }
  return def;
}

void CCrystalTextBuffer::UpdateViews (CCrystalTextView * pSource, 
									  CUpdateContext * pContext, 
									  DWORD dwUpdateFlags, int nLineIndex /*= -1*/ )
{
  POSITION pos = m_lpViews.GetHeadPosition ();
  while (pos != NULL)
  {
      CCrystalTextView *pView = m_lpViews.GetNext (pos);
      pView->UpdateView (pSource, pContext, dwUpdateFlags, nLineIndex);
  }
}


BOOL CCrystalTextBuffer::InternalInsertTextExt(CCrystalTextView * pSource, int nLine, 
						int nPos, LPCTSTR pszText, int &nEndLine, int &nEndChar)
{
	return InternalInsertText(pSource,nLine,nPos,pszText,nEndLine,nEndChar);

}

BOOL CCrystalTextBuffer::InternalDeleteTextExt(CCrystalTextView * pSource, int nStartLine, 
						int nStartPos, int nEndLine, int nEndPos)
{
	return InternalDeleteText(pSource,nStartLine,nStartPos,nEndLine,nEndPos);
}






BOOL CCrystalTextBuffer::InternalDeleteText (CCrystalTextView * pSource,
											 int nStartLine, int nStartChar,
											 int nEndLine, int nEndChar)
{
  ASSERT (m_bInit);             //  Text buffer not yet initialized.
  //  You must call InitNew() or LoadFromFile() first!

  ASSERT (nStartLine >= 0 && nStartLine < m_aLines.GetSize ());
  ASSERT (nStartChar >= 0 && nStartChar <= m_aLines[nStartLine]->m_nLength);
  ASSERT (nEndLine >= 0 && nEndLine < m_aLines.GetSize ());
  ASSERT (nEndChar >= 0 && nEndChar <= m_aLines[nEndLine]->m_nLength);
  ASSERT (nStartLine < nEndLine || nStartLine == nEndLine && nStartChar < nEndChar);
  
  if(m_bReadOnly)
    return FALSE;

  CDeleteContext context;
  context.m_ptStart.y = nStartLine;
  context.m_ptStart.x = nStartChar;
  context.m_ptEnd.y = nEndLine;
  context.m_ptEnd.x = nEndChar;

  if(nStartLine == nEndLine)
  {
      SLineInfo * li = m_aLines[nStartLine];
      if(nEndChar < li->m_nLength)
	  {
          memcpy (li->m_pcLine + nStartChar, li->m_pcLine + nEndChar,
                  sizeof (TCHAR) * (li->m_nLength - nEndChar));
	  }
      li->m_nLength -= (nEndChar - nStartChar);

      UpdateViews (pSource, &context, UPDATE_SINGLELINE | UPDATE_HORZRANGE, nStartLine);
  }
  else
  {
      int nRestCount = m_aLines[nEndLine]->m_nLength - nEndChar;
      LPTSTR pszRestChars = NULL;
      if(nRestCount > 0)
	  {
         pszRestChars = new TCHAR[nRestCount];
         memcpy (pszRestChars, m_aLines[nEndLine]->m_pcLine + nEndChar, nRestCount * sizeof (TCHAR));
	  }

      int nDelCount = nEndLine - nStartLine;

      for(int L = nStartLine + 1; L <= nEndLine; L++)
	  {
        delete m_aLines[L]->m_pcLine;
		delete m_aLines[L];
	  }
      m_aLines.RemoveAt(nStartLine + 1, nDelCount);


      //  nEndLine is no more valid
      m_aLines[nStartLine]->m_nLength = nStartChar;
      if(nRestCount > 0)
	  {
         AppendLine (nStartLine, pszRestChars, nRestCount);
         delete pszRestChars;
	  }

      UpdateViews (pSource, &context, UPDATE_HORZRANGE | UPDATE_VERTRANGE, nStartLine);
  }

  if (!m_bModified)
    SetModified (TRUE);
	//BEGIN SW
	// remember current cursor position as last editing position
	m_ptLastChange = context.m_ptStart;
	//END SW
  return TRUE;
}

BOOL CCrystalTextBuffer::InternalInsertText (CCrystalTextView * pSource,
											 int nLine, int nPos, LPCTSTR pszText,
											 int &nEndLine, int &nEndChar)
{
  ASSERT (m_bInit);             //  Text buffer not yet initialized.
  //  You must call InitNew() or LoadFromFile() first!
  ASSERT (nLine >= 0 && nLine < m_aLines.GetSize ());
  ASSERT (nPos >= 0 && nPos <= m_aLines[nLine]->m_nLength);
  if (m_bReadOnly)
    return FALSE;

  CInsertContext context;
  context.m_ptStart.x = nPos;
  context.m_ptStart.y = nLine;

  int nRestCount = m_aLines[nLine]->m_nLength - nPos;
  LPTSTR pszRestChars = NULL;

  if(nRestCount > 0)
  {
	
    pszRestChars = new TCHAR[nRestCount];
    memcpy (pszRestChars, m_aLines[nLine]->m_pcLine + nPos, nRestCount * sizeof (TCHAR));
    m_aLines[nLine]->m_nLength = nPos;
  }

  int nCurrentLine = nLine;
  BOOL bNewLines = FALSE;
  int nTextPos;
  for(;;)
  {
      nTextPos = 0;
      while (pszText[nTextPos] != 0 && pszText[nTextPos] != _T ('\r'))
        nTextPos++;

      if (nCurrentLine == nLine)
        {
          AppendLine (nLine, pszText, nTextPos);
        }
      else
        {
          InsertLine (pszText, nTextPos, nCurrentLine);
          bNewLines = TRUE;
        }

      if (pszText[nTextPos] == 0)
        {
          nEndLine = nCurrentLine;
          nEndChar = m_aLines[nCurrentLine]->m_nLength;
          AppendLine (nCurrentLine, pszRestChars, nRestCount);
          break;
        }

      nCurrentLine++;
      nTextPos++;

      if (pszText[nTextPos] == _T ('\n'))
        {
          nTextPos++;
        }
      else
        {
          ASSERT (FALSE);       //  Invalid line-end format passed

        }

      pszText += nTextPos;
  }

  if (pszRestChars != NULL)
    delete pszRestChars;

  context.m_ptEnd.x = nEndChar;
  context.m_ptEnd.y = nEndLine;


  if (bNewLines)
    UpdateViews (pSource, &context, UPDATE_HORZRANGE | UPDATE_VERTRANGE, nLine);
  else
    UpdateViews (pSource, &context, UPDATE_SINGLELINE | UPDATE_HORZRANGE, nLine);

  if (!m_bModified)
    SetModified (TRUE);
	//BEGIN SW
	// remember current cursor position as last editing position
	m_ptLastChange = context.m_ptEnd;
	//END SW
  return TRUE;
}


BOOL CCrystalTextBuffer::CanUndo()
{
  ASSERT (m_nUndoPosition >= 0 && m_nUndoPosition <= m_aUndoBuf.GetSize ());
  return m_nUndoPosition > 0;
}

BOOL CCrystalTextBuffer::CanRedo()
{
  ASSERT (m_nUndoPosition >= 0 && m_nUndoPosition <= m_aUndoBuf.GetSize ());
  return m_nUndoPosition < m_aUndoBuf.GetSize ();
}

POSITION CCrystalTextBuffer::GetUndoDescription(CString & desc,
												POSITION pos /*= NULL*/ )
{
  ASSERT (CanUndo ());          //  Please call CanUndo() first

  ASSERT ((m_aUndoBuf[0].m_dwFlags & UNDO_BEGINGROUP) != 0);

  int nPosition;
  if (pos == NULL)
    {
      //  Start from beginning
      nPosition = m_nUndoPosition;
    }
  else
    {
      nPosition = (int) pos;
      ASSERT (nPosition > 0 && nPosition < m_nUndoPosition);
      ASSERT ((m_aUndoBuf[nPosition].m_dwFlags & UNDO_BEGINGROUP) != 0);
    }

  //  Advance to next undo group
  nPosition--;
  while ((m_aUndoBuf[nPosition].m_dwFlags & UNDO_BEGINGROUP) == 0)
    nPosition--;

  //  Read description
  if (!GetActionDescription (m_aUndoBuf[nPosition].m_nAction, desc))
    desc.Empty ();              //  Use empty string as description

  //  Now, if we stop at zero position, this will be the last action,
  //  since we return (POSITION) nPosition
  return (POSITION) nPosition;
}

POSITION CCrystalTextBuffer::GetRedoDescription(CString & desc, 
												POSITION pos /*= NULL*/ )
{
  ASSERT (CanRedo ());          //  Please call CanRedo() before!

  ASSERT ((m_aUndoBuf[0].m_dwFlags & UNDO_BEGINGROUP) != 0);
  ASSERT ((m_aUndoBuf[m_nUndoPosition].m_dwFlags & UNDO_BEGINGROUP) != 0);

  int nPosition;
  if (pos == NULL)
    {
      //  Start from beginning
      nPosition = m_nUndoPosition;
    }
  else
    {
      nPosition = (int) pos;
      ASSERT (nPosition > m_nUndoPosition);
      ASSERT ((m_aUndoBuf[nPosition].m_dwFlags & UNDO_BEGINGROUP) != 0);
    }

  //  Read description
  if (!GetActionDescription (m_aUndoBuf[nPosition].m_nAction, desc))
    desc.Empty ();              //  Use empty string as description

  //  Advance to next undo group
  nPosition++;
  while (nPosition < m_aUndoBuf.GetSize () &&
        (m_aUndoBuf[nPosition].m_dwFlags & UNDO_BEGINGROUP) == 0)
    nPosition--;

  if (nPosition >= m_aUndoBuf.GetSize ())
    return NULL;                //  No more redo actions!

  return (POSITION) nPosition;
}

BOOL CCrystalTextBuffer::Undo(CPoint & ptCursorPos)
{
  ASSERT (CanUndo ());
  ASSERT ((m_aUndoBuf[0].m_dwFlags & UNDO_BEGINGROUP) != 0);
  for (;;)
    {
      m_nUndoPosition--;
      const SUndoRecord & ur = m_aUndoBuf[m_nUndoPosition];
      if (ur.m_dwFlags & UNDO_INSERT)
        {
#ifdef _ADVANCED_BUGCHECK
          //  Try to ensure that we undoing correctly...
          //  Just compare the text as it was before Undo operation
          CString text;
          GetText (ur.m_ptStartPos.y, ur.m_ptStartPos.x, ur.m_ptEndPos.y, ur.m_ptEndPos.x, text);
          ASSERT (lstrcmp (text, ur.GetText ()) == 0);
#endif
		  
          VERIFY (InternalDeleteTextExt(NULL, ur.m_ptStartPos.y, ur.m_ptStartPos.x, ur.m_ptEndPos.y, ur.m_ptEndPos.x)); 
		  ptCursorPos = ur.m_ptStartPos;
        } 
      else
        {
          int nEndLine, nEndChar;
          VERIFY (InternalInsertTextExt(NULL, ur.m_ptStartPos.y, ur.m_ptStartPos.x, ur.GetText (), nEndLine, nEndChar));
#ifdef _ADVANCED_BUGCHECK
          ASSERT (ur.m_ptEndPos.y == nEndLine);
          ASSERT (ur.m_ptEndPos.x == nEndChar);
#endif
          ptCursorPos = ur.m_ptEndPos;
        }
      if (ur.m_dwFlags & UNDO_BEGINGROUP)
        break;
    }
  if (m_bModified && m_nSyncPosition == m_nUndoPosition)
    SetModified (FALSE);
  if (!m_bModified && m_nSyncPosition != m_nUndoPosition)
    SetModified (TRUE);
  return TRUE;
}

BOOL CCrystalTextBuffer::Redo(CPoint & ptCursorPos)
{
  ASSERT (CanRedo ());
  ASSERT ((m_aUndoBuf[0].m_dwFlags & UNDO_BEGINGROUP) != 0);
  ASSERT ((m_aUndoBuf[m_nUndoPosition].m_dwFlags & UNDO_BEGINGROUP) != 0);
  for (;;)
    {
      const SUndoRecord & ur = m_aUndoBuf[m_nUndoPosition];
      if (ur.m_dwFlags & UNDO_INSERT)
        {
          int nEndLine, nEndChar;
          VERIFY (InternalInsertTextExt(NULL, ur.m_ptStartPos.y, ur.m_ptStartPos.x, ur.GetText (), nEndLine, nEndChar));
#ifdef _ADVANCED_BUGCHECK
          ASSERT (ur.m_ptEndPos.y == nEndLine);
          ASSERT (ur.m_ptEndPos.x == nEndChar);
#endif
          ptCursorPos = ur.m_ptEndPos;
        }
      else
        {
#ifdef _ADVANCED_BUGCHECK
          CString text;
          GetText (ur.m_ptStartPos.y, ur.m_ptStartPos.x, ur.m_ptEndPos.y, ur.m_ptEndPos.x, text);
          ASSERT (lstrcmp (text, ur.GetText ()) == 0);
#endif
          VERIFY (InternalDeleteTextExt(NULL, ur.m_ptStartPos.y, ur.m_ptStartPos.x, ur.m_ptEndPos.y, ur.m_ptEndPos.x));
          ptCursorPos = ur.m_ptStartPos;
        }
      m_nUndoPosition++;
      if (m_nUndoPosition == m_aUndoBuf.GetSize ())
        break;
      if ((m_aUndoBuf[m_nUndoPosition].m_dwFlags & UNDO_BEGINGROUP) != 0)
        break;
    }
  if (m_bModified && m_nSyncPosition == m_nUndoPosition)
    SetModified (FALSE);
  if (!m_bModified && m_nSyncPosition != m_nUndoPosition)
    SetModified (TRUE);
  return TRUE;
}

//  [JRT] Support For Descriptions On Undo/Redo Actions
void CCrystalTextBuffer::AddUndoRecord (BOOL bInsert, 
										const CPoint & ptStartPos, 
										const CPoint & ptEndPos, 
										LPCTSTR pszText, int nActionType)
{
  //  Forgot to call BeginUndoGroup()?
  ASSERT (m_bUndoGroup);
  ASSERT (m_aUndoBuf.GetSize () == 0 || (m_aUndoBuf[0].m_dwFlags & UNDO_BEGINGROUP) != 0);

  //  Strip unnecessary undo records (edit after undo)
  int nBufSize = m_aUndoBuf.GetSize ();
  if(m_nUndoPosition < nBufSize)
  {
     for (int I = m_nUndoPosition; I < nBufSize; I++)
        m_aUndoBuf[I].FreeText ();
     m_aUndoBuf.SetSize (m_nUndoPosition);
  }

  //  If undo buffer size is close to critical, remove the oldest records
  ASSERT (m_aUndoBuf.GetSize () <= m_nUndoBufSize);
  nBufSize = m_aUndoBuf.GetSize ();
  if(nBufSize >= m_nUndoBufSize)
  {
      int nIndex = 0;
      for(;;)
      {
         m_aUndoBuf[nIndex].FreeText ();
         nIndex++;
         if(nIndex == nBufSize || (m_aUndoBuf[nIndex].m_dwFlags & UNDO_BEGINGROUP) != 0)
            break;
      }
      m_aUndoBuf.RemoveAt (0, nIndex);
  }
  ASSERT(m_aUndoBuf.GetSize () < m_nUndoBufSize);

  //  Add new record
  SUndoRecord ur;
  ur.m_dwFlags = bInsert ? UNDO_INSERT : 0;
  ur.m_nAction = nActionType;
  if(m_bUndoBeginGroup)
  {
     ur.m_dwFlags |= UNDO_BEGINGROUP;
     m_bUndoBeginGroup = FALSE;
  }
  ur.m_ptStartPos = ptStartPos;
  ur.m_ptEndPos = ptEndPos;
  ur.SetText(pszText);

  m_aUndoBuf.Add(ur);
  m_nUndoPosition = m_aUndoBuf.GetSize ();

  ASSERT(m_aUndoBuf.GetSize () <= m_nUndoBufSize);
}


BOOL CCrystalTextBuffer::InsertText(CCrystalTextView * pSource, 
									 int nLine, int nPos, LPCTSTR pszText,
            int &nEndLine, int &nEndChar, int nAction)
{
  if (!InternalInsertText (pSource, nLine, nPos, pszText, nEndLine, nEndChar))
    return FALSE;


  BOOL bGroupFlag = FALSE;
  if (!m_bUndoGroup)
    {
      BeginUndoGroup ();
      bGroupFlag = TRUE;
    }
  AddUndoRecord (TRUE, CPoint (nPos, nLine), CPoint (nEndChar, nEndLine), pszText, nAction);
  if (bGroupFlag)
    FlushUndoGroup (pSource);
  return TRUE;
}

BOOL CCrystalTextBuffer::DeleteText (CCrystalTextView * pSource,
									 int nStartLine, int nStartChar,
            int nEndLine, int nEndChar, int nAction)
{
  CString sTextToDelete;
  GetText(nStartLine, nStartChar, nEndLine, nEndChar, sTextToDelete);

  if (!InternalDeleteText(pSource, nStartLine, nStartChar, nEndLine, nEndChar))
    return FALSE;

  BOOL bGroupFlag = FALSE;
  if (!m_bUndoGroup)
    {
      BeginUndoGroup ();
      bGroupFlag = TRUE;
    }
  AddUndoRecord (FALSE, CPoint (nStartChar, nStartLine), CPoint (nEndChar, nEndLine), sTextToDelete, nAction);
  if (bGroupFlag)
    FlushUndoGroup (pSource);

  return TRUE;
}


BOOL CCrystalTextBuffer::InsertTextExt(CCrystalTextView * pSource, int nLine, 
				int nPos,LPCTSTR pszText, int &nEndLine, int &nEndChar, 
				   int nAction /*= CE_ACTION_UNKNOWN*/)
{

  return InsertText(pSource,nLine,nPos,pszText,nEndLine,nEndChar,nAction);
}

BOOL CCrystalTextBuffer::DeleteTextExt(CCrystalTextView * pSource, int nStartLine, 
				   int nStartPos, int nEndLine, int nEndPos, 
				   int nAction /*= CE_ACTION_UNKNOWN*/)
{
  return DeleteText(pSource,nStartLine,nStartPos,nEndLine,nEndPos,nAction);
}



BOOL CCrystalTextBuffer::GetActionDescription (int nAction, CString & desc)
{
  HINSTANCE hOldResHandle = AfxGetResourceHandle ();
#ifdef CRYSEDIT_RES_HANDLE
  AfxSetResourceHandle (CRYSEDIT_RES_HANDLE);
#else
  if (CCrystalTextView::s_hResourceInst != NULL)
    AfxSetResourceHandle (CCrystalTextView::s_hResourceInst);
#endif
  BOOL bSuccess = FALSE;
  switch (nAction)
    {
    case CE_ACTION_PASTE:
      bSuccess = desc.LoadString (IDS_EDITOP_PASTE);
      break;
    case CE_ACTION_DELSEL:
      bSuccess = desc.LoadString (IDS_EDITOP_DELSELECTION);
      break;
    case CE_ACTION_CUT:
      bSuccess = desc.LoadString (IDS_EDITOP_CUT);
      break;
    case CE_ACTION_TYPING:
      bSuccess = desc.LoadString (IDS_EDITOP_TYPING);
      break;
    case CE_ACTION_BACKSPACE:
      bSuccess = desc.LoadString (IDS_EDITOP_BACKSPACE);
      break;
    case CE_ACTION_INDENT:
      bSuccess = desc.LoadString (IDS_EDITOP_INDENT);
      break;
    case CE_ACTION_DRAGDROP:
      bSuccess = desc.LoadString (IDS_EDITOP_DRAGDROP);
      break;
    case CE_ACTION_REPLACE:
      bSuccess = desc.LoadString (IDS_EDITOP_REPLACE);
      break;
    case CE_ACTION_DELETE:
      bSuccess = desc.LoadString (IDS_EDITOP_DELETE);
      break;
    case CE_ACTION_AUTOINDENT:
      bSuccess = desc.LoadString (IDS_EDITOP_AUTOINDENT);
      break;
    case CE_ACTION_AUTOCOMPLETE:
      bSuccess = desc.LoadString (IDS_EDITOP_AUTOCOMPLETE);
      break;
    case CE_ACTION_AUTOEXPAND:
      bSuccess = desc.LoadString (IDS_EDITOP_AUTOEXPAND);
      break;
    case CE_ACTION_LOWERCASE:
      bSuccess = desc.LoadString (IDS_EDITOP_LOWERCASE);
      break;
    case CE_ACTION_UPPERCASE:
      bSuccess = desc.LoadString (IDS_EDITOP_UPPERCASE);
      break;
    case CE_ACTION_SWAPCASE:
      bSuccess = desc.LoadString (IDS_EDITOP_SWAPCASE);
      break;
    case CE_ACTION_CAPITALIZE:
      bSuccess = desc.LoadString (IDS_EDITOP_CAPITALIZE);
      break;
    case CE_ACTION_SENTENCIZE:
      bSuccess = desc.LoadString (IDS_EDITOP_SENTENCIZE);
      break;
    case CE_ACTION_RECODE:
      bSuccess = desc.LoadString (IDS_EDITOP_RECODE);
      break;
    case CE_ACTION_SPELL:
      bSuccess = desc.LoadString (IDS_EDITOP_SPELL);
      break;
    default: /* case CE_ACTION_UNKNOWN: */
      bSuccess = desc.LoadString (IDS_EDITOP_UNKNOWN);
    }
  AfxSetResourceHandle (hOldResHandle);
  return bSuccess;
}

void CCrystalTextBuffer::SetModified(BOOL bModified /*= TRUE*/ )
{
  m_bModified = bModified;
}

void CCrystalTextBuffer::BeginUndoGroup(BOOL bMergeWithPrevious /*= FALSE*/ )
{
  ASSERT (!m_bUndoGroup);
  m_bUndoGroup = TRUE;
  m_bUndoBeginGroup = m_nUndoPosition == 0 || !bMergeWithPrevious;
}

void CCrystalTextBuffer::FlushUndoGroup(CCrystalTextView * pSource)
{
  ASSERT (m_bUndoGroup);
  if(pSource != NULL)
  {
     ASSERT(m_nUndoPosition == m_aUndoBuf.GetSize());
     if(m_nUndoPosition > 0)
     {
        m_bUndoBeginGroup = TRUE;
        pSource->OnEditOperation(m_aUndoBuf[m_nUndoPosition - 1].m_nAction, 
			                    m_aUndoBuf[m_nUndoPosition - 1].GetText());
	 }
  }
  m_bUndoGroup = FALSE;
}

int CCrystalTextBuffer::FindNextBookmarkLine(int nCurrentLine)
{
  BOOL bWrapIt = TRUE;
  DWORD dwFlags = GetLineFlags (nCurrentLine);
  if ((dwFlags & LF_BOOKMARKS) != 0)
    nCurrentLine++;

  int nSize = m_aLines.GetSize ();
  for (;;)
    {
      while (nCurrentLine < nSize)
        {
          if ((m_aLines[nCurrentLine]->m_dwFlags & LF_BOOKMARKS) != 0)
            return nCurrentLine;
          // Keep going
          nCurrentLine++;
        }
      // End of text reached
      if (!bWrapIt)
        return -1;

      // Start from the beginning of text
      bWrapIt = FALSE;
      nCurrentLine = 0;
    }
  return -1;
}

int CCrystalTextBuffer::FindPrevBookmarkLine(int nCurrentLine)
{
  BOOL bWrapIt = TRUE;
  DWORD dwFlags = GetLineFlags (nCurrentLine);
  if ((dwFlags & LF_BOOKMARKS) != 0)
    nCurrentLine--;

  int nSize = m_aLines.GetSize ();
  for (;;)
    {
      while (nCurrentLine >= 0)
        {
          if ((m_aLines[nCurrentLine]->m_dwFlags & LF_BOOKMARKS) != 0)
            return nCurrentLine;
          // Keep moving up
          nCurrentLine--;
        }
      // Beginning of text reached
      if (!bWrapIt)
        return -1;

      // Start from the end of text
      bWrapIt = FALSE;
      nCurrentLine = nSize - 1;
    }
  return -1;
}
#include <mbctype.h>
BOOL CCrystalTextBuffer::IsMBSLead(int nLine, int nCol)
{
  ASSERT (m_bInit);             //  Text buffer not yet initialized.
  //  You must call InitNew() or LoadFromFile() first!

#ifdef _UNICODE
  LPCTSTR string = (LPCTSTR) GetLineChars (nLine);
  LPCTSTR current = string + nCol;
  return FALSE;
#else // _UNICODE
  const unsigned char *string = (const unsigned char *) GetLineChars (nLine);
  const unsigned char *current = string + nCol;
  if (_ismbslead (string, current) < 0)
    return TRUE;
  return FALSE;
#endif // _UNICODE
}

BOOL CCrystalTextBuffer::IsMBSTrail(int nLine, int nCol)
{
  ASSERT (m_bInit);             //  Text buffer not yet initialized.
  //  You must call InitNew() or LoadFromFile() first!

#ifdef _UNICODE
  LPCTSTR string = (LPCTSTR) GetLineChars (nLine);
  LPCTSTR current = string + nCol;
  return FALSE;
#else // _UNICODE
  const unsigned char *string = (const unsigned char *) GetLineChars (nLine);
  const unsigned char *current = string + nCol;
  if (_ismbstrail (string, current) < 0)
    return TRUE;
  return FALSE;
#endif // _UNICODE
}

//BEGIN SW
CPoint CCrystalTextBuffer::GetLastChangePos() const
{
	return m_ptLastChange;
}
//END SW

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
biography? I am not that old yet.

Comments and Discussions