Click here to Skip to main content
15,893,588 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.6K   3.4K   41  
This is a partially implemented IDE for the Java platform.
////////////////////////////////////////////////////////////////////////////
//  File:       ccrystaltextview.cpp
//  Version:    1.2.0.5
//  Created:    29-Dec-1998
//
//  Author:     Stcherbatchenko Andrei
//  E-mail:     windfall@gmx.de
//
//  Implementation of the CCrystalTextView 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:    missing UpdateCaret() in CCrystalTextView::SetFont
//  FIX:    missing UpdateCaret() in CCrystalTextView::RecalcVertScrollBar
//  FIX:    mistype in CCrystalTextView::RecalcPageLayouts + instead of +=
//  FIX:    removed condition 'm_nLineHeight < 20' in
//      CCrystalTextView::CalcLineCharDim(). This caused painting defects
//      when using very small fonts.
//
//  FEATURE:    Some experiments with smooth scrolling, controlled by
//      m_bSmoothScroll member variable, by default turned off.
//      See ScrollToLine function for implementation details.
////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
//  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
//
//  +   FIX:  ResetView() now virtual
//  +   FEATURE: Added OnEditOperation() virtual: base for auto-indent,
//      smart indent etc.
////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
//  19-Jul-99
//      Ferdinand Prantl:
//  +   FEATURE: regular expressions, go to line and things ...
//  +   FEATURE: plenty of syntax highlighting definitions
//  +   FEATURE: corrected bug in syntax highlighting C comments
//  +   FEATURE: extended registry support for saving settings
//  +   FEATURE: some other things I've forgotten ...
//
//  ... it's being edited very rapidly so sorry for non-commented
//        and maybe "ugly" code ...
////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
//	01-Jun-99 to 31-Aug-99
//		Sven Wiegand (search for "//BEGIN SW" to find my changes):
//
//	+ FEATURE: support for language switching on the fly with class 
//			CCrystalParser
//	+	FEATURE: word wrapping
//	+ FIX:	Setting m_nIdealCharPos, when choosing cursor position by mouse
//	+ FIX:	Backward search
//	+ FEATURE: incremental search
////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
//	24-Oct-99
//		Sven Wiegand
//
//	+ FIX: Opening large files won't crash anymore and will go very fast
//	       (removed call to RecalcVertScrollBar() in WrapLineCached())
//	+ FIX: Problems with repainting and cursor-position by resizing window 
//	       fixed by adding call to ScrollToSubLine() in OnSize().
//	+ FEATURE: Supporting [Return] to exit incremental-search-mode
//		     (see OnChar())
///////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <malloc.h>
#include "editcmd.h"
#include "editreg.h"
#include "ccrystaltextview.h"
#include "ccrystaltextbuffer.h"
#include "cfindtextdlg.h"
#include "fpattern.h"
#include "filesup.h"
#include "registry.h"
#include "gotodlg.h"
#include "resource.h"
#include "browser.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

#define TAB_CHARACTER               _T('\xBB')
#define SPACE_CHARACTER             _T('\x95')
#define DEFAULT_PRINT_MARGIN        1000    //  10 millimeters

#define SMOOTH_SCROLL_FACTOR        6

#pragma warning ( disable : 4100 )
////////////////////////////////////////////////////////////////////////////
// CCrystalTextView

#define COOKIE_SLOT 0x0
#define DATA_SLOT   0x1
#define COOKIE_COLAPSED         0x0100



#define BACK_GRND 1
#define FORE_GRND 0


LOGFONT CCrystalTextView::m_LogFont;

IMPLEMENT_DYNCREATE (CCrystalTextView, CView)

HINSTANCE CCrystalTextView::s_hResourceInst = NULL;

BEGIN_MESSAGE_MAP (CCrystalTextView, CView)
//{{AFX_MSG_MAP(CCrystalTextView)
ON_WM_DESTROY ()
ON_WM_ERASEBKGND ()
ON_WM_SIZE ()
ON_WM_VSCROLL ()
ON_WM_SETCURSOR ()
ON_WM_LBUTTONDOWN ()
ON_WM_SETFOCUS ()
ON_WM_HSCROLL ()
ON_WM_LBUTTONUP ()
ON_WM_MOUSEMOVE ()
ON_WM_TIMER ()
ON_WM_KILLFOCUS ()
ON_WM_LBUTTONDBLCLK ()
ON_COMMAND (ID_EDIT_COPY, OnEditCopy)
ON_UPDATE_COMMAND_UI (ID_EDIT_COPY, OnUpdateEditCopy)
ON_COMMAND (ID_EDIT_SELECT_ALL, OnEditSelectAll)
ON_UPDATE_COMMAND_UI (ID_EDIT_SELECT_ALL, OnUpdateEditSelectAll)
ON_WM_RBUTTONDOWN ()
ON_WM_SYSCOLORCHANGE ()
ON_WM_CREATE ()
ON_COMMAND (ID_EDIT_FIND, OnEditFind)
ON_COMMAND (ID_EDIT_REPEAT, OnEditRepeat)
ON_UPDATE_COMMAND_UI (ID_EDIT_REPEAT, OnUpdateEditRepeat)
ON_COMMAND (ID_EDIT_FIND_PREVIOUS, OnEditFindPrevious)
ON_UPDATE_COMMAND_UI (ID_EDIT_FIND_PREVIOUS, OnUpdateEditFindPrevious)
ON_WM_MOUSEWHEEL ()
//}}AFX_MSG_MAP
ON_COMMAND (ID_EDIT_CHAR_LEFT, OnCharLeft)
ON_COMMAND (ID_EDIT_EXT_CHAR_LEFT, OnExtCharLeft)
ON_COMMAND (ID_EDIT_CHAR_RIGHT, OnCharRight)
ON_COMMAND (ID_EDIT_EXT_CHAR_RIGHT, OnExtCharRight)
ON_COMMAND (ID_EDIT_WORD_LEFT, OnWordLeft)
ON_COMMAND (ID_EDIT_EXT_WORD_LEFT, OnExtWordLeft)
ON_COMMAND (ID_EDIT_WORD_RIGHT, OnWordRight)
ON_COMMAND (ID_EDIT_EXT_WORD_RIGHT, OnExtWordRight)
ON_COMMAND (ID_EDIT_LINE_UP, OnLineUp)
ON_COMMAND (ID_EDIT_EXT_LINE_UP, OnExtLineUp)
ON_COMMAND (ID_EDIT_LINE_DOWN, OnLineDown)
ON_COMMAND (ID_EDIT_EXT_LINE_DOWN, OnExtLineDown)
ON_COMMAND (ID_EDIT_SCROLL_UP, ScrollUp)
ON_COMMAND (ID_EDIT_SCROLL_DOWN, ScrollDown)
ON_COMMAND (ID_EDIT_PAGE_UP, OnPageUp)
ON_COMMAND (ID_EDIT_EXT_PAGE_UP, OnExtPageUp)
ON_COMMAND (ID_EDIT_PAGE_DOWN, OnPageDown)
ON_COMMAND (ID_EDIT_EXT_PAGE_DOWN, OnExtPageDown)
ON_COMMAND (ID_EDIT_LINE_END, OnLineEnd)
ON_COMMAND (ID_EDIT_EXT_LINE_END, OnExtLineEnd)
ON_COMMAND (ID_EDIT_HOME, OnHome)
ON_COMMAND (ID_EDIT_EXT_HOME, OnExtHome)
ON_COMMAND (ID_EDIT_TEXT_BEGIN, OnTextBegin)
ON_COMMAND (ID_EDIT_EXT_TEXT_BEGIN, OnExtTextBegin)
ON_COMMAND (ID_EDIT_TEXT_END, OnTextEnd)
ON_COMMAND (ID_EDIT_EXT_TEXT_END, OnExtTextEnd)
//  Standard printing commands
ON_COMMAND (ID_FILE_PAGE_SETUP, OnFilePageSetup)
ON_COMMAND (ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND (ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND (ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
//  Status
ON_UPDATE_COMMAND_UI (ID_EDIT_INDICATOR_CRLF, OnUpdateIndicatorCRLF)
ON_UPDATE_COMMAND_UI (ID_EDIT_INDICATOR_POSITION, OnUpdateIndicatorPosition)
//  Bookmarks
ON_COMMAND_RANGE (ID_EDIT_TOGGLE_BOOKMARK0, ID_EDIT_TOGGLE_BOOKMARK9, OnToggleBookmark)
ON_COMMAND_RANGE (ID_EDIT_GO_BOOKMARK0, ID_EDIT_GO_BOOKMARK9, OnGoBookmark)
ON_COMMAND (ID_EDIT_CLEAR_BOOKMARKS, OnClearBookmarks)
// More Bookmarks
ON_COMMAND (ID_EDIT_TOGGLE_BOOKMARK, OnToggleBookmark)
ON_COMMAND (ID_EDIT_GOTO_NEXT_BOOKMARK, OnNextBookmark)
ON_COMMAND (ID_EDIT_GOTO_PREV_BOOKMARK, OnPrevBookmark)
ON_COMMAND (ID_EDIT_CLEAR_ALL_BOOKMARKS, OnClearAllBookmarks)
ON_UPDATE_COMMAND_UI (ID_EDIT_GOTO_NEXT_BOOKMARK, OnUpdateNextBookmark)
ON_UPDATE_COMMAND_UI (ID_EDIT_GOTO_PREV_BOOKMARK, OnUpdatePrevBookmark)
ON_UPDATE_COMMAND_UI (ID_EDIT_CLEAR_ALL_BOOKMARKS, OnUpdateClearAllBookmarks)
// Ferdi's source type chnages
ON_COMMAND_RANGE (ID_SOURCE_PLAIN, ID_SOURCE_TEX, OnSourceType)
ON_UPDATE_COMMAND_UI_RANGE (ID_SOURCE_PLAIN, ID_SOURCE_TEX, OnUpdateSourceType)
ON_COMMAND (ID_EDIT_MATCHBRACE, OnMatchBrace)
ON_UPDATE_COMMAND_UI (ID_EDIT_MATCHBRACE, OnUpdateMatchBrace)
ON_COMMAND (ID_EDIT_GOTO, OnEditGoTo)
ON_UPDATE_COMMAND_UI (ID_VIEW_TOGGLE_SRC_HDR, OnUpdateToggleSourceHeader)
ON_COMMAND (ID_VIEW_TOGGLE_SRC_HDR, OnToggleSourceHeader)
ON_UPDATE_COMMAND_UI (ID_VIEW_SELMARGIN, OnUpdateSelMargin)
ON_COMMAND (ID_VIEW_SELMARGIN, OnSelMargin)
ON_UPDATE_COMMAND_UI (ID_VIEW_WORDWRAP, OnUpdateWordWrap)
ON_COMMAND (ID_VIEW_WORDWRAP, OnWordWrap)
ON_COMMAND (ID_FORCE_REDRAW, OnForceRedraw)
	//BEGIN SW
	// incremental search
	ON_COMMAND(ID_EDIT_FIND_INCREMENTAL_FORWARD, OnEditFindIncrementalForward)
	ON_COMMAND(ID_EDIT_FIND_INCREMENTAL_BACKWARD, OnEditFindIncrementalBackward)
	ON_UPDATE_COMMAND_UI(ID_EDIT_FIND_INCREMENTAL_FORWARD, OnUpdateEditFindIncrementalForward)
	ON_UPDATE_COMMAND_UI(ID_EDIT_FIND_INCREMENTAL_BACKWARD, OnUpdateEditFindIncrementalBackward)
	//END SW
END_MESSAGE_MAP ()

#define EXPAND_PRIMITIVE(impl, func)    \
void CCrystalTextView::On##func() { impl(FALSE); }  \
void CCrystalTextView::OnExt##func() { impl(TRUE); }
EXPAND_PRIMITIVE (MoveLeft, CharLeft)
EXPAND_PRIMITIVE (MoveRight, CharRight)
EXPAND_PRIMITIVE (MoveWordLeft, WordLeft)
EXPAND_PRIMITIVE (MoveWordRight, WordRight)
EXPAND_PRIMITIVE (MoveUp, LineUp)
EXPAND_PRIMITIVE (MoveDown, LineDown)
EXPAND_PRIMITIVE (MovePgUp, PageUp)
EXPAND_PRIMITIVE (MovePgDn, PageDown)
EXPAND_PRIMITIVE (MoveHome, Home)
EXPAND_PRIMITIVE (MoveEnd, LineEnd)
EXPAND_PRIMITIVE (MoveCtrlHome, TextBegin)
EXPAND_PRIMITIVE (MoveCtrlEnd, TextEnd)
#undef EXPAND_PRIMITIVE

CCrystalTextView::TextDefinition CCrystalTextView::m_SourceDefs[] =
  {
    CCrystalTextView::SRC_PLAIN, _T ("Plain"), _T ("txt,doc,diz"), CCrystalTextView::ParseLinePlain, SRCOPT_AUTOINDENT, 4, _T (""), _T (""), _T (""), -1,
    CCrystalTextView::SRC_ASP, _T ("ASP"), _T ("asp"), CCrystalTextView::ParseLineAsp, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU, 2, _T (""), _T (""), _T ("'"), -1,
    CCrystalTextView::SRC_BASIC, _T ("Basic"), _T ("bas,vb,vbs,frm,dsm"), CCrystalTextView::ParseLineBasic, SRCOPT_AUTOINDENT, 4, _T (""), _T (""), _T ("\'"), -1,
    CCrystalTextView::SRC_BATCH, _T ("Batch"), _T ("bat,btm,cmd"), CCrystalTextView::ParseLineBatch, SRCOPT_INSERTTABS|SRCOPT_AUTOINDENT, 4, _T (""), _T (""), _T ("rem "), -1,
    CCrystalTextView::SRC_C, _T ("C"), _T ("c,cc,cpp,cxx,h,hpp.hxx,hm,inl,rh,tlh,tli,xs"), CCrystalTextView::ParseLineC, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU, 2, _T ("/*"), _T ("*/"), _T ("//"), -1,
    CCrystalTextView::SRC_DCL, _T ("DCL"), _T ("dcl,dcc"), CCrystalTextView::ParseLineDcl, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU, 2, _T ("/*"), _T ("*/"), _T ("//"), -1,
    CCrystalTextView::SRC_FORTRAN, _T ("Fortran"), _T ("f,f90,f9p,fpp"), CCrystalTextView::ParseLineFortran, SRCOPT_INSERTTABS|SRCOPT_AUTOINDENT, 8, _T (""), _T (""), _T ("!"), -1,
    CCrystalTextView::SRC_HTML, _T ("HTML"), _T ("html,htm,shtml,ihtml,ssi"), CCrystalTextView::ParseLineHtml, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, 2, _T ("<!--"), _T ("-->"), _T (""), -1,
    CCrystalTextView::SRC_INSTALLSHIELD, _T ("InstallShield"), _T ("rul"), CCrystalTextView::ParseLineIS, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, 2, _T ("/*"), _T ("*/"), _T ("//"), -1,
    CCrystalTextView::SRC_JAVA, _T ("Java"), _T ("java,jav,js"), CCrystalTextView::ParseLineJava, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU, 2, _T ("/*"), _T ("*/"), _T ("//"), -1,
    CCrystalTextView::SRC_LISP, _T ("AutoLISP"), _T ("lsp"), CCrystalTextView::ParseLineLisp, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, 2, _T (";|"), _T ("|;"), _T (";"), -1,
    CCrystalTextView::SRC_PASCAL, _T ("Pascal"), _T ("pas"), CCrystalTextView::ParseLinePascal, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU, 2, _T ("{"), _T ("}"), _T (""), -1,
    CCrystalTextView::SRC_PERL, _T ("Perl"), _T ("pl"), CCrystalTextView::ParseLinePerl, SRCOPT_AUTOINDENT|SRCOPT_EOLNUNIX, 4, _T (""), _T (""), _T ("#"), -1,
    CCrystalTextView::SRC_PHP, _T ("PHP"), _T ("php,php3,php4"), CCrystalTextView::ParseLinePhp, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU, 2, _T ("/*"), _T ("*/"), _T ("//"), -1,
    CCrystalTextView::SRC_PYTHON, _T ("Python"), _T ("py"), CCrystalTextView::ParseLinePython, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU, 2, _T ("/*"), _T ("*/"), _T ("//"), -1,
    CCrystalTextView::SRC_REXX, _T ("REXX"), _T ("rex,rexx,cmd"), CCrystalTextView::ParseLineRexx, SRCOPT_AUTOINDENT, 4, _T ("/*"), _T ("*/"), _T ("//"), -1,
    CCrystalTextView::SRC_RSRC, _T ("Resources"), _T ("rc,dlg"), CCrystalTextView::ParseLineRsrc, SRCOPT_AUTOINDENT, 4, _T ("/*"), _T ("*/"), _T ("//"), -1,
    CCrystalTextView::SRC_SGML, _T ("Sgml"), _T ("sgml"), CCrystalTextView::ParseLineSgml, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, 2, _T ("<!--"), _T ("-->"), _T (""), -1,
    CCrystalTextView::SRC_SH, _T ("Shell"), _T ("sh,conf"), CCrystalTextView::ParseLineSh, SRCOPT_INSERTTABS|SRCOPT_AUTOINDENT|SRCOPT_EOLNUNIX, 4, _T (""), _T (""), _T ("#"), -1,
    CCrystalTextView::SRC_SIOD, _T ("SIOD"), _T ("scm"), CCrystalTextView::ParseLineSiod, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU, 2, _T (";|"), _T ("|;"), _T (";"), -1,
    CCrystalTextView::SRC_SQL, _T ("SQL"), _T ("sql"), CCrystalTextView::ParseLineSql, SRCOPT_AUTOINDENT, 4, _T ("/*"), _T ("*/"), _T ("//"), -1,
    CCrystalTextView::SRC_TCL, _T ("TCL"), _T ("tcl"), CCrystalTextView::ParseLineTcl, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU|SRCOPT_EOLNUNIX, 2, _T (""), _T (""), _T ("#"), -1,
    CCrystalTextView::SRC_TEX, _T ("TEX"), _T ("tex,sty,cls,clo,ltx,fd,dtx"), CCrystalTextView::ParseLineTex, SRCOPT_AUTOINDENT, 4, _T (""), _T (""), _T ("%"), -1
  };

/////////////////////////////////////////////////////////////////////////////
// CCrystalTextView construction/destruction

BOOL MatchType (CString pattern, LPCTSTR lpszExt)
{
  CString part;
  int pos, len = pattern.GetLength ();

  while ((pos = pattern.Find (_T (','))) != -1)
  {
     part = pattern.Left (pos);
     if(!part.IsEmpty () && fpattern_isvalid (part))
          if(fpattern_matchn (part, lpszExt))
              return TRUE;
     len -= pos + 1;
     pattern = pattern.Right (len);
  }

  if(!pattern.IsEmpty () && fpattern_isvalid (pattern))
     if(fpattern_matchn (pattern, lpszExt))
          return TRUE;
  return FALSE;
}

bool CCrystalTextView::DoSetTextType(TextDefinition *def)
{
  m_CurSourceDef = def;
  SetFlags (def->flags);

  SetWordWrapping ((def->flags & SRCOPT_WORDWRAP) != FALSE);
  SetSelectionMargin ((def->flags & SRCOPT_SELMARGIN) != FALSE);

  SetTabSize (def->tabsize);
  SetViewTabs ((def->flags & SRCOPT_SHOWTABS) != FALSE);
  
  int nEoln;
  if(def->flags & SRCOPT_EOLNDOS)
      nEoln = 0;
  else if(def->flags & SRCOPT_EOLNUNIX)
      nEoln = 1;
  else if(def->flags & SRCOPT_EOLNMAC)
      nEoln = 2;
  else /* eoln auto */
      nEoln = -1;
  SetCRLFMode (nEoln);
  return true;
}

CCrystalTextView::TextDefinition* CCrystalTextView::GetTextType (LPCTSTR pszExt)
{
  TextDefinition *def;
  CString sExt = pszExt;

  def = CCrystalTextView::m_SourceDefs;
  sExt.MakeLower();

  for (int i = 0; i < countof(CCrystalTextView::m_SourceDefs); i++, def++)
    if (MatchType (def->exts, sExt))
      return def;
  return NULL;
}

bool CCrystalTextView::SetTextType(LPCTSTR pszExt)
{
  m_CurSourceDef = m_SourceDefs;

  TextDefinition *def = GetTextType(pszExt);

  return SetTextType(def);
}

bool CCrystalTextView::SetTextType (CCrystalTextView::TextType enuType)
{
  TextDefinition *def;
  m_CurSourceDef = def = m_SourceDefs;

  for(int i = 0; i < countof (m_SourceDefs); i++, def++)
      if(def->type == enuType)
          return SetTextType (def);

  return false;
}

bool CCrystalTextView::SetTextType (CCrystalTextView::TextDefinition *def)
{
  if(def)
    if(m_CurSourceDef != def)
      return DoSetTextType(def);
    else
      return true;
  return false;
}

void CCrystalTextView::LoadSettings ()
{
  TextDefinition *def = m_SourceDefs;
  bool bFontLoaded;
  CReg reg;

  if(reg.Open (HKEY_CURRENT_USER, REG_EDITPAD, KEY_READ))
  {
      reg.LoadNumber (_T ("DefaultEncoding"), (DWORD*) &CCrystalTextBuffer::m_nDefaultEncoding);
      for(int i = 0; i < countof (m_SourceDefs); i++, def++)
	  {
          CReg reg1;
          if(reg1.Open(reg.hKey,def->name,KEY_READ))
		  {
             reg1.LoadString (_T ("Extensions"), def->exts, countof (def->exts));
             reg1.LoadNumber (_T ("Flags"), &def->flags);
             reg1.LoadNumber (_T ("TabSize"), &def->tabsize);
             reg1.LoadString (_T ("OpenComment"), def->opencomment, countof (def->opencomment));
             reg1.LoadString (_T ("CloseComment"), def->closecomment, countof (def->closecomment));
             reg1.LoadString (_T ("CommentLine"), def->commentline, countof (def->commentline));
             reg1.LoadNumber (_T ("DefaultEncoding"), &def->encoding);
		  }
	  }
      bFontLoaded = reg.LoadBinary (_T ("LogFont"), (LPBYTE) &m_LogFont, sizeof (m_LogFont));
  }
  else
  bFontLoaded = false;

  if(!bFontLoaded)
  {
      CWindowDC dc (CWnd::GetDesktopWindow ());
      NONCLIENTMETRICS info;
      info.cbSize = sizeof(info);

      SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);

      memcpy(&m_LogFont, &info.lfMessageFont, sizeof (LOGFONT));
      m_LogFont.lfHeight = -MulDiv (11, dc.GetDeviceCaps (LOGPIXELSY), 72);
      m_LogFont.lfWeight = FW_THIN;//FW_NORMAL;
      m_LogFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
      m_LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
      m_LogFont.lfQuality = DEFAULT_QUALITY;
      m_LogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
      _tcscpy (m_LogFont.lfFaceName, _T ("Courier New")/*_T("Times New Roman")*/);
  }
}

void CCrystalTextView::SaveSettings ()
{
  TextDefinition *def = m_SourceDefs;
  CReg reg;
  if(reg.Create (HKEY_CURRENT_USER, REG_EDITPAD, KEY_WRITE))
  {
      VERIFY (reg.SaveNumber (_T ("DefaultEncoding"), (DWORD) CCrystalTextBuffer::m_nDefaultEncoding));
      for(int i = 0; i < countof (m_SourceDefs); i++, def++)
	  {
          CReg reg1;
          if(reg1.Create (reg.hKey, def->name, KEY_WRITE))
		  {
             VERIFY (reg1.SaveString (_T ("Extensions"), def->exts));
             VERIFY (reg1.SaveNumber (_T ("Flags"), def->flags));
             VERIFY (reg1.SaveNumber (_T ("TabSize"), def->tabsize));
             VERIFY (reg1.SaveString (_T ("OpenComment"), def->opencomment));
             VERIFY (reg1.SaveString (_T ("CloseComment"), def->closecomment));
             VERIFY (reg1.SaveString (_T ("CommentLine"), def->commentline));
             VERIFY (reg1.SaveNumber (_T ("DefaultEncoding"), def->encoding));
			 reg1.Close();
		  }
	  }
      VERIFY (reg.SaveBinary (_T ("LogFont"), (LPBYTE) &m_LogFont, sizeof (m_LogFont)));
  }
}

CCrystalTextView::CCrystalTextView ()
{
   AFX_ZERO_INIT_OBJECT(CView);
   m_rxnode = NULL;
   m_pszMatched = NULL;
   m_bSelMargin = TRUE;
   m_bWordWrap = FALSE;

   m_panSubLines = new CArray<int,int>();
   ASSERT(m_panSubLines);
   m_panSubLines->SetSize(0,4096 );

   m_pstrIncrementalSearchString = new CString;
   ASSERT(m_pstrIncrementalSearchString);
   m_pstrIncrementalSearchStringOld = new CString;
   ASSERT(m_pstrIncrementalSearchStringOld);

   ResetView();
   SetTextType(SRC_PLAIN);
   m_bSingle = false; // needed to be set in descendat classes
   m_bRememberLastPos = false;



   COLORREF nColors[24][2] =
   {
	{0x000000,0xffffff},//TEXT_COLOR
    {0xffffff,0x000000},//TEXT_SELECTION_COLOR
    {0xFFFFFF,0xffffff},//CUR_ERR_TAG_COLOR
    {0x800000,0xffffff},//BOOK_MARK_COLOR
    {0x008000,0xffffff},//BREAK_POINT_COLOR
    {0x228b22,0xffffff},//CUR_STATEMENT_COLOR
    {0x4b0082,0xffffff},//SEL_MARGIN_COLOR
    {0xff0000,0xffffff},//KEYWORD_COLOR
    {0x00ff00,0xffffff},//COMMENT_COLOR
    {0xa9a9a9,0xffffff},//NUMBER_COLOR
    {0x0000ff,0xffffff},//STRING_COLOR
    {0xff4500,0xffffff},//OPERATOR_COLOR
    {0x00ff7f,0xffffff},//HTML_ELENAME_COLOR
    {0xffff00,0xffffff},//HTML_ATTRNAME_COLOR
    {0x4169e1,0xffffff},//HTML_ATTRVAL_COLOR
    {0xee82ee,0xffffff},//HTML_COMMENT_COLOR
    {0xb0e0e6,0xffffff},//HTML_ENTITY_COLOR
    {0xc21a84,0xffffff},//HTML_TAG_DEL_COLOR
    {0xbde245,0xffffff},//HTML_STRING_COLOR
    {0x456378,0xffffff},//HTML_TAG_TEXT_COLOR
    {0x7c5e2f,0xffffff},//HTML_OPERATOR_COLOR
    {0x2ab35c,0xffffff},//HTML_SsS_COLOR
    {0x237954,0xffffff},//WIZARD_CODE_COLOR
    {0xff0000,0xffffff},//USER_DEFINED_KEYWD_COLOR
    //{0xff0000,0xffffff},//
  };

  for(int i=0; i<24; i++)
  {
    m_nColors[i][0] = nColors[i][0];
	m_nColors[i][1] = nColors[i][1];
  }
}

CCrystalTextView::~CCrystalTextView ()
{
  ASSERT (m_hAccel == NULL);
  ASSERT (m_pCacheBitmap == NULL);
  ASSERT (m_pTextBuffer == NULL);   //  Must be correctly detached

  if (m_pszLastFindWhat != NULL)
    free (m_pszLastFindWhat);
  if (m_pdwParseCookies != NULL)
    delete m_pdwParseCookies;
  if (m_pnActualLineLength != NULL)
    delete m_pnActualLineLength;
  if (m_rxnode)
    RxFree (m_rxnode);
  if (m_pszMatched)
    delete m_pszMatched;
	//BEGIN SW
	if( m_panSubLines )
		delete m_panSubLines;
	if( m_pstrIncrementalSearchString )
		delete m_pstrIncrementalSearchString;
	if( m_pstrIncrementalSearchStringOld )
		delete m_pstrIncrementalSearchStringOld;
	//END SW
}

BOOL CCrystalTextView::PreCreateWindow (CREATESTRUCT & cs)
{
  CWnd *pParentWnd = CWnd::FromHandlePermanent(cs.hwndParent);
  if(pParentWnd == NULL || !pParentWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd)))
  {
     //View must always create its own scrollbars,
     //if only it's not used within splitter
	 if(m_bWordWrap)// we do not need a horizontal scroll bar, if we wrap the lines
		cs.style|= WS_VSCROLL;
	 else
		cs.style |= (WS_HSCROLL | WS_VSCROLL);
		/*ORIGINAL
		cs.style |= (WS_HSCROLL | WS_VSCROLL);
		*/
  }
  cs.lpszClass = AfxRegisterWndClass(CS_DBLCLKS);
  return CView::PreCreateWindow (cs);
}


