Author: nick
Date: Wed Jan  9 15:21:35 2008
New Revision: 610608

URL: http://svn.apache.org/viewvc?rev=610608&view=rev
Log:
Make a start on processing shapes on a sheet out of a record. For now, doesn't 
actually manage to do this, but has much of the infrastructure that'll be 
needed. Includes ability to get an existing HSSFPatriarch for a sheet, if there 
are the required records, and for the HSSFPatriarch to be in a position to be 
given the shapes that make it up (but this isn't done yet)

Modified:
    poi/trunk/src/java/org/apache/poi/ddf/EscherOptRecord.java
    poi/trunk/src/java/org/apache/poi/hssf/model/Sheet.java
    poi/trunk/src/java/org/apache/poi/hssf/model/Workbook.java
    
poi/trunk/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java
    poi/trunk/src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java
    poi/trunk/src/java/org/apache/poi/hssf/record/EscherAggregate.java
    poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
    poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
    poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java
    poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java

Modified: poi/trunk/src/java/org/apache/poi/ddf/EscherOptRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ddf/EscherOptRecord.java?rev=610608&r1=610607&r2=610608&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ddf/EscherOptRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/ddf/EscherOptRecord.java Wed Jan  9 
15:21:35 2008
@@ -18,11 +18,14 @@
         
 package org.apache.poi.ddf;
 
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.HexDump;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
 
-import java.util.*;
-import java.io.IOException;
+import org.apache.poi.util.HexDump;
+import org.apache.poi.util.LittleEndian;
 
 /**
  * The opt record is used to store property values for a shape.  It is the key 
to determining

Modified: poi/trunk/src/java/org/apache/poi/hssf/model/Sheet.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/model/Sheet.java?rev=610608&r1=610607&r2=610608&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/model/Sheet.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/model/Sheet.java Wed Jan  9 15:21:35 
2008
@@ -2663,12 +2663,26 @@
        return margins;
     }
 
-    public int aggregateDrawingRecords(DrawingManager2 drawingManager)
+    /**
+     * Finds the DrawingRecord for our sheet, and
+     *  attaches it to the DrawingManager (which knows about
+     *  the overall DrawingGroup for our workbook).
+     * If requested, will create a new DrawRecord
+     *  if none currently exist
+     * @param drawingManager The DrawingManager2 for our workbook
+     * @param createIfMissing Should one be created if missing?
+     */
+    public int aggregateDrawingRecords(DrawingManager2 drawingManager, boolean 
createIfMissing)
     {
         int loc = findFirstRecordLocBySid(DrawingRecord.sid);
-        boolean noDrawingRecordsFound = loc == -1;
+        boolean noDrawingRecordsFound = (loc == -1);
         if (noDrawingRecordsFound)
         {
+               if(!createIfMissing) {
+                       // None found, and not allowed to add in
+                       return -1;
+               }
+               
             EscherAggregate aggregate = new EscherAggregate( drawingManager );
             loc = findFirstRecordLocBySid(EscherAggregate.sid);
             if (loc == -1)

Modified: poi/trunk/src/java/org/apache/poi/hssf/model/Workbook.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/model/Workbook.java?rev=610608&r1=610607&r2=610608&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/model/Workbook.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/model/Workbook.java Wed Jan  9 
15:21:35 2008
@@ -2165,13 +2165,68 @@
       }
       return palette;
     }
+    
+    /**
+     * Finds the primary drawing group, if one already exists
+     */
+    public void findDrawingGroup() {
+       // Need to find a DrawingGroupRecord that
+       //  contains a EscherDggRecord
+       for(Iterator rit = records.iterator(); rit.hasNext();) {
+               Record r = (Record)rit.next();
+               
+               if(r instanceof DrawingGroupRecord) {
+               DrawingGroupRecord dg = (DrawingGroupRecord)r;
+               dg.processChildRecords();
+               
+               EscherContainerRecord cr =
+                       dg.getEscherContainer();
+               if(cr == null) {
+                       continue;
+               }
+               
+               EscherDggRecord dgg = null;
+               for(Iterator it = cr.getChildRecords().iterator(); 
it.hasNext();) {
+                       Object er = it.next();
+                       if(er instanceof EscherDggRecord) {
+                               dgg = (EscherDggRecord)er;
+                       }
+               }
+               
+               if(dgg != null) {
+                       drawingManager = new DrawingManager2(dgg);
+                       return;
+               }
+               }
+       }
+
+       // Look for the DrawingGroup record
+        int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
+        
+       // If there is one, does it have a EscherDggRecord?
+        if(dgLoc != -1) {
+               DrawingGroupRecord dg =
+                       (DrawingGroupRecord)records.get(dgLoc);
+               EscherDggRecord dgg = null;
+               for(Iterator it = dg.getEscherRecords().iterator(); 
it.hasNext();) {
+                       Object er = it.next();
+                       if(er instanceof EscherDggRecord) {
+                               dgg = (EscherDggRecord)er;
+                       }
+               }
+               
+               if(dgg != null) {
+                       drawingManager = new DrawingManager2(dgg);
+               }
+        }
+    }
 
     /**
-     * Creates a drawing group record.  If it already exists then it's 
modified.
+     * Creates a primary drawing group record.  If it already 
+     *  exists then it's modified.
      */
     public void createDrawingGroup()
     {
-
         if (drawingManager == null)
         {
             EscherContainerRecord dggContainer = new EscherContainerRecord();
@@ -2235,7 +2290,6 @@
             }
 
         }
-
     }
     
     public WindowOneRecord getWindowOne() {

Modified: 
poi/trunk/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java?rev=610608&r1=610607&r2=610608&view=diff
==============================================================================
--- 
poi/trunk/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java 
(original)
+++ 
poi/trunk/src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java 
Wed Jan  9 15:21:35 2008
@@ -18,19 +18,18 @@
 
 package org.apache.poi.hssf.record;
 
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
 import org.apache.poi.ddf.DefaultEscherRecordFactory;
+import org.apache.poi.ddf.EscherContainerRecord;
 import org.apache.poi.ddf.EscherRecord;
 import org.apache.poi.ddf.EscherRecordFactory;
 import org.apache.poi.ddf.NullEscherSerializationListener;
 import org.apache.poi.util.LittleEndian;
 
-import java.io.ByteArrayInputStream;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
 /**
  * The escher container record is used to hold escher records.  It is abstract 
and
  * must be subclassed for maximum benefit.
@@ -97,6 +96,9 @@
         }
     }
 
+    protected void convertRawBytesToEscherRecords() {
+       convertToEscherRecords(0, rawData.length, rawData);
+    }
     private void convertToEscherRecords( int offset, int size, byte[] data )
     {
         EscherRecordFactory recordFactory = new DefaultEscherRecordFactory();
@@ -263,6 +265,54 @@
     public void clearEscherRecords()
     {
         escherRecords.clear();
+    }
+    
+    /**
+     * If we have a EscherContainerRecord as one of our
+     *  children (and most top level escher holders do),
+     *  then return that.
+     */
+    public EscherContainerRecord getEscherContainer() {
+       for(Iterator it = escherRecords.iterator(); it.hasNext();) {
+               Object er = it.next();
+               if(er instanceof EscherContainerRecord) {
+                       return (EscherContainerRecord)er;
+               }
+       }
+       return null;
+    }
+
+    /**
+     * Descends into all our children, returning the
+     *  first EscherRecord with the given id, or null
+     *  if none found
+     */
+    public EscherRecord findFirstWithId(short id) {
+       return findFirstWithId(id, getEscherRecords());
+    }
+    private EscherRecord findFirstWithId(short id, List records) {
+       // Check at our level
+       for(Iterator it = records.iterator(); it.hasNext();) {
+               EscherRecord r = (EscherRecord)it.next();
+               if(r.getRecordId() == id) {
+                       return r;
+               }
+       }
+       
+       // Then check our children in turn
+       for(Iterator it = records.iterator(); it.hasNext();) {
+               EscherRecord r = (EscherRecord)it.next();
+               if(r.isContainerRecord()) {
+                       EscherRecord found =
+                               findFirstWithId(id, r.getChildRecords());
+                       if(found != null) {
+                               return found;
+                       }
+               }
+       }
+       
+       // Not found in this lot
+       return null;
     }
 
 

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java?rev=610608&r1=610607&r2=610608&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java Wed 
Jan  9 15:21:35 2008
@@ -72,6 +72,16 @@
             return writeData( offset, data, buffer );
         }
     }
