home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic 4 Unleashed / Visual_Basic_4_Unleashed_SAMS_Publishing_1995.iso / tedevkit / ter_mfc.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-05  |  14.0 KB  |  505 lines

  1. // ter_mfc.cpp : implementation file
  2. //
  3.  
  4. #include "stdafx.h"
  5.  
  6. #include "ter_mfc.h"
  7.  
  8. #ifdef _DEBUG
  9. #undef THIS_FILE
  10. static char BASED_CODE THIS_FILE[] = __FILE__;
  11. #endif
  12.  
  13. /////////////////////////////////////////////////////////////////////////////
  14. // CTer
  15.  
  16. IMPLEMENT_DYNAMIC(CTer, CWnd)
  17.  
  18. BEGIN_MESSAGE_MAP(CTer, CWnd)
  19.         //{{AFX_MSG_MAP(CTer)
  20.                 // NOTE - the ClassWizard will add and remove mapping macros here.
  21.         //}}AFX_MSG_MAP
  22.  
  23. END_MESSAGE_MAP()
  24.  
  25. /////////////////////////////////////////////////////////////////////////////
  26. // Contruction 
  27.  
  28. CTer::CTer()
  29. {
  30.     // Variable initialization
  31.     m_hBuffer=0;
  32.     m_BufLen=0;
  33. }
  34.  
  35. CTer::~CTer()
  36. {
  37.     DestroyWindow();
  38. }
  39.  
  40. BOOL CTer::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
  41. {
  42.     LoadTerControl();
  43.  
  44.     return CWnd::Create(TER_CLASS, "", dwStyle ? dwStyle : DefaultEditStyles(), rect, pParentWnd, nID);
  45. }
  46.  
  47. // Specify address where mfc should store the address for the window process
  48. WNDPROC* CTer::GetSuperWndProcAddr()
  49. {
  50.     static WNDPROC NEAR pfnSuper;
  51.     return &pfnSuper;
  52. }
  53.  
  54. // Call TER menu option
  55. void CTer::TerMenu(WPARAM MenuOption)
  56. {
  57.     if (MenuEnable(MenuOption)) TerWindowProc(WM_COMMAND,MenuOption,0L);
  58. }
  59.  
  60. // Call TER window process
  61. LRESULT CTer::TerWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
  62. {
  63.     WNDPROC pfnWndProc = *GetSuperWndProcAddr();
  64.     #ifdef STRICT
  65.         return ::CallWindowProc(pfnWndProc, m_hWnd, nMsg, wParam, lParam);
  66.     #else
  67.         return ::CallWindowProc((FARPROC)pfnWndProc, m_hWnd, nMsg, wParam, lParam);
  68.     #endif
  69. }
  70.  
  71. // Return edit styles to be used with the window
  72. DWORD CTer::DefaultEditStyles()
  73. {
  74.     return WS_CHILD|WS_VISIBLE|WS_BORDER|TER_WORD_WRAP|TER_VSCROLL|TER_BORDER_MARGIN|TER_SHOW_TOOLBAR;  // control style
  75. }
  76.  
  77. /////////////////////////////////////////////////////////////////////////////
  78. // File io functions
  79. void CTer::DeleteContents()
  80. {
  81.     HGLOBAL hMem;
  82.     LPSTR pMem;
  83.  
  84.     ASSERT_VALID(this);
  85.     ASSERT(m_hWnd!=NULL);
  86.  
  87.     // allocate an empty buffer
  88.     hMem=::GlobalAlloc(GMEM_MOVEABLE,1);
  89.     pMem=(LPSTR)::GlobalLock(hMem);
  90.     pMem[0]=0xD;                         // line delimiter
  91.     ::GlobalUnlock(hMem);
  92.     
  93.     SetHandle(hMem,1,NULL,TRUE);
  94.  
  95.     ASSERT_VALID(this);
  96. }
  97.  
  98. DWORD CTer::GetBuffer()
  99.         // Retrieve the text buffer from the control
  100. {
  101.     if (m_hBuffer) ::GlobalFree(m_hBuffer);
  102.  
  103.     m_hBuffer=GetHandle((long far *)&m_BufLen);
  104.     return m_BufLen;
  105. }
  106.  
  107. // Read and write CTer object to archive, with a 4 byte length prefix.
  108. void CTer::Serialize(CArchive& ar)
  109. {
  110.     ASSERT_VALID(this);
  111.     ASSERT(m_hWnd != NULL);
  112.  
  113.     if (ar.IsStoring()) {        // Save data
  114.         DWORD nLen = GetBuffer();
  115.         ar << nLen;              // write length
  116.         WriteArchive(ar);
  117.     }
  118.     else {                       // load data
  119.         DWORD dwLen;
  120.         ar >> dwLen;             // read length
  121.         ReadArchive(ar, dwLen);
  122.     }
  123.     ASSERT_VALID(this);
  124. }
  125.  
  126. // Read certain amount of text from the file, assume at least nLen
  127. // bytes are in the file.
  128. void CTer::ReadArchive(CArchive& ar, DWORD nLen)
  129. {
  130.     ASSERT_VALID(this);
  131.     
  132.     HGLOBAL hBuf=::GlobalAlloc(GMEM_MOVEABLE, nLen+1);
  133.     char huge * pMem=(char huge *)GlobalLock(hBuf);
  134.  
  135.     if (pMem == NULL) {
  136.         AfxThrowMemoryException();
  137.         ASSERT(FALSE);
  138.     }
  139.     
  140.     // read the buffer
  141.     DWORD BlockSize=0x4000;       // 16 blocks
  142.     DWORD BytesDone=0;            // bytes written so far
  143.  
  144.     while (BytesDone<nLen) {
  145.        if ((BytesDone+BlockSize)>nLen) BlockSize=nLen-BytesDone;
  146.  
  147.        if (ar.Read(&(pMem[BytesDone]),(UINT)BlockSize)!=(UINT)BlockSize) {
  148.           ::GlobalUnlock(hBuf);
  149.           AfxThrowArchiveException(CArchiveException::endOfFile);
  150.           ASSERT(FALSE);
  151.        }
  152.        BytesDone+=BlockSize;
  153.     }
  154.     
  155.     // pass the handle to the control
  156.     pMem[nLen]=0;
  157.     ::GlobalUnlock(hBuf);
  158.     SetHandle(hBuf,nLen,"",TRUE);  // control now owns the handle
  159.  
  160.     ASSERT_VALID(this);
  161. }
  162.  
  163. // Write just the text to an archive, no length prefix.
  164. void CTer::WriteArchive(CArchive& ar)
  165. {
  166.     ASSERT_VALID(this);
  167.     ASSERT(m_hBuffer!=NULL);
  168.  
  169.     char huge *pMem = (char huge *)::GlobalLock(m_hBuffer);
  170.  
  171.     ASSERT(pMem != NULL);
  172.  
  173.     // direct write for a huge buffer
  174.     TRY
  175.     {
  176.        DWORD BlockSize=0x4000;       // 16 blocks
  177.        DWORD BytesDone=0;            // bytes written so far
  178.  
  179.        while (BytesDone<m_BufLen) {
  180.           if ((BytesDone+BlockSize)>m_BufLen) BlockSize=m_BufLen-BytesDone;
  181.           ar.Write(&(pMem[BytesDone]),(UINT)BlockSize);
  182.           BytesDone+=BlockSize;
  183.        }
  184.     }
  185.     CATCH_ALL(e)
  186.     {
  187.         ::GlobalUnlock(m_hBuffer);
  188.         THROW_LAST();
  189.         ASSERT(FALSE);
  190.     }
  191.     END_CATCH_ALL
  192.     
  193.     // release our buffer
  194.     ::GlobalUnlock(m_hBuffer);
  195.     ::GlobalFree(m_hBuffer);
  196.     m_hBuffer=0;
  197.     m_BufLen=0;
  198.     
  199.     // mark the window as updated
  200.     SetModify(FALSE);
  201.  
  202.     ASSERT_VALID(this);
  203. }
  204.  
  205. void CTer::SerializeRaw(CArchive& ar)
  206.     // Read/Write object as stand-alone file.
  207. {
  208.     ASSERT_VALID(this);
  209.     if (ar.IsStoring())  {   // save data
  210.         GetBuffer();         // retrieve data from control
  211.         WriteArchive(ar);
  212.     }
  213.     else {                   // load file
  214.         CFile *pFile = ar.GetFile();
  215.         ASSERT(pFile->GetPosition() == 0);
  216.         DWORD nFileSize = pFile->GetLength();
  217.         ReadArchive(ar,nFileSize);
  218.     }
  219.     ASSERT_VALID(this);
  220. }
  221.  
  222. ///////////////////////////////////////////////////////////////////////////
  223. // Menu Commands
  224. // These functions simply invoke the given menu option
  225. //////////////////////////////////////////////////////////////////////////
  226. // Check if a menu item should be enabled
  227. BOOL CTer::MenuEnable(int MenuItem)
  228. {
  229.     if (m_hWnd && MF_ENABLED==::TerMenuEnable(m_hWnd,MenuItem)) return TRUE;
  230.     else                                                        return FALSE;
  231.  
  232. }
  233.  
  234. // Check if a menu item should be selected
  235. int CTer::MenuSelect(int MenuItem)
  236. {
  237.     if (m_hWnd && MF_CHECKED==::TerMenuSelect(m_hWnd,MenuItem)) return 1;
  238.     else                                                        return 0;
  239. }
  240.  
  241.  
  242. /////////////////////////////////////////////////////////////////////////////
  243. // CTer API functions
  244.  
  245. // Get the handle to the control data
  246. HGLOBAL CTer::GetHandle(long far *BufferLen) {return GetTerBuffer(m_hWnd,BufferLen);}
  247.  
  248. // Set new text to the control 
  249. BOOL CTer::SetHandle(HGLOBAL hBuffer, long BufferLen, LPSTR title, BOOL release) {
  250.    BOOL result;
  251.    TerEnableRefresh(m_hWnd,FALSE);  // suppress painting by SetTerBuffer function
  252.    result = SetTerBuffer(m_hWnd,hBuffer,BufferLen, (LPBYTE)title, release);
  253.    TerEnableRefresh(m_hWnd,TRUE);  // resume painting
  254.    return result;
  255. }
  256.  
  257. void CTer::Cut()     {TerMenu(ID_CUT);}
  258. void CTer::Copy()    {TerMenu(ID_COPY);}
  259. void CTer::Paste()   {TerMenu(ID_PASTE);}
  260. BOOL CTer::CanUndo() {return MenuEnable(ID_UNDO);}
  261. BOOL CTer::Undo()    {TerMenu(ID_UNDO);return TRUE;}
  262.  
  263. // get the beginning and ending position of a highlighted block.
  264. // EndPos points to the character immediately after the block
  265. void CTer::GetSel(long &StartPos,long &EndPos)
  266. {   
  267.     StrTerField field;
  268.  
  269.     StartPos=EndPos=0;
  270.     ::GetTerFields(m_hWnd,&field);
  271.  
  272.     if (field.HilightTypeW!=HILIGHT_OFF) {
  273.        if (field.HilightTypeW==HILIGHT_LINE) {
  274.           field.HilightBegColW=0;
  275.           field.HilightEndColW=field.LineLenW;   // entire line highlighted
  276.        }
  277.        StartPos=TerRowColToAbs(m_hWnd,field.HilightBegRowW,field.HilightBegColW);
  278.        EndPos=TerRowColToAbs(m_hWnd,field.HilightEndRowW,field.HilightEndColW);
  279.  
  280.        if (StartPos>EndPos) {                    // swap the values
  281.            long temp=StartPos;
  282.            StartPos=EndPos;
  283.            EndPos=temp;
  284.        }
  285.     }
  286. }
  287.  
  288. // Delete any highlighted block
  289. void CTer::Clear()
  290. {
  291.     long StartPos,EndPos;
  292.  
  293.     GetSel(StartPos,EndPos);
  294.  
  295.     if (EndPos>0) TerMenu(ID_DEL);    // send the DEL key message
  296. }
  297.  
  298. // Check if text modified
  299. BOOL CTer::GetModify()
  300. {
  301.     StrTerField field;
  302.  
  303.     ::GetTerFields(m_hWnd,&field);
  304.  
  305.     return field.modified;
  306. }
  307.  
  308. // set or reset modification status
  309. void CTer::SetModify(BOOL bModified) {::TerSetModify(m_hWnd,bModified);}
  310.  
  311. // Get total number of lines the in the document
  312. long CTer::GetLineCount()
  313. {
  314.     StrTerField field;
  315.  
  316.     ::GetTerFields(m_hWnd,&field);
  317.  
  318.     return field.TotalLinesW;
  319. }
  320.  
  321. // retrieve the character index of the line.  Set nLine to -1 to specify 
  322. // the current line.  The nLine is zero based parameter.
  323. long CTer::LineIndex(long nLine)
  324. {
  325.     if (nLine<0) {            // get the current line
  326.        StrTerField field;
  327.        ::GetTerFields(m_hWnd,&field);
  328.        nLine=field.CurLineW;
  329.     }
  330.  
  331.     return ::TerRowColToAbs(m_hWnd,nLine,0);
  332. }
  333.  
  334. // set or reset modification status
  335. BOOL CTer::SetReadOnly(BOOL bReadOnly) {return ::TerSetReadOnly(m_hWnd,bReadOnly);}
  336.  
  337. // Retrieve the specified line.
  338. int CTer:: GetLine(long index, LPSTR buffer)
  339. {
  340.    WORD MaxLength;
  341.  
  342.    MaxLength=*((LPWORD)buffer);  // retrive max bytes to copy
  343.    return GetLine(index,buffer,(int)MaxLength);
  344. }
  345.  
  346. int CTer::GetLine(long index, LPSTR buffer, int MaxLength)
  347. {
  348.    char string[301];
  349.    int  LineLen,i;
  350.  
  351.    *((LPWORD)buffer)=(WORD)MaxLength; // store maximum number of bytes to copy
  352.  
  353.    if ((LineLen=::GetTerLine(m_hWnd,index,(LPBYTE)string,NULL))<=0) return 0;
  354.  
  355.    if (LineLen>MaxLength) LineLen=MaxLength;
  356.  
  357.    for (i=0;i<LineLen;i++) buffer[2+i]=string[i];  // first  word reserved for line length
  358.  
  359.    return LineLen;
  360. }
  361.  
  362. // get the line index of the first line on the screen
  363. long  CTer::GetFirstVisibleLine()
  364. {
  365.     StrTerField field;
  366.  
  367.     ::GetTerFields(m_hWnd,&field);
  368.  
  369.     return field.BeginLineW;
  370. }
  371.  
  372. // get the line number (0 based) from the character index (0 based).
  373. // when nIndex is -1, the number of the line that contains the first character
  374. // of the selection is returned.  If there is no selection, the current line
  375. // number is returned.
  376. long  CTer::LineFromChar(long nIndex)
  377. {
  378.     long line;
  379.     int  col;
  380.     
  381.     if (nIndex<0) {
  382.        StrTerField field;
  383.        ::GetTerFields(m_hWnd,&field);
  384.  
  385.        if (field.HilightTypeW!=HILIGHT_OFF) return field.HilightBegRowW;
  386.        else                                 return field.CurLineW;
  387.     }
  388.  
  389.     TerAbsToRowCol(m_hWnd,nIndex,&line,&col);
  390.  
  391.     return line;
  392. }
  393.  
  394. // Get the length of the line which contains a character at an index
  395. // equal to nLine. if nLine is -1, the function returns total number of 
  396. // unselected lines in the first and last highlighted line.
  397. int   CTer::LineLength(long nLine) 
  398. {
  399.     if (nLine>=0) return ::GetTerLine(m_hWnd,nLine, NULL,NULL); // get the length of the specified line
  400.  
  401.     // test if a block highlighted
  402.     StrTerField field;
  403.     ::GetTerFields(m_hWnd,&field);
  404.  
  405.     if (field.HilightTypeW==HILIGHT_OFF) return field.LineLenW;  // return the length of the current line
  406.  
  407.     // count the un-highlighted characters in the first and last line
  408.     if (field.HilightTypeW==HILIGHT_LINE) return 0;              // entire lines highlighted
  409.  
  410.     int EndLineLen=::GetTerLine(m_hWnd,field.HilightEndRowW,NULL,NULL);
  411.  
  412.     return field.HilightBegColW+EndLineLen-field.HilightEndColW;
  413.  
  414. }
  415.  
  416. // Scroll specified number of lines in the vertical or horizontal direction
  417. void CTer::LineScroll(long nLines, int nChars)
  418. {
  419.     StrTerField field;
  420.     int i;
  421.     WORD wParam;
  422.  
  423.     // disable painting
  424.     ::GetTerFields(m_hWnd,&field);
  425.     field.PaintEnabledW=FALSE;
  426.     ::SetTerFields(m_hWnd,&field);
  427.  
  428.     // scroll vertically
  429.     if (nLines) {
  430.        wParam=SB_LINEDOWN;       // send line down message
  431.        if (nLines<0) {
  432.           wParam=SB_LINEUP;
  433.           nLines=-nLines;
  434.        }
  435.        for (i=0;i<nLines;i++) TerWindowProc(WM_VSCROLL,wParam,0L);
  436.     }
  437.  
  438.     if (nChars) {
  439.        wParam=SB_LINEDOWN;       // send line down message
  440.        if (nChars<0) {
  441.           wParam=SB_LINEUP;
  442.           nChars=-nChars;
  443.        }
  444.        for (i=0;i<nChars;i++) TerWindowProc(WM_HSCROLL,wParam,0L);
  445.     }
  446.  
  447.     // enable painting
  448.     ::GetTerFields(m_hWnd,&field);
  449.     field.PaintEnabledW=TRUE;
  450.     ::SetTerFields(m_hWnd,&field);
  451. }
  452.  
  453. // Replace the exiting highlighted text by the specified text.  If a block
  454. // is not highlighted, the new text is inserted at the current cursor location.
  455. void CTer::ReplaceSel(char huge *NewText)
  456. {
  457.     StrTerField field;
  458.  
  459.     // Delete the exiting text
  460.     ::GetTerFields(m_hWnd,&field);
  461.     if (field.HilightTypeW!=HILIGHT_OFF) {
  462.        TerMenu(ID_DEL);       // send the DEL key message
  463.        ::SetTerCursorPos(m_hWnd,field.HilightBegRowW, field.HilightBegColW, FALSE);
  464.     }
  465.      
  466.     InsertTerText(m_hWnd,(LPBYTE)NewText,TRUE);
  467.  
  468. }
  469.  
  470. // Highlight a block of text.  if nStartChar is 0 and nEndChar is -1,
  471. // the entire text is highlighted.  If nStartChar is -1, any current
  472. // highlighting is turned off.
  473.  
  474. void CTer::SetSel(long nStartChar, long nEndChar, BOOL bNoScroll)
  475. {
  476.    if (nStartChar==-1) {                // remove any highlighting
  477.       ::DeselectTerText(m_hWnd,TRUE);
  478.       return;
  479.    }
  480.  
  481.    if (nStartChar==0 && nEndChar==-1) { // select the entire text
  482.        StrTerField field;
  483.        ::GetTerFields(m_hWnd,&field);
  484.        int len=::GetTerLine(m_hWnd,field.TotalLinesW-1,NULL,NULL); // length of the last line
  485.        ::SelectTerText(m_hWnd,0,0,field.TotalLinesW-1,len,bNoScroll);
  486.  
  487.        if (!bNoScroll) {                // set the cursor at the end of the block
  488.           int LineLen=::GetTerLine(m_hWnd,field.TotalLinesW-1,NULL,NULL);
  489.           if (field.WordWrapW && LineLen>0) LineLen--;
  490.           ::SetTerCursorPos(m_hWnd,field.TotalLinesW-1, LineLen, TRUE);
  491.        }
  492.        return;
  493.    }
  494.  
  495.    // select the specified line
  496.    ::SelectTerText(m_hWnd,nStartChar,-1,nEndChar+1,-1,bNoScroll);
  497.    if (!bNoScroll) {   // set the cursor at the end of the block
  498.       long line;
  499.       int  col;
  500.       TerAbsToRowCol(m_hWnd,nEndChar+1,&line,&col);
  501.       ::SetTerCursorPos(m_hWnd,line, col, TRUE);
  502.    }
  503.  
  504. }
  505.