/////////////////////////////////////////////////////////////////////////////
// CCrystalTextView drawing

void CCrystalTextView::GetSelection (CPoint & ptStart, CPoint & ptEnd)
{
  PrepareSelBounds();
  ptStart = m_ptDrawSelStart;
  ptEnd   = m_ptDrawSelEnd;
}

CCrystalTextBuffer *CCrystalTextView::LocateTextBuffer ()
{
  return NULL;
}

int CCrystalTextView::GetLineActualLength (int nLineIndex)
{
  int nLineCount = GetLineCount ();
  ASSERT (nLineCount > 0);
  ASSERT (nLineIndex >= 0 && nLineIndex < nLineCount);

  if(m_pnActualLineLength == NULL)
  {
     m_pnActualLineLength = new int[nLineCount];
     memset (m_pnActualLineLength, 0xff, sizeof (int) * nLineCount);
     m_nActualLengthArraySize = nLineCount;
  }

  if(m_pnActualLineLength[nLineIndex] >= 0)
    return m_pnActualLineLength[nLineIndex];

  //  Actual line length is not determined yet, let's calculate a little
  int nActualLength = 0;
  int nLength = GetLineLength(nLineIndex);

  if(nLength > 0)
  {
      LPCTSTR pszLine = GetLineChars (nLineIndex);
      LPTSTR pszChars = (LPTSTR) _alloca (sizeof (TCHAR) * (nLength + 1));
      memcpy (pszChars, pszLine, sizeof (TCHAR) * nLength);
      pszChars[nLength] = 0;
      LPTSTR pszCurrent = pszChars;

      int nTabSize = GetTabSize ();
      for(;;)
	  {
          LPTSTR psz = _tcschr (pszCurrent, _T('\t'));
          if(psz == NULL)
		  {
            nActualLength += (pszChars + nLength - pszCurrent);
            break;
          }

          nActualLength += (psz - pszCurrent);
          nActualLength += (nTabSize - nActualLength % nTabSize);
          pszCurrent = psz + 1;
	  }
    }

  m_pnActualLineLength[nLineIndex] = nActualLength;
  return nActualLength;
}

void CCrystalTextView::ScrollToChar (int  nNewOffsetChar, 
									 BOOL bNoSmoothScroll /*= FALSE*/ , 
									 BOOL bTrackScrollBar /*= TRUE*/ )
{
	// no horizontal scrolling, when word wrapping is enabled
  if(m_bWordWrap)
	  return;
	
  //  For now, ignoring bNoSmoothScroll and m_bSmoothScroll
  if(m_nOffsetChar != nNewOffsetChar)
  {
      int nScrollChars = m_nOffsetChar - nNewOffsetChar;
      m_nOffsetChar = nNewOffsetChar;
      
	  CRect rcScroll;
      GetClientRect (&rcScroll);
      rcScroll.left += GetMarginWidth();

      ScrollWindow(nScrollChars * GetCharWidth(), 0, &rcScroll, &rcScroll);
      UpdateWindow ();
      
	  if(bTrackScrollBar)
        RecalcHorzScrollBar(TRUE);
  }
}

//BEGIN SW
void CCrystalTextView::ScrollToSubLine( int nNewTopSubLine, 
									BOOL bNoSmoothScroll /*= FALSE*/, BOOL bTrackScrollBar /*= TRUE*/ )
{
	if(m_nTopSubLine != nNewTopSubLine)
	{
		if(bNoSmoothScroll || ! m_bSmoothScroll)
		{
			int nScrollLines = m_nTopSubLine - nNewTopSubLine;
			m_nTopSubLine = nNewTopSubLine;
			ScrollWindow(0, nScrollLines * GetLineHeight());
			
			UpdateWindow();
			
			if(bTrackScrollBar)RecalcVertScrollBar(TRUE);
		}
		else
		{
			//	Do smooth scrolling
			int nLineHeight = GetLineHeight();
			if(m_nTopSubLine > nNewTopSubLine)
			{
				int nIncrement = (m_nTopSubLine - nNewTopSubLine) / SMOOTH_SCROLL_FACTOR + 1;
				while(m_nTopSubLine != nNewTopSubLine)
				{
					int nTopSubLine = m_nTopSubLine - nIncrement;
					if (nTopSubLine < nNewTopSubLine)
						nTopSubLine = nNewTopSubLine;
					int nScrollLines = nTopSubLine - m_nTopSubLine;
					m_nTopSubLine = nTopSubLine;
					ScrollWindow(0, - nLineHeight * nScrollLines);
					UpdateWindow();
					if (bTrackScrollBar)
						RecalcVertScrollBar(TRUE);
				}
			}
			else
			{
				int nIncrement = (nNewTopSubLine - m_nTopSubLine) / SMOOTH_SCROLL_FACTOR + 1;
				while (m_nTopSubLine != nNewTopSubLine)
				{
					int nTopSubLine = m_nTopSubLine + nIncrement;
					if (nTopSubLine > nNewTopSubLine)
						nTopSubLine = nNewTopSubLine;
					int nScrollLines = nTopSubLine - m_nTopSubLine;
					m_nTopSubLine = nTopSubLine;
					ScrollWindow(0, - nLineHeight * nScrollLines);
					UpdateWindow();
					if (bTrackScrollBar)
						RecalcVertScrollBar(TRUE);
				}
			}
		}
		int nDummy;
		GetLineBySubLine( m_nTopSubLine, m_nTopLine, nDummy );
		InvalidateRect( NULL );	// repaint whole window
	}
}


void CCrystalTextView::ScrollToLine (int nNewTopLine, BOOL bNoSmoothScroll 
									 /*= FALSE*/ , BOOL bTrackScrollBar /*= TRUE*/ )
{
	//BEGIN SW
	if( m_nTopLine != nNewTopLine )
		ScrollToSubLine( GetSubLineIndex( nNewTopLine ), bNoSmoothScroll, bTrackScrollBar );

	/*ORIGINAL
	if (m_nTopLine != nNewTopLine)
	{
		if (bNoSmoothScroll || ! m_bSmoothScroll)
		{
			int nScrollLines = m_nTopLine - nNewTopLine;
			m_nTopLine = nNewTopLine;
			ScrollWindow(0, nScrollLines * GetLineHeight());
			UpdateWindow();
			if (bTrackScrollBar)
				RecalcVertScrollBar(TRUE);
		}
		else
		{
			//	Do smooth scrolling
			int nLineHeight = GetLineHeight();
			if (m_nTopLine > nNewTopLine)
			{
				int nIncrement = (m_nTopLine - nNewTopLine) / SMOOTH_SCROLL_FACTOR + 1;
				while (m_nTopLine != nNewTopLine)
				{
					int nTopLine = m_nTopLine - nIncrement;
					if (nTopLine < nNewTopLine)
						nTopLine = nNewTopLine;
					int nScrollLines = nTopLine - m_nTopLine;
					m_nTopLine = nTopLine;
					ScrollWindow(0, - nLineHeight * nScrollLines);
					UpdateWindow();
					if (bTrackScrollBar)
						RecalcVertScrollBar(TRUE);
				}
			}
			else
			{
				int nIncrement = (nNewTopLine - m_nTopLine) / SMOOTH_SCROLL_FACTOR + 1;
				while (m_nTopLine != nNewTopLine)
				{
					int nTopLine = m_nTopLine + nIncrement;
					if (nTopLine > nNewTopLine)
						nTopLine = nNewTopLine;
					int nScrollLines = nTopLine - m_nTopLine;
					m_nTopLine = nTopLine;
					ScrollWindow(0, - nLineHeight * nScrollLines);
					UpdateWindow();
					if (bTrackScrollBar)
						RecalcVertScrollBar(TRUE);
				}
			}
		}
	}
	*///END SW
}

void CCrystalTextView::ExpandChars (LPCTSTR pszChars, int nOffset, int nCount,
									                               CString & line)
{
  if(nCount <= 0)
  {
    line = _T ("");
    return;
  }

  int nTabSize = GetTabSize();

  int nActualOffset = 0;
  for(int I = 0; I < nOffset; I++)
  {
     if(pszChars[I] == _T ('\t'))
        nActualOffset += (nTabSize - nActualOffset % nTabSize);
     else
        nActualOffset++;
  }

  pszChars += nOffset;
  int nLength = nCount;

  int nTabCount = 0;
  for(I = 0; I < nLength; I++)
  {
     if(pszChars[I] == _T ('\t'))
        nTabCount++;
  }

  LPTSTR pszBuf = line.GetBuffer (nLength + nTabCount * (nTabSize - 1) + 1);
  int nCurPos = 0;

  if(nTabCount > 0 || m_bViewTabs)
  {
      for(I = 0; I < nLength; I++)
	  {
          if(pszChars[I] == _T ('\t'))
		  {
              int nSpaces = nTabSize - (nActualOffset + nCurPos) % nTabSize;
              if(m_bViewTabs)
			  {
                  pszBuf[nCurPos++] = TAB_CHARACTER;
                  nSpaces--;
              }
              
			  while(nSpaces > 0)
              {
                 pszBuf[nCurPos++] = _T (' ');
                 nSpaces--;
              }
		  }
          else
          {
             if(pszChars[I] == _T (' ') && m_bViewTabs)
                pszBuf[nCurPos] = SPACE_CHARACTER;
              else
                pszBuf[nCurPos] = pszChars[I];
              nCurPos++;
          }
	  }
  }
  else
  {
     memcpy (pszBuf, pszChars, sizeof (TCHAR) * nLength);
     nCurPos = nLength;
  }
  pszBuf[nCurPos] = 0;
  line.ReleaseBuffer ();
}

void CCrystalTextView::DrawLineHelperImpl(CDC * pdc,CPoint & ptOrigin,
										  const CRect & rcClip,LPCTSTR pszChars,
										  int nOffset, int nCount)
{
  ASSERT (nCount >= 0);
  if(nCount > 0)
  {
     CString line;
     ExpandChars(pszChars,nOffset,nCount,line);
     int nWidth = rcClip.right - ptOrigin.x;

     if(nWidth > 0)
	 {
        int nCharWidth = GetCharWidth ();
        int nCount = line.GetLength ();
        int nCountFit = nWidth / nCharWidth + 1;
        if (nCount > nCountFit)
            nCount = nCountFit;

        VERIFY(pdc->ExtTextOut(ptOrigin.x,ptOrigin.y,ETO_CLIPPED,&rcClip,line,nCount,NULL));
	 }
     ptOrigin.x += GetCharWidth () * line.GetLength ();
  }
}

void CCrystalTextView::DrawLineHelper(CDC * pdc,CPoint & ptOrigin, 
									   const CRect & rcClip, int nColorIndex,
                                       LPCTSTR pszChars, int nOffset, int nCount,
									   CPoint ptTextPos)
{
  if(nCount > 0)
  {
     if(m_bFocused || m_bShowInactiveSelection)
	 {
          int nSelBegin = 0, nSelEnd = 0;

          if(m_ptDrawSelStart.y > ptTextPos.y)
              nSelBegin = nCount;
          else 
		  if(m_ptDrawSelStart.y == ptTextPos.y)
		  {
              nSelBegin = m_ptDrawSelStart.x - ptTextPos.x;
              if (nSelBegin < 0)
                nSelBegin = 0;
              if (nSelBegin > nCount)
                nSelBegin = nCount;
		  }
          
		  if(m_ptDrawSelEnd.y > ptTextPos.y)
              nSelEnd = nCount;
          else 
		  if(m_ptDrawSelEnd.y == ptTextPos.y)
		  {
             nSelEnd = m_ptDrawSelEnd.x - ptTextPos.x;
             if(nSelEnd < 0)
                nSelEnd = 0;
             if(nSelEnd > nCount)
                nSelEnd = nCount;
		  }

          ASSERT(nSelBegin >= 0 && nSelBegin <= nCount);
          ASSERT(nSelEnd >= 0 && nSelEnd <= nCount);
          ASSERT(nSelBegin <= nSelEnd);

          // Draw part of the text before selection
          if(nSelBegin > 0)
              DrawLineHelperImpl(pdc,ptOrigin,rcClip,pszChars,nOffset,nSelBegin);

          if(nSelBegin < nSelEnd)
		  {
              COLORREF crOldBk = pdc->SetBkColor(GetColor(COLORINDEX_SELBKGND));

              COLORREF crOldText = pdc->SetTextColor(GetColor(COLORINDEX_SELTEXT));

              DrawLineHelperImpl(pdc,ptOrigin,rcClip,pszChars, 
				                  nOffset + nSelBegin,nSelEnd - nSelBegin);

              pdc->SetBkColor(crOldBk);
              pdc->SetTextColor(crOldText);
		  }

          if(nSelEnd < nCount)
              DrawLineHelperImpl(pdc,ptOrigin,rcClip,pszChars,nOffset + nSelEnd,nCount - nSelEnd);
	 }
      else
      DrawLineHelperImpl(pdc,ptOrigin,rcClip,pszChars,nOffset,nCount);
    }
}

void CCrystalTextView::GetLineColors (int nLineIndex, COLORREF & crBkgnd,
                                      COLORREF & crText, BOOL & bDrawWhitespace)
{
  DWORD dwLineFlags = GetLineFlags(nLineIndex);
  bDrawWhitespace = TRUE;
  crText = RGB(255,255,255);

  if(dwLineFlags & LF_EXECUTION)
  {
     crBkgnd = RGB(0,128,0);
     return;
  }

  if(dwLineFlags & LF_BREAKPOINT)
  {
    crBkgnd = RGB(255,0,0);
    return;
  }

  if(dwLineFlags & LF_INVALID_BREAKPOINT)
  {
    crBkgnd = RGB(128,128,0);
    return;
  }

  crBkgnd = CLR_NONE;
  crText = CLR_NONE;
  bDrawWhitespace = FALSE;
}

DWORD CCrystalTextView::GetParseCookie (int nLineIndex)
{
  int nLineCount = GetLineCount();
  if(m_pdwParseCookies == NULL)
  {
     m_nParseArraySize = nLineCount;
     m_pdwParseCookies = new DWORD[nLineCount];
     memset (m_pdwParseCookies, 0xff, nLineCount * sizeof (DWORD));
  }

  if(nLineIndex < 0)
    return 0;
  if(m_pdwParseCookies[nLineIndex] != (DWORD) - 1)
    return m_pdwParseCookies[nLineIndex];

  int L = nLineIndex;
  while (L >= 0 && m_pdwParseCookies[L] == (DWORD) - 1)
    L--;
  L++;

  int nBlocks;
  while (L <= nLineIndex)
  {
     DWORD dwCookie = 0;
     if (L > 0)
       dwCookie = m_pdwParseCookies[L - 1];

      ASSERT (dwCookie != (DWORD) - 1);
      m_pdwParseCookies[L] = ParseLine (dwCookie, L, NULL, nBlocks);
      ASSERT (m_pdwParseCookies[L] != (DWORD) - 1);
      L++;
  }
  return m_pdwParseCookies[nLineIndex];
}



void CCrystalTextView::WrapLine(int nLineIndex,int nMaxLineWidth,int *anBreaks,
								                                    int &nBreaks )
{
	// There must be a parser attached to this view
	if( !m_pParser )
		return;
	m_pParser->WrapLine( nLineIndex, nMaxLineWidth, anBreaks, nBreaks );
}


void CCrystalTextView::WrapLineCached(int nLineIndex, int nMaxLineWidth, 
									      int *anBreaks, int &nBreaks )
{
	// if word wrap is not active, there is not any break in the line
	if( !m_bWordWrap )
	{
		nBreaks = 0;
		return;
	}

	// word wrap is active
	if( nLineIndex < m_panSubLines->GetSize() && !anBreaks && 
		                                       (*m_panSubLines)[nLineIndex] > -1 )
		// return cached data
		nBreaks = (*m_panSubLines)[nLineIndex] - 1;
	else
	{
		// recompute line wrap
		nBreaks = 0;
		WrapLine( nLineIndex, nMaxLineWidth, anBreaks, nBreaks );

		// cache data
		ASSERT( nBreaks > -1 );
		m_panSubLines->SetAtGrow( nLineIndex, nBreaks + 1 );

		// RecalcVertScrollBar();
	}
}


void CCrystalTextView::InvalidateLineCache( int nLineIndex1, 
										                  int nLineIndex2 /*= -1*/ )
{
	// invalidate cached sub line count

	if( nLineIndex2 == -1 && nLineIndex1 < m_panSubLines->GetSize() )
		for( int i = nLineIndex1; i < m_panSubLines->GetSize(); i++ )
			(*m_panSubLines)[i] = -1;
	else
	{
		if( nLineIndex1 > nLineIndex2 )
		{
			int	nStorage = nLineIndex1;
			nLineIndex1 = nLineIndex2;
			nLineIndex2 = nStorage;
		}

		if( nLineIndex1 >= m_panSubLines->GetSize() )
			return;

		if( nLineIndex2 >= m_panSubLines->GetSize() )
			nLineIndex2 = m_panSubLines->GetUpperBound();

		for( int i = nLineIndex1; i <= nLineIndex2; i++ )
			if( i >= 0 && i < m_panSubLines->GetSize() )
				(*m_panSubLines)[i] = -1;
	}
}