+    
+    /**
+     * Process the bytes into escher records.
+     * (Not done by default in case we break things,
+     *  unless you set the "poi.deserialize.escher" 
+     *  system property)
+     */
+    public void processChildRecords() {
+       convertRawBytesToEscherRecords();
+    }
 
     /**
      * Size of record (including 4 byte headers for all sections)

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/EscherAggregate.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/EscherAggregate.java?rev=610608&r1=610607&r2=610608&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/EscherAggregate.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/EscherAggregate.java Wed Jan  
9 15:21:35 2008
@@ -523,7 +523,20 @@
     {
         this.patriarch = patriarch;
     }
-
+    
+    /**
+     * Converts the Records into UserModel
+     *  objects on the bound HSSFPatriarch
+     */
+    public void convertRecordsToUserModel() {
+       if(patriarch == null) {
+               throw new IllegalStateException("Must call setPatriarch() 
first");
+       }
+       
+       // TODO: Support converting our records
+       //  back into shapes
+    }
+    
     public void clear()
     {
         clearEscherRecords();

Modified: poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java?rev=610608&r1=610607&r2=610608&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java Wed Jan 
 9 15:21:35 2008
@@ -21,6 +21,13 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.poi.ddf.EscherComplexProperty;
+import org.apache.poi.ddf.EscherOptRecord;
+import org.apache.poi.ddf.EscherProperty;
+import org.apache.poi.hssf.record.EscherAggregate;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.StringUtil;
+
 /**
  * The patriarch is the toplevel container for shapes in a sheet.  It does
  * little other than act as a container for other shapes and groups.
@@ -38,12 +45,20 @@
     int y2 = 255;
 
     /**
+     * The EscherAggregate we have been bound to.
+     * (This will handle writing us out into records,
+     *  and building up our shapes from the records)
+     */
+    private EscherAggregate boundAggregate;
+
+    /**
      * Creates the patriarch.
      *
-     * @param sheet     the sheet this patriarch is stored in.
+     * @param sheet the sheet this patriarch is stored in.
      */
-    HSSFPatriarch(HSSFSheet sheet)
+    HSSFPatriarch(HSSFSheet sheet, EscherAggregate boundAggregate)
     {
+       this.boundAggregate = boundAggregate;
         this.sheet = sheet;
     }
 
@@ -172,6 +187,39 @@
         this.y1 = y1;
         this.x2 = x2;
         this.y2 = y2;
+    }
+    
+    /**
+     * Does this HSSFPatriarch contain a chart?
+     * (Technically a reference to a chart, since they
+     *  get stored in a different block of records)
+     * FIXME - detect chart in all cases (only seems
+     *  to work on some charts so far)
+     */
+    public boolean containsChart() {
+       // TODO - support charts properly in usermodel
+       
+       // We're looking for a EscherOptRecord
+       EscherOptRecord optRecord = (EscherOptRecord)
+               boundAggregate.findFirstWithId(EscherOptRecord.RECORD_ID);
+       if(optRecord == null) {
+               // No opt record, can't have chart
+               return false;
+       }
+       
+       for(Iterator it = optRecord.getEscherProperties().iterator(); 
it.hasNext();) {
+               EscherProperty prop = (EscherProperty)it.next();
+               if(prop.getPropertyNumber() == 896 && prop.isComplex()) {
+                       EscherComplexProperty cp = (EscherComplexProperty)prop;
+                       String str = 
StringUtil.getFromUnicodeLE(cp.getComplexData());
+                       System.err.println(str);
+                       if(str.equals("Chart 1\0")) {
+                               return true;
+                       }
+               }
+       }
+
+       return false;
     }
 
     /**

Modified: poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java?rev=610608&r1=610607&r2=610608&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java Wed Jan  9 
15:21:35 2008
@@ -1488,7 +1488,7 @@
      */
     public void dumpDrawingRecords(boolean fat)
     {
-        sheet.aggregateDrawingRecords(book.getDrawingManager());
+        sheet.aggregateDrawingRecords(book.getDrawingManager(), false);
 
         EscherAggregate r = (EscherAggregate) 
getSheet().findFirstRecordBySid(EscherAggregate.sid);
         List escherRecords = r.getEscherRecords();
@@ -1505,9 +1505,10 @@
     }
 
     /**
-     * Creates the toplevel drawing patriarch.  This will have the effect of
-     * removing any existing drawings on this sheet.
-     *
+     * Creates the top-level drawing patriarch.  This will have
+     *  the effect of removing any existing drawings on this
+     *  sheet.
+     * This may then be used to add graphics or charts
      * @return  The new patriarch.
      */
     public HSSFPatriarch createDrawingPatriarch()
@@ -1515,12 +1516,41 @@
         // Create the drawing group if it doesn't already exist.
         book.createDrawingGroup();
 
-        sheet.aggregateDrawingRecords(book.getDrawingManager());
+        sheet.aggregateDrawingRecords(book.getDrawingManager(), true);
         EscherAggregate agg = (EscherAggregate) 
sheet.findFirstRecordBySid(EscherAggregate.sid);
-        HSSFPatriarch patriarch = new HSSFPatriarch(this);
+        HSSFPatriarch patriarch = new HSSFPatriarch(this, agg);
         agg.clear();     // Initially the behaviour will be to clear out any 
existing shapes in the sheet when
                          // creating a new patriarch.
         agg.setPatriarch(patriarch);
+        return patriarch;
+    }
+    
+    /**
+     * Returns the top-level drawing patriach, if there is
+     *  one.
+     * This will hold any graphics or charts for the sheet
+     */
+    public HSSFPatriarch getDrawingPatriarch() {
+       book.findDrawingGroup();
+       
+       // If there's now no drawing manager, then there's
+       //  no drawing escher records on the workbook
+       if(book.getDrawingManager() == null) {
+               return null;
+       }
+       
+       int found = sheet.aggregateDrawingRecords(
+                       book.getDrawingManager(), false
+       );
+       if(found == -1) {
+               // Workbook has drawing stuff, but this sheet doesn't
+               return null;
+       }
+       
+        EscherAggregate agg = (EscherAggregate) 
sheet.findFirstRecordBySid(EscherAggregate.sid);
+        HSSFPatriarch patriarch = new HSSFPatriarch(this, agg);
+        agg.setPatriarch(patriarch);
+        agg.convertRecordsToUserModel();
         return patriarch;
     }
 

