]> source.dussan.org Git - poi.git/commitdiff
[bug-63902] reference cloned sheet in cloned chart data series
authorAlain Béarez <abearez@apache.org>
Tue, 16 Feb 2021 23:39:19 +0000 (23:39 +0000)
committerAlain Béarez <abearez@apache.org>
Tue, 16 Feb 2021 23:39:19 +0000 (23:39 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1886605 13f79535-47bb-0310-9956-ffa450edef68

src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFCategoryDataSource.java
src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFChart.java
src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFChartData.java
src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFDataSource.java
src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFDataSourcesFactory.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFChart.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChart.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
src/ooxml/testcases/org/apache/poi/xssf/TestXSSFCloneSheet.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java

index 426a1a4fc4031d94ded0b3746639a6aa0eda8629..6bdc8cf911daa922ba98b60485ba437521ea758d 100644 (file)
@@ -42,9 +42,4 @@ public interface XDDFCategoryDataSource extends XDDFDataSource<String> {
     default boolean isReference() {
         return true;
     }
-
-    @Override
-    default String getDataRangeReference() {
-        return getFormula();
-    }
 }
index 88592c08437ad0cae5161c6446277f65bd03e5d1..7b29b33a28a7be374c2059381983ea4be7d8b3aa 100644 (file)
@@ -124,10 +124,6 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
      */
     protected final CTChartSpace chartSpace;
 
-    /**
-     * Chart element in the chart space
-     */
-    protected final CTChart chart;
 
     /**
      * Construct a chart.
@@ -136,8 +132,7 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
         super();
 
         chartSpace = CTChartSpace.Factory.newInstance();
-        chart = chartSpace.addNewChart();
-        chart.addNewPlotArea();
+        chartSpace.addNewChart().addNewPlotArea();
     }
 
     /**
@@ -153,7 +148,6 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
         super(part);
 
         chartSpace = ChartSpaceDocument.Factory.parse(part.getInputStream(), DEFAULT_XML_OPTIONS).getChartSpace();
-        chart = chartSpace.getChart();
     }
 
     /**
@@ -174,8 +168,7 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
      */
     @Internal
     public CTChart getCTChart() {
-        return chart;
-
+        return chartSpace.getChart();
     }
 
     /**
@@ -185,7 +178,7 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
      */
     @Internal
     protected CTPlotArea getCTPlotArea() {
-        return chart.getPlotArea();
+        return getCTChart().getPlotArea();
     }
 
     /**
@@ -199,8 +192,8 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
             workbook.removeSheetAt(0);
             workbook.createSheet();
         }
-        chart.set(CTChart.Factory.newInstance());
-        chart.addNewPlotArea();
+        getCTChart().set(CTChart.Factory.newInstance());
+        getCTChart().addNewPlotArea();
     }
 
     /**
@@ -208,8 +201,8 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
      *         otherwise
      */
     public boolean isPlotOnlyVisibleCells() {
-        if (chart.isSetPlotVisOnly()) {
-            return chart.getPlotVisOnly().getVal();
+        if (getCTChart().isSetPlotVisOnly()) {
+            return getCTChart().getPlotVisOnly().getVal();
         } else {
             return false;
         }
@@ -221,40 +214,40 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
      *            the chart
      */
     public void setPlotOnlyVisibleCells(boolean only) {
-        if (!chart.isSetPlotVisOnly()) {
-            chart.setPlotVisOnly(CTBoolean.Factory.newInstance());
+        if (!getCTChart().isSetPlotVisOnly()) {
+            getCTChart().setPlotVisOnly(CTBoolean.Factory.newInstance());
         }
-        chart.getPlotVisOnly().setVal(only);
+        getCTChart().getPlotVisOnly().setVal(only);
     }
 
     public void setFloor(int thickness) {
-        if (!chart.isSetFloor()) {
-            chart.setFloor(CTSurface.Factory.newInstance());
+        if (!getCTChart().isSetFloor()) {
+            getCTChart().setFloor(CTSurface.Factory.newInstance());
         }
-        chart.getFloor().getThickness().setVal(thickness);
+        getCTChart().getFloor().getThickness().setVal(thickness);
     }
 
     public void setBackWall(int thickness) {
-        if (!chart.isSetBackWall()) {
-            chart.setBackWall(CTSurface.Factory.newInstance());
+        if (!getCTChart().isSetBackWall()) {
+            getCTChart().setBackWall(CTSurface.Factory.newInstance());
         }
-        chart.getBackWall().getThickness().setVal(thickness);
+        getCTChart().getBackWall().getThickness().setVal(thickness);
     }
 
     public void setSideWall(int thickness) {
-        if (!chart.isSetSideWall()) {
-            chart.setSideWall(CTSurface.Factory.newInstance());
+        if (!getCTChart().isSetSideWall()) {
+            getCTChart().setSideWall(CTSurface.Factory.newInstance());
         }
-        chart.getSideWall().getThickness().setVal(thickness);
+        getCTChart().getSideWall().getThickness().setVal(thickness);
     }
 
     public void setAutoTitleDeleted(boolean deleted) {
-        if (!chart.isSetAutoTitleDeleted()) {
-            chart.setAutoTitleDeleted(CTBoolean.Factory.newInstance());
+        if (!getCTChart().isSetAutoTitleDeleted()) {
+            getCTChart().setAutoTitleDeleted(CTBoolean.Factory.newInstance());
         }
-        chart.getAutoTitleDeleted().setVal(deleted);
-        if (deleted && chart.isSetTitle()) {
-            chart.unsetTitle();
+        getCTChart().getAutoTitleDeleted().setVal(deleted);
+        if (deleted && getCTChart().isSetTitle()) {
+            getCTChart().unsetTitle();
         }
     }
 
@@ -264,14 +257,14 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
      */
     public void displayBlanksAs(DisplayBlanks as) {
         if (as == null){
-            if (chart.isSetDispBlanksAs()) {
-                chart.unsetDispBlanksAs();
+            if (getCTChart().isSetDispBlanksAs()) {
+                getCTChart().unsetDispBlanksAs();
             }
         } else {
-            if (chart.isSetDispBlanksAs()) {
-              chart.getDispBlanksAs().setVal(as.underlying);
+            if (getCTChart().isSetDispBlanksAs()) {
+              getCTChart().getDispBlanksAs().setVal(as.underlying);
             } else {
-                chart.addNewDispBlanksAs().setVal(as.underlying);
+                getCTChart().addNewDispBlanksAs().setVal(as.underlying);
             }
         }
     }
@@ -280,8 +273,8 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
      * @since 4.0.1
      */
     public Boolean getTitleOverlay() {
-        if (chart.isSetTitle()) {
-            CTTitle title = chart.getTitle();
+        if (getCTChart().isSetTitle()) {
+            CTTitle title = getCTChart().getTitle();
             if (title.isSetOverlay()) {
                 return title.getOverlay().getVal();
             }
@@ -293,10 +286,10 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
      * @since 4.0.1
      */
     public void setTitleOverlay(boolean overlay) {
-        if (!chart.isSetTitle()) {
-            chart.addNewTitle();
+        if (!getCTChart().isSetTitle()) {
+            getCTChart().addNewTitle();
         }
-        new XDDFTitle(this, chart.getTitle()).setOverlay(overlay);
+        new XDDFTitle(this, getCTChart().getTitle()).setOverlay(overlay);
     }
 
     /**
@@ -307,18 +300,18 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
      * @since 4.0.1
      */
     public void setTitleText(String text) {
-        if (!chart.isSetTitle()) {
-            chart.addNewTitle();
+        if (!getCTChart().isSetTitle()) {
+            getCTChart().addNewTitle();
         }
-        new XDDFTitle(this, chart.getTitle()).setText(text);
+        new XDDFTitle(this, getCTChart().getTitle()).setText(text);
     }
 
     /**
      * @since 4.0.1
      */
     public XDDFTitle getTitle() {
-        if (chart.isSetTitle()) {
-            return new XDDFTitle(this, chart.getTitle());
+        if (getCTChart().isSetTitle()) {
+            return new XDDFTitle(this, getCTChart().getTitle());
         } else {
             return null;
         }
@@ -339,10 +332,10 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
     */
    public XDDFView3D getOrAddView3D() {
       CTView3D view3D;
-      if (chart.isSetView3D()) {
-         view3D = chart.getView3D();
+      if (getCTChart().isSetView3D()) {
+         view3D = getCTChart().getView3D();
       } else {
-         view3D = chart.addNewView3D();
+         view3D = getCTChart().addNewView3D();
       }
       return new XDDFView3D(view3D);
    }
@@ -355,10 +348,10 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
      */
     @Beta
     public XDDFTextBody getFormattedTitle() {
-        if (!chart.isSetTitle()) {
+        if (!getCTChart().isSetTitle()) {
             return null;
         }
-        return new XDDFTitle(this, chart.getTitle()).getBody();
+        return new XDDFTitle(this, getCTChart().getTitle()).getBody();
     }
 
     @Override
@@ -393,12 +386,12 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
     }
 
     public XDDFChartLegend getOrAddLegend() {
-        return new XDDFChartLegend(chart);
+        return new XDDFChartLegend(getCTChart());
     }
 
     public void deleteLegend() {
-        if (chart.isSetLegend()) {
-            chart.unsetLegend();
+        if (getCTChart().isSetLegend()) {
+            getCTChart().unsetLegend();
         }
     }
 
@@ -418,7 +411,8 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
             series.plot();
             XDDFDataSource<?> categoryDS = series.getCategoryData();
             XDDFNumericalDataSource<? extends Number> valuesDS = series.getValuesData();
-            if (categoryDS.isCellRange() || valuesDS.isCellRange()
+            if (categoryDS == null || valuesDS == null
+                    || categoryDS.isCellRange() || valuesDS.isCellRange()
                     || categoryDS.isLiteral() || valuesDS.isLiteral()) {
                 // let's assume the data is already in the sheet
             } else {
@@ -910,7 +904,7 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
      * @since POI 4.0.0
      */
     public void importContent(XDDFChart other) {
-        this.chart.set(other.chart);
+        getCTChartSpace().set(other.getCTChartSpace());
     }
 
     /**
@@ -1074,12 +1068,51 @@ public abstract class XDDFChart extends POIXMLDocumentPart implements TextContai
     }
 
     /**
-     * set chart index which can be use for relation part
+     * Set chart index which can be used for relation part.
      *
      * @param chartIndex
-     *            chart index which can be use for relation part
+     *            chart index which can be used for relation part.
      */
     public void setChartIndex(int chartIndex) {
         this.chartIndex = chartIndex;
     }
+
+    /**
+     * Replace references to the sheet name in the data supporting the chart.
+     *
+     * @param newSheet
+     *          sheet to be used in the data references.
+     *
+     * @since POI 5.0.1
+     */
+    public void replaceReferences(XSSFSheet newSheet) {
+        for (XDDFChartData data : getChartSeries()) {
+            for (XDDFChartData.Series series : data.series) {
+                XDDFDataSource newCategory = series.categoryData;
+                XDDFNumericalDataSource newValues = series.valuesData;
+                try {
+                    if (series.categoryData != null && series.categoryData.isReference()) {
+                        String ref = series.categoryData.getDataRangeReference();
+                        CellRangeAddress rangeAddress = CellRangeAddress.valueOf(ref.substring(ref.indexOf('!') + 1));
+                        newCategory = series.categoryData.isNumeric()
+                                ? XDDFDataSourcesFactory.fromNumericCellRange(newSheet, rangeAddress)
+                                : XDDFDataSourcesFactory.fromStringCellRange(newSheet, rangeAddress);
+                        if (newCategory.isNumeric()) {
+                            ((XDDFNumericalDataSource) newCategory).setFormatCode(series.categoryData.getFormatCode());
+                        }
+                    }
+                    if (series.valuesData!= null && series.valuesData.isReference()) {
+                        String ref = series.valuesData.getDataRangeReference();
+                        CellRangeAddress rangeAddress = CellRangeAddress.valueOf(ref.substring(ref.indexOf('!') + 1));
+                        newValues = XDDFDataSourcesFactory.fromNumericCellRange(newSheet, rangeAddress);
+                        newValues.setFormatCode(series.valuesData.getFormatCode());
+                    }
+                } catch (IllegalArgumentException iae) {
+                    // keep old values when cell range cannot be parsed
+                }
+                series.replaceData(newCategory, newValues);
+                series.plot();
+            }
+        }
+    }
 }
index 937ed1bbb6ec30fb2aa2e7d72fcf91b23589c025..225749f50885ed21a90fbecd8208e3a706d20634 100644 (file)
@@ -162,12 +162,11 @@ public abstract class XDDFChartData {
         }
 
         public void replaceData(XDDFDataSource<?> category, XDDFNumericalDataSource<? extends Number> values) {
-            if (category == null || values == null) {
-                throw new IllegalStateException("Category and values must be defined before filling chart data.");
-            }
-            int numOfPoints = category.getPointCount();
-            if (numOfPoints != values.getPointCount()) {
-                throw new IllegalStateException("Category and values must have the same point count.");
+            if (categoryData != null && values != null) {
+                int numOfPoints = category.getPointCount();
+                if (numOfPoints != values.getPointCount()) {
+                    throw new IllegalStateException("Category and values must have the same point count.");
+                }
             }
             this.categoryData = category;
             this.valuesData = values;
@@ -209,15 +208,19 @@ public abstract class XDDFChartData {
         }
 
         public void plot() {
-            if (categoryData.isNumeric()) {
-                CTNumData cache = retrieveNumCache(getAxDS(), categoryData);
-                categoryData.fillNumericalCache(cache);
-            } else {
-                CTStrData cache = retrieveStrCache(getAxDS(), categoryData);
-                categoryData.fillStringCache(cache);
+            if (categoryData != null) {
+                if (categoryData.isNumeric()) {
+                    CTNumData cache = retrieveNumCache(getAxDS(), categoryData);
+                    categoryData.fillNumericalCache(cache);
+                } else {
+                    CTStrData cache = retrieveStrCache(getAxDS(), categoryData);
+                    categoryData.fillStringCache(cache);
+                }
+            }
+            if (valuesData != null) {
+                CTNumData cache = retrieveNumCache(getNumDS(), valuesData);
+                valuesData.fillNumericalCache(cache);
             }
-            CTNumData cache = retrieveNumCache(getNumDS(), valuesData);
-            valuesData.fillNumericalCache(cache);
         }
 
         /**
index 439d0a325ce7b580d30c78c70eb444b25d1b5fc3..ea99a34b127d7a8a7a3200ca1b1e8c69f21f2658 100644 (file)
@@ -50,7 +50,9 @@ public interface XDDFDataSource<T> {
 
     String getDataRangeReference();
 
-    String getFormula();
+    default String getFormula() {
+        return getDataRangeReference();
+    }
 
     String getFormatCode();
 
index c45fbaa6a78f125f76f58f6f05dbb2f92b53ad4a..4cd3bc876f2f0fccb9375572bbe9ba79287e585c 100644 (file)
@@ -42,7 +42,10 @@ public class XDDFDataSourcesFactory {
     }
 
     public static XDDFCategoryDataSource fromDataSource(final CTAxDataSource categoryDS) {
-        if (categoryDS.getStrRef() == null) {
+        if (categoryDS == null) {
+            return null;
+        }
+        if (categoryDS.getNumRef() != null && categoryDS.getNumRef().getNumCache() != null) {
             return new XDDFCategoryDataSource() {
                 private CTNumData category = (CTNumData) categoryDS.getNumRef().getNumCache().copy();
                 private String formatCode = category.isSetFormatCode() ? category.getFormatCode() : null;
@@ -58,7 +61,7 @@ public class XDDFDataSourcesFactory {
                 }
 
                 @Override
-                public String getFormula() {
+                public String getDataRangeReference() {
                     return categoryDS.getNumRef().getF();
                 }
 
@@ -75,7 +78,7 @@ public class XDDFDataSourcesFactory {
                 @Override
                 public String getFormatCode() { return formatCode; }
             };
-        } else {
+        } else if (categoryDS.getStrRef() != null && categoryDS.getStrRef().getStrCache() != null) {
             return new XDDFCategoryDataSource() {
                 private CTStrData category = (CTStrData) categoryDS.getStrRef().getStrCache().copy();
 
@@ -85,7 +88,7 @@ public class XDDFDataSourcesFactory {
                 }
 
                 @Override
-                public String getFormula() {
+                public String getDataRangeReference() {
                     return categoryDS.getStrRef().getF();
                 }
 
@@ -102,64 +105,203 @@ public class XDDFDataSourcesFactory {
                 @Override
                 public String getFormatCode() { return null; }
             };
+        } else if (categoryDS.getNumLit() != null) {
+            return new XDDFCategoryDataSource() {
+                private CTNumData category = (CTNumData) categoryDS.getNumLit().copy();
+                private String formatCode = category.isSetFormatCode() ? category.getFormatCode() : null;
+
+                @Override
+                public boolean isCellRange() {
+                    return false;
+                }
+
+                @Override
+                public boolean isLiteral() {
+                    return true;
+                }
+
+                @Override
+                public boolean isNumeric() {
+                    return true;
+                }
+
+                @Override
+                public boolean isReference() {
+                    return false;
+                }
+
+                @Override
+                public String getDataRangeReference() {
+                    return null;
+                }
+
+                @Override
+                public int getPointCount() {
+                    return (int) category.getPtCount().getVal();
+                }
+
+                @Override
+                public String getPointAt(int index) {
+                    return category.getPtArray(index).getV();
+                }
+
+                @Override
+                public String getFormatCode() { return formatCode; }
+            };
+        } else if (categoryDS.getStrLit() != null) {
+            return new XDDFCategoryDataSource() {
+                private CTStrData category = (CTStrData) categoryDS.getStrLit().copy();
+
+                @Override
+                public boolean isCellRange() {
+                    return false;
+                }
+
+                @Override
+                public boolean isLiteral() {
+                    return true;
+                }
+
+                @Override
+                public boolean isReference() {
+                    return false;
+                }
+
+                @Override
+                public String getDataRangeReference() {
+                    return null;
+                }
+
+                @Override
+                public int getPointCount() {
+                    return (int) category.getPtCount().getVal();
+                }
+
+                @Override
+                public String getPointAt(int index) {
+                    return category.getPtArray(index).getV();
+                }
+
+                @Override
+                public String getFormatCode() { return null; }
+            };
+        } else {
+            return null; // in some weird cases the element is empty
         }
     }
 
     public static XDDFNumericalDataSource<Double> fromDataSource(final CTNumDataSource valuesDS) {
-        return new XDDFNumericalDataSource<Double>() {
-            private CTNumData values = (CTNumData) valuesDS.getNumRef().getNumCache().copy();
-            private String formatCode = values.isSetFormatCode() ? values.getFormatCode() : null;
+        if (valuesDS == null) {
+            return null;
+        }
+        if (valuesDS.getNumRef() != null && valuesDS.getNumRef().getNumCache() != null) {
+            return new XDDFNumericalDataSource<Double>() {
+                private CTNumData values = (CTNumData) valuesDS.getNumRef().getNumCache().copy();
+                private String formatCode = values.isSetFormatCode() ? values.getFormatCode() : null;
 
-            @Override
-            public String getFormula() {
-                return valuesDS.getNumRef().getF();
-            }
+                @Override
+                public String getFormatCode() {
+                    return formatCode;
+                }
 
-            @Override
-            public String getFormatCode() {
-                return formatCode;
-            }
+                @Override
+                public void setFormatCode(String formatCode) {
+                    this.formatCode = formatCode;
+                }
 
-            @Override
-            public void setFormatCode(String formatCode) {
-                this.formatCode = formatCode;
-            }
+                @Override
+                public boolean isCellRange() {
+                    return true;
+                }
 
-            @Override
-            public boolean isCellRange() {
-                return true;
-            }
+                @Override
+                public boolean isNumeric() {
+                    return true;
+                }
 
-            @Override
-            public boolean isNumeric() {
-                return true;
-            }
+                @Override
+                public boolean isReference() {
+                    return true;
+                }
 
-            @Override
-            public boolean isReference() {
-                return true;
-            }
+                @Override
+                public int getPointCount() {
+                    return (int) values.getPtCount().getVal();
+                }
 
-            @Override
-            public int getPointCount() {
-                return (int) values.getPtCount().getVal();
-            }
+                @Override
+                public Double getPointAt(int index) {
+                    return Double.valueOf(values.getPtArray(index).getV());
+                }
 
-            @Override
-            public Double getPointAt(int index) {
-                return Double.valueOf(values.getPtArray(index).getV());
-            }
+                @Override
+                public String getDataRangeReference() {
+                    return valuesDS.getNumRef().getF();
+                }
 
-            @Override
-            public String getDataRangeReference() {
-                return valuesDS.getNumRef().getF();
-            }
+                @Override
+                public int getColIndex() {
+                    return 0;
+                }
+            };
+        } else if (valuesDS.getNumLit() != null) {
+            return new XDDFNumericalDataSource<Double>() {
+                private CTNumData values = (CTNumData) valuesDS.getNumLit().copy();
+                private String formatCode = values.isSetFormatCode() ? values.getFormatCode() : null;
 
-            @Override
-            public int getColIndex() {
-                return 0;
-            }
-        };
+                @Override
+                public String getFormatCode() {
+                    return formatCode;
+                }
+
+                @Override
+                public void setFormatCode(String formatCode) {
+                    this.formatCode = formatCode;
+                }
+
+                @Override
+                public boolean isCellRange() {
+                    return false;
+                }
+
+                @Override
+                public boolean isLiteral() {
+                    return true;
+                }
+
+                @Override
+                public boolean isNumeric() {
+                    return true;
+                }
+
+                @Override
+                public boolean isReference() {
+                    return false;
+                }
+
+                @Override
+                public int getPointCount() {
+                    return (int) values.getPtCount().getVal();
+                }
+
+                @Override
+                public Double getPointAt(int index) {
+                    return Double.valueOf(values.getPtArray(index).getV());
+                }
+
+                @Override
+                public String getDataRangeReference() {
+                    return null;
+                }
+
+                @Override
+                public int getColIndex() {
+                    return 0;
+                }
+            };
+        } else {
+            return null; // in some weird cases the element is empty
+        }
     }
 
     public static <T extends Number> XDDFNumericalDataSource<T> fromArray(T[] elements) {
@@ -264,11 +406,6 @@ public class XDDFDataSourcesFactory {
             super(elements, dataRange, col);
         }
 
-        @Override
-        public String getFormula() {
-            return getDataRangeReference();
-        }
-
         @Override
         public String getFormatCode() {
             return formatCode;
@@ -290,11 +427,6 @@ public class XDDFDataSourcesFactory {
             super(elements, dataRange, col);
         }
 
-        @Override
-        public String getFormula() {
-            return getDataRangeReference();
-        }
-
         @Override
         public String getFormatCode() { return null; }
     }
@@ -382,11 +514,6 @@ public class XDDFDataSourcesFactory {
             super(sheet, cellRangeAddress);
         }
 
-        @Override
-        public String getFormula() {
-            return getDataRangeReference();
-        }
-
         private String formatCode;
 
         @Override
@@ -421,11 +548,6 @@ public class XDDFDataSourcesFactory {
             super(sheet, cellRangeAddress);
         }
 
-        @Override
-        public String getFormula() {
-            return getDataRangeReference();
-        }
-
         @Override
         public String getPointAt(int index) {
             CellValue cellValue = getCellValueAt(index);
index 97f3ec23eeae844a96101133b5c826db11e96131..c54cba50c8ceb41a4f26ba99dfbc0293e74a0276 100644 (file)
@@ -84,10 +84,10 @@ public final class XSLFChart extends XDDFChart {
     }
 
     public XSLFTextShape getTitleShape() {
-        if (!chart.isSetTitle()) {
-            chart.addNewTitle();
+        if (!getCTChart().isSetTitle()) {
+            getCTChart().addNewTitle();
         }
-        final CTTitle title = chart.getTitle();
+        final CTTitle title = getCTChart().getTitle();
         if (title.getTx() != null && title.getTx().isSetRich()) {
             return new XSLFTextShape(title, null) {
                 @Override
index 428d74e96a10f743c0da7d2af299bb824f60ad60..e5646a41d6829ee243a0957e8b0e1dd8033dcb39 100644 (file)
@@ -91,7 +91,7 @@ public final class XSSFChart extends XDDFChart {
         CTPlotArea plotArea = getCTPlotArea();
 
         plotArea.addNewLayout();
-        chart.addNewPlotVisOnly().setVal(true);
+        getCTChart().addNewPlotVisOnly().setVal(true);
 
         CTPrintSettings printSettings = chartSpace.addNewPrintSettings();
         printSettings.addNewHeaderFooter();
@@ -154,12 +154,12 @@ public final class XSSFChart extends XDDFChart {
      *         if the title text is empty or the title uses a formula instead
      */
     public XSSFRichTextString getTitleText() {
-        if (!chart.isSetTitle()) {
+        if (!getCTChart().isSetTitle()) {
             return null;
         }
 
         // TODO Do properly
-        CTTitle title = chart.getTitle();
+        CTTitle title = getCTChart().getTitle();
 
         StringBuilder text = new StringBuilder(64);
         XmlObject[] t = title.selectPath("declare namespace a='" + XSSFDrawing.NAMESPACE_A + "' .//a:t");
@@ -183,11 +183,11 @@ public final class XSSFChart extends XDDFChart {
      * @return formula expression or null
      */
     public String getTitleFormula() {
-        if (!chart.isSetTitle()) {
+        if (!getCTChart().isSetTitle()) {
             return null;
         }
 
-        CTTitle title = chart.getTitle();
+        CTTitle title = getCTChart().getTitle();
 
         if (!title.isSetTx()) {
             return null;
@@ -209,10 +209,10 @@ public final class XSSFChart extends XDDFChart {
      */
     public void setTitleFormula(String formula) {
         CTTitle ctTitle;
-        if (chart.isSetTitle()) {
-            ctTitle = chart.getTitle();
+        if (getCTChart().isSetTitle()) {
+            ctTitle = getCTChart().getTitle();
         } else {
-            ctTitle = chart.addNewTitle();
+            ctTitle = getCTChart().addNewTitle();
         }
 
         CTTx tx;
index fadb24dae8aaacceb3762c694ec070a8f5fc7063..8b437cb2228d56e8c7d8f33e94c11252c0914ce5 100644 (file)
@@ -229,10 +229,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
      * @see org.apache.poi.xssf.usermodel.XSSFDrawing#createChart(ClientAnchor)
      */
     public XSSFChart createChart(XSSFClientAnchor anchor) {
-        int chartNumber = getPackagePart().getPackage().getPartsByContentType(XSSFRelation.CHART.getContentType())
-            .size() + 1;
-
-        RelationPart rp = createRelationship(XSSFRelation.CHART, XSSFFactory.getInstance(), chartNumber, false);
+        RelationPart rp = createChartRelationPart();
         XSSFChart chart = rp.getDocumentPart();
         String chartRelId = rp.getRelationship().getId();
 
@@ -243,6 +240,13 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
         return chart;
     }
 
+    protected RelationPart createChartRelationPart() {
+        int chartNumber = getPackagePart().getPackage().getPartsByContentType(XSSFRelation.CHART.getContentType())
+            .size() + 1;
+
+        return createRelationship(XSSFRelation.CHART, XSSFFactory.getInstance(), chartNumber, false);
+    }
+
     /**
      * Creates a chart.
      *
@@ -271,7 +275,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
         XSSFClientAnchor destAnchor = new XSSFClientAnchor(from, to);
         destAnchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
         XSSFChart destChart = createChart(destAnchor);
-        destChart.getCTChart().set(srcChart.getCTChartSpace().getChart().copy());
+        destChart.getCTChartSpace().set(srcChart.getCTChartSpace().copy());
         return destChart;
     }
 
index e390bca2ca4e607c76689cb0a7228f466cdf03e0..fc019a8f30ca12524a106bf4bfe0a4bbf02d52de 100644 (file)
@@ -671,9 +671,18 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Date1904Su
             clonedDg.getCTDrawing().set(dg.getCTDrawing().copy());
 
             // Clone drawing relations
-            List<RelationPart> srcRels = srcSheet.createDrawingPatriarch().getRelationParts();
+            List<RelationPart> srcRels = srcSheet.getDrawingPatriarch().getRelationParts();
             for (RelationPart rp : srcRels) {
-                addRelation(rp, clonedDg);
+                POIXMLDocumentPart r = rp.getDocumentPart();
+                if (r instanceof XSSFChart) {
+                    // Replace chart relation part with new relationship, cloning the chart's content
+                    RelationPart chartPart = clonedDg.createChartRelationPart();
+                    XSSFChart chart = chartPart.getDocumentPart();
+                    chart.importContent((XSSFChart)r);
+                    chart.replaceReferences(clonedSheet);
+                } else {
+                    addRelation(rp, clonedDg);
+                }
             }
         }
         return clonedSheet;
index 28584293894bb9867a372305840d3705ce49909d..b3c2896fd847954e6680bb04d93de39fb40b812d 100644 (file)
 package org.apache.poi.xssf;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.fail;
 
 import org.apache.poi.hssf.HSSFITestDataProvider;
 import org.apache.poi.ss.usermodel.BaseTestCloneSheet;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xssf.usermodel.XSSFDrawing;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.junit.jupiter.api.BeforeEach;
@@ -87,4 +89,33 @@ class TestXSSFCloneSheet  extends BaseTestCloneSheet {
             assertNotNull(source_sh);
         }
     }
+
+    @Test
+    void testBug63902() throws IOException {
+        try (XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("chartTitle_withTitle.xlsx")) {
+            XSSFSheet sheet = workbook.getSheetAt(0);
+            XSSFDrawing drawing = sheet.getDrawingPatriarch();
+            assertEquals(1, drawing.getCharts().size());
+
+            XSSFSheet sheet2 = workbook.cloneSheet(0, "Sheet 2");
+            XSSFDrawing drawing2 = sheet2.getDrawingPatriarch();
+            assertEquals(1, drawing2.getCharts().size());
+            assertEquals("Sheet 2", sheet2.getSheetName());
+
+            XDDFDataSource<?> data = drawing.getCharts().get(0).getChartSeries().get(0).getSeries(0).getCategoryData();
+            XDDFDataSource<?> data2 = drawing2.getCharts().get(0).getChartSeries().get(0).getSeries(0).getCategoryData();
+            assertNotEquals(data.getFormula(), data2.getFormula());
+            assertEquals(sheet.getSheetName(), data.getFormula().substring(0, data.getFormula().indexOf('!')));
+            assertEquals("'Sheet 2'", data2.getFormula().substring(0, data2.getFormula().indexOf('!')));
+            assertEquals(
+                    data.getFormula().substring(data.getFormula().indexOf('!')),
+                    data2.getFormula().substring(data2.getFormula().indexOf('!'))
+            );
+
+            Workbook wbBack = XSSFTestDataSamples.writeOutAndReadBack(workbook, "poi_cloned_sheet_with_chart");
+            assertNotNull(wbBack);
+            wbBack.close();
+        }
+    }
+
 }
index e000ed3dc95170e9c3919588befc57c91b82f797..c0720134049ce02dfa34d53df6a79bd73b279ca7 100644 (file)
@@ -914,19 +914,19 @@ class TestXSSFDrawing {
     }
 
     @Test
-    void testBug63901() {
-        XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("chartTitle_withTitle.xlsx");
-        XSSFSheet sheet = workbook.getSheet("Sheet1");
-        XSSFDrawing drawing = sheet.createDrawingPatriarch();
-        assert(drawing.getCharts().size() > 0);
-
-        XSSFWorkbook workbook2 = new XSSFWorkbook();
-        XSSFSheet sheet2 = workbook2.createSheet();
-        XSSFDrawing drawing2 = sheet2.createDrawingPatriarch();
-
-        drawing.getCharts().forEach(drawing2::importChart);
-
-        assertEquals(drawing.getCharts().size(), drawing2.getCharts().size());
+    void testBug63901() throws IOException {
+        try (XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("chartTitle_withTitle.xlsx")) {
+            XSSFSheet sheet = workbook.getSheetAt(0);
+            XSSFDrawing drawing = sheet.getDrawingPatriarch();
+            assertEquals(1, drawing.getCharts().size());
+
+            XSSFWorkbook workbook2 = new XSSFWorkbook();
+            XSSFSheet sheet2 = workbook2.createSheet();
+            XSSFDrawing drawing2 = sheet2.createDrawingPatriarch();
+
+            drawing.getCharts().forEach(drawing2::importChart);
+            assertEquals(1, drawing2.getCharts().size());
+        }
     }
 
     private static void checkRewrite(XSSFWorkbook wb) throws IOException {