void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, 
									   const CRect &rcClip,
																			
									   CCrystalTextView::TEXTBLOCK *pBuf, int nBlocks, 
									   int &nActualItem, COLORREF crText, 
									   COLORREF crBkgnd, BOOL bDrawWhitespace,
									   LPCTSTR pszChars,int nOffset, int nCount,
									   CPoint ptTextPos )
{

	CPoint	originalOrigin = ptOrigin;
	CRect		frect = rcClip;
	int			nLength = GetLineLength( ptTextPos.y );

	frect.top = ptOrigin.y;
	frect.bottom = frect.top + GetLineHeight();

	ASSERT( nActualItem < nBlocks );

	if (crText == CLR_NONE)
		pdc->SetTextColor(GetColor(pBuf[nActualItem].m_nColorIndex));

	pdc->SelectObject(GetFont());

	if( nBlocks > 0 && nActualItem < nBlocks - 1 && 
		pBuf[nActualItem + 1].m_nCharPos >= nOffset && 
		pBuf[nActualItem + 1].m_nCharPos <= nOffset + nCount )
	{
		ASSERT(pBuf[nActualItem].m_nCharPos >= 0 && 
			                            pBuf[nActualItem].m_nCharPos <= nLength);

		for (int I = nActualItem; I < nBlocks - 1 && 
			                    pBuf[I + 1].m_nCharPos <= nOffset + nCount; I ++)
		{
			ASSERT(pBuf[I].m_nCharPos >= 0 && pBuf[I].m_nCharPos <= nLength);

			if (crText == CLR_NONE)
				pdc->SetTextColor(GetColor(pBuf[I].m_nColorIndex));

			pdc->SelectObject(GetFont());

			int nOffsetToUse = (nOffset > pBuf[I].m_nCharPos)? nOffset : pBuf[I].m_nCharPos;

			DrawLineHelper(pdc, ptOrigin, rcClip, pBuf[I].m_nColorIndex, pszChars,
					(nOffset > pBuf[I].m_nCharPos)? nOffset : pBuf[I].m_nCharPos, 
					pBuf[I + 1].m_nCharPos - nOffsetToUse,
					CPoint( nOffsetToUse, ptTextPos.y ));
		}

		nActualItem = I;

		ASSERT(pBuf[nActualItem].m_nCharPos >= 0 && pBuf[nActualItem].m_nCharPos <= nLength);
		if (crText == CLR_NONE)
			pdc->SetTextColor(GetColor(pBuf[nActualItem].m_nColorIndex));

		pdc->SelectObject(GetFont());

		DrawLineHelper(pdc,ptOrigin, rcClip, pBuf[nActualItem].m_nColorIndex,
			           pszChars,pBuf[nActualItem].m_nCharPos, 
					   nOffset + nCount - pBuf[nActualItem].m_nCharPos,
					   CPoint(pBuf[nActualItem].m_nCharPos, ptTextPos.y));
	}
	else
	{
		DrawLineHelper(
			pdc, ptOrigin, rcClip, pBuf[nActualItem].m_nColorIndex, 
			pszChars, nOffset, nCount, ptTextPos);
	}

	// Draw space on the right of the text
	if (ptOrigin.x > frect.left)
		frect.left = ptOrigin.x;

	if(frect.right > frect.left)
	{
		if ((m_bFocused || m_bShowInactiveSelection) 
			&& IsInsideSelBlock(CPoint(GetLineLength( ptTextPos.y ), ptTextPos.y)) 
			&& (nOffset + nCount) == GetLineLength( ptTextPos.y ) )
		{
			pdc->FillSolidRect(frect.left, frect.top, GetCharWidth(), frect.Height(),
												GetColor(COLORINDEX_SELBKGND));
			frect.left += GetCharWidth();
		}
		if (frect.right > frect.left)
			pdc->FillSolidRect(frect, bDrawWhitespace ? crBkgnd :
		                    GetColor(COLORINDEX_WHITESPACE));
	}

	// set origin to beginning of next screen line
	ptOrigin.x = originalOrigin.x;
	ptOrigin.y+= GetLineHeight();
}


void CCrystalTextView::DrawSingleLine (CDC * pdc, const CRect & rc, int nLineIndex)
{
  
   ASSERT (nLineIndex >= -1 && nLineIndex < GetLineCount());

   if(nLineIndex == -1)
   {
      pdc->FillSolidRect(rc,GetColor(COLORINDEX_WHITESPACE));
      return;
   }

   //  Acquire the background color for the current line
   BOOL bDrawWhitespace = FALSE;
   COLORREF crBkgnd, crText;
   GetLineColors(nLineIndex,crBkgnd,crText,bDrawWhitespace);

   if(crBkgnd == CLR_NONE)
     crBkgnd = GetColor(COLORINDEX_BKGND);

   int nLength = GetLineLength(nLineIndex);
   if(nLength == 0)
   {
      //  Draw the empty line
      CRect rect = rc;
      if ((m_bFocused || m_bShowInactiveSelection) && 
		   IsInsideSelBlock (CPoint (0, nLineIndex)))
      {
          pdc->FillSolidRect (rect.left,rect.top,GetCharWidth(),rect.Height(),
			                                  GetColor(COLORINDEX_SELBKGND));

          rect.left += GetCharWidth();
      }
      pdc->FillSolidRect (rect, bDrawWhitespace ? crBkgnd :
	                           GetColor (COLORINDEX_WHITESPACE));
      return;
   }

   //  Parse the line
   LPCTSTR pszChars = GetLineChars(nLineIndex);
   DWORD dwCookie   = GetParseCookie(nLineIndex - 1);
   TEXTBLOCK *pBuf  = (TEXTBLOCK *) _alloca (sizeof (TEXTBLOCK) * nLength * 3);
   int nBlocks = 0;

   // insert at least one textblock of normal color at the beginning
   pBuf[0].m_nCharPos = 0;
   pBuf[0].m_nColorIndex = COLORINDEX_NORMALTEXT;
   nBlocks++;

   m_pdwParseCookies[nLineIndex] = ParseLine(dwCookie,nLineIndex,pBuf,nBlocks);
   ASSERT (m_pdwParseCookies[nLineIndex] != (DWORD) - 1);

   int nActualItem = 0;

	
   //Wrap the line
   int *anBreaks = (int*)_alloca( sizeof( int ) * nLength );
   int	nBreaks = 0;

   WrapLineCached( nLineIndex, GetScreenChars(), anBreaks, nBreaks );

   //  Draw the line text
   CPoint origin (rc.left - m_nOffsetChar * GetCharWidth (), rc.top);
   pdc->SetBkColor(crBkgnd);
   
   if (crText != CLR_NONE)
     pdc->SetTextColor (crText);
	
   BOOL bColorSet = FALSE;

   if(nBreaks > 0)
   {
	  // Draw all the screen lines of the wrapped line
	  ASSERT( anBreaks[0] < nLength );
		
	  // draw start of line to first break
	  DrawScreenLine(pdc, origin, rc,pBuf, nBlocks, nActualItem,crText, crBkgnd,
		             bDrawWhitespace,pszChars, 0, anBreaks[0],CPoint( 0, nLineIndex ) );
		
	  // draw from first break to last break
	  for( int i = 0; i < nBreaks - 1; i++ )
	  {
		 ASSERT( anBreaks[i] >= 0 && anBreaks[i] < nLength );

		 DrawScreenLine(pdc,origin,rc,pBuf,nBlocks,nActualItem,crText,crBkgnd,
		                bDrawWhitespace,pszChars, anBreaks[i], 
						anBreaks[i + 1] - anBreaks[i],CPoint(anBreaks[i], 
						nLineIndex));
	  }
	  // draw from last break till end of line
	  DrawScreenLine(pdc,origin,rc,pBuf,nBlocks,nActualItem,crText,crBkgnd,
	                 bDrawWhitespace,pszChars,anBreaks[i],nLength - anBreaks[i],
	                 CPoint(anBreaks[i],nLineIndex));
	}
	else
	DrawScreenLine(pdc, origin, rc,pBuf, nBlocks, nActualItem,crText, crBkgnd,
	               bDrawWhitespace,pszChars, 0, nLength, CPoint(0, nLineIndex));
}




COLORREF CCrystalTextView::GetColor (int nColorIndex)
{
  switch (nColorIndex)
  {
    case COLORINDEX_WHITESPACE :
    case COLORINDEX_BKGND:
      return   m_nColors[TEXT_COLOR][1];
    case COLORINDEX_NORMALTEXT:
      return  m_nColors[TEXT_COLOR][0];
    case COLORINDEX_SELMARGIN:
      return   m_nColors[SEL_MARGIN_COLOR][0];
    case COLORINDEX_PREPROCESSOR:
      return RGB (0, 128, 192);
    case COLORINDEX_COMMENT:
      return m_nColors[COMMENT_COLOR][0];//RGB (0, 128, 0);
	case COLORINDEX_WIZARDCODE:
	  return m_nColors[WIZARD_CODE_COLOR][0];
      //  [JRT]: Enabled Support For Numbers...
    case COLORINDEX_NUMBER:
      return m_nColors[NUMBER_COLOR][0];
      //  [JRT]: Support For C/C++ Operators
    case COLORINDEX_OPERATOR:
      return m_nColors[TEXT_COLOR][0];//RGB (96, 96, 96);
    case COLORINDEX_KEYWORD:
      return m_nColors[KEYWORD_COLOR][0];//RGB (0, 0, 255);
    case COLORINDEX_FUNCNAME:
      return RGB (0,255,0);
    case COLORINDEX_USER1:
      return RGB (0, 0, 128);
    case COLORINDEX_USER2:
      return RGB (0, 128, 192);
    case COLORINDEX_SELBKGND:
      return m_nColors[TEXT_SELECTION_COLOR][1];//RGB (0, 0, 0);
    case COLORINDEX_SELTEXT:
      return m_nColors[TEXT_SELECTION_COLOR][0];//RGB (255, 255, 255);
   }
  return m_nColors[STRING_COLOR][0];//RGB (128, 0, 0);
}

DWORD CCrystalTextView::GetLineFlags (int nLineIndex)
{
  if (m_pTextBuffer == NULL)
    return 0;
  return m_pTextBuffer->GetLineFlags (nLineIndex);
}



void CCrystalTextView::DrawMargin (CDC * pdc, const CRect & rect, int nLineIndex)
{
  if(!m_bSelMargin)
  {
     pdc->FillSolidRect(rect,GetColor(COLORINDEX_BKGND));
     return;
  }

  CRect rcRect(rect);

  pdc->Draw3dRect(rcRect,COLOR_BTNSHADOW,COLOR_BTNSHADOW);

  rcRect.DeflateRect(0,0,1,0);
  pdc->FillSolidRect(rcRect,GetColor(COLORINDEX_SELMARGIN));

  int nImageIndex = -1;
  if(nLineIndex >= 0)
  {
      DWORD dwLineFlags = GetLineFlags (nLineIndex);
      static const DWORD adwFlags[] =
      {
          LF_EXECUTION,
          LF_BREAKPOINT,
          LF_COMPILATION_ERROR,
          LF_BOOKMARK (1),
          LF_BOOKMARK (2),
          LF_BOOKMARK (3),
          LF_BOOKMARK (4),
          LF_BOOKMARK (5),
          LF_BOOKMARK (6),
          LF_BOOKMARK (7),
          LF_BOOKMARK (8),
          LF_BOOKMARK (9),
          LF_BOOKMARK (0),
          LF_BOOKMARKS,
          LF_INVALID_BREAKPOINT
      };

      for(int I = 0; I <= sizeof (adwFlags) / sizeof (adwFlags[0]); I++)
      {
          if((dwLineFlags & adwFlags[I]) != 0)
          {
            nImageIndex = I;
            break;
          }
       }
  }

  if(nImageIndex >= 0)
  {
      if(m_pIcons == NULL)
      {
         m_pIcons = new CImageList;
         VERIFY(m_pIcons->Create (IDR_MARGIN_ICONS, 16, 16, RGB (255, 255, 255)));
      }
	  CPoint pt(rcRect.left + 2, rect.top + (GetLineHeight() - 16) / 2);

	  VERIFY(m_pIcons->Draw(pdc, nImageIndex, pt, ILD_TRANSPARENT));
      VERIFY (m_pIcons->Draw (pdc, nImageIndex, pt, ILD_TRANSPARENT));
   }
}

BOOL CCrystalTextView::IsInsideSelBlock (CPoint ptTextPos)
{
  ASSERT_VALIDTEXTPOS(ptTextPos);
  if (ptTextPos.y < m_ptDrawSelStart.y)
    return FALSE;

  if (ptTextPos.y > m_ptDrawSelEnd.y)
    return FALSE;

  if (ptTextPos.y < m_ptDrawSelEnd.y && ptTextPos.y > m_ptDrawSelStart.y)
    return TRUE;

  if(m_ptDrawSelStart.y < m_ptDrawSelEnd.y)
  {
     if (ptTextPos.y == m_ptDrawSelEnd.y)
        return ptTextPos.x < m_ptDrawSelEnd.x;

     ASSERT (ptTextPos.y == m_ptDrawSelStart.y);
     return ptTextPos.x >= m_ptDrawSelStart.x;
  }

  ASSERT (m_ptDrawSelStart.y == m_ptDrawSelEnd.y);
  return ptTextPos.x >= m_ptDrawSelStart.x && ptTextPos.x < m_ptDrawSelEnd.x;
}

BOOL CCrystalTextView::IsInsideSelection (const CPoint & ptTextPos)
{
  PrepareSelBounds ();
  return IsInsideSelBlock (ptTextPos);
}

void CCrystalTextView::PrepareSelBounds ()
{
  if(m_ptSelStart.y < m_ptSelEnd.y ||
    (m_ptSelStart.y == m_ptSelEnd.y && m_ptSelStart.x < m_ptSelEnd.x))
  {
    m_ptDrawSelStart = m_ptSelStart;
    m_ptDrawSelEnd = m_ptSelEnd;
  }
  else
  {
    m_ptDrawSelStart = m_ptSelEnd;
    m_ptDrawSelEnd = m_ptSelStart;
  }
}

void CCrystalTextView::OnDraw(CDC * pdc)
{
  CRect rcClient;
  GetClientRect (rcClient);

  int nLineCount = GetLineCount ();
  int nLineHeight = GetLineHeight ();
  PrepareSelBounds ();

  CDC cacheDC;
  VERIFY (cacheDC.CreateCompatibleDC (pdc));
  if (m_pCacheBitmap == NULL)
    {
      m_pCacheBitmap = new CBitmap;
		//BEGIN SW
		VERIFY(m_pCacheBitmap->CreateCompatibleBitmap(pdc, rcClient.Width(), rcClient.Height()));
		/*ORIGINAL
		VERIFY(m_pCacheBitmap->CreateCompatibleBitmap(pdc, rcClient.Width(), nLineHeight));
		*/
		//END SW
    }
  CBitmap *pOldBitmap = cacheDC.SelectObject (m_pCacheBitmap);

  CRect rcLine;
  rcLine = rcClient;
  rcLine.bottom = rcLine.top + nLineHeight;
  CRect rcCacheMargin (0, 0, GetMarginWidth (), nLineHeight);
  CRect rcCacheLine (GetMarginWidth (), 0, rcLine.Width (), nLineHeight);
	//BEGIN SW
	// initialize rects
	int		nSubLineOffset = GetSubLineIndex( m_nTopLine ) - m_nTopSubLine;
	if( nSubLineOffset < 0 )
	{
		rcCacheMargin.OffsetRect( 0, nSubLineOffset * nLineHeight );
		rcCacheLine.OffsetRect( 0, nSubLineOffset * nLineHeight );
	}

	int		nBreaks;
	int		nMaxLineChars = GetScreenChars();
	//END SW

  int nCurrentLine = m_nTopLine;
  while (rcLine.top < rcClient.bottom)
    {
		//BEGIN SW
		nBreaks = 0;
		if( nCurrentLine < nLineCount /*&& GetLineLength( nCurrentLine ) > nMaxLineChars*/ )
			WrapLineCached( nCurrentLine, nMaxLineChars, NULL, nBreaks );

		rcLine.bottom = rcLine.top + (nBreaks + 1) * nLineHeight;
		rcCacheLine.bottom = rcCacheLine.top + rcLine.Height();
		rcCacheMargin.bottom = rcCacheMargin.top + rcLine.Height();

		if( rcCacheLine.top < 0 )
			rcLine.bottom+= rcCacheLine.top;
		//END SW
      if (nCurrentLine < nLineCount)
        {
          DrawMargin (&cacheDC, rcCacheMargin, nCurrentLine);
          DrawSingleLine (&cacheDC, rcCacheLine, nCurrentLine);
        }
      else
        {
          DrawMargin (&cacheDC, rcCacheMargin, -1);
          DrawSingleLine (&cacheDC, rcCacheLine, -1);
        }

      VERIFY (pdc->BitBlt (rcLine.left, rcLine.top, rcLine.Width (), rcLine.Height (), &cacheDC, 0, 0, SRCCOPY));

      nCurrentLine++;
		//BEGIN SW
		rcLine.top = rcLine.bottom;
		rcCacheLine.top = 0;
		rcCacheMargin.top = 0;
		/*ORIGINAL
		rcLine.OffsetRect(0, nLineHeight);
		*/
		//END SW
    }

  cacheDC.SelectObject (pOldBitmap);
  cacheDC.DeleteDC ();

}


void CCrystalTextView::ResetView ()
{
  // m_bWordWrap = FALSE;
  m_nTopLine = 0;
  m_nOffsetChar = 0;
  m_nLineHeight = -1;
  m_nCharWidth = -1;
  m_nTabSize = 4;
  m_nMaxLineLength = -1;
  m_nScreenLines = -1;
  m_nScreenChars = -1;
  m_nIdealCharPos = -1;
  m_ptAnchor.x = 0;
  m_ptAnchor.y = 0;
  if (m_pIcons != NULL)
    {
      delete m_pIcons;
      m_pIcons = NULL;
    }
  for (int I = 0; I < 4; I++)
    {
      if (m_apFonts[I] != NULL)
        {
          m_apFonts[I]->DeleteObject ();
          delete m_apFonts[I];
          m_apFonts[I] = NULL;
        }
    }
  if (m_pdwParseCookies != NULL)
    {
      delete m_pdwParseCookies;
      m_pdwParseCookies = NULL;
    }
  if (m_pnActualLineLength != NULL)
    {
      delete m_pnActualLineLength;
      m_pnActualLineLength = NULL;
    }
  m_nParseArraySize = 0;
  m_nActualLengthArraySize = 0;
  m_ptCursorPos.x = 0;
  m_ptCursorPos.y = 0;
  m_ptSelStart = m_ptSelEnd = m_ptCursorPos;
  m_bDragSelection = FALSE;
  m_bVertScrollBarLocked = FALSE;
  m_bHorzScrollBarLocked = FALSE;
  if (::IsWindow (m_hWnd))
    UpdateCaret ();
  m_bLastSearch = FALSE;
  m_bShowInactiveSelection = TRUE; // FP: reverted because I like it
  m_bPrintHeader = FALSE;
  m_bPrintFooter = TRUE;

  m_bBookmarkExist = FALSE;     // More bookmarks

  m_bMultipleSearch = FALSE;    // More search

}



void CCrystalTextView::UpdateCaret()
{

  ASSERT_VALIDTEXTPOS (m_ptCursorPos);
  if(m_bFocused && !m_bCursorHidden &&
        CalculateActualOffset(m_ptCursorPos.y,m_ptCursorPos.x) >= m_nOffsetChar)
  {
    CreateSolidCaret(2,GetLineHeight());
    SetCaretPos(TextToClient(m_ptCursorPos));
    ShowCaret();
  }
  else
    HideCaret();
}

int CCrystalTextView::GetCRLFMode()
{
  if(m_pTextBuffer)
    return m_pTextBuffer->GetCRLFMode();

  return -1;
}

void CCrystalTextView::SetCRLFMode(int nCRLFMode)
{
  if(m_pTextBuffer)
    m_pTextBuffer->SetCRLFMode(nCRLFMode);
}

int CCrystalTextView::GetTabSize()
{
  ASSERT(m_nTabSize >= 0 && m_nTabSize <= 64);
  return m_nTabSize;
}

void CCrystalTextView::SetTabSize(int nTabSize)
{
  ASSERT(nTabSize >= 0 && nTabSize <= 64);

  if(m_nTabSize != nTabSize)
  {
     m_nTabSize = nTabSize;
     if(m_pnActualLineLength != NULL)
     {
       delete m_pnActualLineLength;
       m_pnActualLineLength = NULL;
     }

     m_nActualLengthArraySize = 0;
     m_nMaxLineLength = -1;
     RecalcHorzScrollBar ();
     Invalidate ();
     UpdateCaret ();
  }
}

CFont *CCrystalTextView::GetFont (BOOL bItalic /*= FALSE*/ , BOOL bBold /*= FALSE*/ )
{
    
  int nIndex = 0;
  if (bBold)
    nIndex |= 1;

  if (bItalic)
    nIndex |= 2;

  if(m_apFonts[nIndex] == NULL)
  {
      m_apFonts[nIndex] = new CFont;
      if(!m_lfBaseFont.lfHeight)
	  {
         CClientDC dc (GetDesktopWindow ());
         m_lfBaseFont.lfHeight = -MulDiv (11, dc.GetDeviceCaps (LOGPIXELSY), 72);
      }

      m_lfBaseFont.lfWeight = bBold && !_tcsnicmp (m_lfBaseFont.lfFaceName, _T ("Courier"), 7) ? FW_BOLD : FW_NORMAL;
      m_lfBaseFont.lfItalic = (BYTE) (bItalic && !_tcsnicmp (m_lfBaseFont.lfFaceName, _T ("Courier"), 7));

      if(!m_apFonts[nIndex]->CreateFontIndirect(&m_lfBaseFont))
	  {
         delete m_apFonts[nIndex];
         m_apFonts[nIndex] = NULL;
         return CView::GetFont();
      }

  }
  return m_apFonts[nIndex];
  
/*  m_apFonts[0] = new CFont;
  m_apFonts[0]->CreatePointFont(100,_T("Times New Roman"),GetDC());
  return m_apFonts[0];*/
}

void CCrystalTextView::CalcLineCharDim()
{
  CDC *pdc        = GetDC();
  CFont *pOldFont = pdc->SelectObject(GetFont());
  CSize szCharExt = pdc->GetTextExtent(_T ("X"));

  m_nLineHeight   = szCharExt.cy;

  if(m_nLineHeight < 1)
    m_nLineHeight = 1;

  m_nCharWidth = szCharExt.cx;

  pdc->SelectObject(pOldFont);
  ReleaseDC (pdc);
}