Modified: 
poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java?rev=610608&r1=610607&r2=610608&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java 
(original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java 
Wed Jan  9 15:21:35 2008
@@ -407,6 +407,30 @@
         assertEquals(0, r6.getOutlineLevel());
     }
     
+    public void testGetDrawings() throws Exception {
+        String filename = System.getProperty("HSSF.testdata.path");
+       HSSFWorkbook wb1c = new HSSFWorkbook(
+                       new FileInputStream(new File(filename,"WithChart.xls"))
+       );
+       HSSFWorkbook wb2c = new HSSFWorkbook(
+                       new FileInputStream(new 
File(filename,"WithTwoCharts.xls"))
+       );
+       
+       // 1 chart sheet -> data on 1st, chart on 2nd
+       assertNotNull(wb1c.getSheetAt(0).getDrawingPatriarch());
+       assertNotNull(wb1c.getSheetAt(1).getDrawingPatriarch());
+       assertFalse(wb1c.getSheetAt(0).getDrawingPatriarch().containsChart());
+       assertTrue(wb1c.getSheetAt(1).getDrawingPatriarch().containsChart());
+       
+       // 2 chart sheet -> data on 1st, chart on 2nd+3rd
+       assertNotNull(wb2c.getSheetAt(0).getDrawingPatriarch());
+       assertNotNull(wb2c.getSheetAt(1).getDrawingPatriarch());
+       assertNotNull(wb2c.getSheetAt(2).getDrawingPatriarch());
+       assertFalse(wb2c.getSheetAt(0).getDrawingPatriarch().containsChart());
+       assertTrue(wb2c.getSheetAt(1).getDrawingPatriarch().containsChart());
+       assertTrue(wb2c.getSheetAt(2).getDrawingPatriarch().containsChart());
+    }
+    
        /**
         * Test that the ProtectRecord is included when creating or cloning a 
sheet
         */

