Clover coverage report -
Coverage timestamp: Sun Apr 18 2004 21:32:30 EDT
file stats: LOC: 304   Methods: 10
NCLOC: 175   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
HTMLText.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  * SimplyHTML, a word processor based on Java, HTML and CSS
 3   
  * Copyright (C) 2002 Ulrich Hilger
 4   
  *
 5   
  * This program is free software; you can redistribute it and/or
 6   
  * modify it under the terms of the GNU General Public License
 7   
  * as published by the Free Software Foundation; either version 2
 8   
  * of the License, or (at your option) any later version.
 9   
  *
 10   
  * This program is distributed in the hope that it will be useful,
 11   
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12   
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13   
  * GNU General Public License for more details.
 14   
  *
 15   
  * You should have received a copy of the GNU General Public License
 16   
  * along with this program; if not, write to the Free Software
 17   
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 18   
  */
 19   
 
 20   
 import javax.swing.text.BadLocationException;
 21   
 import java.io.IOException;
 22   
 import javax.swing.text.Document;
 23   
 import javax.swing.text.html.HTMLDocument;
 24   
 import javax.swing.text.EditorKit;
 25   
 import java.io.StringWriter;
 26   
 import javax.swing.text.html.HTMLEditorKit;
 27   
 import java.io.StringReader;
 28   
 import java.util.Vector;
 29   
 import javax.swing.text.AttributeSet;
 30   
 import javax.swing.text.ElementIterator;
 31   
 import javax.swing.text.Element;
 32   
 import javax.swing.text.AbstractDocument;
 33   
 import javax.swing.text.html.*;
 34   
 
 35   
 /**
 36   
  * A class to represent a portion of HTML text.
 37   
  *
 38   
  * <p>In stage 9 copy and paste have been refined to correct bugs that
 39   
  * occurred when cut and paste was happening in nested paragraph elements</p>
 40   
  *
 41   
  * @author Ulrich Hilger
 42   
  * @author Light Development
 43   
  * @author <a href="http://www.lightdev.com">http://www.lightdev.com</a>
 44   
  * @author <a href="mailto:info@lightdev.com">info@lightdev.com</a>
 45   
  * @author published under the terms and conditions of the
 46   
  *      GNU General Public License,
 47   
  *      for details see file gpl.txt in the distribution
 48   
  *      package of this software
 49   
  *
 50   
  * @version stage 11, April 27, 2003
 51   
  */
 52   
 
 53   
 public class HTMLText {
 54   
 
 55   
   /** the HTML representation of the text */
 56   
   private String htmlText;
 57   
 
 58   
   /** the plain text representation of the text */
 59   
   private String plainText;
 60   
 
 61   
   /** holds the copied plain text chunks */
 62   
   private Vector clipText = new Vector(0);
 63   
 
 64   
   /** holds the copied character attributes mapping to clipText */
 65   
   private Vector clipAttr = new Vector(0);
 66   
 
 67   
   /**
 68   
    * indicates whether or not the html represented by this
 69   
    * <code>HTMLText</code> instance contains more than one paragraph
 70   
    */
 71   
   private boolean multiPara = false;
 72   
 
 73   
   /**
 74   
    * construct a new empty <code>HTMLText</code> object
 75   
    */
 76  0
   public HTMLText() {
 77   
   }
 78   
 
 79   
   /**
 80   
    * copy an HTML string representation of a content portion from the
 81   
    * given editor pane.
 82   
    *
 83   
    * @param  src  the <code>SHTMLEditorPane</code> to copy from
 84   
    * @param  start  the position to start copying at
 85   
    * @param  length  the length of the content portion to copy
 86   
    *
 87   
    * @return an HTML string representation of the copied portion of content
 88   
    *
 89   
    * @see com.lightdev.app.shtm.SHTMLEditorPane
 90   
    */
 91  0
   public void copyHTML(SHTMLEditorPane src, int start, int length)
 92   
         throws BadLocationException, IOException
 93   
   {
 94  0
     HTMLDocument doc = (HTMLDocument) src.getDocument();
 95  0
     if( doc.getParagraphElement(start).equals(
 96   
         doc.getParagraphElement(start + length)))
 97   
     {
 98  0
       multiPara = false;
 99  0
       clearStyledText();
 100  0
       copyStyledText(src);
 101   
     }
 102   
     else {
 103  0
       multiPara = true;
 104  0
       StringWriter sw = new StringWriter();
 105  0
       SHTMLWriter w = new SHTMLWriter(sw, doc, start, length);
 106  0
       Element first = doc.getParagraphElement(start);
 107  0
       Element last = doc.getCharacterElement(start + length);
 108  0
       w.write(first, last);
 109  0
       htmlText = sw.getBuffer().toString();
 110  0
       plainText = doc.getText(start, length);
 111   
     }
 112   
   }
 113   
 
 114   
   /**
 115   
    * insert this <code>HTMLText<code> into a <code>Document</code>.
 116   
    *
 117   
    * @param  doc  the document to insert into
 118   
    * @param  pos  the text position to insert at
 119   
    */
 120  0
   public void pasteHTML(Document doc, int pos)
 121   
         throws BadLocationException, IOException
 122   
   {
 123   
     /**
 124   
      * if only text within one paragraph is to be inserted,
 125   
      * iterate over copied text chunks and insert each
 126   
      * chunk with its own set of copied attributes. Else
 127   
      * simply read copied HTML code back in.
 128   
      */
 129  0
     if(!multiPara) {
 130  0
       int contentSize = getClipTextSize();
 131  0
       String text;
 132  0
       for(int i=0;i<contentSize;i++) {
 133  0
         text = getCharactersAt(i);
 134  0
         doc.insertString(pos, text, getCharacterAttributes(i));
 135  0
         pos += text.length();
 136   
       }
 137   
     }
 138   
     else {
 139  0
       SHTMLDocument sDoc = (SHTMLDocument) doc;
 140  0
       Element cElem = sDoc.getCharacterElement(pos);
 141  0
       Element pElem = cElem.getParentElement();
 142  0
       if(pos == pElem.getStartOffset()) {
 143   
         // we are at the start of the paragraph to insert at
 144  0
         sDoc.insertBeforeStart(pElem, htmlText);
 145   
       }
 146   
       else {
 147  0
         if(pElem.getEndOffset() == pos + 1) {
 148   
           // we are at the end of the paragraph to insert at
 149  0
           sDoc.insertAfterEnd(pElem, htmlText);
 150   
         }
 151   
         else {
 152   
           // we are somewhere else inside the paragraph to insert at
 153  0
           String newHtml = splitPaste(sDoc, cElem, pElem, pos, htmlText);
 154  0
           sDoc.setOuterHTML(pElem, newHtml);
 155   
         }
 156   
       }
 157   
     }
 158   
   }
 159   
 
 160   
   /**
 161   
    * paste HTML by splitting a given paragraph element and inserting
 162   
    * at the split position
 163   
    *
 164   
    * @param doc  the document to insert to
 165   
    * @param elem  the character element to split
 166   
    * @param pElem  the paragraph element to split
 167   
    * @param pos  the text position inside the document where to split
 168   
    * @param html  the html text to insert at pos
 169   
    */
 170  0
   private String splitPaste(SHTMLDocument doc, Element elem, Element pElem, int pos, String html) {
 171  0
     StringWriter sw = new StringWriter();
 172  0
     SHTMLWriter w = new SHTMLWriter(sw, doc);
 173  0
     StringWriter splitSw = new StringWriter();
 174  0
     SHTMLWriter splitW = new SHTMLWriter(splitSw, doc);
 175  0
     try {
 176  0
       int count = pElem.getElementCount();
 177  0
       Element e;
 178  0
       w.startTag(pElem.getName(), pElem.getAttributes());
 179  0
       for(int i = 0; i < count; i++) {
 180  0
         e = pElem.getElement(i);
 181  0
         if(e.equals(elem)) {
 182  0
           int start = e.getStartOffset();
 183  0
           String textToSplit = doc.getText(start, e.getEndOffset() - start);
 184  0
           splitW.write(e);
 185  0
           String splitHtml = splitSw.getBuffer().toString();
 186  0
           int splitStart = splitSw.getBuffer().toString().indexOf(textToSplit);
 187  0
           int splitEnd = splitStart + pos - start;
 188  0
           if(i > 0) {
 189  0
             w.startTag(pElem.getName(), pElem.getAttributes());
 190   
           }
 191  0
           sw.write(splitHtml.substring(0, splitEnd));
 192  0
           w.endTag(pElem.getName());
 193  0
           sw.write(html);
 194  0
           w.startTag(pElem.getName(), pElem.getAttributes());
 195  0
           sw.write(splitHtml.substring(splitEnd));
 196  0
           if(i > 0) {
 197  0
             w.endTag(pElem.getName());
 198   
           }
 199   
         }
 200   
         else {
 201  0
           w.write(e);
 202   
         }
 203   
       }
 204  0
       w.endTag(pElem.getName());
 205   
     }
 206   
     catch(Exception e) {
 207  0
       e.printStackTrace();
 208   
     }
 209  0
     return sw.getBuffer().toString();
 210   
   }
 211   
 
 212   
   /**
 213   
    * Copy the selected portion of an SHTMLEditorPane as styled text,
 214   
    * i.e. chunks of plain text strings with an AttributeSet associated
 215   
    * to each of them.
 216   
    *
 217   
    * @param src  the SHTMLEditorPane to copy from
 218   
    */
 219  0
   private void copyStyledText(SHTMLEditorPane src) throws BadLocationException {
 220  0
     Document doc = src.getDocument();
 221  0
     int selStart = src.getSelectionStart();
 222  0
     int selEnd = src.getSelectionEnd();
 223  0
     int eStart;
 224  0
     int eEnd;
 225  0
     String eText;
 226  0
     ElementIterator eli = new ElementIterator(doc);
 227  0
     Element elem = eli.first();
 228  0
     while(elem != null) {
 229  0
       eStart = elem.getStartOffset();
 230  0
       eEnd = elem.getEndOffset();
 231  0
       if(elem.getName().equalsIgnoreCase(AbstractDocument.ContentElementName)) {
 232  0
         if((eEnd >= selStart) && (eStart <= selEnd)) {
 233  0
           clipAttr.addElement(elem.getAttributes());
 234  0
           if(eStart < selStart) {
 235  0
             if(eEnd > selEnd) { // both ends of elem outside selection
 236  0
               clipText.addElement(src.getText(selStart, selEnd - selStart));
 237   
             }
 238   
             else { // only first part of elem outside selection
 239  0
               clipText.addElement(src.getText(selStart, eEnd - selStart));
 240   
             }
 241   
           }
 242  0
           else if(eEnd > selEnd) { // only last part of elem outside selection
 243  0
             clipText.addElement(src.getText(eStart, selEnd - eStart));
 244   
           }
 245   
           else { // whole element inside selection
 246  0
             clipText.addElement(src.getText(eStart, eEnd - eStart));
 247   
           }
 248   
         }
 249   
       }
 250  0
       elem = eli.next();
 251   
     }
 252   
   }
 253   
 
 254   
   /** get the number of text chunks in this <code>StyledText</code> object */
 255  0
   private int getClipTextSize() {
 256  0
     return clipText.size();
 257   
   }
 258   
 
 259   
   /**
 260   
    * get the attributes of a certain chunk of styled text
 261   
    *
 262   
    * @param chunkPos - the number of the chunk to get the attributes for
 263   
    * @return the attributes for respective character position
 264   
    */
 265  0
   private AttributeSet getCharacterAttributes(int chunkNo) {
 266  0
     return (AttributeSet) clipAttr.elementAt(chunkNo);
 267   
   }
 268   
 
 269   
   /**
 270   
    * get the characters of a certain chunk of styled text
 271   
    *
 272   
    * @param chunkNo - the number of the chunk to get the characters for
 273   
    * @return the characters for respective chunk as String
 274   
    */
 275  0
   private String getCharactersAt(int chunkNo) {
 276  0
     return (String) clipText.elementAt(chunkNo);
 277   
   }
 278   
 
 279   
   /** clear all styled text contents of this <code>HTMLText</code> object */
 280  0
   private void clearStyledText() {
 281  0
     clipText.clear();
 282  0
     clipAttr.clear();
 283   
   }
 284   
 
 285   
   /**
 286   
    * get a String containing all chunks of text contained in this object
 287   
    *
 288   
    * @return string of all chunks in this object
 289   
    */
 290  0
   public String toString() {
 291  0
     StringBuffer text = new StringBuffer();
 292  0
     if(multiPara) {
 293  0
       text.append(plainText);
 294   
     }
 295   
     else {
 296  0
       int i;
 297  0
       for(i=0;i<clipText.size();i++) {
 298  0
         text.append((String) clipText.elementAt(i));
 299   
       }
 300   
     }
 301  0
     return text.toString();
 302   
   }
 303   
 
 304   
 }