int CCrystalTextView::GetLineHeight()
{
  if (m_nLineHeight == -1)
    CalcLineCharDim ();
  return m_nLineHeight;
}

int CCrystalTextView::GetSubLines(int nLineIndex)
{
  // get number of wrapped lines, this line contains of
  int nBreaks = 0;
  WrapLineCached( nLineIndex, GetScreenChars(), NULL, nBreaks );
  return nBreaks + 1;
}

int CCrystalTextView::CharPosToPoint(int nLineIndex,int nCharPos, CPoint &charPoint)
{
	// if we do not wrap lines, y is allways 0 and x is equl to nCharPos
	if( !m_bWordWrap )
	{
	  charPoint.x = nCharPos;
	  charPoint.y = 0;
	}

	// line is wrapped
	int *anBreaks = (int*)_alloca( sizeof( int ) * GetLineLength( nLineIndex ) );
	int	nBreaks = 0;

	WrapLineCached( nLineIndex, GetScreenChars(), anBreaks, nBreaks );

	for( int i = nBreaks - 1; i >= 0 && nCharPos < anBreaks[i]; i-- );

	charPoint.x = (i >= 0)? nCharPos - anBreaks[i] : nCharPos;
	charPoint.y = i + 1;

	return (i >= 0)? anBreaks[i] : 0;
}

int CCrystalTextView::CursorPointToCharPos(int nLineIndex,const CPoint &curPoint )
{
	// calculate char pos out of point
	int			nLength = GetLineLength( nLineIndex );
	int			nScreenChars = GetScreenChars();
	LPCTSTR	szLine = GetLineChars( nLineIndex );

	// wrap line
	int *anBreaks = (int*)_alloca( sizeof( int ) * nLength );
	int	nBreaks = 0;

	WrapLineCached(nLineIndex, nScreenChars, anBreaks, nBreaks );

	// find char pos that matches cursor position
	int nXPos = 0;
	int nYPos = 0;
	int	nCurPos = 0;
	int nTabSize = GetTabSize();

	for(int nIndex = 0; nIndex < nLength; nIndex++ )
	{
		if(nBreaks && nIndex == anBreaks[nYPos] )
		{
			nXPos = 0;
			nYPos++;
		}

		if(szLine[nIndex] == _T('\t'))
		{
		   nXPos+= (nTabSize - nCurPos % nTabSize);
		   nCurPos+= (nTabSize - nCurPos % nTabSize);
		}
		else
		{
		   nXPos++;
		   nCurPos++;
		}

		if( nXPos > curPoint.x && nYPos == curPoint.y )
			break;
		else if( nYPos > curPoint.y )
		{
			nIndex--;
			break;
		}
	}
	return nIndex;	
}

void CCrystalTextView::SubLineCursorPosToTextPos(const CPoint &subLineCurPos,
												                   CPoint &textPos )
{
	// Get line breaks
	int	nSubLineOffset, nLine;

	GetLineBySubLine( subLineCurPos.y, nLine, nSubLineOffset );

	// compute cursor-position
	textPos.x = CursorPointToCharPos(nLine,CPoint(subLineCurPos.x,nSubLineOffset));
	textPos.y = nLine;
}

int CCrystalTextView::SubLineEndToCharPos(int nLineIndex,int nSubLineOffset)
{
	int		nLength = GetLineLength(nLineIndex);

	// if word wrapping is disabled, the end is equal to the length of the line -1
	if(!m_bWordWrap)
		return nLength;

	// wrap line
	int *anBreaks = (int*)_alloca( sizeof( int ) * nLength);
	int	nBreaks = 0;

	WrapLineCached(nLineIndex,GetScreenChars(),anBreaks,nBreaks );

	// if there is no break inside the line or the given subline is the last
	// one in this line...
	if(!nBreaks || nSubLineOffset == nBreaks)
		return nLength;

	// compute character position for end of subline
	ASSERT(nSubLineOffset >= 0 && nSubLineOffset <= nBreaks);
	
	return anBreaks[nSubLineOffset] - 1;
}

int CCrystalTextView::SubLineHomeToCharPos(int nLineIndex,int nSubLineOffset)
{
	int		nLength = GetLineLength(nLineIndex);

	// if word wrapping is disabled, the start is 0
	if(!m_bWordWrap||nSubLineOffset == 0)
		return 0;

	// wrap line
	int *anBreaks = (int*)_alloca( sizeof( int ) * nLength);
	int	nBreaks = 0;

	WrapLineCached(nLineIndex,GetScreenChars(),anBreaks,nBreaks);

	// if there is no break inside the line...
	if( !nBreaks )
		return 0;

	// compute character position for end of subline
	ASSERT(nSubLineOffset > 0 && nSubLineOffset <= nBreaks);
	
	return anBreaks[nSubLineOffset - 1];
}
//END SW

int CCrystalTextView::GetCharWidth()
{
  if (m_nCharWidth == -1)
    CalcLineCharDim ();
  return m_nCharWidth;
}

int CCrystalTextView::GetMaxLineLength()
{
  if(m_nMaxLineLength == -1)
  {
     m_nMaxLineLength = 0;
     int nLineCount = GetLineCount();

     for(int I = 0; I < nLineCount;I++)
     {
       int nActualLength = GetLineActualLength(I);
       if(m_nMaxLineLength < nActualLength)
       m_nMaxLineLength = nActualLength;
     }
  }
  return m_nMaxLineLength;
}

CCrystalTextView *CCrystalTextView::GetSiblingView(int nRow, int nCol)
{
  CSplitterWnd *pSplitter = GetParentSplitter (this, FALSE);
  if (pSplitter == NULL)
    return NULL;

  CWnd *pWnd = CWnd::FromHandlePermanent(
                 ::GetDlgItem (pSplitter->m_hWnd, pSplitter->IdFromRowCol (nRow, nCol)));
  if (pWnd == NULL || !pWnd->IsKindOf (RUNTIME_CLASS (CCrystalTextView)))
    return NULL;
  return (CCrystalTextView *) pWnd;
}

void CCrystalTextView::GoToLine(int nLine, bool bRelative)
{
  int nLines = m_pTextBuffer->GetLineCount() - 1;
  CPoint ptCursorPos = GetCursorPos ();

  if(bRelative)
    nLine += ptCursorPos.y;

  if(nLine)
    nLine--;

  if(nLine > nLines)
    nLine = nLines;

  if(nLine >= 0)
  {
     int nChars = m_pTextBuffer->GetLineLength(nLine);

     if(nChars)
       nChars--;

     if(ptCursorPos.x > nChars)
       ptCursorPos.x = nChars;

     if(ptCursorPos.x >= 0)
     {
       ptCursorPos.y = nLine;
       ASSERT_VALIDTEXTPOS (ptCursorPos);
       SetAnchor (ptCursorPos);
       SetSelection (ptCursorPos, ptCursorPos);
       SetCursorPos (ptCursorPos);
       EnsureVisible (ptCursorPos);
	 }
  }
}

void CCrystalTextView::OnInitialUpdate()
{
  CView::OnInitialUpdate ();
  CString sDoc = GetDocument ()->GetPathName (), sExt = GetExt (sDoc);
  SetTextType(sExt);
  AttachToBuffer (NULL);

  CSplitterWnd *pSplitter = GetParentSplitter (this, FALSE);
  if(pSplitter != NULL)
  {
    //  See CSplitterWnd::IdFromRowCol() implementation
    int nRow = (GetDlgCtrlID () - AFX_IDW_PANE_FIRST) / 16;
    int nCol = (GetDlgCtrlID () - AFX_IDW_PANE_FIRST) % 16;
    ASSERT (nRow >= 0 && nRow < pSplitter->GetRowCount ());
    ASSERT (nCol >= 0 && nCol < pSplitter->GetColumnCount ());

    if(nRow > 0)
    {
       CCrystalTextView *pSiblingView = GetSiblingView (0, nCol);
       if(pSiblingView != NULL && pSiblingView != this)
       {
          m_nOffsetChar = pSiblingView->m_nOffsetChar;
          ASSERT(m_nOffsetChar >= 0 && m_nOffsetChar <= GetMaxLineLength ());
       }
	}

    if(nCol > 0)
    {
      CCrystalTextView *pSiblingView = GetSiblingView (nRow, 0);
      if(pSiblingView != NULL && pSiblingView != this)
      {
        m_nTopLine = pSiblingView->m_nTopLine;
        ASSERT (m_nTopLine >= 0 && m_nTopLine < GetLineCount ());
	  }
    }
  }

  SetTextType (sExt);
  SetFont (m_LogFont);

  if(m_bRememberLastPos && !sDoc.IsEmpty ())
  {
     DWORD dwLastPos[3];
     CString sKey = REG_EDITPAD;
     sKey += _T ("\\Remembered");
     CReg reg;
     if(reg.Open (HKEY_CURRENT_USER, sKey, KEY_READ) &&
        reg.LoadBinary (sDoc, (LPBYTE) dwLastPos, sizeof (dwLastPos)))
     {
          CPoint ptCursorPos;
          ptCursorPos.x = dwLastPos[1];
          ptCursorPos.y = dwLastPos[2];
          if(IsValidTextPosY (ptCursorPos))
		  {
             if (!IsValidTextPosX (ptCursorPos))
                ptCursorPos.x = 0;
             ASSERT_VALIDTEXTPOS (ptCursorPos);
             SetCursorPos (ptCursorPos);
             SetSelection (ptCursorPos, ptCursorPos);
             SetAnchor (ptCursorPos);
             EnsureVisible (ptCursorPos);
		  }
	 }
  }
}

/////////////////////////////////////////////////////////////////////////////
// CCrystalTextView printing

void CCrystalTextView::OnPrepareDC(CDC * pDC,CPrintInfo * pInfo)
{
  CView::OnPrepareDC (pDC, pInfo);

  if(pInfo != NULL)
  {
     pInfo->m_bContinuePrinting = TRUE;
     if (m_pnPages != NULL && (int) pInfo->m_nCurPage > m_nPrintPages)
        pInfo->m_bContinuePrinting = FALSE;
  }
}

BOOL CCrystalTextView::OnPreparePrinting (CPrintInfo * pInfo)
{
  return DoPreparePrinting (pInfo);
}

int CCrystalTextView::PrintLineHeight (CDC * pdc, int nLine)
{
  ASSERT (nLine >= 0 && nLine < GetLineCount ());
  ASSERT (m_nPrintLineHeight > 0);

  int nLength = GetLineLength (nLine);
  if (nLength == 0)
    return m_nPrintLineHeight;

  CString line;
  LPCTSTR pszChars = GetLineChars (nLine);
  ExpandChars (pszChars, 0, nLength, line);

  CRect rcPrintArea = m_rcPrintArea;
  pdc->DrawText (line, &rcPrintArea, DT_LEFT | DT_NOPREFIX | DT_TOP | DT_WORDBREAK | DT_CALCRECT);
  return rcPrintArea.Height ();
}

void CCrystalTextView::GetPrintHeaderText (int nPageNum, CString & text)
{
  ASSERT (m_bPrintHeader);
  text = _T ("");
}

void CCrystalTextView::GetPrintFooterText (int nPageNum, CString & text)
{
  ASSERT (m_bPrintFooter);
  text.Format (_T ("Page %d/%d"), nPageNum, m_nPrintPages);
}

void CCrystalTextView::PrintHeader (CDC * pdc, int nPageNum)
{
  CRect rcHeader = m_rcPrintArea;
  rcHeader.bottom = rcHeader.top;
  rcHeader.top -= (m_nPrintLineHeight + m_nPrintLineHeight / 2);

  CString text;
  GetPrintHeaderText(nPageNum,text);

  if (!text.IsEmpty())
    pdc->DrawText (text, &rcHeader, DT_CENTER | DT_NOPREFIX | DT_TOP | DT_SINGLELINE);
}

void CCrystalTextView::PrintFooter (CDC * pdc, int nPageNum)
{
  CRect rcFooter = m_rcPrintArea;
  rcFooter.top = rcFooter.bottom;
  rcFooter.bottom += (m_nPrintLineHeight + m_nPrintLineHeight / 2);

  CString text;
  GetPrintFooterText(nPageNum,text);

  if(!text.IsEmpty())
    pdc->DrawText (text, &rcFooter, DT_CENTER | DT_NOPREFIX | DT_BOTTOM | DT_SINGLELINE);
}

void CCrystalTextView::RecalcPageLayouts (CDC * pdc, CPrintInfo * pInfo)
{
  m_ptPageArea = pInfo->m_rectDraw;
  m_ptPageArea.NormalizeRect ();

  m_nPrintLineHeight = pdc->GetTextExtent (_T ("X")).cy;

  m_rcPrintArea = m_ptPageArea;
  CSize szTopLeft, szBottomRight;
  
  CWinApp *pApp = AfxGetApp ();  
  ASSERT (pApp != NULL);

  szTopLeft.cx = DEFAULT_PRINT_MARGIN;
  szBottomRight.cx = DEFAULT_PRINT_MARGIN;
  szTopLeft.cy = DEFAULT_PRINT_MARGIN;
  szBottomRight.cy = DEFAULT_PRINT_MARGIN;

  CReg reg;
  if(reg.Open (HKEY_CURRENT_USER, REG_EDITPAD, KEY_READ))
  {
      DWORD dwTemp;
      if (reg.LoadNumber (_T ("PageLeft"), &dwTemp))
        szTopLeft.cx = dwTemp;
      if (reg.LoadNumber (_T ("PageRight"), &dwTemp))
        szBottomRight.cx = dwTemp;
      if (reg.LoadNumber (_T ("PageTop"), &dwTemp))
        szTopLeft.cy = dwTemp;
      if (reg.LoadNumber (_T ("PageBottom"), &dwTemp))
        szBottomRight.cy = dwTemp;
  }


  pdc->HIMETRICtoLP (&szTopLeft);
  pdc->HIMETRICtoLP (&szBottomRight);

  m_rcPrintArea.left += szTopLeft.cx;
  m_rcPrintArea.right -= szBottomRight.cx;
  m_rcPrintArea.top += szTopLeft.cy;
  m_rcPrintArea.bottom -= szBottomRight.cy;

  if (m_bPrintHeader)
    m_rcPrintArea.top += m_nPrintLineHeight + m_nPrintLineHeight / 2;

  if (m_bPrintFooter)
    m_rcPrintArea.bottom += m_nPrintLineHeight + m_nPrintLineHeight / 2;

  int nLimit = 32;
  m_nPrintPages = 1;
  m_pnPages = new int[nLimit];
  m_pnPages[0] = 0;

  int nLineCount = GetLineCount ();
  int nLine = 1;
  int y = m_rcPrintArea.top + PrintLineHeight (pdc, 0);
  while(nLine < nLineCount)
  {
      int nHeight = PrintLineHeight (pdc, nLine);
      if(y + nHeight <= m_rcPrintArea.bottom)
          y += nHeight;
      else
	  {
         ASSERT (nLimit >= m_nPrintPages);
         if(nLimit <= m_nPrintPages)
         {
           nLimit += 32;
           int *pnNewPages = new int[nLimit];
           memcpy (pnNewPages, m_pnPages, sizeof (int) * m_nPrintPages);
           delete m_pnPages;
           m_pnPages = pnNewPages;
		 }
         
		 ASSERT (nLimit > m_nPrintPages);
         m_pnPages[m_nPrintPages++] = nLine;
         y = m_rcPrintArea.top + nHeight;
	  }
      nLine++;
  }
}

void CCrystalTextView::OnBeginPrinting (CDC * pdc, CPrintInfo * pInfo)
{
  ASSERT (m_pnPages == NULL);
  ASSERT (m_pPrintFont == NULL);
  CFont *pDisplayFont = GetFont ();

  LOGFONT lf;
  pDisplayFont->GetLogFont (&lf);

  CDC *pDisplayDC = GetDC ();
  lf.lfHeight = MulDiv (lf.lfHeight, pdc->GetDeviceCaps (LOGPIXELSY), pDisplayDC->GetDeviceCaps (LOGPIXELSY) * 2);
  lf.lfWidth = MulDiv (lf.lfWidth, pdc->GetDeviceCaps (LOGPIXELSX), pDisplayDC->GetDeviceCaps (LOGPIXELSX) * 2);
  ReleaseDC (pDisplayDC);

  m_pPrintFont = new CFont;
  if(!m_pPrintFont->CreateFontIndirect (&lf))
  {
     delete m_pPrintFont;
     m_pPrintFont = NULL;
     return;
  }
  pdc->SelectObject (m_pPrintFont);
}

void CCrystalTextView::OnEndPrinting(CDC * pdc, CPrintInfo * pInfo)
{
  if(m_pPrintFont != NULL)
  {
     delete m_pPrintFont;
     m_pPrintFont = NULL;
  }

  if(m_pnPages != NULL)
  {
     delete m_pnPages;
     m_pnPages = NULL;
  }

  m_nPrintPages = 0;
  m_nPrintLineHeight = 0;
}

void CCrystalTextView::OnPrint (CDC * pdc, CPrintInfo * pInfo)
{
  if(m_pnPages == NULL)
  {
     RecalcPageLayouts (pdc, pInfo);
     ASSERT (m_pnPages != NULL);
  }

  ASSERT (pInfo->m_nCurPage >= 1 && (int) pInfo->m_nCurPage <= m_nPrintPages);

  int nLine = m_pnPages[pInfo->m_nCurPage - 1];
  int nEndLine = GetLineCount ();

  if((int) pInfo->m_nCurPage < m_nPrintPages)
    nEndLine = m_pnPages[pInfo->m_nCurPage];

  TRACE (_T ("Printing page %d of %d, lines %d - %d\n"), pInfo->m_nCurPage, m_nPrintPages,
         nLine, nEndLine - 1);

  if(m_bPrintHeader)
    PrintHeader (pdc, pInfo->m_nCurPage);

  if(m_bPrintFooter)
    PrintFooter (pdc, pInfo->m_nCurPage);

  int y = m_rcPrintArea.top;
  for(; nLine < nEndLine; nLine++)
  {
    int nLineLength = GetLineLength (nLine);
    if(nLineLength == 0)
	{
       y += m_nPrintLineHeight;
       continue;
	}

    CRect rcPrintRect = m_rcPrintArea;
    rcPrintRect.top = y;
    LPCTSTR pszChars = GetLineChars (nLine);
    CString line;
    ExpandChars (pszChars, 0, nLineLength, line);
    y += pdc->DrawText (line, &rcPrintRect, DT_LEFT | DT_NOPREFIX | DT_TOP | DT_WORDBREAK);
  }
}


/////////////////////////////////////////////////////////////////////////////
// CCrystalTextView message handlers

int CCrystalTextView::GetLineCount ()
{
  if(m_pTextBuffer == NULL)
    return 1;                   //  Single empty line

  int nLineCount = m_pTextBuffer->GetLineCount ();
  ASSERT (nLineCount > 0);
  return nLineCount;
}

//BEGIN SW
int CCrystalTextView::GetSubLineCount()
{
	// if we do not wrap words, number of sub lines is equal to number of lines
	if(!m_bWordWrap )
		return GetLineCount();

	// calculate number of sub lines
	int	nLineCount = GetLineCount();
	int nSubLineCount = 0;

	for( int i = 0; i < nLineCount; i++ )
		nSubLineCount+= GetSubLines( i );

	return nSubLineCount;
}

int CCrystalTextView::GetSubLineIndex( int nLineIndex )
{
	// if we do not wrap words, subline index of this line is equal to its index
	if(!m_bWordWrap )
		return nLineIndex;

	// calculate subline index of the line
	int	nSubLineCount = 0;

	if(nLineIndex >= GetLineCount())
		nLineIndex = GetLineCount() - 1;

	for(int i = 0; i < nLineIndex; i++)
		nSubLineCount+= GetSubLines( i );

	return nSubLineCount;
}

void CCrystalTextView::GetLineBySubLine( int nSubLineIndex, int &nLine, int &nSubLine )
{
	ASSERT( nSubLineIndex < GetSubLineCount() );

	// if we do not wrap words, nLine is equal to nSubLineIndex and nSubLine is allways 0
	if(!m_bWordWrap )
	{
	   nLine = nSubLineIndex;
	   nSubLine = 0;
	}

	// compute result
	int	nSubLineCount = 0;
	int	nLineCount = GetLineCount();

	for(int i = 0; i < nLineCount; i++)
	{
	   nSubLineCount+= GetSubLines( i );
	   if(!(nSubLineCount <= nSubLineIndex))
			break;
	}

	ASSERT(i < nLineCount);
	nLine = i;
	nSubLine = nSubLineIndex - (nSubLineCount - GetSubLines(i));
}
//END SW

int CCrystalTextView::GetLineLength (int nLineIndex)
{
  if(m_pTextBuffer == NULL)
    return 0;
  return m_pTextBuffer->GetLineLength(nLineIndex);
}

LPCTSTR CCrystalTextView::GetLineChars (int nLineIndex)
{
  if(m_pTextBuffer == NULL)
    return NULL;
  return m_pTextBuffer->GetLineChars (nLineIndex);
}

void CCrystalTextView::AttachToBuffer (CCrystalTextBuffer * pBuf /*= NULL*/ )
{
  if(m_pTextBuffer != NULL)
    m_pTextBuffer->RemoveView (this);

  if(pBuf == NULL)
      pBuf = LocateTextBuffer ();

  m_pTextBuffer = pBuf;
  if(m_pTextBuffer != NULL)
    m_pTextBuffer->AddView (this);
  ResetView();

  //  Init scrollbars
  CScrollBar *pVertScrollBarCtrl = GetScrollBarCtrl (SB_VERT);
  if (pVertScrollBarCtrl != NULL)
    pVertScrollBarCtrl->EnableScrollBar (GetScreenLines () >= GetLineCount ()?
                                         ESB_DISABLE_BOTH : ESB_ENABLE_BOTH);
  CScrollBar *pHorzScrollBarCtrl = GetScrollBarCtrl (SB_HORZ);
  if (pHorzScrollBarCtrl != NULL)
    pHorzScrollBarCtrl->EnableScrollBar (GetScreenChars () >= GetMaxLineLength ()?
                                         ESB_DISABLE_BOTH : ESB_ENABLE_BOTH);

  //  Update scrollbars
  RecalcVertScrollBar ();
  RecalcHorzScrollBar ();
}

void CCrystalTextView::DetachFromBuffer ()
{
  if(m_pTextBuffer != NULL)
  {
     m_pTextBuffer->RemoveView (this);
     m_pTextBuffer = NULL;
     ResetView ();
  }
}

int CCrystalTextView::GetScreenLines ()
{
  if(m_nScreenLines == -1)
  {
    CRect rect;
    GetClientRect (&rect);
    m_nScreenLines = rect.Height () / GetLineHeight ();
  }
  return m_nScreenLines;
}

BOOL CCrystalTextView::GetItalic (int nColorIndex)
{
  return nColorIndex == COLORINDEX_COMMENT;
  //  return FALSE;
}