Modified: 
poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java?rev=610608&r1=610607&r2=610608&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java 
(original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java 
Wed Jan  9 15:21:35 2008
@@ -16,6 +16,8 @@
 */
 package org.apache.poi.hssf.usermodel;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 
@@ -128,5 +130,70 @@
         assertEquals(1, b.getNumberOfSheets());
         b.cloneSheet(0);
         assertEquals(2, b.getNumberOfSheets());
+    }
+    
+    public void testReadWriteWithCharts() throws Exception {
+        HSSFWorkbook b;
+        HSSFSheet s;
+        
+        // Single chart, two sheets
+        b = new HSSFWorkbook(
+                       new FileInputStream(new 
File(filename,"44010-SingleChart.xls"))
+        );
+        assertEquals(2, b.getNumberOfSheets());
+        s = b.getSheetAt(1);
+        assertEquals(0, s.getFirstRowNum());
+        assertEquals(0, s.getLastRowNum());
+        
+        // Has chart on 1st sheet??
+        // FIXME
+        assertNotNull(b.getSheetAt(0).getDrawingPatriarch());
+        assertNull(b.getSheetAt(1).getDrawingPatriarch());
+        assertFalse(b.getSheetAt(0).getDrawingPatriarch().containsChart());
+        
+        b = writeRead(b);
+        assertEquals(2, b.getNumberOfSheets());
+        s = b.getSheetAt(1);
+        assertEquals(0, s.getFirstRowNum());
+        assertEquals(0, s.getLastRowNum());
+
+        
+        // Two charts, three sheets
+        b = new HSSFWorkbook(
+                       new FileInputStream(new 
File(filename,"44010-TwoCharts.xls"))
+        );
+        assertEquals(3, b.getNumberOfSheets());
+        
+        s = b.getSheetAt(1);
+        assertEquals(0, s.getFirstRowNum());
+        assertEquals(0, s.getLastRowNum());
+        s = b.getSheetAt(2);
+        assertEquals(0, s.getFirstRowNum());
+        assertEquals(0, s.getLastRowNum());
+        
+        // Has chart on 1st sheet??
+        // FIXME
+        assertNotNull(b.getSheetAt(0).getDrawingPatriarch());
+        assertNull(b.getSheetAt(1).getDrawingPatriarch());
+        assertNull(b.getSheetAt(2).getDrawingPatriarch());
+        assertFalse(b.getSheetAt(0).getDrawingPatriarch().containsChart());
+        
+        b = writeRead(b);
+        assertEquals(3, b.getNumberOfSheets());
+        
+        s = b.getSheetAt(1);
+        assertEquals(0, s.getFirstRowNum());
+        assertEquals(0, s.getLastRowNum());
+        s = b.getSheetAt(2);
+        assertEquals(0, s.getFirstRowNum());
+        assertEquals(0, s.getLastRowNum());
+    }
+    
+    private HSSFWorkbook writeRead(HSSFWorkbook b) throws Exception {
+       ByteArrayOutputStream baos = new ByteArrayOutputStream();
+       b.write(baos);
+       return new HSSFWorkbook(
+                       new ByteArrayInputStream(baos.toByteArray())
+       );
     }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to