Coverage Report - palmed.edit.text.LargeText

Classes in this Package Line Coverage Branch Coverage Complexity
LargeText
75% 
89% 
2,182

 1  
 /**
 2  
  * Redistribution  and use  in source  and binary  forms, with  or without
 3  
  * modification, are permitted provided  that the following conditions are
 4  
  * met :
 5  
  *
 6  
  * . Redistributions  of  source  code  must  retain  the  above copyright
 7  
  *   notice, this list of conditions and the following disclaimer.
 8  
  *
 9  
  * . Redistributions in  binary form  must reproduce  the above  copyright
 10  
  *   notice, this list of conditions  and the following disclaimer in  the
 11  
  *   documentation and/or other materials provided with the distribution.
 12  
  *
 13  
  * . The name of the author may not be used to endorse or promote products
 14  
  *   derived from this software without specific prior written permission.
 15  
  *
 16  
  * THIS SOFTWARE IS  PROVIDED BY THE  AUTHOR ``AS IS''  AND ANY EXPRESS  OR
 17  
  * IMPLIED  WARRANTIES,  INCLUDING,  BUT   NOT  LIMITED  TO,  THE   IMPLIED
 18  
  * WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE ARE
 19  
  * DISCLAIMED.  IN NO  EVENT SHALL  THE AUTHOR  BE LIABLE  FOR ANY  DIRECT,
 20  
  * INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL  DAMAGES
 21  
  * (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT OF  SUBSTITUTE  GOODS OR
 22  
  * SERVICES;  LOSS  OF USE,  DATA,  OR PROFITS;  OR  BUSINESS INTERRUPTION)
 23  
  * HOWEVER CAUSED  AND ON  ANY THEORY  OF LIABILITY,  WHETHER IN  CONTRACT,
 24  
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 25  
  * ANY  WAY  OUT OF  THE  USE OF  THIS  SOFTWARE, EVEN  IF  ADVISED OF  THE
 26  
  * POSSIBILITY OF SUCH DAMAGE.
 27  
  *
 28  
  * $Id$
 29  
  */
 30  
 
 31  
 package palmed.edit.text;
 32  
 
 33  
 import java.io.IOException;
 34  
 import java.io.InputStream;
 35  
 import java.io.OutputStream;
 36  
 import java.util.Enumeration;
 37  
 import java.util.Vector;
 38  
 import palmed.edit.util.Coordinate;
 39  
 
 40  
 /**
 41  
  * This class implements a composite of cachable text chunks.
 42  
  *
 43  
  * @author Mathieu Champlon
 44  
  * @version $Revision$ $Date$
 45  
  */
 46  
 public final class LargeText implements IText
 47  
 {
 48  
     /**
 49  
      * The maximum size of each text chunk in bytes.
 50  
      */
 51  
     private final int threshold_;
 52  
     /**
 53  
      * The views.
 54  
      */
 55  
     private final Vector views_;
 56  
     /**
 57  
      * The line inserter.
 58  
      */
 59  
     private final NewLineInserter newLineInserter_;
 60  
     /**
 61  
      * The text eraser.
 62  
      */
 63  
     private final TextEraser textEraser_;
 64  
     /**
 65  
      * The cache.
 66  
      */
 67  
     private final ICache cache_;
 68  
 
 69  
     /**
 70  
      * Create a large text.
 71  
      *
 72  
      * @param cache the cache
 73  
      * @param threshold the size of each text chunk in bytes.
 74  
      */
 75  
     public LargeText( final ICache cache, final int threshold )
 76  80
     {
 77  80
         if( cache == null )
 78  0
             throw new IllegalArgumentException( "parameter 'cache' is null" );
 79  80
         if( threshold <= 0 )
 80  0
             throw new IllegalArgumentException( "parameter 'threshold' must be > 0" );
 81  80
         cache_ = cache;
 82  80
         threshold_ = threshold;
 83  80
         views_ = new Vector();
 84  80
         newLineInserter_ = new NewLineInserter();
 85  80
         textEraser_ = new TextEraser();
 86  80
         cache_.add( new Chunk( cache_ ) );
 87  80
     }
 88  
 
 89  
     private boolean apply( final ILineExtractor functor, final int line )
 90  
     {
 91  230
         if( line < 0 )
 92  25
             return false;
 93  205
         final Enumeration chunks = cache_.elements();
 94  205
         int height = 0;
 95  710
         while( chunks.hasMoreElements() && line >= height )
 96  505
             height += ((IChunk)chunks.nextElement()).handle( functor, line - height );
 97  205
         return line <= height;
 98  
     }
 99  
 
 100  
     private void apply( final ICoordinateExtractor functor, final Coordinate coordinate )
 101  
     {
 102  50
         checkPosition( coordinate );
 103  30
         apply( new CoordinateExtractor( coordinate, functor ), coordinate.y_ );
 104  30
     }
 105  
 
 106  
     private void apply( final ITextExtractor functor, final Coordinate from, final Coordinate to )
 107  
     {
 108  25
         final Enumeration chunks = cache_.elements();
 109  25
         Coordinate start = new Coordinate();
 110  105
         while( chunks.hasMoreElements() && to.y_ >= start.y_ )
 111  80
             start = ((IChunk)chunks.nextElement()).handle( functor, start, from, to );
 112  25
     }
 113  
 
 114  
     /**
 115  
      * {@inheritDoc}
 116  
      */
 117  
     public int getHeight()
 118  
     {
 119  70
         int height = 1;
 120  70
         final Enumeration chunks = cache_.elements();
 121  260
         while( chunks.hasMoreElements() )
 122  190
             height += ((IChunk)chunks.nextElement()).getHeight();
 123  70
         return height;
 124  
     }
 125  
 
 126  
     /**
 127  
      * {@inheritDoc}
 128  
      */
 129  
     public String getLine( final int y )
 130  
     {
 131  200
         final StringBuffer result = new StringBuffer();
 132  200
         if( apply( new LineBuilder( result ), y ) )
 133  150
             return result.toString();
 134  50
         return null;
 135  
     }
 136  
 
 137  
     /**
 138  
      * {@inheritDoc}
 139  
      */
 140  
     public void insert( final Coordinate position, final char c )
 141  
     {
 142  50
         apply( new CharacterInserter( c ), position );
 143  30
         update();
 144  30
     }
 145  
 
 146  
     private void checkPosition( final Coordinate position )
 147  
     {
 148  50
         if( position.y_ >= getHeight() || position.x_ > getLine( position.y_ ).length() )
 149  10
             throw new RuntimeException( "invalid position : " + position );
 150  30
     }
 151  
 
 152  
     /**
 153  
      * {@inheritDoc}
 154  
      */
 155  
     public void insertNewLine( final Coordinate position )
 156  
     {
 157  0
         apply( newLineInserter_, position );
 158  0
         update();
 159  0
     }
 160  
 
 161  
     /**
 162  
      * {@inheritDoc}
 163  
      */
 164  
     public void remove( final Coordinate from, final Coordinate to )
 165  
     {
 166  25
         apply( textEraser_, from, to );
 167  25
         update();
 168  25
     }
 169  
 
 170  
     /**
 171  
      * {@inheritDoc}
 172  
      */
 173  
     public void register( final ITextView view )
 174  
     {
 175  80
         if( view == null )
 176  0
             throw new IllegalArgumentException( "parameter 'view' is null" );
 177  80
         views_.addElement( view );
 178  80
     }
 179  
 
 180  
     /**
 181  
      * {@inheritDoc}
 182  
      */
 183  
     public void clear()
 184  
     {
 185  0
         cache_.clear();
 186  0
         cache_.add( new Chunk( cache_ ) );
 187  0
         update();
 188  0
     }
 189  
 
 190  
     /**
 191  
      * {@inheritDoc}
 192  
      */
 193  
     public void write( final OutputStream stream, final Coordinate from, final Coordinate to ) throws IOException
 194  
     {
 195  0
         final Vector exceptions = new Vector(); // FIXME dirty !
 196  0
         apply( new TextSerializer( stream, exceptions ), from, to );
 197  0
         if( !exceptions.isEmpty() )
 198  0
             throw (IOException)exceptions.firstElement();
 199  0
     }
 200  
 
 201  
     /**
 202  
      * {@inheritDoc}
 203  
      */
 204  
     public void read( final InputStream stream, final Coordinate from ) throws IOException
 205  
     {
 206  0
         final Vector exceptions = new Vector(); // FIXME dirty !
 207  0
         apply( new TextDeserializer( stream, exceptions ), from );
 208  0
         if( !exceptions.isEmpty() )
 209  0
             throw (IOException)exceptions.firstElement();
 210  0
         update();
 211  0
     }
 212  
 
 213  
     private void update()
 214  
     {
 215  120
         final Coordinate size = new Coordinate( 0, 1 );
 216  120
         int length = 0;
 217  120
         boolean hasBeenModified = false;
 218  120
         final Enumeration chunks = cache_.elements();
 219  465
         while( chunks.hasMoreElements() )
 220  
         {
 221  345
             final IChunk chunk = (IChunk)chunks.nextElement();
 222  345
             length = chunk.count( size, length );
 223  345
             hasBeenModified |= chunk.hasBeenModified();
 224  345
         }
 225  120
         final Enumeration views = views_.elements();
 226  240
         while( views.hasMoreElements() )
 227  
         {
 228  120
             final ITextView view = (ITextView)views.nextElement();
 229  120
             view.update( size.x_, size.y_ );
 230  120
             view.modified( hasBeenModified );
 231  120
         }
 232  120
     }
 233  
 
 234  
     private void updateModificationStatus()
 235  
     {
 236  15
         boolean hasBeenModified = false;
 237  15
         final Enumeration chunks = cache_.elements();
 238  55
         while( chunks.hasMoreElements() )
 239  
         {
 240  40
             final IChunk chunk = (IChunk)chunks.nextElement();
 241  40
             hasBeenModified |= chunk.hasBeenModified();
 242  40
         }
 243  15
         final Enumeration views = views_.elements();
 244  30
         while( views.hasMoreElements() )
 245  15
             ((ITextView)views.nextElement()).modified( hasBeenModified );
 246  15
     }
 247  
 
 248  
     /**
 249  
      * {@inheritDoc}
 250  
      */
 251  
     public void read( final InputStream stream ) throws IOException
 252  
     {
 253  65
         final MultiInputStream multi = new MultiInputStream( stream, threshold_ );
 254  65
         cache_.delete();
 255  
         do
 256  
         {
 257  180
             final IChunk chunk = new Chunk( cache_ );
 258  180
             chunk.read( multi );
 259  180
             cache_.add( chunk );
 260  180
             multi.next();
 261  
         }
 262  180
         while( stream.available() > 0 );
 263  65
         update();
 264  65
     }
 265  
 
 266  
     /**
 267  
      * {@inheritDoc}
 268  
      */
 269  
     public void write( final OutputStream stream ) throws IOException
 270  
     {
 271  15
         final Enumeration chunks = cache_.elements();
 272  55
         while( chunks.hasMoreElements() )
 273  40
             ((IChunk)chunks.nextElement()).write( stream );
 274  15
         updateModificationStatus();
 275  15
     }
 276  
 
 277  
     /**
 278  
      * {@inheritDoc}
 279  
      */
 280  
     public void unmarshall( final InputStream stream ) throws IOException
 281  
     {
 282  0
         cache_.unmarshall( stream );
 283  0
         update();
 284  0
     }
 285  
 
 286  
     /**
 287  
      * {@inheritDoc}
 288  
      */
 289  
     public void marshall( final OutputStream stream ) throws IOException
 290  
     {
 291  0
         cache_.marshall( stream );
 292  0
     }
 293  
 
 294  
     /**
 295  
      * {@inheritDoc}
 296  
      */
 297  
     public void delete()
 298  
     {
 299  0
         cache_.delete();
 300  0
     }
 301  
 
 302  
     /**
 303  
      * {@inheritDoc}
 304  
      */
 305  
     public void setLineSeparator( final String separator )
 306  
     {
 307  
         // TODO support custom separator in large text
 308  0
         throw new RuntimeException( "TODO support custom separator in large text" );
 309  
     }
 310  
 }