BOOL CCrystalTextView::GetBold (int nColorIndex)
{
  return nColorIndex == COLORINDEX_KEYWORD;
  //  return FALSE;
}

int CCrystalTextView::GetScreenChars()
{
  if(m_nScreenChars == -1)
  {
    CRect rect;
    GetClientRect (&rect);
    m_nScreenChars = (rect.Width () - GetMarginWidth ()) / GetCharWidth ();
  }
  return m_nScreenChars;
}

void CCrystalTextView::OnDestroy()
{
  GetFont()->GetLogFont(&m_lfBaseFont);
  DetachFromBuffer();
  m_hAccel = NULL;

  CView::OnDestroy();

  for(int I = 0; I < 4; I++)
  {
      if(m_apFonts[I] != NULL)
	  {
        m_apFonts[I]->DeleteObject ();
        delete m_apFonts[I];
        m_apFonts[I] = NULL;
      }
  }

  if(m_pCacheBitmap != NULL)
  {
     delete m_pCacheBitmap;
     m_pCacheBitmap = NULL;
  }
}

BOOL CCrystalTextView::OnEraseBkgnd (CDC * pdc)
{
  return TRUE;
}

void CCrystalTextView::OnSize (UINT nType, int cx, int cy)
{
  CView::OnSize (nType, cx, cy);

	// get char position of top left visible character with old cached word wrap
	CPoint	topPos;
	SubLineCursorPosToTextPos( CPoint( 0, m_nTopSubLine ), topPos );

  if(m_pCacheBitmap != NULL)
  {
     m_pCacheBitmap->DeleteObject ();
     delete m_pCacheBitmap;
     m_pCacheBitmap = NULL;
  }

  m_nScreenLines = -1;
  m_nScreenChars = -1;

	//BEGIN SW
	// we have to recompute the line wrapping
	InvalidateLineCache( 0, -1 );

	// compute new top sub line
	CPoint	topSubLine;
	CharPosToPoint( topPos.y, topPos.x, topSubLine );
	m_nTopSubLine = topPos.y + topSubLine.y;

	// set caret to right position
	UpdateCaret();
	//END SW

  RecalcVertScrollBar ();
  RecalcHorzScrollBar ();
  PostMessage (WM_COMMAND, ID_FORCE_REDRAW);
}

void CCrystalTextView::UpdateSiblingScrollPos (BOOL bHorz)
{
  CSplitterWnd *pSplitterWnd = GetParentSplitter (this, FALSE);
  if(pSplitterWnd != NULL)
  {
      //  See CSplitterWnd::IdFromRowCol() implementation for details
      int nCurrentRow = (GetDlgCtrlID () - AFX_IDW_PANE_FIRST) / 16;
      int nCurrentCol = (GetDlgCtrlID () - AFX_IDW_PANE_FIRST) % 16;
      ASSERT (nCurrentRow >= 0 && nCurrentRow < pSplitterWnd->GetRowCount ());
      ASSERT (nCurrentCol >= 0 && nCurrentCol < pSplitterWnd->GetColumnCount ());

      if(bHorz)
      {
         int nCols = pSplitterWnd->GetColumnCount ();
         for(int nCol = 0; nCol < nCols; nCol++)
		 {
            if(nCol != nCurrentCol)  //  We don't need to update ourselves
			{
               CCrystalTextView *pSiblingView = GetSiblingView (nCurrentRow, nCol);
               if (pSiblingView != NULL)
                  pSiblingView->OnUpdateSibling (this, TRUE);
			}
		 }
	  }
      else
	  {
         int nRows = pSplitterWnd->GetRowCount ();
         for(int nRow = 0; nRow < nRows; nRow++)
		 {
            if(nRow != nCurrentRow)  //  We don't need to update ourselves
			{
               CCrystalTextView *pSiblingView = GetSiblingView (nRow, nCurrentCol);
               if (pSiblingView != NULL)
                   pSiblingView->OnUpdateSibling (this, FALSE);
			}
		 }
	  }
    }
}

void CCrystalTextView::OnUpdateSibling (CCrystalTextView * pUpdateSource, BOOL bHorz)
{
  if(pUpdateSource != this)
  {
     ASSERT (pUpdateSource != NULL);
     ASSERT_KINDOF (CCrystalTextView, pUpdateSource);
     if(bHorz)
	 {
          ASSERT (pUpdateSource->m_nTopLine >= 0);
          ASSERT (pUpdateSource->m_nTopLine < GetLineCount ());
          if(pUpdateSource->m_nTopLine != m_nTopLine)
		  {
             ScrollToLine(pUpdateSource->m_nTopLine, TRUE, FALSE);
             UpdateCaret();
          }
	 }
     else
	 {
        ASSERT(pUpdateSource->m_nOffsetChar >= 0);
        ASSERT (pUpdateSource->m_nOffsetChar < GetMaxLineLength ());
        if(pUpdateSource->m_nOffsetChar != m_nOffsetChar)
		{
          ScrollToChar (pUpdateSource->m_nOffsetChar, TRUE, FALSE);
          UpdateCaret ();
		}
	 }
  }
}

void CCrystalTextView::RecalcVertScrollBar (BOOL bPositionOnly /*= FALSE*/ )
{
  SCROLLINFO si;
  si.cbSize = sizeof (si);
  if(bPositionOnly)
  {
      si.fMask = SIF_POS;
		//BEGIN SW
		si.nPos = m_nTopSubLine;
		/*ORIGINAL
		si.nPos = m_nTopLine;
		*/
		//END SW
  }
  else
  {
		//BEGIN SW
	 if(GetScreenLines() >= GetSubLineCount() && m_nTopSubLine > 0 )
		/*ORIGINAL
		if (GetScreenLines() >= GetLineCount() && m_nTopLine > 0)
		*/
		//END SW
	 {
          m_nTopLine = 0;
          Invalidate ();
          UpdateCaret ();
	 }
     
	 si.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_POS | SIF_RANGE;
     si.nMin = 0;
		//BEGIN SW
	 si.nMax = GetSubLineCount() - 1;
		/*ORIGINAL
		si.nMax = GetLineCount() - 1;
		*/
		//END SW
     si.nPage = GetScreenLines ();
		//BEGIN SW
	 si.nPos = m_nTopSubLine;
		/*ORIGINAL
		si.nPos = m_nTopLine;
		*/
		//END SW
  }
  VERIFY (SetScrollInfo (SB_VERT, &si));
}

void CCrystalTextView::OnVScroll (UINT nSBCode, UINT nPos, CScrollBar * pScrollBar)
{
  CView::OnVScroll (nSBCode, nPos, pScrollBar);

  //  Note we cannot use nPos because of its 16-bit nature
  SCROLLINFO si;
  si.cbSize = sizeof (si);
  si.fMask = SIF_ALL;
  VERIFY (GetScrollInfo (SB_VERT, &si));

	//BEGIN SW
	int nPageLines = GetScreenLines();
	int nSubLineCount = GetSubLineCount();

	int nNewTopSubLine;
	BOOL bDisableSmooth = TRUE;
	switch (nSBCode)
	{
	case SB_TOP:
		nNewTopSubLine = 0;
		bDisableSmooth = FALSE;
		break;
	case SB_BOTTOM:
		nNewTopSubLine = nSubLineCount - nPageLines + 1;
		bDisableSmooth = FALSE;
		break;
	case SB_LINEUP:
		nNewTopSubLine = m_nTopSubLine - 1;
		break;
	case SB_LINEDOWN:
		nNewTopSubLine = m_nTopSubLine + 1;
		break;
	case SB_PAGEUP:
		nNewTopSubLine = m_nTopSubLine - si.nPage + 1;
		bDisableSmooth = FALSE;
		break;
	case SB_PAGEDOWN:
		nNewTopSubLine = m_nTopSubLine + si.nPage - 1;
		bDisableSmooth = FALSE;
		break;
	case SB_THUMBPOSITION:
	case SB_THUMBTRACK:
		nNewTopSubLine = si.nTrackPos;
		break;
	default:
		return;
	}

	if (nNewTopSubLine < 0)
		nNewTopSubLine = 0;
	if (nNewTopSubLine >= nSubLineCount)
		nNewTopSubLine = nSubLineCount - 1;
	ScrollToSubLine(nNewTopSubLine, bDisableSmooth);

	/*ORIGINAL
	int nPageLines = GetScreenLines();
	int nLineCount = GetLineCount();

	int nNewTopLine;
	BOOL bDisableSmooth = TRUE;
	switch (nSBCode)
	{
	case SB_TOP:
		nNewTopLine = 0;
		bDisableSmooth = FALSE;
		break;
	case SB_BOTTOM:
		nNewTopLine = nLineCount - nPageLines + 1;
		bDisableSmooth = FALSE;
		break;
	case SB_LINEUP:
		nNewTopLine = m_nTopLine - 1;
		break;
	case SB_LINEDOWN:
		nNewTopLine = m_nTopLine + 1;
		break;
	case SB_PAGEUP:
		nNewTopLine = m_nTopLine - si.nPage + 1;
		bDisableSmooth = FALSE;
		break;
	case SB_PAGEDOWN:
		nNewTopLine = m_nTopLine + si.nPage - 1;
		bDisableSmooth = FALSE;
		break;
	case SB_THUMBPOSITION:
	case SB_THUMBTRACK:
		nNewTopLine = si.nTrackPos;
		break;
	default:
		return;
	}

	if (nNewTopLine < 0)
		nNewTopLine = 0;
	if (nNewTopLine >= nLineCount)
		nNewTopLine = nLineCount - 1;
	ScrollToLine(nNewTopLine, bDisableSmooth);
	*///END SW
}

void CCrystalTextView::RecalcHorzScrollBar (BOOL bPositionOnly /*= FALSE*/ )
{
  //  Again, we cannot use nPos because it's 16-bit
  SCROLLINFO si;
  si.cbSize = sizeof (si);
  if(bPositionOnly)
  {
     si.fMask = SIF_POS;
     si.nPos = m_nOffsetChar;
  }
  else
  {
     if(GetScreenChars () >= GetMaxLineLength () && m_nOffsetChar > 0)
     {
        m_nOffsetChar = 0;
        Invalidate ();
        UpdateCaret ();
     }
     
	 si.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_POS | SIF_RANGE;
     si.nMin  = 0;
     si.nMax  = 20*GetMaxLineLength() - 1;
     si.nPage = GetScreenChars();
     si.nPos  = m_nOffsetChar;
  }
  VERIFY (SetScrollInfo (SB_HORZ, &si));
}

void CCrystalTextView::OnHScroll (UINT nSBCode, UINT nPos, CScrollBar * pScrollBar)
{
  CView::OnHScroll (nSBCode, nPos, pScrollBar);

  SCROLLINFO si;
  si.cbSize = sizeof (si);
  si.fMask = SIF_ALL;
  VERIFY (GetScrollInfo (SB_HORZ, &si));

  int nPageChars = GetScreenChars ();
  int nMaxLineLength = GetMaxLineLength ();

  int nNewOffset;
  switch (nSBCode)
    {
    case SB_LEFT:
      nNewOffset = 0;
      break;
    case SB_BOTTOM:
      nNewOffset = nMaxLineLength - nPageChars + 1;
      break;
    case SB_LINEUP:
      nNewOffset = m_nOffsetChar - 1;
      break;
    case SB_LINEDOWN:
      nNewOffset = m_nOffsetChar + 1;
      break;
    case SB_PAGEUP:
      nNewOffset = m_nOffsetChar - si.nPage + 1;
      break;
    case SB_PAGEDOWN:
      nNewOffset = m_nOffsetChar + si.nPage - 1;
      break;
    case SB_THUMBPOSITION:
    case SB_THUMBTRACK:
      nNewOffset = si.nTrackPos;
      break;
    default:
      return;
    }

  //if (nNewOffset >= nMaxLineLength)
  //  nNewOffset = nMaxLineLength - 1;
  if (nNewOffset < 0)
    nNewOffset = 0;
  ScrollToChar (nNewOffset, TRUE);
  UpdateCaret ();
}





BOOL CCrystalTextView::OnSetCursor (CWnd * pWnd, UINT nHitTest, UINT message)
{
  if(nHitTest == HTCLIENT)
  {
      CPoint pt;
      ::GetCursorPos(&pt);
      ScreenToClient(&pt);

      if(pt.x < GetMarginWidth())
      {
        ::SetCursor(::LoadCursor(GetResourceHandle(),MAKEINTRESOURCE(IDR_MARGIN_CURSOR)));
      }
      else
      {
         CPoint ptText = ClientToText(pt);
         PrepareSelBounds();

          if(IsInsideSelBlock(ptText))
		  {
              //  [JRT]:  Support For Disabling Drag and Drop...
             if(!m_bDisableDragAndDrop)   // If Drag And Drop Not Disabled
                ::SetCursor(::LoadCursor (NULL, MAKEINTRESOURCE (IDC_ARROW)));     // Set To Arrow Cursor
          }
          else
          ::SetCursor(::LoadCursor(NULL,MAKEINTRESOURCE(IDC_IBEAM)));
	  }
      return TRUE;
  }
  return CView::OnSetCursor(pWnd,nHitTest,message);
}

CPoint CCrystalTextView::ClientToText (const CPoint & point)
{
	//BEGIN SW
	int nSubLineCount = GetSubLineCount();
	int nLineCount = GetLineCount();

	CPoint pt;
	pt.y = m_nTopSubLine + point.y / GetLineHeight();
	if (pt.y >= nSubLineCount)
		pt.y = nSubLineCount - 1;
	if (pt.y < 0)
		pt.y = 0;

	int nLine;
	int nSubLineOffset;
	int nOffsetChar = m_nOffsetChar;

	GetLineBySubLine( pt.y, nLine, nSubLineOffset );
	pt.y = nLine;

	LPCTSTR pszLine = NULL;
	int	nLength = 0;
	int *anBreaks = NULL;
	int	nBreaks = 0;

	if (pt.y >= 0 && pt.y < nLineCount)
	{
		nLength = GetLineLength( pt.y );
		anBreaks = (int*)_alloca( sizeof( int ) * nLength );
		pszLine = GetLineChars(pt.y);
		WrapLineCached( pt.y, GetScreenChars(), anBreaks, nBreaks );

		if( nSubLineOffset > 0 )
			nOffsetChar = anBreaks[nSubLineOffset - 1];
		if( nBreaks > nSubLineOffset )
			nLength = anBreaks[nSubLineOffset] - 1;
	}

	int nPos = nOffsetChar + (point.x - GetMarginWidth()) / GetCharWidth();
	if (nPos < 0)
		nPos = 0;

	int nIndex = 0, nCurPos = 0, n = 0, i = 0;
	int nTabSize = GetTabSize();

	/*
	if( m_bWordWrap )
		nCurPos = nIndex = nOffsetChar;
	*/

	while (nIndex < nLength)
	{
		if( nBreaks && nIndex == anBreaks[i] )
		{
			n = nIndex;
			i++;
		}

		if (pszLine[nIndex] == _T('\t'))
		{
			n+= (nTabSize - nCurPos % nTabSize);
			nCurPos += (nTabSize - nCurPos % nTabSize);
		}
		else
		{
			n++;
			nCurPos ++;
		}

		if (n > nPos && i == nSubLineOffset)
			break;

		nIndex ++;
	}

	ASSERT(nIndex >= 0 && nIndex <= nLength);
	pt.x = nIndex;
	return pt;

	/*ORIGINAL
	int nLineCount = GetLineCount();

	CPoint pt;
	pt.y = m_nTopLine + point.y / GetLineHeight();
	if (pt.y >= nLineCount)
		pt.y = nLineCount - 1;
	if (pt.y < 0)
		pt.y = 0;

	int nLength = 0;
	LPCTSTR pszLine = NULL;
	if (pt.y >= 0 && pt.y < nLineCount)
	{
		nLength = GetLineLength(pt.y);
		pszLine = GetLineChars(pt.y);
	}

	int nPos = m_nOffsetChar + (point.x - GetMarginWidth()) / GetCharWidth();
	if (nPos < 0)
		nPos = 0;

	int nIndex = 0, nCurPos = 0;
	int nTabSize = GetTabSize();
	while (nIndex < nLength)
	{
		if (pszLine[nIndex] == _T('\t'))
			nCurPos += (nTabSize - nCurPos % nTabSize);
		else
			nCurPos ++;

		if (nCurPos > nPos)
			break;

		nIndex ++;
	}

	ASSERT(nIndex >= 0 && nIndex <= nLength);
	pt.x = nIndex;
	return pt;
	*///END SW
}

#ifdef _DEBUG
void CCrystalTextView::AssertValidTextPos (const CPoint & point)
{
  if(GetLineCount () > 0)
  {
     ASSERT(m_nTopLine >= 0 && m_nOffsetChar >= 0);
     ASSERT(point.y >= 0 && point.y < GetLineCount ());
     ASSERT(point.x >= 0 && point.x <= GetLineLength(point.y));
  }
}
#endif

bool CCrystalTextView::IsValidTextPos (const CPoint &point)
{
  return GetLineCount () > 0 && m_nTopLine >= 0 && m_nOffsetChar >= 0 &&
    point.y >= 0 && point.y < GetLineCount () && point.x >= 0 && point.x <= GetLineLength (point.y);
}

bool CCrystalTextView::IsValidTextPosX (const CPoint &point)
{
  return GetLineCount () > 0 && m_nTopLine >= 0 && m_nOffsetChar >= 0 &&
    point.y >= 0 && point.y < GetLineCount () && point.x >= 0 && point.x <= GetLineLength (point.y);
}

bool CCrystalTextView::IsValidTextPosY (const CPoint &point)
{
  return GetLineCount () > 0 && m_nTopLine >= 0 && m_nOffsetChar >= 0 &&
    point.y >= 0 && point.y < GetLineCount ();
}

CPoint CCrystalTextView::TextToClient (const CPoint & point)
{
  ASSERT_VALIDTEXTPOS (point);
  LPCTSTR pszLine = GetLineChars (point.y);

  CPoint pt;
	//BEGIN SW
	CPoint	charPoint;
	int			nSubLineStart = CharPosToPoint( point.y, point.x, charPoint );
	charPoint.y+= GetSubLineIndex( point.y );

	// compute y-position
	pt.y = (charPoint.y - m_nTopSubLine) * GetLineHeight();

	// if pt.x is null, we know the result
	if(charPoint.x == 0 )
	{
		pt.x = GetMarginWidth();
		return pt;
	}

	// we have to calculate x-position
	int	nPreOffset = 0;
	/*ORIGINAL
	pt.y = (point.y - m_nTopLine) * GetLineHeight();
	*/
	//END SW
  pt.x = 0;
  int nTabSize = GetTabSize ();
  for(int nIndex = 0; nIndex < point.x; nIndex++)
  {
		//BEGIN SW
		if( nIndex == nSubLineStart )
			nPreOffset = pt.x;
		//END SW
      if (pszLine[nIndex] == _T ('\t'))
        pt.x += (nTabSize - pt.x % nTabSize);
      else
        pt.x++;
  }
	//BEGIN SW
  pt.x-= nPreOffset;
	//END SW

  pt.x = (pt.x - m_nOffsetChar) * GetCharWidth () + GetMarginWidth ();
  return pt;
}

void CCrystalTextView::InvalidateLines (int nLine1, int nLine2, BOOL bInvalidateMargin /*= FALSE*/ )
{
  bInvalidateMargin = TRUE;
  if(nLine2 == -1)
  {
      CRect rcInvalid;
      GetClientRect (&rcInvalid);
      if (!bInvalidateMargin)
        rcInvalid.left += GetMarginWidth ();
		//BEGIN SW
		rcInvalid.top = (GetSubLineIndex( nLine1 ) - m_nTopSubLine) * GetLineHeight();
		/*ORIGINAL
		rcInvalid.top = (nLine1 - m_nTopLine) * GetLineHeight();
		*/
		//END SW
      InvalidateRect (&rcInvalid, FALSE);
  }
  else
  {
      if (nLine2 < nLine1)
        {
          int nTemp = nLine1;
          nLine1 = nLine2;
          nLine2 = nTemp;
        }
      CRect rcInvalid;
      GetClientRect (&rcInvalid);
      if (!bInvalidateMargin)
        rcInvalid.left += GetMarginWidth ();
		//BEGIN SW
		rcInvalid.top = (GetSubLineIndex( nLine1 ) - m_nTopSubLine) * GetLineHeight();
		rcInvalid.bottom = (GetSubLineIndex( nLine2 ) - m_nTopSubLine + GetSubLines( nLine2 )) * GetLineHeight();
		/*ORIGINAL
		rcInvalid.top = (nLine1 - m_nTopLine) * GetLineHeight();
		rcInvalid.bottom = (nLine2 - m_nTopLine + 1) * GetLineHeight();
		*/
		//END SW
      InvalidateRect (&rcInvalid, FALSE);
  }
}

void CCrystalTextView::SetSelection (const CPoint & ptStart, const CPoint & ptEnd)
{
  ASSERT_VALIDTEXTPOS (ptStart);
  ASSERT_VALIDTEXTPOS (ptEnd);
  if(m_ptSelStart == ptStart)
  {
     if (m_ptSelEnd != ptEnd)
        InvalidateLines (ptEnd.y, m_ptSelEnd.y);
  }
  else
  {
     InvalidateLines (ptStart.y, ptEnd.y);
     InvalidateLines (m_ptSelStart.y, m_ptSelEnd.y);
  }
  m_ptSelStart = ptStart;
  m_ptSelEnd = ptEnd;
}

void CCrystalTextView::AdjustTextPoint (CPoint & point)
{
  point.x += GetCharWidth() / 2;   //todo
}

void CCrystalTextView::OnSetFocus (CWnd * pOldWnd)
{
  CView::OnSetFocus (pOldWnd);

  m_bFocused = TRUE;
  if (m_ptSelStart != m_ptSelEnd)
    InvalidateLines (m_ptSelStart.y, m_ptSelEnd.y);
  UpdateCaret ();
}

DWORD CCrystalTextView::ParseLinePlain (DWORD dwCookie, int nLineIndex, TEXTBLOCK * pBuf, int &nActualItems)
{
  return 0;
}

DWORD CCrystalTextView::ParseLine (DWORD dwCookie, int nLineIndex, TEXTBLOCK * pBuf, int &nActualItems)
{
  return (this->*(m_CurSourceDef->ParseLineX)) (dwCookie, nLineIndex, pBuf, nActualItems);
}

