Home » JCraft » jxl » biff » drawing » [javadoc | source]

    1   /*********************************************************************
    2   *
    3   *      Copyright (C) 2002 Andrew Khan
    4   *
    5   * This library is free software; you can redistribute it and/or
    6   * modify it under the terms of the GNU Lesser General Public
    7   * License as published by the Free Software Foundation; either
    8   * version 2.1 of the License, or (at your option) any later version.
    9   *
   10   * This library 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 GNU
   13   * Lesser General Public License for more details.
   14   *
   15   * You should have received a copy of the GNU Lesser General Public
   16   * License along with this library; if not, write to the Free Software
   17   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   18   ***************************************************************************/
   19   
   20   package jxl.biff.drawing;
   21   
   22   import java.io.IOException;
   23   
   24   import jxl.common.Assert;
   25   import jxl.common.Logger;
   26   
   27   import jxl.WorkbookSettings;
   28   import jxl.biff.ContinueRecord;
   29   import jxl.biff.IntegerHelper;
   30   import jxl.biff.StringHelper;
   31   import jxl.write.biff.File;
   32   
   33   /**
   34    * Contains the various biff records used to insert a cell note into a
   35    * worksheet
   36    */
   37   public class Comment implements DrawingGroupObject
   38   {
   39     /**
   40      * The logger
   41      */
   42     private static Logger logger = Logger.getLogger(Comment.class);
   43   
   44     /**
   45      * The spContainer that was read in
   46      */
   47     private EscherContainer readSpContainer;
   48   
   49     /**
   50      * The spContainer that was generated
   51      */
   52     private EscherContainer spContainer;
   53   
   54     /**
   55      * The MsoDrawingRecord associated with the drawing
   56      */
   57     private MsoDrawingRecord msoDrawingRecord;
   58   
   59     /**
   60      * The ObjRecord associated with the drawing
   61      */
   62     private ObjRecord objRecord;
   63   
   64     /**
   65      * Initialized flag
   66      */
   67     private boolean initialized = false;
   68   
   69     /**
   70      * The object id, assigned by the drawing group
   71      */
   72     private int objectId;
   73   
   74     /**
   75      * The blip id
   76      */
   77     private int blipId;
   78   
   79     /**
   80      * The shape id
   81      */
   82     private int shapeId;
   83   
   84     /**
   85      * The column
   86      */
   87     private int column;
   88   
   89     /**
   90      * The row position of the image
   91      */
   92     private int row;
   93   
   94     /**
   95      * The width of the image in cells
   96      */
   97     private double width;
   98   
   99     /**
  100      * The height of the image in cells
  101      */
  102     private double height;
  103   
  104     /**
  105      * The number of places this drawing is referenced
  106      */
  107     private int referenceCount;
  108   
  109     /**
  110      * The top level escher container
  111      */
  112     private EscherContainer escherData;
  113   
  114     /**
  115      * Where this image came from (read, written or a copy)
  116      */
  117     private Origin origin;
  118   
  119     /**
  120      * The drawing group for all the images
  121      */
  122     private DrawingGroup drawingGroup;
  123   
  124     /**
  125      * The drawing data
  126      */
  127     private DrawingData drawingData;
  128   
  129     /**
  130      * The type of this drawing object
  131      */
  132     private ShapeType type;
  133   
  134     /**
  135      * The drawing position on the sheet
  136      */
  137     private int drawingNumber;
  138   
  139     /**
  140      * An mso drawing record, which sometimes appears
  141      */
  142     private MsoDrawingRecord mso;
  143   
  144     /**
  145      * The text object record
  146      */
  147     private TextObjectRecord txo;
  148   
  149     /**
  150      * The note record
  151      */
  152     private NoteRecord note;
  153   
  154     /**
  155      * Text data from the first continue record
  156      */
  157     private ContinueRecord text;
  158   
  159     /**
  160      * Formatting data from the second continue record
  161      */
  162     private ContinueRecord formatting;
  163   
  164     /**
  165      * The comment text
  166      */
  167     private String commentText;
  168   
  169     /**
  170      * The workbook settings
  171      */
  172     private WorkbookSettings workbookSettings;
  173   
  174     /**
  175      * Constructor used when reading images
  176      *
  177      * @param msorec the drawing record
  178      * @param obj the object record
  179      * @param dd the drawing data for all drawings on this sheet
  180      * @param dg the drawing group
  181      * @param ws the workbook settings
  182      */
  183     public Comment(MsoDrawingRecord msorec, ObjRecord obj, DrawingData dd,
  184                    DrawingGroup dg, WorkbookSettings ws)
  185     {
  186       drawingGroup = dg;
  187       msoDrawingRecord = msorec;
  188       drawingData = dd;
  189       objRecord = obj;
  190       initialized = false;
  191       workbookSettings = ws;
  192       origin = Origin.READ;
  193       drawingData.addData(msoDrawingRecord.getData());
  194       drawingNumber = drawingData.getNumDrawings() - 1;
  195       drawingGroup.addDrawing(this);
  196   
  197       Assert.verify(msoDrawingRecord != null && objRecord != null);
  198   
  199       if (!initialized)
  200       {
  201         initialize();
  202       }
  203     }
  204   
  205     /**
  206      * Copy constructor used to copy drawings from read to write
  207      *
  208      * @param dgo the drawing group object
  209      * @param dg the drawing group
  210      * @param ws the workbook settings
  211      */
  212     /*protected*/ public Comment(DrawingGroupObject dgo,
  213                                  DrawingGroup dg,
  214                                  WorkbookSettings ws)
  215     {
  216       Comment d = (Comment) dgo;
  217       Assert.verify(d.origin == Origin.READ);
  218       msoDrawingRecord = d.msoDrawingRecord;
  219       objRecord = d.objRecord;
  220       initialized = false;
  221       origin = Origin.READ;
  222       drawingData = d.drawingData;
  223       drawingGroup = dg;
  224       drawingNumber = d.drawingNumber;
  225       drawingGroup.addDrawing(this);
  226       mso = d.mso;
  227       txo = d.txo;
  228       text = d.text;
  229       formatting = d.formatting;
  230       note = d.note;
  231       width = d.width;
  232       height = d.height;
  233       workbookSettings = ws;
  234     }
  235   
  236     /**
  237      * Constructor invoked when writing the images
  238      *
  239      * @param txt the comment text
  240      * @param c the column
  241      * @param r the row
  242      */
  243     public Comment(String txt, int c, int r)
  244     {
  245       initialized = true;
  246       origin = Origin.WRITE;
  247       column = c;
  248       row = r;
  249       referenceCount = 1;
  250       type = ShapeType.TEXT_BOX;
  251       commentText = txt;
  252       width = 3;
  253       height = 4;
  254     }
  255   
  256     /**
  257      * Initializes the member variables from the Escher stream data
  258      */
  259     private void initialize()
  260     {
  261       readSpContainer = drawingData.getSpContainer(drawingNumber);
  262       Assert.verify(readSpContainer != null);
  263   
  264       EscherRecord[] children = readSpContainer.getChildren();
  265   
  266       Sp sp = (Sp) readSpContainer.getChildren()[0];
  267       objectId = objRecord.getObjectId();
  268       shapeId = sp.getShapeId();
  269       type = ShapeType.getType(sp.getShapeType());
  270   
  271       if (type == ShapeType.UNKNOWN)
  272       {
  273         logger.warn("Unknown shape type");
  274       }
  275   
  276       ClientAnchor clientAnchor = null;
  277       for (int i = 0; i < children.length && clientAnchor == null; i++)
  278       {
  279         if (children[i].getType() == EscherRecordType.CLIENT_ANCHOR)
  280         {
  281           clientAnchor = (ClientAnchor) children[i];
  282         }
  283       }
  284   
  285       if (clientAnchor == null)
  286       {
  287         logger.warn("client anchor not found");
  288       }
  289       else
  290       {
  291         column = (int) clientAnchor.getX1() - 1;
  292         row = (int) clientAnchor.getY1() + 1;
  293         width = clientAnchor.getX2() - clientAnchor.getX1();
  294         height = clientAnchor.getY2() - clientAnchor.getY1();
  295       }
  296   
  297       initialized = true;
  298     }
  299   
  300   
  301     /**
  302      * Sets the object id.  Invoked by the drawing group when the object is
  303      * added to id
  304      *
  305      * @param objid the object id
  306      * @param bip the blip id
  307      * @param sid the shape id
  308      */
  309     public final void setObjectId(int objid, int bip, int sid)
  310     {
  311       objectId = objid;
  312       blipId = bip;
  313       shapeId = sid;
  314   
  315       if (origin == Origin.READ)
  316       {
  317         origin = Origin.READ_WRITE;
  318       }
  319     }
  320   
  321     /**
  322      * Accessor for the object id
  323      *
  324      * @return the object id
  325      */
  326     public final int getObjectId()
  327     {
  328       if (!initialized)
  329       {
  330         initialize();
  331       }
  332   
  333       return objectId;
  334     }
  335   
  336     /**
  337      * Accessor for the shape id
  338      *
  339      * @return the object id
  340      */
  341     public final int getShapeId()
  342     {
  343       if (!initialized)
  344       {
  345         initialize();
  346       }
  347   
  348       return shapeId;
  349     }
  350   
  351     /**
  352      * Accessor for the blip id
  353      *
  354      * @return the blip id
  355      */
  356     public final int getBlipId()
  357     {
  358       if (!initialized)
  359       {
  360         initialize();
  361       }
  362   
  363       return blipId;
  364     }
  365   
  366     /**
  367      * Gets the drawing record which was read in
  368      *
  369      * @return the drawing record
  370      */
  371     public MsoDrawingRecord  getMsoDrawingRecord()
  372     {
  373       return msoDrawingRecord;
  374     }
  375   
  376     /**
  377      * Creates the main Sp container for the drawing
  378      *
  379      * @return the SP container
  380      */
  381     public EscherContainer getSpContainer()
  382     {
  383       if (!initialized)
  384       {
  385         initialize();
  386       }
  387   
  388       if (origin == Origin.READ)
  389       {
  390         return getReadSpContainer();
  391       }
  392   
  393       if (spContainer == null)
  394       {
  395         spContainer = new SpContainer();
  396         Sp sp = new Sp(type, shapeId, 2560);
  397         spContainer.add(sp);
  398         Opt opt = new Opt();
  399         opt.addProperty(344, false, false, 0); // ?
  400         opt.addProperty(385, false, false, 134217808); // fill colour
  401         opt.addProperty(387, false, false, 134217808); // background colour
  402         opt.addProperty(959, false, false, 131074); // hide
  403         spContainer.add(opt);
  404   
  405         ClientAnchor clientAnchor = new ClientAnchor(column + 1.3,
  406                                                      Math.max(0, row - 0.6),
  407                                                      column + 1.3 + width,
  408                                                      row + height, 
  409                                                      0x1);
  410   
  411         spContainer.add(clientAnchor);
  412   
  413         ClientData clientData = new ClientData();
  414         spContainer.add(clientData);
  415   
  416         ClientTextBox clientTextBox = new ClientTextBox();
  417         spContainer.add(clientTextBox);
  418       }
  419   
  420       return spContainer;
  421     }
  422   
  423     /**
  424      * Sets the drawing group for this drawing.  Called by the drawing group
  425      * when this drawing is added to it
  426      *
  427      * @param dg the drawing group
  428      */
  429     public void setDrawingGroup(DrawingGroup dg)
  430     {
  431       drawingGroup = dg;
  432     }
  433   
  434     /**
  435      * Accessor for the drawing group
  436      *
  437      * @return the drawing group
  438      */
  439     public DrawingGroup getDrawingGroup()
  440     {
  441       return drawingGroup;
  442     }
  443   
  444     /**
  445      * Gets the origin of this drawing
  446      *
  447      * @return where this drawing came from
  448      */
  449     public Origin getOrigin()
  450     {
  451       return origin;
  452     }
  453   
  454     /**
  455      * Accessor for the reference count on this drawing
  456      *
  457      * @return the reference count
  458      */
  459     public int getReferenceCount()
  460     {
  461       return referenceCount;
  462     }
  463   
  464     /**
  465      * Sets the new reference count on the drawing
  466      *
  467      * @param r the new reference count
  468      */
  469     public void setReferenceCount(int r)
  470     {
  471       referenceCount = r;
  472     }
  473   
  474     /**
  475      * Accessor for the column of this drawing
  476      *
  477      * @return the column
  478      */
  479     public double getX()
  480     {
  481       if (!initialized)
  482       {
  483         initialize();
  484       }
  485       return column;
  486     }
  487   
  488     /**
  489      * Sets the column position of this drawing.  Used when inserting/removing
  490      * columns from the spreadsheet
  491      *
  492      * @param x the column
  493      */
  494     public void setX(double x)
  495     {
  496       if (origin == Origin.READ)
  497       {
  498         if (!initialized)
  499         {
  500           initialize();
  501         }
  502         origin = Origin.READ_WRITE;
  503       }
  504   
  505       column = (int) x;
  506     }
  507   
  508     /**
  509      * Accessor for the row of this drawing
  510      *
  511      * @return the row
  512      */
  513     public double getY()
  514     {
  515       if (!initialized)
  516       {
  517         initialize();
  518       }
  519   
  520       return row;
  521     }
  522   
  523     /**
  524      * Accessor for the row of the drawing
  525      *
  526      * @param y the row
  527      */
  528     public void setY(double y)
  529     {
  530       if (origin == Origin.READ)
  531       {
  532         if (!initialized)
  533         {
  534           initialize();
  535         }
  536         origin = Origin.READ_WRITE;
  537       }
  538   
  539       row = (int) y;
  540     }
  541   
  542   
  543     /**
  544      * Accessor for the width of this drawing
  545      *
  546      * @return the number of columns spanned by this image
  547      */
  548     public double getWidth()
  549     {
  550       if (!initialized)
  551       {
  552         initialize();
  553       }
  554   
  555       return width;
  556     }
  557   
  558     /**
  559      * Accessor for the width
  560      *
  561      * @param w the number of columns to span
  562      */
  563     public void setWidth(double w)
  564     {
  565       if (origin == Origin.READ)
  566       {
  567         if (!initialized)
  568         {
  569           initialize();
  570         }
  571         origin = Origin.READ_WRITE;
  572       }
  573   
  574       width = w;
  575     }
  576   
  577     /**
  578      * Accessor for the height of this drawing
  579      *
  580      * @return the number of rows spanned by this image
  581      */
  582     public double getHeight()
  583     {
  584       if (!initialized)
  585       {
  586         initialize();
  587       }
  588   
  589       return height;
  590     }
  591   
  592     /**
  593      * Accessor for the height of this drawing
  594      *
  595      * @param h the number of rows spanned by this image
  596      */
  597     public void setHeight(double h)
  598     {
  599       if (origin == Origin.READ)
  600       {
  601         if (!initialized)
  602         {
  603           initialize();
  604         }
  605         origin = Origin.READ_WRITE;
  606       }
  607   
  608       height = h;
  609     }
  610   
  611   
  612     /**
  613      * Gets the SpContainer that was read in
  614      *
  615      * @return the read sp container
  616      */
  617     private EscherContainer getReadSpContainer()
  618     {
  619       if (!initialized)
  620       {
  621         initialize();
  622       }
  623   
  624       return readSpContainer;
  625     }
  626   
  627     /**
  628      * Accessor for the image data
  629      *
  630      * @return the image data
  631      */
  632     public byte[] getImageData()
  633     {
  634       Assert.verify(origin == Origin.READ || origin == Origin.READ_WRITE);
  635   
  636       if (!initialized)
  637       {
  638         initialize();
  639       }
  640   
  641       return drawingGroup.getImageData(blipId);
  642     }
  643   
  644     /**
  645      * Accessor for the type
  646      *
  647      * @return the type
  648      */
  649     public ShapeType getType()
  650     {
  651       return type;
  652     }
  653   
  654     /**
  655      * Sets the text object
  656      *
  657      * @param t the text object
  658      */
  659     public void setTextObject(TextObjectRecord t)
  660     {
  661       txo = t;
  662     }
  663   
  664     /**
  665      * Sets the note object
  666      *
  667      * @param t the note record
  668      */
  669     public void setNote(NoteRecord t)
  670     {
  671       note = t;
  672     }
  673   
  674     /**
  675      * Sets the text data
  676      *
  677      * @param t the text data
  678      */
  679     public void setText(ContinueRecord t)
  680     {
  681       text = t;
  682     }
  683   
  684     /**
  685      * Sets the formatting
  686      *
  687      * @param t the formatting record
  688      */
  689     public void setFormatting(ContinueRecord t)
  690     {
  691       formatting = t;
  692     }
  693   
  694     /**
  695      * Accessor for the image data
  696      *
  697      * @return the image data
  698      */
  699     public byte[] getImageBytes()
  700     {
  701       Assert.verify(false);
  702       return null;
  703     }
  704   
  705     /**
  706      * Accessor for the image file path.  Normally this is the absolute path
  707      * of a file on the directory system, but if this drawing was constructed
  708      * using an byte[] then the blip id is returned
  709      *
  710      * @return the image file path, or the blip id
  711      */
  712     public String getImageFilePath()
  713     {
  714       Assert.verify(false);
  715       return null;
  716     }
  717   
  718     /**
  719      * Adds an mso record to this object
  720      *
  721      * @param d the mso record
  722      */
  723     public void addMso(MsoDrawingRecord d)
  724     {
  725       mso = d;
  726       drawingData.addRawData(mso.getData());
  727     }
  728   
  729     /**
  730      * Writes out the additional comment records
  731      *
  732      * @param outputFile the output file
  733      * @exception IOException
  734      */
  735     public void writeAdditionalRecords(File outputFile) throws IOException
  736     {
  737       if (origin == Origin.READ)
  738       {
  739         outputFile.write(objRecord);
  740   
  741         if (mso != null)
  742         {
  743           outputFile.write(mso);
  744         }
  745         outputFile.write(txo);
  746         outputFile.write(text);
  747         if (formatting != null)
  748         {
  749           outputFile.write(formatting);
  750         }
  751         return;
  752       }
  753   
  754       // Create the obj record
  755       ObjRecord objrec = new ObjRecord(objectId,
  756                                        ObjRecord.EXCELNOTE);
  757   
  758       outputFile.write(objrec);
  759   
  760       // Create the mso data record.  Write the text box record again,
  761       // although it is already included in the SpContainer
  762       ClientTextBox textBox = new ClientTextBox();
  763       MsoDrawingRecord msod = new MsoDrawingRecord(textBox.getData());
  764       outputFile.write(msod);
  765   
  766       TextObjectRecord txorec = new TextObjectRecord(getText());
  767       outputFile.write(txorec);
  768   
  769       // Data for the first continue record
  770       byte[] textData = new byte[commentText.length() * 2 + 1];
  771       textData[0] = 0x1; // unicode indicator
  772       StringHelper.getUnicodeBytes(commentText, textData, 1);
  773       //StringHelper.getBytes(commentText, textData, 1);
  774       ContinueRecord textContinue = new ContinueRecord(textData);
  775       outputFile.write(textContinue);
  776   
  777       // Data for the formatting runs
  778   
  779       byte[] frData = new byte[16];
  780   
  781       // First txo run (the user)
  782       IntegerHelper.getTwoBytes(0, frData, 0); // index to the first character
  783       IntegerHelper.getTwoBytes(0, frData, 2); // index to the font(default)
  784       // Mandatory last txo run
  785       IntegerHelper.getTwoBytes(commentText.length(), frData, 8);
  786       IntegerHelper.getTwoBytes(0, frData, 10); // index to the font(default)
  787   
  788       ContinueRecord frContinue = new ContinueRecord(frData);
  789       outputFile.write(frContinue);
  790     }
  791   
  792     /**
  793      * Writes any records that need to be written after all the drawing group
  794      * objects have been written
  795      * Writes out all the note records
  796      *
  797      * @param outputFile the output file
  798      * @exception IOException
  799      */
  800     public void writeTailRecords(File outputFile) throws IOException
  801     {
  802       if (origin == Origin.READ)
  803       {
  804         outputFile.write(note);
  805         return;
  806       }
  807   
  808       // The note record
  809       NoteRecord noteRecord = new NoteRecord(column, row, objectId);
  810       outputFile.write(noteRecord);
  811     }
  812   
  813     /**
  814      * Accessor for the row
  815      *
  816      * @return  the row
  817      */
  818     public int getRow()
  819     {
  820       return note.getRow();
  821     }
  822   
  823     /**
  824      * Accessor for the column
  825      *
  826      * @return  the column
  827      */
  828     public int getColumn()
  829     {
  830       return note.getColumn();
  831     }
  832   
  833     /**
  834      * Accessor for the comment text
  835      *
  836      * @return  the comment text
  837      */
  838     public String getText()
  839     {
  840       if (commentText == null)
  841       {
  842         Assert.verify(text != null);
  843   
  844         byte[] td = text.getData();
  845         if (td[0] == 0)
  846         {
  847           commentText = StringHelper.getString
  848             (td, td.length - 1, 1, workbookSettings);
  849         }
  850         else
  851         {
  852           commentText = StringHelper.getUnicodeString
  853             (td, (td.length - 1) / 2, 1);
  854         }
  855       }
  856   
  857       return commentText;
  858     }
  859   
  860     /**
  861      * Hashing algorithm
  862      *
  863      * @return the hash code
  864      */
  865     public int hashCode()
  866     {
  867       return commentText.hashCode();
  868     }
  869   
  870     /**
  871      * Called when the comment text is changed during the sheet copy process
  872      *
  873      * @param t the new text
  874      */
  875     public void setCommentText(String t)
  876     {
  877       commentText = t;
  878   
  879       if (origin == Origin.READ)
  880       {
  881         origin = Origin.READ_WRITE;
  882       }
  883     }
  884   
  885     /**
  886      * Accessor for the first drawing on the sheet.  This is used when
  887      * copying unmodified sheets to indicate that this drawing contains
  888      * the first time Escher gubbins
  889      *
  890      * @return TRUE if this MSORecord is the first drawing on the sheet
  891      */
  892     public boolean isFirst()
  893     {
  894       return msoDrawingRecord.isFirst();
  895     }
  896   
  897     /**
  898      * Queries whether this object is a form object.  Form objects have their
  899      * drawings records spread over several records and require special handling
  900      *
  901      * @return TRUE if this is a form object, FALSE otherwise
  902      */
  903     public boolean isFormObject()
  904     {
  905       return true;
  906     }
  907   }
  908   
  909   
  910   

Home » JCraft » jxl » biff » drawing » [javadoc | source]