home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / opendc12.zip / od124os2.exe / od12osp1.exe / src / text / textmgr.cpp < prev    next >
Text File  |  1997-04-02  |  14KB  |  395 lines

  1. //====START_GENERATED_PROLOG======================================
  2. //
  3. //
  4. //   COMPONENT_NAME: odtextpart
  5. //
  6. //   CLASSES: none
  7. //
  8. //   ORIGINS: 82,27
  9. //
  10. //
  11. //   (C) COPYRIGHT International Business Machines Corp. 1995,1996
  12. //   All Rights Reserved
  13. //   Licensed Materials - Property of IBM
  14. //   US Government Users Restricted Rights - Use, duplication or
  15. //   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  16. //
  17. //   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  18. //   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  19. //   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  20. //   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  21. //   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  22. //   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
  23. //   OR PERFORMANCE OF THIS SOFTWARE.
  24. //
  25. //====END_GENERATED_PROLOG========================================
  26. //
  27. // @(#) 1.17 com/src/samples/text/textmgr.cpp, odtextpart, od96os2, odos29712d 2/21/97 13:41:07 [3/21/97 17:48:39]
  28. #include "textmgr.hpp"
  29. #include "iodtext.xh"
  30. #include "indxcoll.hpp"
  31.  
  32. #include <string.h>
  33. #include <ctype.h>
  34.  
  35. #ifdef _PLATFORM_WIN32_
  36. #define _UNICODE
  37. #include <tchar.h>
  38. #include <wchar.h>
  39. #endif
  40.  
  41. // TextMgr Constructor
  42. TextMgr::TextMgr(TextPart* parent)
  43. {
  44.    myEv = somGetGlobalEnvironment();
  45.    myParent = parent;
  46.    paragraphs = new IndexedCollection();
  47.  
  48.    SetNullPosition(currentPos);
  49.  
  50.    Paragraph* newPara = new Paragraph(0);
  51.    paragraphs->AddLast(1, (ElementType*)&newPara);
  52.    currentParagraph = newPara;
  53.    insertMode = 1;
  54.    maxParagraphLength = 0;
  55.    memset(&myFont, 0, sizeof(MYFONT));
  56. }
  57.  
  58. TextMgr::~TextMgr()
  59. {
  60.    // Delete each paragraph
  61.     for(int i = 0; i < paragraphs->Count(); i++)
  62.     {
  63.       Paragraph* para = (Paragraph*) paragraphs->FromIndex(i);
  64.       delete para;
  65.     }
  66.     delete paragraphs;
  67. }
  68.  
  69. void TextMgr::ToggleInsertMode()
  70. {
  71.    insertMode = insertMode ^ 1;
  72. #ifdef ODDebug
  73.    PRINT("insertMode is %d\n", insertMode);
  74. #endif
  75. }
  76.  
  77. int TextMgr::GetText(char** text)
  78. {
  79.    int   textSize = GetTextSize();
  80.    char* textPtr;
  81.    int   paraSize;
  82.  
  83.    // If we haven't input any text, return with a null buffer pointer.
  84.    if (textSize == 0) {
  85.       *text = kODNULL;
  86.    } else {
  87.       // Otherwise, allocate a buffer for the text
  88.       textPtr = new char[textSize+1];  // Add one for last (ignored) endLine.
  89.       *text = textPtr;
  90.  
  91.       // Iterate through each paragraph to read its text
  92.       for(int i = 0; i < paragraphs->Count(); i++)
  93.       {
  94.          Paragraph* para = (Paragraph*) paragraphs->FromIndex(i);
  95.          paraSize = para->GetTextSize(); // Set up to copy whole paragraph
  96.          para->CopyText(0, paraSize-1, textPtr);
  97.  
  98.          textPtr += paraSize;       // Advance pointer past the copied text
  99.          memcpy(textPtr++,"\n",1);  // Append endLine for each paragraph
  100.       } /* end for */
  101.    } /* end if */
  102.  
  103.    return textSize;
  104. }
  105.  
  106. // void TextMgr::DrawText(HDC hdc, ODRect clipRect)
  107. // See textplat.cpp for definition
  108.  
  109. // void TextMgr::SetFont(HDC hdc)
  110. // See textplat.cpp for definition
  111.  
  112. // void TextMgr::SetCursor(HWND hwnd, ODPoint cursor, ODRect cliprect)
  113. // See textplat.cpp for definition
  114.  
  115. int TextMgr::GetTextSize()
  116. {
  117.    // Initialize to number of paragraphs, to account for endLine characters.
  118.    int totalChars = paragraphs->Count();
  119.  
  120.    // Add text for each paragraph.
  121.    for (int i=0; i < paragraphs->Count(); i++)
  122.    {
  123.        Paragraph* para = (Paragraph*) paragraphs->FromIndex(i);
  124.        totalChars += para->GetTextSize();
  125.    }
  126.  
  127.    // Subtract one from the size to account for the currentParagraph.  For example,
  128.    // if the total is only one, this means we only have our default paragraph
  129.    // with no text, so we'll return 0.
  130.    return totalChars-1;
  131.  
  132. } // end GetTextSize
  133.  
  134. BOOL TextMgr::HasText()
  135. {
  136.    if (paragraphs->Count() > 1 || maxParagraphLength > 0)
  137.       return TRUE;
  138.    else
  139.       return FALSE;
  140. }
  141.  
  142. long TextMgr::GetTotalHeight()
  143. {
  144. #ifdef ODDebug
  145.    PRINT("paracount is %d, fontHeight is %d, total is %d\n",
  146.           paragraphs->Count(), myFont.height, paragraphs->Count()*myFont.height);
  147. #endif
  148.    return paragraphs->Count() * myFont.height;
  149. }
  150.  
  151. long TextMgr::GetMaximumWidth()
  152. {
  153.    return maxParagraphLength * myFont.width;
  154. }
  155.  
  156. void TextMgr::AddText(char* buffer, int bufferSize)
  157. {
  158.    int   j = 0;  // loop counter
  159.    int   i = 0;  // loop counter
  160.    int addChars = 0;  // Number of characters being added
  161.    int lastPara = paragraphs->Count() -1; // Index of last paragraph
  162.  
  163.    // Ignore this request if there is no text to add.
  164.    if (bufferSize == 0 || buffer == NULL)
  165.       return;
  166.  
  167.    // To avoid incorporating unprintable eof characters at the end of the buffer,
  168.    // decrement bufferSize down to the last carriage return.
  169.    for (j = bufferSize -1;
  170.         (j >= 0) && (!isprint(buffer[j])) && (buffer[j] != '\n') ;
  171.         j--)
  172.    {bufferSize--;}
  173.  
  174.    // Loop through the buffer characters, creating a paragraph each time an
  175.    // endLine or carriage return is encountered.
  176.    do {
  177.       for (j = i;
  178.            j < bufferSize && isprint(buffer[j]) ;
  179.            j++ )
  180.       {}
  181.       addChars = j - i;
  182.  
  183.       // If we have text without an endline or carriage return, insert
  184.       // it in front of the next paragraph.
  185.       if (j == bufferSize) {
  186.         currentPos.row++;
  187.         Paragraph* nextPara = (Paragraph*) paragraphs->Next(currentPos.row);
  188.  
  189.         // If we're at the end of the paragraph list, create a new one for
  190.         // the remaining text.
  191.         if (nextPara == NULL) {
  192.            nextPara = new Paragraph(0);
  193.            paragraphs->AddLast(1, (ElementType*)&nextPara);
  194.         }
  195.  
  196.         // Insert the text in front of the next paragraph.
  197.         currentParagraph = nextPara;
  198.         currentParagraph->InsertText(0, buffer+i, addChars);
  199.         maxParagraphLength = max(maxParagraphLength, currentParagraph->GetTextSize());
  200.  
  201.         // The current column is at the end of the text that was just input
  202.         currentPos.column = addChars;
  203.  
  204.         // This is our last time through the loop
  205.         i = bufferSize;
  206.       } else { // j != bufferSize
  207.          currentParagraph->AppendText(buffer+i, addChars);
  208.          maxParagraphLength = max(maxParagraphLength, currentParagraph->GetTextSize());
  209.  
  210.          // If we hit a new line or carriage return, start a new paragraph
  211.          currentPos.row++;
  212.          currentPos.column = 0;
  213.          Paragraph* newPara = new Paragraph(0);
  214.          paragraphs->AddBefore(currentPos.row, 1, (ElementType*)&newPara);
  215.          currentParagraph = newPara;
  216.  
  217.          // advance to the beginning of the next paragraph - ignore extra
  218.          // carriage returns and other unprintable characters
  219.          for (i = j;
  220.               (i < bufferSize) && (!isprint(buffer[i])) ;
  221.               i++ )
  222.             {
  223.               if (buffer[i] == '\n') {
  224.                  i++;
  225.                  break;
  226.               }
  227.             }
  228.       } /* endif */
  229.  
  230.    } while (i < bufferSize);  // end do loop
  231.  
  232. } // end AddText
  233.  
  234.  
  235. // ProcessKeyInput handles a keyboard event.  The message parameter
  236. // contains a key up, key down, or WM_CHAR event.  The keyEvent
  237. // parameter contains the virtual key code or the ASCII character
  238. // value of the input.
  239.  
  240. BOOL TextMgr::ProcessKeyInput(long &message, short keyEvent)
  241. {
  242.    BOOL result = TRUE;
  243.    int lastRow = paragraphs->Count() -1;
  244.    int lastCol = currentParagraph->GetTextSize();
  245.  
  246.    //>>> First, let's look for character input.
  247.    if (message == CHARACTER_KEY) {
  248.       switch(keyEvent) {
  249.  
  250.          case 0x0A:   // Linefeed
  251.             if (currentPos.row < lastRow) {
  252.                currentPos.row++;
  253.                currentPos.column = 0;
  254.                // Set the current paragraph to correspond to the current row.
  255.                currentParagraph = (Paragraph*) paragraphs->FromIndex(currentPos.row);
  256.             }
  257.             message = NO_CHANGE; // Communicate that no change occurred to text.
  258.             break;
  259.  
  260.          case 0x1B:   // Escape
  261.          case 0x09:   // Tab
  262.             message = NO_CHANGE; // Communicate that no change occurred to text.
  263.             result = FALSE;      // Let the parent handle these.
  264.             break;
  265.  
  266.          case 0x08:   // Backspace
  267.             // If we're at the beginning of the column, see if there's a previous row.
  268.             if (currentPos.column == 0) {
  269.                // If there is a previous row, just append text of the current paragraph to it.
  270.                if (currentPos.row > 0) {
  271.                   Paragraph* appendPara = (Paragraph*) paragraphs->RemoveFrom(currentPos.row);
  272.                   currentParagraph = (Paragraph*) paragraphs->FromIndex(--currentPos.row);
  273.                   currentPos.column = currentParagraph->GetTextSize();
  274.                   currentParagraph->Join(appendPara);  // Join will delete the paragraph.
  275.                   maxParagraphLength = max(maxParagraphLength, currentParagraph->GetTextSize());
  276.                   message = TEXT_CHANGED;  // Communicate that the text was changed.
  277.                } else {
  278.                   message = NO_CHANGE; // Communicate that no change occurred to text.
  279.                }
  280.             // Otherwise, move the caret back one space and delete the character.
  281.             } else {
  282.                currentPos.column--;
  283.                currentParagraph->DeleteText(currentPos.column,1);
  284.                message = TEXT_CHANGED;  // Communicate that the text was changed.
  285.             }
  286.             break;
  287.  
  288.          case 0x0D:   // Carriage Return
  289.             Paragraph* nextPara;
  290.  
  291.             if (currentPos.column == currentParagraph->GetTextSize()) {
  292.               nextPara = new Paragraph(0); // We're past the end of the text- start a new paragraph
  293.             } else { // Else we're in the middle of a paragraph, so split the text.
  294.                nextPara = currentParagraph->Split(currentPos.column);
  295.             }
  296.             paragraphs->AddBefore(++currentPos.row, 1, (ElementType*)&nextPara);
  297.             currentPos.column = 0;  // Go to beginning of new line
  298.             currentParagraph = nextPara;
  299.             message = TEXT_CHANGED;  // Communicate that the text was changed.
  300.             break;
  301.  
  302.          default:     // Must be a displayable character.
  303.             char newChar = keyEvent;
  304.             // If we're at the end of the paragraph or we're in insertMode, use InsertText.
  305.             // Otherwise, use ReplaceText.
  306.             if (insertMode || (currentPos.column == currentParagraph->GetTextSize()))  {
  307.               currentParagraph->InsertText(currentPos.column++, &newChar, 1);
  308.               maxParagraphLength = max(maxParagraphLength, currentParagraph->GetTextSize());
  309.             } else {
  310.               currentParagraph->ReplaceText(currentPos.column, currentPos.column, &newChar, 1);
  311.               currentPos.column++; // Can't use ++ in ReplaceText call since the incremented
  312.                                    // currentPos.column parm could be processed first before
  313.                                    // the unincremented?!
  314.             }
  315.             message = TEXT_CHANGED;  // Communicate that the text was changed.
  316.       } /* end switch */
  317.  
  318.    //>>> If not character input, check for accelerator keys
  319.    } else if (message == ACCEL_KEY) {
  320.       switch(keyEvent) {
  321.       case kODCommandDelete:         // Delete text.
  322.          // If we're at the end of the row, see if there's a row following.
  323.          if (currentPos.column == currentParagraph->GetTextSize()) {
  324.             // If there is a row following, just append its text to the current paragraph.
  325.             if (currentPos.row != paragraphs->Count() -1) {
  326.               Paragraph* nextPara = (Paragraph*) paragraphs->RemoveFrom(currentPos.row+1);
  327.               currentParagraph->Join(nextPara);
  328.               message = TEXT_CHANGED;  // Communicate that the text was changed.
  329.             } else {
  330.               message = NO_CHANGE; // Communicate that no change occurred to text.
  331.             }
  332.          } else {
  333.             currentParagraph->DeleteText(currentPos.column,1);
  334.             message = TEXT_CHANGED;  // Communicate that the text was changed.
  335.          }
  336.          break;
  337.  
  338.       default:
  339.          message = NO_CHANGE; // Communicate that no change occurred to text.
  340.          result = FALSE;      // Let our parent handle this.
  341.       } /* end switch */
  342.  
  343.    //>>> Virtual key must have been generated.  Look for keys that affect
  344.    //    the cursor position.
  345.    } else {
  346.       switch(keyEvent) {
  347.       case VK_UP:
  348.          if (currentPos.row > 0) {
  349.             currentPos.row--;
  350.             // Set the current paragraph to correspond to the current row.
  351.             currentParagraph = (Paragraph*) paragraphs->FromIndex(currentPos.row);
  352.          }
  353.          break;
  354.       case VK_DOWN:
  355.          if (currentPos.row < lastRow) {
  356.             currentPos.row++;
  357.          // Set the current paragraph to correspond to the current row.
  358.          currentParagraph = (Paragraph*) paragraphs->FromIndex(currentPos.row);
  359.          }
  360.          break;
  361.       case VK_LEFT:
  362.          if (currentPos.column > 0)
  363.             currentPos.column--;
  364.          break;
  365.       case VK_RIGHT:
  366.          if (currentPos.column < lastCol)
  367.             currentPos.column++;
  368.          break;
  369.       case VK_HOME:
  370.          currentPos.column = 0;
  371.          break;
  372.       case VK_END:
  373.          currentPos.column = lastCol;
  374.          break;
  375.       default:            /* all other characters */
  376.          result = FALSE;  // Let our parent handle these
  377.          break;
  378.       } /* endswitch */
  379.  
  380.       message = NO_CHANGE; // Communicate that no change occurred to text.
  381.    } /* end keydown event */
  382.  
  383.    return result;
  384. } // end ProcessKeyInput
  385.  
  386. Paragraph* TextMgr::GetParagraphFrom(POSITION pos)
  387. {
  388.    return (Paragraph*) paragraphs->FromIndex(pos.row);
  389. }
  390.  
  391. Paragraph* TextMgr::GetLastParagraph()
  392. {
  393.    return (Paragraph*) paragraphs->Last();
  394. }
  395.