int CCrystalTextView::CalculateActualOffset (int nLineIndex, int nCharIndex)
{
  int nLength = GetLineLength (nLineIndex);
  ASSERT (nCharIndex >= 0 && nCharIndex <= nLength);
  LPCTSTR pszChars = GetLineChars (nLineIndex);
  int nOffset = 0;
  int nTabSize = GetTabSize ();
	//BEGIN SW
	int			*anBreaks = (int*)_alloca( sizeof( int ) * nLength );
	int			nBreaks = 0;

	/*if( nLength > GetScreenChars() )*/
	WrapLineCached( nLineIndex, GetScreenChars(), anBreaks, nBreaks );

	int	nPreOffset = 0;
	int	nPreBreak = 0;

	if( nBreaks )
	{
		for( int J = nBreaks - 1; J >= 0 && nCharIndex < anBreaks[J]; J-- );
		nPreBreak = anBreaks[J];
	}
	//END SW
  for(int I = 0; I < nCharIndex; I++)
  {
		//BEGIN SW
	 if(nPreBreak == I && nBreaks )
			nPreOffset = nOffset;
		//END SW

     if(pszChars[I] == _T ('\t'))
        nOffset += (nTabSize - nOffset % nTabSize);
     else
        nOffset++;
  }
	//BEGIN SW
	if( nPreBreak == I && nBreaks )
		return 0;
	else
		return nOffset - nPreOffset;
	/*ORIGINAL
	return nOffset;
	*///END SW
}

int CCrystalTextView::ApproxActualOffset (int nLineIndex, int nOffset)
{
  if (nOffset == 0)
    return 0;

  int nLength = GetLineLength (nLineIndex);
  LPCTSTR pszChars = GetLineChars (nLineIndex);
  int nCurrentOffset = 0;
  int nTabSize = GetTabSize ();
  for(int I = 0; I < nLength; I++)
  {
     if(pszChars[I] == _T ('\t'))
        nCurrentOffset += (nTabSize - nCurrentOffset % nTabSize);
     else
        nCurrentOffset++;
     if(nCurrentOffset >= nOffset)
     {
        if(nOffset <= nCurrentOffset - nTabSize / 2)
            return I;
        return I + 1;
     }
  }
  return nLength;
}

void CCrystalTextView::EnsureVisible (CPoint pt)
{
  //  Scroll vertically
	//BEGIN SW
	int			nSubLineCount = GetSubLineCount();
	int			nNewTopSubLine = m_nTopSubLine;
	CPoint	subLinePos;

	CharPosToPoint( pt.y, pt.x, subLinePos );
	subLinePos.y+= GetSubLineIndex( pt.y );

	if( subLinePos.y >= nNewTopSubLine + GetScreenLines() )
		nNewTopSubLine = subLinePos.y - GetScreenLines() + 1;
	if( subLinePos.y < nNewTopSubLine )
		nNewTopSubLine = subLinePos.y;

	if( nNewTopSubLine < 0 )
		nNewTopSubLine = 0;
	if( nNewTopSubLine >= nSubLineCount )
		nNewTopSubLine = nSubLineCount - 1;
	
	if( nNewTopSubLine != m_nTopSubLine )
	{
		ScrollToSubLine( nNewTopSubLine );
		UpdateCaret();
		UpdateSiblingScrollPos( TRUE );
	}
	/*ORIGINAL
	int nLineCount = GetLineCount();
	int nNewTopLine = m_nTopLine;
	if (pt.y >= nNewTopLine + GetScreenLines())
	{
		nNewTopLine = pt.y - GetScreenLines() + 1;
	}
	if (pt.y < nNewTopLine)
	{
		nNewTopLine = pt.y;
	}

	if (nNewTopLine < 0)
		nNewTopLine = 0;
	if (nNewTopLine >= nLineCount)
		nNewTopLine = nLineCount - 1;

	if (m_nTopLine != nNewTopLine)
	{
		ScrollToLine(nNewTopLine);
		UpdateSiblingScrollPos(TRUE);
	}
	*/
	//END SW

  //  Scroll horizontally
	//BEGIN SW
	// we do not need horizontally scrolling, if we wrap the words
	if( m_bWordWrap )
		return;
	//END SW
  int nActualPos = CalculateActualOffset (pt.y, pt.x);
  int nNewOffset = m_nOffsetChar;
  
  if(nActualPos > nNewOffset + GetScreenChars ())
      nNewOffset = nActualPos - GetScreenChars ();

  if(nActualPos < nNewOffset)
      nNewOffset = nActualPos;

  if (nNewOffset >= GetMaxLineLength ())
    nNewOffset = GetMaxLineLength () - 1;

  if (nNewOffset < 0)
    nNewOffset = 0;

  if(m_nOffsetChar != nNewOffset)
  {
    ScrollToChar (nNewOffset);
    UpdateCaret ();
    UpdateSiblingScrollPos (FALSE);
  }
}

void CCrystalTextView::OnKillFocus (CWnd * pNewWnd)
{
  CView::OnKillFocus (pNewWnd);

  m_bFocused = FALSE;
  UpdateCaret ();
  if(m_ptSelStart != m_ptSelEnd)
    InvalidateLines (m_ptSelStart.y, m_ptSelEnd.y);

  if(m_bDragSelection)
  {
    ReleaseCapture ();
    KillTimer (m_nDragSelTimer);
    m_bDragSelection = FALSE;
  }
}

void CCrystalTextView::OnSysColorChange ()
{
  CView::OnSysColorChange ();
  Invalidate ();
}

void CCrystalTextView::GetText (const CPoint & ptStart, const CPoint & ptEnd, CString & text)
{
  if(m_pTextBuffer != NULL)
    m_pTextBuffer->GetText (ptStart.y, ptStart.x, ptEnd.y, ptEnd.x, text);
  else
    text = _T ("");
}

void CCrystalTextView::UpdateView (CCrystalTextView * pSource,
								   CUpdateContext * pContext,
            DWORD dwFlags, int nLineIndex /*= -1*/ )
{
  // SetTextType (GetExt (GetDocument ()->GetPathName ()));
  if(dwFlags & UPDATE_RESET)
  {
      ResetView ();
      RecalcVertScrollBar ();
      RecalcHorzScrollBar ();
      return;
  }

  int nLineCount = GetLineCount ();
  ASSERT (nLineCount > 0);
  ASSERT (nLineIndex >= -1 && nLineIndex < nLineCount);
  if((dwFlags & UPDATE_SINGLELINE) != 0)
  {
      ASSERT (nLineIndex != -1);
      //  All text below this line should be reparsed
      if (m_pdwParseCookies != NULL)
        {
          ASSERT (m_nParseArraySize == nLineCount);
          memset (m_pdwParseCookies + nLineIndex, 0xff, sizeof (DWORD) * (m_nParseArraySize - nLineIndex));
        }
      //  This line'th actual length must be recalculated
      if (m_pnActualLineLength != NULL)
        {
          ASSERT (m_nActualLengthArraySize == nLineCount);
          m_pnActualLineLength[nLineIndex] = -1;
			//BEGIN SW
			InvalidateLineCache( nLineIndex, nLineIndex );
			//END SW
        }
      //  Repaint the lines
      InvalidateLines (nLineIndex, -1, TRUE);
  }
  else
  {
      if (nLineIndex == -1)
        nLineIndex = 0;         //  Refresh all text
      //  All text below this line should be reparsed

      if (m_pdwParseCookies != NULL)
        {
          if (m_nParseArraySize != nLineCount)
            {
              //  Reallocate cookies array
              DWORD *pdwNewArray = new DWORD[nLineCount];
              if (nLineIndex > 0)
                memcpy (pdwNewArray, m_pdwParseCookies, sizeof (DWORD) * nLineIndex);
              delete m_pdwParseCookies;
              m_nParseArraySize = nLineCount;
              m_pdwParseCookies = pdwNewArray;
            }
          memset (m_pdwParseCookies + nLineIndex, 0xff, sizeof (DWORD) * (m_nParseArraySize - nLineIndex));
        }
      //  Recalculate actual length for all lines below this
      if (m_pnActualLineLength != NULL)
        {
          if (m_nActualLengthArraySize != nLineCount)
            {
              //  Reallocate actual length array
              int *pnNewArray = new int[nLineCount];
              if (nLineIndex > 0)
                memcpy (pnNewArray, m_pnActualLineLength, sizeof (int) * nLineIndex);
              delete m_pnActualLineLength;
              m_nActualLengthArraySize = nLineCount;
              m_pnActualLineLength = pnNewArray;
            }
          memset (m_pnActualLineLength + nLineIndex, 0xff, sizeof (DWORD) * (m_nActualLengthArraySize - nLineIndex));
        }
		//BEGIN SW
		InvalidateLineCache( nLineIndex, -1 );
		//END SW
      //  Repaint the lines
      InvalidateLines (nLineIndex, -1, TRUE);
    }

  //  All those points must be recalculated and validated
  if (pContext != NULL)
    {
      pContext->RecalcPoint (m_ptCursorPos);
      pContext->RecalcPoint (m_ptSelStart);
      pContext->RecalcPoint (m_ptSelEnd);
      pContext->RecalcPoint (m_ptAnchor);
      ASSERT_VALIDTEXTPOS (m_ptCursorPos);
      ASSERT_VALIDTEXTPOS (m_ptSelStart);
      ASSERT_VALIDTEXTPOS (m_ptSelEnd);
      ASSERT_VALIDTEXTPOS (m_ptAnchor);
      if (m_bDraggingText)
        {
          pContext->RecalcPoint (m_ptDraggedTextBegin);
          pContext->RecalcPoint (m_ptDraggedTextEnd);
          ASSERT_VALIDTEXTPOS (m_ptDraggedTextBegin);
          ASSERT_VALIDTEXTPOS (m_ptDraggedTextEnd);
        }
      CPoint ptTopLine (0, m_nTopLine);
      pContext->RecalcPoint (ptTopLine);
      ASSERT_VALIDTEXTPOS (ptTopLine);
      m_nTopLine = ptTopLine.y;
      UpdateCaret ();
    }

  //  Recalculate vertical scrollbar, if needed
  if ((dwFlags & UPDATE_VERTRANGE) != 0)
    {
      if (!m_bVertScrollBarLocked)
        RecalcVertScrollBar ();
    }

  //  Recalculate horizontal scrollbar, if needed
  if ((dwFlags & UPDATE_HORZRANGE) != 0)
    {
      m_nMaxLineLength = -1;
      if (!m_bHorzScrollBarLocked)
        RecalcHorzScrollBar ();
    }
}

HINSTANCE CCrystalTextView::GetResourceHandle ()
{
#ifdef CRYSEDIT_RES_HANDLE
  return CRYSEDIT_RES_HANDLE;
#else
  if (s_hResourceInst != NULL)
    return s_hResourceInst;
  return AfxGetResourceHandle ();
#endif
}

int CCrystalTextView::OnCreate (LPCREATESTRUCT lpCreateStruct)
{
  memset (&m_lfBaseFont, 0, sizeof (m_lfBaseFont));
  _tcscpy (m_lfBaseFont.lfFaceName, _T ("FixedSys"));
  m_lfBaseFont.lfHeight = 0;
  m_lfBaseFont.lfWeight = FW_NORMAL;
  m_lfBaseFont.lfItalic = FALSE;
  m_lfBaseFont.lfCharSet = DEFAULT_CHARSET;
  m_lfBaseFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
  m_lfBaseFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  m_lfBaseFont.lfQuality = DEFAULT_QUALITY;
  m_lfBaseFont.lfPitchAndFamily = DEFAULT_PITCH;

  if (CView::OnCreate (lpCreateStruct) == -1)
    return -1;

  ASSERT (m_hAccel == NULL);
             // vvv GetResourceHandle () ???
  HINSTANCE hInst = AfxFindResourceHandle (MAKEINTRESOURCE(IDR_DEFAULT_ACCEL), RT_ACCELERATOR);
  ASSERT (hInst);
  m_hAccel =::LoadAccelerators (hInst, MAKEINTRESOURCE (IDR_DEFAULT_ACCEL));
  ASSERT (m_hAccel != NULL);
  return 0;
}

void CCrystalTextView::SetAnchor (const CPoint & ptNewAnchor)
{
  ASSERT_VALIDTEXTPOS (ptNewAnchor);
  m_ptAnchor = ptNewAnchor;
}

void CCrystalTextView::OnEditOperation (int nAction, LPCTSTR pszText)
{
}

BOOL CCrystalTextView::PreTranslateMessage (MSG * pMsg)
{
  if(pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
  {
     if(m_hAccel != NULL)
     {
        if(::TranslateAccelerator (m_hWnd, m_hAccel, pMsg))
           return TRUE;
     }
  }
  return CView::PreTranslateMessage (pMsg);
}

CPoint CCrystalTextView::GetCursorPos ()
{
  return m_ptCursorPos;
}

void CCrystalTextView::SetCursorPos (const CPoint & ptCursorPos)
{
  ASSERT_VALIDTEXTPOS (ptCursorPos);
  m_ptCursorPos = ptCursorPos;
  m_nIdealCharPos = CalculateActualOffset (m_ptCursorPos.y, m_ptCursorPos.x);
  UpdateCaret ();
}

void CCrystalTextView::SetSelectionMargin (BOOL bSelMargin)
{
  if(m_bSelMargin != bSelMargin)
  {
     m_bSelMargin = bSelMargin;
     if(::IsWindow(m_hWnd))
     {
        m_nScreenChars = -1;
        Invalidate ();
        RecalcHorzScrollBar ();
     }
  }
}

void CCrystalTextView::GetFont (LOGFONT & lf)
{
  lf = m_lfBaseFont;
}

void CCrystalTextView::SetFont (const LOGFONT & lf)
{
  m_lfBaseFont = lf;
  m_nScreenLines = -1;
  m_nScreenChars = -1;
  m_nCharWidth = -1;
  m_nLineHeight = -1;

  if(m_pCacheBitmap != NULL)
  {
    m_pCacheBitmap->DeleteObject ();
    delete m_pCacheBitmap;
    m_pCacheBitmap = NULL;
  }

  for(int I = 0; I < 4; I++)
  {
    if(m_apFonts[I] != NULL)
    {
       m_apFonts[I]->DeleteObject ();
       delete m_apFonts[I];
       m_apFonts[I] = NULL;
	}
  }

  if(::IsWindow (m_hWnd))
  {
    RecalcVertScrollBar();
    RecalcHorzScrollBar();
    UpdateCaret();
    Invalidate();
  }
}

void CCrystalTextView::OnUpdateIndicatorPosition (CCmdUI * pCmdUI)
{
  ASSERT_VALIDTEXTPOS (m_ptCursorPos);
  CString stat;
                                                   // VVV m_ptCursorPos.x + 1 ???
  stat.Format (_T ("Ln %d, Col %d"), m_ptCursorPos.y + 1, m_nIdealCharPos + 1);
  pCmdUI->SetText (stat);
	
  //BEGIN SW
  if(pCmdUI->m_pOther && pCmdUI->m_pOther->IsKindOf( RUNTIME_CLASS(CStatusBar) ) )
		OnUpdateStatusMessage( (CStatusBar*)pCmdUI->m_pOther );
  //END SW
}

void CCrystalTextView::OnUpdateIndicatorCRLF (CCmdUI * pCmdUI)
{
  if(m_pTextBuffer != NULL)
  {
      int crlfMode = m_pTextBuffer->GetCRLFMode ();
      switch (crlfMode)
	  {
        case CRLF_STYLE_DOS:
          pCmdUI->SetText (_T ("DOS"));
          pCmdUI->Enable (TRUE);
          break;
        case CRLF_STYLE_UNIX:
          pCmdUI->SetText (_T ("UNIX"));
          pCmdUI->Enable (TRUE);
          break;
        case CRLF_STYLE_MAC:
          pCmdUI->SetText (_T ("MAC"));
          pCmdUI->Enable (TRUE);
          break;
        default:
          pCmdUI->SetText (NULL);
          pCmdUI->Enable (FALSE);
	  }
    }
  else
  {
     pCmdUI->SetText (NULL);
     pCmdUI->Enable (FALSE);
  }
}

void CCrystalTextView::OnToggleBookmark (UINT nCmdID)
{
  int nBookmarkID = nCmdID - ID_EDIT_TOGGLE_BOOKMARK0;
  ASSERT (nBookmarkID >= 0 && nBookmarkID <= 9);
  
  if(m_pTextBuffer != NULL)
  {
     DWORD dwFlags = GetLineFlags (m_ptCursorPos.y);
     DWORD dwMask = LF_BOOKMARK (nBookmarkID);
     m_pTextBuffer->SetLineFlag (m_ptCursorPos.y, dwMask, (dwFlags & dwMask) == 0);
  }
}

void CCrystalTextView::OnGoBookmark (UINT nCmdID)
{
  int nBookmarkID = nCmdID - ID_EDIT_GO_BOOKMARK0;
  ASSERT (nBookmarkID >= 0 && nBookmarkID <= 9);
  
  if(m_pTextBuffer != NULL)
  {
    int nLine = m_pTextBuffer->GetLineWithFlag (LF_BOOKMARK (nBookmarkID));
    if(nLine >= 0)
    {
       CPoint pt (0, nLine);
       ASSERT_VALIDTEXTPOS (pt);
       SetCursorPos (pt);
       SetSelection (pt, pt);
       SetAnchor (pt);
        EnsureVisible (pt);
	}
  }
}

void CCrystalTextView::OnClearBookmarks ()
{
  if(m_pTextBuffer != NULL)
    for(int nBookmarkID = 0; nBookmarkID <= 9; nBookmarkID++)
	{
       int nLine = m_pTextBuffer->GetLineWithFlag (LF_BOOKMARK (nBookmarkID));
       if(nLine >= 0)
           m_pTextBuffer->SetLineFlag (nLine, LF_BOOKMARK (nBookmarkID), FALSE);
	}
}

void CCrystalTextView::ShowCursor ()
{
  m_bCursorHidden = FALSE;
  UpdateCaret ();
}

void CCrystalTextView::HideCursor ()
{
  m_bCursorHidden = TRUE;
  UpdateCaret ();
}

void CCrystalTextView::PopCursor ()
{
  if(IsValidTextPosY (m_ptCursorLast))
  {
    if (!IsValidTextPosX (m_ptCursorLast))
        m_ptCursorLast.x = 0;

    ASSERT_VALIDTEXTPOS (m_ptCursorLast);
    CPoint ptCursorPos = m_ptCursorLast;
    SetCursorPos (ptCursorPos);
    SetSelection (ptCursorPos, ptCursorPos);
    SetAnchor (ptCursorPos);
    EnsureVisible (ptCursorPos);
  }
}

void CCrystalTextView::PushCursor ()
{
  m_ptCursorLast = m_ptCursorPos;
}

DROPEFFECT CCrystalTextView::GetDropEffect ()
{
  return DROPEFFECT_COPY;
}

void CCrystalTextView::OnDropSource (DROPEFFECT de)
{
  ASSERT (de == DROPEFFECT_COPY);
}

HGLOBAL CCrystalTextView::PrepareDragData ()
{
  PrepareSelBounds ();
  if (m_ptDrawSelStart == m_ptDrawSelEnd)
    return NULL;

  CString text;
  GetText (m_ptDrawSelStart, m_ptDrawSelEnd, text);
  HGLOBAL hData =::GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, _tcslen (text) + 1);
  if (hData == NULL)
    return NULL;

  LPTSTR pszData = (LPTSTR)::GlobalLock (hData);
  _tcscpy (pszData, text.GetBuffer (0));
  text.ReleaseBuffer ();
  ::GlobalUnlock (hData);

  m_ptDraggedTextBegin = m_ptDrawSelStart;
  m_ptDraggedTextEnd = m_ptDrawSelEnd;
  return hData;
}

static int FindStringHelper (LPCTSTR pszFindWhere, LPCTSTR pszFindWhat, DWORD dwFlags, int &nLen, RxNode *&rxnode, RxMatchRes *rxmatch)
{
  if(dwFlags & FIND_REGEXP)
  {
      int pos;

      if(rxnode)
        RxFree (rxnode);
      rxnode = RxCompile (pszFindWhat);
      if(rxnode && RxExec (rxnode, pszFindWhere, _tcslen (pszFindWhere), pszFindWhere, rxmatch, (dwFlags & FIND_MATCH_CASE) != 0 ? RX_CASE : 0))
      {
         pos = rxmatch->Open[0];
         nLen = rxmatch->Close[0] - rxmatch->Open[0];
      }
      else
      pos = -1;
     return pos;
  }
  else
  {
      ASSERT (pszFindWhere != NULL);
      ASSERT (pszFindWhat != NULL);

      int nCur = 0;
      int nLength = _tcslen (pszFindWhat);
      nLen = nLength;

      for(;;)
	  {
          LPCTSTR pszPos = _tcsstr (pszFindWhere, pszFindWhat);
          if(pszPos == NULL)
            return -1;

          if((dwFlags & FIND_WHOLE_WORD) == 0)
            return nCur + (pszPos - pszFindWhere);

          if(pszPos > pszFindWhere && xisalnum (pszPos[-1]))
		  {
             nCur += (pszPos - pszFindWhere);
             pszFindWhere = pszPos + 1;
             continue;
          }

          if(xisalnum (pszPos[nLength]))
		  {
             nCur += (pszPos - pszFindWhere + 1);
             pszFindWhere = pszPos + 1;
             continue;
          }
          return nCur + (pszPos - pszFindWhere);
	  }
  }
  ASSERT (FALSE);               // Unreachable

  return -1;
}

BOOL CCrystalTextView::HighlightText (const CPoint & ptStartPos, 
									  int nLength, BOOL bReverse /*= FALSE*/)
{
  ASSERT_VALIDTEXTPOS (ptStartPos);
  CPoint ptEndPos = ptStartPos;

  int nCount = GetLineLength (ptEndPos.y) - ptEndPos.x;
  if(nLength <= nCount)
  {
    ptEndPos.x += nLength;
  }
  else
  {
     while(nLength > nCount)
     {
       nLength -= nCount + 1;
       nCount = GetLineLength (++ptEndPos.y);
     }
     ptEndPos.x = nLength;
  }
  ASSERT_VALIDTEXTPOS (m_ptCursorPos);  //  Probably 'nLength' is bigger than expected...

  m_ptCursorPos = bReverse ? ptStartPos : ptEndPos;
  m_ptAnchor = m_ptCursorPos;
  SetSelection (ptStartPos, ptEndPos);

  UpdateCaret ();
  EnsureVisible (m_ptCursorPos);
  return TRUE;
}

BOOL CCrystalTextView::FindText (LPCTSTR pszText, const CPoint & ptStartPos,
								 DWORD dwFlags,
          BOOL bWrapSearch, CPoint * pptFoundPos)
{
  int nLineCount = GetLineCount ();
  return FindTextInBlock (pszText, ptStartPos, CPoint (0, 0),
                          CPoint (GetLineLength (nLineCount - 1), nLineCount - 1),
                          dwFlags, bWrapSearch, pptFoundPos);
}

int HowManyStr (LPCTSTR s, LPCTSTR m)
{
  LPCTSTR p = s;
  int n = 0, l = _tcslen (m);

  while((p = _tcsstr (p, m)) != NULL)
  {
    n++;
    p += l;
  }
  return n;
}

int HowManyStr (LPCTSTR s, TCHAR c)
{
  LPCTSTR p = s;
  int n = 0;

  while((p = _tcschr (p, c)) != NULL)
  {
    n++;
    p++;
  }
  return n;
}

