SynEditView.cpp
上传用户:hgtech
上传日期:2022-06-07
资源大小:4455k
文件大小:30k
源码类别:

词法分析

开发平台:

Visual C++

  1. #include "stdafx.h"
  2. #include <winver.h>
  3. #include <malloc.h>
  4. #include "SynEditView.h"
  5. bool flag=false;
  6. const COOKIE_COMMENT = 0x0002;
  7. const COOKIE_EXT_COMMENT = 0x0004;
  8. const COOKIE_STRING = 0x0008;
  9. const COOKIE_CHAR = 0x0010;
  10. const COOKIE_DKH = 0x0100;
  11. const COOKIE_XKH = 0x0200;
  12. //定义颜色块宏
  13. #define DEFINE_BLOCK(pos, color)
  14. ASSERT((pos) >= 0 && (pos) <= nLength);
  15. if (ColorInfo != NULL)
  16. {
  17. if (nActualItems == 0 || ColorInfo[nActualItems - 1].Pos <= (pos)) {
  18. ColorInfo[nActualItems].Pos = (pos);
  19. ColorInfo[nActualItems].Color = (color);
  20. nActualItems ++;
  21. }
  22. }
  23. #ifdef _DEBUG
  24. #define new DEBUG_NEW
  25. #undef THIS_FILE
  26. static char THIS_FILE[] = __FILE__;
  27. #endif
  28.  
  29. /////////////////////////////////////////////////////////////////////////////
  30. // CSynEditView
  31. IMPLEMENT_DYNCREATE(CSynEditView, CRichEditView)
  32. BEGIN_MESSAGE_MAP(CSynEditView, CRichEditView)
  33. //{{AFX_MSG_MAP(CSynEditView)
  34. ON_WM_CREATE()
  35. ON_WM_HSCROLL()
  36. ON_WM_VSCROLL()
  37. //}}AFX_MSG_MAP
  38. // Standard printing commands
  39. ON_COMMAND(ID_FILE_PRINT, CRichEditView::OnFilePrint)
  40. ON_COMMAND(ID_FILE_PRINT_DIRECT, CRichEditView::OnFilePrint)
  41. ON_COMMAND(ID_FILE_PRINT_PREVIEW, CRichEditView::OnFilePrintPreview)
  42. END_MESSAGE_MAP()
  43. /////////////////////////////////////////////////////////////////////////////
  44. // CSynEditView construction/destruction
  45. CSynEditView::CSynEditView()
  46. {
  47. m_clrBkColor = RGB(255, 255, 255);  
  48. m_clrCommentColor = RGB(0, 128, 0);  
  49. m_clrSyntaxColor = RGB(0, 0, 255);  
  50. m_clrNormalColor = RGB(0, 0, 0);  
  51. m_clrStringColor = RGB(200, 0, 0);  
  52. m_clrCharColor = RGB(200, 0, 0);  
  53. m_clrNumberColor = RGB(255, 0, 0);  
  54. m_clrBKSelText = RGB(0, 0, 128);  
  55. m_nTabSize = 4;
  56. m_nParseArraySize = 0;
  57. m_nLeftMargin = 1;
  58. m_nTopMargin = 1;
  59. m_bAllowDraw = TRUE;
  60. m_bRealReturn = TRUE;
  61. m_bTracking = FALSE;
  62. m_pdwParseCookies = NULL;
  63. m_rcClient = NULL;
  64. m_pCacheBitmap = NULL;
  65. }
  66. CSynEditView::~CSynEditView()
  67. {
  68. if (m_pCacheBitmap != NULL)
  69. delete m_pCacheBitmap;
  70. if (m_pdwParseCookies != NULL)
  71. delete m_pdwParseCookies;
  72. }
  73. BOOL CSynEditView::PreCreateWindow(CREATESTRUCT& cs)
  74. {
  75. //装入rich edit version 2.0
  76. if (LoadLibraryA("RICHED20.DLL") == NULL)
  77. {
  78. AfxMessageBox(_T("Fail to load "riched20.dll"."),
  79. MB_OK | MB_ICONERROR);
  80. PostMessage(WM_QUIT,0,0);
  81. return FALSE;
  82. }
  83. m_strClass = RICHEDIT_CLASSA; //for 2.0 class 
  84. return CRichEditView::PreCreateWindow(cs);
  85. }
  86. void CSynEditView::OnInitialUpdate()
  87. {
  88. CRichEditView::OnInitialUpdate();
  89. SetMargins(CRect(720, 720, 720, 720));
  90. ResetParseCookie();  //Version 1.0.0.1加入
  91. LoadSynWord();
  92. ::GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT), &m_lf);  
  93. m_lf.lfWeight = FW_NORMAL;
  94. m_lf.lfHeight = 0xfffffff2;
  95. m_lf.lfCharSet = GB2312_CHARSET;
  96. strcpy(m_lf.lfFaceName, _T("Fixedsys"));
  97. SetSynEditViewFont(m_lf);      //设定编辑器字体
  98. SendMessage(EM_SETUNDOLIMIT, 1000, 0);
  99. // GetDocument()->m_bRTF = FALSE; //只处理文本
  100. SetWrapMode(WrapNone);
  101. SendMessage(EM_SETTEXTMODE, TM_PLAINTEXT|TM_MULTILEVELUNDO|TM_SINGLECODEPAGE, 0);
  102. }
  103. /////////////////////////////////////////////////////////////////////////////
  104. // CSynEditView printing
  105. BOOL CSynEditView::OnPreparePrinting(CPrintInfo* pInfo)
  106. {
  107. // default preparation
  108. return DoPreparePrinting(pInfo);
  109. }
  110. /////////////////////////////////////////////////////////////////////////////
  111. // CSynEditView diagnostics
  112. #ifdef _DEBUG
  113. void CSynEditView::AssertValid() const
  114. {
  115. CRichEditView::AssertValid();
  116. }
  117. void CSynEditView::Dump(CDumpContext& dc) const
  118. {
  119. CRichEditView::Dump(dc);
  120. }
  121. #endif //_DEBUG
  122. /////////////////////////////////////////////////////////////////////////////
  123. // CSynEditView message handlers
  124. void CSynEditView::LoadFile(CString strFile)
  125. {
  126. ASSERT(this);
  127. CFile* pInputFile = NULL;
  128. try
  129. {
  130. pInputFile = new CFile(strFile, CFile::modeRead | CFile::shareDenyNone);
  131. EDITSTREAM strm;
  132. strm.dwCookie = (DWORD) pInputFile;
  133. strm.pfnCallback = EditStreamCallbackReadFromFile;
  134. long lResult = GetRichEditCtrl().StreamIn(SF_TEXT, strm);
  135. pInputFile->Close();
  136. delete pInputFile;
  137. }
  138. catch (CFileException* pEx)
  139. {
  140. pEx->Delete();
  141. }
  142. GetRichEditCtrl().SetModify( FALSE ); 
  143. }
  144.  
  145. //设定编辑器字体
  146. void CSynEditView::SetSynEditViewFont(LOGFONT lf)
  147. {
  148. m_lf = lf;
  149. SetSynCtrlFont();
  150. SetSynEditViewTabSize(m_nTabSize);
  151. }
  152. void CSynEditView::SetSynCtrlFont()
  153. {
  154. CString str;
  155. GetWindowText(str);
  156. BOOL bModify = GetRichEditCtrl().GetModify(); 
  157. m_font.DeleteObject();
  158. m_font.CreateFontIndirect(&m_lf); 
  159. SetFont(&m_font);
  160. CalcEditorInfo();
  161. SetSynEditViewMargin(m_nCharNumberWidth, 0);
  162. SetWindowText(str);
  163. GetRichEditCtrl().SetModify(bModify);
  164. }
  165. //设定编辑器的Tab宽度,以空格为标准进行计算   //TAB也是一种形式的空格
  166. void CSynEditView::SetSynEditViewTabSize(int nSize)
  167. {
  168. ResetParseCookie();
  169. CString str;
  170. GetWindowText(str);
  171. CRichEditCtrl &SynCtrl = GetRichEditCtrl();
  172. BOOL bModify = SynCtrl.GetModify(); 
  173. SetSynCtrlTabSize(nSize);
  174. SetWindowText(str);
  175. SynCtrl.SetModify(bModify);
  176. }
  177. //改变RichEditCtrl的默认Tab宽度
  178. void CSynEditView::SetSynCtrlTabSize(int nSize)
  179. {
  180. CRichEditCtrl &SynCtrl = GetRichEditCtrl();  
  181. //设置TAB间隔
  182. CDC *pdc = GetDC();
  183. PARAFORMAT pf ;
  184. pf.cbSize = sizeof(PARAFORMAT);
  185. pf.dwMask = PFM_TABSTOPS ;
  186. pf.cTabCount = MAX_TAB_STOPS;
  187. SynCtrl.GetParaFormat( pf );
  188. int nSynCtrlTabSize = pf.rgxTabs[0];
  189. if(nSynCtrlTabSize == 0)
  190. nSynCtrlTabSize = 720;
  191. int nNewTab;
  192. nNewTab = int(nSynCtrlTabSize * 1.0 * nSize * m_nCharSpaceWidth / m_nCharTabWidth);
  193. pf.cTabCount = MAX_TAB_STOPS;
  194. pf.dwMask = PFM_TABSTOPS;
  195. for( int itab = 0; itab < pf.cTabCount; itab++ )
  196. pf.rgxTabs[itab] = (itab+1) * nNewTab ;
  197. SetParaFormat( pf );
  198. m_nTabSize = nSize;
  199. }
  200. //根据指定行在指定的矩形区域画出语法加亮的文本
  201. void CSynEditView::DrawSingleLineColorText( CDC *cacheDC, int nLine, CRect rcLine)
  202. {
  203. CRect rectforspace(rcLine);
  204. CRect rect(rcLine);
  205. CFont cf;
  206. cf.CreateFontIndirect(&m_lf);
  207. CFont *pOldFont = cacheDC->SelectObject(&cf);
  208. CString strnewline=_T(""), strtmp=_T(""), strLine;
  209. BOOL bRealReturn = GetLineString(nLine, strLine); //取指定行文本,并返回是否为硬回车标志
  210. int nTabNumber = 0;
  211. int npos = strLine.Find(_T("t"));
  212. //将所有的Tab转化为相应数量的空格
  213. while(npos!=-1) {
  214. strtmp = strLine.Left(npos); 
  215. int nlen = strtmp.GetLength();
  216. nlen %= m_nTabSize;
  217. nlen = m_nTabSize - nlen;
  218. CString strNewTab(0x20, nlen);
  219. strtmp+=strNewTab;
  220. strnewline+=strtmp;
  221. strLine=strLine.Right(strLine.GetLength()-npos-1); 
  222. npos = strLine.Find(_T("t"));
  223. }
  224. strnewline+=strLine;
  225. strLine=strnewline;
  226. int nLength = strLine.GetLength(); 
  227. CSize size;
  228. int nActualItems = 0;
  229. COLORINFO *ColorInfo = (COLORINFO *)_alloca( sizeof(COLORINFO) * (nLength + 1) );
  230. DWORD dwCookie = GetParseCookie(nLine-1);
  231. CString str;
  232. if( m_bRealReturn )
  233. dwCookie &= COOKIE_EXT_COMMENT;
  234. m_bRealReturn = bRealReturn;
  235. dwCookie = ParseLine(dwCookie, strLine, ColorInfo, nActualItems);
  236. m_pdwParseCookies[nLine] = dwCookie;
  237. COLORREF clr;
  238. int nlen;
  239. if (nActualItems > 0)
  240. {
  241. ASSERT(ColorInfo[0].Pos >= 0 && ColorInfo[0].Pos <= nLength);
  242. for (int I = 0; I < nActualItems; I ++)
  243. {
  244. nlen = ColorInfo[I + 1].Pos - ColorInfo[I].Pos;
  245. if( I == nActualItems - 1 )
  246. str = strLine.Mid(ColorInfo[I].Pos, strLine.GetLength() - ColorInfo[I].Pos);
  247. else
  248. str = strLine.Mid(ColorInfo[I].Pos, nlen);
  249. if(str.IsEmpty())
  250. continue;
  251. clr = GetColor(ColorInfo[I].Color);
  252. JudgeInSeletioAndDrawText( cacheDC, rcLine, str, m_clrBkColor, clr );
  253. }
  254. }
  255. cacheDC->SelectObject(pOldFont); 
  256. }
  257. //设置窗口内是否自动换行
  258. void CSynEditView::SetWrapMode(int nWrapMode)   
  259. {
  260. ASSERT(this);
  261. m_nWordWrap = nWrapMode;
  262. CSynEditView::WrapChanged(); 
  263. ResetParseCookie();
  264. if(m_nWordWrap == WrapNone)
  265. {
  266. GetRichEditCtrl().ShowScrollBar(SB_BOTH, TRUE); 
  267. }
  268. else
  269. {
  270. GetRichEditCtrl().ShowScrollBar(SB_HORZ, FALSE); 
  271. }
  272. }
  273. int CSynEditView::GetLinesTop(int nline)         //得到第一行
  274. {
  275. CRichEditCtrl &SynCtrl = GetRichEditCtrl();
  276. if( nline > SynCtrl.GetLineCount()-1 ) {
  277. int nOffset = SynCtrl.LineIndex( nline-1 );
  278. CPoint p = SynCtrl.GetCharPos( nOffset );
  279. return p.y+m_nLineHeight;
  280. }
  281. int nOffset = SynCtrl.LineIndex( nline );
  282. CPoint p = SynCtrl.GetCharPos( nOffset );
  283. return p.y;
  284. }
  285. int CSynEditView::GetCurrentLine()               //得到当前行
  286. {
  287. CRichEditCtrl &SynCtrl=GetRichEditCtrl();
  288. CHARRANGE cr;
  289. SynCtrl.GetSel(cr); 
  290. if( cr.cpMin == cr.cpMax )
  291. return SynCtrl.LineFromChar( cr.cpMax );
  292. else
  293. return m_nCurrentLine;
  294. }
  295. DWORD CSynEditView::GetParseCookie(int nLineIndex)
  296. {
  297. CRichEditCtrl &SynCtrl=GetRichEditCtrl();
  298. if (m_pdwParseCookies == NULL)
  299. {
  300. m_nParseArraySize = m_nLineCount;
  301. m_pdwParseCookies = new DWORD[m_nLineCount];
  302. memset(m_pdwParseCookies, 0xff, m_nLineCount * sizeof(DWORD));
  303. }
  304. if (nLineIndex < 0)
  305. return 0;
  306. if (m_pdwParseCookies[nLineIndex] != (DWORD) -1)
  307. return m_pdwParseCookies[nLineIndex];
  308. register int L = nLineIndex;
  309. while (L >= 0 && m_pdwParseCookies[L] == (DWORD) -1)
  310. L --;
  311.  L ++;
  312. int nBlocks = 0;
  313. CString strLine;
  314. BOOL bRealReturn = m_bRealReturn;
  315. while (L <= nLineIndex)
  316. {
  317. DWORD dwCookie = 0;
  318. if (L > 0) {
  319. dwCookie = m_pdwParseCookies[L - 1];
  320. if(bRealReturn )
  321. dwCookie &= COOKIE_EXT_COMMENT;
  322. }
  323. ASSERT(dwCookie != (DWORD) -1);
  324. bRealReturn = GetLineString(L, strLine);
  325. m_pdwParseCookies[L] = ParseLine(dwCookie, strLine, NULL, nBlocks);
  326. ASSERT(m_pdwParseCookies[L] != (DWORD) -1);
  327. L ++;
  328. }
  329. return m_pdwParseCookies[nLineIndex];
  330. }
  331. //取指定行文本,返回指定该行在WrapToWindow模式下是否为硬回车
  332. //[注]在WrapToWindow模式下如果一行过长则会被分割成多行,此时只有最后一行才是硬回车
  333. BOOL CSynEditView::GetLineString(int nLine, CString &strLine)
  334. {
  335. strLine = _T("");
  336. CRichEditCtrl &SynCtrl=GetRichEditCtrl();
  337. if(nLine > m_nLineCount - 1 || nLine < 0) 
  338. return TRUE;
  339. int nTemp = SynCtrl.LineIndex(nLine);
  340. nTemp = SynCtrl.LineLength(nTemp) * sizeof(WCHAR);
  341. if(nTemp<=1) {
  342. strLine=_T(" ");
  343. return TRUE;
  344. }
  345. nTemp += 4 * sizeof(WCHAR); //尽量多留点空
  346. int nLen = SynCtrl.GetLine(nLine, strLine.GetBuffer(nTemp), nTemp);  
  347. strLine.ReleaseBuffer(); 
  348. BOOL bRealReturn;
  349. if(nLen > strLine.GetLength())
  350. nLen = strLine.GetLength();
  351. if(nLen>=1 && strLine[nLen-1]==0xd ) {
  352. strLine = strLine.Left(--nLen);  
  353. bRealReturn=TRUE;
  354. }
  355. else  {
  356. strLine = strLine.Left(nLen);  
  357. bRealReturn=FALSE;
  358. }
  359. strLine += _T(" ");
  360. return bRealReturn;
  361. }
  362. //重置语法解析缓冲区
  363. void CSynEditView::ResetParseCookie()
  364. {
  365. m_nParseArraySize = 0;
  366. m_nHorzPos = 0;
  367. if(m_pdwParseCookies != NULL) {
  368. delete m_pdwParseCookies;
  369. m_pdwParseCookies = NULL;
  370. }
  371. if(m_pCacheBitmap!=NULL) {
  372. delete m_pCacheBitmap;
  373. m_pCacheBitmap = NULL;
  374. }
  375. return;
  376. }
  377. int CSynEditView::OnCreate( LPCREATESTRUCT lpCreateStruct )
  378. {
  379. if (CRichEditView::OnCreate(lpCreateStruct) == -1)
  380. return -1;
  381. GetRichEditCtrl().HideSelection(TRUE, FALSE); 
  382. return 0;
  383. }
  384. void CSynEditView::CalcSelection()
  385. {
  386. CRichEditCtrl &SynCtrl = GetRichEditCtrl();
  387. CHARRANGE cr;
  388. SynCtrl.GetSel( cr ); 
  389. m_ptSelStart = SynCtrl.GetCharPos( cr.cpMin ); 
  390. m_ptSelEnd = SynCtrl.GetCharPos( cr.cpMax );
  391. }
  392. //根据给定点的x,y坐标判断该点是否在选定区域内
  393. BOOL CSynEditView::IsStrInSelection(int ptLeft, int ptTop)
  394. {
  395. if( m_ptSelStart == m_ptSelEnd ) //如果没有选定直接返回FALSE
  396. return FALSE;
  397. CPoint ptSelStart = m_ptSelStart;
  398. CPoint ptSelEnd = m_ptSelEnd;
  399. //考虑边界的情况,将选定区域左右延伸半个字符宽度
  400. ptSelStart.x -= m_nCharNumberWidth/2;
  401. ptSelEnd.x += m_nCharNumberWidth/2;
  402. if( ptSelStart.y == ptSelEnd.y ) { //如果选定行为单行
  403. if( ptTop != ptSelStart.y ) //如果光标不在该行
  404. return FALSE;
  405. else {
  406. if( ptLeft >= ptSelStart.x && ptLeft <= ptSelEnd.x)
  407. return TRUE;
  408. else
  409. return FALSE;
  410. }
  411. }
  412. else {
  413. if( ptTop == ptSelStart.y ) { //如果当前位置在选取定行的第一行
  414. if( ptLeft <  ptSelStart.x )
  415. return FALSE;
  416. else
  417. return TRUE;
  418. }
  419. if( ptTop == ptSelEnd.y ) { //如果当前位置在选定行的最后一行
  420. if( ptLeft < ptSelEnd.x )
  421. return TRUE;
  422. else
  423. return FALSE;
  424. }
  425. else if( ptTop > ptSelStart.y && ptTop < ptSelEnd.y ) //如果当前位置在选定行的中间
  426. return TRUE;
  427. else
  428. return FALSE;
  429. }
  430. }
  431. //判断给定的字符是否在选择区域内,并画出该字符串
  432. void CSynEditView::JudgeInSeletioAndDrawText(CDC *cacheDC, CRect &rcLine, CString &str, COLORREF clrBkColor, COLORREF clrText)
  433. {
  434. COLORREF clrSelText;
  435. int nFormat = DT_LEFT|DT_NOPREFIX|DT_EXPANDTABS|DT_VCENTER|DT_SINGLELINE|DT_RTLREADING;
  436. CSize size = cacheDC->GetTextExtent(str); 
  437. if( !IsSelectionInStr(rcLine.left, size.cx, rcLine.top) ) {
  438. BOOL bStrLeft = IsStrInSelection( rcLine.left, rcLine.top );
  439. BOOL bStrRight = IsStrInSelection( rcLine.left + size.cx, rcLine.top );
  440. if( !bStrLeft && !bStrRight ) { //如果str的左右都不在选定区域内
  441. cacheDC->SetBkColor( clrBkColor ); 
  442. cacheDC->SetTextColor( clrText );
  443. cacheDC->TextOut( rcLine.left, rcLine.top, str);
  444. rcLine.OffsetRect( size.cx, 0 );
  445. return;
  446. }
  447. else if( bStrLeft && bStrRight ) { //如果str的左右都在选定区域内
  448. CRect rect(rcLine);
  449. rect.right = rect.left + size.cx;
  450. cacheDC->FillSolidRect( &rect, m_clrBKSelText ); 
  451. clrSelText = RGB( 255-GetRValue(clrText), 255-GetGValue(clrText), 255-GetBValue(clrText) );
  452. cacheDC->SetTextColor( clrSelText );
  453. cacheDC->TextOut( rcLine.left, rcLine.top, str);
  454. rcLine.OffsetRect( size.cx, 0 );
  455. return;
  456. }
  457. }
  458. //如果str部分在选定区域内, 或者选定区域在str内执行以下代码
  459. CString strChar;
  460. for( int nChar = 0; nChar < str.GetLength(); nChar++ ) {
  461. strChar = str.Mid( nChar, 1 );
  462. size = cacheDC->GetTextExtent( strChar ); 
  463. BOOL bStrLeft = IsStrInSelection( rcLine.left, rcLine.top );
  464. BOOL bStrRight = IsStrInSelection( rcLine.left + size.cx, rcLine.top );
  465. if( bStrLeft && bStrRight ) { 
  466. CRect rect(rcLine);
  467. rect.right = rect.left + size.cx;
  468. cacheDC->FillSolidRect( &rect, m_clrBKSelText ); 
  469. clrSelText = RGB( 255-GetRValue(clrText), 255-GetGValue(clrText), 255-GetBValue(clrText) );
  470. cacheDC->SetTextColor( clrSelText );
  471. }
  472. else {
  473. cacheDC->SetBkColor( clrBkColor ); 
  474. cacheDC->SetTextColor( clrText );
  475. }
  476. cacheDC->TextOut( rcLine.left, rcLine.top, strChar);
  477. rcLine.OffsetRect( size.cx, 0 );
  478. }
  479. }
  480. //计算水平滚动位置,以便在水平滚动时可以正确显示
  481. void CSynEditView::CalcHorzScrollPos()
  482. {
  483. if(m_nWordWrap == WrapToWindow)
  484. {
  485. m_nHorzPos = 0;
  486. return;
  487. }
  488. SCROLLINFO si;
  489. si.cbSize = sizeof(si);
  490. GetScrollInfo(SB_HORZ, &si);
  491. if( m_bTracking ) 
  492. m_nHorzPos = si.nTrackPos;
  493. else
  494. m_nHorzPos = si.nPos;
  495. }
  496. //在RichEditView上画出内容
  497. void CSynEditView::DrawSynEditView()
  498. {
  499. if(!m_bAllowDraw)
  500.   return;
  501.    CRichEditCtrl &SynCtrl = GetRichEditCtrl();
  502. m_nLineCount = SynCtrl.GetLineCount(); 
  503.   m_nCurrentLine = GetCurrentLine();
  504.   if (m_pdwParseCookies != NULL)
  505.   {
  506.   if (m_nParseArraySize != m_nLineCount)
  507.   {
  508. int nCurrentLine = m_nCurrentLine;
  509. if(m_nParseArraySize < m_nLineCount) 
  510. {
  511. nCurrentLine = m_nParseArraySize + m_nCurrentLine - m_nLineCount; 
  512. if(nCurrentLine<0)
  513. nCurrentLine = m_nCurrentLine;
  514. }
  515. if(m_nCurrentLine>m_nLineCount)
  516. nCurrentLine=0;
  517.   // 重新分配缓冲区大小
  518.   DWORD *pdwNewArray = new DWORD[m_nLineCount];
  519.   if (m_nCurrentLine > 0)
  520.   memcpy(pdwNewArray, m_pdwParseCookies, sizeof(DWORD) * nCurrentLine);
  521.  
  522. delete m_pdwParseCookies;
  523.   m_nParseArraySize = m_nLineCount;
  524.   m_pdwParseCookies = pdwNewArray;
  525. memset(m_pdwParseCookies + nCurrentLine, 0xff, sizeof(DWORD) * (m_nParseArraySize - nCurrentLine));
  526.   }
  527.   }
  528.  
  529.   CDC *pdc=GetDC();
  530.   CDC cacheDC;
  531.   VERIFY(cacheDC.CreateCompatibleDC(pdc));
  532.   if (m_pCacheBitmap == NULL)
  533.   {
  534.   m_pCacheBitmap = new CBitmap;
  535.   m_pCacheBitmap->CreateCompatibleBitmap(pdc, m_rcClient.Width(), m_rcClient.Height());  //nLineHeight);
  536.   }
  537.   CBitmap *pOldBitmap = cacheDC.SelectObject(m_pCacheBitmap);
  538.  
  539. CalcSelection();
  540. CalcHorzScrollPos();
  541. CString str;
  542. int nLine = SynCtrl.GetFirstVisibleLine();           
  543.   if(nLine==0)
  544. m_bRealReturn = TRUE;
  545. else
  546. m_bRealReturn = GetLineString(nLine-1, str);
  547. CRect rcEditor(m_rcClient);
  548. //将显示区域背景色画好
  549. cacheDC.FillSolidRect(&rcEditor, m_clrBkColor); 
  550. rcEditor.left = m_nLeftMargin - m_nHorzPos - 1;
  551. int nLinesTop = GetLinesTop(nLine); //第一行要计算好偏移值,因为第一行可能只显示部分
  552. rcEditor.top = nLinesTop + m_nTopMargin;
  553. rcEditor.bottom = rcEditor.top + m_nLineHeight;
  554. int nNumberToDraw = 0;
  555. while(rcEditor.top <= m_rcClient.bottom ) 
  556. {
  557. if(nLine > m_nLineCount-1)
  558. break;
  559. //画出一行文本
  560. DrawSingleLineColorText(&cacheDC, nLine++, rcEditor);
  561. //重新定位下一行的位置
  562. rcEditor.OffsetRect(0, m_nLineHeight );
  563. }
  564. //将缓冲画布cacheDC上的内容复制到RichEditView视上
  565. pdc->BitBlt(m_rcClient.left, m_rcClient.top, m_rcClient.Width(), m_rcClient.Height(), &cacheDC, 0, 0, SRCCOPY);
  566.  
  567.   cacheDC.SelectObject(pOldBitmap);
  568.   cacheDC.DeleteDC();
  569. }
  570. /* 判断选择选区域是否在字符串所处位置的内部
  571. [入口参数]:
  572. nFromHere - 待测试的字符串的起始位置
  573. nStrWidth - 待测试的字符串的宽度
  574. nTop - 待测试的字符串的顶部位置
  575. [返回值]:
  576. TRUE - 选定区域在字符串所处位置的内部
  577. FLASE - 选定区域不在字符串所处位置的内部
  578. */
  579. BOOL CSynEditView::IsSelectionInStr(int nFromHere, int nStrWidth, int nTop)
  580. {
  581. if( m_ptSelStart == m_ptSelEnd )
  582. return FALSE;
  583. if( m_ptSelStart.y != m_ptSelEnd.y )  //如果选定行不为单行,返回,因为字符不可能跨行
  584. return FALSE;
  585. if( m_ptSelStart.y != nTop )  //如果待测试行的顶部不等于选定行的顶部则返回
  586. return FALSE;
  587. if( (m_ptSelStart.x > nFromHere) && (m_ptSelEnd.x < nFromHere + nStrWidth) )
  588. return TRUE;
  589. else
  590. return FALSE;
  591. }
  592. COLORREF CSynEditView::GetColor(int nColorIndex)
  593. {
  594. switch(nColorIndex) 
  595. {
  596. case COLORINDEX_NUMBER:
  597. return m_clrNumberColor;
  598. case COLORINDEX_BK:
  599. return m_clrBkColor;
  600. case COLORINDEX_COMMENT:
  601. return m_clrCommentColor;
  602. case COLORINDEX_SYNTAX:
  603. return m_clrSyntaxColor;
  604. case COLORINDEX_NORMAL:
  605. return m_clrNormalColor;
  606. case COLORINDEX_STRING:
  607. return m_clrStringColor;
  608. case COLORINDEX_CHAR:
  609. return m_clrCharColor;
  610. default:
  611. return m_clrNormalColor;
  612. }
  613. }
  614. //这个函数的作用是在粘贴时重置nParseArraySize的语法解析缓冲区
  615. void CSynEditView::SetParseCookieZeroFromGivenLine(int nParseArraySize)
  616. {
  617. memset(m_pdwParseCookies + nParseArraySize, 0xff, sizeof(DWORD) * (m_nParseArraySize - nParseArraySize));
  618. }
  619. //判断给定的串是否是语法关键字
  620. BOOL CSynEditView::IsSynWord(CString &strReadyToTest)
  621. {
  622. BOOL bMatch;
  623. for(int i=0; i<m_strArrayKeyWords.GetSize(); i++) 
  624. {
  625. bMatch = (strReadyToTest.CompareNoCase(m_strArrayKeyWords[i])==0);
  626. if(bMatch)
  627. return TRUE;
  628. }
  629. return FALSE;
  630. }
  631. //装入指定语言的语法关键字
  632. void CSynEditView::LoadSynWord() 
  633. {
  634. CString strAllSynWord;
  635. m_strArrayKeyWords.RemoveAll();
  636. strAllSynWord = _T(" #define,#else,#elif,#elseif,#endif,#error,#if,#ifdef,#ifndef,#include,#pragma,#undef,__asm,__based,__cdecl,__declspec,__except,__fastcall,__finally,__inline,__int16,__int32,__int64,__int8,__leave,__multiple_inheritance,__pascal,__single_inheritance,__stdcall,__try,__uuidof,__virtual_inheritance,_asm,_cdecl,_fastcall,_pascal,_stdcall,afx_msg,auto,bool,break,case,catch,char,class,code_seg,const,const_cast,continue,default,defined,delete,dllexport,dllimport,do,double,dynamic_cast,else,enum,explicit,extern,false,float,for,friend,goto,if,inline,int,interface,long,main,mutable,naked,namespace,new,off,on,once,operator,pack,pascal,pop,private,protected,public,push,register,reinterpret_cast,return,short,signed,sizeof,static,static_cast,struct,switch,template,this,thread,throw,true,try,typedef,typeid,typename,union,unsigned,using,uuid,virtual,void,volatile,while,wmain,xalloc,");
  637. CString strTemp;
  638. int nPosPrior = 0;
  639. int nPos;
  640. nPos = strAllSynWord.Find(_T(","), nPosPrior);
  641. while(nPos!=-1)
  642. {
  643. strTemp = strAllSynWord.Mid(nPosPrior+1 , nPos - nPosPrior - 1);
  644. m_strArrayKeyWords.Add(strTemp);
  645. nPosPrior = nPos;
  646. nPos = strAllSynWord.Find(_T(","),  nPosPrior + 1);
  647. }
  648. }
  649. void CSynEditView::CalcEditorInfo()
  650. {
  651. ShowWindow(FALSE);
  652. CPoint p1, p2;
  653. CRichEditCtrl &SynCtrl = GetRichEditCtrl();
  654. SynCtrl.SetWindowText(_T("8"));  
  655. p1 = SynCtrl.GetCharPos(0);
  656. p2 = SynCtrl.GetCharPos(1);
  657. m_nCharNumberWidth = p2.x - p1.x; //数字宽度
  658. SynCtrl.SetWindowText(_T(" "));  
  659. p1 = SynCtrl.GetCharPos(0);
  660. p2 = SynCtrl.GetCharPos(1);
  661. m_nCharSpaceWidth = p2.x - p1.x; //空格宽度
  662. SynCtrl.SetWindowText(_T("t"));  
  663. p1 = SynCtrl.GetCharPos(0);
  664. p2 = SynCtrl.GetCharPos(1);
  665. m_nCharTabWidth = p2.x - p1.x; //TAB宽度
  666. SynCtrl.SetWindowText(_T("n     "));
  667. CPoint ps, pe;
  668. p1 = SynCtrl.GetCharPos(0);
  669. p2 = SynCtrl.GetCharPos(3);
  670. //m_nLineHeight = p2.y - p1.y; //行高
  671. m_nLineHeight = 16;
  672. ShowWindow(TRUE);
  673. }
  674. LRESULT CSynEditView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
  675. {
  676. switch (message) 
  677. {
  678. case WM_PAINT:
  679. {
  680. CPaintDC dc(this); // device context for painting
  681. DrawSynEditView();
  682. return FALSE;
  683. }
  684. case WM_PASTE:
  685. {
  686. //处理粘贴的情况,当用户粘入rtf格式时,只取出其中的文本,否则直接粘可能会引起文本错位
  687. char * buffer;
  688. if(!OpenClipboard())
  689. return FALSE;
  690. buffer = (char*)::GetClipboardData(CF_TEXT);
  691. CloseClipboard(); 
  692. CString str = buffer;
  693. CRichEditCtrl &edit = GetRichEditCtrl();
  694. CHARRANGE cr;
  695. edit.GetSel(cr); 
  696. SetParseCookieZeroFromGivenLine(edit.LineFromChar(cr.cpMin)); //粘贴时需重置解析缓冲区
  697. edit.ReplaceSel(str, TRUE); 
  698. return FALSE;
  699. }
  700. case WM_SIZE:
  701. {
  702. CRichEditView::WindowProc(message, wParam, lParam);
  703. GetParent()->GetClientRect(&m_rcClient); 
  704. MoveWindow(&m_rcClient);
  705. if (m_pCacheBitmap != NULL)
  706. {
  707. delete m_pCacheBitmap;
  708. m_pCacheBitmap = NULL;
  709. }
  710. return FALSE;
  711. }
  712. default:
  713. return CRichEditView::WindowProc(message, wParam, lParam);
  714. }
  715. }
  716. void CSynEditView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
  717. {
  718. InvalidateRect(m_rcClient, FALSE);
  719. m_bAllowDraw = FALSE;
  720. CRichEditView::OnHScroll(nSBCode, nPos, pScrollBar);
  721. m_bAllowDraw = TRUE;
  722. ValidateRect(m_rcClient);
  723. //判断用户是否正在拖动水平滚动条
  724. SCROLLINFO si;
  725. si.cbSize = sizeof(si);
  726. GetScrollInfo(SB_HORZ, &si);
  727. if(nSBCode==SB_THUMBPOSITION || nSBCode==SB_THUMBTRACK)
  728. m_bTracking = TRUE;
  729. else
  730. m_bTracking = FALSE;
  731. SendMessage(WM_PAINT, 0, 0);
  732. }
  733. void CSynEditView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
  734. {
  735. InvalidateRect(m_rcClient, FALSE);
  736. m_bAllowDraw = FALSE;
  737. CRichEditView::OnVScroll(nSBCode, nPos, pScrollBar);
  738. m_bAllowDraw = TRUE;
  739. ValidateRect(m_rcClient);
  740. SendMessage(WM_PAINT, 0, 0);
  741. }
  742. /* dwCookie - 传入前一行的解析结果,如果前一行是多行注释的开始
  743. 或者前一行是一软回车时有用
  744. strLine - 被解析的一行字符串
  745. ColorInfo - 解析后的颜色值,指定是关键字、字符串、注释还是正常的字符颜色
  746. nActualItems - strLine被解析后的块数
  747. 函数返回解析结果,指示解析后当前行是处于字符串中、注释中、多行注释中还是正常状态
  748. nActualItems - 返回当前行分解的字符串块数
  749. */
  750. DWORD CSynEditView::ParseLine( DWORD dwCookie, 
  751. CString &strLine, 
  752. COLORINFO *ColorInfo, 
  753. int &nActualItems)
  754. {
  755. int nLength = strLine.GetLength(); 
  756. if(nLength == 0)
  757. return dwCookie;
  758. int nIdentBegin = -1;
  759. BOOL bRedefineBlock = TRUE;
  760. BOOL bDecIndex  = FALSE;
  761. BOOL bIsInTheControlChar = FALSE;
  762. //上一行之变量指示是否在的控制中, 初始化时必须为FALSE
  763. //控制字符的含义:参考下列语句:
  764. //CString strTemp = _T(""");
  765. //第二个引号并不表示字符串变量的结束,而是表明这是在定义"这个字符串,
  766. //这是因为它的前面有控制字符,第三个引号才表示定义字符串变量的结束。
  767. for (int I = 0; ; I++)
  768. {
  769. if (bRedefineBlock) //如果开始定义颜色块则向下做
  770. {
  771. int nPos = I;
  772. if (bDecIndex)
  773. nPos--;
  774. if (dwCookie & (COOKIE_COMMENT | COOKIE_EXT_COMMENT))
  775. {
  776. DEFINE_BLOCK(nPos, COLORINDEX_COMMENT);
  777. }
  778. else {
  779. if (dwCookie & COOKIE_STRING)
  780. {
  781. DEFINE_BLOCK(nPos, COLORINDEX_STRING);
  782. }
  783. else
  784. {
  785. DEFINE_BLOCK(nPos, COLORINDEX_NORMAL);
  786. }
  787. }
  788. bRedefineBlock = FALSE;
  789. bDecIndex      = FALSE;
  790. }
  791. if (I == nLength)
  792. goto Out;
  793. if (dwCookie & COOKIE_COMMENT)
  794. {
  795. DEFINE_BLOCK(I, COLORINDEX_COMMENT);
  796. dwCookie |= COOKIE_COMMENT;
  797. goto Out;
  798. }
  799. if (dwCookie & COOKIE_STRING)
  800. //如果当前正处于字符串变量中,则应检查是否有结束字符串变量的字符串
  801. {
  802. if(I > 0) 
  803. {
  804. if(strLine[I-1] != '\')
  805. {
  806. if(strLine[I] != '\') 
  807. bIsInTheControlChar = FALSE;
  808. else
  809. bIsInTheControlChar = TRUE;
  810. }
  811. else 
  812. {
  813. if(strLine[I] == '\') 
  814. {
  815. if(!bIsInTheControlChar)
  816. bIsInTheControlChar = TRUE;
  817. else
  818. bIsInTheControlChar = FALSE;
  819. }
  820. }
  821. }
  822. if(strLine[I]==_T('"') && !bIsInTheControlChar) 
  823. {
  824. dwCookie &= ~COOKIE_STRING;
  825. bRedefineBlock = TRUE;
  826. }
  827. goto CmpNextChar;
  828. }
  829. if (dwCookie & COOKIE_CHAR)
  830. //如果当前正处于字符变量中,则应检查是否有结束字符变量的字符串
  831. {
  832. if(I > 0) {
  833. if(strLine[I-1] != '\') 
  834. {
  835. if(strLine[I] != '\') 
  836. bIsInTheControlChar = FALSE;
  837. else
  838. bIsInTheControlChar = TRUE;
  839. }
  840. else 
  841. {
  842. if(strLine[I] == '\') 
  843. {
  844. if(!bIsInTheControlChar)
  845. bIsInTheControlChar = TRUE;
  846. else
  847. bIsInTheControlChar = FALSE;
  848. }
  849. }
  850. }
  851. if(strLine[I]==_T(''') && !bIsInTheControlChar) 
  852. {
  853. dwCookie &= ~COOKIE_CHAR;
  854. bRedefineBlock = TRUE;
  855. }
  856. goto CmpNextChar;
  857. }
  858. if (dwCookie & COOKIE_EXT_COMMENT)
  859. //如果当前正处于多行注释中,则应检查是否有结束多行注释的字符串
  860. {
  861. if(I >= 1 && strLine[I-1]==_T('*') && strLine[I]==_T('/'))
  862. {
  863. dwCookie &= ~COOKIE_EXT_COMMENT;
  864. bRedefineBlock = TRUE;
  865. }
  866. goto CmpNextChar;
  867. }
  868. if(I >= 1 && strLine[I-1]==_T('/') && strLine[I]==_T('/'))
  869. //处理单行注释
  870. {
  871. DEFINE_BLOCK(I - 1, COLORINDEX_COMMENT);
  872. dwCookie |= COOKIE_COMMENT;
  873. goto Out; //只要发现有单行注释的字符串则退出
  874. }
  875. if( strLine[I]==_T('"') )
  876. //处理字符串变量
  877. {
  878. DEFINE_BLOCK(I, COLORINDEX_STRING);
  879. dwCookie |= COOKIE_STRING;
  880. goto CmpNextChar;
  881. }
  882. if( strLine[I]==_T(''') )
  883. //处理字符变量
  884. {
  885. DEFINE_BLOCK(I, COLORINDEX_CHAR);
  886. dwCookie |= COOKIE_CHAR;
  887. goto CmpNextChar;
  888. }
  889. if(strLine[I]=='}'||strLine[I]=='{')
  890. {
  891.    
  892.  DEFINE_BLOCK(I , COLORINDEX_COMMENT);
  893.  bRedefineBlock = true;
  894.  goto CmpNextChar;
  895. }                                                   //判断是否为'}'或'{'
  896. if(strLine[I]=='('||strLine[I]==')')
  897. {
  898.    
  899. DEFINE_BLOCK(I , COLORINDEX_NUMBER);
  900. bRedefineBlock = true;
  901. goto CmpNextChar;
  902. }                                               //判断是否为')'或'('
  903. if( I>=1 && strLine[I-1]==_T('/') && strLine[I]==_T('*'))
  904. //处理多行注释
  905. {
  906. DEFINE_BLOCK(I - 1, COLORINDEX_COMMENT);
  907. dwCookie |= COOKIE_EXT_COMMENT;
  908. if ( ++I >= nLength) // 考虑"/*/"的情况
  909. goto Out;
  910. goto CmpNextChar;
  911. }
  912. //C++中,字符串由字母和下划线_组成,我们扩展来包含#以处理类似#if的关键字
  913. if (isalnum(strLine[I]) || strLine[I] == '_' || strLine[I] == '#')
  914. {
  915. if (nIdentBegin == -1)
  916. nIdentBegin = I;
  917. }
  918. else
  919. {
  920. //分解出一个字符串,此时判断是关键字还是数字
  921. if (nIdentBegin >= 0)
  922. {
  923. CString strtmp= strLine.Mid(nIdentBegin, I - nIdentBegin); 
  924. /*if(strtmp=='}'||strtmp=='}')
  925. {
  926.   DEFINE_BLOCK(nIdentBegin, COLORINDEX_SYNTAX);
  927. } */
  928. if (IsSynWord(strtmp))
  929. {
  930. DEFINE_BLOCK(nIdentBegin, COLORINDEX_SYNTAX);
  931. }
  932. else if (IsNumber(strtmp))
  933. {
  934. DEFINE_BLOCK(nIdentBegin, COLORINDEX_NUMBER);
  935. }
  936. bRedefineBlock = TRUE;
  937. bDecIndex = TRUE;
  938. nIdentBegin = -1;
  939. }
  940. }
  941. CmpNextChar:;
  942. }
  943. Out: //当遇到单行注释时会直接跳到这儿
  944. //处理剩下的字符串
  945. if (nIdentBegin >= 0)
  946. {
  947. CString strtmp = strLine.Mid(nIdentBegin, I - nIdentBegin); 
  948. if (IsSynWord(strtmp))
  949. {
  950. DEFINE_BLOCK(nIdentBegin, COLORINDEX_SYNTAX);
  951. }
  952. else if (IsNumber(strtmp))
  953. {
  954. DEFINE_BLOCK(nIdentBegin, COLORINDEX_NUMBER);
  955. }
  956. }
  957. return dwCookie;
  958. }
  959. //判断给定的串是否是数字变量
  960. BOOL CSynEditView::IsNumber(CString &strReadyToTest)
  961. {
  962. int nLength = strReadyToTest.GetLength(); 
  963. {
  964. if (nLength > 2 && strReadyToTest[0] == _T('0') && 
  965. strReadyToTest[1] == _T('x'))
  966. {
  967. for (int I = 2; I < nLength; I++)
  968. {
  969. if (_istdigit(strReadyToTest[I])  ||(strReadyToTest[I] >= _T('A') && 
  970. strReadyToTest[I] <= _T('F')) ||(strReadyToTest[I] >= _T('a') && 
  971. strReadyToTest[I] <= _T('f')))
  972. continue;
  973. return FALSE;
  974. }
  975. return TRUE;
  976. }
  977. }
  978. if (!_istdigit(strReadyToTest[0]))
  979. return FALSE;
  980. for (int I = 1; I < nLength; I++)
  981. {
  982. if (!_istdigit(strReadyToTest[I]) && strReadyToTest[I] != _T('+') &&
  983. strReadyToTest[I] != _T('-')  && strReadyToTest[I] != _T('.') && 
  984. strReadyToTest[I] != _T('e')  && strReadyToTest[I] != _T('E'))
  985. return FALSE;
  986. }
  987. return TRUE;
  988. }
  989. void CSynEditView::SetSynEditViewMargin(int nLeftMargin, int nTopMargin)
  990. {
  991. m_nLeftMargin = nLeftMargin;
  992. m_nTopMargin = nTopMargin;
  993. GetClientRect(&m_rcClient);
  994. CRect rect(m_rcClient);
  995. rect.left = m_nLeftMargin;
  996. rect.top = m_nTopMargin;
  997. GetRichEditCtrl().SetRect(&rect); 
  998. }
  999. DWORD CALLBACK CSynEditView::EditStreamCallbackReadFromFile(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
  1000. {
  1001. CFile* pFile = (CFile*) dwCookie;
  1002. ASSERT_KINDOF(CFile, pFile);
  1003. *pcb = pFile->Read(pbBuff, cb);
  1004. return 0;
  1005. }