home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / un2maiq4 / pjjava / src / pj / awt / textbox.java < prev    next >
Encoding:
Java Source  |  1996-08-14  |  23.0 KB  |  765 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.     @(#)TextBox.java  0.00 28-Dec-95
  4.  
  5.         A prototype of a scrolling, word-wrapping text area.
  6.  
  7.     Authors:
  8.  
  9.         jlee     James Lee
  10.  
  11.     Version Ident:
  12.  
  13.         $Header$
  14.  
  15.     History:
  16.  
  17.         0.00 5-Mar-96  jlee   Initial Creation
  18.             26-Mar-96  jlee   Got rid of panel used 3d border, instead used line drawing
  19.                               and fixed some scrolling problem.
  20.             29-Mar-96  jlee   Optimized LineTextBox a little bit.
  21. ---------------------------------------------------------------------------*/
  22.  
  23. package pj.awt;
  24.  
  25. import pj.awt.Panel3D;
  26. import pj.awt.PjFinals;
  27.  
  28. import java.awt.BorderLayout;
  29. import java.awt.Color;
  30. import java.awt.Container;
  31. import java.awt.Dimension;
  32. import java.awt.Event;
  33. import java.awt.Font;
  34. import java.awt.FontMetrics;
  35. import java.awt.Graphics;
  36. import java.awt.Image;
  37. import java.awt.Panel;
  38. import java.awt.Scrollbar;
  39. import java.lang.String;
  40. import java.lang.Thread;
  41.  
  42. import java.util.NoSuchElementException;
  43. import java.util.StringTokenizer;
  44. import java.util.Vector;
  45.  
  46. public class TextBox extends Panel3D
  47.     {
  48.  
  49.  
  50.     // --- Instance variables
  51.     private protected   Vector          m_vTextArray    = null; //growable array for the text contents
  52.     private protected   Font            m_fntTextPlain  = null;
  53.     private protected   Font            m_fntTextBold   = null;
  54.     private protected   FontMetrics     m_fmTextPlain   = null;
  55.     private protected   FontMetrics     m_fmTextBold    = null;
  56.  
  57.  
  58.     private Panel       m_pnlText       = null;                 //text area panel
  59.     private Scrollbar   m_sbText        = null;
  60.  
  61.     private int         m_nPagesize       = 10;                 //scroll page size
  62.     private int         m_sbTextCurValue  = 0;
  63.     private int         m_sbTextPrevValue = 0;
  64.     private int         m_nLineHeight     = 0;                  //text line height
  65.     private int         m_nLeftOffset     = PjFinals.nTextBoxHorInset;
  66.     private int         m_nLastMax        = 0;
  67.  
  68.     private Dimension   m_dimPanelText          = null;         //size of m_pnlText
  69.     private Dimension   m_dimPanelTextPrevDim   = null;         //previous size of m_pnltext
  70.  
  71.     private Graphics    m_grPanelText           = null;         //graphics context for the offscreen image
  72.     private Color       m_colorBackgroundColor  = null;
  73.  
  74.  
  75.     // --- Public constructors
  76.  
  77.     public TextBox()
  78.     {
  79.     init();
  80.     }
  81.  
  82.     public TextBox( int nBorderSize )
  83.         {
  84.         super( nBorderSize );
  85.         init();
  86.         if (nBorderSize == 0)
  87.             m_colorBackgroundColor = Color.lightGray;
  88.         }
  89.  
  90.  
  91.     // --- Public operations
  92.  
  93.     private void init()
  94.         {
  95.         m_pnlText = new Panel();
  96.  
  97.         m_pnlText.setLayout( new BorderLayout() );
  98.         m_sbText = new Scrollbar( Scrollbar.VERTICAL );
  99.  
  100.         m_sbText.resize( PjFinals.nScrollbarWidth, 10 );
  101.         m_sbText.setBackground( Color.lightGray );
  102.  
  103.         m_pnlText.add( "East", m_sbText );
  104.         m_sbText.hide();
  105.  
  106.         m_dimPanelText = m_pnlText.size();
  107.         m_dimPanelTextPrevDim = new Dimension( -1, -1 );
  108.  
  109.         add( m_pnlText );
  110.  
  111.         m_vTextArray = new Vector();
  112.         m_colorBackgroundColor = Color.white;
  113.         }
  114.  
  115.     public void setBackColor( Color c )
  116.         {
  117.         m_colorBackgroundColor = c;
  118.         repaint();
  119.         }
  120.  
  121.     public void paint( Graphics gParent )
  122.         {
  123.         int nSize = 0;
  124.  
  125.         super.paint( gParent );
  126.  
  127.         if ( m_pnlText != null && m_sbText != null )
  128.             {
  129.             // set line height and pagesize
  130.             if ( null == m_grPanelText )
  131.                 m_grPanelText = m_pnlText.getGraphics();
  132.  
  133.             FontMetrics fmText = m_grPanelText.getFontMetrics();
  134.             m_nLineHeight = fmText.getHeight() * 82 / 80;
  135.  
  136.             if ( m_nLineHeight > 0 )
  137.                 m_nPagesize = m_pnlText.size().height / m_nLineHeight;
  138.  
  139.             nSize = m_vTextArray.size();
  140.  
  141.             // resize the scrollbar
  142.             if ( nSize > m_nPagesize )
  143.                 {
  144.                 m_sbText.reshape( m_pnlText.size().width - PjFinals.nScrollbarWidth, 0,
  145.                                   PjFinals.nScrollbarWidth, m_pnlText.size().height );
  146.                 m_sbText.show();
  147.                 }
  148.             else
  149.                 m_sbText.hide();
  150.  
  151.             if ( nSize > 0 )
  152.                 drawScrollString( m_sbText.getValue(), 0, nSize );
  153.             }
  154.         else
  155.             return;
  156.         }
  157.  
  158.     private int resolveSbMaxValue( int nSbValue, int min, int max )
  159.         {
  160.         if ( (m_nLastMax != max) && (m_nLastMax != 0) && (max != 0) )
  161.             nSbValue = nSbValue * max / m_nLastMax;
  162.  
  163.         m_nLastMax = max;
  164.  
  165.         if ( nSbValue + m_nPagesize > max )
  166.             {
  167.             int v = 0;
  168.             v = max - m_nPagesize;
  169.             if ( v < min)
  170.                 v = min;
  171.             return v;
  172.             }
  173.         return nSbValue;
  174.         }
  175.  
  176.     public boolean handleEvent(Event evt)
  177.         {
  178.         int v, max;
  179.  
  180.         switch (evt.id)
  181.             {
  182.             case Event.SCROLL_LINE_UP:
  183.                 break;
  184.             case Event.SCROLL_LINE_DOWN:
  185.                 break;
  186.             case Event.SCROLL_PAGE_UP:
  187.                 v = m_sbTextCurValue - m_nPagesize;
  188.                 if ( v < 0)
  189.                     v = 0;
  190.                 m_sbText.setValue( v );
  191.                 break;
  192.             case Event.SCROLL_PAGE_DOWN:
  193.                 max = m_sbText.getMaximum() - m_nPagesize;
  194.                 v = m_sbTextCurValue + m_nPagesize;
  195.                 if ( v > max )
  196.                     v = max;
  197.                 m_sbText.setValue( v );
  198.                 break;
  199.             case Event.SCROLL_ABSOLUTE:
  200.                 break;
  201.             default:
  202.                 return false;
  203.             }   // switch
  204.  
  205.         repaint();
  206.         return true;
  207.         }// handleEvent
  208.  
  209.     protected void finalize() throws Throwable
  210.         {
  211.         if ( null != m_grPanelText )
  212.             m_grPanelText.finalize();
  213.         }
  214.  
  215.     public synchronized void setFont( Font f )
  216.         {
  217.         if ( f != null )
  218.             {
  219.             m_fntTextPlain = f;
  220.             m_fmTextPlain = getFontMetrics( f );
  221.  
  222.             m_fntTextBold = new Font( f.getName(), Font.BOLD, f.getSize() );
  223.             m_fmTextBold = getFontMetrics( m_fntTextBold );
  224.             repaint();
  225.             }
  226.         }
  227.  
  228.     private void drawScrollString( int val, int min, int max )
  229.         {
  230.         boolean bFontChanged = false;
  231.         String  str;
  232.         int     nLeftMargin = 0;
  233.  
  234.         val = resolveSbMaxValue(val, min, max);
  235.  
  236.         m_dimPanelText = m_pnlText.size();
  237.         m_grPanelText.setFont( m_fntTextPlain );
  238.         m_sbTextCurValue = val;
  239.  
  240.         // reset the scroll bar
  241.         m_sbText.setValues( val, m_nPagesize, min, max );
  242.         m_sbText.setPageIncrement( m_nPagesize );//dosen't seem to work.
  243.  
  244.         // fill area with Color.white
  245.         m_grPanelText.setColor( m_colorBackgroundColor );
  246.         m_grPanelText.fillRect( 0, 0, m_dimPanelText.width, m_dimPanelText.height );
  247.  
  248.         // setting black color for the font
  249.         m_grPanelText.setColor( Color.black );
  250.  
  251.         // draw the actual string
  252.         for ( int i = val; i < val + m_nPagesize; i++ )
  253.             {
  254.             if ( i >= max )
  255.                 break;
  256.  
  257.             str = (String)m_vTextArray.elementAt( i );
  258.  
  259.             if ( str.length() > 0 )
  260.                 {
  261.                 if ( '\\' == str.charAt(0) )
  262.                     {
  263.                     switch ( str.charAt(1) )
  264.                         {
  265.                         case 'b':
  266.                             str = str.substring( 2 );
  267.                             m_grPanelText.setFont( m_fntTextBold );
  268.                             bFontChanged = true;
  269.                             break;
  270.                         case 'q':
  271.                             switch ( str.charAt(2) )
  272.                                 {
  273.                                 case 'l':
  274.                                 case 'r':
  275.                                 case 'c':
  276.                                     str = str.substring( 3 ).trim().replace( '-', '*' );
  277.                                     int nOffset = m_sbText.isVisible() ? PjFinals.nScrollbarWidth: 0;
  278.                                     nLeftMargin = ( m_dimPanelText.width - nOffset -
  279.                                                     m_fmTextPlain.stringWidth( str )
  280.                                                    ) / 2;
  281.                                     break;
  282.                                 case 'j':
  283.                                 default:
  284.                                     break;
  285.                                 }
  286.                             break;
  287.                         default:
  288.                             break;
  289.                         }//switch
  290.                     }//if
  291.  
  292.                 m_grPanelText.drawString( str, m_nLeftOffset + nLeftMargin, (i + 1 - val) * m_nLineHeight );
  293.  
  294.                 nLeftMargin = 0;
  295.  
  296.                 if ( bFontChanged )
  297.                     {
  298.                     m_grPanelText.setFont( m_fntTextPlain );
  299.                     bFontChanged = false;
  300.                     }
  301.                 }//if ( str.length() > 0 )
  302.             }//for ( int i = val; i < val + m_nPagesize; i++ )
  303.         }//drawScrollString
  304.     }//TextBox
  305.  
  306. /*---------------------------------------------------------------------------
  307.  
  308.     @(#)LineTextBox.java  0.00 28-Dec-95
  309.  
  310.         A prototype of a scrolling, word-wrapping text area.
  311.         Originally written by Rick Hall and released into the public domain.
  312.  
  313.     Authors:
  314.  
  315.         rphall   Rick Hall
  316.         jlee     James Lee
  317.  
  318.     Version Ident:
  319.  
  320.         $Header$
  321.  
  322.     History:
  323.  
  324.         0.00 28-Dec-95  rphall   Initial Creation
  325.         0.00 01-Mar-95  jlee     List's clear() has a bug, replaced it with delItem() and modified
  326.                                  list width handling.
  327.  
  328. ---------------------------------------------------------------------------*/
  329.  
  330. /**
  331.  * A prototype of a scrolling, word-wrapping text area.
  332.  *
  333.  * @see java.awt.List
  334.  * @version 0.00 28-Dec-95
  335.  * @author rphall
  336. */
  337. class LineTextBox extends TextBox
  338.     {
  339.  
  340.     // --- Class variables
  341.  
  342.     /**
  343.      * Default set of line-delimiting characters
  344.     */
  345.     public  static final char[] NEWLINE         = {'\r','\n'};
  346.  
  347.     /**
  348.      * Default set of word-delimiting characters
  349.     */
  350.     public  static final char[] WORDBRK         = {'\t',' ','-'};
  351.  
  352.     private static final String  CR             = "\r";
  353.     private static final String  LF             = "\n";
  354.     private static final String  CRLF           = CR + LF;
  355.     private static final boolean bReturnTokens  = true;
  356.  
  357.     // --- Instance variables
  358.  
  359.     // Pristine, unwrapped input text
  360.     private String strText;
  361.  
  362.     // Input text broken into word-wrapped lines
  363.     private String[] astrLine;
  364.  
  365.     // Flag that indicates whether selection feature of List is enabled
  366.     private boolean bSelectionEnabled;
  367.  
  368.     // Flag that indicates whether astrLine should be recalc'd
  369.     private boolean bWrapped;
  370.  
  371.     // Cached value of LineTextBox width, including scrollbar
  372.     private int cachedWidth;
  373.  
  374.     // Cached value of LineTextBox height.
  375.     private int cachedHeight;
  376.  
  377.     // Right margin compensating scrollbar
  378.     private int nUnuseableSize = PjFinals.nScrollbarWidth + 2 * PjFinals.nTextBoxHorInset;
  379.  
  380.     private String[]    astrLineDelim;
  381.     private String[]    astrWordDelim;
  382.     private String      strDelim;
  383.  
  384.     // --- Public constructors
  385.  
  386.     /**
  387.      * Construct an empty LineTextBox.
  388.     */
  389.     public LineTextBox()
  390.         {
  391.         init("");
  392.         }
  393.  
  394.     /**
  395.      * Construct an empty LineTextBox.
  396.     */
  397.     public LineTextBox( int nBorderSize )
  398.         {
  399.         super( nBorderSize );
  400.         init("");
  401.         }
  402.  
  403.     /**
  404.      * Construct an empty LineTextBox.
  405.     */
  406.     public LineTextBox( String text, int nBorderSize )
  407.         {
  408.         super( nBorderSize );
  409.         init( text );
  410.         }
  411.  
  412.     /**
  413.      * Construct a LineTextBox with some text.
  414.      *
  415.      * @param text     The text that is initially displayed.
  416.     */
  417.     public LineTextBox(String text)
  418.         {
  419.         init( text );
  420.         } // LineTextBox(String)
  421.  
  422.  
  423.     // --- Public operations
  424.  
  425.     public void init( String text )
  426.         {
  427.         strText = new String( cleanString(text) );
  428.         astrLine = null;
  429.         bSelectionEnabled = false;
  430.         bWrapped = false;
  431.         cachedWidth = 0;
  432.         } // init
  433.  
  434.     /**
  435.      * Set the text displayed by a LineTextBox.
  436.      *
  437.      * @param text     The new text for a LineTextBox.
  438.     */
  439.     public synchronized void setText(String text)
  440.         {
  441.         strText = new String( cleanString(text) );
  442.         breakText();
  443.         }
  444.  
  445.     /**
  446.      * Clear the text displayed by a LineTextBox.
  447.      * Equivalent to:
  448.      * <pre>
  449.      *      setText("");
  450.      * </pre>
  451.      * @see setText
  452.      *
  453.     */
  454.     public synchronized void clearText()
  455.         {
  456.         setText("");
  457.         }
  458.  
  459.     /**
  460.      * Return the text displayed by a LineTextBox.
  461.     */
  462.     public synchronized String getText()
  463.         {
  464.         return strText;
  465.         }
  466.  
  467.     /**
  468.      * Set whether selection features of List are enabled.
  469.      *
  470.      * @param  bEnable     true enables selection feature
  471.      * @see java.awt.List
  472.     */
  473.     public synchronized void setSelectionEnabled(boolean bEnable)
  474.         {
  475.         bSelectionEnabled = bEnable;
  476.         }
  477.  
  478.     /**
  479.      * Return whether selection features of List are enabled.
  480.      *
  481.      * @see java.awt.List
  482.     */
  483.     public synchronized boolean getSelectionEnabled()
  484.         {
  485.         return bSelectionEnabled;
  486.         }
  487.  
  488.     /**
  489.      * Reshape a LineTextBox:
  490.      * Hand off operation to super, then rewrap text if width has changes.
  491.      *
  492.      * @see java.awt.List#reshape
  493.      * @see java.awt.Component#reshape
  494.     */
  495.     public synchronized void reshape(int x, int y, int width, int height)
  496.         {
  497.         super.reshape( x, y, width, height );
  498.  
  499.         cachedHeight = height;
  500.  
  501.         if ( cachedWidth != width || bWrapped == false )
  502.             {
  503.             cachedWidth  = width;
  504.             if ( cachedWidth > nUnuseableSize )
  505.                 breakText();
  506.             }
  507.         repaint();
  508.         } // reshape
  509.  
  510.     /**
  511.      * Set the font used by a LineTextBox:
  512.      * Signal an internal flag to rewrap, then hand off operation to super.
  513.      *
  514.      * @see java.awt.Component#setFont
  515.     */
  516.     public synchronized void setFont(Font f)
  517.         {
  518.         super.setFont(f);
  519.         breakText();
  520.         }
  521.  
  522.     // --- Private operations
  523.  
  524.     // Break strText into lines of string
  525.     private void breakText()
  526.         {
  527.         bWrapped = false;
  528.         if ( cachedWidth == 0 || strText == null )
  529.             return;
  530.  
  531.         try {
  532.             initDelimiter();
  533.             int width = cachedWidth - nUnuseableSize;
  534.  
  535.             if ( strText.length() != 0 )
  536.                 {
  537.                 formatToArray( strText, width );
  538.  
  539.                 if ( cachedHeight >= m_vTextArray.size() * m_fmTextPlain.getHeight() )
  540.                     {
  541.                     width += PjFinals.nScrollbarWidth;
  542.                     formatToArray( strText, width );
  543.                     }
  544.                 }
  545.  
  546.             bWrapped=true;
  547.             }
  548.         catch (LineTextBoxError e)
  549.             {
  550.             System.out.println("Error-TextBox-breakText(): error invoking initDelimiter.");
  551.             }
  552.  
  553.         } // breakText
  554.  
  555.  
  556.     public void initDelimiter()
  557.         {
  558.         astrLineDelim = new String[NEWLINE.length];
  559.         for (int i=0; i<NEWLINE.length; i++)
  560.             astrLineDelim[i] = new String(NEWLINE,i,1);
  561.  
  562.         astrWordDelim = new String[WORDBRK.length];
  563.         for (int i=0; i<WORDBRK.length; i++)
  564.             astrWordDelim[i] = new String(WORDBRK,i,1);
  565.  
  566.         strDelim = new String(NEWLINE) + new String(WORDBRK);
  567.         }
  568.  
  569.     /**
  570.      * Throws an LineTextBoxError if predicate is false.
  571.      * The right way to implement assert is to import Assertable
  572.      * and ImplementationError from
  573.      * <b><a href="http://g.oswego.edu/dl/classes/collections/index.html">
  574.      * Collection Classes</a></b>
  575.      *
  576.      * @param predicate    Boolean expression to be checked.
  577.      * @see collections.ImplementationError
  578.      * @see collections.Assertable
  579.     */
  580.     public void assert(boolean predicate)
  581.         throws LineTextBoxError
  582.         {
  583.         if (!predicate) throw new LineTextBoxError();
  584.         }
  585.  
  586.     /**
  587.      * Formats unbroken text into lines.
  588.      * Returns a string array.
  589.      * Each string of the returned array is a line.
  590.      * Line delimiters are stripped from the unbroken text.
  591.      * The sequence "\r\n" is treated as a single line delimiter.
  592.      * Throws an implementation error if input text is empty.
  593.      *
  594.      * @param strRawText   The input text, length > 0
  595.      * @param linewidth    The desired line width
  596.     */
  597.  
  598.     public void formatToArray( String strRawText, int linewidth ) throws LineTextBoxError
  599.         {
  600.         Thread.currentThread().setPriority( Thread.NORM_PRIORITY );
  601.  
  602.         // Precondition
  603.         assert( strRawText.length() != 0 );
  604.  
  605.         // Format into lines
  606.         formatLine( strRawText, linewidth );
  607.         } // formatToStringArray
  608.  
  609.     // --- Private operations
  610.  
  611.     /*
  612.      * Returns a line and prunes the line from the input text.
  613.      * Line delimiters are stripped from the line.  This operation will
  614.      * treat the sequence "\r\n" as two line delimiters, rather than one.
  615.      * If this is undesirable, replace all CRLF sequences by single LF
  616.      * sequences before invoking this operation.
  617.      *
  618.      * @return String[0]   An extracted line
  619.      * @return String[1]   The input text pruned of the extracted line.
  620.     */
  621.     private void formatLine( String text, int desiredWidth ) throws LineTextBoxError
  622.         {
  623.         int     currentWidth;
  624.         int     checkWidth;
  625.         int     numLineChars;
  626.         String  line;
  627.         String  strToken;
  628.  
  629.         // reset line array
  630.         m_vTextArray.removeAllElements();
  631.  
  632.         while ( text.length() > 0 )
  633.             {
  634.             // reset FontMetrics
  635.             FontMetrics fm = m_fmTextPlain;
  636.  
  637.             if ( ('\\' == text.charAt(0)) && 'b' == text.charAt(1) )
  638.                 fm = m_fmTextBold;
  639.  
  640.             StringTokenizer st = new StringTokenizer( text, strDelim, bReturnTokens );
  641.  
  642.             line          = new String(""); // The extracted line
  643.             strToken      = null;           // A new token from text
  644.             currentWidth  = 0;              // The current width of the extracted line
  645.             checkWidth    = 0;              // The currentWidth plus a new token width
  646.             numLineChars  = 0;              // The number of chars in current line
  647.  
  648.             TokenLoop:
  649.             for ( int i = 0;;i++ )
  650.                 {
  651.                 // Implementation note: countTokens() does not seem to be
  652.                 // working correctly.  Hence this loop continues until an
  653.                 // exception occurs, rather than politely using countTokens
  654.                 // to limit iterations.
  655.                 try {
  656.                     strToken = st.nextToken();
  657.                     }
  658.                 catch (NoSuchElementException e)
  659.                     {
  660.                     break TokenLoop;
  661.                     }
  662.  
  663.                 // Line delimiters reset a line length calc
  664.                 for ( int j = 0; j < astrLineDelim.length; j++ )
  665.                     if ( strToken.equals( astrLineDelim[j] ) )
  666.                         {
  667.                         numLineChars += strToken.length();
  668.                         break TokenLoop;
  669.                         }
  670.  
  671.                 // Check desiredWidth with the addition of the new token
  672.                 if ( strToken != null )
  673.                     checkWidth = currentWidth + fm.stringWidth(strToken);
  674.                 else
  675.                     break TokenLoop;
  676.  
  677.                 // If the checked width is less than a line width,
  678.                 // add the new token to the current line and continue.
  679.                 if ( checkWidth < desiredWidth )
  680.                     {
  681.                     line += strToken;
  682.                     currentWidth = checkWidth;
  683.                     numLineChars += strToken.length();
  684.                     continue TokenLoop;
  685.                     }
  686.  
  687.                 // If the checked width is longer than a line width,
  688.                 // check if the new token is a word delimiter.  Extra
  689.                 // word delimiters are OK at the end of a line.
  690.                 for (int j=0; j<astrWordDelim.length; j++)
  691.                     if ( strToken.equals(astrWordDelim[j]) )
  692.                         {
  693.                         line += strToken;
  694.                         currentWidth = checkWidth;
  695.                         numLineChars += strToken.length();
  696.                         continue TokenLoop;
  697.                         }
  698.  
  699.                 // Avoid pathology by making sure the current line has
  700.                 // at least one token.
  701.                 if ( currentWidth == 0 )
  702.                     {
  703.                     line += strToken;
  704.                     currentWidth = checkWidth;
  705.                     numLineChars += strToken.length();
  706.                     continue TokenLoop;
  707.                     }
  708.  
  709.                 // If the checked width is longer than a line width,
  710.                 // and the current line has at least one token, the line
  711.                 // is finished. The new token starts the returned text.
  712.  
  713.                 break TokenLoop;
  714.  
  715.                 } // for TokenLoop
  716.  
  717.             assert( numLineChars > 0 );
  718.             assert( numLineChars <= text.length() );
  719.             assert( line.length() <= text.length() );
  720.  
  721.             text = ( numLineChars == text.length() ) ? "": text.substring( numLineChars );
  722.  
  723.             m_vTextArray.addElement( line );
  724.             }//while ( text.length() > 0 )
  725.         } // formatLine
  726.  
  727.     // Private operations
  728.     private String cleanString( String text )
  729.         {
  730.         // Replace CRLF with LF
  731.         int nextCRLF   = text.indexOf( CRLF );
  732.         int nextSubstr = 0;
  733.  
  734.         while ( nextCRLF != -1 )
  735.             {
  736.             nextSubstr = text.length() - CRLF.length();
  737.             if ( nextSubstr == 0 )
  738.                 text = text.substring( 0, nextCRLF ) + LF;
  739.             else
  740.                 text = text.substring( 0, nextCRLF ) + LF + text.substring( nextCRLF + CRLF.length() );
  741.             nextCRLF  = text.indexOf(CRLF);
  742.             } // while CRLF
  743.  
  744.          return text;
  745.         }
  746.     }; // LineTextBox
  747.  
  748. /**
  749.  * An internal implementation error
  750.  *
  751.  * @version    0.00 29-Dec-95
  752.  * @author     rphall
  753. */
  754. class LineTextBoxError extends Error
  755.     {
  756.  
  757.     // --- Public operations
  758.  
  759.     public LineTextBoxError()
  760.         {
  761.         super("LineTextBox implementation error");
  762.         }
  763.     }
  764.  
  765.