BOOL CCrystalTextView::FindTextInBlock (LPCTSTR pszText, const CPoint & ptStartPosition,
                 const CPoint & ptBlockBegin, const CPoint & ptBlockEnd,
                 DWORD dwFlags, BOOL bWrapSearch, CPoint * pptFoundPos)
{
  CPoint ptCurrentPos = ptStartPosition;

  ASSERT (pszText != NULL && _tcslen (pszText) > 0);
  ASSERT_VALIDTEXTPOS (ptCurrentPos);
  ASSERT_VALIDTEXTPOS (ptBlockBegin);
  ASSERT_VALIDTEXTPOS (ptBlockEnd);
  ASSERT (ptBlockBegin.y < ptBlockEnd.y || ptBlockBegin.y == ptBlockEnd.y &&
          ptBlockBegin.x <= ptBlockEnd.x);

  if(ptBlockBegin == ptBlockEnd)
    return FALSE;

  CWaitCursor waitCursor;
  if(ptCurrentPos.y < ptBlockBegin.y || ptCurrentPos.y == ptBlockBegin.y &&
        ptCurrentPos.x < ptBlockBegin.x)
    ptCurrentPos = ptBlockBegin;

  CString what = pszText;
  int nEolns;
  if(dwFlags & FIND_REGEXP)
  {
      nEolns = HowManyStr (what, _T("\\n"));
  }
  else
  {
     nEolns = 0;
     if((dwFlags & FIND_MATCH_CASE) == 0)
        what.MakeUpper ();
  }


  if(dwFlags & FIND_DIRECTION_UP)
  {
      //  Let's check if we deal with whole text.
      //  At this point, we cannot search *up* in selection
      ASSERT (ptBlockBegin.x == 0 && ptBlockBegin.y == 0);
      ASSERT (ptBlockEnd.x == GetLineLength (GetLineCount () - 1) &&
              ptBlockEnd.y == GetLineCount () - 1);

      //  Proceed as if we have whole text search.
      for (;;)
        {
          while (ptCurrentPos.y >= 0)
            {
              int nLineLength;
              CString line;
              if (dwFlags & FIND_REGEXP)
                {
                  for (int i = 0; i <= nEolns && ptCurrentPos.y >= i; i++)
                    {
                      CString item;
                      LPCTSTR pszChars = GetLineChars (ptCurrentPos.y - i);
                      if (i)
                        {
                          nLineLength = GetLineLength (ptCurrentPos.y - i);
                          ptCurrentPos.x = 0;
                          line = _T ('\n') + line;
                        }
                      else
                        {
                          nLineLength = ptCurrentPos.x != -1 ? ptCurrentPos.x : GetLineLength (ptCurrentPos.y - i);
                        }
                      if (nLineLength > 0)
                        {
                          LPTSTR pszBuf = item.GetBuffer (nLineLength + 1);
                          _tcsncpy (pszBuf, pszChars, nLineLength);
                          pszBuf[nLineLength] = _T ('\0');
                          item.ReleaseBuffer ();
                          line = item + line;
                        }
                    }
                  nLineLength = line.GetLength ();
                  if (ptCurrentPos.x == -1)
                    ptCurrentPos.x = 0;
                }
              else
                {
				nLineLength = GetLineLength(ptCurrentPos.y);
				//BEGIN SW+FP
                  if (ptCurrentPos.x == -1)
                    {
                      ptCurrentPos.x = nLineLength;
                    }
                  else
				if( ptCurrentPos.x >= nLineLength )
					ptCurrentPos.x = nLineLength - 1;
				/*ORIGINAL
                  if (ptCurrentPos.x == -1)
                    {
                      nLineLength = GetLineLength (ptCurrentPos.y);
                      ptCurrentPos.x = nLineLength;
                    }
                  else
                    nLineLength = ptCurrentPos.x;
                  if (nLineLength <= 0)
                    {
                      ptCurrentPos.x = -1;
                      ptCurrentPos.y--;
                      continue;
                    }
				*///END SW

                  LPCTSTR pszChars = GetLineChars (ptCurrentPos.y);
				//BEGIN SW
				_tcsncpy(line.GetBuffer(ptCurrentPos.x + 2), pszChars, ptCurrentPos.x + 1);
				/*ORIGINAL
                  LPTSTR pszBuf = line.GetBuffer (nLineLength + 1);
                  _tcsncpy (pszBuf, pszChars, nLineLength);
                  pszBuf[nLineLength] = _T ('\0');
				*///END SW
                  line.ReleaseBuffer ();
                  if ((dwFlags & FIND_MATCH_CASE) == 0)
                    line.MakeUpper ();
                }

				//BEGIN SW
				int	nFoundPos = -1;
				int	nMatchLen = what.GetLength();
				int	nLineLen = line.GetLength();
				int	nPos;
				do
				{
					nPos = ::FindStringHelper(line, what, dwFlags, m_nLastFindWhatLen, m_rxnode, &m_rxmatch);
					if( nPos >= 0 )
					{
						nFoundPos = (nFoundPos == -1)? nPos : nFoundPos + nPos;
						nFoundPos+= nMatchLen;
						line = line.Right( nLineLen - (nMatchLen + nPos) );
						nLineLen = line.GetLength();
					}
				}
				while( nPos >= 0 );

				if( nFoundPos >= 0 )	// Found text!
				{
					ptCurrentPos.x = nFoundPos - nMatchLen;
					*pptFoundPos = ptCurrentPos;
					return TRUE;
				}

				ptCurrentPos.y--;
				if( ptCurrentPos.y >= 0 )
					ptCurrentPos.x = GetLineLength( ptCurrentPos.y );
				/*ORIGINAL
              int nPos =::FindStringHelper (line, what, dwFlags, m_nLastFindWhatLen, m_rxnode, &m_rxmatch);
              if (nPos >= 0)    //  Found text!
                {
                  LPTSTR pszText = line.GetBuffer (nLineLength + 1);
                  m_pszMatched = _tcsdup (pszText);
                  line.ReleaseBuffer ();
                  // m_sMatched = line.Mid (nPos);
                  if (nEolns)
                    {
                      CString item = line.Left (nPos);
                      ptCurrentPos.y -= nEolns - HowManyStr (item, _T('\n'));
                      if (ptCurrentPos.y < 0)
                        ptCurrentPos.y = 0;
                      LPCTSTR current = _tcsrchr (item, _T('\n'));
                      if (current)
                        current++;
                      else
                        current = item;
                      ptCurrentPos.x = nPos - (current - (LPCTSTR) item);
                      if (ptCurrentPos.x < 0)
                        ptCurrentPos.x = 0;
                    }
                  else
                    {
                      ptCurrentPos.x = nPos;
                    }
                  *pptFoundPos = ptCurrentPos;
                  return TRUE;
                }
              else
                m_pszMatched = NULL;

              ptCurrentPos.x = -1;
              ptCurrentPos.y--;
				*///END SW
            }

          //  Beginning of text reached
          if (!bWrapSearch)
            return FALSE;

          //  Start again from the end of text
          bWrapSearch = FALSE;
          ptCurrentPos = CPoint (0, GetLineCount () - 1);
        }
    }
  else
    {
      for (;;)
        {
          while (ptCurrentPos.y <= ptBlockEnd.y)
            {
              int nLineLength, nLines;
              CString line;
              if (dwFlags & FIND_REGEXP)
                {
                  nLines = m_pTextBuffer->GetLineCount ();
                  for (int i = 0; i <= nEolns && ptCurrentPos.y + i < nLines; i++)
                    {
                      CString item;
                      LPCTSTR pszChars = GetLineChars (ptCurrentPos.y + i);
                      nLineLength = GetLineLength (ptCurrentPos.y + i);
                      if (i)
                        {
                          line += _T ('\n');
                        }
                      else
                        {
                          pszChars += ptCurrentPos.x;
                          nLineLength -= ptCurrentPos.x;
                        }
                      if (nLineLength > 0)
                        {
                          LPTSTR pszBuf = item.GetBuffer (nLineLength + 1);
                          _tcsncpy (pszBuf, pszChars, nLineLength);
                          pszBuf[nLineLength] = _T ('\0');
                          item.ReleaseBuffer ();
                          line += item;
                        }
                    }
                  nLineLength = line.GetLength ();
                }
              else
                {
                  nLineLength = GetLineLength (ptCurrentPos.y) - ptCurrentPos.x;
                  if (nLineLength <= 0)
                    {
                      ptCurrentPos.x = 0;
                      ptCurrentPos.y++;
                      continue;
                    }

                  LPCTSTR pszChars = GetLineChars (ptCurrentPos.y);
                  pszChars += ptCurrentPos.x;

                  //  Prepare necessary part of line
                  LPTSTR pszBuf = line.GetBuffer (nLineLength + 1);
                  _tcsncpy (pszBuf, pszChars, nLineLength);
                  pszBuf[nLineLength] = _T ('\0');
                  line.ReleaseBuffer ();
                  if ((dwFlags & FIND_MATCH_CASE) == 0)
                    line.MakeUpper ();
                }

              //  Perform search in the line
              int nPos =::FindStringHelper (line, what, dwFlags, m_nLastFindWhatLen, m_rxnode, &m_rxmatch);
              if (nPos >= 0)
                {
                  LPTSTR pszText = line.GetBuffer (nLineLength + 1);
                  m_pszMatched = _tcsdup (pszText);
                  line.ReleaseBuffer ();
                  // m_sMatched = line.Mid (nPos);
                  if (nEolns)
                    {
                      CString item = line.Left (nPos);
                      LPCTSTR current = _tcsrchr (item, _T('\n'));
                      if (current)
                        current++;
                      else
                        current = item;
                      nEolns = HowManyStr (item, _T('\n'));
                      if (nEolns)
                        {
                          ptCurrentPos.y += nEolns;
                          ptCurrentPos.x = nPos - (current - (LPCTSTR) item);
                        }
                      else
                        {
                          ptCurrentPos.x += nPos - (current - (LPCTSTR) item);
                        }
                      if (ptCurrentPos.x < 0)
                        ptCurrentPos.x = 0;
                    }
                  else
                    {
                      ptCurrentPos.x += nPos;
                    }
                  //  Check of the text found is outside the block.
                  if (ptCurrentPos.y == ptBlockEnd.y && ptCurrentPos.x >= ptBlockEnd.x)
                    break;

                  *pptFoundPos = ptCurrentPos;
                  return TRUE;
                }
              else
                m_pszMatched = NULL;

              //  Go further, text was not found
              ptCurrentPos.x = 0;
              ptCurrentPos.y++;
            }

          //  End of text reached
          if (!bWrapSearch)
            return FALSE;

          //  Start from the beginning
          bWrapSearch = FALSE;
          ptCurrentPos = ptBlockBegin;
        }
    }

  ASSERT (FALSE);               // Unreachable

  return FALSE;
}

void CCrystalTextView::OnEditFind ()
{
  CWinApp *pApp = AfxGetApp ();
  ASSERT (pApp != NULL);

  CFindTextDlg dlg (this);
  if(m_bLastSearch)
  {
      //  Get the latest search parameters
      dlg.m_bMatchCase = (m_dwLastSearchFlags & FIND_MATCH_CASE) != 0;
      dlg.m_bWholeWord = (m_dwLastSearchFlags & FIND_WHOLE_WORD) != 0;
      dlg.m_bRegExp = (m_dwLastSearchFlags & FIND_REGEXP) != 0;
      dlg.m_nDirection = (m_dwLastSearchFlags & FIND_DIRECTION_UP) != 0 ? 0 : 1;
      if (m_pszLastFindWhat != NULL)
        dlg.m_sText = m_pszLastFindWhat;
  }
  else
  {
      DWORD dwFlags;
      if (!RegLoadNumber (HKEY_CURRENT_USER, REG_EDITPAD, _T ("FindFlags"), &dwFlags))
        dwFlags = 0;
      dlg.m_bMatchCase = (dwFlags & FIND_MATCH_CASE) != 0;
      dlg.m_bWholeWord = (dwFlags & FIND_WHOLE_WORD) != 0;
      dlg.m_bRegExp = (dwFlags & FIND_REGEXP) != 0;
      dlg.m_nDirection = (dwFlags & FIND_DIRECTION_UP) == 0;
      // dlg.m_sText = pApp->GetProfileString (REG_FIND_SUBKEY, REG_FIND_WHAT, _T (""));
  }

  //  Take the current selection, if any
  if(IsSelection ())
  {
     CPoint ptSelStart, ptSelEnd;
     GetSelection (ptSelStart, ptSelEnd);
     if(ptSelStart.y == ptSelEnd.y)
	 {
        LPCTSTR pszChars = GetLineChars (ptSelStart.y);
        int nChars = ptSelEnd.x - ptSelStart.x;
        _tcsncpy (dlg.m_sText.GetBuffer (nChars + 1), pszChars + ptSelStart.x, nChars + 1);
        dlg.m_sText.ReleaseBuffer ();
	 }
  }
  else
  {
     CPoint ptCursorPos = GetCursorPos (), ptStart = WordToLeft (ptCursorPos), ptEnd = WordToRight (ptCursorPos);
     if(IsValidTextPos (ptStart) && IsValidTextPos (ptEnd) && ptStart != ptEnd)
        GetText (ptStart, ptEnd, dlg.m_sText);
  }

  //  Execute Find dialog
  dlg.m_ptCurrentPos = m_ptCursorPos;   //  Search from cursor position

  // m_bShowInactiveSelection = TRUE; // FP: removed because I like it
  dlg.DoModal ();
  // m_bShowInactiveSelection = FALSE; // FP: removed because I like it

  //  Save search parameters for 'F3' command
  m_bLastSearch = TRUE;
  if (m_pszLastFindWhat != NULL)
    free (m_pszLastFindWhat);

  m_pszLastFindWhat = _tcsdup (dlg.m_sText);
  m_dwLastSearchFlags = 0;

  if (dlg.m_bMatchCase)
    m_dwLastSearchFlags |= FIND_MATCH_CASE;

  if (dlg.m_bWholeWord)
    m_dwLastSearchFlags |= FIND_WHOLE_WORD;

  if (dlg.m_bRegExp)
    m_dwLastSearchFlags |= FIND_REGEXP;

  if (dlg.m_nDirection == 0)
    m_dwLastSearchFlags |= FIND_DIRECTION_UP;

  //  Save search parameters to registry
  VERIFY (RegSaveNumber (HKEY_CURRENT_USER, REG_EDITPAD, _T ("FindFlags"), m_dwLastSearchFlags));
  // pApp->WriteProfileString (REG_FIND_SUBKEY, REG_FIND_WHAT, dlg.m_sText);
}

void CCrystalTextView::OnEditRepeat ()
{
  BOOL bEnable = m_bLastSearch;
  CString sText;
  if (bEnable)
    sText = m_pszLastFindWhat;
  else
    {
      bEnable = CMemComboBox::groups.Lookup (_T ("FindText"), sText) && !sText.IsEmpty ();
      if (bEnable)
        {
          int pos = sText.Find (_T('\n'));
          if (pos >= 0)
            sText = sText.Left (pos);
        }
    }
  if (bEnable)
    {
      CPoint ptFoundPos;
		//BEGIN SW
		// for correct backward search we need some changes:
		CPoint ptSearchPos = m_ptCursorPos;
		if( m_dwLastSearchFlags & FIND_DIRECTION_UP && IsSelection() )
		{
			CPoint	ptDummy;
			GetSelection( ptSearchPos, ptDummy );
		}

		if (! FindText(sText, ptSearchPos, m_dwLastSearchFlags, TRUE, &ptFoundPos))
		/*ORIGINAL
		if (! FindText(sText, m_ptCursorPos, m_dwLastSearchFlags, TRUE, &ptFoundPos))
		*///END SW
        {
          CString prompt;
          prompt.Format (IDS_EDIT_TEXT_NOT_FOUND, sText);
          AfxMessageBox (prompt);
          return;
        }
      HighlightText (ptFoundPos, m_nLastFindWhatLen, (m_dwLastSearchFlags & FIND_DIRECTION_UP) != 0);
      m_bMultipleSearch = TRUE; // More search

    }
}

void CCrystalTextView::OnUpdateEditRepeat (CCmdUI * pCmdUI)
{
  BOOL bEnable = m_bLastSearch;
  if (!bEnable)
    {
      CString sText;
      bEnable = CMemComboBox::groups.Lookup (_T ("FindText"), sText) && !sText.IsEmpty ();
    }
  pCmdUI->Enable (bEnable);
}

void CCrystalTextView::OnEditFindPrevious ()
{
  DWORD dwSaveSearchFlags = m_dwLastSearchFlags;
  if ((m_dwLastSearchFlags & FIND_DIRECTION_UP) != 0)
    m_dwLastSearchFlags &= ~FIND_DIRECTION_UP;
  else
    m_dwLastSearchFlags |= FIND_DIRECTION_UP;
  OnEditRepeat ();
  m_dwLastSearchFlags = dwSaveSearchFlags;
}

void CCrystalTextView::OnUpdateEditFindPrevious (CCmdUI * pCmdUI)
{
  BOOL bEnable = m_bLastSearch;
  if (!bEnable)
    {
      CString sText;
      bEnable = CMemComboBox::groups.Lookup (_T ("FindText"), sText) && !sText.IsEmpty ();
    }
  pCmdUI->Enable (bEnable);
}

void CCrystalTextView::OnFilePageSetup ()
{
  CWinApp *pApp = AfxGetApp ();
  ASSERT (pApp != NULL);

  CPageSetupDialog dlg;
  //dlg.m_psd.Flags &= ~PSD_INTHOUSANDTHSOFINCHES;
  dlg.m_psd.Flags = PSD_INHUNDREDTHSOFMILLIMETERS|PSD_MARGINS;
  dlg.m_psd.rtMargin.left = DEFAULT_PRINT_MARGIN;
  dlg.m_psd.rtMargin.right = DEFAULT_PRINT_MARGIN;
  dlg.m_psd.rtMargin.top = DEFAULT_PRINT_MARGIN;
  dlg.m_psd.rtMargin.bottom = DEFAULT_PRINT_MARGIN;
  CReg reg;
  if (reg.Open (HKEY_CURRENT_USER, REG_EDITPAD, KEY_READ))
    {
      DWORD dwTemp;
      if (reg.LoadNumber (_T ("PageWidth"), &dwTemp))
        dlg.m_psd.ptPaperSize.x = dwTemp;
      if (reg.LoadNumber (_T ("PageHeight"), &dwTemp))
        dlg.m_psd.ptPaperSize.y = dwTemp;
      if (reg.LoadNumber (_T ("PageLeft"), &dwTemp))
        dlg.m_psd.rtMargin.left = dwTemp;
      if (reg.LoadNumber (_T ("PageRight"), &dwTemp))
        dlg.m_psd.rtMargin.right = dwTemp;
      if (reg.LoadNumber (_T ("PageTop"), &dwTemp))
        dlg.m_psd.rtMargin.top = dwTemp;
      if (reg.LoadNumber (_T ("PageBottom"), &dwTemp))
        dlg.m_psd.rtMargin.bottom = dwTemp;
    }
  if (dlg.DoModal () == IDOK)
    {
      CReg reg;
      if (reg.Create (HKEY_CURRENT_USER, REG_EDITPAD, KEY_WRITE))
        {
          VERIFY (reg.SaveNumber (_T ("PageWidth"), dlg.m_psd.ptPaperSize.x));
          VERIFY (reg.SaveNumber (_T ("PageHeight"), dlg.m_psd.ptPaperSize.y));
          VERIFY (reg.SaveNumber (_T ("PageLeft"), dlg.m_psd.rtMargin.left));
          VERIFY (reg.SaveNumber (_T ("PageRight"), dlg.m_psd.rtMargin.right));
          VERIFY (reg.SaveNumber (_T ("PageTop"), dlg.m_psd.rtMargin.top));
          VERIFY (reg.SaveNumber (_T ("PageBottom"), dlg.m_psd.rtMargin.bottom));
        }
    }
}

void CCrystalTextView::OnToggleBookmark ()
{
  if (m_pTextBuffer != NULL)
    {
      DWORD dwFlags = GetLineFlags (m_ptCursorPos.y);
      DWORD dwMask = LF_BOOKMARKS;
      m_pTextBuffer->SetLineFlag (m_ptCursorPos.y, dwMask, (dwFlags & dwMask) == 0, FALSE);
    }
  int nLine = m_pTextBuffer->GetLineWithFlag (LF_BOOKMARKS);
  if (nLine >= 0)
    m_bBookmarkExist = TRUE;
  else
    m_bBookmarkExist = FALSE;
}

void CCrystalTextView::OnNextBookmark ()
{
  if (m_pTextBuffer != NULL)
    {
      int nLine = m_pTextBuffer->FindNextBookmarkLine (m_ptCursorPos.y);
      if (nLine >= 0)
        {
          CPoint pt (0, nLine);
          ASSERT_VALIDTEXTPOS (pt);
          SetCursorPos (pt);
          SetSelection (pt, pt);
          SetAnchor (pt);
          EnsureVisible (pt);
        }
    }
}

void CCrystalTextView::OnPrevBookmark ()
{
  if (m_pTextBuffer != NULL)
    {
      int nLine = m_pTextBuffer->FindPrevBookmarkLine (m_ptCursorPos.y);
      if (nLine >= 0)
        {
          CPoint pt (0, nLine);
          ASSERT_VALIDTEXTPOS (pt);
          SetCursorPos (pt);
          SetSelection (pt, pt);
          SetAnchor (pt);
          EnsureVisible (pt);
        }
    }
}

void CCrystalTextView::OnClearAllBookmarks ()
{
  if (m_pTextBuffer != NULL)
    {
      int nLineCount = GetLineCount ();
      for (int I = 0; I < nLineCount; I++)
        {
          if (m_pTextBuffer->GetLineFlags (I) & LF_BOOKMARKS)
            m_pTextBuffer->SetLineFlag (I, LF_BOOKMARKS, FALSE);
        }
      m_bBookmarkExist = FALSE;
    }
}

void CCrystalTextView::OnUpdateNextBookmark (CCmdUI * pCmdUI)
{
  pCmdUI->Enable (m_bBookmarkExist);
}

void CCrystalTextView::OnUpdatePrevBookmark (CCmdUI * pCmdUI)
{
  pCmdUI->Enable (m_bBookmarkExist);
}

void CCrystalTextView::OnUpdateClearAllBookmarks (CCmdUI * pCmdUI)
{
  pCmdUI->Enable (m_bBookmarkExist);
}

BOOL CCrystalTextView::GetViewTabs ()
{
  return m_bViewTabs;
}

void CCrystalTextView::SetViewTabs (BOOL bViewTabs)
{
  if (bViewTabs != m_bViewTabs)
    {
      m_bViewTabs = bViewTabs;
      if (::IsWindow (m_hWnd))
        Invalidate ();
    }
}

DWORD CCrystalTextView::GetFlags ()
{
  return m_dwFlags;
}

void CCrystalTextView::SetFlags (DWORD dwFlags)
{
  if (m_dwFlags != dwFlags)
    {
      m_dwFlags = dwFlags;
      if (::IsWindow (m_hWnd))
        Invalidate ();
    }
}

BOOL CCrystalTextView::GetSelectionMargin()
{
  return m_bSelMargin;
}

int CCrystalTextView::GetMarginWidth()
{
	return (m_bSelMargin? 20 :1 );
}

BOOL CCrystalTextView::GetSmoothScroll ()const
{
  return m_bSmoothScroll;
}

void CCrystalTextView::SetSmoothScroll (BOOL bSmoothScroll)
{
  m_bSmoothScroll = bSmoothScroll;
}

//  [JRT]
BOOL CCrystalTextView::GetDisableDragAndDrop ()const
{
  return m_bDisableDragAndDrop;
}

//  [JRT]
void CCrystalTextView::SetDisableDragAndDrop (BOOL bDDAD)
{
  m_bDisableDragAndDrop = bDDAD;
}

//
// Mouse wheel event.  zDelta is in multiples of 120.
// Divide by 40 so each click is 3 lines.  I know some
// drivers let you set the ammount of scroll, but I
// don't know how to retrieve this or if they just
// adjust the zDelta you get here.
BOOL CCrystalTextView::OnMouseWheel (UINT nFlags, short zDelta, CPoint pt)
{
	// -> HE
	int nPageLines = GetScreenLines();
	int nSubLineCount = GetSubLineCount();

	int nNewTopSubLine= m_nTopSubLine - zDelta / 40;

	if (nNewTopSubLine < 0)
		nNewTopSubLine = 0;
	if (nNewTopSubLine >= nSubLineCount)
		nNewTopSubLine = nSubLineCount - 1;

	ScrollToSubLine(nNewTopSubLine, TRUE);
	// <- HE

  return CView::OnMouseWheel (nFlags, zDelta, pt);
}

void CCrystalTextView::OnSourceType (UINT nId)
{
  SetTextType ((CCrystalTextView::TextType) (nId - ID_SOURCE_PLAIN));
  Invalidate ();
}

void CCrystalTextView::OnUpdateSourceType (CCmdUI * pCmdUI)
{
  pCmdUI->SetRadio (m_SourceDefs + (pCmdUI->m_nID - ID_SOURCE_PLAIN) == m_CurSourceDef);
}

int bracetype (TCHAR c);

void CCrystalTextView::OnMatchBrace ()
{
  CPoint ptCursorPos = GetCursorPos ();
  int nLength = m_pTextBuffer->GetLineLength (ptCursorPos.y);
  LPCTSTR pszText = m_pTextBuffer->GetLineChars (ptCursorPos.y), pszEnd = pszText + ptCursorPos.x;
  bool bAfter;
  int nType = 0;
  if (ptCursorPos.x < nLength)
    {
      nType = bracetype (*pszEnd);
      if (nType)
        {
          bAfter = false;
        }
      else if (!nType && ptCursorPos.x > 0)
        {
          nType = bracetype (pszEnd[-1]);
          bAfter = true;
        }
    }
  else if (ptCursorPos.x > 0)
    {
      nType = bracetype (pszEnd[-1]);
      bAfter = true;
    }
  if (nType)
    {
      int nOther, nCount = 0, nComment = 0;
      if (bAfter)
        {
          nOther = ((nType - 1) ^ 1) + 1;
          if (nOther & 1)
            pszEnd--;
        }
      else
        {
          nOther = ((nType - 1) ^ 1) + 1;
          if (!(nOther & 1))
            pszEnd++;
        }
      LPCTSTR pszOpenComment = m_CurSourceDef->opencomment,
        pszCloseComment = m_CurSourceDef->closecomment,
        pszCommentLine = m_CurSourceDef->commentline, pszTest;
      int nOpenComment = _tcslen (pszOpenComment),
        nCloseComment = _tcslen (pszCloseComment),
        nCommentLine = _tcslen (pszCommentLine);
      if (nOther & 1)
        {
          for (;;)
            {
              while (--pszEnd >= pszText)
                {
                  pszTest = pszEnd - nOpenComment + 1;
                  if (pszTest >= pszText && !_tcsnicmp (pszTest, pszOpenComment, nOpenComment))
                    {
                      nComment--;
                      pszEnd = pszTest;
                      if (--pszEnd < pszText)
                        {
                          break;
                        }
                    }
                  pszTest = pszEnd - nCloseComment + 1;
                  if (pszTest >= pszText && !_tcsnicmp (pszTest, pszCloseComment, nCloseComment))
                    {
                      nComment++;
                      pszEnd = pszTest;
                      if (--pszEnd < pszText)
                        {
                          break;
                        }
                    }
                  if (!nComment)
                    {
                      pszTest = pszEnd - nCommentLine + 1;
                      if (pszTest >= pszText && !_tcsnicmp (pszTest, pszCommentLine, nCommentLine))
                        {
                          break;
                        }
                      if (bracetype (*pszEnd) == nType)
                        {
                          nCount++;
                        }
                      else if (bracetype (*pszEnd) == nOther)
                        {
                          if (!nCount--)
                            {
                              ptCursorPos.x = pszEnd - pszText;
                              if (bAfter)
                                ptCursorPos.x++;
                              SetCursorPos (ptCursorPos);
                              SetSelection (ptCursorPos, ptCursorPos);
                              SetAnchor (ptCursorPos);
                              EnsureVisible (ptCursorPos);
                              return;
                            }
                        }
                    }
                }
              if (ptCursorPos.y)
                {
                  ptCursorPos.x = m_pTextBuffer->GetLineLength (--ptCursorPos.y);
                  pszText = m_pTextBuffer->GetLineChars (ptCursorPos.y);
                  pszEnd = pszText + ptCursorPos.x;
                }
              else
                break;
            }
        }
      else
        {
          LPCTSTR pszBegin = pszText;
          pszText = pszEnd;
          pszEnd = pszBegin + nLength;
          int nLines = m_pTextBuffer->GetLineCount ();
          for (;;)
            {
              while (pszText < pszEnd)
                {
                  pszTest = pszText + nCloseComment;
                  if (pszTest <= pszEnd && !_tcsnicmp (pszText, pszCloseComment, nCloseComment))
                    {
                      nComment--;
                      pszText = pszTest;
                      if (pszText > pszEnd)
                        {
                          break;
                        }
                    }
                  pszTest = pszText + nOpenComment;
                  if (pszTest <= pszEnd && !_tcsnicmp (pszText, pszOpenComment, nOpenComment))
                    {
                      nComment++;
                      pszText = pszTest;
                      if (pszText > pszEnd)
                        {
                          break;
                        }
                    }
                  if (!nComment)
                    {
                      pszTest = pszText + nCommentLine;
                      if (pszTest <= pszEnd && !_tcsnicmp (pszText, pszCommentLine, nCommentLine))
                        {
                          break;
                        }
                      if (bracetype (*pszText) == nType)
                        {
                          nCount++;
                        }
                      else if (bracetype (*pszText) == nOther)
                        {
                          if (!nCount--)
                            {
                              ptCursorPos.x = pszText - pszBegin;
                              if (bAfter)
                                ptCursorPos.x++;
                              SetCursorPos (ptCursorPos);
                              SetSelection (ptCursorPos, ptCursorPos);
                              SetAnchor (ptCursorPos);
                              EnsureVisible (ptCursorPos);
                              return;
                            }
                        }
                    }
                  pszText++;
                }
              if (ptCursorPos.y < nLines)
                {
                  ptCursorPos.x = 0;
                  nLength = m_pTextBuffer->GetLineLength (++ptCursorPos.y);
                  pszBegin = pszText = m_pTextBuffer->GetLineChars (ptCursorPos.y);
                  pszEnd = pszBegin + nLength;
                }
              else
                break;
            }
        }
    }
}

void CCrystalTextView::OnUpdateMatchBrace (CCmdUI * pCmdUI)
{
  CPoint ptCursorPos = GetCursorPos ();
  int nLength = m_pTextBuffer->GetLineLength (ptCursorPos.y);
  LPCTSTR pszText = m_pTextBuffer->GetLineChars (ptCursorPos.y) + ptCursorPos.x;
  pCmdUI->Enable (ptCursorPos.x < nLength && (bracetype (*pszText) || ptCursorPos.x > 0 && bracetype (pszText[-1])) || ptCursorPos.x > 0 && bracetype (pszText[-1]));
}

void CCrystalTextView::OnEditGoTo ()
{
  CGotoDlg dlg (this);
  dlg.DoModal ();
}

void CCrystalTextView::OnUpdateToggleSourceHeader (CCmdUI * pCmdUI)
{
  pCmdUI->Enable (m_CurSourceDef->type == SRC_C);
}

void CCrystalTextView::OnToggleSourceHeader ()
{
  if (m_CurSourceDef->type == SRC_C)
    {
      CDocument *pDoc = GetDocument ();
      ASSERT (pDoc);
      CString sFilePath = pDoc->GetPathName (), sOriginalPath = sFilePath;
      if (!_tcsicmp (sFilePath.Right (2), _T (".c")))
        {
          sFilePath = sFilePath.Left (sFilePath.GetLength () - 1) + _T ('h');
        }
      else if (!_tcsicmp (sFilePath.Right (4), _T (".cpp")))
        {
          sFilePath = sFilePath.Left (sFilePath.GetLength () - 3) + _T ('h');
        }
      else if (!_tcsicmp (sFilePath.Right (4), _T (".inl")))
        {
          sFilePath = sFilePath.Left (sFilePath.GetLength () - 3) + _T ('c');
          if (!FileExist(sFilePath))
            {
              sFilePath = sFilePath + _T ("pp");
            }
        }
      else if (!_tcsicmp (sFilePath.Right (4), _T (".hpp")))
        {
          sFilePath = sFilePath.Left (sFilePath.GetLength () - 3) + _T ("inl");
          if (!FileExist(sFilePath))
            {
              sFilePath = sFilePath.Left (sFilePath.GetLength () - 3) + _T ('c');
              if (!FileExist(sFilePath))
                {
                  sFilePath = sFilePath + _T ("pp");
                }
            }
        }
      else if (!_tcsicmp (sFilePath.Right (2), _T (".h")))
        {
          sFilePath = sFilePath.Left (sFilePath.GetLength () - 1) + _T ("hpp");
          if (!FileExist(sFilePath))
            {
              sFilePath = sFilePath.Left (sFilePath.GetLength () - 3) + _T ("inl");
              if (!FileExist(sFilePath))
                {
                  sFilePath = sFilePath.Left (sFilePath.GetLength () - 3) + _T ('c');
                  if (!FileExist(sFilePath))
                    {
                      sFilePath = sFilePath + _T ("pp");
                    }
                }
            }
        }
      if (FileExist(sFilePath))
        {
          if (!m_bSingle || !pDoc->IsModified () || pDoc->DoSave (sOriginalPath))
            {
              AfxGetApp ()->OpenDocumentFile (sFilePath);
              if (m_bSingle)
                {
                  m_ptCursorLast.x = m_ptCursorLast.y = 0;
                  ASSERT_VALIDTEXTPOS (m_ptCursorLast);
                  CPoint ptCursorPos = m_ptCursorLast;
                  SetCursorPos (ptCursorPos);
                  SetSelection (ptCursorPos, ptCursorPos);
                  SetAnchor (ptCursorPos);
                  EnsureVisible (ptCursorPos);
                  Invalidate ();
                }
            }
        }
    }
}

void CCrystalTextView::OnUpdateSelMargin (CCmdUI * pCmdUI)
{
  pCmdUI->SetCheck (m_bSelMargin);
}

void CCrystalTextView::setMargin()
{
  ASSERT(m_CurSourceDef);
  if(m_bSelMargin)
  {
    m_CurSourceDef->flags |= SRCOPT_SELMARGIN;
    SetSelectionMargin (TRUE);
  }
  else
  {
    m_CurSourceDef->flags &= ~SRCOPT_SELMARGIN;
    SetSelectionMargin (FALSE);
  }
}

void CCrystalTextView::OnSelMargin ()
{
  ASSERT (m_CurSourceDef);
  if (m_bSelMargin)
    {
      m_CurSourceDef->flags &= ~SRCOPT_SELMARGIN;
      SetSelectionMargin (FALSE);
    }
  else
    {
      m_CurSourceDef->flags |= SRCOPT_SELMARGIN;
      SetSelectionMargin (TRUE);
    }
}

void CCrystalTextView::OnUpdateWordWrap (CCmdUI * pCmdUI)
{
  pCmdUI->SetCheck (m_bWordWrap);
}

void CCrystalTextView::OnWordWrap ()
{
  ASSERT (m_CurSourceDef);
  if (m_bWordWrap)
    {
      m_CurSourceDef->flags &= ~SRCOPT_WORDWRAP;
      SetWordWrapping (FALSE);
    }
  else
    {
      m_CurSourceDef->flags |= SRCOPT_WORDWRAP;
      SetWordWrapping (TRUE);
    }
}

void CCrystalTextView::OnForceRedraw ()
{
  //Invalidate ();
  RedrawWindow (NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_ERASENOW);
}

//BEGIN SW
BOOL CCrystalTextView::GetWordWrapping() const
{
	return m_bWordWrap;
}

void CCrystalTextView::SetWordWrapping( BOOL bWordWrap )
{
	m_bWordWrap = bWordWrap;

	if( IsWindow( m_hWnd ) )
		InvalidateLines( 0, -1, TRUE );
}

CCrystalParser *CCrystalTextView::SetParser( CCrystalParser *pParser )
{
	CCrystalParser	*pOldParser = m_pParser;

	m_pParser = pParser;

	if( pParser )
		pParser->m_pTextView = this;

	return pOldParser;
}
//END SW


//BEGIN SW
// incremental search imlementation
BOOL CCrystalTextView::OnCmdMsg( UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO *pHandlerInfo )
{
	// just look for commands
	if( nCode != CN_COMMAND || pExtra )
		return CView::OnCmdMsg( nID, nCode, pExtra, pHandlerInfo );

	// handle code:
	// each command that is not related to incremental search
	// ends the incremental search
	if( nID == ID_EDIT_FIND_INCREMENTAL_FORWARD || 
		nID == ID_EDIT_FIND_INCREMENTAL_BACKWARD || 
		nID == ID_EDIT_DELETE_BACK )
		return CView::OnCmdMsg( nID, nCode, pExtra, pHandlerInfo );

	if( nID >= ID_EDIT_FIRST && nID <= ID_EDIT_LAST )
		m_bIncrementalSearchForward = m_bIncrementalSearchBackward = FALSE;

	return CView::OnCmdMsg( nID, nCode, pExtra, pHandlerInfo );
}

void CCrystalTextView::OnChar( UINT nChar, UINT nRepCnt, UINT nFlags )
{
	CView::OnChar( nChar, nRepCnt, nFlags );

	// we only have to handle character-input, if we are in incremental search mode
	if( !m_bIncrementalSearchForward && !m_bIncrementalSearchBackward )
		return;

	// exit incremental search, wenn Escape is pressed
	if( nChar == VK_ESCAPE )
	{
		// if not end incremental search
		m_bIncrementalSearchForward = m_bIncrementalSearchBackward = FALSE;
		SetSelection( m_selStartBeforeIncrementalSearch, m_selEndBeforeIncrementalSearch );
		SetCursorPos( m_cursorPosBeforeIncrementalSearch );
		EnsureVisible( m_cursorPosBeforeIncrementalSearch );
		return;
	}

  // exit incremental search without destroying selection
  if( nChar == VK_RETURN )
  {
    m_bIncrementalSearchForward = m_bIncrementalSearchBackward = FALSE;
    return;
  }

	// is the character valid for incremental search?
	if( !_istgraph( nChar ) && !(nChar == _T(' ')) && !(nChar == _T('\t')) )
	{
		// if not end incremental search
		m_bIncrementalSearchForward = m_bIncrementalSearchBackward = FALSE;
		return;
	}

	// if last search was not successfull do not add a new character
	if( !m_bIncrementalFound )
	{
		MessageBeep( MB_OK );
		return;
	}

	// add character to incremental search string and search
	*m_pstrIncrementalSearchString += (TCHAR) nChar;
	OnEditFindIncremental();
}


void CCrystalTextView::OnEditDeleteBack() 
{
	if( !m_bIncrementalSearchForward && !m_bIncrementalSearchBackward )
		return;

	// remove last character from search string
	if( m_pstrIncrementalSearchString->IsEmpty() )
		return;

	*m_pstrIncrementalSearchString = m_pstrIncrementalSearchString->Left( m_pstrIncrementalSearchString->GetLength() - 1 );
	OnEditFindIncremental();
}


void CCrystalTextView::OnEditFindIncremental( BOOL bFindNextOccurence /*= FALSE*/ )
{
	// when string is empty, then goto position where the search starts
	if( m_pstrIncrementalSearchString->IsEmpty() )
	{
		SetSelection( m_incrementalSearchStartPos, m_incrementalSearchStartPos );
		SetCursorPos( m_incrementalSearchStartPos );
		EnsureVisible( m_incrementalSearchStartPos );
		return;
	}

	// otherwise search next occurence of search string, 
	// starting at current cursor position
	CPoint	matchStart, matchEnd;

	// calculate start point for search
	if( bFindNextOccurence )
	{
		CPoint	selStart, selEnd;
		GetSelection( selStart, selEnd );
		m_incrementalSearchStartPos = (m_bIncrementalSearchBackward)? selStart : selEnd;
	}

	m_bIncrementalFound = FindText( 
		*m_pstrIncrementalSearchString,
		m_incrementalSearchStartPos,
		m_bIncrementalSearchBackward? FIND_DIRECTION_UP : 0,
		TRUE,
		&matchStart );

	if( !m_bIncrementalFound )
	{
		MessageBeep( MB_OK );
		return;
	}

	// select found text and set cursor to end of match
	matchEnd = matchStart;
	matchEnd.x+= m_pstrIncrementalSearchString->GetLength();
	SetSelection( matchStart, matchEnd );
	SetCursorPos( matchEnd );
	EnsureVisible( matchEnd );
}



void CCrystalTextView::OnEditFindIncrementalForward()
{
	if( !m_bIncrementalSearchForward && !m_bIncrementalSearchBackward )
	{
		// initialize
		if( !m_pstrIncrementalSearchString->IsEmpty() )
			*m_pstrIncrementalSearchStringOld = *m_pstrIncrementalSearchString;
		m_pstrIncrementalSearchString->Empty();
		m_incrementalSearchStartPos = m_cursorPosBeforeIncrementalSearch = m_ptCursorPos;
		GetSelection( m_selStartBeforeIncrementalSearch, m_selEndBeforeIncrementalSearch );
	}
	else if( m_bIncrementalSearchForward )
	{
		if( m_pstrIncrementalSearchString->IsEmpty() )
		{
			*m_pstrIncrementalSearchString = *m_pstrIncrementalSearchStringOld;
			m_pstrIncrementalSearchStringOld->Empty();
			OnEditFindIncremental();
		}
		else
			OnEditFindIncremental( TRUE );

		return;
	}

	m_bIncrementalSearchForward = TRUE;
	m_bIncrementalSearchBackward = FALSE;
	m_bIncrementalFound = TRUE;
	OnEditFindIncremental();
}

void CCrystalTextView::OnEditFindIncrementalBackward()
{
	if( !m_bIncrementalSearchForward && !m_bIncrementalSearchBackward )
	{
		// initialize
		if( !m_pstrIncrementalSearchString->IsEmpty() )
			*m_pstrIncrementalSearchStringOld = *m_pstrIncrementalSearchString;
		m_pstrIncrementalSearchString->Empty();
		GetSelection( m_selStartBeforeIncrementalSearch, m_selEndBeforeIncrementalSearch );
		m_incrementalSearchStartPos = m_cursorPosBeforeIncrementalSearch = m_ptCursorPos;
	}
	else if( m_bIncrementalSearchBackward )
	{
		if( m_pstrIncrementalSearchString->IsEmpty() )
		{
			*m_pstrIncrementalSearchString = *m_pstrIncrementalSearchStringOld;
			m_pstrIncrementalSearchStringOld->Empty();
			OnEditFindIncremental();
		}
		else
			OnEditFindIncremental( TRUE );

		return;
	}

	m_bIncrementalSearchForward = FALSE;
	m_bIncrementalSearchBackward = TRUE;
	m_bIncrementalFound = TRUE;
	OnEditFindIncremental();
}

void CCrystalTextView::OnUpdateEditFindIncrementalForward(CCmdUI* pCmdUI)
{
  if (m_pTextBuffer)
    {
      int nLines = m_pTextBuffer->GetLineCount ();
      int nChars = m_pTextBuffer->GetLineLength (m_ptCursorPos.y);
      pCmdUI->Enable(m_ptCursorPos.y < nLines - 1 || m_ptCursorPos.x < nChars);
      return;
    }
  pCmdUI->Enable(FALSE);
}

void CCrystalTextView::OnUpdateEditFindIncrementalBackward(CCmdUI* pCmdUI)
{
  if (m_pTextBuffer)
    {
      pCmdUI->Enable(m_ptCursorPos.y > 0 || m_ptCursorPos.x > 0);
      return;
    }
  pCmdUI->Enable(FALSE);
}

DWORD CCrystalTextView::ParseLineJava (DWORD dwCookie, int nLineIndex, TEXTBLOCK * pBuf,
					 int &nActualItems)
{
  return 0;
}

void CCrystalTextView::OnUpdateStatusMessage( CStatusBar *pStatusBar )
{
	static BOOL	bUpdatedAtLastCall = FALSE;

	ASSERT( pStatusBar && IsWindow( pStatusBar->m_hWnd ) );
	if( !pStatusBar || !IsWindow( pStatusBar->m_hWnd ) )
		return;

	if( !m_bIncrementalSearchForward && !m_bIncrementalSearchBackward )
	{
		if( bUpdatedAtLastCall )
			pStatusBar->SetPaneText( 0, CString( (LPCTSTR)AFX_IDS_IDLEMESSAGE ) );

		bUpdatedAtLastCall = FALSE;

		return;
	}

	CString	strFormat;
	if( !m_bIncrementalFound )
		strFormat.Format( IDS_FIND_INCREMENTAL_FAILED, *m_pstrIncrementalSearchString );
	else if( m_bIncrementalSearchForward )
		strFormat.Format( IDS_FIND_INCREMENTAL_FORWARD, *m_pstrIncrementalSearchString );
	else if( m_bIncrementalSearchBackward )
		strFormat.Format( IDS_FIND_INCREMENTAL_BACKWARD, *m_pstrIncrementalSearchString );

	if( strFormat.IsEmpty() )
		return;

	pStatusBar->SetPaneText( 0, strFormat );
	bUpdatedAtLastCall = TRUE;
}
//END SW





////////////////////////////////////////////////////////////////////////////
#pragma warning ( default : 4100 )

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